VirtualBox

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

Last change on this file since 82264 was 82264, checked in by vboxsync, 5 years ago

VMM/HMVMXR0: Comment typo.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 710.1 KB
Line 
1/* $Id: HMVMXR0.cpp 82264 2019-11-28 10:28:42Z vboxsync $ */
2/** @file
3 * HM VMX (Intel VT-x) - Host Context Ring-0.
4 */
5
6/*
7 * Copyright (C) 2012-2019 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)->hm.s.idEnteredCpu == RTMpCpuId(), \
165 ("Illegal migration! Entered on CPU %u Current %u\n", \
166 (a_pVCpu)->hm.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 DECLCALLBACK(VBOXSTRICTRC) FNVMXEXITHANDLER(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
324/** Pointer to VM-exit handler. */
325typedef FNVMXEXITHANDLER *PFNVMXEXITHANDLER;
326#endif
327
328/**
329 * VMX VM-exit handler, non-strict status code.
330 *
331 * This is generally the same as FNVMXEXITHANDLER, the NSRC bit is just FYI.
332 *
333 * @returns VBox status code, no informational status code returned.
334 * @param pVCpu The cross context virtual CPU structure.
335 * @param pVmxTransient The VMX-transient structure.
336 *
337 * @remarks This is not used on anything returning VERR_EM_INTERPRETER as the
338 * use of that status code will be replaced with VINF_EM_SOMETHING
339 * later when switching over to IEM.
340 */
341#ifndef HMVMX_USE_FUNCTION_TABLE
342typedef int FNVMXEXITHANDLERNSRC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
343#else
344typedef FNVMXEXITHANDLER FNVMXEXITHANDLERNSRC;
345#endif
346
347
348/*********************************************************************************************************************************
349* Internal Functions *
350*********************************************************************************************************************************/
351#ifndef HMVMX_USE_FUNCTION_TABLE
352DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
353# define HMVMX_EXIT_DECL DECLINLINE(VBOXSTRICTRC)
354# define HMVMX_EXIT_NSRC_DECL DECLINLINE(int)
355#else
356# define HMVMX_EXIT_DECL static DECLCALLBACK(VBOXSTRICTRC)
357# define HMVMX_EXIT_NSRC_DECL HMVMX_EXIT_DECL
358#endif
359#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
360DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
361#endif
362
363static int hmR0VmxImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat);
364
365/** @name VM-exit handler prototypes.
366 * @{
367 */
368static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmi;
369static FNVMXEXITHANDLER hmR0VmxExitExtInt;
370static FNVMXEXITHANDLER hmR0VmxExitTripleFault;
371static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindow;
372static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindow;
373static FNVMXEXITHANDLER hmR0VmxExitTaskSwitch;
374static FNVMXEXITHANDLER hmR0VmxExitCpuid;
375static FNVMXEXITHANDLER hmR0VmxExitGetsec;
376static FNVMXEXITHANDLER hmR0VmxExitHlt;
377static FNVMXEXITHANDLERNSRC hmR0VmxExitInvd;
378static FNVMXEXITHANDLER hmR0VmxExitInvlpg;
379static FNVMXEXITHANDLER hmR0VmxExitRdpmc;
380static FNVMXEXITHANDLER hmR0VmxExitVmcall;
381#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
382static FNVMXEXITHANDLER hmR0VmxExitVmclear;
383static FNVMXEXITHANDLER hmR0VmxExitVmlaunch;
384static FNVMXEXITHANDLER hmR0VmxExitVmptrld;
385static FNVMXEXITHANDLER hmR0VmxExitVmptrst;
386static FNVMXEXITHANDLER hmR0VmxExitVmread;
387static FNVMXEXITHANDLER hmR0VmxExitVmresume;
388static FNVMXEXITHANDLER hmR0VmxExitVmwrite;
389static FNVMXEXITHANDLER hmR0VmxExitVmxoff;
390static FNVMXEXITHANDLER hmR0VmxExitVmxon;
391static FNVMXEXITHANDLER hmR0VmxExitInvvpid;
392#endif
393static FNVMXEXITHANDLER hmR0VmxExitRdtsc;
394static FNVMXEXITHANDLER hmR0VmxExitMovCRx;
395static FNVMXEXITHANDLER hmR0VmxExitMovDRx;
396static FNVMXEXITHANDLER hmR0VmxExitIoInstr;
397static FNVMXEXITHANDLER hmR0VmxExitRdmsr;
398static FNVMXEXITHANDLER hmR0VmxExitWrmsr;
399static FNVMXEXITHANDLER hmR0VmxExitMwait;
400static FNVMXEXITHANDLER hmR0VmxExitMtf;
401static FNVMXEXITHANDLER hmR0VmxExitMonitor;
402static FNVMXEXITHANDLER hmR0VmxExitPause;
403static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThreshold;
404static FNVMXEXITHANDLER hmR0VmxExitApicAccess;
405static FNVMXEXITHANDLER hmR0VmxExitEptViolation;
406static FNVMXEXITHANDLER hmR0VmxExitEptMisconfig;
407static FNVMXEXITHANDLER hmR0VmxExitRdtscp;
408static FNVMXEXITHANDLER hmR0VmxExitPreemptTimer;
409static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvd;
410static FNVMXEXITHANDLER hmR0VmxExitXsetbv;
411static FNVMXEXITHANDLER hmR0VmxExitInvpcid;
412static FNVMXEXITHANDLERNSRC hmR0VmxExitSetPendingXcptUD;
413static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestState;
414static FNVMXEXITHANDLERNSRC hmR0VmxExitErrUnexpected;
415/** @} */
416
417#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
418/** @name Nested-guest VM-exit handler prototypes.
419 * @{
420 */
421static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmiNested;
422static FNVMXEXITHANDLER hmR0VmxExitTripleFaultNested;
423static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindowNested;
424static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindowNested;
425static FNVMXEXITHANDLER hmR0VmxExitTaskSwitchNested;
426static FNVMXEXITHANDLER hmR0VmxExitHltNested;
427static FNVMXEXITHANDLER hmR0VmxExitInvlpgNested;
428static FNVMXEXITHANDLER hmR0VmxExitRdpmcNested;
429static FNVMXEXITHANDLER hmR0VmxExitVmreadVmwriteNested;
430static FNVMXEXITHANDLER hmR0VmxExitRdtscNested;
431static FNVMXEXITHANDLER hmR0VmxExitMovCRxNested;
432static FNVMXEXITHANDLER hmR0VmxExitMovDRxNested;
433static FNVMXEXITHANDLER hmR0VmxExitIoInstrNested;
434static FNVMXEXITHANDLER hmR0VmxExitRdmsrNested;
435static FNVMXEXITHANDLER hmR0VmxExitWrmsrNested;
436static FNVMXEXITHANDLER hmR0VmxExitMwaitNested;
437static FNVMXEXITHANDLER hmR0VmxExitMtfNested;
438static FNVMXEXITHANDLER hmR0VmxExitMonitorNested;
439static FNVMXEXITHANDLER hmR0VmxExitPauseNested;
440static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThresholdNested;
441static FNVMXEXITHANDLER hmR0VmxExitApicAccessNested;
442static FNVMXEXITHANDLER hmR0VmxExitApicWriteNested;
443static FNVMXEXITHANDLER hmR0VmxExitVirtEoiNested;
444static FNVMXEXITHANDLER hmR0VmxExitRdtscpNested;
445static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvdNested;
446static FNVMXEXITHANDLER hmR0VmxExitInvpcidNested;
447static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestStateNested;
448static FNVMXEXITHANDLER hmR0VmxExitInstrNested;
449static FNVMXEXITHANDLER hmR0VmxExitInstrWithInfoNested;
450/** @} */
451#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
452
453
454/*********************************************************************************************************************************
455* Global Variables *
456*********************************************************************************************************************************/
457#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
458/**
459 * Array of all VMCS fields.
460 * Any fields added to the VT-x spec. should be added here.
461 *
462 * Currently only used to derive shadow VMCS fields for hardware-assisted execution
463 * of nested-guests.
464 */
465static const uint32_t g_aVmcsFields[] =
466{
467 /* 16-bit control fields. */
468 VMX_VMCS16_VPID,
469 VMX_VMCS16_POSTED_INT_NOTIFY_VECTOR,
470 VMX_VMCS16_EPTP_INDEX,
471
472 /* 16-bit guest-state fields. */
473 VMX_VMCS16_GUEST_ES_SEL,
474 VMX_VMCS16_GUEST_CS_SEL,
475 VMX_VMCS16_GUEST_SS_SEL,
476 VMX_VMCS16_GUEST_DS_SEL,
477 VMX_VMCS16_GUEST_FS_SEL,
478 VMX_VMCS16_GUEST_GS_SEL,
479 VMX_VMCS16_GUEST_LDTR_SEL,
480 VMX_VMCS16_GUEST_TR_SEL,
481 VMX_VMCS16_GUEST_INTR_STATUS,
482 VMX_VMCS16_GUEST_PML_INDEX,
483
484 /* 16-bits host-state fields. */
485 VMX_VMCS16_HOST_ES_SEL,
486 VMX_VMCS16_HOST_CS_SEL,
487 VMX_VMCS16_HOST_SS_SEL,
488 VMX_VMCS16_HOST_DS_SEL,
489 VMX_VMCS16_HOST_FS_SEL,
490 VMX_VMCS16_HOST_GS_SEL,
491 VMX_VMCS16_HOST_TR_SEL,
492
493 /* 64-bit control fields. */
494 VMX_VMCS64_CTRL_IO_BITMAP_A_FULL,
495 VMX_VMCS64_CTRL_IO_BITMAP_A_HIGH,
496 VMX_VMCS64_CTRL_IO_BITMAP_B_FULL,
497 VMX_VMCS64_CTRL_IO_BITMAP_B_HIGH,
498 VMX_VMCS64_CTRL_MSR_BITMAP_FULL,
499 VMX_VMCS64_CTRL_MSR_BITMAP_HIGH,
500 VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL,
501 VMX_VMCS64_CTRL_EXIT_MSR_STORE_HIGH,
502 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL,
503 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_HIGH,
504 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL,
505 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_HIGH,
506 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL,
507 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_HIGH,
508 VMX_VMCS64_CTRL_EXEC_PML_ADDR_FULL,
509 VMX_VMCS64_CTRL_EXEC_PML_ADDR_HIGH,
510 VMX_VMCS64_CTRL_TSC_OFFSET_FULL,
511 VMX_VMCS64_CTRL_TSC_OFFSET_HIGH,
512 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL,
513 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_HIGH,
514 VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL,
515 VMX_VMCS64_CTRL_APIC_ACCESSADDR_HIGH,
516 VMX_VMCS64_CTRL_POSTED_INTR_DESC_FULL,
517 VMX_VMCS64_CTRL_POSTED_INTR_DESC_HIGH,
518 VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL,
519 VMX_VMCS64_CTRL_VMFUNC_CTRLS_HIGH,
520 VMX_VMCS64_CTRL_EPTP_FULL,
521 VMX_VMCS64_CTRL_EPTP_HIGH,
522 VMX_VMCS64_CTRL_EOI_BITMAP_0_FULL,
523 VMX_VMCS64_CTRL_EOI_BITMAP_0_HIGH,
524 VMX_VMCS64_CTRL_EOI_BITMAP_1_FULL,
525 VMX_VMCS64_CTRL_EOI_BITMAP_1_HIGH,
526 VMX_VMCS64_CTRL_EOI_BITMAP_2_FULL,
527 VMX_VMCS64_CTRL_EOI_BITMAP_2_HIGH,
528 VMX_VMCS64_CTRL_EOI_BITMAP_3_FULL,
529 VMX_VMCS64_CTRL_EOI_BITMAP_3_HIGH,
530 VMX_VMCS64_CTRL_EPTP_LIST_FULL,
531 VMX_VMCS64_CTRL_EPTP_LIST_HIGH,
532 VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL,
533 VMX_VMCS64_CTRL_VMREAD_BITMAP_HIGH,
534 VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL,
535 VMX_VMCS64_CTRL_VMWRITE_BITMAP_HIGH,
536 VMX_VMCS64_CTRL_VIRTXCPT_INFO_ADDR_FULL,
537 VMX_VMCS64_CTRL_VIRTXCPT_INFO_ADDR_HIGH,
538 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_FULL,
539 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_HIGH,
540 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_FULL,
541 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_HIGH,
542 VMX_VMCS64_CTRL_TSC_MULTIPLIER_FULL,
543 VMX_VMCS64_CTRL_TSC_MULTIPLIER_HIGH,
544
545 /* 64-bit read-only data fields. */
546 VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL,
547 VMX_VMCS64_RO_GUEST_PHYS_ADDR_HIGH,
548
549 /* 64-bit guest-state fields. */
550 VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL,
551 VMX_VMCS64_GUEST_VMCS_LINK_PTR_HIGH,
552 VMX_VMCS64_GUEST_DEBUGCTL_FULL,
553 VMX_VMCS64_GUEST_DEBUGCTL_HIGH,
554 VMX_VMCS64_GUEST_PAT_FULL,
555 VMX_VMCS64_GUEST_PAT_HIGH,
556 VMX_VMCS64_GUEST_EFER_FULL,
557 VMX_VMCS64_GUEST_EFER_HIGH,
558 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL,
559 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_HIGH,
560 VMX_VMCS64_GUEST_PDPTE0_FULL,
561 VMX_VMCS64_GUEST_PDPTE0_HIGH,
562 VMX_VMCS64_GUEST_PDPTE1_FULL,
563 VMX_VMCS64_GUEST_PDPTE1_HIGH,
564 VMX_VMCS64_GUEST_PDPTE2_FULL,
565 VMX_VMCS64_GUEST_PDPTE2_HIGH,
566 VMX_VMCS64_GUEST_PDPTE3_FULL,
567 VMX_VMCS64_GUEST_PDPTE3_HIGH,
568 VMX_VMCS64_GUEST_BNDCFGS_FULL,
569 VMX_VMCS64_GUEST_BNDCFGS_HIGH,
570
571 /* 64-bit host-state fields. */
572 VMX_VMCS64_HOST_PAT_FULL,
573 VMX_VMCS64_HOST_PAT_HIGH,
574 VMX_VMCS64_HOST_EFER_FULL,
575 VMX_VMCS64_HOST_EFER_HIGH,
576 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL,
577 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_HIGH,
578
579 /* 32-bit control fields. */
580 VMX_VMCS32_CTRL_PIN_EXEC,
581 VMX_VMCS32_CTRL_PROC_EXEC,
582 VMX_VMCS32_CTRL_EXCEPTION_BITMAP,
583 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK,
584 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH,
585 VMX_VMCS32_CTRL_CR3_TARGET_COUNT,
586 VMX_VMCS32_CTRL_EXIT,
587 VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT,
588 VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT,
589 VMX_VMCS32_CTRL_ENTRY,
590 VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT,
591 VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO,
592 VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE,
593 VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH,
594 VMX_VMCS32_CTRL_TPR_THRESHOLD,
595 VMX_VMCS32_CTRL_PROC_EXEC2,
596 VMX_VMCS32_CTRL_PLE_GAP,
597 VMX_VMCS32_CTRL_PLE_WINDOW,
598
599 /* 32-bits read-only fields. */
600 VMX_VMCS32_RO_VM_INSTR_ERROR,
601 VMX_VMCS32_RO_EXIT_REASON,
602 VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO,
603 VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE,
604 VMX_VMCS32_RO_IDT_VECTORING_INFO,
605 VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE,
606 VMX_VMCS32_RO_EXIT_INSTR_LENGTH,
607 VMX_VMCS32_RO_EXIT_INSTR_INFO,
608
609 /* 32-bit guest-state fields. */
610 VMX_VMCS32_GUEST_ES_LIMIT,
611 VMX_VMCS32_GUEST_CS_LIMIT,
612 VMX_VMCS32_GUEST_SS_LIMIT,
613 VMX_VMCS32_GUEST_DS_LIMIT,
614 VMX_VMCS32_GUEST_FS_LIMIT,
615 VMX_VMCS32_GUEST_GS_LIMIT,
616 VMX_VMCS32_GUEST_LDTR_LIMIT,
617 VMX_VMCS32_GUEST_TR_LIMIT,
618 VMX_VMCS32_GUEST_GDTR_LIMIT,
619 VMX_VMCS32_GUEST_IDTR_LIMIT,
620 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
621 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
622 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
623 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
624 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
625 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS,
626 VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS,
627 VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS,
628 VMX_VMCS32_GUEST_INT_STATE,
629 VMX_VMCS32_GUEST_ACTIVITY_STATE,
630 VMX_VMCS32_GUEST_SMBASE,
631 VMX_VMCS32_GUEST_SYSENTER_CS,
632 VMX_VMCS32_PREEMPT_TIMER_VALUE,
633
634 /* 32-bit host-state fields. */
635 VMX_VMCS32_HOST_SYSENTER_CS,
636
637 /* Natural-width control fields. */
638 VMX_VMCS_CTRL_CR0_MASK,
639 VMX_VMCS_CTRL_CR4_MASK,
640 VMX_VMCS_CTRL_CR0_READ_SHADOW,
641 VMX_VMCS_CTRL_CR4_READ_SHADOW,
642 VMX_VMCS_CTRL_CR3_TARGET_VAL0,
643 VMX_VMCS_CTRL_CR3_TARGET_VAL1,
644 VMX_VMCS_CTRL_CR3_TARGET_VAL2,
645 VMX_VMCS_CTRL_CR3_TARGET_VAL3,
646
647 /* Natural-width read-only data fields. */
648 VMX_VMCS_RO_EXIT_QUALIFICATION,
649 VMX_VMCS_RO_IO_RCX,
650 VMX_VMCS_RO_IO_RSI,
651 VMX_VMCS_RO_IO_RDI,
652 VMX_VMCS_RO_IO_RIP,
653 VMX_VMCS_RO_GUEST_LINEAR_ADDR,
654
655 /* Natural-width guest-state field */
656 VMX_VMCS_GUEST_CR0,
657 VMX_VMCS_GUEST_CR3,
658 VMX_VMCS_GUEST_CR4,
659 VMX_VMCS_GUEST_ES_BASE,
660 VMX_VMCS_GUEST_CS_BASE,
661 VMX_VMCS_GUEST_SS_BASE,
662 VMX_VMCS_GUEST_DS_BASE,
663 VMX_VMCS_GUEST_FS_BASE,
664 VMX_VMCS_GUEST_GS_BASE,
665 VMX_VMCS_GUEST_LDTR_BASE,
666 VMX_VMCS_GUEST_TR_BASE,
667 VMX_VMCS_GUEST_GDTR_BASE,
668 VMX_VMCS_GUEST_IDTR_BASE,
669 VMX_VMCS_GUEST_DR7,
670 VMX_VMCS_GUEST_RSP,
671 VMX_VMCS_GUEST_RIP,
672 VMX_VMCS_GUEST_RFLAGS,
673 VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS,
674 VMX_VMCS_GUEST_SYSENTER_ESP,
675 VMX_VMCS_GUEST_SYSENTER_EIP,
676
677 /* Natural-width host-state fields */
678 VMX_VMCS_HOST_CR0,
679 VMX_VMCS_HOST_CR3,
680 VMX_VMCS_HOST_CR4,
681 VMX_VMCS_HOST_FS_BASE,
682 VMX_VMCS_HOST_GS_BASE,
683 VMX_VMCS_HOST_TR_BASE,
684 VMX_VMCS_HOST_GDTR_BASE,
685 VMX_VMCS_HOST_IDTR_BASE,
686 VMX_VMCS_HOST_SYSENTER_ESP,
687 VMX_VMCS_HOST_SYSENTER_EIP,
688 VMX_VMCS_HOST_RSP,
689 VMX_VMCS_HOST_RIP
690};
691#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
692
693static const uint32_t g_aVmcsSegBase[] =
694{
695 VMX_VMCS_GUEST_ES_BASE,
696 VMX_VMCS_GUEST_CS_BASE,
697 VMX_VMCS_GUEST_SS_BASE,
698 VMX_VMCS_GUEST_DS_BASE,
699 VMX_VMCS_GUEST_FS_BASE,
700 VMX_VMCS_GUEST_GS_BASE
701};
702static const uint32_t g_aVmcsSegSel[] =
703{
704 VMX_VMCS16_GUEST_ES_SEL,
705 VMX_VMCS16_GUEST_CS_SEL,
706 VMX_VMCS16_GUEST_SS_SEL,
707 VMX_VMCS16_GUEST_DS_SEL,
708 VMX_VMCS16_GUEST_FS_SEL,
709 VMX_VMCS16_GUEST_GS_SEL
710};
711static const uint32_t g_aVmcsSegLimit[] =
712{
713 VMX_VMCS32_GUEST_ES_LIMIT,
714 VMX_VMCS32_GUEST_CS_LIMIT,
715 VMX_VMCS32_GUEST_SS_LIMIT,
716 VMX_VMCS32_GUEST_DS_LIMIT,
717 VMX_VMCS32_GUEST_FS_LIMIT,
718 VMX_VMCS32_GUEST_GS_LIMIT
719};
720static const uint32_t g_aVmcsSegAttr[] =
721{
722 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
723 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
724 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
725 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
726 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
727 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS
728};
729AssertCompile(RT_ELEMENTS(g_aVmcsSegSel) == X86_SREG_COUNT);
730AssertCompile(RT_ELEMENTS(g_aVmcsSegLimit) == X86_SREG_COUNT);
731AssertCompile(RT_ELEMENTS(g_aVmcsSegBase) == X86_SREG_COUNT);
732AssertCompile(RT_ELEMENTS(g_aVmcsSegAttr) == X86_SREG_COUNT);
733
734#ifdef HMVMX_USE_FUNCTION_TABLE
735/**
736 * VMX_EXIT dispatch table.
737 */
738static const PFNVMXEXITHANDLER g_apfnVMExitHandlers[VMX_EXIT_MAX + 1] =
739{
740 /* 0 VMX_EXIT_XCPT_OR_NMI */ hmR0VmxExitXcptOrNmi,
741 /* 1 VMX_EXIT_EXT_INT */ hmR0VmxExitExtInt,
742 /* 2 VMX_EXIT_TRIPLE_FAULT */ hmR0VmxExitTripleFault,
743 /* 3 VMX_EXIT_INIT_SIGNAL */ hmR0VmxExitErrUnexpected,
744 /* 4 VMX_EXIT_SIPI */ hmR0VmxExitErrUnexpected,
745 /* 5 VMX_EXIT_IO_SMI */ hmR0VmxExitErrUnexpected,
746 /* 6 VMX_EXIT_SMI */ hmR0VmxExitErrUnexpected,
747 /* 7 VMX_EXIT_INT_WINDOW */ hmR0VmxExitIntWindow,
748 /* 8 VMX_EXIT_NMI_WINDOW */ hmR0VmxExitNmiWindow,
749 /* 9 VMX_EXIT_TASK_SWITCH */ hmR0VmxExitTaskSwitch,
750 /* 10 VMX_EXIT_CPUID */ hmR0VmxExitCpuid,
751 /* 11 VMX_EXIT_GETSEC */ hmR0VmxExitGetsec,
752 /* 12 VMX_EXIT_HLT */ hmR0VmxExitHlt,
753 /* 13 VMX_EXIT_INVD */ hmR0VmxExitInvd,
754 /* 14 VMX_EXIT_INVLPG */ hmR0VmxExitInvlpg,
755 /* 15 VMX_EXIT_RDPMC */ hmR0VmxExitRdpmc,
756 /* 16 VMX_EXIT_RDTSC */ hmR0VmxExitRdtsc,
757 /* 17 VMX_EXIT_RSM */ hmR0VmxExitErrUnexpected,
758 /* 18 VMX_EXIT_VMCALL */ hmR0VmxExitVmcall,
759#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
760 /* 19 VMX_EXIT_VMCLEAR */ hmR0VmxExitVmclear,
761 /* 20 VMX_EXIT_VMLAUNCH */ hmR0VmxExitVmlaunch,
762 /* 21 VMX_EXIT_VMPTRLD */ hmR0VmxExitVmptrld,
763 /* 22 VMX_EXIT_VMPTRST */ hmR0VmxExitVmptrst,
764 /* 23 VMX_EXIT_VMREAD */ hmR0VmxExitVmread,
765 /* 24 VMX_EXIT_VMRESUME */ hmR0VmxExitVmresume,
766 /* 25 VMX_EXIT_VMWRITE */ hmR0VmxExitVmwrite,
767 /* 26 VMX_EXIT_VMXOFF */ hmR0VmxExitVmxoff,
768 /* 27 VMX_EXIT_VMXON */ hmR0VmxExitVmxon,
769#else
770 /* 19 VMX_EXIT_VMCLEAR */ hmR0VmxExitSetPendingXcptUD,
771 /* 20 VMX_EXIT_VMLAUNCH */ hmR0VmxExitSetPendingXcptUD,
772 /* 21 VMX_EXIT_VMPTRLD */ hmR0VmxExitSetPendingXcptUD,
773 /* 22 VMX_EXIT_VMPTRST */ hmR0VmxExitSetPendingXcptUD,
774 /* 23 VMX_EXIT_VMREAD */ hmR0VmxExitSetPendingXcptUD,
775 /* 24 VMX_EXIT_VMRESUME */ hmR0VmxExitSetPendingXcptUD,
776 /* 25 VMX_EXIT_VMWRITE */ hmR0VmxExitSetPendingXcptUD,
777 /* 26 VMX_EXIT_VMXOFF */ hmR0VmxExitSetPendingXcptUD,
778 /* 27 VMX_EXIT_VMXON */ hmR0VmxExitSetPendingXcptUD,
779#endif
780 /* 28 VMX_EXIT_MOV_CRX */ hmR0VmxExitMovCRx,
781 /* 29 VMX_EXIT_MOV_DRX */ hmR0VmxExitMovDRx,
782 /* 30 VMX_EXIT_IO_INSTR */ hmR0VmxExitIoInstr,
783 /* 31 VMX_EXIT_RDMSR */ hmR0VmxExitRdmsr,
784 /* 32 VMX_EXIT_WRMSR */ hmR0VmxExitWrmsr,
785 /* 33 VMX_EXIT_ERR_INVALID_GUEST_STATE */ hmR0VmxExitErrInvalidGuestState,
786 /* 34 VMX_EXIT_ERR_MSR_LOAD */ hmR0VmxExitErrUnexpected,
787 /* 35 UNDEFINED */ hmR0VmxExitErrUnexpected,
788 /* 36 VMX_EXIT_MWAIT */ hmR0VmxExitMwait,
789 /* 37 VMX_EXIT_MTF */ hmR0VmxExitMtf,
790 /* 38 UNDEFINED */ hmR0VmxExitErrUnexpected,
791 /* 39 VMX_EXIT_MONITOR */ hmR0VmxExitMonitor,
792 /* 40 VMX_EXIT_PAUSE */ hmR0VmxExitPause,
793 /* 41 VMX_EXIT_ERR_MACHINE_CHECK */ hmR0VmxExitErrUnexpected,
794 /* 42 UNDEFINED */ hmR0VmxExitErrUnexpected,
795 /* 43 VMX_EXIT_TPR_BELOW_THRESHOLD */ hmR0VmxExitTprBelowThreshold,
796 /* 44 VMX_EXIT_APIC_ACCESS */ hmR0VmxExitApicAccess,
797 /* 45 VMX_EXIT_VIRTUALIZED_EOI */ hmR0VmxExitErrUnexpected,
798 /* 46 VMX_EXIT_GDTR_IDTR_ACCESS */ hmR0VmxExitErrUnexpected,
799 /* 47 VMX_EXIT_LDTR_TR_ACCESS */ hmR0VmxExitErrUnexpected,
800 /* 48 VMX_EXIT_EPT_VIOLATION */ hmR0VmxExitEptViolation,
801 /* 49 VMX_EXIT_EPT_MISCONFIG */ hmR0VmxExitEptMisconfig,
802 /* 50 VMX_EXIT_INVEPT */ hmR0VmxExitSetPendingXcptUD,
803 /* 51 VMX_EXIT_RDTSCP */ hmR0VmxExitRdtscp,
804 /* 52 VMX_EXIT_PREEMPT_TIMER */ hmR0VmxExitPreemptTimer,
805#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
806 /* 53 VMX_EXIT_INVVPID */ hmR0VmxExitInvvpid,
807#else
808 /* 53 VMX_EXIT_INVVPID */ hmR0VmxExitSetPendingXcptUD,
809#endif
810 /* 54 VMX_EXIT_WBINVD */ hmR0VmxExitWbinvd,
811 /* 55 VMX_EXIT_XSETBV */ hmR0VmxExitXsetbv,
812 /* 56 VMX_EXIT_APIC_WRITE */ hmR0VmxExitErrUnexpected,
813 /* 57 VMX_EXIT_RDRAND */ hmR0VmxExitErrUnexpected,
814 /* 58 VMX_EXIT_INVPCID */ hmR0VmxExitInvpcid,
815 /* 59 VMX_EXIT_VMFUNC */ hmR0VmxExitErrUnexpected,
816 /* 60 VMX_EXIT_ENCLS */ hmR0VmxExitErrUnexpected,
817 /* 61 VMX_EXIT_RDSEED */ hmR0VmxExitErrUnexpected,
818 /* 62 VMX_EXIT_PML_FULL */ hmR0VmxExitErrUnexpected,
819 /* 63 VMX_EXIT_XSAVES */ hmR0VmxExitErrUnexpected,
820 /* 64 VMX_EXIT_XRSTORS */ hmR0VmxExitErrUnexpected,
821 /* 65 UNDEFINED */ hmR0VmxExitErrUnexpected,
822 /* 66 VMX_EXIT_SPP_EVENT */ hmR0VmxExitErrUnexpected,
823 /* 67 VMX_EXIT_UMWAIT */ hmR0VmxExitErrUnexpected,
824 /* 68 VMX_EXIT_TPAUSE */ hmR0VmxExitErrUnexpected,
825};
826#endif /* HMVMX_USE_FUNCTION_TABLE */
827
828#if defined(VBOX_STRICT) && defined(LOG_ENABLED)
829static const char * const g_apszVmxInstrErrors[HMVMX_INSTR_ERROR_MAX + 1] =
830{
831 /* 0 */ "(Not Used)",
832 /* 1 */ "VMCALL executed in VMX root operation.",
833 /* 2 */ "VMCLEAR with invalid physical address.",
834 /* 3 */ "VMCLEAR with VMXON pointer.",
835 /* 4 */ "VMLAUNCH with non-clear VMCS.",
836 /* 5 */ "VMRESUME with non-launched VMCS.",
837 /* 6 */ "VMRESUME after VMXOFF",
838 /* 7 */ "VM-entry with invalid control fields.",
839 /* 8 */ "VM-entry with invalid host state fields.",
840 /* 9 */ "VMPTRLD with invalid physical address.",
841 /* 10 */ "VMPTRLD with VMXON pointer.",
842 /* 11 */ "VMPTRLD with incorrect revision identifier.",
843 /* 12 */ "VMREAD/VMWRITE from/to unsupported VMCS component.",
844 /* 13 */ "VMWRITE to read-only VMCS component.",
845 /* 14 */ "(Not Used)",
846 /* 15 */ "VMXON executed in VMX root operation.",
847 /* 16 */ "VM-entry with invalid executive-VMCS pointer.",
848 /* 17 */ "VM-entry with non-launched executing VMCS.",
849 /* 18 */ "VM-entry with executive-VMCS pointer not VMXON pointer.",
850 /* 19 */ "VMCALL with non-clear VMCS.",
851 /* 20 */ "VMCALL with invalid VM-exit control fields.",
852 /* 21 */ "(Not Used)",
853 /* 22 */ "VMCALL with incorrect MSEG revision identifier.",
854 /* 23 */ "VMXOFF under dual monitor treatment of SMIs and SMM.",
855 /* 24 */ "VMCALL with invalid SMM-monitor features.",
856 /* 25 */ "VM-entry with invalid VM-execution control fields in executive VMCS.",
857 /* 26 */ "VM-entry with events blocked by MOV SS.",
858 /* 27 */ "(Not Used)",
859 /* 28 */ "Invalid operand to INVEPT/INVVPID."
860};
861#endif /* VBOX_STRICT && LOG_ENABLED */
862
863
864/**
865 * Gets the CR0 guest/host mask.
866 *
867 * These bits typically does not change through the lifetime of a VM. Any bit set in
868 * this mask is owned by the host/hypervisor and would cause a VM-exit when modified
869 * by the guest.
870 *
871 * @returns The CR0 guest/host mask.
872 * @param pVCpu The cross context virtual CPU structure.
873 */
874static uint64_t hmR0VmxGetFixedCr0Mask(PCVMCPUCC pVCpu)
875{
876 /*
877 * Modifications to CR0 bits that VT-x ignores saving/restoring (CD, ET, NW) and
878 * to CR0 bits that we require for shadow paging (PG) by the guest must cause VM-exits.
879 *
880 * Furthermore, modifications to any bits that are reserved/unspecified currently
881 * by the Intel spec. must also cause a VM-exit. This prevents unpredictable behavior
882 * when future CPUs specify and use currently reserved/unspecified bits.
883 */
884 /** @todo Avoid intercepting CR0.PE with unrestricted guest execution. Fix PGM
885 * enmGuestMode to be in-sync with the current mode. See @bugref{6398}
886 * and @bugref{6944}. */
887 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
888 return ( X86_CR0_PE
889 | X86_CR0_NE
890 | (pVM->hm.s.fNestedPaging ? 0 : X86_CR0_WP)
891 | X86_CR0_PG
892 | VMX_EXIT_HOST_CR0_IGNORE_MASK);
893}
894
895
896/**
897 * Gets the CR4 guest/host mask.
898 *
899 * These bits typically does not change through the lifetime of a VM. Any bit set in
900 * this mask is owned by the host/hypervisor and would cause a VM-exit when modified
901 * by the guest.
902 *
903 * @returns The CR4 guest/host mask.
904 * @param pVCpu The cross context virtual CPU structure.
905 */
906static uint64_t hmR0VmxGetFixedCr4Mask(PCVMCPUCC pVCpu)
907{
908 /*
909 * We construct a mask of all CR4 bits that the guest can modify without causing
910 * a VM-exit. Then invert this mask to obtain all CR4 bits that should cause
911 * a VM-exit when the guest attempts to modify them when executing using
912 * hardware-assisted VMX.
913 *
914 * When a feature is not exposed to the guest (and may be present on the host),
915 * we want to intercept guest modifications to the bit so we can emulate proper
916 * behavior (e.g., #GP).
917 *
918 * Furthermore, only modifications to those bits that don't require immediate
919 * emulation is allowed. For e.g., PCIDE is excluded because the behavior
920 * depends on CR3 which might not always be the guest value while executing
921 * using hardware-assisted VMX.
922 */
923 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
924 bool const fFsGsBase = pVM->cpum.ro.GuestFeatures.fFsGsBase;
925 bool const fXSaveRstor = pVM->cpum.ro.GuestFeatures.fXSaveRstor;
926 bool const fFxSaveRstor = pVM->cpum.ro.GuestFeatures.fFxSaveRstor;
927
928 /*
929 * Paranoia.
930 * Ensure features exposed to the guest are present on the host.
931 */
932 Assert(!fFsGsBase || pVM->cpum.ro.HostFeatures.fFsGsBase);
933 Assert(!fXSaveRstor || pVM->cpum.ro.HostFeatures.fXSaveRstor);
934 Assert(!fFxSaveRstor || pVM->cpum.ro.HostFeatures.fFxSaveRstor);
935
936 uint64_t const fGstMask = ( X86_CR4_PVI
937 | X86_CR4_TSD
938 | X86_CR4_DE
939 | X86_CR4_MCE
940 | X86_CR4_PCE
941 | X86_CR4_OSXMMEEXCPT
942 | (fFsGsBase ? X86_CR4_FSGSBASE : 0)
943 | (fXSaveRstor ? X86_CR4_OSXSAVE : 0)
944 | (fFxSaveRstor ? X86_CR4_OSFXSR : 0));
945 return ~fGstMask;
946}
947
948
949/**
950 * Returns whether the the VM-exit MSR-store area differs from the VM-exit MSR-load
951 * area.
952 *
953 * @returns @c true if it's different, @c false otherwise.
954 * @param pVmcsInfo The VMCS info. object.
955 */
956DECL_FORCE_INLINE(bool) hmR0VmxIsSeparateExitMsrStoreAreaVmcs(PCVMXVMCSINFO pVmcsInfo)
957{
958 return RT_BOOL( pVmcsInfo->pvGuestMsrStore != pVmcsInfo->pvGuestMsrLoad
959 && pVmcsInfo->pvGuestMsrStore);
960}
961
962
963/**
964 * Sets the given Processor-based VM-execution controls.
965 *
966 * @param pVmxTransient The VMX-transient structure.
967 * @param uProcCtls The Processor-based VM-execution controls to set.
968 */
969static void hmR0VmxSetProcCtlsVmcs(PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
970{
971 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
972 if ((pVmcsInfo->u32ProcCtls & uProcCtls) != uProcCtls)
973 {
974 pVmcsInfo->u32ProcCtls |= uProcCtls;
975 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
976 AssertRC(rc);
977 }
978}
979
980
981/**
982 * Removes the given Processor-based VM-execution controls.
983 *
984 * @param pVCpu The cross context virtual CPU structure.
985 * @param pVmxTransient The VMX-transient structure.
986 * @param uProcCtls The Processor-based VM-execution controls to remove.
987 *
988 * @remarks When executing a nested-guest, this will not remove any of the specified
989 * controls if the nested hypervisor has set any one of them.
990 */
991static void hmR0VmxRemoveProcCtlsVmcs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
992{
993 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
994 if (pVmcsInfo->u32ProcCtls & uProcCtls)
995 {
996#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
997 bool const fRemoveCtls = !pVmxTransient->fIsNestedGuest
998 ? true
999 : !CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, uProcCtls);
1000#else
1001 NOREF(pVCpu);
1002 bool const fRemoveCtls = true;
1003#endif
1004 if (fRemoveCtls)
1005 {
1006 pVmcsInfo->u32ProcCtls &= ~uProcCtls;
1007 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
1008 AssertRC(rc);
1009 }
1010 }
1011}
1012
1013
1014/**
1015 * Sets the TSC offset for the current VMCS.
1016 *
1017 * @param uTscOffset The TSC offset to set.
1018 * @param pVmcsInfo The VMCS info. object.
1019 */
1020static void hmR0VmxSetTscOffsetVmcs(PVMXVMCSINFO pVmcsInfo, uint64_t uTscOffset)
1021{
1022 if (pVmcsInfo->u64TscOffset != uTscOffset)
1023 {
1024 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, uTscOffset);
1025 AssertRC(rc);
1026 pVmcsInfo->u64TscOffset = uTscOffset;
1027 }
1028}
1029
1030
1031/**
1032 * Adds one or more exceptions to the exception bitmap and commits it to the current
1033 * VMCS.
1034 *
1035 * @param pVmxTransient The VMX-transient structure.
1036 * @param uXcptMask The exception(s) to add.
1037 */
1038static void hmR0VmxAddXcptInterceptMask(PCVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1039{
1040 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1041 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
1042 if ((uXcptBitmap & uXcptMask) != uXcptMask)
1043 {
1044 uXcptBitmap |= uXcptMask;
1045 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
1046 AssertRC(rc);
1047 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
1048 }
1049}
1050
1051
1052/**
1053 * Adds an exception to the exception bitmap and commits it to the current VMCS.
1054 *
1055 * @param pVmxTransient The VMX-transient structure.
1056 * @param uXcpt The exception to add.
1057 */
1058static void hmR0VmxAddXcptIntercept(PCVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1059{
1060 Assert(uXcpt <= X86_XCPT_LAST);
1061 hmR0VmxAddXcptInterceptMask(pVmxTransient, RT_BIT_32(uXcpt));
1062}
1063
1064
1065/**
1066 * Remove one or more exceptions from the exception bitmap and commits it to the
1067 * current VMCS.
1068 *
1069 * This takes care of not removing the exception intercept if a nested-guest
1070 * requires the exception to be intercepted.
1071 *
1072 * @returns VBox status code.
1073 * @param pVCpu The cross context virtual CPU structure.
1074 * @param pVmxTransient The VMX-transient structure.
1075 * @param uXcptMask The exception(s) to remove.
1076 */
1077static int hmR0VmxRemoveXcptInterceptMask(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1078{
1079 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1080 uint32_t u32XcptBitmap = pVmcsInfo->u32XcptBitmap;
1081 if (u32XcptBitmap & uXcptMask)
1082 {
1083#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1084 if (!pVmxTransient->fIsNestedGuest)
1085 { /* likely */ }
1086 else
1087 {
1088 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
1089 uXcptMask &= ~pVmcsNstGst->u32XcptBitmap;
1090 }
1091#endif
1092#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
1093 uXcptMask &= ~( RT_BIT(X86_XCPT_BP)
1094 | RT_BIT(X86_XCPT_DE)
1095 | RT_BIT(X86_XCPT_NM)
1096 | RT_BIT(X86_XCPT_TS)
1097 | RT_BIT(X86_XCPT_UD)
1098 | RT_BIT(X86_XCPT_NP)
1099 | RT_BIT(X86_XCPT_SS)
1100 | RT_BIT(X86_XCPT_GP)
1101 | RT_BIT(X86_XCPT_PF)
1102 | RT_BIT(X86_XCPT_MF));
1103#elif defined(HMVMX_ALWAYS_TRAP_PF)
1104 uXcptMask &= ~RT_BIT(X86_XCPT_PF);
1105#endif
1106 if (uXcptMask)
1107 {
1108 /* Validate we are not removing any essential exception intercepts. */
1109 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging || !(uXcptMask & RT_BIT(X86_XCPT_PF)));
1110 NOREF(pVCpu);
1111 Assert(!(uXcptMask & RT_BIT(X86_XCPT_DB)));
1112 Assert(!(uXcptMask & RT_BIT(X86_XCPT_AC)));
1113
1114 /* Remove it from the exception bitmap. */
1115 u32XcptBitmap &= ~uXcptMask;
1116
1117 /* Commit and update the cache if necessary. */
1118 if (pVmcsInfo->u32XcptBitmap != u32XcptBitmap)
1119 {
1120 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
1121 AssertRC(rc);
1122 pVmcsInfo->u32XcptBitmap = u32XcptBitmap;
1123 }
1124 }
1125 }
1126 return VINF_SUCCESS;
1127}
1128
1129
1130/**
1131 * Remove an exceptions from the exception bitmap and commits it to the current
1132 * VMCS.
1133 *
1134 * @returns VBox status code.
1135 * @param pVCpu The cross context virtual CPU structure.
1136 * @param pVmxTransient The VMX-transient structure.
1137 * @param uXcpt The exception to remove.
1138 */
1139static int hmR0VmxRemoveXcptIntercept(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1140{
1141 return hmR0VmxRemoveXcptInterceptMask(pVCpu, pVmxTransient, RT_BIT(uXcpt));
1142}
1143
1144
1145/**
1146 * Loads the VMCS specified by the VMCS info. object.
1147 *
1148 * @returns VBox status code.
1149 * @param pVmcsInfo The VMCS info. object.
1150 *
1151 * @remarks Can be called with interrupts disabled.
1152 */
1153static int hmR0VmxLoadVmcs(PVMXVMCSINFO pVmcsInfo)
1154{
1155 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1156 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1157
1158 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysVmcs);
1159 if (RT_SUCCESS(rc))
1160 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1161 return rc;
1162}
1163
1164
1165/**
1166 * Clears the VMCS specified by the VMCS info. object.
1167 *
1168 * @returns VBox status code.
1169 * @param pVmcsInfo The VMCS info. object.
1170 *
1171 * @remarks Can be called with interrupts disabled.
1172 */
1173static int hmR0VmxClearVmcs(PVMXVMCSINFO pVmcsInfo)
1174{
1175 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1176 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1177
1178 int rc = VMXClearVmcs(pVmcsInfo->HCPhysVmcs);
1179 if (RT_SUCCESS(rc))
1180 pVmcsInfo->fVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1181 return rc;
1182}
1183
1184
1185#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1186/**
1187 * Loads the shadow VMCS specified by the VMCS info. object.
1188 *
1189 * @returns VBox status code.
1190 * @param pVmcsInfo The VMCS info. object.
1191 *
1192 * @remarks Can be called with interrupts disabled.
1193 */
1194static int hmR0VmxLoadShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1195{
1196 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1197 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1198
1199 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysShadowVmcs);
1200 if (RT_SUCCESS(rc))
1201 pVmcsInfo->fShadowVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1202 return rc;
1203}
1204
1205
1206/**
1207 * Clears the shadow VMCS specified by the VMCS info. object.
1208 *
1209 * @returns VBox status code.
1210 * @param pVmcsInfo The VMCS info. object.
1211 *
1212 * @remarks Can be called with interrupts disabled.
1213 */
1214static int hmR0VmxClearShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1215{
1216 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1217 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1218
1219 int rc = VMXClearVmcs(pVmcsInfo->HCPhysShadowVmcs);
1220 if (RT_SUCCESS(rc))
1221 pVmcsInfo->fShadowVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1222 return rc;
1223}
1224
1225
1226/**
1227 * Switches from and to the specified VMCSes.
1228 *
1229 * @returns VBox status code.
1230 * @param pVmcsInfoFrom The VMCS info. object we are switching from.
1231 * @param pVmcsInfoTo The VMCS info. object we are switching to.
1232 *
1233 * @remarks Called with interrupts disabled.
1234 */
1235static int hmR0VmxSwitchVmcs(PVMXVMCSINFO pVmcsInfoFrom, PVMXVMCSINFO pVmcsInfoTo)
1236{
1237 /*
1238 * Clear the VMCS we are switching out if it has not already been cleared.
1239 * This will sync any CPU internal data back to the VMCS.
1240 */
1241 if (pVmcsInfoFrom->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1242 {
1243 int rc = hmR0VmxClearVmcs(pVmcsInfoFrom);
1244 if (RT_SUCCESS(rc))
1245 {
1246 /*
1247 * The shadow VMCS, if any, would not be active at this point since we
1248 * would have cleared it while importing the virtual hardware-virtualization
1249 * state as part the VMLAUNCH/VMRESUME VM-exit. Hence, there's no need to
1250 * clear the shadow VMCS here, just assert for safety.
1251 */
1252 Assert(!pVmcsInfoFrom->pvShadowVmcs || pVmcsInfoFrom->fShadowVmcsState == VMX_V_VMCS_LAUNCH_STATE_CLEAR);
1253 }
1254 else
1255 return rc;
1256 }
1257
1258 /*
1259 * Clear the VMCS we are switching to if it has not already been cleared.
1260 * This will initialize the VMCS launch state to "clear" required for loading it.
1261 *
1262 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
1263 */
1264 if (pVmcsInfoTo->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1265 {
1266 int rc = hmR0VmxClearVmcs(pVmcsInfoTo);
1267 if (RT_SUCCESS(rc))
1268 { /* likely */ }
1269 else
1270 return rc;
1271 }
1272
1273 /*
1274 * Finally, load the VMCS we are switching to.
1275 */
1276 return hmR0VmxLoadVmcs(pVmcsInfoTo);
1277}
1278
1279
1280/**
1281 * Switches between the guest VMCS and the nested-guest VMCS as specified by the
1282 * caller.
1283 *
1284 * @returns VBox status code.
1285 * @param pVCpu The cross context virtual CPU structure.
1286 * @param fSwitchToNstGstVmcs Whether to switch to the nested-guest VMCS (pass
1287 * true) or guest VMCS (pass false).
1288 */
1289static int hmR0VmxSwitchToGstOrNstGstVmcs(PVMCPUCC pVCpu, bool fSwitchToNstGstVmcs)
1290{
1291 /* Ensure we have synced everything from the guest-CPU context to the VMCS before switching. */
1292 HMVMX_CPUMCTX_ASSERT(pVCpu, HMVMX_CPUMCTX_EXTRN_ALL);
1293
1294 PVMXVMCSINFO pVmcsInfoFrom;
1295 PVMXVMCSINFO pVmcsInfoTo;
1296 if (fSwitchToNstGstVmcs)
1297 {
1298 pVmcsInfoFrom = &pVCpu->hm.s.vmx.VmcsInfo;
1299 pVmcsInfoTo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
1300 }
1301 else
1302 {
1303 pVmcsInfoFrom = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
1304 pVmcsInfoTo = &pVCpu->hm.s.vmx.VmcsInfo;
1305 }
1306
1307 /*
1308 * Disable interrupts to prevent being preempted while we switch the current VMCS as the
1309 * preemption hook code path acquires the current VMCS.
1310 */
1311 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1312
1313 int rc = hmR0VmxSwitchVmcs(pVmcsInfoFrom, pVmcsInfoTo);
1314 if (RT_SUCCESS(rc))
1315 {
1316 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs = fSwitchToNstGstVmcs;
1317
1318 /*
1319 * If we are switching to a VMCS that was executed on a different host CPU or was
1320 * never executed before, flag that we need to export the host state before executing
1321 * guest/nested-guest code using hardware-assisted VMX.
1322 *
1323 * This could probably be done in a preemptible context since the preemption hook
1324 * will flag the necessary change in host context. However, since preemption is
1325 * already disabled and to avoid making assumptions about host specific code in
1326 * RTMpCpuId when called with preemption enabled, we'll do this while preemption is
1327 * disabled.
1328 */
1329 if (pVmcsInfoTo->idHostCpuState == RTMpCpuId())
1330 { /* likely */ }
1331 else
1332 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE);
1333
1334 ASMSetFlags(fEFlags);
1335
1336 /*
1337 * We use a different VM-exit MSR-store areas for the guest and nested-guest. Hence,
1338 * flag that we need to update the host MSR values there. Even if we decide in the
1339 * future to share the VM-exit MSR-store area page between the guest and nested-guest,
1340 * if its content differs, we would have to update the host MSRs anyway.
1341 */
1342 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
1343 }
1344 else
1345 ASMSetFlags(fEFlags);
1346 return rc;
1347}
1348#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
1349
1350
1351/**
1352 * Updates the VM's last error record.
1353 *
1354 * If there was a VMX instruction error, reads the error data from the VMCS and
1355 * updates VCPU's last error record as well.
1356 *
1357 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1358 * Can be NULL if @a rc is not VERR_VMX_UNABLE_TO_START_VM or
1359 * VERR_VMX_INVALID_VMCS_FIELD.
1360 * @param rc The error code.
1361 */
1362static void hmR0VmxUpdateErrorRecord(PVMCPUCC pVCpu, int rc)
1363{
1364 if ( rc == VERR_VMX_INVALID_VMCS_FIELD
1365 || rc == VERR_VMX_UNABLE_TO_START_VM)
1366 {
1367 AssertPtrReturnVoid(pVCpu);
1368 VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
1369 }
1370 pVCpu->CTX_SUFF(pVM)->hm.s.rcInit = rc;
1371}
1372
1373
1374#ifdef VBOX_STRICT
1375/**
1376 * Reads the VM-entry interruption-information field from the VMCS into the VMX
1377 * transient structure.
1378 *
1379 * @param pVmxTransient The VMX-transient structure.
1380 */
1381DECLINLINE(void) hmR0VmxReadEntryIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1382{
1383 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntInfo);
1384 AssertRC(rc);
1385}
1386
1387
1388/**
1389 * Reads the VM-entry exception error code field from the VMCS into
1390 * the VMX transient structure.
1391 *
1392 * @param pVmxTransient The VMX-transient structure.
1393 */
1394DECLINLINE(void) hmR0VmxReadEntryXcptErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1395{
1396 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
1397 AssertRC(rc);
1398}
1399
1400
1401/**
1402 * Reads the VM-entry exception error code field from the VMCS into
1403 * the VMX transient structure.
1404 *
1405 * @param pVmxTransient The VMX-transient structure.
1406 */
1407DECLINLINE(void) hmR0VmxReadEntryInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1408{
1409 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
1410 AssertRC(rc);
1411}
1412#endif /* VBOX_STRICT */
1413
1414
1415/**
1416 * Reads the VM-exit interruption-information field from the VMCS into the VMX
1417 * transient structure.
1418 *
1419 * @param pVmxTransient The VMX-transient structure.
1420 */
1421DECLINLINE(void) hmR0VmxReadExitIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1422{
1423 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_INFO))
1424 {
1425 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1426 AssertRC(rc);
1427 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_INFO;
1428 }
1429}
1430
1431
1432/**
1433 * Reads the VM-exit interruption error code from the VMCS into the VMX
1434 * transient structure.
1435 *
1436 * @param pVmxTransient The VMX-transient structure.
1437 */
1438DECLINLINE(void) hmR0VmxReadExitIntErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1439{
1440 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE))
1441 {
1442 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1443 AssertRC(rc);
1444 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE;
1445 }
1446}
1447
1448
1449/**
1450 * Reads the VM-exit instruction length field from the VMCS into the VMX
1451 * transient structure.
1452 *
1453 * @param pVmxTransient The VMX-transient structure.
1454 */
1455DECLINLINE(void) hmR0VmxReadExitInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1456{
1457 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_LEN))
1458 {
1459 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1460 AssertRC(rc);
1461 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_LEN;
1462 }
1463}
1464
1465
1466/**
1467 * Reads the VM-exit instruction-information field from the VMCS into
1468 * the VMX transient structure.
1469 *
1470 * @param pVmxTransient The VMX-transient structure.
1471 */
1472DECLINLINE(void) hmR0VmxReadExitInstrInfoVmcs(PVMXTRANSIENT pVmxTransient)
1473{
1474 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_INFO))
1475 {
1476 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1477 AssertRC(rc);
1478 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_INFO;
1479 }
1480}
1481
1482
1483/**
1484 * Reads the Exit Qualification from the VMCS into the VMX transient structure.
1485 *
1486 * @param pVmxTransient The VMX-transient structure.
1487 */
1488DECLINLINE(void) hmR0VmxReadExitQualVmcs(PVMXTRANSIENT pVmxTransient)
1489{
1490 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_QUALIFICATION))
1491 {
1492 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1493 AssertRC(rc);
1494 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION;
1495 }
1496}
1497
1498
1499/**
1500 * Reads the Guest-linear address from the VMCS into the VMX transient structure.
1501 *
1502 * @param pVmxTransient The VMX-transient structure.
1503 */
1504DECLINLINE(void) hmR0VmxReadGuestLinearAddrVmcs(PVMXTRANSIENT pVmxTransient)
1505{
1506 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_LINEAR_ADDR))
1507 {
1508 int rc = VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1509 AssertRC(rc);
1510 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_LINEAR_ADDR;
1511 }
1512}
1513
1514
1515/**
1516 * Reads the Guest-physical address from the VMCS into the VMX transient structure.
1517 *
1518 * @param pVmxTransient The VMX-transient structure.
1519 */
1520DECLINLINE(void) hmR0VmxReadGuestPhysicalAddrVmcs(PVMXTRANSIENT pVmxTransient)
1521{
1522 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PHYSICAL_ADDR))
1523 {
1524 int rc = VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1525 AssertRC(rc);
1526 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PHYSICAL_ADDR;
1527 }
1528}
1529
1530#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1531/**
1532 * Reads the Guest pending-debug exceptions from the VMCS into the VMX transient
1533 * structure.
1534 *
1535 * @param pVmxTransient The VMX-transient structure.
1536 */
1537DECLINLINE(void) hmR0VmxReadGuestPendingDbgXctps(PVMXTRANSIENT pVmxTransient)
1538{
1539 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PENDING_DBG_XCPTS))
1540 {
1541 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &pVmxTransient->uGuestPendingDbgXcpts);
1542 AssertRC(rc);
1543 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PENDING_DBG_XCPTS;
1544 }
1545}
1546#endif
1547
1548/**
1549 * Reads the IDT-vectoring information field from the VMCS into the VMX
1550 * transient structure.
1551 *
1552 * @param pVmxTransient The VMX-transient structure.
1553 *
1554 * @remarks No-long-jump zone!!!
1555 */
1556DECLINLINE(void) hmR0VmxReadIdtVectoringInfoVmcs(PVMXTRANSIENT pVmxTransient)
1557{
1558 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_INFO))
1559 {
1560 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1561 AssertRC(rc);
1562 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_INFO;
1563 }
1564}
1565
1566
1567/**
1568 * Reads the IDT-vectoring error code from the VMCS into the VMX
1569 * transient structure.
1570 *
1571 * @param pVmxTransient The VMX-transient structure.
1572 */
1573DECLINLINE(void) hmR0VmxReadIdtVectoringErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1574{
1575 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_ERROR_CODE))
1576 {
1577 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1578 AssertRC(rc);
1579 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_ERROR_CODE;
1580 }
1581}
1582
1583#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
1584/**
1585 * Reads all relevant read-only VMCS fields into the VMX transient structure.
1586 *
1587 * @param pVmxTransient The VMX-transient structure.
1588 */
1589static void hmR0VmxReadAllRoFieldsVmcs(PVMXTRANSIENT pVmxTransient)
1590{
1591 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1592 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1593 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1594 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1595 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1596 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1597 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1598 rc |= VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1599 rc |= VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1600 AssertRC(rc);
1601 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION
1602 | HMVMX_READ_EXIT_INSTR_LEN
1603 | HMVMX_READ_EXIT_INSTR_INFO
1604 | HMVMX_READ_IDT_VECTORING_INFO
1605 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
1606 | HMVMX_READ_EXIT_INTERRUPTION_INFO
1607 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
1608 | HMVMX_READ_GUEST_LINEAR_ADDR
1609 | HMVMX_READ_GUEST_PHYSICAL_ADDR;
1610}
1611#endif
1612
1613/**
1614 * Enters VMX root mode operation on the current CPU.
1615 *
1616 * @returns VBox status code.
1617 * @param pHostCpu The HM physical-CPU structure.
1618 * @param pVM The cross context VM structure. Can be
1619 * NULL, after a resume.
1620 * @param HCPhysCpuPage Physical address of the VMXON region.
1621 * @param pvCpuPage Pointer to the VMXON region.
1622 */
1623static int hmR0VmxEnterRootMode(PHMPHYSCPU pHostCpu, PVMCC pVM, RTHCPHYS HCPhysCpuPage, void *pvCpuPage)
1624{
1625 Assert(pHostCpu);
1626 Assert(HCPhysCpuPage && HCPhysCpuPage != NIL_RTHCPHYS);
1627 Assert(RT_ALIGN_T(HCPhysCpuPage, _4K, RTHCPHYS) == HCPhysCpuPage);
1628 Assert(pvCpuPage);
1629 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1630
1631 if (pVM)
1632 {
1633 /* Write the VMCS revision identifier to the VMXON region. */
1634 *(uint32_t *)pvCpuPage = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
1635 }
1636
1637 /* Paranoid: Disable interrupts as, in theory, interrupt handlers might mess with CR4. */
1638 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1639
1640 /* Enable the VMX bit in CR4 if necessary. */
1641 RTCCUINTREG const uOldCr4 = SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
1642
1643 /* Record whether VMXE was already prior to us enabling it above. */
1644 pHostCpu->fVmxeAlreadyEnabled = RT_BOOL(uOldCr4 & X86_CR4_VMXE);
1645
1646 /* Enter VMX root mode. */
1647 int rc = VMXEnable(HCPhysCpuPage);
1648 if (RT_FAILURE(rc))
1649 {
1650 /* Restore CR4.VMXE if it was not set prior to our attempt to set it above. */
1651 if (!pHostCpu->fVmxeAlreadyEnabled)
1652 SUPR0ChangeCR4(0 /* fOrMask */, ~(uint64_t)X86_CR4_VMXE);
1653
1654 if (pVM)
1655 pVM->hm.s.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
1656 }
1657
1658 /* Restore interrupts. */
1659 ASMSetFlags(fEFlags);
1660 return rc;
1661}
1662
1663
1664/**
1665 * Exits VMX root mode operation on the current CPU.
1666 *
1667 * @returns VBox status code.
1668 * @param pHostCpu The HM physical-CPU structure.
1669 */
1670static int hmR0VmxLeaveRootMode(PHMPHYSCPU pHostCpu)
1671{
1672 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1673
1674 /* Paranoid: Disable interrupts as, in theory, interrupts handlers might mess with CR4. */
1675 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1676
1677 /* If we're for some reason not in VMX root mode, then don't leave it. */
1678 RTCCUINTREG const uHostCr4 = ASMGetCR4();
1679
1680 int rc;
1681 if (uHostCr4 & X86_CR4_VMXE)
1682 {
1683 /* Exit VMX root mode and clear the VMX bit in CR4. */
1684 VMXDisable();
1685
1686 /* Clear CR4.VMXE only if it was clear prior to use setting it. */
1687 if (!pHostCpu->fVmxeAlreadyEnabled)
1688 SUPR0ChangeCR4(0 /* fOrMask */, ~(uint64_t)X86_CR4_VMXE);
1689
1690 rc = VINF_SUCCESS;
1691 }
1692 else
1693 rc = VERR_VMX_NOT_IN_VMX_ROOT_MODE;
1694
1695 /* Restore interrupts. */
1696 ASMSetFlags(fEFlags);
1697 return rc;
1698}
1699
1700
1701/**
1702 * Allocates pages specified as specified by an array of VMX page allocation info
1703 * objects.
1704 *
1705 * The pages contents are zero'd after allocation.
1706 *
1707 * @returns VBox status code.
1708 * @param hMemObj The ring-0 memory object associated with the allocation.
1709 * @param paAllocInfo The pointer to the first element of the VMX
1710 * page-allocation info object array.
1711 * @param cEntries The number of elements in the @a paAllocInfo array.
1712 */
1713static int hmR0VmxPagesAllocZ(RTR0MEMOBJ hMemObj, PVMXPAGEALLOCINFO paAllocInfo, uint32_t cEntries)
1714{
1715 /* Figure out how many pages to allocate. */
1716 uint32_t cPages = 0;
1717 for (uint32_t iPage = 0; iPage < cEntries; iPage++)
1718 cPages += !!paAllocInfo[iPage].fValid;
1719
1720 /* Allocate the pages. */
1721 if (cPages)
1722 {
1723 size_t const cbPages = cPages << X86_PAGE_4K_SHIFT;
1724 int rc = RTR0MemObjAllocPage(&hMemObj, cbPages, false /* fExecutable */);
1725 if (RT_FAILURE(rc))
1726 return rc;
1727
1728 /* Zero the contents and assign each page to the corresponding VMX page-allocation entry. */
1729 void *pvFirstPage = RTR0MemObjAddress(hMemObj);
1730 ASMMemZero32(pvFirstPage, cbPages);
1731
1732 uint32_t iPage = 0;
1733 for (uint32_t i = 0; i < cEntries; i++)
1734 if (paAllocInfo[i].fValid)
1735 {
1736 RTHCPHYS const HCPhysPage = RTR0MemObjGetPagePhysAddr(hMemObj, iPage);
1737 void *pvPage = (void *)((uintptr_t)pvFirstPage + (iPage << X86_PAGE_4K_SHIFT));
1738 Assert(HCPhysPage && HCPhysPage != NIL_RTHCPHYS);
1739 AssertPtr(pvPage);
1740
1741 Assert(paAllocInfo[iPage].pHCPhys);
1742 Assert(paAllocInfo[iPage].ppVirt);
1743 *paAllocInfo[iPage].pHCPhys = HCPhysPage;
1744 *paAllocInfo[iPage].ppVirt = pvPage;
1745
1746 /* Move to next page. */
1747 ++iPage;
1748 }
1749
1750 /* Make sure all valid (requested) pages have been assigned. */
1751 Assert(iPage == cPages);
1752 }
1753 return VINF_SUCCESS;
1754}
1755
1756
1757/**
1758 * Frees pages allocated using hmR0VmxPagesAllocZ.
1759 *
1760 * @param hMemObj The ring-0 memory object associated with the allocation.
1761 */
1762DECL_FORCE_INLINE(void) hmR0VmxPagesFree(RTR0MEMOBJ hMemObj)
1763{
1764 /* We can cleanup wholesale since it's all one allocation. */
1765 RTR0MemObjFree(hMemObj, true /* fFreeMappings */);
1766}
1767
1768
1769/**
1770 * Initializes a VMCS info. object.
1771 *
1772 * @param pVmcsInfo The VMCS info. object.
1773 */
1774static void hmR0VmxVmcsInfoInit(PVMXVMCSINFO pVmcsInfo)
1775{
1776 memset(pVmcsInfo, 0, sizeof(*pVmcsInfo));
1777
1778 Assert(pVmcsInfo->hMemObj == NIL_RTR0MEMOBJ);
1779 pVmcsInfo->HCPhysVmcs = NIL_RTHCPHYS;
1780 pVmcsInfo->HCPhysShadowVmcs = NIL_RTHCPHYS;
1781 pVmcsInfo->HCPhysMsrBitmap = NIL_RTHCPHYS;
1782 pVmcsInfo->HCPhysGuestMsrLoad = NIL_RTHCPHYS;
1783 pVmcsInfo->HCPhysGuestMsrStore = NIL_RTHCPHYS;
1784 pVmcsInfo->HCPhysHostMsrLoad = NIL_RTHCPHYS;
1785 pVmcsInfo->HCPhysVirtApic = NIL_RTHCPHYS;
1786 pVmcsInfo->HCPhysEPTP = NIL_RTHCPHYS;
1787 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
1788 pVmcsInfo->idHostCpuState = NIL_RTCPUID;
1789 pVmcsInfo->idHostCpuExec = NIL_RTCPUID;
1790}
1791
1792
1793/**
1794 * Frees the VT-x structures for a VMCS info. object.
1795 *
1796 * @param pVmcsInfo The VMCS info. object.
1797 */
1798static void hmR0VmxVmcsInfoFree(PVMXVMCSINFO pVmcsInfo)
1799{
1800 if (pVmcsInfo->hMemObj != NIL_RTR0MEMOBJ)
1801 {
1802 hmR0VmxPagesFree(pVmcsInfo->hMemObj);
1803 hmR0VmxVmcsInfoInit(pVmcsInfo);
1804 }
1805}
1806
1807
1808/**
1809 * Allocates the VT-x structures for a VMCS info. object.
1810 *
1811 * @returns VBox status code.
1812 * @param pVCpu The cross context virtual CPU structure.
1813 * @param pVmcsInfo The VMCS info. object.
1814 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
1815 *
1816 * @remarks The caller is expected to take care of any and all allocation failures.
1817 * This function will not perform any cleanup for failures half-way
1818 * through.
1819 */
1820static int hmR0VmxAllocVmcsInfo(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
1821{
1822 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
1823
1824 bool const fMsrBitmaps = RT_BOOL(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS);
1825 bool const fShadowVmcs = !fIsNstGstVmcs ? pVM->hm.s.vmx.fUseVmcsShadowing : pVM->cpum.ro.GuestFeatures.fVmxVmcsShadowing;
1826 Assert(!pVM->cpum.ro.GuestFeatures.fVmxVmcsShadowing); /* VMCS shadowing is not yet exposed to the guest. */
1827 VMXPAGEALLOCINFO aAllocInfo[] = {
1828 { true, 0 /* Unused */, &pVmcsInfo->HCPhysVmcs, &pVmcsInfo->pvVmcs },
1829 { true, 0 /* Unused */, &pVmcsInfo->HCPhysGuestMsrLoad, &pVmcsInfo->pvGuestMsrLoad },
1830 { true, 0 /* Unused */, &pVmcsInfo->HCPhysHostMsrLoad, &pVmcsInfo->pvHostMsrLoad },
1831 { fMsrBitmaps, 0 /* Unused */, &pVmcsInfo->HCPhysMsrBitmap, &pVmcsInfo->pvMsrBitmap },
1832 { fShadowVmcs, 0 /* Unused */, &pVmcsInfo->HCPhysShadowVmcs, &pVmcsInfo->pvShadowVmcs },
1833 };
1834
1835 int rc = hmR0VmxPagesAllocZ(pVmcsInfo->hMemObj, &aAllocInfo[0], RT_ELEMENTS(aAllocInfo));
1836 if (RT_FAILURE(rc))
1837 return rc;
1838
1839 /*
1840 * We use the same page for VM-entry MSR-load and VM-exit MSR store areas.
1841 * Because they contain a symmetric list of guest MSRs to load on VM-entry and store on VM-exit.
1842 */
1843 AssertCompile(RT_ELEMENTS(aAllocInfo) > 0);
1844 Assert(pVmcsInfo->HCPhysGuestMsrLoad != NIL_RTHCPHYS);
1845 pVmcsInfo->pvGuestMsrStore = pVmcsInfo->pvGuestMsrLoad;
1846 pVmcsInfo->HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrLoad;
1847
1848 /*
1849 * Get the virtual-APIC page rather than allocating them again.
1850 */
1851 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW)
1852 {
1853 if (!fIsNstGstVmcs)
1854 {
1855 if (PDMHasApic(pVM))
1856 {
1857 rc = APICGetApicPageForCpu(pVCpu, &pVmcsInfo->HCPhysVirtApic, (PRTR0PTR)&pVmcsInfo->pbVirtApic, NULL /*pR3Ptr*/);
1858 if (RT_FAILURE(rc))
1859 return rc;
1860 Assert(pVmcsInfo->pbVirtApic);
1861 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1862 }
1863 }
1864 else
1865 {
1866 pVmcsInfo->pbVirtApic = (uint8_t *)CPUMGetGuestVmxVirtApicPage(&pVCpu->cpum.GstCtx, &pVmcsInfo->HCPhysVirtApic);
1867 Assert(pVmcsInfo->pbVirtApic);
1868 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1869 }
1870 }
1871
1872 return VINF_SUCCESS;
1873}
1874
1875
1876/**
1877 * Free all VT-x structures for the VM.
1878 *
1879 * @returns IPRT status code.
1880 * @param pVM The cross context VM structure.
1881 */
1882static void hmR0VmxStructsFree(PVMCC pVM)
1883{
1884 hmR0VmxPagesFree(pVM->hm.s.vmx.hMemObj);
1885#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1886 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1887 {
1888 RTMemFree(pVM->hm.s.vmx.paShadowVmcsFields);
1889 RTMemFree(pVM->hm.s.vmx.paShadowVmcsRoFields);
1890 }
1891#endif
1892
1893 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1894 {
1895 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
1896 hmR0VmxVmcsInfoFree(&pVCpu->hm.s.vmx.VmcsInfo);
1897#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1898 if (pVM->cpum.ro.GuestFeatures.fVmx)
1899 hmR0VmxVmcsInfoFree(&pVCpu->hm.s.vmx.VmcsInfoNstGst);
1900#endif
1901 }
1902}
1903
1904
1905/**
1906 * Allocate all VT-x structures for the VM.
1907 *
1908 * @returns IPRT status code.
1909 * @param pVM The cross context VM structure.
1910 *
1911 * @remarks This functions will cleanup on memory allocation failures.
1912 */
1913static int hmR0VmxStructsAlloc(PVMCC pVM)
1914{
1915 /*
1916 * Sanity check the VMCS size reported by the CPU as we assume 4KB allocations.
1917 * The VMCS size cannot be more than 4096 bytes.
1918 *
1919 * See Intel spec. Appendix A.1 "Basic VMX Information".
1920 */
1921 uint32_t const cbVmcs = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_SIZE);
1922 if (cbVmcs <= X86_PAGE_4K_SIZE)
1923 { /* likely */ }
1924 else
1925 {
1926 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_INVALID_VMCS_SIZE;
1927 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1928 }
1929
1930 /*
1931 * Allocate per-VM VT-x structures.
1932 */
1933 bool const fVirtApicAccess = RT_BOOL(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
1934 bool const fUseVmcsShadowing = pVM->hm.s.vmx.fUseVmcsShadowing;
1935 VMXPAGEALLOCINFO aAllocInfo[] = {
1936 { fVirtApicAccess, 0 /* Unused */, &pVM->hm.s.vmx.HCPhysApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess },
1937 { fUseVmcsShadowing, 0 /* Unused */, &pVM->hm.s.vmx.HCPhysVmreadBitmap, &pVM->hm.s.vmx.pvVmreadBitmap },
1938 { fUseVmcsShadowing, 0 /* Unused */, &pVM->hm.s.vmx.HCPhysVmwriteBitmap, &pVM->hm.s.vmx.pvVmwriteBitmap },
1939#ifdef VBOX_WITH_CRASHDUMP_MAGIC
1940 { true, 0 /* Unused */, &pVM->hm.s.vmx.HCPhysScratch, &(PRTR0PTR)pVM->hm.s.vmx.pbScratch },
1941#endif
1942 };
1943
1944 int rc = hmR0VmxPagesAllocZ(pVM->hm.s.vmx.hMemObj, &aAllocInfo[0], RT_ELEMENTS(aAllocInfo));
1945 if (RT_FAILURE(rc))
1946 goto cleanup;
1947
1948#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1949 /* Allocate the shadow VMCS-fields array. */
1950 if (fUseVmcsShadowing)
1951 {
1952 Assert(!pVM->hm.s.vmx.cShadowVmcsFields);
1953 Assert(!pVM->hm.s.vmx.cShadowVmcsRoFields);
1954 pVM->hm.s.vmx.paShadowVmcsFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
1955 pVM->hm.s.vmx.paShadowVmcsRoFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
1956 if (RT_LIKELY( pVM->hm.s.vmx.paShadowVmcsFields
1957 && pVM->hm.s.vmx.paShadowVmcsRoFields))
1958 { /* likely */ }
1959 else
1960 {
1961 rc = VERR_NO_MEMORY;
1962 goto cleanup;
1963 }
1964 }
1965#endif
1966
1967 /*
1968 * Allocate per-VCPU VT-x structures.
1969 */
1970 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1971 {
1972 /* Allocate the guest VMCS structures. */
1973 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
1974 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hm.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
1975 if (RT_FAILURE(rc))
1976 goto cleanup;
1977
1978#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1979 /* Allocate the nested-guest VMCS structures, when the VMX feature is exposed to the guest. */
1980 if (pVM->cpum.ro.GuestFeatures.fVmx)
1981 {
1982 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hm.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
1983 if (RT_FAILURE(rc))
1984 goto cleanup;
1985 }
1986#endif
1987 }
1988
1989 return VINF_SUCCESS;
1990
1991cleanup:
1992 hmR0VmxStructsFree(pVM);
1993 Assert(rc != VINF_SUCCESS);
1994 return rc;
1995}
1996
1997
1998/**
1999 * Pre-initializes non-zero fields in VMX structures that will be allocated.
2000 *
2001 * @param pVM The cross context VM structure.
2002 */
2003static void hmR0VmxStructsInit(PVMCC pVM)
2004{
2005 /* Paranoia. */
2006 Assert(pVM->hm.s.vmx.pbApicAccess == NULL);
2007#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2008 Assert(pVM->hm.s.vmx.pbScratch == NULL);
2009#endif
2010
2011 /*
2012 * Initialize members up-front so we can cleanup en masse on allocation failures.
2013 */
2014#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2015 pVM->hm.s.vmx.HCPhysScratch = NIL_RTHCPHYS;
2016#endif
2017 pVM->hm.s.vmx.HCPhysApicAccess = NIL_RTHCPHYS;
2018 pVM->hm.s.vmx.HCPhysVmreadBitmap = NIL_RTHCPHYS;
2019 pVM->hm.s.vmx.HCPhysVmwriteBitmap = NIL_RTHCPHYS;
2020 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
2021 {
2022 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
2023 hmR0VmxVmcsInfoInit(&pVCpu->hm.s.vmx.VmcsInfo);
2024 hmR0VmxVmcsInfoInit(&pVCpu->hm.s.vmx.VmcsInfoNstGst);
2025 }
2026}
2027
2028#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2029/**
2030 * Returns whether an MSR at the given MSR-bitmap offset is intercepted or not.
2031 *
2032 * @returns @c true if the MSR is intercepted, @c false otherwise.
2033 * @param pvMsrBitmap The MSR bitmap.
2034 * @param offMsr The MSR byte offset.
2035 * @param iBit The bit offset from the byte offset.
2036 */
2037DECLINLINE(bool) hmR0VmxIsMsrBitSet(const void *pvMsrBitmap, uint16_t offMsr, int32_t iBit)
2038{
2039 uint8_t const * const pbMsrBitmap = (uint8_t const * const)pvMsrBitmap;
2040 Assert(pbMsrBitmap);
2041 Assert(offMsr + (iBit >> 3) <= X86_PAGE_4K_SIZE);
2042 return ASMBitTest(pbMsrBitmap + offMsr, iBit);
2043}
2044#endif
2045
2046/**
2047 * Sets the permission bits for the specified MSR in the given MSR bitmap.
2048 *
2049 * If the passed VMCS is a nested-guest VMCS, this function ensures that the
2050 * read/write intercept is cleared from the MSR bitmap used for hardware-assisted
2051 * VMX execution of the nested-guest, only if nested-guest is also not intercepting
2052 * the read/write access of this MSR.
2053 *
2054 * @param pVCpu The cross context virtual CPU structure.
2055 * @param pVmcsInfo The VMCS info. object.
2056 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2057 * @param idMsr The MSR value.
2058 * @param fMsrpm The MSR permissions (see VMXMSRPM_XXX). This must
2059 * include both a read -and- a write permission!
2060 *
2061 * @sa CPUMGetVmxMsrPermission.
2062 * @remarks Can be called with interrupts disabled.
2063 */
2064static void hmR0VmxSetMsrPermission(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs, uint32_t idMsr, uint32_t fMsrpm)
2065{
2066 uint8_t *pbMsrBitmap = (uint8_t *)pVmcsInfo->pvMsrBitmap;
2067 Assert(pbMsrBitmap);
2068 Assert(VMXMSRPM_IS_FLAG_VALID(fMsrpm));
2069
2070 /*
2071 * MSR-bitmap Layout:
2072 * Byte index MSR range Interpreted as
2073 * 0x000 - 0x3ff 0x00000000 - 0x00001fff Low MSR read bits.
2074 * 0x400 - 0x7ff 0xc0000000 - 0xc0001fff High MSR read bits.
2075 * 0x800 - 0xbff 0x00000000 - 0x00001fff Low MSR write bits.
2076 * 0xc00 - 0xfff 0xc0000000 - 0xc0001fff High MSR write bits.
2077 *
2078 * A bit corresponding to an MSR within the above range causes a VM-exit
2079 * if the bit is 1 on executions of RDMSR/WRMSR. If an MSR falls out of
2080 * the MSR range, it always cause a VM-exit.
2081 *
2082 * See Intel spec. 24.6.9 "MSR-Bitmap Address".
2083 */
2084 uint16_t const offBitmapRead = 0;
2085 uint16_t const offBitmapWrite = 0x800;
2086 uint16_t offMsr;
2087 int32_t iBit;
2088 if (idMsr <= UINT32_C(0x00001fff))
2089 {
2090 offMsr = 0;
2091 iBit = idMsr;
2092 }
2093 else if (idMsr - UINT32_C(0xc0000000) <= UINT32_C(0x00001fff))
2094 {
2095 offMsr = 0x400;
2096 iBit = idMsr - UINT32_C(0xc0000000);
2097 }
2098 else
2099 AssertMsgFailedReturnVoid(("Invalid MSR %#RX32\n", idMsr));
2100
2101 /*
2102 * Set the MSR read permission.
2103 */
2104 uint16_t const offMsrRead = offBitmapRead + offMsr;
2105 Assert(offMsrRead + (iBit >> 3) < offBitmapWrite);
2106 if (fMsrpm & VMXMSRPM_ALLOW_RD)
2107 {
2108#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2109 bool const fClear = !fIsNstGstVmcs ? true
2110 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrRead, iBit);
2111#else
2112 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2113 bool const fClear = true;
2114#endif
2115 if (fClear)
2116 ASMBitClear(pbMsrBitmap + offMsrRead, iBit);
2117 }
2118 else
2119 ASMBitSet(pbMsrBitmap + offMsrRead, iBit);
2120
2121 /*
2122 * Set the MSR write permission.
2123 */
2124 uint16_t const offMsrWrite = offBitmapWrite + offMsr;
2125 Assert(offMsrWrite + (iBit >> 3) < X86_PAGE_4K_SIZE);
2126 if (fMsrpm & VMXMSRPM_ALLOW_WR)
2127 {
2128#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2129 bool const fClear = !fIsNstGstVmcs ? true
2130 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrWrite, iBit);
2131#else
2132 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2133 bool const fClear = true;
2134#endif
2135 if (fClear)
2136 ASMBitClear(pbMsrBitmap + offMsrWrite, iBit);
2137 }
2138 else
2139 ASMBitSet(pbMsrBitmap + offMsrWrite, iBit);
2140}
2141
2142
2143/**
2144 * Updates the VMCS with the number of effective MSRs in the auto-load/store MSR
2145 * area.
2146 *
2147 * @returns VBox status code.
2148 * @param pVCpu The cross context virtual CPU structure.
2149 * @param pVmcsInfo The VMCS info. object.
2150 * @param cMsrs The number of MSRs.
2151 */
2152static int hmR0VmxSetAutoLoadStoreMsrCount(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t cMsrs)
2153{
2154 /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
2155 uint32_t const cMaxSupportedMsrs = VMX_MISC_MAX_MSRS(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc);
2156 if (RT_LIKELY(cMsrs < cMaxSupportedMsrs))
2157 {
2158 /* Commit the MSR counts to the VMCS and update the cache. */
2159 if (pVmcsInfo->cEntryMsrLoad != cMsrs)
2160 {
2161 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2162 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, cMsrs); AssertRC(rc);
2163 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2164 pVmcsInfo->cEntryMsrLoad = cMsrs;
2165 pVmcsInfo->cExitMsrStore = cMsrs;
2166 pVmcsInfo->cExitMsrLoad = cMsrs;
2167 }
2168 return VINF_SUCCESS;
2169 }
2170
2171 LogRel(("Auto-load/store MSR count exceeded! cMsrs=%u MaxSupported=%u\n", cMsrs, cMaxSupportedMsrs));
2172 pVCpu->hm.s.u32HMError = VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE;
2173 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2174}
2175
2176
2177/**
2178 * Adds a new (or updates the value of an existing) guest/host MSR
2179 * pair to be swapped during the world-switch as part of the
2180 * auto-load/store MSR area in the VMCS.
2181 *
2182 * @returns VBox status code.
2183 * @param pVCpu The cross context virtual CPU structure.
2184 * @param pVmxTransient The VMX-transient structure.
2185 * @param idMsr The MSR.
2186 * @param uGuestMsrValue Value of the guest MSR.
2187 * @param fSetReadWrite Whether to set the guest read/write access of this
2188 * MSR (thus not causing a VM-exit).
2189 * @param fUpdateHostMsr Whether to update the value of the host MSR if
2190 * necessary.
2191 */
2192static int hmR0VmxAddAutoLoadStoreMsr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t idMsr, uint64_t uGuestMsrValue,
2193 bool fSetReadWrite, bool fUpdateHostMsr)
2194{
2195 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2196 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2197 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2198 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2199 uint32_t i;
2200
2201 /* Paranoia. */
2202 Assert(pGuestMsrLoad);
2203
2204 LogFlowFunc(("pVCpu=%p idMsr=%#RX32 uGestMsrValue=%#RX64\n", pVCpu, idMsr, uGuestMsrValue));
2205
2206 /* Check if the MSR already exists in the VM-entry MSR-load area. */
2207 for (i = 0; i < cMsrs; i++)
2208 {
2209 if (pGuestMsrLoad[i].u32Msr == idMsr)
2210 break;
2211 }
2212
2213 bool fAdded = false;
2214 if (i == cMsrs)
2215 {
2216 /* The MSR does not exist, bump the MSR count to make room for the new MSR. */
2217 ++cMsrs;
2218 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2219 AssertMsgRCReturn(rc, ("Insufficient space to add MSR to VM-entry MSR-load/store area %u\n", idMsr), rc);
2220
2221 /* Set the guest to read/write this MSR without causing VM-exits. */
2222 if ( fSetReadWrite
2223 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
2224 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_ALLOW_RD_WR);
2225
2226 Log4Func(("Added MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2227 fAdded = true;
2228 }
2229
2230 /* Update the MSR value for the newly added or already existing MSR. */
2231 pGuestMsrLoad[i].u32Msr = idMsr;
2232 pGuestMsrLoad[i].u64Value = uGuestMsrValue;
2233
2234 /* Create the corresponding slot in the VM-exit MSR-store area if we use a different page. */
2235 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2236 {
2237 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2238 pGuestMsrStore[i].u32Msr = idMsr;
2239 pGuestMsrStore[i].u64Value = uGuestMsrValue;
2240 }
2241
2242 /* Update the corresponding slot in the host MSR area. */
2243 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2244 Assert(pHostMsr != pVmcsInfo->pvGuestMsrLoad);
2245 Assert(pHostMsr != pVmcsInfo->pvGuestMsrStore);
2246 pHostMsr[i].u32Msr = idMsr;
2247
2248 /*
2249 * Only if the caller requests to update the host MSR value AND we've newly added the
2250 * MSR to the host MSR area do we actually update the value. Otherwise, it will be
2251 * updated by hmR0VmxUpdateAutoLoadHostMsrs().
2252 *
2253 * We do this for performance reasons since reading MSRs may be quite expensive.
2254 */
2255 if (fAdded)
2256 {
2257 if (fUpdateHostMsr)
2258 {
2259 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2260 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2261 pHostMsr[i].u64Value = ASMRdMsr(idMsr);
2262 }
2263 else
2264 {
2265 /* Someone else can do the work. */
2266 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
2267 }
2268 }
2269 return VINF_SUCCESS;
2270}
2271
2272
2273/**
2274 * Removes a guest/host MSR pair to be swapped during the world-switch from the
2275 * auto-load/store MSR area in the VMCS.
2276 *
2277 * @returns VBox status code.
2278 * @param pVCpu The cross context virtual CPU structure.
2279 * @param pVmxTransient The VMX-transient structure.
2280 * @param idMsr The MSR.
2281 */
2282static int hmR0VmxRemoveAutoLoadStoreMsr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t idMsr)
2283{
2284 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2285 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2286 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2287 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2288
2289 LogFlowFunc(("pVCpu=%p idMsr=%#RX32\n", pVCpu, idMsr));
2290
2291 for (uint32_t i = 0; i < cMsrs; i++)
2292 {
2293 /* Find the MSR. */
2294 if (pGuestMsrLoad[i].u32Msr == idMsr)
2295 {
2296 /*
2297 * If it's the last MSR, we only need to reduce the MSR count.
2298 * If it's -not- the last MSR, copy the last MSR in place of it and reduce the MSR count.
2299 */
2300 if (i < cMsrs - 1)
2301 {
2302 /* Remove it from the VM-entry MSR-load area. */
2303 pGuestMsrLoad[i].u32Msr = pGuestMsrLoad[cMsrs - 1].u32Msr;
2304 pGuestMsrLoad[i].u64Value = pGuestMsrLoad[cMsrs - 1].u64Value;
2305
2306 /* Remove it from the VM-exit MSR-store area if it's in a different page. */
2307 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2308 {
2309 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2310 Assert(pGuestMsrStore[i].u32Msr == idMsr);
2311 pGuestMsrStore[i].u32Msr = pGuestMsrStore[cMsrs - 1].u32Msr;
2312 pGuestMsrStore[i].u64Value = pGuestMsrStore[cMsrs - 1].u64Value;
2313 }
2314
2315 /* Remove it from the VM-exit MSR-load area. */
2316 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2317 Assert(pHostMsr[i].u32Msr == idMsr);
2318 pHostMsr[i].u32Msr = pHostMsr[cMsrs - 1].u32Msr;
2319 pHostMsr[i].u64Value = pHostMsr[cMsrs - 1].u64Value;
2320 }
2321
2322 /* Reduce the count to reflect the removed MSR and bail. */
2323 --cMsrs;
2324 break;
2325 }
2326 }
2327
2328 /* Update the VMCS if the count changed (meaning the MSR was found and removed). */
2329 if (cMsrs != pVmcsInfo->cEntryMsrLoad)
2330 {
2331 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2332 AssertRCReturn(rc, rc);
2333
2334 /* We're no longer swapping MSRs during the world-switch, intercept guest read/writes to them. */
2335 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2336 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR);
2337
2338 Log4Func(("Removed MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2339 return VINF_SUCCESS;
2340 }
2341
2342 return VERR_NOT_FOUND;
2343}
2344
2345
2346/**
2347 * Checks if the specified guest MSR is part of the VM-entry MSR-load area.
2348 *
2349 * @returns @c true if found, @c false otherwise.
2350 * @param pVmcsInfo The VMCS info. object.
2351 * @param idMsr The MSR to find.
2352 */
2353static bool hmR0VmxIsAutoLoadGuestMsr(PCVMXVMCSINFO pVmcsInfo, uint32_t idMsr)
2354{
2355 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2356 uint32_t const cMsrs = pVmcsInfo->cEntryMsrLoad;
2357 Assert(pMsrs);
2358 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
2359 for (uint32_t i = 0; i < cMsrs; i++)
2360 {
2361 if (pMsrs[i].u32Msr == idMsr)
2362 return true;
2363 }
2364 return false;
2365}
2366
2367
2368/**
2369 * Updates the value of all host MSRs in the VM-exit MSR-load area.
2370 *
2371 * @param pVCpu The cross context virtual CPU structure.
2372 * @param pVmcsInfo The VMCS info. object.
2373 *
2374 * @remarks No-long-jump zone!!!
2375 */
2376static void hmR0VmxUpdateAutoLoadHostMsrs(PCVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2377{
2378 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2379
2380 PVMXAUTOMSR pHostMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2381 uint32_t const cMsrs = pVmcsInfo->cExitMsrLoad;
2382 Assert(pHostMsrLoad);
2383 Assert(sizeof(*pHostMsrLoad) * cMsrs <= X86_PAGE_4K_SIZE);
2384 LogFlowFunc(("pVCpu=%p cMsrs=%u\n", pVCpu, cMsrs));
2385 for (uint32_t i = 0; i < cMsrs; i++)
2386 {
2387 /*
2388 * Performance hack for the host EFER MSR. We use the cached value rather than re-read it.
2389 * Strict builds will catch mismatches in hmR0VmxCheckAutoLoadStoreMsrs(). See @bugref{7368}.
2390 */
2391 if (pHostMsrLoad[i].u32Msr == MSR_K6_EFER)
2392 pHostMsrLoad[i].u64Value = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer;
2393 else
2394 pHostMsrLoad[i].u64Value = ASMRdMsr(pHostMsrLoad[i].u32Msr);
2395 }
2396}
2397
2398
2399/**
2400 * Saves a set of host MSRs to allow read/write passthru access to the guest and
2401 * perform lazy restoration of the host MSRs while leaving VT-x.
2402 *
2403 * @param pVCpu The cross context virtual CPU structure.
2404 *
2405 * @remarks No-long-jump zone!!!
2406 */
2407static void hmR0VmxLazySaveHostMsrs(PVMCPUCC pVCpu)
2408{
2409 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2410
2411 /*
2412 * Note: If you're adding MSRs here, make sure to update the MSR-bitmap accesses in hmR0VmxSetupVmcsProcCtls().
2413 */
2414 if (!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST))
2415 {
2416 Assert(!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)); /* Guest MSRs better not be loaded now. */
2417 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2418 {
2419 pVCpu->hm.s.vmx.u64HostMsrLStar = ASMRdMsr(MSR_K8_LSTAR);
2420 pVCpu->hm.s.vmx.u64HostMsrStar = ASMRdMsr(MSR_K6_STAR);
2421 pVCpu->hm.s.vmx.u64HostMsrSfMask = ASMRdMsr(MSR_K8_SF_MASK);
2422 pVCpu->hm.s.vmx.u64HostMsrKernelGsBase = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
2423 }
2424 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_SAVED_HOST;
2425 }
2426}
2427
2428
2429/**
2430 * Checks whether the MSR belongs to the set of guest MSRs that we restore
2431 * lazily while leaving VT-x.
2432 *
2433 * @returns true if it does, false otherwise.
2434 * @param pVCpu The cross context virtual CPU structure.
2435 * @param idMsr The MSR to check.
2436 */
2437static bool hmR0VmxIsLazyGuestMsr(PCVMCPUCC pVCpu, uint32_t idMsr)
2438{
2439 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2440 {
2441 switch (idMsr)
2442 {
2443 case MSR_K8_LSTAR:
2444 case MSR_K6_STAR:
2445 case MSR_K8_SF_MASK:
2446 case MSR_K8_KERNEL_GS_BASE:
2447 return true;
2448 }
2449 }
2450 return false;
2451}
2452
2453
2454/**
2455 * Loads a set of guests MSRs to allow read/passthru to the guest.
2456 *
2457 * The name of this function is slightly confusing. This function does NOT
2458 * postpone loading, but loads the MSR right now. "hmR0VmxLazy" is simply a
2459 * common prefix for functions dealing with "lazy restoration" of the shared
2460 * MSRs.
2461 *
2462 * @param pVCpu The cross context virtual CPU structure.
2463 *
2464 * @remarks No-long-jump zone!!!
2465 */
2466static void hmR0VmxLazyLoadGuestMsrs(PVMCPUCC pVCpu)
2467{
2468 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2469 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2470
2471 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2472 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2473 {
2474 /*
2475 * If the guest MSRs are not loaded -and- if all the guest MSRs are identical
2476 * to the MSRs on the CPU (which are the saved host MSRs, see assertion above) then
2477 * we can skip a few MSR writes.
2478 *
2479 * Otherwise, it implies either 1. they're not loaded, or 2. they're loaded but the
2480 * guest MSR values in the guest-CPU context might be different to what's currently
2481 * loaded in the CPU. In either case, we need to write the new guest MSR values to the
2482 * CPU, see @bugref{8728}.
2483 */
2484 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
2485 if ( !(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2486 && pCtx->msrKERNELGSBASE == pVCpu->hm.s.vmx.u64HostMsrKernelGsBase
2487 && pCtx->msrLSTAR == pVCpu->hm.s.vmx.u64HostMsrLStar
2488 && pCtx->msrSTAR == pVCpu->hm.s.vmx.u64HostMsrStar
2489 && pCtx->msrSFMASK == pVCpu->hm.s.vmx.u64HostMsrSfMask)
2490 {
2491#ifdef VBOX_STRICT
2492 Assert(ASMRdMsr(MSR_K8_KERNEL_GS_BASE) == pCtx->msrKERNELGSBASE);
2493 Assert(ASMRdMsr(MSR_K8_LSTAR) == pCtx->msrLSTAR);
2494 Assert(ASMRdMsr(MSR_K6_STAR) == pCtx->msrSTAR);
2495 Assert(ASMRdMsr(MSR_K8_SF_MASK) == pCtx->msrSFMASK);
2496#endif
2497 }
2498 else
2499 {
2500 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pCtx->msrKERNELGSBASE);
2501 ASMWrMsr(MSR_K8_LSTAR, pCtx->msrLSTAR);
2502 ASMWrMsr(MSR_K6_STAR, pCtx->msrSTAR);
2503 ASMWrMsr(MSR_K8_SF_MASK, pCtx->msrSFMASK);
2504 }
2505 }
2506 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_LOADED_GUEST;
2507}
2508
2509
2510/**
2511 * Performs lazy restoration of the set of host MSRs if they were previously
2512 * loaded with guest MSR values.
2513 *
2514 * @param pVCpu The cross context virtual CPU structure.
2515 *
2516 * @remarks No-long-jump zone!!!
2517 * @remarks The guest MSRs should have been saved back into the guest-CPU
2518 * context by hmR0VmxImportGuestState()!!!
2519 */
2520static void hmR0VmxLazyRestoreHostMsrs(PVMCPUCC pVCpu)
2521{
2522 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2523 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2524
2525 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2526 {
2527 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2528 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2529 {
2530 ASMWrMsr(MSR_K8_LSTAR, pVCpu->hm.s.vmx.u64HostMsrLStar);
2531 ASMWrMsr(MSR_K6_STAR, pVCpu->hm.s.vmx.u64HostMsrStar);
2532 ASMWrMsr(MSR_K8_SF_MASK, pVCpu->hm.s.vmx.u64HostMsrSfMask);
2533 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pVCpu->hm.s.vmx.u64HostMsrKernelGsBase);
2534 }
2535 }
2536 pVCpu->hm.s.vmx.fLazyMsrs &= ~(VMX_LAZY_MSRS_LOADED_GUEST | VMX_LAZY_MSRS_SAVED_HOST);
2537}
2538
2539
2540/**
2541 * Verifies that our cached values of the VMCS fields are all consistent with
2542 * what's actually present in the VMCS.
2543 *
2544 * @returns VBox status code.
2545 * @retval VINF_SUCCESS if all our caches match their respective VMCS fields.
2546 * @retval VERR_VMX_VMCS_FIELD_CACHE_INVALID if a cache field doesn't match the
2547 * VMCS content. HMCPU error-field is
2548 * updated, see VMX_VCI_XXX.
2549 * @param pVCpu The cross context virtual CPU structure.
2550 * @param pVmcsInfo The VMCS info. object.
2551 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2552 */
2553static int hmR0VmxCheckCachedVmcsCtls(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2554{
2555 const char * const pcszVmcs = fIsNstGstVmcs ? "Nested-guest VMCS" : "VMCS";
2556
2557 uint32_t u32Val;
2558 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
2559 AssertRC(rc);
2560 AssertMsgReturnStmt(pVmcsInfo->u32EntryCtls == u32Val,
2561 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32EntryCtls, u32Val),
2562 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_ENTRY,
2563 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2564
2565 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val);
2566 AssertRC(rc);
2567 AssertMsgReturnStmt(pVmcsInfo->u32ExitCtls == u32Val,
2568 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ExitCtls, u32Val),
2569 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_EXIT,
2570 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2571
2572 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val);
2573 AssertRC(rc);
2574 AssertMsgReturnStmt(pVmcsInfo->u32PinCtls == u32Val,
2575 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32PinCtls, u32Val),
2576 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PIN_EXEC,
2577 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2578
2579 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val);
2580 AssertRC(rc);
2581 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls == u32Val,
2582 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls, u32Val),
2583 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC,
2584 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2585
2586 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
2587 {
2588 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val);
2589 AssertRC(rc);
2590 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls2 == u32Val,
2591 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls2, u32Val),
2592 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC2,
2593 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2594 }
2595
2596 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val);
2597 AssertRC(rc);
2598 AssertMsgReturnStmt(pVmcsInfo->u32XcptBitmap == u32Val,
2599 ("%s exception bitmap mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32XcptBitmap, u32Val),
2600 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_XCPT_BITMAP,
2601 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2602
2603 uint64_t u64Val;
2604 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, &u64Val);
2605 AssertRC(rc);
2606 AssertMsgReturnStmt(pVmcsInfo->u64TscOffset == u64Val,
2607 ("%s TSC offset mismatch: Cache=%#RX64 VMCS=%#RX64\n", pcszVmcs, pVmcsInfo->u64TscOffset, u64Val),
2608 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_TSC_OFFSET,
2609 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2610
2611 NOREF(pcszVmcs);
2612 return VINF_SUCCESS;
2613}
2614
2615
2616#ifdef VBOX_STRICT
2617/**
2618 * Verifies that our cached host EFER MSR value has not changed since we cached it.
2619 *
2620 * @param pVCpu The cross context virtual CPU structure.
2621 * @param pVmcsInfo The VMCS info. object.
2622 */
2623static void hmR0VmxCheckHostEferMsr(PCVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2624{
2625 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2626
2627 if (pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_LOAD_EFER_MSR)
2628 {
2629 uint64_t const uHostEferMsr = ASMRdMsr(MSR_K6_EFER);
2630 uint64_t const uHostEferMsrCache = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer;
2631 uint64_t uVmcsEferMsrVmcs;
2632 int rc = VMXReadVmcs64(VMX_VMCS64_HOST_EFER_FULL, &uVmcsEferMsrVmcs);
2633 AssertRC(rc);
2634
2635 AssertMsgReturnVoid(uHostEferMsr == uVmcsEferMsrVmcs,
2636 ("EFER Host/VMCS mismatch! host=%#RX64 vmcs=%#RX64\n", uHostEferMsr, uVmcsEferMsrVmcs));
2637 AssertMsgReturnVoid(uHostEferMsr == uHostEferMsrCache,
2638 ("EFER Host/Cache mismatch! host=%#RX64 cache=%#RX64\n", uHostEferMsr, uHostEferMsrCache));
2639 }
2640}
2641
2642
2643/**
2644 * Verifies whether the guest/host MSR pairs in the auto-load/store area in the
2645 * VMCS are correct.
2646 *
2647 * @param pVCpu The cross context virtual CPU structure.
2648 * @param pVmcsInfo The VMCS info. object.
2649 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2650 */
2651static void hmR0VmxCheckAutoLoadStoreMsrs(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2652{
2653 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2654
2655 /* Read the various MSR-area counts from the VMCS. */
2656 uint32_t cEntryLoadMsrs;
2657 uint32_t cExitStoreMsrs;
2658 uint32_t cExitLoadMsrs;
2659 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &cEntryLoadMsrs); AssertRC(rc);
2660 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &cExitStoreMsrs); AssertRC(rc);
2661 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &cExitLoadMsrs); AssertRC(rc);
2662
2663 /* Verify all the MSR counts are the same. */
2664 Assert(cEntryLoadMsrs == cExitStoreMsrs);
2665 Assert(cExitStoreMsrs == cExitLoadMsrs);
2666 uint32_t const cMsrs = cExitLoadMsrs;
2667
2668 /* Verify the MSR counts do not exceed the maximum count supported by the hardware. */
2669 Assert(cMsrs < VMX_MISC_MAX_MSRS(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc));
2670
2671 /* Verify the MSR counts are within the allocated page size. */
2672 Assert(sizeof(VMXAUTOMSR) * cMsrs <= X86_PAGE_4K_SIZE);
2673
2674 /* Verify the relevant contents of the MSR areas match. */
2675 PCVMXAUTOMSR pGuestMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2676 PCVMXAUTOMSR pGuestMsrStore = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2677 PCVMXAUTOMSR pHostMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2678 bool const fSeparateExitMsrStorePage = hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo);
2679 for (uint32_t i = 0; i < cMsrs; i++)
2680 {
2681 /* Verify that the MSRs are paired properly and that the host MSR has the correct value. */
2682 if (fSeparateExitMsrStorePage)
2683 {
2684 AssertMsgReturnVoid(pGuestMsrLoad->u32Msr == pGuestMsrStore->u32Msr,
2685 ("GuestMsrLoad=%#RX32 GuestMsrStore=%#RX32 cMsrs=%u\n",
2686 pGuestMsrLoad->u32Msr, pGuestMsrStore->u32Msr, cMsrs));
2687 }
2688
2689 AssertMsgReturnVoid(pHostMsrLoad->u32Msr == pGuestMsrLoad->u32Msr,
2690 ("HostMsrLoad=%#RX32 GuestMsrLoad=%#RX32 cMsrs=%u\n",
2691 pHostMsrLoad->u32Msr, pGuestMsrLoad->u32Msr, cMsrs));
2692
2693 uint64_t const u64Msr = ASMRdMsr(pHostMsrLoad->u32Msr);
2694 AssertMsgReturnVoid(pHostMsrLoad->u64Value == u64Msr,
2695 ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2696 pHostMsrLoad->u32Msr, pHostMsrLoad->u64Value, u64Msr, cMsrs));
2697
2698 /* Verify that cached host EFER MSR matches what's loaded the CPU. */
2699 bool const fIsEferMsr = RT_BOOL(pHostMsrLoad->u32Msr == MSR_K6_EFER);
2700 if (fIsEferMsr)
2701 {
2702 AssertMsgReturnVoid(u64Msr == pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer,
2703 ("Cached=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2704 pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer, u64Msr, cMsrs));
2705 }
2706
2707 /* Verify that the accesses are as expected in the MSR bitmap for auto-load/store MSRs. */
2708 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2709 {
2710 uint32_t const fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, pGuestMsrLoad->u32Msr);
2711 if (fIsEferMsr)
2712 {
2713 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_RD), ("Passthru read for EFER MSR!?\n"));
2714 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_WR), ("Passthru write for EFER MSR!?\n"));
2715 }
2716 else
2717 {
2718 if (!fIsNstGstVmcs)
2719 {
2720 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_ALLOW_RD_WR) == VMXMSRPM_ALLOW_RD_WR,
2721 ("u32Msr=%#RX32 cMsrs=%u No passthru read/write!\n", pGuestMsrLoad->u32Msr, cMsrs));
2722 }
2723 else
2724 {
2725 /*
2726 * A nested-guest VMCS must -also- allow read/write passthrough for the MSR for us to
2727 * execute a nested-guest with MSR passthrough.
2728 *
2729 * Check if the nested-guest MSR bitmap allows passthrough, and if so, assert that we
2730 * allow passthrough too.
2731 */
2732 void const *pvMsrBitmapNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
2733 Assert(pvMsrBitmapNstGst);
2734 uint32_t const fMsrpmNstGst = CPUMGetVmxMsrPermission(pvMsrBitmapNstGst, pGuestMsrLoad->u32Msr);
2735 AssertMsgReturnVoid(fMsrpm == fMsrpmNstGst,
2736 ("u32Msr=%#RX32 cMsrs=%u Permission mismatch fMsrpm=%#x fMsrpmNstGst=%#x!\n",
2737 pGuestMsrLoad->u32Msr, cMsrs, fMsrpm, fMsrpmNstGst));
2738 }
2739 }
2740 }
2741
2742 /* Move to the next MSR. */
2743 pHostMsrLoad++;
2744 pGuestMsrLoad++;
2745 pGuestMsrStore++;
2746 }
2747}
2748#endif /* VBOX_STRICT */
2749
2750
2751/**
2752 * Flushes the TLB using EPT.
2753 *
2754 * @returns VBox status code.
2755 * @param pVCpu The cross context virtual CPU structure of the calling
2756 * EMT. Can be NULL depending on @a enmTlbFlush.
2757 * @param pVmcsInfo The VMCS info. object. Can be NULL depending on @a
2758 * enmTlbFlush.
2759 * @param enmTlbFlush Type of flush.
2760 *
2761 * @remarks Caller is responsible for making sure this function is called only
2762 * when NestedPaging is supported and providing @a enmTlbFlush that is
2763 * supported by the CPU.
2764 * @remarks Can be called with interrupts disabled.
2765 */
2766static void hmR0VmxFlushEpt(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, VMXTLBFLUSHEPT enmTlbFlush)
2767{
2768 uint64_t au64Descriptor[2];
2769 if (enmTlbFlush == VMXTLBFLUSHEPT_ALL_CONTEXTS)
2770 au64Descriptor[0] = 0;
2771 else
2772 {
2773 Assert(pVCpu);
2774 Assert(pVmcsInfo);
2775 au64Descriptor[0] = pVmcsInfo->HCPhysEPTP;
2776 }
2777 au64Descriptor[1] = 0; /* MBZ. Intel spec. 33.3 "VMX Instructions" */
2778
2779 int rc = VMXR0InvEPT(enmTlbFlush, &au64Descriptor[0]);
2780 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %#RHp failed. rc=%Rrc\n", enmTlbFlush, au64Descriptor[0], rc));
2781
2782 if ( RT_SUCCESS(rc)
2783 && pVCpu)
2784 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushNestedPaging);
2785}
2786
2787
2788/**
2789 * Flushes the TLB using VPID.
2790 *
2791 * @returns VBox status code.
2792 * @param pVCpu The cross context virtual CPU structure of the calling
2793 * EMT. Can be NULL depending on @a enmTlbFlush.
2794 * @param enmTlbFlush Type of flush.
2795 * @param GCPtr Virtual address of the page to flush (can be 0 depending
2796 * on @a enmTlbFlush).
2797 *
2798 * @remarks Can be called with interrupts disabled.
2799 */
2800static void hmR0VmxFlushVpid(PVMCPUCC pVCpu, VMXTLBFLUSHVPID enmTlbFlush, RTGCPTR GCPtr)
2801{
2802 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fVpid);
2803
2804 uint64_t au64Descriptor[2];
2805 if (enmTlbFlush == VMXTLBFLUSHVPID_ALL_CONTEXTS)
2806 {
2807 au64Descriptor[0] = 0;
2808 au64Descriptor[1] = 0;
2809 }
2810 else
2811 {
2812 AssertPtr(pVCpu);
2813 AssertMsg(pVCpu->hm.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
2814 AssertMsg(pVCpu->hm.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
2815 au64Descriptor[0] = pVCpu->hm.s.uCurrentAsid;
2816 au64Descriptor[1] = GCPtr;
2817 }
2818
2819 int rc = VMXR0InvVPID(enmTlbFlush, &au64Descriptor[0]);
2820 AssertMsg(rc == VINF_SUCCESS,
2821 ("VMXR0InvVPID %#x %u %RGv failed with %Rrc\n", enmTlbFlush, pVCpu ? pVCpu->hm.s.uCurrentAsid : 0, GCPtr, rc));
2822
2823 if ( RT_SUCCESS(rc)
2824 && pVCpu)
2825 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
2826 NOREF(rc);
2827}
2828
2829
2830/**
2831 * Invalidates a guest page by guest virtual address. Only relevant for EPT/VPID,
2832 * otherwise there is nothing really to invalidate.
2833 *
2834 * @returns VBox status code.
2835 * @param pVCpu The cross context virtual CPU structure.
2836 * @param GCVirt Guest virtual address of the page to invalidate.
2837 */
2838VMMR0DECL(int) VMXR0InvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt)
2839{
2840 AssertPtr(pVCpu);
2841 LogFlowFunc(("pVCpu=%p GCVirt=%RGv\n", pVCpu, GCVirt));
2842
2843 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_TLB_FLUSH))
2844 {
2845 /*
2846 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for
2847 * the EPT case. See @bugref{6043} and @bugref{6177}.
2848 *
2849 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VM-entry in hmR0VmxFlushTLB*()
2850 * as this function maybe called in a loop with individual addresses.
2851 */
2852 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2853 if (pVM->hm.s.vmx.fVpid)
2854 {
2855 bool fVpidFlush = RT_BOOL(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR);
2856 if (fVpidFlush)
2857 {
2858 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_INDIV_ADDR, GCVirt);
2859 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
2860 }
2861 else
2862 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2863 }
2864 else if (pVM->hm.s.fNestedPaging)
2865 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2866 }
2867
2868 return VINF_SUCCESS;
2869}
2870
2871
2872/**
2873 * Dummy placeholder for tagged-TLB flush handling before VM-entry. Used in the
2874 * case where neither EPT nor VPID is supported by the CPU.
2875 *
2876 * @param pHostCpu The HM physical-CPU structure.
2877 * @param pVCpu The cross context virtual CPU structure.
2878 *
2879 * @remarks Called with interrupts disabled.
2880 */
2881static void hmR0VmxFlushTaggedTlbNone(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
2882{
2883 AssertPtr(pVCpu);
2884 AssertPtr(pHostCpu);
2885
2886 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
2887
2888 Assert(pHostCpu->idCpu != NIL_RTCPUID);
2889 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
2890 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
2891 pVCpu->hm.s.fForceTLBFlush = false;
2892 return;
2893}
2894
2895
2896/**
2897 * Flushes the tagged-TLB entries for EPT+VPID CPUs as necessary.
2898 *
2899 * @param pHostCpu The HM physical-CPU structure.
2900 * @param pVCpu The cross context virtual CPU structure.
2901 * @param pVmcsInfo The VMCS info. object.
2902 *
2903 * @remarks All references to "ASID" in this function pertains to "VPID" in Intel's
2904 * nomenclature. The reason is, to avoid confusion in compare statements
2905 * since the host-CPU copies are named "ASID".
2906 *
2907 * @remarks Called with interrupts disabled.
2908 */
2909static void hmR0VmxFlushTaggedTlbBoth(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2910{
2911#ifdef VBOX_WITH_STATISTICS
2912 bool fTlbFlushed = false;
2913# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { fTlbFlushed = true; } while (0)
2914# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { \
2915 if (!fTlbFlushed) \
2916 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch); \
2917 } while (0)
2918#else
2919# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { } while (0)
2920# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { } while (0)
2921#endif
2922
2923 AssertPtr(pVCpu);
2924 AssertPtr(pHostCpu);
2925 Assert(pHostCpu->idCpu != NIL_RTCPUID);
2926
2927 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2928 AssertMsg(pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid,
2929 ("hmR0VmxFlushTaggedTlbBoth cannot be invoked unless NestedPaging & VPID are enabled."
2930 "fNestedPaging=%RTbool fVpid=%RTbool", pVM->hm.s.fNestedPaging, pVM->hm.s.vmx.fVpid));
2931
2932 /*
2933 * Force a TLB flush for the first world-switch if the current CPU differs from the one we
2934 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
2935 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
2936 * cannot reuse the current ASID anymore.
2937 */
2938 if ( pVCpu->hm.s.idLastCpu != pHostCpu->idCpu
2939 || pVCpu->hm.s.cTlbFlushes != pHostCpu->cTlbFlushes)
2940 {
2941 ++pHostCpu->uCurrentAsid;
2942 if (pHostCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
2943 {
2944 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0. */
2945 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
2946 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
2947 }
2948
2949 pVCpu->hm.s.uCurrentAsid = pHostCpu->uCurrentAsid;
2950 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
2951 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
2952
2953 /*
2954 * Flush by EPT when we get rescheduled to a new host CPU to ensure EPT-only tagged mappings are also
2955 * invalidated. We don't need to flush-by-VPID here as flushing by EPT covers it. See @bugref{6568}.
2956 */
2957 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hm.s.vmx.enmTlbFlushEpt);
2958 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
2959 HMVMX_SET_TAGGED_TLB_FLUSHED();
2960 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
2961 }
2962 else if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH)) /* Check for explicit TLB flushes. */
2963 {
2964 /*
2965 * Changes to the EPT paging structure by VMM requires flushing-by-EPT as the CPU
2966 * creates guest-physical (ie. only EPT-tagged) mappings while traversing the EPT
2967 * tables when EPT is in use. Flushing-by-VPID will only flush linear (only
2968 * VPID-tagged) and combined (EPT+VPID tagged) mappings but not guest-physical
2969 * mappings, see @bugref{6568}.
2970 *
2971 * See Intel spec. 28.3.2 "Creating and Using Cached Translation Information".
2972 */
2973 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hm.s.vmx.enmTlbFlushEpt);
2974 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
2975 HMVMX_SET_TAGGED_TLB_FLUSHED();
2976 }
2977 else if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
2978 {
2979 /*
2980 * The nested-guest specifies its own guest-physical address to use as the APIC-access
2981 * address which requires flushing the TLB of EPT cached structures.
2982 *
2983 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
2984 */
2985 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hm.s.vmx.enmTlbFlushEpt);
2986 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
2987 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
2988 HMVMX_SET_TAGGED_TLB_FLUSHED();
2989 }
2990
2991
2992 pVCpu->hm.s.fForceTLBFlush = false;
2993 HMVMX_UPDATE_FLUSH_SKIPPED_STAT();
2994
2995 Assert(pVCpu->hm.s.idLastCpu == pHostCpu->idCpu);
2996 Assert(pVCpu->hm.s.cTlbFlushes == pHostCpu->cTlbFlushes);
2997 AssertMsg(pVCpu->hm.s.cTlbFlushes == pHostCpu->cTlbFlushes,
2998 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pHostCpu->cTlbFlushes));
2999 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
3000 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3001 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
3002 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
3003 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
3004
3005 /* Update VMCS with the VPID. */
3006 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
3007 AssertRC(rc);
3008
3009#undef HMVMX_SET_TAGGED_TLB_FLUSHED
3010}
3011
3012
3013/**
3014 * Flushes the tagged-TLB entries for EPT 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 Called with interrupts disabled.
3021 */
3022static void hmR0VmxFlushTaggedTlbEpt(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3023{
3024 AssertPtr(pVCpu);
3025 AssertPtr(pHostCpu);
3026 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3027 AssertMsg(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked without NestedPaging."));
3028 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fVpid, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with VPID."));
3029
3030 /*
3031 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
3032 * A change in the TLB flush count implies the host CPU is online after a suspend/resume.
3033 */
3034 if ( pVCpu->hm.s.idLastCpu != pHostCpu->idCpu
3035 || pVCpu->hm.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3036 {
3037 pVCpu->hm.s.fForceTLBFlush = true;
3038 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3039 }
3040
3041 /* Check for explicit TLB flushes. */
3042 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3043 {
3044 pVCpu->hm.s.fForceTLBFlush = true;
3045 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3046 }
3047
3048 /* Check for TLB flushes while switching to/from a nested-guest. */
3049 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3050 {
3051 pVCpu->hm.s.fForceTLBFlush = true;
3052 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3053 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3054 }
3055
3056 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
3057 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3058
3059 if (pVCpu->hm.s.fForceTLBFlush)
3060 {
3061 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVCpu->CTX_SUFF(pVM)->hm.s.vmx.enmTlbFlushEpt);
3062 pVCpu->hm.s.fForceTLBFlush = false;
3063 }
3064}
3065
3066
3067/**
3068 * Flushes the tagged-TLB entries for VPID CPUs as necessary.
3069 *
3070 * @param pHostCpu The HM physical-CPU structure.
3071 * @param pVCpu The cross context virtual CPU structure.
3072 *
3073 * @remarks Called with interrupts disabled.
3074 */
3075static void hmR0VmxFlushTaggedTlbVpid(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
3076{
3077 AssertPtr(pVCpu);
3078 AssertPtr(pHostCpu);
3079 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3080 AssertMsg(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fVpid, ("hmR0VmxFlushTlbVpid cannot be invoked without VPID."));
3081 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging"));
3082
3083 /*
3084 * Force a TLB flush for the first world switch if the current CPU differs from the one we
3085 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
3086 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
3087 * cannot reuse the current ASID anymore.
3088 */
3089 if ( pVCpu->hm.s.idLastCpu != pHostCpu->idCpu
3090 || pVCpu->hm.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3091 {
3092 pVCpu->hm.s.fForceTLBFlush = true;
3093 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3094 }
3095
3096 /* Check for explicit TLB flushes. */
3097 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3098 {
3099 /*
3100 * If we ever support VPID flush combinations other than ALL or SINGLE-context (see
3101 * hmR0VmxSetupTaggedTlb()) we would need to explicitly flush in this case (add an
3102 * fExplicitFlush = true here and change the pHostCpu->fFlushAsidBeforeUse check below to
3103 * include fExplicitFlush's too) - an obscure corner case.
3104 */
3105 pVCpu->hm.s.fForceTLBFlush = true;
3106 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3107 }
3108
3109 /* Check for TLB flushes while switching to/from a nested-guest. */
3110 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3111 {
3112 pVCpu->hm.s.fForceTLBFlush = true;
3113 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3114 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3115 }
3116
3117 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3118 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
3119 if (pVCpu->hm.s.fForceTLBFlush)
3120 {
3121 ++pHostCpu->uCurrentAsid;
3122 if (pHostCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
3123 {
3124 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0 */
3125 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
3126 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
3127 }
3128
3129 pVCpu->hm.s.fForceTLBFlush = false;
3130 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3131 pVCpu->hm.s.uCurrentAsid = pHostCpu->uCurrentAsid;
3132 if (pHostCpu->fFlushAsidBeforeUse)
3133 {
3134 if (pVM->hm.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_SINGLE_CONTEXT)
3135 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_SINGLE_CONTEXT, 0 /* GCPtr */);
3136 else if (pVM->hm.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_ALL_CONTEXTS)
3137 {
3138 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_ALL_CONTEXTS, 0 /* GCPtr */);
3139 pHostCpu->fFlushAsidBeforeUse = false;
3140 }
3141 else
3142 {
3143 /* hmR0VmxSetupTaggedTlb() ensures we never get here. Paranoia. */
3144 AssertMsgFailed(("Unsupported VPID-flush context type.\n"));
3145 }
3146 }
3147 }
3148
3149 AssertMsg(pVCpu->hm.s.cTlbFlushes == pHostCpu->cTlbFlushes,
3150 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pHostCpu->cTlbFlushes));
3151 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
3152 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3153 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
3154 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
3155 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
3156
3157 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
3158 AssertRC(rc);
3159}
3160
3161
3162/**
3163 * Flushes the guest TLB entry based on CPU capabilities.
3164 *
3165 * @param pHostCpu The HM physical-CPU structure.
3166 * @param pVCpu The cross context virtual CPU structure.
3167 * @param pVmcsInfo The VMCS info. object.
3168 *
3169 * @remarks Called with interrupts disabled.
3170 */
3171static void hmR0VmxFlushTaggedTlb(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3172{
3173#ifdef HMVMX_ALWAYS_FLUSH_TLB
3174 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
3175#endif
3176 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3177 switch (pVM->hm.s.vmx.enmTlbFlushType)
3178 {
3179 case VMXTLBFLUSHTYPE_EPT_VPID: hmR0VmxFlushTaggedTlbBoth(pHostCpu, pVCpu, pVmcsInfo); break;
3180 case VMXTLBFLUSHTYPE_EPT: hmR0VmxFlushTaggedTlbEpt(pHostCpu, pVCpu, pVmcsInfo); break;
3181 case VMXTLBFLUSHTYPE_VPID: hmR0VmxFlushTaggedTlbVpid(pHostCpu, pVCpu); break;
3182 case VMXTLBFLUSHTYPE_NONE: hmR0VmxFlushTaggedTlbNone(pHostCpu, pVCpu); break;
3183 default:
3184 AssertMsgFailed(("Invalid flush-tag function identifier\n"));
3185 break;
3186 }
3187 /* Don't assert that VMCPU_FF_TLB_FLUSH should no longer be pending. It can be set by other EMTs. */
3188}
3189
3190
3191/**
3192 * Sets up the appropriate tagged TLB-flush level and handler for flushing guest
3193 * TLB entries from the host TLB before VM-entry.
3194 *
3195 * @returns VBox status code.
3196 * @param pVM The cross context VM structure.
3197 */
3198static int hmR0VmxSetupTaggedTlb(PVMCC pVM)
3199{
3200 /*
3201 * Determine optimal flush type for nested paging.
3202 * We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup
3203 * unrestricted guest execution (see hmR3InitFinalizeR0()).
3204 */
3205 if (pVM->hm.s.fNestedPaging)
3206 {
3207 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT)
3208 {
3209 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT)
3210 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_SINGLE_CONTEXT;
3211 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
3212 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_ALL_CONTEXTS;
3213 else
3214 {
3215 /* Shouldn't happen. EPT is supported but no suitable flush-types supported. */
3216 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3217 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED;
3218 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3219 }
3220
3221 /* Make sure the write-back cacheable memory type for EPT is supported. */
3222 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EMT_WB)))
3223 {
3224 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3225 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_MEM_TYPE_NOT_WB;
3226 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3227 }
3228
3229 /* EPT requires a page-walk length of 4. */
3230 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4)))
3231 {
3232 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3233 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED;
3234 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3235 }
3236 }
3237 else
3238 {
3239 /* Shouldn't happen. EPT is supported but INVEPT instruction is not supported. */
3240 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3241 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_INVEPT_UNAVAILABLE;
3242 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3243 }
3244 }
3245
3246 /*
3247 * Determine optimal flush type for VPID.
3248 */
3249 if (pVM->hm.s.vmx.fVpid)
3250 {
3251 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID)
3252 {
3253 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT)
3254 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_SINGLE_CONTEXT;
3255 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS)
3256 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_ALL_CONTEXTS;
3257 else
3258 {
3259 /* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
3260 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
3261 LogRelFunc(("Only INDIV_ADDR supported. Ignoring VPID.\n"));
3262 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
3263 LogRelFunc(("Only SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
3264 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3265 pVM->hm.s.vmx.fVpid = false;
3266 }
3267 }
3268 else
3269 {
3270 /* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
3271 Log4Func(("VPID supported without INVEPT support. Ignoring VPID.\n"));
3272 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3273 pVM->hm.s.vmx.fVpid = false;
3274 }
3275 }
3276
3277 /*
3278 * Setup the handler for flushing tagged-TLBs.
3279 */
3280 if (pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid)
3281 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT_VPID;
3282 else if (pVM->hm.s.fNestedPaging)
3283 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT;
3284 else if (pVM->hm.s.vmx.fVpid)
3285 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_VPID;
3286 else
3287 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_NONE;
3288 return VINF_SUCCESS;
3289}
3290
3291
3292#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3293/**
3294 * Sets up the shadow VMCS fields arrays.
3295 *
3296 * This function builds arrays of VMCS fields to sync the shadow VMCS later while
3297 * executing the guest.
3298 *
3299 * @returns VBox status code.
3300 * @param pVM The cross context VM structure.
3301 */
3302static int hmR0VmxSetupShadowVmcsFieldsArrays(PVMCC pVM)
3303{
3304 /*
3305 * Paranoia. Ensure we haven't exposed the VMWRITE-All VMX feature to the guest
3306 * when the host does not support it.
3307 */
3308 bool const fGstVmwriteAll = pVM->cpum.ro.GuestFeatures.fVmxVmwriteAll;
3309 if ( !fGstVmwriteAll
3310 || (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL))
3311 { /* likely. */ }
3312 else
3313 {
3314 LogRelFunc(("VMX VMWRITE-All feature exposed to the guest but host CPU does not support it!\n"));
3315 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_GST_HOST_VMWRITE_ALL;
3316 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3317 }
3318
3319 uint32_t const cVmcsFields = RT_ELEMENTS(g_aVmcsFields);
3320 uint32_t cRwFields = 0;
3321 uint32_t cRoFields = 0;
3322 for (uint32_t i = 0; i < cVmcsFields; i++)
3323 {
3324 VMXVMCSFIELD VmcsField;
3325 VmcsField.u = g_aVmcsFields[i];
3326
3327 /*
3328 * We will be writing "FULL" (64-bit) fields while syncing the shadow VMCS.
3329 * Therefore, "HIGH" (32-bit portion of 64-bit) fields must not be included
3330 * in the shadow VMCS fields array as they would be redundant.
3331 *
3332 * If the VMCS field depends on a CPU feature that is not exposed to the guest,
3333 * we must not include it in the shadow VMCS fields array. Guests attempting to
3334 * VMREAD/VMWRITE such VMCS fields would cause a VM-exit and we shall emulate
3335 * the required behavior.
3336 */
3337 if ( VmcsField.n.fAccessType == VMX_VMCSFIELD_ACCESS_FULL
3338 && CPUMIsGuestVmxVmcsFieldValid(pVM, VmcsField.u))
3339 {
3340 /*
3341 * Read-only fields are placed in a separate array so that while syncing shadow
3342 * VMCS fields later (which is more performance critical) we can avoid branches.
3343 *
3344 * However, if the guest can write to all fields (including read-only fields),
3345 * we treat it a as read/write field. Otherwise, writing to these fields would
3346 * cause a VMWRITE instruction error while syncing the shadow VMCS.
3347 */
3348 if ( fGstVmwriteAll
3349 || !VMXIsVmcsFieldReadOnly(VmcsField.u))
3350 pVM->hm.s.vmx.paShadowVmcsFields[cRwFields++] = VmcsField.u;
3351 else
3352 pVM->hm.s.vmx.paShadowVmcsRoFields[cRoFields++] = VmcsField.u;
3353 }
3354 }
3355
3356 /* Update the counts. */
3357 pVM->hm.s.vmx.cShadowVmcsFields = cRwFields;
3358 pVM->hm.s.vmx.cShadowVmcsRoFields = cRoFields;
3359 return VINF_SUCCESS;
3360}
3361
3362
3363/**
3364 * Sets up the VMREAD and VMWRITE bitmaps.
3365 *
3366 * @param pVM The cross context VM structure.
3367 */
3368static void hmR0VmxSetupVmreadVmwriteBitmaps(PVMCC pVM)
3369{
3370 /*
3371 * By default, ensure guest attempts to access any VMCS fields cause VM-exits.
3372 */
3373 uint32_t const cbBitmap = X86_PAGE_4K_SIZE;
3374 uint8_t *pbVmreadBitmap = (uint8_t *)pVM->hm.s.vmx.pvVmreadBitmap;
3375 uint8_t *pbVmwriteBitmap = (uint8_t *)pVM->hm.s.vmx.pvVmwriteBitmap;
3376 ASMMemFill32(pbVmreadBitmap, cbBitmap, UINT32_C(0xffffffff));
3377 ASMMemFill32(pbVmwriteBitmap, cbBitmap, UINT32_C(0xffffffff));
3378
3379 /*
3380 * Skip intercepting VMREAD/VMWRITE to guest read/write fields in the
3381 * VMREAD and VMWRITE bitmaps.
3382 */
3383 {
3384 uint32_t const *paShadowVmcsFields = pVM->hm.s.vmx.paShadowVmcsFields;
3385 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
3386 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
3387 {
3388 uint32_t const uVmcsField = paShadowVmcsFields[i];
3389 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3390 Assert(uVmcsField >> 3 < cbBitmap);
3391 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3392 ASMBitClear(pbVmwriteBitmap + (uVmcsField >> 3), uVmcsField & 7);
3393 }
3394 }
3395
3396 /*
3397 * Skip intercepting VMREAD for guest read-only fields in the VMREAD bitmap
3398 * if the host supports VMWRITE to all supported VMCS fields.
3399 */
3400 if (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL)
3401 {
3402 uint32_t const *paShadowVmcsRoFields = pVM->hm.s.vmx.paShadowVmcsRoFields;
3403 uint32_t const cShadowVmcsRoFields = pVM->hm.s.vmx.cShadowVmcsRoFields;
3404 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
3405 {
3406 uint32_t const uVmcsField = paShadowVmcsRoFields[i];
3407 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3408 Assert(uVmcsField >> 3 < cbBitmap);
3409 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3410 }
3411 }
3412}
3413#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
3414
3415
3416/**
3417 * Sets up the virtual-APIC page address for the VMCS.
3418 *
3419 * @param pVmcsInfo The VMCS info. object.
3420 */
3421DECLINLINE(void) hmR0VmxSetupVmcsVirtApicAddr(PCVMXVMCSINFO pVmcsInfo)
3422{
3423 RTHCPHYS const HCPhysVirtApic = pVmcsInfo->HCPhysVirtApic;
3424 Assert(HCPhysVirtApic != NIL_RTHCPHYS);
3425 Assert(!(HCPhysVirtApic & 0xfff)); /* Bits 11:0 MBZ. */
3426 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
3427 AssertRC(rc);
3428}
3429
3430
3431/**
3432 * Sets up the MSR-bitmap address for the VMCS.
3433 *
3434 * @param pVmcsInfo The VMCS info. object.
3435 */
3436DECLINLINE(void) hmR0VmxSetupVmcsMsrBitmapAddr(PCVMXVMCSINFO pVmcsInfo)
3437{
3438 RTHCPHYS const HCPhysMsrBitmap = pVmcsInfo->HCPhysMsrBitmap;
3439 Assert(HCPhysMsrBitmap != NIL_RTHCPHYS);
3440 Assert(!(HCPhysMsrBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3441 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_MSR_BITMAP_FULL, HCPhysMsrBitmap);
3442 AssertRC(rc);
3443}
3444
3445
3446/**
3447 * Sets up the APIC-access page address for the VMCS.
3448 *
3449 * @param pVCpu The cross context virtual CPU structure.
3450 */
3451DECLINLINE(void) hmR0VmxSetupVmcsApicAccessAddr(PVMCPUCC pVCpu)
3452{
3453 RTHCPHYS const HCPhysApicAccess = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysApicAccess;
3454 Assert(HCPhysApicAccess != NIL_RTHCPHYS);
3455 Assert(!(HCPhysApicAccess & 0xfff)); /* Bits 11:0 MBZ. */
3456 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
3457 AssertRC(rc);
3458}
3459
3460
3461#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3462/**
3463 * Sets up the VMREAD bitmap address for the VMCS.
3464 *
3465 * @param pVCpu The cross context virtual CPU structure.
3466 */
3467DECLINLINE(void) hmR0VmxSetupVmcsVmreadBitmapAddr(PVMCPUCC pVCpu)
3468{
3469 RTHCPHYS const HCPhysVmreadBitmap = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysVmreadBitmap;
3470 Assert(HCPhysVmreadBitmap != NIL_RTHCPHYS);
3471 Assert(!(HCPhysVmreadBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3472 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL, HCPhysVmreadBitmap);
3473 AssertRC(rc);
3474}
3475
3476
3477/**
3478 * Sets up the VMWRITE bitmap address for the VMCS.
3479 *
3480 * @param pVCpu The cross context virtual CPU structure.
3481 */
3482DECLINLINE(void) hmR0VmxSetupVmcsVmwriteBitmapAddr(PVMCPUCC pVCpu)
3483{
3484 RTHCPHYS const HCPhysVmwriteBitmap = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysVmwriteBitmap;
3485 Assert(HCPhysVmwriteBitmap != NIL_RTHCPHYS);
3486 Assert(!(HCPhysVmwriteBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3487 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL, HCPhysVmwriteBitmap);
3488 AssertRC(rc);
3489}
3490#endif
3491
3492
3493/**
3494 * Sets up the VM-entry MSR load, VM-exit MSR-store and VM-exit MSR-load addresses
3495 * in the VMCS.
3496 *
3497 * @returns VBox status code.
3498 * @param pVmcsInfo The VMCS info. object.
3499 */
3500DECLINLINE(int) hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(PVMXVMCSINFO pVmcsInfo)
3501{
3502 RTHCPHYS const HCPhysGuestMsrLoad = pVmcsInfo->HCPhysGuestMsrLoad;
3503 Assert(HCPhysGuestMsrLoad != NIL_RTHCPHYS);
3504 Assert(!(HCPhysGuestMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3505
3506 RTHCPHYS const HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrStore;
3507 Assert(HCPhysGuestMsrStore != NIL_RTHCPHYS);
3508 Assert(!(HCPhysGuestMsrStore & 0xf)); /* Bits 3:0 MBZ. */
3509
3510 RTHCPHYS const HCPhysHostMsrLoad = pVmcsInfo->HCPhysHostMsrLoad;
3511 Assert(HCPhysHostMsrLoad != NIL_RTHCPHYS);
3512 Assert(!(HCPhysHostMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3513
3514 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL, HCPhysGuestMsrLoad); AssertRC(rc);
3515 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL, HCPhysGuestMsrStore); AssertRC(rc);
3516 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL, HCPhysHostMsrLoad); AssertRC(rc);
3517 return VINF_SUCCESS;
3518}
3519
3520
3521/**
3522 * Sets up MSR permissions in the MSR bitmap of a VMCS info. object.
3523 *
3524 * @param pVCpu The cross context virtual CPU structure.
3525 * @param pVmcsInfo The VMCS info. object.
3526 */
3527static void hmR0VmxSetupVmcsMsrPermissions(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3528{
3529 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS);
3530
3531 /*
3532 * By default, ensure guest attempts to access any MSR cause VM-exits.
3533 * This shall later be relaxed for specific MSRs as necessary.
3534 *
3535 * Note: For nested-guests, the entire bitmap will be merged prior to
3536 * executing the nested-guest using hardware-assisted VMX and hence there
3537 * is no need to perform this operation. See hmR0VmxMergeMsrBitmapNested.
3538 */
3539 Assert(pVmcsInfo->pvMsrBitmap);
3540 ASMMemFill32(pVmcsInfo->pvMsrBitmap, X86_PAGE_4K_SIZE, UINT32_C(0xffffffff));
3541
3542 /*
3543 * The guest can access the following MSRs (read, write) without causing
3544 * VM-exits; they are loaded/stored automatically using fields in the VMCS.
3545 */
3546 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3547 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_CS, VMXMSRPM_ALLOW_RD_WR);
3548 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_ESP, VMXMSRPM_ALLOW_RD_WR);
3549 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_EIP, VMXMSRPM_ALLOW_RD_WR);
3550 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3551 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_FS_BASE, VMXMSRPM_ALLOW_RD_WR);
3552
3553 /*
3554 * The IA32_PRED_CMD and IA32_FLUSH_CMD MSRs are write-only and has no state
3555 * associated with then. We never need to intercept access (writes need to be
3556 * executed without causing a VM-exit, reads will #GP fault anyway).
3557 *
3558 * The IA32_SPEC_CTRL MSR is read/write and has state. We allow the guest to
3559 * read/write them. We swap the the guest/host MSR value using the
3560 * auto-load/store MSR area.
3561 */
3562 if (pVM->cpum.ro.GuestFeatures.fIbpb)
3563 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_PRED_CMD, VMXMSRPM_ALLOW_RD_WR);
3564 if (pVM->cpum.ro.GuestFeatures.fFlushCmd)
3565 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_FLUSH_CMD, VMXMSRPM_ALLOW_RD_WR);
3566 if (pVM->cpum.ro.GuestFeatures.fIbrs)
3567 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SPEC_CTRL, VMXMSRPM_ALLOW_RD_WR);
3568
3569 /*
3570 * Allow full read/write access for the following MSRs (mandatory for VT-x)
3571 * required for 64-bit guests.
3572 */
3573 if (pVM->hm.s.fAllow64BitGuests)
3574 {
3575 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_LSTAR, VMXMSRPM_ALLOW_RD_WR);
3576 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K6_STAR, VMXMSRPM_ALLOW_RD_WR);
3577 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_SF_MASK, VMXMSRPM_ALLOW_RD_WR);
3578 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_KERNEL_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3579 }
3580
3581 /*
3582 * IA32_EFER MSR is always intercepted, see @bugref{9180#c37}.
3583 */
3584#ifdef VBOX_STRICT
3585 Assert(pVmcsInfo->pvMsrBitmap);
3586 uint32_t const fMsrpmEfer = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, MSR_K6_EFER);
3587 Assert(fMsrpmEfer == VMXMSRPM_EXIT_RD_WR);
3588#endif
3589}
3590
3591
3592/**
3593 * Sets up pin-based VM-execution controls in the VMCS.
3594 *
3595 * @returns VBox status code.
3596 * @param pVCpu The cross context virtual CPU structure.
3597 * @param pVmcsInfo The VMCS info. object.
3598 */
3599static int hmR0VmxSetupVmcsPinCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3600{
3601 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3602 uint32_t fVal = pVM->hm.s.vmx.Msrs.PinCtls.n.allowed0; /* Bits set here must always be set. */
3603 uint32_t const fZap = pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
3604
3605 fVal |= VMX_PIN_CTLS_EXT_INT_EXIT /* External interrupts cause a VM-exit. */
3606 | VMX_PIN_CTLS_NMI_EXIT; /* Non-maskable interrupts (NMIs) cause a VM-exit. */
3607
3608 if (pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1 & VMX_PIN_CTLS_VIRT_NMI)
3609 fVal |= VMX_PIN_CTLS_VIRT_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
3610
3611 /* Enable the VMX-preemption timer. */
3612 if (pVM->hm.s.vmx.fUsePreemptTimer)
3613 {
3614 Assert(pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1 & VMX_PIN_CTLS_PREEMPT_TIMER);
3615 fVal |= VMX_PIN_CTLS_PREEMPT_TIMER;
3616 }
3617
3618#if 0
3619 /* Enable posted-interrupt processing. */
3620 if (pVM->hm.s.fPostedIntrs)
3621 {
3622 Assert(pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1 & VMX_PIN_CTLS_POSTED_INT);
3623 Assert(pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_ACK_EXT_INT);
3624 fVal |= VMX_PIN_CTLS_POSTED_INT;
3625 }
3626#endif
3627
3628 if ((fVal & fZap) != fVal)
3629 {
3630 LogRelFunc(("Invalid pin-based VM-execution controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3631 pVM->hm.s.vmx.Msrs.PinCtls.n.allowed0, fVal, fZap));
3632 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
3633 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3634 }
3635
3636 /* Commit it to the VMCS and update our cache. */
3637 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, fVal);
3638 AssertRC(rc);
3639 pVmcsInfo->u32PinCtls = fVal;
3640
3641 return VINF_SUCCESS;
3642}
3643
3644
3645/**
3646 * Sets up secondary processor-based VM-execution controls in the VMCS.
3647 *
3648 * @returns VBox status code.
3649 * @param pVCpu The cross context virtual CPU structure.
3650 * @param pVmcsInfo The VMCS info. object.
3651 */
3652static int hmR0VmxSetupVmcsProcCtls2(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3653{
3654 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3655 uint32_t fVal = pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed0; /* Bits set here must be set in the VMCS. */
3656 uint32_t const fZap = pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3657
3658 /* WBINVD causes a VM-exit. */
3659 if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_WBINVD_EXIT)
3660 fVal |= VMX_PROC_CTLS2_WBINVD_EXIT;
3661
3662 /* Enable EPT (aka nested-paging). */
3663 if (pVM->hm.s.fNestedPaging)
3664 fVal |= VMX_PROC_CTLS2_EPT;
3665
3666 /* Enable the INVPCID instruction if we expose it to the guest and is supported
3667 by the hardware. Without this, guest executing INVPCID would cause a #UD. */
3668 if ( pVM->cpum.ro.GuestFeatures.fInvpcid
3669 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_INVPCID))
3670 fVal |= VMX_PROC_CTLS2_INVPCID;
3671
3672 /* Enable VPID. */
3673 if (pVM->hm.s.vmx.fVpid)
3674 fVal |= VMX_PROC_CTLS2_VPID;
3675
3676 /* Enable unrestricted guest execution. */
3677 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3678 fVal |= VMX_PROC_CTLS2_UNRESTRICTED_GUEST;
3679
3680#if 0
3681 if (pVM->hm.s.fVirtApicRegs)
3682 {
3683 /* Enable APIC-register virtualization. */
3684 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_APIC_REG_VIRT);
3685 fVal |= VMX_PROC_CTLS2_APIC_REG_VIRT;
3686
3687 /* Enable virtual-interrupt delivery. */
3688 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_INTR_DELIVERY);
3689 fVal |= VMX_PROC_CTLS2_VIRT_INTR_DELIVERY;
3690 }
3691#endif
3692
3693 /* Virtualize-APIC accesses if supported by the CPU. The virtual-APIC page is
3694 where the TPR shadow resides. */
3695 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
3696 * done dynamically. */
3697 if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
3698 {
3699 fVal |= VMX_PROC_CTLS2_VIRT_APIC_ACCESS;
3700 hmR0VmxSetupVmcsApicAccessAddr(pVCpu);
3701 }
3702
3703 /* Enable the RDTSCP instruction if we expose it to the guest and is supported
3704 by the hardware. Without this, guest executing RDTSCP would cause a #UD. */
3705 if ( pVM->cpum.ro.GuestFeatures.fRdTscP
3706 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_RDTSCP))
3707 fVal |= VMX_PROC_CTLS2_RDTSCP;
3708
3709 /* Enable Pause-Loop exiting. */
3710 if ( (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)
3711 && pVM->hm.s.vmx.cPleGapTicks
3712 && pVM->hm.s.vmx.cPleWindowTicks)
3713 {
3714 fVal |= VMX_PROC_CTLS2_PAUSE_LOOP_EXIT;
3715
3716 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, pVM->hm.s.vmx.cPleGapTicks); AssertRC(rc);
3717 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, pVM->hm.s.vmx.cPleWindowTicks); AssertRC(rc);
3718 }
3719
3720 if ((fVal & fZap) != fVal)
3721 {
3722 LogRelFunc(("Invalid secondary processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3723 pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed0, fVal, fZap));
3724 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
3725 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3726 }
3727
3728 /* Commit it to the VMCS and update our cache. */
3729 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, fVal);
3730 AssertRC(rc);
3731 pVmcsInfo->u32ProcCtls2 = fVal;
3732
3733 return VINF_SUCCESS;
3734}
3735
3736
3737/**
3738 * Sets up processor-based VM-execution controls in the VMCS.
3739 *
3740 * @returns VBox status code.
3741 * @param pVCpu The cross context virtual CPU structure.
3742 * @param pVmcsInfo The VMCS info. object.
3743 */
3744static int hmR0VmxSetupVmcsProcCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3745{
3746 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3747 uint32_t fVal = pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
3748 uint32_t const fZap = pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3749
3750 fVal |= VMX_PROC_CTLS_HLT_EXIT /* HLT causes a VM-exit. */
3751 | VMX_PROC_CTLS_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
3752 | VMX_PROC_CTLS_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
3753 | VMX_PROC_CTLS_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
3754 | VMX_PROC_CTLS_RDPMC_EXIT /* RDPMC causes a VM-exit. */
3755 | VMX_PROC_CTLS_MONITOR_EXIT /* MONITOR causes a VM-exit. */
3756 | VMX_PROC_CTLS_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
3757
3758 /* We toggle VMX_PROC_CTLS_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
3759 if ( !(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MOV_DR_EXIT)
3760 || (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0 & VMX_PROC_CTLS_MOV_DR_EXIT))
3761 {
3762 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
3763 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3764 }
3765
3766 /* Without nested paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
3767 if (!pVM->hm.s.fNestedPaging)
3768 {
3769 Assert(!pVM->hm.s.vmx.fUnrestrictedGuest);
3770 fVal |= VMX_PROC_CTLS_INVLPG_EXIT
3771 | VMX_PROC_CTLS_CR3_LOAD_EXIT
3772 | VMX_PROC_CTLS_CR3_STORE_EXIT;
3773 }
3774
3775 /* Use TPR shadowing if supported by the CPU. */
3776 if ( PDMHasApic(pVM)
3777 && (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW))
3778 {
3779 fVal |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
3780 /* CR8 writes cause a VM-exit based on TPR threshold. */
3781 Assert(!(fVal & VMX_PROC_CTLS_CR8_STORE_EXIT));
3782 Assert(!(fVal & VMX_PROC_CTLS_CR8_LOAD_EXIT));
3783 hmR0VmxSetupVmcsVirtApicAddr(pVmcsInfo);
3784 }
3785 else
3786 {
3787 /* Some 32-bit CPUs do not support CR8 load/store exiting as MOV CR8 is
3788 invalid on 32-bit Intel CPUs. Set this control only for 64-bit guests. */
3789 if (pVM->hm.s.fAllow64BitGuests)
3790 {
3791 fVal |= VMX_PROC_CTLS_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
3792 | VMX_PROC_CTLS_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
3793 }
3794 }
3795
3796 /* Use MSR-bitmaps if supported by the CPU. */
3797 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
3798 {
3799 fVal |= VMX_PROC_CTLS_USE_MSR_BITMAPS;
3800 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
3801 }
3802
3803 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
3804 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
3805 fVal |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
3806
3807 if ((fVal & fZap) != fVal)
3808 {
3809 LogRelFunc(("Invalid processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3810 pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0, fVal, fZap));
3811 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
3812 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3813 }
3814
3815 /* Commit it to the VMCS and update our cache. */
3816 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, fVal);
3817 AssertRC(rc);
3818 pVmcsInfo->u32ProcCtls = fVal;
3819
3820 /* Set up MSR permissions that don't change through the lifetime of the VM. */
3821 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
3822 hmR0VmxSetupVmcsMsrPermissions(pVCpu, pVmcsInfo);
3823
3824 /* Set up secondary processor-based VM-execution controls if the CPU supports it. */
3825 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
3826 return hmR0VmxSetupVmcsProcCtls2(pVCpu, pVmcsInfo);
3827
3828 /* Sanity check, should not really happen. */
3829 if (RT_LIKELY(!pVM->hm.s.vmx.fUnrestrictedGuest))
3830 { /* likely */ }
3831 else
3832 {
3833 pVCpu->hm.s.u32HMError = VMX_UFC_INVALID_UX_COMBO;
3834 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3835 }
3836
3837 /* Old CPUs without secondary processor-based VM-execution controls would end up here. */
3838 return VINF_SUCCESS;
3839}
3840
3841
3842/**
3843 * Sets up miscellaneous (everything other than Pin, Processor and secondary
3844 * Processor-based VM-execution) control fields in the VMCS.
3845 *
3846 * @returns VBox status code.
3847 * @param pVCpu The cross context virtual CPU structure.
3848 * @param pVmcsInfo The VMCS info. object.
3849 */
3850static int hmR0VmxSetupVmcsMiscCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3851{
3852#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3853 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
3854 {
3855 hmR0VmxSetupVmcsVmreadBitmapAddr(pVCpu);
3856 hmR0VmxSetupVmcsVmwriteBitmapAddr(pVCpu);
3857 }
3858#endif
3859
3860 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
3861 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
3862 AssertRC(rc);
3863
3864 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
3865 if (RT_SUCCESS(rc))
3866 {
3867 uint64_t const u64Cr0Mask = hmR0VmxGetFixedCr0Mask(pVCpu);
3868 uint64_t const u64Cr4Mask = hmR0VmxGetFixedCr4Mask(pVCpu);
3869
3870 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask); AssertRC(rc);
3871 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask); AssertRC(rc);
3872
3873 pVmcsInfo->u64Cr0Mask = u64Cr0Mask;
3874 pVmcsInfo->u64Cr4Mask = u64Cr4Mask;
3875 return VINF_SUCCESS;
3876 }
3877 else
3878 LogRelFunc(("Failed to initialize VMCS auto-load/store MSR addresses. rc=%Rrc\n", rc));
3879 return rc;
3880}
3881
3882
3883/**
3884 * Sets up the initial exception bitmap in the VMCS based on static conditions.
3885 *
3886 * We shall setup those exception intercepts that don't change during the
3887 * lifetime of the VM here. The rest are done dynamically while loading the
3888 * guest state.
3889 *
3890 * @param pVCpu The cross context virtual CPU structure.
3891 * @param pVmcsInfo The VMCS info. object.
3892 */
3893static void hmR0VmxSetupVmcsXcptBitmap(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3894{
3895 /*
3896 * The following exceptions are always intercepted:
3897 *
3898 * #AC - To prevent the guest from hanging the CPU.
3899 * #DB - To maintain the DR6 state even when intercepting DRx reads/writes and
3900 * recursive #DBs can cause a CPU hang.
3901 * #PF - To sync our shadow page tables when nested-paging is not used.
3902 */
3903 bool const fNestedPaging = pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging;
3904 uint32_t const uXcptBitmap = RT_BIT(X86_XCPT_AC)
3905 | RT_BIT(X86_XCPT_DB)
3906 | (fNestedPaging ? 0 : RT_BIT(X86_XCPT_PF));
3907
3908 /* Commit it to the VMCS. */
3909 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
3910 AssertRC(rc);
3911
3912 /* Update our cache of the exception bitmap. */
3913 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
3914}
3915
3916
3917#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3918/**
3919 * Sets up the VMCS for executing a nested-guest using hardware-assisted VMX.
3920 *
3921 * @returns VBox status code.
3922 * @param pVCpu The cross context virtual CPU structure.
3923 * @param pVmcsInfo The VMCS info. object.
3924 */
3925static int hmR0VmxSetupVmcsCtlsNested(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3926{
3927 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
3928 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
3929 AssertRC(rc);
3930
3931 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
3932 if (RT_SUCCESS(rc))
3933 {
3934 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
3935 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
3936
3937 /* Paranoia - We've not yet initialized these, they shall be done while merging the VMCS. */
3938 Assert(!pVmcsInfo->u64Cr0Mask);
3939 Assert(!pVmcsInfo->u64Cr4Mask);
3940 return VINF_SUCCESS;
3941 }
3942 else
3943 LogRelFunc(("Failed to set up the VMCS link pointer in the nested-guest VMCS. rc=%Rrc\n", rc));
3944 return rc;
3945}
3946#endif
3947
3948
3949/**
3950 * Sets up the VMCS for executing a guest (or nested-guest) using hardware-assisted
3951 * VMX.
3952 *
3953 * @returns VBox status code.
3954 * @param pVCpu The cross context virtual CPU structure.
3955 * @param pVmcsInfo The VMCS info. object.
3956 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
3957 */
3958static int hmR0VmxSetupVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
3959{
3960 Assert(pVmcsInfo->pvVmcs);
3961 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
3962
3963 /* Set the CPU specified revision identifier at the beginning of the VMCS structure. */
3964 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3965 *(uint32_t *)pVmcsInfo->pvVmcs = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
3966 const char * const pszVmcs = fIsNstGstVmcs ? "nested-guest VMCS" : "guest VMCS";
3967
3968 LogFlowFunc(("\n"));
3969
3970 /*
3971 * Initialize the VMCS using VMCLEAR before loading the VMCS.
3972 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
3973 */
3974 int rc = hmR0VmxClearVmcs(pVmcsInfo);
3975 if (RT_SUCCESS(rc))
3976 {
3977 rc = hmR0VmxLoadVmcs(pVmcsInfo);
3978 if (RT_SUCCESS(rc))
3979 {
3980 if (!fIsNstGstVmcs)
3981 {
3982 rc = hmR0VmxSetupVmcsPinCtls(pVCpu, pVmcsInfo);
3983 if (RT_SUCCESS(rc))
3984 {
3985 rc = hmR0VmxSetupVmcsProcCtls(pVCpu, pVmcsInfo);
3986 if (RT_SUCCESS(rc))
3987 {
3988 rc = hmR0VmxSetupVmcsMiscCtls(pVCpu, pVmcsInfo);
3989 if (RT_SUCCESS(rc))
3990 {
3991 hmR0VmxSetupVmcsXcptBitmap(pVCpu, pVmcsInfo);
3992#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3993 /*
3994 * If a shadow VMCS is allocated for the VMCS info. object, initialize the
3995 * VMCS revision ID and shadow VMCS indicator bit. Also, clear the VMCS
3996 * making it fit for use when VMCS shadowing is later enabled.
3997 */
3998 if (pVmcsInfo->pvShadowVmcs)
3999 {
4000 VMXVMCSREVID VmcsRevId;
4001 VmcsRevId.u = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
4002 VmcsRevId.n.fIsShadowVmcs = 1;
4003 *(uint32_t *)pVmcsInfo->pvShadowVmcs = VmcsRevId.u;
4004 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
4005 if (RT_SUCCESS(rc))
4006 { /* likely */ }
4007 else
4008 LogRelFunc(("Failed to initialize shadow VMCS. rc=%Rrc\n", rc));
4009 }
4010#endif
4011 }
4012 else
4013 LogRelFunc(("Failed to setup miscellaneous controls. rc=%Rrc\n", rc));
4014 }
4015 else
4016 LogRelFunc(("Failed to setup processor-based VM-execution controls. rc=%Rrc\n", rc));
4017 }
4018 else
4019 LogRelFunc(("Failed to setup pin-based controls. rc=%Rrc\n", rc));
4020 }
4021 else
4022 {
4023#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4024 rc = hmR0VmxSetupVmcsCtlsNested(pVCpu, pVmcsInfo);
4025 if (RT_SUCCESS(rc))
4026 { /* likely */ }
4027 else
4028 LogRelFunc(("Failed to initialize nested-guest VMCS. rc=%Rrc\n", rc));
4029#else
4030 AssertFailed();
4031#endif
4032 }
4033 }
4034 else
4035 LogRelFunc(("Failed to load the %s. rc=%Rrc\n", rc, pszVmcs));
4036 }
4037 else
4038 LogRelFunc(("Failed to clear the %s. rc=%Rrc\n", rc, pszVmcs));
4039
4040 /* Sync any CPU internal VMCS data back into our VMCS in memory. */
4041 if (RT_SUCCESS(rc))
4042 {
4043 rc = hmR0VmxClearVmcs(pVmcsInfo);
4044 if (RT_SUCCESS(rc))
4045 { /* likely */ }
4046 else
4047 LogRelFunc(("Failed to clear the %s post setup. rc=%Rrc\n", rc, pszVmcs));
4048 }
4049
4050 /*
4051 * Update the last-error record both for failures and success, so we
4052 * can propagate the status code back to ring-3 for diagnostics.
4053 */
4054 hmR0VmxUpdateErrorRecord(pVCpu, rc);
4055 NOREF(pszVmcs);
4056 return rc;
4057}
4058
4059
4060/**
4061 * Does global VT-x initialization (called during module initialization).
4062 *
4063 * @returns VBox status code.
4064 */
4065VMMR0DECL(int) VMXR0GlobalInit(void)
4066{
4067#ifdef HMVMX_USE_FUNCTION_TABLE
4068 AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(g_apfnVMExitHandlers));
4069# ifdef VBOX_STRICT
4070 for (unsigned i = 0; i < RT_ELEMENTS(g_apfnVMExitHandlers); i++)
4071 Assert(g_apfnVMExitHandlers[i]);
4072# endif
4073#endif
4074 return VINF_SUCCESS;
4075}
4076
4077
4078/**
4079 * Does global VT-x termination (called during module termination).
4080 */
4081VMMR0DECL(void) VMXR0GlobalTerm()
4082{
4083 /* Nothing to do currently. */
4084}
4085
4086
4087/**
4088 * Sets up and activates VT-x on the current CPU.
4089 *
4090 * @returns VBox status code.
4091 * @param pHostCpu The HM physical-CPU structure.
4092 * @param pVM The cross context VM structure. Can be
4093 * NULL after a host resume operation.
4094 * @param pvCpuPage Pointer to the VMXON region (can be NULL if @a
4095 * fEnabledByHost is @c true).
4096 * @param HCPhysCpuPage Physical address of the VMXON region (can be 0 if
4097 * @a fEnabledByHost is @c true).
4098 * @param fEnabledByHost Set if SUPR0EnableVTx() or similar was used to
4099 * enable VT-x on the host.
4100 * @param pHwvirtMsrs Pointer to the hardware-virtualization MSRs.
4101 */
4102VMMR0DECL(int) VMXR0EnableCpu(PHMPHYSCPU pHostCpu, PVMCC pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost,
4103 PCSUPHWVIRTMSRS pHwvirtMsrs)
4104{
4105 AssertPtr(pHostCpu);
4106 AssertPtr(pHwvirtMsrs);
4107 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4108
4109 /* Enable VT-x if it's not already enabled by the host. */
4110 if (!fEnabledByHost)
4111 {
4112 int rc = hmR0VmxEnterRootMode(pHostCpu, pVM, HCPhysCpuPage, pvCpuPage);
4113 if (RT_FAILURE(rc))
4114 return rc;
4115 }
4116
4117 /*
4118 * Flush all EPT tagged-TLB entries (in case VirtualBox or any other hypervisor have been
4119 * using EPTPs) so we don't retain any stale guest-physical mappings which won't get
4120 * invalidated when flushing by VPID.
4121 */
4122 if (pHwvirtMsrs->u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
4123 {
4124 hmR0VmxFlushEpt(NULL /* pVCpu */, NULL /* pVmcsInfo */, VMXTLBFLUSHEPT_ALL_CONTEXTS);
4125 pHostCpu->fFlushAsidBeforeUse = false;
4126 }
4127 else
4128 pHostCpu->fFlushAsidBeforeUse = true;
4129
4130 /* Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}. */
4131 ++pHostCpu->cTlbFlushes;
4132
4133 return VINF_SUCCESS;
4134}
4135
4136
4137/**
4138 * Deactivates VT-x on the current CPU.
4139 *
4140 * @returns VBox status code.
4141 * @param pHostCpu The HM physical-CPU structure.
4142 * @param pvCpuPage Pointer to the VMXON region.
4143 * @param HCPhysCpuPage Physical address of the VMXON region.
4144 *
4145 * @remarks This function should never be called when SUPR0EnableVTx() or
4146 * similar was used to enable VT-x on the host.
4147 */
4148VMMR0DECL(int) VMXR0DisableCpu(PHMPHYSCPU pHostCpu, void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
4149{
4150 RT_NOREF2(pvCpuPage, HCPhysCpuPage);
4151
4152 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4153 return hmR0VmxLeaveRootMode(pHostCpu);
4154}
4155
4156
4157/**
4158 * Does per-VM VT-x initialization.
4159 *
4160 * @returns VBox status code.
4161 * @param pVM The cross context VM structure.
4162 */
4163VMMR0DECL(int) VMXR0InitVM(PVMCC pVM)
4164{
4165 AssertPtr(pVM);
4166 LogFlowFunc(("pVM=%p\n", pVM));
4167
4168 hmR0VmxStructsInit(pVM);
4169 int rc = hmR0VmxStructsAlloc(pVM);
4170 if (RT_FAILURE(rc))
4171 {
4172 LogRelFunc(("Failed to allocated VMX structures. rc=%Rrc\n", rc));
4173 return rc;
4174 }
4175
4176 /* Setup the crash dump page. */
4177#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4178 strcpy((char *)pVM->hm.s.vmx.pbScratch, "SCRATCH Magic");
4179 *(uint64_t *)(pVM->hm.s.vmx.pbScratch + 16) = UINT64_C(0xdeadbeefdeadbeef);
4180#endif
4181 return VINF_SUCCESS;
4182}
4183
4184
4185/**
4186 * Does per-VM VT-x termination.
4187 *
4188 * @returns VBox status code.
4189 * @param pVM The cross context VM structure.
4190 */
4191VMMR0DECL(int) VMXR0TermVM(PVMCC pVM)
4192{
4193 AssertPtr(pVM);
4194 LogFlowFunc(("pVM=%p\n", pVM));
4195
4196#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4197 if (pVM->hm.s.vmx.hMemObjScratch != NIL_RTR0MEMOBJ)
4198 {
4199 Assert(pVM->hm.s.vmx.pvScratch);
4200 ASMMemZero32(pVM->hm.s.vmx.pvScratch, X86_PAGE_4K_SIZE);
4201 }
4202#endif
4203 hmR0VmxStructsFree(pVM);
4204 return VINF_SUCCESS;
4205}
4206
4207
4208/**
4209 * Sets up the VM for execution using hardware-assisted VMX.
4210 * This function is only called once per-VM during initialization.
4211 *
4212 * @returns VBox status code.
4213 * @param pVM The cross context VM structure.
4214 */
4215VMMR0DECL(int) VMXR0SetupVM(PVMCC pVM)
4216{
4217 AssertPtr(pVM);
4218 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4219
4220 LogFlowFunc(("pVM=%p\n", pVM));
4221
4222 /*
4223 * At least verify if VMX is enabled, since we can't check if we're in VMX root mode or not
4224 * without causing a #GP.
4225 */
4226 RTCCUINTREG const uHostCr4 = ASMGetCR4();
4227 if (RT_LIKELY(uHostCr4 & X86_CR4_VMXE))
4228 { /* likely */ }
4229 else
4230 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
4231
4232 /*
4233 * Without unrestricted guest execution, pRealModeTSS and pNonPagingModeEPTPageTable *must*
4234 * always be allocated. We no longer support the highly unlikely case of unrestricted guest
4235 * without pRealModeTSS, see hmR3InitFinalizeR0Intel().
4236 */
4237 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
4238 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
4239 || !pVM->hm.s.vmx.pRealModeTSS))
4240 {
4241 LogRelFunc(("Invalid real-on-v86 state.\n"));
4242 return VERR_INTERNAL_ERROR;
4243 }
4244
4245 /* Initialize these always, see hmR3InitFinalizeR0().*/
4246 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NONE;
4247 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NONE;
4248
4249 /* Setup the tagged-TLB flush handlers. */
4250 int rc = hmR0VmxSetupTaggedTlb(pVM);
4251 if (RT_FAILURE(rc))
4252 {
4253 LogRelFunc(("Failed to setup tagged TLB. rc=%Rrc\n", rc));
4254 return rc;
4255 }
4256
4257#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4258 /* Setup the shadow VMCS fields array and VMREAD/VMWRITE bitmaps. */
4259 if (pVM->hm.s.vmx.fUseVmcsShadowing)
4260 {
4261 rc = hmR0VmxSetupShadowVmcsFieldsArrays(pVM);
4262 if (RT_SUCCESS(rc))
4263 hmR0VmxSetupVmreadVmwriteBitmaps(pVM);
4264 else
4265 {
4266 LogRelFunc(("Failed to setup shadow VMCS fields arrays. rc=%Rrc\n", rc));
4267 return rc;
4268 }
4269 }
4270#endif
4271
4272 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
4273 {
4274 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
4275 Log4Func(("pVCpu=%p idCpu=%RU32\n", pVCpu, pVCpu->idCpu));
4276
4277 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hm.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
4278 if (RT_SUCCESS(rc))
4279 {
4280#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4281 if (pVM->cpum.ro.GuestFeatures.fVmx)
4282 {
4283 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hm.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
4284 if (RT_SUCCESS(rc))
4285 { /* likely */ }
4286 else
4287 {
4288 LogRelFunc(("Nested-guest VMCS setup failed. rc=%Rrc\n", rc));
4289 return rc;
4290 }
4291 }
4292#endif
4293 }
4294 else
4295 {
4296 LogRelFunc(("VMCS setup failed. rc=%Rrc\n", rc));
4297 return rc;
4298 }
4299 }
4300
4301 return VINF_SUCCESS;
4302}
4303
4304
4305/**
4306 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
4307 * the VMCS.
4308 */
4309static void hmR0VmxExportHostControlRegs(void)
4310{
4311 int rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR0, ASMGetCR0()); AssertRC(rc);
4312 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR3, ASMGetCR3()); AssertRC(rc);
4313 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR4, ASMGetCR4()); AssertRC(rc);
4314}
4315
4316
4317/**
4318 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
4319 * the host-state area in the VMCS.
4320 *
4321 * @returns VBox status code.
4322 * @param pVCpu The cross context virtual CPU structure.
4323 */
4324static int hmR0VmxExportHostSegmentRegs(PVMCPUCC pVCpu)
4325{
4326/**
4327 * Macro for adjusting host segment selectors to satisfy VT-x's VM-entry
4328 * requirements. See hmR0VmxExportHostSegmentRegs().
4329 */
4330#define VMXLOCAL_ADJUST_HOST_SEG(a_Seg, a_selValue) \
4331 if ((a_selValue) & (X86_SEL_RPL | X86_SEL_LDT)) \
4332 { \
4333 bool fValidSelector = true; \
4334 if ((a_selValue) & X86_SEL_LDT) \
4335 { \
4336 uint32_t const uAttr = ASMGetSegAttr(a_selValue); \
4337 fValidSelector = RT_BOOL(uAttr != UINT32_MAX && (uAttr & X86_DESC_P)); \
4338 } \
4339 if (fValidSelector) \
4340 { \
4341 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4342 pVCpu->hm.s.vmx.RestoreHost.uHostSel##a_Seg = (a_selValue); \
4343 } \
4344 (a_selValue) = 0; \
4345 }
4346
4347 /*
4348 * If we've executed guest code using hardware-assisted VMX, the host-state bits
4349 * will be messed up. We should -not- save the messed up state without restoring
4350 * the original host-state, see @bugref{7240}.
4351 *
4352 * This apparently can happen (most likely the FPU changes), deal with it rather than
4353 * asserting. Was observed booting Solaris 10u10 32-bit guest.
4354 */
4355 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
4356 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
4357 {
4358 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags,
4359 pVCpu->idCpu));
4360 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
4361 }
4362 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
4363
4364 /*
4365 * Host segment registers.
4366 */
4367 RTSEL uSelES = ASMGetES();
4368 RTSEL uSelCS = ASMGetCS();
4369 RTSEL uSelSS = ASMGetSS();
4370 RTSEL uSelDS = ASMGetDS();
4371 RTSEL uSelFS = ASMGetFS();
4372 RTSEL uSelGS = ASMGetGS();
4373 RTSEL uSelTR = ASMGetTR();
4374
4375 /*
4376 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to
4377 * gain VM-entry and restore them before we get preempted.
4378 *
4379 * See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
4380 */
4381 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
4382 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
4383 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
4384 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
4385
4386 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
4387 Assert(!(uSelCS & X86_SEL_RPL)); Assert(!(uSelCS & X86_SEL_LDT));
4388 Assert(!(uSelSS & X86_SEL_RPL)); Assert(!(uSelSS & X86_SEL_LDT));
4389 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
4390 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
4391 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
4392 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
4393 Assert(!(uSelTR & X86_SEL_RPL)); Assert(!(uSelTR & X86_SEL_LDT));
4394 Assert(uSelCS);
4395 Assert(uSelTR);
4396
4397 /* Write these host selector fields into the host-state area in the VMCS. */
4398 int rc = VMXWriteVmcs16(VMX_VMCS16_HOST_CS_SEL, uSelCS); AssertRC(rc);
4399 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_SS_SEL, uSelSS); AssertRC(rc);
4400 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_DS_SEL, uSelDS); AssertRC(rc);
4401 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_ES_SEL, uSelES); AssertRC(rc);
4402 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_FS_SEL, uSelFS); AssertRC(rc);
4403 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_GS_SEL, uSelGS); AssertRC(rc);
4404 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_TR_SEL, uSelTR); AssertRC(rc);
4405
4406 /*
4407 * Host GDTR and IDTR.
4408 */
4409 RTGDTR Gdtr;
4410 RTIDTR Idtr;
4411 RT_ZERO(Gdtr);
4412 RT_ZERO(Idtr);
4413 ASMGetGDTR(&Gdtr);
4414 ASMGetIDTR(&Idtr);
4415 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GDTR_BASE, Gdtr.pGdt); AssertRC(rc);
4416 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_IDTR_BASE, Idtr.pIdt); AssertRC(rc);
4417
4418 /*
4419 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps
4420 * them to the maximum limit (0xffff) on every VM-exit.
4421 */
4422 if (Gdtr.cbGdt != 0xffff)
4423 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
4424
4425 /*
4426 * IDT limit is effectively capped at 0xfff. (See Intel spec. 6.14.1 "64-Bit Mode IDT" and
4427 * Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit
4428 * as 0xfff, VT-x bloating the limit to 0xffff shouldn't cause any different CPU behavior.
4429 * However, several hosts either insists on 0xfff being the limit (Windows Patch Guard) or
4430 * uses the limit for other purposes (darwin puts the CPU ID in there but botches sidt
4431 * alignment in at least one consumer). So, we're only allowing the IDTR.LIMIT to be left
4432 * at 0xffff on hosts where we are sure it won't cause trouble.
4433 */
4434#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
4435 if (Idtr.cbIdt < 0x0fff)
4436#else
4437 if (Idtr.cbIdt != 0xffff)
4438#endif
4439 {
4440 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
4441 AssertCompile(sizeof(Idtr) == sizeof(X86XDTR64));
4442 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostIdtr, &Idtr, sizeof(X86XDTR64));
4443 }
4444
4445 /*
4446 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI
4447 * and RPL bits is effectively what the CPU does for "scaling by 8". TI is always 0 and
4448 * RPL should be too in most cases.
4449 */
4450 AssertMsgReturn((uSelTR | X86_SEL_RPL_LDT) <= Gdtr.cbGdt,
4451 ("TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, Gdtr.cbGdt), VERR_VMX_INVALID_HOST_STATE);
4452
4453 PCX86DESCHC pDesc = (PCX86DESCHC)(Gdtr.pGdt + (uSelTR & X86_SEL_MASK));
4454 uintptr_t const uTRBase = X86DESC64_BASE(pDesc);
4455
4456 /*
4457 * VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on
4458 * all VM-exits. The type is the same for 64-bit busy TSS[1]. The limit needs manual
4459 * restoration if the host has something else. Task switching is not supported in 64-bit
4460 * mode[2], but the limit still matters as IOPM is supported in 64-bit mode. Restoring the
4461 * limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
4462 *
4463 * [1] See Intel spec. 3.5 "System Descriptor Types".
4464 * [2] See Intel spec. 7.2.3 "TSS Descriptor in 64-bit mode".
4465 */
4466 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4467 Assert(pDesc->System.u4Type == 11);
4468 if ( pDesc->System.u16LimitLow != 0x67
4469 || pDesc->System.u4LimitHigh)
4470 {
4471 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_TR;
4472 /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */
4473 if (pVM->hm.s.fHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY)
4474 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY;
4475 pVCpu->hm.s.vmx.RestoreHost.uHostSelTR = uSelTR;
4476 }
4477
4478 /*
4479 * Store the GDTR as we need it when restoring the GDT and while restoring the TR.
4480 */
4481 if (pVCpu->hm.s.vmx.fRestoreHostFlags & (VMX_RESTORE_HOST_GDTR | VMX_RESTORE_HOST_SEL_TR))
4482 {
4483 AssertCompile(sizeof(Gdtr) == sizeof(X86XDTR64));
4484 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
4485 if (pVM->hm.s.fHostKernelFeatures & SUPKERNELFEATURES_GDT_NEED_WRITABLE)
4486 {
4487 /* The GDT is read-only but the writable GDT is available. */
4488 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_NEED_WRITABLE;
4489 pVCpu->hm.s.vmx.RestoreHost.HostGdtrRw.cb = Gdtr.cbGdt;
4490 rc = SUPR0GetCurrentGdtRw(&pVCpu->hm.s.vmx.RestoreHost.HostGdtrRw.uAddr);
4491 AssertRCReturn(rc, rc);
4492 }
4493 }
4494
4495 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_TR_BASE, uTRBase);
4496 AssertRC(rc);
4497
4498 /*
4499 * Host FS base and GS base.
4500 */
4501 uint64_t const u64FSBase = ASMRdMsr(MSR_K8_FS_BASE);
4502 uint64_t const u64GSBase = ASMRdMsr(MSR_K8_GS_BASE);
4503 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_FS_BASE, u64FSBase); AssertRC(rc);
4504 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GS_BASE, u64GSBase); AssertRC(rc);
4505
4506 /* Store the base if we have to restore FS or GS manually as we need to restore the base as well. */
4507 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_FS)
4508 pVCpu->hm.s.vmx.RestoreHost.uHostFSBase = u64FSBase;
4509 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_GS)
4510 pVCpu->hm.s.vmx.RestoreHost.uHostGSBase = u64GSBase;
4511
4512 return VINF_SUCCESS;
4513#undef VMXLOCAL_ADJUST_HOST_SEG
4514}
4515
4516
4517/**
4518 * Exports certain host MSRs in the VM-exit MSR-load area and some in the
4519 * host-state area of the VMCS.
4520 *
4521 * These MSRs will be automatically restored on the host after every successful
4522 * VM-exit.
4523 *
4524 * @param pVCpu The cross context virtual CPU structure.
4525 *
4526 * @remarks No-long-jump zone!!!
4527 */
4528static void hmR0VmxExportHostMsrs(PVMCPUCC pVCpu)
4529{
4530 AssertPtr(pVCpu);
4531
4532 /*
4533 * Save MSRs that we restore lazily (due to preemption or transition to ring-3)
4534 * rather than swapping them on every VM-entry.
4535 */
4536 hmR0VmxLazySaveHostMsrs(pVCpu);
4537
4538 /*
4539 * Host Sysenter MSRs.
4540 */
4541 int rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS)); AssertRC(rc);
4542 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP)); AssertRC(rc);
4543 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP)); AssertRC(rc);
4544
4545 /*
4546 * Host EFER MSR.
4547 *
4548 * If the CPU supports the newer VMCS controls for managing EFER, use it. Otherwise it's
4549 * done as part of auto-load/store MSR area in the VMCS, see hmR0VmxExportGuestMsrs().
4550 */
4551 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4552 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
4553 {
4554 rc = VMXWriteVmcs64(VMX_VMCS64_HOST_EFER_FULL, pVM->hm.s.vmx.u64HostMsrEfer);
4555 AssertRC(rc);
4556 }
4557
4558 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT also see
4559 * hmR0VmxExportGuestEntryExitCtls(). */
4560}
4561
4562
4563/**
4564 * Figures out if we need to swap the EFER MSR which is particularly expensive.
4565 *
4566 * We check all relevant bits. For now, that's everything besides LMA/LME, as
4567 * these two bits are handled by VM-entry, see hmR0VMxExportGuestEntryExitCtls().
4568 *
4569 * @returns true if we need to load guest EFER, false otherwise.
4570 * @param pVCpu The cross context virtual CPU structure.
4571 * @param pVmxTransient The VMX-transient structure.
4572 *
4573 * @remarks Requires EFER, CR4.
4574 * @remarks No-long-jump zone!!!
4575 */
4576static bool hmR0VmxShouldSwapEferMsr(PCVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
4577{
4578#ifdef HMVMX_ALWAYS_SWAP_EFER
4579 RT_NOREF2(pVCpu, pVmxTransient);
4580 return true;
4581#else
4582 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4583 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4584 uint64_t const u64HostEfer = pVM->hm.s.vmx.u64HostMsrEfer;
4585 uint64_t const u64GuestEfer = pCtx->msrEFER;
4586
4587# ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4588 /*
4589 * For nested-guests, we shall honor swapping the EFER MSR when requested by
4590 * the nested-guest.
4591 */
4592 if ( pVmxTransient->fIsNestedGuest
4593 && ( CPUMIsGuestVmxEntryCtlsSet(pCtx, VMX_ENTRY_CTLS_LOAD_EFER_MSR)
4594 || CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_SAVE_EFER_MSR)
4595 || CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_LOAD_EFER_MSR)))
4596 return true;
4597# else
4598 RT_NOREF(pVmxTransient);
4599#endif
4600
4601 /*
4602 * For 64-bit guests, if EFER.SCE bit differs, we need to swap the EFER MSR
4603 * to ensure that the guest's SYSCALL behaviour isn't broken, see @bugref{7386}.
4604 */
4605 if ( CPUMIsGuestInLongModeEx(pCtx)
4606 && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
4607 return true;
4608
4609 /*
4610 * If the guest uses PAE and EFER.NXE bit differs, we need to swap the EFER MSR
4611 * as it affects guest paging. 64-bit paging implies CR4.PAE as well.
4612 *
4613 * See Intel spec. 4.5 "IA-32e Paging".
4614 * See Intel spec. 4.1.1 "Three Paging Modes".
4615 *
4616 * Verify that we always intercept CR4.PAE and CR0.PG bits, so we don't need to
4617 * import CR4 and CR0 from the VMCS here as those bits are always up to date.
4618 */
4619 Assert(hmR0VmxGetFixedCr4Mask(pVCpu) & X86_CR4_PAE);
4620 Assert(hmR0VmxGetFixedCr0Mask(pVCpu) & X86_CR0_PG);
4621 if ( (pCtx->cr4 & X86_CR4_PAE)
4622 && (pCtx->cr0 & X86_CR0_PG))
4623 {
4624 /*
4625 * If nested paging is not used, verify that the guest paging mode matches the
4626 * shadow paging mode which is/will be placed in the VMCS (which is what will
4627 * actually be used while executing the guest and not the CR4 shadow value).
4628 */
4629 AssertMsg(pVM->hm.s.fNestedPaging || ( pVCpu->hm.s.enmShadowMode == PGMMODE_PAE
4630 || pVCpu->hm.s.enmShadowMode == PGMMODE_PAE_NX
4631 || pVCpu->hm.s.enmShadowMode == PGMMODE_AMD64
4632 || pVCpu->hm.s.enmShadowMode == PGMMODE_AMD64_NX),
4633 ("enmShadowMode=%u\n", pVCpu->hm.s.enmShadowMode));
4634 if ((u64GuestEfer & MSR_K6_EFER_NXE) != (u64HostEfer & MSR_K6_EFER_NXE))
4635 {
4636 /* Verify that the host is NX capable. */
4637 Assert(pVCpu->CTX_SUFF(pVM)->cpum.ro.HostFeatures.fNoExecute);
4638 return true;
4639 }
4640 }
4641
4642 return false;
4643#endif
4644}
4645
4646
4647/**
4648 * Exports the guest state with appropriate VM-entry and VM-exit controls in the
4649 * VMCS.
4650 *
4651 * This is typically required when the guest changes paging mode.
4652 *
4653 * @returns VBox status code.
4654 * @param pVCpu The cross context virtual CPU structure.
4655 * @param pVmxTransient The VMX-transient structure.
4656 *
4657 * @remarks Requires EFER.
4658 * @remarks No-long-jump zone!!!
4659 */
4660static int hmR0VmxExportGuestEntryExitCtls(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
4661{
4662 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS)
4663 {
4664 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4665 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4666 bool const fGstInLongMode = CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx);
4667
4668 /*
4669 * VMRUN function.
4670 * If the guest is in long mode, use the 64-bit guest handler, else the 32-bit guest handler.
4671 * The host is always 64-bit since we no longer support 32-bit hosts.
4672 */
4673 if (fGstInLongMode)
4674 {
4675#ifndef VBOX_WITH_64_BITS_GUESTS
4676 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
4677#else
4678 Assert(pVM->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
4679 pVmcsInfo->pfnStartVM = VMXR0StartVM64;
4680#endif
4681 }
4682 else
4683 pVmcsInfo->pfnStartVM = VMXR0StartVM32;
4684
4685 /*
4686 * VM-entry controls.
4687 */
4688 {
4689 uint32_t fVal = pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
4690 uint32_t const fZap = pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
4691
4692 /*
4693 * Load the guest debug controls (DR7 and IA32_DEBUGCTL MSR) on VM-entry.
4694 * The first VT-x capable CPUs only supported the 1-setting of this bit.
4695 *
4696 * For nested-guests, this is a mandatory VM-entry control. It's also
4697 * required because we do not want to leak host bits to the nested-guest.
4698 */
4699 fVal |= VMX_ENTRY_CTLS_LOAD_DEBUG;
4700
4701 /*
4702 * Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry.
4703 *
4704 * For nested-guests, the "IA-32e mode guest" control we initialize with what is
4705 * required to get the nested-guest working with hardware-assisted VMX execution.
4706 * It depends on the nested-guest's IA32_EFER.LMA bit. Remember, a nested hypervisor
4707 * can skip intercepting changes to the EFER MSR. This is why it it needs to be done
4708 * here rather than while merging the guest VMCS controls.
4709 */
4710 if (fGstInLongMode)
4711 {
4712 Assert(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LME);
4713 fVal |= VMX_ENTRY_CTLS_IA32E_MODE_GUEST;
4714 }
4715 else
4716 Assert(!(fVal & VMX_ENTRY_CTLS_IA32E_MODE_GUEST));
4717
4718 /*
4719 * If the CPU supports the newer VMCS controls for managing guest/host EFER, use it.
4720 *
4721 * For nested-guests, we use the "load IA32_EFER" if the hardware supports it,
4722 * regardless of whether the nested-guest VMCS specifies it because we are free to
4723 * load whatever MSRs we require and we do not need to modify the guest visible copy
4724 * of the VM-entry MSR load area.
4725 */
4726 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
4727 && hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
4728 fVal |= VMX_ENTRY_CTLS_LOAD_EFER_MSR;
4729 else
4730 Assert(!(fVal & VMX_ENTRY_CTLS_LOAD_EFER_MSR));
4731
4732 /*
4733 * The following should -not- be set (since we're not in SMM mode):
4734 * - VMX_ENTRY_CTLS_ENTRY_TO_SMM
4735 * - VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON
4736 */
4737
4738 /** @todo VMX_ENTRY_CTLS_LOAD_PERF_MSR,
4739 * VMX_ENTRY_CTLS_LOAD_PAT_MSR. */
4740
4741 if ((fVal & fZap) == fVal)
4742 { /* likely */ }
4743 else
4744 {
4745 Log4Func(("Invalid VM-entry controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
4746 pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed0, fVal, fZap));
4747 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_ENTRY;
4748 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4749 }
4750
4751 /* Commit it to the VMCS. */
4752 if (pVmcsInfo->u32EntryCtls != fVal)
4753 {
4754 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, fVal);
4755 AssertRC(rc);
4756 pVmcsInfo->u32EntryCtls = fVal;
4757 }
4758 }
4759
4760 /*
4761 * VM-exit controls.
4762 */
4763 {
4764 uint32_t fVal = pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
4765 uint32_t const fZap = pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
4766
4767 /*
4768 * Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only
4769 * supported the 1-setting of this bit.
4770 *
4771 * For nested-guests, we set the "save debug controls" as the converse
4772 * "load debug controls" is mandatory for nested-guests anyway.
4773 */
4774 fVal |= VMX_EXIT_CTLS_SAVE_DEBUG;
4775
4776 /*
4777 * Set the host long mode active (EFER.LMA) bit (which Intel calls
4778 * "Host address-space size") if necessary. On VM-exit, VT-x sets both the
4779 * host EFER.LMA and EFER.LME bit to this value. See assertion in
4780 * hmR0VmxExportHostMsrs().
4781 *
4782 * For nested-guests, we always set this bit as we do not support 32-bit
4783 * hosts.
4784 */
4785 fVal |= VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE;
4786
4787 /*
4788 * If the VMCS EFER MSR fields are supported by the hardware, we use it.
4789 *
4790 * For nested-guests, we should use the "save IA32_EFER" control if we also
4791 * used the "load IA32_EFER" control while exporting VM-entry controls.
4792 */
4793 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
4794 && hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
4795 {
4796 fVal |= VMX_EXIT_CTLS_SAVE_EFER_MSR
4797 | VMX_EXIT_CTLS_LOAD_EFER_MSR;
4798 }
4799
4800 /*
4801 * Enable saving of the VMX-preemption timer value on VM-exit.
4802 * For nested-guests, currently not exposed/used.
4803 */
4804 if ( pVM->hm.s.vmx.fUsePreemptTimer
4805 && (pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER))
4806 fVal |= VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER;
4807
4808 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
4809 Assert(!(fVal & VMX_EXIT_CTLS_ACK_EXT_INT));
4810
4811 /** @todo VMX_EXIT_CTLS_LOAD_PERF_MSR,
4812 * VMX_EXIT_CTLS_SAVE_PAT_MSR,
4813 * VMX_EXIT_CTLS_LOAD_PAT_MSR. */
4814
4815 if ((fVal & fZap) == fVal)
4816 { /* likely */ }
4817 else
4818 {
4819 Log4Func(("Invalid VM-exit controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%R#X32\n",
4820 pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed0, fVal, fZap));
4821 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_EXIT;
4822 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4823 }
4824
4825 /* Commit it to the VMCS. */
4826 if (pVmcsInfo->u32ExitCtls != fVal)
4827 {
4828 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, fVal);
4829 AssertRC(rc);
4830 pVmcsInfo->u32ExitCtls = fVal;
4831 }
4832 }
4833
4834 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
4835 }
4836 return VINF_SUCCESS;
4837}
4838
4839
4840/**
4841 * Sets the TPR threshold in the VMCS.
4842 *
4843 * @param pVmcsInfo The VMCS info. object.
4844 * @param u32TprThreshold The TPR threshold (task-priority class only).
4845 */
4846DECLINLINE(void) hmR0VmxApicSetTprThreshold(PVMXVMCSINFO pVmcsInfo, uint32_t u32TprThreshold)
4847{
4848 Assert(!(u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)); /* Bits 31:4 MBZ. */
4849 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
4850 RT_NOREF(pVmcsInfo);
4851 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
4852 AssertRC(rc);
4853}
4854
4855
4856/**
4857 * Exports the guest APIC TPR state into the VMCS.
4858 *
4859 * @param pVCpu The cross context virtual CPU structure.
4860 * @param pVmxTransient The VMX-transient structure.
4861 *
4862 * @remarks No-long-jump zone!!!
4863 */
4864static void hmR0VmxExportGuestApicTpr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
4865{
4866 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_APIC_TPR)
4867 {
4868 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
4869
4870 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4871 if (!pVmxTransient->fIsNestedGuest)
4872 {
4873 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
4874 && APICIsEnabled(pVCpu))
4875 {
4876 /*
4877 * Setup TPR shadowing.
4878 */
4879 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
4880 {
4881 bool fPendingIntr = false;
4882 uint8_t u8Tpr = 0;
4883 uint8_t u8PendingIntr = 0;
4884 int rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
4885 AssertRC(rc);
4886
4887 /*
4888 * If there are interrupts pending but masked by the TPR, instruct VT-x to
4889 * cause a TPR-below-threshold VM-exit when the guest lowers its TPR below the
4890 * priority of the pending interrupt so we can deliver the interrupt. If there
4891 * are no interrupts pending, set threshold to 0 to not cause any
4892 * TPR-below-threshold VM-exits.
4893 */
4894 uint32_t u32TprThreshold = 0;
4895 if (fPendingIntr)
4896 {
4897 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR
4898 (which is the Task-Priority Class). */
4899 const uint8_t u8PendingPriority = u8PendingIntr >> 4;
4900 const uint8_t u8TprPriority = u8Tpr >> 4;
4901 if (u8PendingPriority <= u8TprPriority)
4902 u32TprThreshold = u8PendingPriority;
4903 }
4904
4905 hmR0VmxApicSetTprThreshold(pVmcsInfo, u32TprThreshold);
4906 }
4907 }
4908 }
4909 /* else: the TPR threshold has already been updated while merging the nested-guest VMCS. */
4910 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
4911 }
4912}
4913
4914
4915/**
4916 * Gets the guest interruptibility-state.
4917 *
4918 * @returns Guest's interruptibility-state.
4919 * @param pVCpu The cross context virtual CPU structure.
4920 *
4921 * @remarks No-long-jump zone!!!
4922 */
4923static uint32_t hmR0VmxGetGuestIntrState(PVMCPUCC pVCpu)
4924{
4925 /*
4926 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
4927 */
4928 uint32_t fIntrState = 0;
4929 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
4930 {
4931 /* If inhibition is active, RIP and RFLAGS should've been imported from the VMCS already. */
4932 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
4933
4934 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4935 if (pCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
4936 {
4937 if (pCtx->eflags.Bits.u1IF)
4938 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
4939 else
4940 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS;
4941 }
4942 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
4943 {
4944 /*
4945 * We can clear the inhibit force flag as even if we go back to the recompiler
4946 * without executing guest code in VT-x, the flag's condition to be cleared is
4947 * met and thus the cleared state is correct.
4948 */
4949 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
4950 }
4951 }
4952
4953 /*
4954 * Check if we should inhibit NMI delivery.
4955 */
4956 if (CPUMIsGuestNmiBlocking(pVCpu))
4957 fIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
4958
4959 return fIntrState;
4960}
4961
4962
4963/**
4964 * Exports the exception intercepts required for guest execution in the VMCS.
4965 *
4966 * @param pVCpu The cross context virtual CPU structure.
4967 * @param pVmxTransient The VMX-transient structure.
4968 *
4969 * @remarks No-long-jump zone!!!
4970 */
4971static void hmR0VmxExportGuestXcptIntercepts(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
4972{
4973 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_XCPT_INTERCEPTS)
4974 {
4975 /* When executing a nested-guest, we do not need to trap GIM hypercalls by intercepting #UD. */
4976 if ( !pVmxTransient->fIsNestedGuest
4977 && pVCpu->hm.s.fGIMTrapXcptUD)
4978 hmR0VmxAddXcptIntercept(pVmxTransient, X86_XCPT_UD);
4979 else
4980 hmR0VmxRemoveXcptIntercept(pVCpu, pVmxTransient, X86_XCPT_UD);
4981
4982 /* Other exception intercepts are handled elsewhere, e.g. while exporting guest CR0. */
4983 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_XCPT_INTERCEPTS);
4984 }
4985}
4986
4987
4988/**
4989 * Exports the guest's RIP into the guest-state area in the VMCS.
4990 *
4991 * @param pVCpu The cross context virtual CPU structure.
4992 *
4993 * @remarks No-long-jump zone!!!
4994 */
4995static void hmR0VmxExportGuestRip(PVMCPUCC pVCpu)
4996{
4997 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RIP)
4998 {
4999 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP);
5000
5001 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RIP, pVCpu->cpum.GstCtx.rip);
5002 AssertRC(rc);
5003
5004 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RIP);
5005 Log4Func(("rip=%#RX64\n", pVCpu->cpum.GstCtx.rip));
5006 }
5007}
5008
5009
5010/**
5011 * Exports the guest's RSP into the guest-state area in the VMCS.
5012 *
5013 * @param pVCpu The cross context virtual CPU structure.
5014 *
5015 * @remarks No-long-jump zone!!!
5016 */
5017static void hmR0VmxExportGuestRsp(PVMCPUCC pVCpu)
5018{
5019 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RSP)
5020 {
5021 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RSP);
5022
5023 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RSP, pVCpu->cpum.GstCtx.rsp);
5024 AssertRC(rc);
5025
5026 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RSP);
5027 Log4Func(("rsp=%#RX64\n", pVCpu->cpum.GstCtx.rsp));
5028 }
5029}
5030
5031
5032/**
5033 * Exports the guest's RFLAGS into the guest-state area in the VMCS.
5034 *
5035 * @param pVCpu The cross context virtual CPU structure.
5036 * @param pVmxTransient The VMX-transient structure.
5037 *
5038 * @remarks No-long-jump zone!!!
5039 */
5040static void hmR0VmxExportGuestRflags(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5041{
5042 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RFLAGS)
5043 {
5044 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
5045
5046 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
5047 Let us assert it as such and use 32-bit VMWRITE. */
5048 Assert(!RT_HI_U32(pVCpu->cpum.GstCtx.rflags.u64));
5049 X86EFLAGS fEFlags = pVCpu->cpum.GstCtx.eflags;
5050 Assert(fEFlags.u32 & X86_EFL_RA1_MASK);
5051 Assert(!(fEFlags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
5052
5053 /*
5054 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so
5055 * we can restore them on VM-exit. Modify the real-mode guest's eflags so that VT-x
5056 * can run the real-mode guest code under Virtual 8086 mode.
5057 */
5058 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5059 if (pVmcsInfo->RealMode.fRealOnV86Active)
5060 {
5061 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
5062 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
5063 Assert(!pVmxTransient->fIsNestedGuest);
5064 pVmcsInfo->RealMode.Eflags.u32 = fEFlags.u32; /* Save the original eflags of the real-mode guest. */
5065 fEFlags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
5066 fEFlags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
5067 }
5068
5069 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RFLAGS, fEFlags.u32);
5070 AssertRC(rc);
5071
5072 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RFLAGS);
5073 Log4Func(("eflags=%#RX32\n", fEFlags.u32));
5074 }
5075}
5076
5077
5078#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5079/**
5080 * Copies the nested-guest VMCS to the shadow VMCS.
5081 *
5082 * @returns VBox status code.
5083 * @param pVCpu The cross context virtual CPU structure.
5084 * @param pVmcsInfo The VMCS info. object.
5085 *
5086 * @remarks No-long-jump zone!!!
5087 */
5088static int hmR0VmxCopyNstGstToShadowVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5089{
5090 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5091 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5092
5093 /*
5094 * Disable interrupts so we don't get preempted while the shadow VMCS is the
5095 * current VMCS, as we may try saving guest lazy MSRs.
5096 *
5097 * Strictly speaking the lazy MSRs are not in the VMCS, but I'd rather not risk
5098 * calling the import VMCS code which is currently performing the guest MSR reads
5099 * (on 64-bit hosts) and accessing the auto-load/store MSR area on 32-bit hosts
5100 * and the rest of the VMX leave session machinery.
5101 */
5102 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
5103
5104 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5105 if (RT_SUCCESS(rc))
5106 {
5107 /*
5108 * Copy all guest read/write VMCS fields.
5109 *
5110 * We don't check for VMWRITE failures here for performance reasons and
5111 * because they are not expected to fail, barring irrecoverable conditions
5112 * like hardware errors.
5113 */
5114 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
5115 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5116 {
5117 uint64_t u64Val;
5118 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
5119 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5120 VMXWriteVmcs64(uVmcsField, u64Val);
5121 }
5122
5123 /*
5124 * If the host CPU supports writing all VMCS fields, copy the guest read-only
5125 * VMCS fields, so the guest can VMREAD them without causing a VM-exit.
5126 */
5127 if (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL)
5128 {
5129 uint32_t const cShadowVmcsRoFields = pVM->hm.s.vmx.cShadowVmcsRoFields;
5130 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
5131 {
5132 uint64_t u64Val;
5133 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsRoFields[i];
5134 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5135 VMXWriteVmcs64(uVmcsField, u64Val);
5136 }
5137 }
5138
5139 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5140 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5141 }
5142
5143 ASMSetFlags(fEFlags);
5144 return rc;
5145}
5146
5147
5148/**
5149 * Copies the shadow VMCS to the nested-guest VMCS.
5150 *
5151 * @returns VBox status code.
5152 * @param pVCpu The cross context virtual CPU structure.
5153 * @param pVmcsInfo The VMCS info. object.
5154 *
5155 * @remarks Called with interrupts disabled.
5156 */
5157static int hmR0VmxCopyShadowToNstGstVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5158{
5159 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5160 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5161 PVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5162
5163 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5164 if (RT_SUCCESS(rc))
5165 {
5166 /*
5167 * Copy guest read/write fields from the shadow VMCS.
5168 * Guest read-only fields cannot be modified, so no need to copy them.
5169 *
5170 * We don't check for VMREAD failures here for performance reasons and
5171 * because they are not expected to fail, barring irrecoverable conditions
5172 * like hardware errors.
5173 */
5174 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
5175 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5176 {
5177 uint64_t u64Val;
5178 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
5179 VMXReadVmcs64(uVmcsField, &u64Val);
5180 IEMWriteVmxVmcsField(pVmcsNstGst, uVmcsField, u64Val);
5181 }
5182
5183 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5184 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5185 }
5186 return rc;
5187}
5188
5189
5190/**
5191 * Enables VMCS shadowing for the given VMCS info. object.
5192 *
5193 * @param pVmcsInfo The VMCS info. object.
5194 *
5195 * @remarks No-long-jump zone!!!
5196 */
5197static void hmR0VmxEnableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5198{
5199 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5200 if (!(uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING))
5201 {
5202 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
5203 uProcCtls2 |= VMX_PROC_CTLS2_VMCS_SHADOWING;
5204 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5205 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, pVmcsInfo->HCPhysShadowVmcs); AssertRC(rc);
5206 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5207 pVmcsInfo->u64VmcsLinkPtr = pVmcsInfo->HCPhysShadowVmcs;
5208 Log4Func(("Enabled\n"));
5209 }
5210}
5211
5212
5213/**
5214 * Disables VMCS shadowing for the given VMCS info. object.
5215 *
5216 * @param pVmcsInfo The VMCS info. object.
5217 *
5218 * @remarks No-long-jump zone!!!
5219 */
5220static void hmR0VmxDisableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5221{
5222 /*
5223 * We want all VMREAD and VMWRITE instructions to cause VM-exits, so we clear the
5224 * VMCS shadowing control. However, VM-entry requires the shadow VMCS indicator bit
5225 * to match the VMCS shadowing control if the VMCS link pointer is not NIL_RTHCPHYS.
5226 * Hence, we must also reset the VMCS link pointer to ensure VM-entry does not fail.
5227 *
5228 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
5229 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5230 */
5231 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5232 if (uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
5233 {
5234 uProcCtls2 &= ~VMX_PROC_CTLS2_VMCS_SHADOWING;
5235 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5236 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS); AssertRC(rc);
5237 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5238 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
5239 Log4Func(("Disabled\n"));
5240 }
5241}
5242#endif
5243
5244
5245/**
5246 * Exports the guest hardware-virtualization state.
5247 *
5248 * @returns VBox status code.
5249 * @param pVCpu The cross context virtual CPU structure.
5250 * @param pVmxTransient The VMX-transient structure.
5251 *
5252 * @remarks No-long-jump zone!!!
5253 */
5254static int hmR0VmxExportGuestHwvirtState(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5255{
5256 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_HWVIRT)
5257 {
5258#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5259 /*
5260 * Check if the VMX feature is exposed to the guest and if the host CPU supports
5261 * VMCS shadowing.
5262 */
5263 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
5264 {
5265 /*
5266 * If the nested hypervisor has loaded a current VMCS and is in VMX root mode,
5267 * copy the nested hypervisor's current VMCS into the shadow VMCS and enable
5268 * VMCS shadowing to skip intercepting some or all VMREAD/VMWRITE VM-exits.
5269 *
5270 * We check for VMX root mode here in case the guest executes VMXOFF without
5271 * clearing the current VMCS pointer and our VMXOFF instruction emulation does
5272 * not clear the current VMCS pointer.
5273 */
5274 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5275 if ( CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx)
5276 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx)
5277 && CPUMIsGuestVmxCurrentVmcsValid(&pVCpu->cpum.GstCtx))
5278 {
5279 /* Paranoia. */
5280 Assert(!pVmxTransient->fIsNestedGuest);
5281
5282 /*
5283 * For performance reasons, also check if the nested hypervisor's current VMCS
5284 * was newly loaded or modified before copying it to the shadow VMCS.
5285 */
5286 if (!pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs)
5287 {
5288 int rc = hmR0VmxCopyNstGstToShadowVmcs(pVCpu, pVmcsInfo);
5289 AssertRCReturn(rc, rc);
5290 pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs = true;
5291 }
5292 hmR0VmxEnableVmcsShadowing(pVmcsInfo);
5293 }
5294 else
5295 hmR0VmxDisableVmcsShadowing(pVmcsInfo);
5296 }
5297#else
5298 NOREF(pVmxTransient);
5299#endif
5300 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_HWVIRT);
5301 }
5302 return VINF_SUCCESS;
5303}
5304
5305
5306/**
5307 * Exports the guest CR0 control register into the guest-state area in the VMCS.
5308 *
5309 * The guest FPU state is always pre-loaded hence we don't need to bother about
5310 * sharing FPU related CR0 bits between the guest and host.
5311 *
5312 * @returns VBox status code.
5313 * @param pVCpu The cross context virtual CPU structure.
5314 * @param pVmxTransient The VMX-transient structure.
5315 *
5316 * @remarks No-long-jump zone!!!
5317 */
5318static int hmR0VmxExportGuestCR0(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5319{
5320 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR0)
5321 {
5322 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5323 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5324
5325 uint64_t fSetCr0 = pVM->hm.s.vmx.Msrs.u64Cr0Fixed0;
5326 uint64_t const fZapCr0 = pVM->hm.s.vmx.Msrs.u64Cr0Fixed1;
5327 if (pVM->hm.s.vmx.fUnrestrictedGuest)
5328 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
5329 else
5330 Assert((fSetCr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
5331
5332 if (!pVmxTransient->fIsNestedGuest)
5333 {
5334 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5335 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5336 uint64_t const u64ShadowCr0 = u64GuestCr0;
5337 Assert(!RT_HI_U32(u64GuestCr0));
5338
5339 /*
5340 * Setup VT-x's view of the guest CR0.
5341 */
5342 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5343 if (pVM->hm.s.fNestedPaging)
5344 {
5345 if (CPUMIsGuestPagingEnabled(pVCpu))
5346 {
5347 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
5348 uProcCtls &= ~( VMX_PROC_CTLS_CR3_LOAD_EXIT
5349 | VMX_PROC_CTLS_CR3_STORE_EXIT);
5350 }
5351 else
5352 {
5353 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
5354 uProcCtls |= VMX_PROC_CTLS_CR3_LOAD_EXIT
5355 | VMX_PROC_CTLS_CR3_STORE_EXIT;
5356 }
5357
5358 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
5359 if (pVM->hm.s.vmx.fUnrestrictedGuest)
5360 uProcCtls &= ~VMX_PROC_CTLS_CR3_STORE_EXIT;
5361 }
5362 else
5363 {
5364 /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
5365 u64GuestCr0 |= X86_CR0_WP;
5366 }
5367
5368 /*
5369 * Guest FPU bits.
5370 *
5371 * Since we pre-load the guest FPU always before VM-entry there is no need to track lazy state
5372 * using CR0.TS.
5373 *
5374 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be
5375 * set on the first CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
5376 */
5377 u64GuestCr0 |= X86_CR0_NE;
5378
5379 /* If CR0.NE isn't set, we need to intercept #MF exceptions and report them to the guest differently. */
5380 bool const fInterceptMF = !(u64ShadowCr0 & X86_CR0_NE);
5381
5382 /*
5383 * Update exception intercepts.
5384 */
5385 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
5386 if (pVmcsInfo->RealMode.fRealOnV86Active)
5387 {
5388 Assert(PDMVmmDevHeapIsEnabled(pVM));
5389 Assert(pVM->hm.s.vmx.pRealModeTSS);
5390 uXcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
5391 }
5392 else
5393 {
5394 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
5395 uXcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
5396 if (fInterceptMF)
5397 uXcptBitmap |= RT_BIT(X86_XCPT_MF);
5398 }
5399
5400 /* Additional intercepts for debugging, define these yourself explicitly. */
5401#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
5402 uXcptBitmap |= 0
5403 | RT_BIT(X86_XCPT_BP)
5404 | RT_BIT(X86_XCPT_DE)
5405 | RT_BIT(X86_XCPT_NM)
5406 | RT_BIT(X86_XCPT_TS)
5407 | RT_BIT(X86_XCPT_UD)
5408 | RT_BIT(X86_XCPT_NP)
5409 | RT_BIT(X86_XCPT_SS)
5410 | RT_BIT(X86_XCPT_GP)
5411 | RT_BIT(X86_XCPT_PF)
5412 | RT_BIT(X86_XCPT_MF)
5413 ;
5414#elif defined(HMVMX_ALWAYS_TRAP_PF)
5415 uXcptBitmap |= RT_BIT(X86_XCPT_PF);
5416#endif
5417 if (pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv)
5418 uXcptBitmap |= RT_BIT(X86_XCPT_GP);
5419 Assert(pVM->hm.s.fNestedPaging || (uXcptBitmap & RT_BIT(X86_XCPT_PF)));
5420
5421 /* Apply the hardware specified CR0 fixed bits and enable caching. */
5422 u64GuestCr0 |= fSetCr0;
5423 u64GuestCr0 &= fZapCr0;
5424 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5425
5426 /* Commit the CR0 and related fields to the guest VMCS. */
5427 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5428 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5429 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5430 {
5431 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5432 AssertRC(rc);
5433 }
5434 if (uXcptBitmap != pVmcsInfo->u32XcptBitmap)
5435 {
5436 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
5437 AssertRC(rc);
5438 }
5439
5440 /* Update our caches. */
5441 pVmcsInfo->u32ProcCtls = uProcCtls;
5442 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
5443
5444 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5445 }
5446 else
5447 {
5448 /*
5449 * With nested-guests, we may have extended the guest/host mask here since we
5450 * merged in the outer guest's mask. Thus, the merged mask can include more bits
5451 * (to read from the nested-guest CR0 read-shadow) than the nested hypervisor
5452 * originally supplied. We must copy those bits from the nested-guest CR0 into
5453 * the nested-guest CR0 read-shadow.
5454 */
5455 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5456 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5457 uint64_t const u64ShadowCr0 = CPUMGetGuestVmxMaskedCr0(&pVCpu->cpum.GstCtx, pVmcsInfo->u64Cr0Mask);
5458 Assert(!RT_HI_U32(u64GuestCr0));
5459 Assert(u64GuestCr0 & X86_CR0_NE);
5460
5461 /* Apply the hardware specified CR0 fixed bits and enable caching. */
5462 u64GuestCr0 |= fSetCr0;
5463 u64GuestCr0 &= fZapCr0;
5464 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5465
5466 /* Commit the CR0 and CR0 read-shadow to the nested-guest VMCS. */
5467 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5468 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5469
5470 Log4Func(("cr0=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5471 }
5472
5473 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR0);
5474 }
5475
5476 return VINF_SUCCESS;
5477}
5478
5479
5480/**
5481 * Exports the guest control registers (CR3, CR4) into the guest-state area
5482 * in the VMCS.
5483 *
5484 * @returns VBox strict status code.
5485 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
5486 * without unrestricted guest access and the VMMDev is not presently
5487 * mapped (e.g. EFI32).
5488 *
5489 * @param pVCpu The cross context virtual CPU structure.
5490 * @param pVmxTransient The VMX-transient structure.
5491 *
5492 * @remarks No-long-jump zone!!!
5493 */
5494static VBOXSTRICTRC hmR0VmxExportGuestCR3AndCR4(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5495{
5496 int rc = VINF_SUCCESS;
5497 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5498
5499 /*
5500 * Guest CR2.
5501 * It's always loaded in the assembler code. Nothing to do here.
5502 */
5503
5504 /*
5505 * Guest CR3.
5506 */
5507 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR3)
5508 {
5509 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
5510
5511 if (pVM->hm.s.fNestedPaging)
5512 {
5513 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5514 pVmcsInfo->HCPhysEPTP = PGMGetHyperCR3(pVCpu);
5515
5516 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
5517 Assert(pVmcsInfo->HCPhysEPTP != NIL_RTHCPHYS);
5518 Assert(!(pVmcsInfo->HCPhysEPTP & UINT64_C(0xfff0000000000000)));
5519 Assert(!(pVmcsInfo->HCPhysEPTP & 0xfff));
5520
5521 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
5522 pVmcsInfo->HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
5523 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
5524
5525 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
5526 AssertMsg( ((pVmcsInfo->HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
5527 && ((pVmcsInfo->HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
5528 ("EPTP %#RX64\n", pVmcsInfo->HCPhysEPTP));
5529 AssertMsg( !((pVmcsInfo->HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
5530 || (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
5531 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVmcsInfo->HCPhysEPTP));
5532
5533 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVmcsInfo->HCPhysEPTP);
5534 AssertRC(rc);
5535
5536 uint64_t u64GuestCr3;
5537 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5538 if ( pVM->hm.s.vmx.fUnrestrictedGuest
5539 || CPUMIsGuestPagingEnabledEx(pCtx))
5540 {
5541 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
5542 if (CPUMIsGuestInPAEModeEx(pCtx))
5543 {
5544 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
5545 AssertRC(rc);
5546 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
5547 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
5548 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
5549 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
5550 }
5551
5552 /*
5553 * The guest's view of its CR3 is unblemished with nested paging when the
5554 * guest is using paging or we have unrestricted guest execution to handle
5555 * the guest when it's not using paging.
5556 */
5557 u64GuestCr3 = pCtx->cr3;
5558 }
5559 else
5560 {
5561 /*
5562 * The guest is not using paging, but the CPU (VT-x) has to. While the guest
5563 * thinks it accesses physical memory directly, we use our identity-mapped
5564 * page table to map guest-linear to guest-physical addresses. EPT takes care
5565 * of translating it to host-physical addresses.
5566 */
5567 RTGCPHYS GCPhys;
5568 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
5569
5570 /* We obtain it here every time as the guest could have relocated this PCI region. */
5571 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
5572 if (RT_SUCCESS(rc))
5573 { /* likely */ }
5574 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
5575 {
5576 Log4Func(("VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n"));
5577 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
5578 }
5579 else
5580 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
5581
5582 u64GuestCr3 = GCPhys;
5583 }
5584
5585 Log4Func(("guest_cr3=%#RX64 (GstN)\n", u64GuestCr3));
5586 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, u64GuestCr3);
5587 AssertRC(rc);
5588 }
5589 else
5590 {
5591 Assert(!pVmxTransient->fIsNestedGuest);
5592 /* Non-nested paging case, just use the hypervisor's CR3. */
5593 RTHCPHYS const HCPhysGuestCr3 = PGMGetHyperCR3(pVCpu);
5594
5595 Log4Func(("guest_cr3=%#RX64 (HstN)\n", HCPhysGuestCr3));
5596 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, HCPhysGuestCr3);
5597 AssertRC(rc);
5598 }
5599
5600 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR3);
5601 }
5602
5603 /*
5604 * Guest CR4.
5605 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
5606 */
5607 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR4)
5608 {
5609 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5610 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5611
5612 uint64_t const fSetCr4 = pVM->hm.s.vmx.Msrs.u64Cr4Fixed0;
5613 uint64_t const fZapCr4 = pVM->hm.s.vmx.Msrs.u64Cr4Fixed1;
5614
5615 /*
5616 * With nested-guests, we may have extended the guest/host mask here (since we
5617 * merged in the outer guest's mask, see hmR0VmxMergeVmcsNested). This means, the
5618 * mask can include more bits (to read from the nested-guest CR4 read-shadow) than
5619 * the nested hypervisor originally supplied. Thus, we should, in essence, copy
5620 * those bits from the nested-guest CR4 into the nested-guest CR4 read-shadow.
5621 */
5622 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
5623 uint64_t u64GuestCr4 = pCtx->cr4;
5624 uint64_t const u64ShadowCr4 = !pVmxTransient->fIsNestedGuest
5625 ? pCtx->cr4
5626 : CPUMGetGuestVmxMaskedCr4(pCtx, pVmcsInfo->u64Cr4Mask);
5627 Assert(!RT_HI_U32(u64GuestCr4));
5628
5629 /*
5630 * Setup VT-x's view of the guest CR4.
5631 *
5632 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software
5633 * interrupts to the 8086 program interrupt handler. Clear the VME bit (the interrupt
5634 * redirection bitmap is already all 0, see hmR3InitFinalizeR0())
5635 *
5636 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
5637 */
5638 if (pVmcsInfo->RealMode.fRealOnV86Active)
5639 {
5640 Assert(pVM->hm.s.vmx.pRealModeTSS);
5641 Assert(PDMVmmDevHeapIsEnabled(pVM));
5642 u64GuestCr4 &= ~(uint64_t)X86_CR4_VME;
5643 }
5644
5645 if (pVM->hm.s.fNestedPaging)
5646 {
5647 if ( !CPUMIsGuestPagingEnabledEx(pCtx)
5648 && !pVM->hm.s.vmx.fUnrestrictedGuest)
5649 {
5650 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
5651 u64GuestCr4 |= X86_CR4_PSE;
5652 /* Our identity mapping is a 32-bit page directory. */
5653 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5654 }
5655 /* else use guest CR4.*/
5656 }
5657 else
5658 {
5659 Assert(!pVmxTransient->fIsNestedGuest);
5660
5661 /*
5662 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
5663 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
5664 */
5665 switch (pVCpu->hm.s.enmShadowMode)
5666 {
5667 case PGMMODE_REAL: /* Real-mode. */
5668 case PGMMODE_PROTECTED: /* Protected mode without paging. */
5669 case PGMMODE_32_BIT: /* 32-bit paging. */
5670 {
5671 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5672 break;
5673 }
5674
5675 case PGMMODE_PAE: /* PAE paging. */
5676 case PGMMODE_PAE_NX: /* PAE paging with NX. */
5677 {
5678 u64GuestCr4 |= X86_CR4_PAE;
5679 break;
5680 }
5681
5682 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
5683 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
5684 {
5685#ifdef VBOX_WITH_64_BITS_GUESTS
5686 /* For our assumption in hmR0VmxShouldSwapEferMsr. */
5687 Assert(u64GuestCr4 & X86_CR4_PAE);
5688 break;
5689#endif
5690 }
5691 default:
5692 AssertFailed();
5693 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
5694 }
5695 }
5696
5697 /* Apply the hardware specified CR4 fixed bits (mainly CR4.VMXE). */
5698 u64GuestCr4 |= fSetCr4;
5699 u64GuestCr4 &= fZapCr4;
5700
5701 /* Commit the CR4 and CR4 read-shadow to the guest VMCS. */
5702 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR4, u64GuestCr4); AssertRC(rc);
5703 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, u64ShadowCr4); AssertRC(rc);
5704
5705 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
5706 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
5707
5708 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR4);
5709
5710 Log4Func(("cr4=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr4, u64ShadowCr4, fSetCr4, fZapCr4));
5711 }
5712 return rc;
5713}
5714
5715
5716/**
5717 * Exports the guest debug registers into the guest-state area in the VMCS.
5718 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
5719 *
5720 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
5721 *
5722 * @returns VBox status code.
5723 * @param pVCpu The cross context virtual CPU structure.
5724 * @param pVmxTransient The VMX-transient structure.
5725 *
5726 * @remarks No-long-jump zone!!!
5727 */
5728static int hmR0VmxExportSharedDebugState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
5729{
5730 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5731
5732 /** @todo NSTVMX: Figure out what we want to do with nested-guest instruction
5733 * stepping. */
5734 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5735 if (pVmxTransient->fIsNestedGuest)
5736 {
5737 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, CPUMGetGuestDR7(pVCpu));
5738 AssertRC(rc);
5739
5740 /* Always intercept Mov DRx accesses for the nested-guest for now. */
5741 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
5742 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
5743 AssertRC(rc);
5744 return VINF_SUCCESS;
5745 }
5746
5747#ifdef VBOX_STRICT
5748 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
5749 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
5750 {
5751 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
5752 Assert((pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0);
5753 Assert((pVCpu->cpum.GstCtx.dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK);
5754 }
5755#endif
5756
5757 bool fSteppingDB = false;
5758 bool fInterceptMovDRx = false;
5759 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5760 if (pVCpu->hm.s.fSingleInstruction)
5761 {
5762 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
5763 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5764 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
5765 {
5766 uProcCtls |= VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
5767 Assert(fSteppingDB == false);
5768 }
5769 else
5770 {
5771 pVCpu->cpum.GstCtx.eflags.u32 |= X86_EFL_TF;
5772 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_RFLAGS;
5773 pVCpu->hm.s.fClearTrapFlag = true;
5774 fSteppingDB = true;
5775 }
5776 }
5777
5778 uint64_t u64GuestDr7;
5779 if ( fSteppingDB
5780 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
5781 {
5782 /*
5783 * Use the combined guest and host DRx values found in the hypervisor register set
5784 * because the hypervisor debugger has breakpoints active or someone is single stepping
5785 * on the host side without a monitor trap flag.
5786 *
5787 * Note! DBGF expects a clean DR6 state before executing guest code.
5788 */
5789 if (!CPUMIsHyperDebugStateActive(pVCpu))
5790 {
5791 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
5792 Assert(CPUMIsHyperDebugStateActive(pVCpu));
5793 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
5794 }
5795
5796 /* Update DR7 with the hypervisor value (other DRx registers are handled by CPUM one way or another). */
5797 u64GuestDr7 = CPUMGetHyperDR7(pVCpu);
5798 pVCpu->hm.s.fUsingHyperDR7 = true;
5799 fInterceptMovDRx = true;
5800 }
5801 else
5802 {
5803 /*
5804 * If the guest has enabled debug registers, we need to load them prior to
5805 * executing guest code so they'll trigger at the right time.
5806 */
5807 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
5808 if (pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
5809 {
5810 if (!CPUMIsGuestDebugStateActive(pVCpu))
5811 {
5812 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
5813 Assert(CPUMIsGuestDebugStateActive(pVCpu));
5814 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
5815 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
5816 }
5817 Assert(!fInterceptMovDRx);
5818 }
5819 else if (!CPUMIsGuestDebugStateActive(pVCpu))
5820 {
5821 /*
5822 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
5823 * must intercept #DB in order to maintain a correct DR6 guest value, and
5824 * because we need to intercept it to prevent nested #DBs from hanging the
5825 * CPU, we end up always having to intercept it. See hmR0VmxSetupVmcsXcptBitmap().
5826 */
5827 fInterceptMovDRx = true;
5828 }
5829
5830 /* Update DR7 with the actual guest value. */
5831 u64GuestDr7 = pVCpu->cpum.GstCtx.dr[7];
5832 pVCpu->hm.s.fUsingHyperDR7 = false;
5833 }
5834
5835 if (fInterceptMovDRx)
5836 uProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
5837 else
5838 uProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
5839
5840 /*
5841 * Update the processor-based VM-execution controls with the MOV-DRx intercepts and the
5842 * monitor-trap flag and update our cache.
5843 */
5844 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5845 {
5846 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5847 AssertRC(rc);
5848 pVmcsInfo->u32ProcCtls = uProcCtls;
5849 }
5850
5851 /*
5852 * Update guest DR7.
5853 */
5854 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, u64GuestDr7);
5855 AssertRC(rc);
5856
5857 /*
5858 * If we have forced EFLAGS.TF to be set because we're single-stepping in the hypervisor debugger,
5859 * we need to clear interrupt inhibition if any as otherwise it causes a VM-entry failure.
5860 *
5861 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5862 */
5863 if (fSteppingDB)
5864 {
5865 Assert(pVCpu->hm.s.fSingleInstruction);
5866 Assert(pVCpu->cpum.GstCtx.eflags.Bits.u1TF);
5867
5868 uint32_t fIntrState = 0;
5869 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
5870 AssertRC(rc);
5871
5872 if (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
5873 {
5874 fIntrState &= ~(VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
5875 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
5876 AssertRC(rc);
5877 }
5878 }
5879
5880 return VINF_SUCCESS;
5881}
5882
5883
5884#ifdef VBOX_STRICT
5885/**
5886 * Strict function to validate segment registers.
5887 *
5888 * @param pVCpu The cross context virtual CPU structure.
5889 * @param pVmcsInfo The VMCS info. object.
5890 *
5891 * @remarks Will import guest CR0 on strict builds during validation of
5892 * segments.
5893 */
5894static void hmR0VmxValidateSegmentRegs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5895{
5896 /*
5897 * Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
5898 *
5899 * The reason we check for attribute value 0 in this function and not just the unusable bit is
5900 * because hmR0VmxExportGuestSegReg() only updates the VMCS' copy of the value with the
5901 * unusable bit and doesn't change the guest-context value.
5902 */
5903 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5904 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5905 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR0);
5906 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
5907 && ( !CPUMIsGuestInRealModeEx(pCtx)
5908 && !CPUMIsGuestInV86ModeEx(pCtx)))
5909 {
5910 /* Protected mode checks */
5911 /* CS */
5912 Assert(pCtx->cs.Attr.n.u1Present);
5913 Assert(!(pCtx->cs.Attr.u & 0xf00));
5914 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
5915 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
5916 || !(pCtx->cs.Attr.n.u1Granularity));
5917 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
5918 || (pCtx->cs.Attr.n.u1Granularity));
5919 /* CS cannot be loaded with NULL in protected mode. */
5920 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
5921 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
5922 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
5923 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
5924 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
5925 else
5926 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
5927 /* SS */
5928 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
5929 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
5930 if ( !(pCtx->cr0 & X86_CR0_PE)
5931 || pCtx->cs.Attr.n.u4Type == 3)
5932 {
5933 Assert(!pCtx->ss.Attr.n.u2Dpl);
5934 }
5935 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
5936 {
5937 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
5938 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
5939 Assert(pCtx->ss.Attr.n.u1Present);
5940 Assert(!(pCtx->ss.Attr.u & 0xf00));
5941 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
5942 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
5943 || !(pCtx->ss.Attr.n.u1Granularity));
5944 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
5945 || (pCtx->ss.Attr.n.u1Granularity));
5946 }
5947 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSegReg(). */
5948 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
5949 {
5950 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5951 Assert(pCtx->ds.Attr.n.u1Present);
5952 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
5953 Assert(!(pCtx->ds.Attr.u & 0xf00));
5954 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
5955 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
5956 || !(pCtx->ds.Attr.n.u1Granularity));
5957 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
5958 || (pCtx->ds.Attr.n.u1Granularity));
5959 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5960 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
5961 }
5962 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
5963 {
5964 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5965 Assert(pCtx->es.Attr.n.u1Present);
5966 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
5967 Assert(!(pCtx->es.Attr.u & 0xf00));
5968 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
5969 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
5970 || !(pCtx->es.Attr.n.u1Granularity));
5971 Assert( !(pCtx->es.u32Limit & 0xfff00000)
5972 || (pCtx->es.Attr.n.u1Granularity));
5973 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5974 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
5975 }
5976 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
5977 {
5978 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5979 Assert(pCtx->fs.Attr.n.u1Present);
5980 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
5981 Assert(!(pCtx->fs.Attr.u & 0xf00));
5982 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
5983 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
5984 || !(pCtx->fs.Attr.n.u1Granularity));
5985 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
5986 || (pCtx->fs.Attr.n.u1Granularity));
5987 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5988 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
5989 }
5990 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
5991 {
5992 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5993 Assert(pCtx->gs.Attr.n.u1Present);
5994 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
5995 Assert(!(pCtx->gs.Attr.u & 0xf00));
5996 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
5997 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
5998 || !(pCtx->gs.Attr.n.u1Granularity));
5999 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
6000 || (pCtx->gs.Attr.n.u1Granularity));
6001 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6002 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
6003 }
6004 /* 64-bit capable CPUs. */
6005 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6006 Assert(!pCtx->ss.Attr.u || !RT_HI_U32(pCtx->ss.u64Base));
6007 Assert(!pCtx->ds.Attr.u || !RT_HI_U32(pCtx->ds.u64Base));
6008 Assert(!pCtx->es.Attr.u || !RT_HI_U32(pCtx->es.u64Base));
6009 }
6010 else if ( CPUMIsGuestInV86ModeEx(pCtx)
6011 || ( CPUMIsGuestInRealModeEx(pCtx)
6012 && !pVM->hm.s.vmx.fUnrestrictedGuest))
6013 {
6014 /* Real and v86 mode checks. */
6015 /* hmR0VmxExportGuestSegReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
6016 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
6017 if (pVmcsInfo->RealMode.fRealOnV86Active)
6018 {
6019 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3;
6020 u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
6021 }
6022 else
6023 {
6024 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
6025 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
6026 }
6027
6028 /* CS */
6029 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
6030 Assert(pCtx->cs.u32Limit == 0xffff);
6031 Assert(u32CSAttr == 0xf3);
6032 /* SS */
6033 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
6034 Assert(pCtx->ss.u32Limit == 0xffff);
6035 Assert(u32SSAttr == 0xf3);
6036 /* DS */
6037 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
6038 Assert(pCtx->ds.u32Limit == 0xffff);
6039 Assert(u32DSAttr == 0xf3);
6040 /* ES */
6041 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
6042 Assert(pCtx->es.u32Limit == 0xffff);
6043 Assert(u32ESAttr == 0xf3);
6044 /* FS */
6045 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
6046 Assert(pCtx->fs.u32Limit == 0xffff);
6047 Assert(u32FSAttr == 0xf3);
6048 /* GS */
6049 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
6050 Assert(pCtx->gs.u32Limit == 0xffff);
6051 Assert(u32GSAttr == 0xf3);
6052 /* 64-bit capable CPUs. */
6053 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6054 Assert(!u32SSAttr || !RT_HI_U32(pCtx->ss.u64Base));
6055 Assert(!u32DSAttr || !RT_HI_U32(pCtx->ds.u64Base));
6056 Assert(!u32ESAttr || !RT_HI_U32(pCtx->es.u64Base));
6057 }
6058}
6059#endif /* VBOX_STRICT */
6060
6061
6062/**
6063 * Exports a guest segment register into the guest-state area in the VMCS.
6064 *
6065 * @returns VBox status code.
6066 * @param pVCpu The cross context virtual CPU structure.
6067 * @param pVmcsInfo The VMCS info. object.
6068 * @param iSegReg The segment register number (X86_SREG_XXX).
6069 * @param pSelReg Pointer to the segment selector.
6070 *
6071 * @remarks No-long-jump zone!!!
6072 */
6073static int hmR0VmxExportGuestSegReg(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t iSegReg, PCCPUMSELREG pSelReg)
6074{
6075 Assert(iSegReg < X86_SREG_COUNT);
6076 uint32_t const idxSel = g_aVmcsSegSel[iSegReg];
6077 uint32_t const idxLimit = g_aVmcsSegLimit[iSegReg];
6078 uint32_t const idxBase = g_aVmcsSegBase[iSegReg];
6079 uint32_t const idxAttr = g_aVmcsSegAttr[iSegReg];
6080
6081 uint32_t u32Access = pSelReg->Attr.u;
6082 if (pVmcsInfo->RealMode.fRealOnV86Active)
6083 {
6084 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
6085 u32Access = 0xf3;
6086 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6087 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
6088 RT_NOREF_PV(pVCpu);
6089 }
6090 else
6091 {
6092 /*
6093 * The way to differentiate between whether this is really a null selector or was just
6094 * a selector loaded with 0 in real-mode is using the segment attributes. A selector
6095 * loaded in real-mode with the value 0 is valid and usable in protected-mode and we
6096 * should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures
6097 * NULL selectors loaded in protected-mode have their attribute as 0.
6098 */
6099 if (!u32Access)
6100 u32Access = X86DESCATTR_UNUSABLE;
6101 }
6102
6103 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
6104 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
6105 ("Access bit not set for usable segment. idx=%#x sel=%#x attr %#x\n", idxBase, pSelReg, pSelReg->Attr.u));
6106
6107 /*
6108 * Commit it to the VMCS.
6109 */
6110 int rc = VMXWriteVmcs32(idxSel, pSelReg->Sel); AssertRC(rc);
6111 rc = VMXWriteVmcs32(idxLimit, pSelReg->u32Limit); AssertRC(rc);
6112 rc = VMXWriteVmcsNw(idxBase, pSelReg->u64Base); AssertRC(rc);
6113 rc = VMXWriteVmcs32(idxAttr, u32Access); AssertRC(rc);
6114 return VINF_SUCCESS;
6115}
6116
6117
6118/**
6119 * Exports the guest segment registers, GDTR, IDTR, LDTR, TR into the guest-state
6120 * area in the VMCS.
6121 *
6122 * @returns VBox status code.
6123 * @param pVCpu The cross context virtual CPU structure.
6124 * @param pVmxTransient The VMX-transient structure.
6125 *
6126 * @remarks Will import guest CR0 on strict builds during validation of
6127 * segments.
6128 * @remarks No-long-jump zone!!!
6129 */
6130static int hmR0VmxExportGuestSegRegsXdtr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6131{
6132 int rc = VERR_INTERNAL_ERROR_5;
6133 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6134 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6135 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6136
6137 /*
6138 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
6139 */
6140 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SREG_MASK)
6141 {
6142 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CS)
6143 {
6144 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CS);
6145 if (pVmcsInfo->RealMode.fRealOnV86Active)
6146 pVmcsInfo->RealMode.AttrCS.u = pCtx->cs.Attr.u;
6147 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_CS, &pCtx->cs);
6148 AssertRC(rc);
6149 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CS);
6150 }
6151
6152 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SS)
6153 {
6154 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SS);
6155 if (pVmcsInfo->RealMode.fRealOnV86Active)
6156 pVmcsInfo->RealMode.AttrSS.u = pCtx->ss.Attr.u;
6157 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_SS, &pCtx->ss);
6158 AssertRC(rc);
6159 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SS);
6160 }
6161
6162 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_DS)
6163 {
6164 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DS);
6165 if (pVmcsInfo->RealMode.fRealOnV86Active)
6166 pVmcsInfo->RealMode.AttrDS.u = pCtx->ds.Attr.u;
6167 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_DS, &pCtx->ds);
6168 AssertRC(rc);
6169 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_DS);
6170 }
6171
6172 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_ES)
6173 {
6174 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_ES);
6175 if (pVmcsInfo->RealMode.fRealOnV86Active)
6176 pVmcsInfo->RealMode.AttrES.u = pCtx->es.Attr.u;
6177 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_ES, &pCtx->es);
6178 AssertRC(rc);
6179 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_ES);
6180 }
6181
6182 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_FS)
6183 {
6184 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_FS);
6185 if (pVmcsInfo->RealMode.fRealOnV86Active)
6186 pVmcsInfo->RealMode.AttrFS.u = pCtx->fs.Attr.u;
6187 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_FS, &pCtx->fs);
6188 AssertRC(rc);
6189 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_FS);
6190 }
6191
6192 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GS)
6193 {
6194 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GS);
6195 if (pVmcsInfo->RealMode.fRealOnV86Active)
6196 pVmcsInfo->RealMode.AttrGS.u = pCtx->gs.Attr.u;
6197 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_GS, &pCtx->gs);
6198 AssertRC(rc);
6199 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GS);
6200 }
6201
6202#ifdef VBOX_STRICT
6203 hmR0VmxValidateSegmentRegs(pVCpu, pVmcsInfo);
6204#endif
6205 Log4Func(("cs={%#04x base=%#RX64 limit=%#RX32 attr=%#RX32}\n", pCtx->cs.Sel, pCtx->cs.u64Base, pCtx->cs.u32Limit,
6206 pCtx->cs.Attr.u));
6207 }
6208
6209 /*
6210 * Guest TR.
6211 */
6212 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_TR)
6213 {
6214 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_TR);
6215
6216 /*
6217 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is
6218 * achieved using the interrupt redirection bitmap (all bits cleared to let the guest
6219 * handle INT-n's) in the TSS. See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
6220 */
6221 uint16_t u16Sel;
6222 uint32_t u32Limit;
6223 uint64_t u64Base;
6224 uint32_t u32AccessRights;
6225 if (!pVmcsInfo->RealMode.fRealOnV86Active)
6226 {
6227 u16Sel = pCtx->tr.Sel;
6228 u32Limit = pCtx->tr.u32Limit;
6229 u64Base = pCtx->tr.u64Base;
6230 u32AccessRights = pCtx->tr.Attr.u;
6231 }
6232 else
6233 {
6234 Assert(!pVmxTransient->fIsNestedGuest);
6235 Assert(pVM->hm.s.vmx.pRealModeTSS);
6236 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMCanExecuteGuest() -XXX- what about inner loop changes? */
6237
6238 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
6239 RTGCPHYS GCPhys;
6240 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
6241 AssertRCReturn(rc, rc);
6242
6243 X86DESCATTR DescAttr;
6244 DescAttr.u = 0;
6245 DescAttr.n.u1Present = 1;
6246 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
6247
6248 u16Sel = 0;
6249 u32Limit = HM_VTX_TSS_SIZE;
6250 u64Base = GCPhys;
6251 u32AccessRights = DescAttr.u;
6252 }
6253
6254 /* Validate. */
6255 Assert(!(u16Sel & RT_BIT(2)));
6256 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
6257 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
6258 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
6259 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
6260 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
6261 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
6262 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
6263 Assert( (u32Limit & 0xfff) == 0xfff
6264 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
6265 Assert( !(pCtx->tr.u32Limit & 0xfff00000)
6266 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
6267
6268 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_TR_SEL, u16Sel); AssertRC(rc);
6269 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit); AssertRC(rc);
6270 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights); AssertRC(rc);
6271 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_TR_BASE, u64Base); AssertRC(rc);
6272
6273 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_TR);
6274 Log4Func(("tr base=%#RX64 limit=%#RX32\n", pCtx->tr.u64Base, pCtx->tr.u32Limit));
6275 }
6276
6277 /*
6278 * Guest GDTR.
6279 */
6280 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GDTR)
6281 {
6282 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GDTR);
6283
6284 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt); AssertRC(rc);
6285 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, pCtx->gdtr.pGdt); AssertRC(rc);
6286
6287 /* Validate. */
6288 Assert(!(pCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6289
6290 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GDTR);
6291 Log4Func(("gdtr base=%#RX64 limit=%#RX32\n", pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt));
6292 }
6293
6294 /*
6295 * Guest LDTR.
6296 */
6297 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_LDTR)
6298 {
6299 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_LDTR);
6300
6301 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
6302 uint32_t u32Access;
6303 if ( !pVmxTransient->fIsNestedGuest
6304 && !pCtx->ldtr.Attr.u)
6305 u32Access = X86DESCATTR_UNUSABLE;
6306 else
6307 u32Access = pCtx->ldtr.Attr.u;
6308
6309 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, pCtx->ldtr.Sel); AssertRC(rc);
6310 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtr.u32Limit); AssertRC(rc);
6311 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access); AssertRC(rc);
6312 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, pCtx->ldtr.u64Base); AssertRC(rc);
6313
6314 /* Validate. */
6315 if (!(u32Access & X86DESCATTR_UNUSABLE))
6316 {
6317 Assert(!(pCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
6318 Assert(pCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
6319 Assert(!pCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
6320 Assert(pCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
6321 Assert(!pCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
6322 Assert(!(pCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
6323 Assert( (pCtx->ldtr.u32Limit & 0xfff) == 0xfff
6324 || !pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
6325 Assert( !(pCtx->ldtr.u32Limit & 0xfff00000)
6326 || pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
6327 }
6328
6329 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_LDTR);
6330 Log4Func(("ldtr base=%#RX64 limit=%#RX32\n", pCtx->ldtr.u64Base, pCtx->ldtr.u32Limit));
6331 }
6332
6333 /*
6334 * Guest IDTR.
6335 */
6336 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_IDTR)
6337 {
6338 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_IDTR);
6339
6340 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt); AssertRC(rc);
6341 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, pCtx->idtr.pIdt); AssertRC(rc);
6342
6343 /* Validate. */
6344 Assert(!(pCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6345
6346 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_IDTR);
6347 Log4Func(("idtr base=%#RX64 limit=%#RX32\n", pCtx->idtr.pIdt, pCtx->idtr.cbIdt));
6348 }
6349
6350 return VINF_SUCCESS;
6351}
6352
6353
6354/**
6355 * Exports certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
6356 * areas.
6357 *
6358 * These MSRs will automatically be loaded to the host CPU on every successful
6359 * VM-entry and stored from the host CPU on every successful VM-exit.
6360 *
6361 * We creates/updates MSR slots for the host MSRs in the VM-exit MSR-load area. The
6362 * actual host MSR values are not- updated here for performance reasons. See
6363 * hmR0VmxExportHostMsrs().
6364 *
6365 * We also exports the guest sysenter MSRs into the guest-state area in the VMCS.
6366 *
6367 * @returns VBox status code.
6368 * @param pVCpu The cross context virtual CPU structure.
6369 * @param pVmxTransient The VMX-transient structure.
6370 *
6371 * @remarks No-long-jump zone!!!
6372 */
6373static int hmR0VmxExportGuestMsrs(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6374{
6375 AssertPtr(pVCpu);
6376 AssertPtr(pVmxTransient);
6377
6378 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6379 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6380
6381 /*
6382 * MSRs that we use the auto-load/store MSR area in the VMCS.
6383 * For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(),
6384 * nothing to do here. The host MSR values are updated when it's safe in
6385 * hmR0VmxLazySaveHostMsrs().
6386 *
6387 * For nested-guests, the guests MSRs from the VM-entry MSR-load area are already
6388 * loaded (into the guest-CPU context) by the VMLAUNCH/VMRESUME instruction
6389 * emulation. The merged MSR permission bitmap will ensure that we get VM-exits
6390 * for any MSR that are not part of the lazy MSRs so we do not need to place
6391 * those MSRs into the auto-load/store MSR area. Nothing to do here.
6392 */
6393 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_GUEST_AUTO_MSRS)
6394 {
6395 /* No auto-load/store MSRs currently. */
6396 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_GUEST_AUTO_MSRS);
6397 }
6398
6399 /*
6400 * Guest Sysenter MSRs.
6401 */
6402 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_MSR_MASK)
6403 {
6404 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SYSENTER_MSRS);
6405
6406 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_CS_MSR)
6407 {
6408 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pCtx->SysEnter.cs);
6409 AssertRC(rc);
6410 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_CS_MSR);
6411 }
6412
6413 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_EIP_MSR)
6414 {
6415 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, pCtx->SysEnter.eip);
6416 AssertRC(rc);
6417 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
6418 }
6419
6420 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_ESP_MSR)
6421 {
6422 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, pCtx->SysEnter.esp);
6423 AssertRC(rc);
6424 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
6425 }
6426 }
6427
6428 /*
6429 * Guest/host EFER MSR.
6430 */
6431 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_EFER_MSR)
6432 {
6433 /* Whether we are using the VMCS to swap the EFER MSR must have been
6434 determined earlier while exporting VM-entry/VM-exit controls. */
6435 Assert(!(ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS));
6436 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
6437
6438 if (hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
6439 {
6440 /*
6441 * EFER.LME is written by software, while EFER.LMA is set by the CPU to (CR0.PG & EFER.LME).
6442 * This means a guest can set EFER.LME=1 while CR0.PG=0 and EFER.LMA can remain 0.
6443 * VT-x requires that "IA-32e mode guest" VM-entry control must be identical to EFER.LMA
6444 * and to CR0.PG. Without unrestricted execution, CR0.PG (used for VT-x, not the shadow)
6445 * must always be 1. This forces us to effectively clear both EFER.LMA and EFER.LME until
6446 * the guest has also set CR0.PG=1. Otherwise, we would run into an invalid-guest state
6447 * during VM-entry.
6448 */
6449 uint64_t uGuestEferMsr = pCtx->msrEFER;
6450 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
6451 {
6452 if (!(pCtx->msrEFER & MSR_K6_EFER_LMA))
6453 uGuestEferMsr &= ~MSR_K6_EFER_LME;
6454 else
6455 Assert((pCtx->msrEFER & (MSR_K6_EFER_LMA | MSR_K6_EFER_LME)) == (MSR_K6_EFER_LMA | MSR_K6_EFER_LME));
6456 }
6457
6458 /*
6459 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
6460 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
6461 */
6462 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
6463 {
6464 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, uGuestEferMsr);
6465 AssertRC(rc);
6466 }
6467 else
6468 {
6469 /*
6470 * We shall use the auto-load/store MSR area only for loading the EFER MSR but we must
6471 * continue to intercept guest read and write accesses to it, see @bugref{7386#c16}.
6472 */
6473 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER, uGuestEferMsr,
6474 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6475 AssertRCReturn(rc, rc);
6476 }
6477
6478 Log4Func(("efer=%#RX64 shadow=%#RX64\n", uGuestEferMsr, pCtx->msrEFER));
6479 }
6480 else if (!pVM->hm.s.vmx.fSupportsVmcsEfer)
6481 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER);
6482
6483 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_EFER_MSR);
6484 }
6485
6486 /*
6487 * Other MSRs.
6488 * Speculation Control (R/W).
6489 */
6490 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_OTHER_MSRS)
6491 {
6492 HMVMX_CPUMCTX_ASSERT(pVCpu, HM_CHANGED_GUEST_OTHER_MSRS);
6493 if (pVM->cpum.ro.GuestFeatures.fIbrs)
6494 {
6495 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_IA32_SPEC_CTRL, CPUMGetGuestSpecCtrl(pVCpu),
6496 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6497 AssertRCReturn(rc, rc);
6498 }
6499 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
6500 }
6501
6502 return VINF_SUCCESS;
6503}
6504
6505
6506/**
6507 * Wrapper for running the guest code in VT-x.
6508 *
6509 * @returns VBox status code, no informational status codes.
6510 * @param pVCpu The cross context virtual CPU structure.
6511 * @param pVmxTransient The VMX-transient structure.
6512 *
6513 * @remarks No-long-jump zone!!!
6514 */
6515DECLINLINE(int) hmR0VmxRunGuest(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6516{
6517 /* Mark that HM is the keeper of all guest-CPU registers now that we're going to execute guest code. */
6518 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6519 pCtx->fExtrn |= HMVMX_CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_KEEPER_HM;
6520
6521 /** @todo Add stats for VMRESUME vs VMLAUNCH. */
6522
6523 /*
6524 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses
6525 * floating-point operations using SSE instructions. Some XMM registers (XMM6-XMM15) are
6526 * callee-saved and thus the need for this XMM wrapper.
6527 *
6528 * See MSDN "Configuring Programs for 64-bit/x64 Software Conventions / Register Usage".
6529 */
6530 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6531 bool const fResumeVM = RT_BOOL(pVmcsInfo->fVmcsState & VMX_V_VMCS_LAUNCH_STATE_LAUNCHED);
6532 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6533#ifdef VBOX_WITH_KERNEL_USING_XMM
6534 int rc = hmR0VMXStartVMWrapXMM(fResumeVM, pCtx, NULL /*pvUnused*/, pVM, pVCpu, pVmcsInfo->pfnStartVM);
6535#else
6536 int rc = pVmcsInfo->pfnStartVM(fResumeVM, pCtx, NULL /*pvUnused*/, pVM, pVCpu);
6537#endif
6538 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
6539 return rc;
6540}
6541
6542
6543/**
6544 * Reports world-switch error and dumps some useful debug info.
6545 *
6546 * @param pVCpu The cross context virtual CPU structure.
6547 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
6548 * @param pVmxTransient The VMX-transient structure (only
6549 * exitReason updated).
6550 */
6551static void hmR0VmxReportWorldSwitchError(PVMCPUCC pVCpu, int rcVMRun, PVMXTRANSIENT pVmxTransient)
6552{
6553 Assert(pVCpu);
6554 Assert(pVmxTransient);
6555 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
6556
6557 Log4Func(("VM-entry failure: %Rrc\n", rcVMRun));
6558 switch (rcVMRun)
6559 {
6560 case VERR_VMX_INVALID_VMXON_PTR:
6561 AssertFailed();
6562 break;
6563 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
6564 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
6565 {
6566 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
6567 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
6568 AssertRC(rc);
6569 hmR0VmxReadExitQualVmcs(pVmxTransient);
6570
6571 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
6572 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
6573 Cannot do it here as we may have been long preempted. */
6574
6575#ifdef VBOX_STRICT
6576 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6577 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
6578 pVmxTransient->uExitReason));
6579 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQual));
6580 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
6581 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
6582 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
6583 else
6584 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
6585 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
6586 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
6587
6588 static struct
6589 {
6590 /** Name of the field to log. */
6591 const char *pszName;
6592 /** The VMCS field. */
6593 uint32_t uVmcsField;
6594 /** Whether host support of this field needs to be checked. */
6595 bool fCheckSupport;
6596 } const s_aVmcsFields[] =
6597 {
6598 { "VMX_VMCS32_CTRL_PIN_EXEC", VMX_VMCS32_CTRL_PIN_EXEC, false },
6599 { "VMX_VMCS32_CTRL_PROC_EXEC", VMX_VMCS32_CTRL_PROC_EXEC, false },
6600 { "VMX_VMCS32_CTRL_PROC_EXEC2", VMX_VMCS32_CTRL_PROC_EXEC2, true },
6601 { "VMX_VMCS32_CTRL_ENTRY", VMX_VMCS32_CTRL_ENTRY, false },
6602 { "VMX_VMCS32_CTRL_EXIT", VMX_VMCS32_CTRL_EXIT, false },
6603 { "VMX_VMCS32_CTRL_CR3_TARGET_COUNT", VMX_VMCS32_CTRL_CR3_TARGET_COUNT, false },
6604 { "VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO", VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, false },
6605 { "VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE", VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, false },
6606 { "VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH", VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, false },
6607 { "VMX_VMCS32_CTRL_TPR_THRESHOLD", VMX_VMCS32_CTRL_TPR_THRESHOLD, false },
6608 { "VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, false },
6609 { "VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, false },
6610 { "VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, false },
6611 { "VMX_VMCS32_CTRL_EXCEPTION_BITMAP", VMX_VMCS32_CTRL_EXCEPTION_BITMAP, false },
6612 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, false },
6613 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, false },
6614 { "VMX_VMCS_CTRL_CR0_MASK", VMX_VMCS_CTRL_CR0_MASK, false },
6615 { "VMX_VMCS_CTRL_CR0_READ_SHADOW", VMX_VMCS_CTRL_CR0_READ_SHADOW, false },
6616 { "VMX_VMCS_CTRL_CR4_MASK", VMX_VMCS_CTRL_CR4_MASK, false },
6617 { "VMX_VMCS_CTRL_CR4_READ_SHADOW", VMX_VMCS_CTRL_CR4_READ_SHADOW, false },
6618 { "VMX_VMCS64_CTRL_EPTP_FULL", VMX_VMCS64_CTRL_EPTP_FULL, true },
6619 { "VMX_VMCS_GUEST_RIP", VMX_VMCS_GUEST_RIP, false },
6620 { "VMX_VMCS_GUEST_RSP", VMX_VMCS_GUEST_RSP, false },
6621 { "VMX_VMCS_GUEST_RFLAGS", VMX_VMCS_GUEST_RFLAGS, false },
6622 { "VMX_VMCS16_VPID", VMX_VMCS16_VPID, true, },
6623 { "VMX_VMCS_HOST_CR0", VMX_VMCS_HOST_CR0, false },
6624 { "VMX_VMCS_HOST_CR3", VMX_VMCS_HOST_CR3, false },
6625 { "VMX_VMCS_HOST_CR4", VMX_VMCS_HOST_CR4, false },
6626 /* The order of selector fields below are fixed! */
6627 { "VMX_VMCS16_HOST_ES_SEL", VMX_VMCS16_HOST_ES_SEL, false },
6628 { "VMX_VMCS16_HOST_CS_SEL", VMX_VMCS16_HOST_CS_SEL, false },
6629 { "VMX_VMCS16_HOST_SS_SEL", VMX_VMCS16_HOST_SS_SEL, false },
6630 { "VMX_VMCS16_HOST_DS_SEL", VMX_VMCS16_HOST_DS_SEL, false },
6631 { "VMX_VMCS16_HOST_FS_SEL", VMX_VMCS16_HOST_FS_SEL, false },
6632 { "VMX_VMCS16_HOST_GS_SEL", VMX_VMCS16_HOST_GS_SEL, false },
6633 { "VMX_VMCS16_HOST_TR_SEL", VMX_VMCS16_HOST_TR_SEL, false },
6634 /* End of ordered selector fields. */
6635 { "VMX_VMCS_HOST_TR_BASE", VMX_VMCS_HOST_TR_BASE, false },
6636 { "VMX_VMCS_HOST_GDTR_BASE", VMX_VMCS_HOST_GDTR_BASE, false },
6637 { "VMX_VMCS_HOST_IDTR_BASE", VMX_VMCS_HOST_IDTR_BASE, false },
6638 { "VMX_VMCS32_HOST_SYSENTER_CS", VMX_VMCS32_HOST_SYSENTER_CS, false },
6639 { "VMX_VMCS_HOST_SYSENTER_EIP", VMX_VMCS_HOST_SYSENTER_EIP, false },
6640 { "VMX_VMCS_HOST_SYSENTER_ESP", VMX_VMCS_HOST_SYSENTER_ESP, false },
6641 { "VMX_VMCS_HOST_RSP", VMX_VMCS_HOST_RSP, false },
6642 { "VMX_VMCS_HOST_RIP", VMX_VMCS_HOST_RIP, false }
6643 };
6644
6645 RTGDTR HostGdtr;
6646 ASMGetGDTR(&HostGdtr);
6647
6648 uint32_t const cVmcsFields = RT_ELEMENTS(s_aVmcsFields);
6649 for (uint32_t i = 0; i < cVmcsFields; i++)
6650 {
6651 uint32_t const uVmcsField = s_aVmcsFields[i].uVmcsField;
6652
6653 bool fSupported;
6654 if (!s_aVmcsFields[i].fCheckSupport)
6655 fSupported = true;
6656 else
6657 {
6658 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6659 switch (uVmcsField)
6660 {
6661 case VMX_VMCS64_CTRL_EPTP_FULL: fSupported = pVM->hm.s.fNestedPaging; break;
6662 case VMX_VMCS16_VPID: fSupported = pVM->hm.s.vmx.fVpid; break;
6663 case VMX_VMCS32_CTRL_PROC_EXEC2:
6664 fSupported = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
6665 break;
6666 default:
6667 AssertMsgFailedReturnVoid(("Failed to provide VMCS field support for %#RX32\n", uVmcsField));
6668 }
6669 }
6670
6671 if (fSupported)
6672 {
6673 uint8_t const uWidth = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH);
6674 switch (uWidth)
6675 {
6676 case VMX_VMCSFIELD_WIDTH_16BIT:
6677 {
6678 uint16_t u16Val;
6679 rc = VMXReadVmcs16(uVmcsField, &u16Val);
6680 AssertRC(rc);
6681 Log4(("%-40s = %#RX16\n", s_aVmcsFields[i].pszName, u16Val));
6682
6683 if ( uVmcsField >= VMX_VMCS16_HOST_ES_SEL
6684 && uVmcsField <= VMX_VMCS16_HOST_TR_SEL)
6685 {
6686 if (u16Val < HostGdtr.cbGdt)
6687 {
6688 /* Order of selectors in s_apszSel is fixed and matches the order in s_aVmcsFields. */
6689 static const char * const s_apszSel[] = { "Host ES", "Host CS", "Host SS", "Host DS",
6690 "Host FS", "Host GS", "Host TR" };
6691 uint8_t const idxSel = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_INDEX);
6692 Assert(idxSel < RT_ELEMENTS(s_apszSel));
6693 PCX86DESCHC pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u16Val & X86_SEL_MASK));
6694 hmR0DumpDescriptor(pDesc, u16Val, s_apszSel[idxSel]);
6695 }
6696 else
6697 Log4((" Selector value exceeds GDT limit!\n"));
6698 }
6699 break;
6700 }
6701
6702 case VMX_VMCSFIELD_WIDTH_32BIT:
6703 {
6704 uint32_t u32Val;
6705 rc = VMXReadVmcs32(uVmcsField, &u32Val);
6706 AssertRC(rc);
6707 Log4(("%-40s = %#RX32\n", s_aVmcsFields[i].pszName, u32Val));
6708 break;
6709 }
6710
6711 case VMX_VMCSFIELD_WIDTH_64BIT:
6712 case VMX_VMCSFIELD_WIDTH_NATURAL:
6713 {
6714 uint64_t u64Val;
6715 rc = VMXReadVmcs64(uVmcsField, &u64Val);
6716 AssertRC(rc);
6717 Log4(("%-40s = %#RX64\n", s_aVmcsFields[i].pszName, u64Val));
6718 break;
6719 }
6720 }
6721 }
6722 }
6723
6724 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
6725 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
6726 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
6727 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
6728 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
6729 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
6730#endif /* VBOX_STRICT */
6731 break;
6732 }
6733
6734 default:
6735 /* Impossible */
6736 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
6737 break;
6738 }
6739}
6740
6741
6742/**
6743 * Sets up the usage of TSC-offsetting and updates the VMCS.
6744 *
6745 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
6746 * VMX-preemption timer.
6747 *
6748 * @returns VBox status code.
6749 * @param pVCpu The cross context virtual CPU structure.
6750 * @param pVmxTransient The VMX-transient structure.
6751 *
6752 * @remarks No-long-jump zone!!!
6753 */
6754static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6755{
6756 bool fOffsettedTsc;
6757 bool fParavirtTsc;
6758 uint64_t uTscOffset;
6759 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6760 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6761
6762 if (pVM->hm.s.vmx.fUsePreemptTimer)
6763 {
6764 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &uTscOffset, &fOffsettedTsc, &fParavirtTsc);
6765
6766 /* Make sure the returned values have sane upper and lower boundaries. */
6767 uint64_t u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
6768 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second */
6769 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
6770 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
6771
6772 /** @todo r=ramshankar: We need to find a way to integrate nested-guest
6773 * preemption timers here. We probably need to clamp the preemption timer,
6774 * after converting the timer value to the host. */
6775 uint32_t const cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
6776 int rc = VMXWriteVmcs32(VMX_VMCS32_PREEMPT_TIMER_VALUE, cPreemptionTickCount);
6777 AssertRC(rc);
6778 }
6779 else
6780 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
6781
6782 if (fParavirtTsc)
6783 {
6784 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
6785 information before every VM-entry, hence disable it for performance sake. */
6786#if 0
6787 int rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
6788 AssertRC(rc);
6789#endif
6790 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
6791 }
6792
6793 if ( fOffsettedTsc
6794 && RT_LIKELY(!pVCpu->hm.s.fDebugWantRdTscExit))
6795 {
6796 if (pVmxTransient->fIsNestedGuest)
6797 uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
6798 hmR0VmxSetTscOffsetVmcs(pVmcsInfo, uTscOffset);
6799 hmR0VmxRemoveProcCtlsVmcs(pVCpu, pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
6800 }
6801 else
6802 {
6803 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
6804 hmR0VmxSetProcCtlsVmcs(pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
6805 }
6806}
6807
6808
6809/**
6810 * Gets the IEM exception flags for the specified vector and IDT vectoring /
6811 * VM-exit interruption info type.
6812 *
6813 * @returns The IEM exception flags.
6814 * @param uVector The event vector.
6815 * @param uVmxEventType The VMX event type.
6816 *
6817 * @remarks This function currently only constructs flags required for
6818 * IEMEvaluateRecursiveXcpt and not the complete flags (e.g, error-code
6819 * and CR2 aspects of an exception are not included).
6820 */
6821static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxEventType)
6822{
6823 uint32_t fIemXcptFlags;
6824 switch (uVmxEventType)
6825 {
6826 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
6827 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
6828 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
6829 break;
6830
6831 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
6832 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
6833 break;
6834
6835 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
6836 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
6837 break;
6838
6839 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
6840 {
6841 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6842 if (uVector == X86_XCPT_BP)
6843 fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
6844 else if (uVector == X86_XCPT_OF)
6845 fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
6846 else
6847 {
6848 fIemXcptFlags = 0;
6849 AssertMsgFailed(("Unexpected vector for software exception. uVector=%#x", uVector));
6850 }
6851 break;
6852 }
6853
6854 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
6855 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6856 break;
6857
6858 default:
6859 fIemXcptFlags = 0;
6860 AssertMsgFailed(("Unexpected vector type! uVmxEventType=%#x uVector=%#x", uVmxEventType, uVector));
6861 break;
6862 }
6863 return fIemXcptFlags;
6864}
6865
6866
6867/**
6868 * Sets an event as a pending event to be injected into the guest.
6869 *
6870 * @param pVCpu The cross context virtual CPU structure.
6871 * @param u32IntInfo The VM-entry interruption-information field.
6872 * @param cbInstr The VM-entry instruction length in bytes (for
6873 * software interrupts, exceptions and privileged
6874 * software exceptions).
6875 * @param u32ErrCode The VM-entry exception error code.
6876 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
6877 * page-fault.
6878 */
6879DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPUCC pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
6880 RTGCUINTPTR GCPtrFaultAddress)
6881{
6882 Assert(!pVCpu->hm.s.Event.fPending);
6883 pVCpu->hm.s.Event.fPending = true;
6884 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
6885 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
6886 pVCpu->hm.s.Event.cbInstr = cbInstr;
6887 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
6888}
6889
6890
6891/**
6892 * Sets an external interrupt as pending-for-injection into the VM.
6893 *
6894 * @param pVCpu The cross context virtual CPU structure.
6895 * @param u8Interrupt The external interrupt vector.
6896 */
6897DECLINLINE(void) hmR0VmxSetPendingExtInt(PVMCPUCC pVCpu, uint8_t u8Interrupt)
6898{
6899 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, u8Interrupt)
6900 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
6901 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6902 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6903 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6904}
6905
6906
6907/**
6908 * Sets an NMI (\#NMI) exception as pending-for-injection into the VM.
6909 *
6910 * @param pVCpu The cross context virtual CPU structure.
6911 */
6912DECLINLINE(void) hmR0VmxSetPendingXcptNmi(PVMCPUCC pVCpu)
6913{
6914 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI)
6915 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI)
6916 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6917 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6918 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6919}
6920
6921
6922/**
6923 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
6924 *
6925 * @param pVCpu The cross context virtual CPU structure.
6926 */
6927DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPUCC pVCpu)
6928{
6929 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
6930 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6931 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6932 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6933 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6934}
6935
6936
6937/**
6938 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
6939 *
6940 * @param pVCpu The cross context virtual CPU structure.
6941 */
6942DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPUCC pVCpu)
6943{
6944 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_UD)
6945 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6946 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6947 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6948 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6949}
6950
6951
6952/**
6953 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
6954 *
6955 * @param pVCpu The cross context virtual CPU structure.
6956 */
6957DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPUCC pVCpu)
6958{
6959 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
6960 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6961 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6962 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6963 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6964}
6965
6966
6967#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6968/**
6969 * Sets a general-protection (\#GP) exception as pending-for-injection into the VM.
6970 *
6971 * @param pVCpu The cross context virtual CPU structure.
6972 * @param u32ErrCode The error code for the general-protection exception.
6973 */
6974DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPUCC pVCpu, uint32_t u32ErrCode)
6975{
6976 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
6977 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6978 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6979 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6980 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
6981}
6982
6983
6984/**
6985 * Sets a stack (\#SS) exception as pending-for-injection into the VM.
6986 *
6987 * @param pVCpu The cross context virtual CPU structure.
6988 * @param u32ErrCode The error code for the stack exception.
6989 */
6990DECLINLINE(void) hmR0VmxSetPendingXcptSS(PVMCPUCC pVCpu, uint32_t u32ErrCode)
6991{
6992 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_SS)
6993 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6994 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6995 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6996 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
6997}
6998#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
6999
7000
7001/**
7002 * Fixes up attributes for the specified segment register.
7003 *
7004 * @param pVCpu The cross context virtual CPU structure.
7005 * @param pSelReg The segment register that needs fixing.
7006 * @param idxSel The VMCS field for the corresponding segment register.
7007 */
7008static void hmR0VmxFixUnusableSegRegAttr(PVMCPUCC pVCpu, PCPUMSELREG pSelReg, uint32_t idxSel)
7009{
7010 Assert(pSelReg->Attr.u & X86DESCATTR_UNUSABLE);
7011
7012 /*
7013 * If VT-x marks the segment as unusable, most other bits remain undefined:
7014 * - For CS the L, D and G bits have meaning.
7015 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
7016 * - For the remaining data segments no bits are defined.
7017 *
7018 * The present bit and the unusable bit has been observed to be set at the
7019 * same time (the selector was supposed to be invalid as we started executing
7020 * a V8086 interrupt in ring-0).
7021 *
7022 * What should be important for the rest of the VBox code, is that the P bit is
7023 * cleared. Some of the other VBox code recognizes the unusable bit, but
7024 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
7025 * safe side here, we'll strip off P and other bits we don't care about. If
7026 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
7027 *
7028 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
7029 */
7030#ifdef VBOX_STRICT
7031 uint32_t const uAttr = pSelReg->Attr.u;
7032#endif
7033
7034 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
7035 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
7036 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
7037
7038#ifdef VBOX_STRICT
7039 VMMRZCallRing3Disable(pVCpu);
7040 Log4Func(("Unusable %#x: sel=%#x attr=%#x -> %#x\n", idxSel, pSelReg->Sel, uAttr, pSelReg->Attr.u));
7041# ifdef DEBUG_bird
7042 AssertMsg((uAttr & ~X86DESCATTR_P) == pSelReg->Attr.u,
7043 ("%#x: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
7044 idxSel, uAttr, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
7045# endif
7046 VMMRZCallRing3Enable(pVCpu);
7047 NOREF(uAttr);
7048#endif
7049 RT_NOREF2(pVCpu, idxSel);
7050}
7051
7052
7053/**
7054 * Imports a guest segment register from the current VMCS into the guest-CPU
7055 * context.
7056 *
7057 * @param pVCpu The cross context virtual CPU structure.
7058 * @param iSegReg The segment register number (X86_SREG_XXX).
7059 *
7060 * @remarks Called with interrupts and/or preemption disabled.
7061 */
7062static void hmR0VmxImportGuestSegReg(PVMCPUCC pVCpu, uint8_t iSegReg)
7063{
7064 Assert(iSegReg < X86_SREG_COUNT);
7065
7066 uint32_t const idxSel = g_aVmcsSegSel[iSegReg];
7067 uint32_t const idxLimit = g_aVmcsSegLimit[iSegReg];
7068 uint32_t const idxAttr = g_aVmcsSegAttr[iSegReg];
7069 uint32_t const idxBase = g_aVmcsSegBase[iSegReg];
7070
7071 uint16_t u16Sel;
7072 uint64_t u64Base;
7073 uint32_t u32Limit, u32Attr;
7074 int rc = VMXReadVmcs16(idxSel, &u16Sel); AssertRC(rc);
7075 rc = VMXReadVmcs32(idxLimit, &u32Limit); AssertRC(rc);
7076 rc = VMXReadVmcs32(idxAttr, &u32Attr); AssertRC(rc);
7077 rc = VMXReadVmcsNw(idxBase, &u64Base); AssertRC(rc);
7078
7079 PCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
7080 pSelReg->Sel = u16Sel;
7081 pSelReg->ValidSel = u16Sel;
7082 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
7083 pSelReg->u32Limit = u32Limit;
7084 pSelReg->u64Base = u64Base;
7085 pSelReg->Attr.u = u32Attr;
7086 if (u32Attr & X86DESCATTR_UNUSABLE)
7087 hmR0VmxFixUnusableSegRegAttr(pVCpu, pSelReg, idxSel);
7088}
7089
7090
7091/**
7092 * Imports the guest LDTR from the current VMCS into the guest-CPU context.
7093 *
7094 * @param pVCpu The cross context virtual CPU structure.
7095 *
7096 * @remarks Called with interrupts and/or preemption disabled.
7097 */
7098static void hmR0VmxImportGuestLdtr(PVMCPUCC pVCpu)
7099{
7100 uint16_t u16Sel;
7101 uint64_t u64Base;
7102 uint32_t u32Limit, u32Attr;
7103 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, &u16Sel); AssertRC(rc);
7104 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, &u32Limit); AssertRC(rc);
7105 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7106 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, &u64Base); AssertRC(rc);
7107
7108 pVCpu->cpum.GstCtx.ldtr.Sel = u16Sel;
7109 pVCpu->cpum.GstCtx.ldtr.ValidSel = u16Sel;
7110 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
7111 pVCpu->cpum.GstCtx.ldtr.u32Limit = u32Limit;
7112 pVCpu->cpum.GstCtx.ldtr.u64Base = u64Base;
7113 pVCpu->cpum.GstCtx.ldtr.Attr.u = u32Attr;
7114 if (u32Attr & X86DESCATTR_UNUSABLE)
7115 hmR0VmxFixUnusableSegRegAttr(pVCpu, &pVCpu->cpum.GstCtx.ldtr, VMX_VMCS16_GUEST_LDTR_SEL);
7116}
7117
7118
7119/**
7120 * Imports the guest TR from the current VMCS into the guest-CPU context.
7121 *
7122 * @param pVCpu The cross context virtual CPU structure.
7123 *
7124 * @remarks Called with interrupts and/or preemption disabled.
7125 */
7126static void hmR0VmxImportGuestTr(PVMCPUCC pVCpu)
7127{
7128 uint16_t u16Sel;
7129 uint64_t u64Base;
7130 uint32_t u32Limit, u32Attr;
7131 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_TR_SEL, &u16Sel); AssertRC(rc);
7132 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, &u32Limit); AssertRC(rc);
7133 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7134 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_TR_BASE, &u64Base); AssertRC(rc);
7135
7136 pVCpu->cpum.GstCtx.tr.Sel = u16Sel;
7137 pVCpu->cpum.GstCtx.tr.ValidSel = u16Sel;
7138 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
7139 pVCpu->cpum.GstCtx.tr.u32Limit = u32Limit;
7140 pVCpu->cpum.GstCtx.tr.u64Base = u64Base;
7141 pVCpu->cpum.GstCtx.tr.Attr.u = u32Attr;
7142 /* TR is the only selector that can never be unusable. */
7143 Assert(!(u32Attr & X86DESCATTR_UNUSABLE));
7144}
7145
7146
7147/**
7148 * Imports the guest RIP from the VMCS back into the guest-CPU context.
7149 *
7150 * @param pVCpu The cross context virtual CPU structure.
7151 *
7152 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7153 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7154 * instead!!!
7155 */
7156static void hmR0VmxImportGuestRip(PVMCPUCC pVCpu)
7157{
7158 uint64_t u64Val;
7159 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7160 if (pCtx->fExtrn & CPUMCTX_EXTRN_RIP)
7161 {
7162 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
7163 AssertRC(rc);
7164
7165 pCtx->rip = u64Val;
7166 EMR0HistoryUpdatePC(pVCpu, pCtx->rip, false);
7167 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RIP;
7168 }
7169}
7170
7171
7172/**
7173 * Imports the guest RFLAGS from the VMCS back into the guest-CPU context.
7174 *
7175 * @param pVCpu The cross context virtual CPU structure.
7176 * @param pVmcsInfo The VMCS info. object.
7177 *
7178 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7179 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7180 * instead!!!
7181 */
7182static void hmR0VmxImportGuestRFlags(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7183{
7184 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7185 if (pCtx->fExtrn & CPUMCTX_EXTRN_RFLAGS)
7186 {
7187 uint64_t u64Val;
7188 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
7189 AssertRC(rc);
7190
7191 pCtx->rflags.u64 = u64Val;
7192 if (pVmcsInfo->RealMode.fRealOnV86Active)
7193 {
7194 pCtx->eflags.Bits.u1VM = 0;
7195 pCtx->eflags.Bits.u2IOPL = pVmcsInfo->RealMode.Eflags.Bits.u2IOPL;
7196 }
7197 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RFLAGS;
7198 }
7199}
7200
7201
7202/**
7203 * Imports the guest interruptibility-state from the VMCS back into the guest-CPU
7204 * context.
7205 *
7206 * @param pVCpu The cross context virtual CPU structure.
7207 * @param pVmcsInfo The VMCS info. object.
7208 *
7209 * @remarks Called with interrupts and/or preemption disabled, try not to assert and
7210 * do not log!
7211 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7212 * instead!!!
7213 */
7214static void hmR0VmxImportGuestIntrState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7215{
7216 uint32_t u32Val;
7217 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32Val); AssertRC(rc);
7218 if (!u32Val)
7219 {
7220 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7221 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7222 CPUMSetGuestNmiBlocking(pVCpu, false);
7223 }
7224 else
7225 {
7226 /*
7227 * We must import RIP here to set our EM interrupt-inhibited state.
7228 * We also import RFLAGS as our code that evaluates pending interrupts
7229 * before VM-entry requires it.
7230 */
7231 hmR0VmxImportGuestRip(pVCpu);
7232 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7233
7234 if (u32Val & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
7235 EMSetInhibitInterruptsPC(pVCpu, pVCpu->cpum.GstCtx.rip);
7236 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7237 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7238
7239 bool const fNmiBlocking = RT_BOOL(u32Val & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
7240 CPUMSetGuestNmiBlocking(pVCpu, fNmiBlocking);
7241 }
7242}
7243
7244
7245/**
7246 * Worker for VMXR0ImportStateOnDemand.
7247 *
7248 * @returns VBox status code.
7249 * @param pVCpu The cross context virtual CPU structure.
7250 * @param pVmcsInfo The VMCS info. object.
7251 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7252 */
7253static int hmR0VmxImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
7254{
7255 int rc = VINF_SUCCESS;
7256 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7257 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7258 uint32_t u32Val;
7259
7260 /*
7261 * Note! This is hack to workaround a mysterious BSOD observed with release builds
7262 * on Windows 10 64-bit hosts. Profile and debug builds are not affected and
7263 * neither are other host platforms.
7264 *
7265 * Committing this temporarily as it prevents BSOD.
7266 *
7267 * Update: This is very likely a compiler optimization bug, see @bugref{9180}.
7268 */
7269#ifdef RT_OS_WINDOWS
7270 if (pVM == 0 || pVM == (void *)(uintptr_t)-1)
7271 return VERR_HM_IPE_1;
7272#endif
7273
7274 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatImportGuestState, x);
7275
7276 /*
7277 * We disable interrupts to make the updating of the state and in particular
7278 * the fExtrn modification atomic wrt to preemption hooks.
7279 */
7280 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
7281
7282 fWhat &= pCtx->fExtrn;
7283 if (fWhat)
7284 {
7285 do
7286 {
7287 if (fWhat & CPUMCTX_EXTRN_RIP)
7288 hmR0VmxImportGuestRip(pVCpu);
7289
7290 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
7291 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7292
7293 if (fWhat & CPUMCTX_EXTRN_HM_VMX_INT_STATE)
7294 hmR0VmxImportGuestIntrState(pVCpu, pVmcsInfo);
7295
7296 if (fWhat & CPUMCTX_EXTRN_RSP)
7297 {
7298 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RSP, &pCtx->rsp);
7299 AssertRC(rc);
7300 }
7301
7302 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
7303 {
7304 bool const fRealOnV86Active = pVmcsInfo->RealMode.fRealOnV86Active;
7305 if (fWhat & CPUMCTX_EXTRN_CS)
7306 {
7307 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_CS);
7308 hmR0VmxImportGuestRip(pVCpu);
7309 if (fRealOnV86Active)
7310 pCtx->cs.Attr.u = pVmcsInfo->RealMode.AttrCS.u;
7311 EMR0HistoryUpdatePC(pVCpu, pCtx->cs.u64Base + pCtx->rip, true /* fFlattened */);
7312 }
7313 if (fWhat & CPUMCTX_EXTRN_SS)
7314 {
7315 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_SS);
7316 if (fRealOnV86Active)
7317 pCtx->ss.Attr.u = pVmcsInfo->RealMode.AttrSS.u;
7318 }
7319 if (fWhat & CPUMCTX_EXTRN_DS)
7320 {
7321 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_DS);
7322 if (fRealOnV86Active)
7323 pCtx->ds.Attr.u = pVmcsInfo->RealMode.AttrDS.u;
7324 }
7325 if (fWhat & CPUMCTX_EXTRN_ES)
7326 {
7327 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_ES);
7328 if (fRealOnV86Active)
7329 pCtx->es.Attr.u = pVmcsInfo->RealMode.AttrES.u;
7330 }
7331 if (fWhat & CPUMCTX_EXTRN_FS)
7332 {
7333 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_FS);
7334 if (fRealOnV86Active)
7335 pCtx->fs.Attr.u = pVmcsInfo->RealMode.AttrFS.u;
7336 }
7337 if (fWhat & CPUMCTX_EXTRN_GS)
7338 {
7339 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_GS);
7340 if (fRealOnV86Active)
7341 pCtx->gs.Attr.u = pVmcsInfo->RealMode.AttrGS.u;
7342 }
7343 }
7344
7345 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
7346 {
7347 if (fWhat & CPUMCTX_EXTRN_LDTR)
7348 hmR0VmxImportGuestLdtr(pVCpu);
7349
7350 if (fWhat & CPUMCTX_EXTRN_GDTR)
7351 {
7352 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &pCtx->gdtr.pGdt); AssertRC(rc);
7353 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRC(rc);
7354 pCtx->gdtr.cbGdt = u32Val;
7355 }
7356
7357 /* Guest IDTR. */
7358 if (fWhat & CPUMCTX_EXTRN_IDTR)
7359 {
7360 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &pCtx->idtr.pIdt); AssertRC(rc);
7361 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRC(rc);
7362 pCtx->idtr.cbIdt = u32Val;
7363 }
7364
7365 /* Guest TR. */
7366 if (fWhat & CPUMCTX_EXTRN_TR)
7367 {
7368 /* Real-mode emulation using virtual-8086 mode has the fake TSS (pRealModeTSS) in TR,
7369 don't need to import that one. */
7370 if (!pVmcsInfo->RealMode.fRealOnV86Active)
7371 hmR0VmxImportGuestTr(pVCpu);
7372 }
7373 }
7374
7375 if (fWhat & CPUMCTX_EXTRN_DR7)
7376 {
7377 if (!pVCpu->hm.s.fUsingHyperDR7)
7378 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_DR7, &pCtx->dr[7]); AssertRC(rc);
7379 }
7380
7381 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
7382 {
7383 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, &pCtx->SysEnter.eip); AssertRC(rc);
7384 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, &pCtx->SysEnter.esp); AssertRC(rc);
7385 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRC(rc);
7386 pCtx->SysEnter.cs = u32Val;
7387 }
7388
7389 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
7390 {
7391 if ( pVM->hm.s.fAllow64BitGuests
7392 && (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7393 pCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
7394 }
7395
7396 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
7397 {
7398 if ( pVM->hm.s.fAllow64BitGuests
7399 && (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7400 {
7401 pCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
7402 pCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
7403 pCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
7404 }
7405 }
7406
7407 if (fWhat & (CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS))
7408 {
7409 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
7410 uint32_t const cMsrs = pVmcsInfo->cExitMsrStore;
7411 Assert(pMsrs);
7412 Assert(cMsrs <= VMX_MISC_MAX_MSRS(pVM->hm.s.vmx.Msrs.u64Misc));
7413 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
7414 for (uint32_t i = 0; i < cMsrs; i++)
7415 {
7416 uint32_t const idMsr = pMsrs[i].u32Msr;
7417 switch (idMsr)
7418 {
7419 case MSR_K8_TSC_AUX: CPUMSetGuestTscAux(pVCpu, pMsrs[i].u64Value); break;
7420 case MSR_IA32_SPEC_CTRL: CPUMSetGuestSpecCtrl(pVCpu, pMsrs[i].u64Value); break;
7421 case MSR_K6_EFER: /* Can't be changed without causing a VM-exit */ break;
7422 default:
7423 {
7424 pCtx->fExtrn = 0;
7425 pVCpu->hm.s.u32HMError = pMsrs->u32Msr;
7426 ASMSetFlags(fEFlags);
7427 AssertMsgFailed(("Unexpected MSR in auto-load/store area. idMsr=%#RX32 cMsrs=%u\n", idMsr, cMsrs));
7428 return VERR_HM_UNEXPECTED_LD_ST_MSR;
7429 }
7430 }
7431 }
7432 }
7433
7434 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
7435 {
7436 if (fWhat & CPUMCTX_EXTRN_CR0)
7437 {
7438 uint64_t u64Cr0;
7439 uint64_t u64Shadow;
7440 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Cr0); AssertRC(rc);
7441 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Shadow); AssertRC(rc);
7442#ifndef VBOX_WITH_NESTED_HWVIRT_VMX
7443 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7444 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7445#else
7446 if (!CPUMIsGuestInVmxNonRootMode(pCtx))
7447 {
7448 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7449 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7450 }
7451 else
7452 {
7453 /*
7454 * We've merged the guest and nested-guest's CR0 guest/host mask while executing
7455 * the nested-guest using hardware-assisted VMX. Accordingly we need to
7456 * re-construct CR0. See @bugref{9180#c95} for details.
7457 */
7458 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hm.s.vmx.VmcsInfo;
7459 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
7460 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7461 | (pVmcsNstGst->u64GuestCr0.u & pVmcsNstGst->u64Cr0Mask.u)
7462 | (u64Shadow & (pVmcsInfoGst->u64Cr0Mask & ~pVmcsNstGst->u64Cr0Mask.u));
7463 }
7464#endif
7465 VMMRZCallRing3Disable(pVCpu); /* May call into PGM which has Log statements. */
7466 CPUMSetGuestCR0(pVCpu, u64Cr0);
7467 VMMRZCallRing3Enable(pVCpu);
7468 }
7469
7470 if (fWhat & CPUMCTX_EXTRN_CR4)
7471 {
7472 uint64_t u64Cr4;
7473 uint64_t u64Shadow;
7474 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64Cr4); AssertRC(rc);
7475 rc |= VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Shadow); AssertRC(rc);
7476#ifndef VBOX_WITH_NESTED_HWVIRT_VMX
7477 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7478 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7479#else
7480 if (!CPUMIsGuestInVmxNonRootMode(pCtx))
7481 {
7482 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7483 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7484 }
7485 else
7486 {
7487 /*
7488 * We've merged the guest and nested-guest's CR4 guest/host mask while executing
7489 * the nested-guest using hardware-assisted VMX. Accordingly we need to
7490 * re-construct CR4. See @bugref{9180#c95} for details.
7491 */
7492 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hm.s.vmx.VmcsInfo;
7493 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
7494 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7495 | (pVmcsNstGst->u64GuestCr4.u & pVmcsNstGst->u64Cr4Mask.u)
7496 | (u64Shadow & (pVmcsInfoGst->u64Cr4Mask & ~pVmcsNstGst->u64Cr4Mask.u));
7497 }
7498#endif
7499 pCtx->cr4 = u64Cr4;
7500 }
7501
7502 if (fWhat & CPUMCTX_EXTRN_CR3)
7503 {
7504 /* CR0.PG bit changes are always intercepted, so it's up to date. */
7505 if ( pVM->hm.s.vmx.fUnrestrictedGuest
7506 || ( pVM->hm.s.fNestedPaging
7507 && CPUMIsGuestPagingEnabledEx(pCtx)))
7508 {
7509 uint64_t u64Cr3;
7510 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR3, &u64Cr3); AssertRC(rc);
7511 if (pCtx->cr3 != u64Cr3)
7512 {
7513 pCtx->cr3 = u64Cr3;
7514 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
7515 }
7516
7517 /* If the guest is in PAE mode, sync back the PDPE's into the guest state.
7518 Note: CR4.PAE, CR0.PG, EFER MSR changes are always intercepted, so they're up to date. */
7519 if (CPUMIsGuestInPAEModeEx(pCtx))
7520 {
7521 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
7522 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
7523 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
7524 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
7525 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
7526 }
7527 }
7528 }
7529 }
7530
7531#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7532 if (fWhat & CPUMCTX_EXTRN_HWVIRT)
7533 {
7534 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
7535 && !CPUMIsGuestInVmxNonRootMode(pCtx))
7536 {
7537 Assert(CPUMIsGuestInVmxRootMode(pCtx));
7538 rc = hmR0VmxCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
7539 if (RT_SUCCESS(rc))
7540 { /* likely */ }
7541 else
7542 break;
7543 }
7544 }
7545#endif
7546 } while (0);
7547
7548 if (RT_SUCCESS(rc))
7549 {
7550 /* Update fExtrn. */
7551 pCtx->fExtrn &= ~fWhat;
7552
7553 /* If everything has been imported, clear the HM keeper bit. */
7554 if (!(pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL))
7555 {
7556 pCtx->fExtrn &= ~CPUMCTX_EXTRN_KEEPER_HM;
7557 Assert(!pCtx->fExtrn);
7558 }
7559 }
7560 }
7561 else
7562 AssertMsg(!pCtx->fExtrn || (pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL), ("%#RX64\n", pCtx->fExtrn));
7563
7564 /*
7565 * Restore interrupts.
7566 */
7567 ASMSetFlags(fEFlags);
7568
7569 STAM_PROFILE_ADV_STOP(& pVCpu->hm.s.StatImportGuestState, x);
7570
7571 if (RT_SUCCESS(rc))
7572 { /* likely */ }
7573 else
7574 return rc;
7575
7576 /*
7577 * Honor any pending CR3 updates.
7578 *
7579 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> VMXR0CallRing3Callback()
7580 * -> VMMRZCallRing3Disable() -> hmR0VmxImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
7581 * -> continue with VM-exit handling -> hmR0VmxImportGuestState() and here we are.
7582 *
7583 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
7584 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
7585 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
7586 * -NOT- check if CPUMCTX_EXTRN_CR3 is set!
7587 *
7588 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
7589 */
7590 if (VMMRZCallRing3IsEnabled(pVCpu))
7591 {
7592 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
7593 {
7594 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & CPUMCTX_EXTRN_CR3));
7595 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
7596 }
7597
7598 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
7599 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
7600
7601 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
7602 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
7603 }
7604
7605 return VINF_SUCCESS;
7606}
7607
7608
7609/**
7610 * Saves the guest state from the VMCS into the guest-CPU context.
7611 *
7612 * @returns VBox status code.
7613 * @param pVCpu The cross context virtual CPU structure.
7614 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7615 */
7616VMMR0DECL(int) VMXR0ImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat)
7617{
7618 AssertPtr(pVCpu);
7619 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7620 return hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fWhat);
7621}
7622
7623
7624/**
7625 * Check per-VM and per-VCPU force flag actions that require us to go back to
7626 * ring-3 for one reason or another.
7627 *
7628 * @returns Strict VBox status code (i.e. informational status codes too)
7629 * @retval VINF_SUCCESS if we don't have any actions that require going back to
7630 * ring-3.
7631 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
7632 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
7633 * interrupts)
7634 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
7635 * all EMTs to be in ring-3.
7636 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
7637 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
7638 * to the EM loop.
7639 *
7640 * @param pVCpu The cross context virtual CPU structure.
7641 * @param pVmxTransient The VMX-transient structure.
7642 * @param fStepping Whether we are single-stepping the guest using the
7643 * hypervisor debugger.
7644 *
7645 * @remarks This might cause nested-guest VM-exits, caller must check if the guest
7646 * is no longer in VMX non-root mode.
7647 */
7648static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, bool fStepping)
7649{
7650 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7651
7652 /*
7653 * Update pending interrupts into the APIC's IRR.
7654 */
7655 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
7656 APICUpdatePendingInterrupts(pVCpu);
7657
7658 /*
7659 * Anything pending? Should be more likely than not if we're doing a good job.
7660 */
7661 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7662 if ( !fStepping
7663 ? !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_MASK)
7664 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
7665 : !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
7666 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
7667 return VINF_SUCCESS;
7668
7669 /* Pending PGM C3 sync. */
7670 if (VMCPU_FF_IS_ANY_SET(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
7671 {
7672 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7673 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & (CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4)));
7674 VBOXSTRICTRC rcStrict = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4,
7675 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
7676 if (rcStrict != VINF_SUCCESS)
7677 {
7678 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
7679 Log4Func(("PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
7680 return rcStrict;
7681 }
7682 }
7683
7684 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
7685 if ( VM_FF_IS_ANY_SET(pVM, VM_FF_HM_TO_R3_MASK)
7686 || VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
7687 {
7688 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
7689 int rc = RT_LIKELY(!VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_RAW_TO_R3 : VINF_EM_NO_MEMORY;
7690 Log4Func(("HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc));
7691 return rc;
7692 }
7693
7694 /* Pending VM request packets, such as hardware interrupts. */
7695 if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
7696 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
7697 {
7698 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchVmReq);
7699 Log4Func(("Pending VM request forcing us back to ring-3\n"));
7700 return VINF_EM_PENDING_REQUEST;
7701 }
7702
7703 /* Pending PGM pool flushes. */
7704 if (VM_FF_IS_SET(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
7705 {
7706 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPgmPoolFlush);
7707 Log4Func(("PGM pool flush pending forcing us back to ring-3\n"));
7708 return VINF_PGM_POOL_FLUSH_PENDING;
7709 }
7710
7711 /* Pending DMA requests. */
7712 if (VM_FF_IS_SET(pVM, VM_FF_PDM_DMA))
7713 {
7714 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchDma);
7715 Log4Func(("Pending DMA request forcing us back to ring-3\n"));
7716 return VINF_EM_RAW_TO_R3;
7717 }
7718
7719#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7720 /*
7721 * Pending nested-guest events.
7722 *
7723 * Please note the priority of these events are specified and important.
7724 * See Intel spec. 29.4.3.2 "APIC-Write Emulation".
7725 * See Intel spec. 6.9 "Priority Among Simultaneous Exceptions And Interrupts".
7726 */
7727 if (pVmxTransient->fIsNestedGuest)
7728 {
7729 /* Pending nested-guest APIC-write. */
7730 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
7731 {
7732 Log4Func(("Pending nested-guest APIC-write\n"));
7733 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitApicWrite(pVCpu);
7734 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
7735 return rcStrict;
7736 }
7737
7738 /* Pending nested-guest monitor-trap flag (MTF). */
7739 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF))
7740 {
7741 Log4Func(("Pending nested-guest MTF\n"));
7742 VBOXSTRICTRC rcStrict = IEMExecVmxVmexit(pVCpu, VMX_EXIT_MTF, 0 /* uExitQual */);
7743 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
7744 return rcStrict;
7745 }
7746
7747 /* Pending nested-guest VMX-preemption timer expired. */
7748 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER))
7749 {
7750 Log4Func(("Pending nested-guest MTF\n"));
7751 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitPreemptTimer(pVCpu);
7752 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
7753 return rcStrict;
7754 }
7755 }
7756#else
7757 NOREF(pVmxTransient);
7758#endif
7759
7760 return VINF_SUCCESS;
7761}
7762
7763
7764/**
7765 * Converts any TRPM trap into a pending HM event. This is typically used when
7766 * entering from ring-3 (not longjmp returns).
7767 *
7768 * @param pVCpu The cross context virtual CPU structure.
7769 */
7770static void hmR0VmxTrpmTrapToPendingEvent(PVMCPUCC pVCpu)
7771{
7772 Assert(TRPMHasTrap(pVCpu));
7773 Assert(!pVCpu->hm.s.Event.fPending);
7774
7775 uint8_t uVector;
7776 TRPMEVENT enmTrpmEvent;
7777 uint32_t uErrCode;
7778 RTGCUINTPTR GCPtrFaultAddress;
7779 uint8_t cbInstr;
7780 bool fIcebp;
7781
7782 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr, &fIcebp);
7783 AssertRC(rc);
7784
7785 uint32_t u32IntInfo;
7786 u32IntInfo = uVector | VMX_IDT_VECTORING_INFO_VALID;
7787 u32IntInfo |= HMTrpmEventTypeToVmxEventType(uVector, enmTrpmEvent, fIcebp);
7788
7789 rc = TRPMResetTrap(pVCpu);
7790 AssertRC(rc);
7791 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
7792 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
7793
7794 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
7795}
7796
7797
7798/**
7799 * Converts the pending HM event into a TRPM trap.
7800 *
7801 * @param pVCpu The cross context virtual CPU structure.
7802 */
7803static void hmR0VmxPendingEventToTrpmTrap(PVMCPUCC pVCpu)
7804{
7805 Assert(pVCpu->hm.s.Event.fPending);
7806
7807 /* If a trap was already pending, we did something wrong! */
7808 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
7809
7810 uint32_t const u32IntInfo = pVCpu->hm.s.Event.u64IntInfo;
7811 uint32_t const uVector = VMX_IDT_VECTORING_INFO_VECTOR(u32IntInfo);
7812 TRPMEVENT const enmTrapType = HMVmxEventTypeToTrpmEventType(u32IntInfo);
7813
7814 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
7815
7816 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
7817 AssertRC(rc);
7818
7819 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
7820 TRPMSetErrorCode(pVCpu, pVCpu->hm.s.Event.u32ErrCode);
7821
7822 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(u32IntInfo))
7823 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
7824 else if (VMX_IDT_VECTORING_INFO_TYPE(u32IntInfo) == VMX_IDT_VECTORING_INFO_TYPE_SW_INT)
7825 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
7826
7827 if (VMX_IDT_VECTORING_INFO_TYPE(u32IntInfo) == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
7828 TRPMSetTrapDueToIcebp(pVCpu);
7829
7830 /* We're now done converting the pending event. */
7831 pVCpu->hm.s.Event.fPending = false;
7832}
7833
7834
7835/**
7836 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
7837 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
7838 *
7839 * @param pVCpu The cross context virtual CPU structure.
7840 * @param pVmcsInfo The VMCS info. object.
7841 */
7842static void hmR0VmxSetIntWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
7843{
7844 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7845 {
7846 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
7847 {
7848 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_INT_WINDOW_EXIT;
7849 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7850 AssertRC(rc);
7851 }
7852 } /* else we will deliver interrupts whenever the guest Vm-exits next and is in a state to receive the interrupt. */
7853}
7854
7855
7856/**
7857 * Clears the interrupt-window exiting control in the VMCS.
7858 *
7859 * @param pVmcsInfo The VMCS info. object.
7860 */
7861DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
7862{
7863 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7864 {
7865 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_INT_WINDOW_EXIT;
7866 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7867 AssertRC(rc);
7868 }
7869}
7870
7871
7872/**
7873 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
7874 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
7875 *
7876 * @param pVCpu The cross context virtual CPU structure.
7877 * @param pVmcsInfo The VMCS info. object.
7878 */
7879static void hmR0VmxSetNmiWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
7880{
7881 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7882 {
7883 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
7884 {
7885 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_NMI_WINDOW_EXIT;
7886 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7887 AssertRC(rc);
7888 Log4Func(("Setup NMI-window exiting\n"));
7889 }
7890 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
7891}
7892
7893
7894/**
7895 * Clears the NMI-window exiting control in the VMCS.
7896 *
7897 * @param pVmcsInfo The VMCS info. object.
7898 */
7899DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
7900{
7901 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7902 {
7903 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_NMI_WINDOW_EXIT;
7904 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7905 AssertRC(rc);
7906 }
7907}
7908
7909
7910/**
7911 * Does the necessary state syncing before returning to ring-3 for any reason
7912 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
7913 *
7914 * @returns VBox status code.
7915 * @param pVCpu The cross context virtual CPU structure.
7916 * @param fImportState Whether to import the guest state from the VMCS back
7917 * to the guest-CPU context.
7918 *
7919 * @remarks No-long-jmp zone!!!
7920 */
7921static int hmR0VmxLeave(PVMCPUCC pVCpu, bool fImportState)
7922{
7923 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7924 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7925
7926 RTCPUID const idCpu = RTMpCpuId();
7927 Log4Func(("HostCpuId=%u\n", idCpu));
7928
7929 /*
7930 * !!! IMPORTANT !!!
7931 * If you modify code here, check whether VMXR0CallRing3Callback() needs to be updated too.
7932 */
7933
7934 /* Save the guest state if necessary. */
7935 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7936 if (fImportState)
7937 {
7938 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
7939 AssertRCReturn(rc, rc);
7940 }
7941
7942 /* Restore host FPU state if necessary. We will resync on next R0 reentry. */
7943 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
7944 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
7945
7946 /* Restore host debug registers if necessary. We will resync on next R0 reentry. */
7947#ifdef VBOX_STRICT
7948 if (CPUMIsHyperDebugStateActive(pVCpu))
7949 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT);
7950#endif
7951 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
7952 Assert(!CPUMIsGuestDebugStateActive(pVCpu) && !CPUMIsGuestDebugStateActivePending(pVCpu));
7953 Assert(!CPUMIsHyperDebugStateActive(pVCpu) && !CPUMIsHyperDebugStateActivePending(pVCpu));
7954
7955 /* Restore host-state bits that VT-x only restores partially. */
7956 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7957 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7958 {
7959 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags, idCpu));
7960 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7961 }
7962 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7963
7964 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7965 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
7966 {
7967 /* We shouldn't restore the host MSRs without saving the guest MSRs first. */
7968 if (!fImportState)
7969 {
7970 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS);
7971 AssertRCReturn(rc, rc);
7972 }
7973 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7974 Assert(!pVCpu->hm.s.vmx.fLazyMsrs);
7975 }
7976 else
7977 pVCpu->hm.s.vmx.fLazyMsrs = 0;
7978
7979 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7980 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
7981
7982 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
7983 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatImportGuestState);
7984 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExportGuestState);
7985 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatPreExit);
7986 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitHandling);
7987 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
7988 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
7989 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
7990 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitVmentry);
7991 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7992
7993 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7994
7995 /** @todo This partially defeats the purpose of having preemption hooks.
7996 * The problem is, deregistering the hooks should be moved to a place that
7997 * lasts until the EMT is about to be destroyed not everytime while leaving HM
7998 * context.
7999 */
8000 int rc = hmR0VmxClearVmcs(pVmcsInfo);
8001 AssertRCReturn(rc, rc);
8002
8003#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8004 /*
8005 * A valid shadow VMCS is made active as part of VM-entry. It is necessary to
8006 * clear a shadow VMCS before allowing that VMCS to become active on another
8007 * logical processor. We may or may not be importing guest state which clears
8008 * it, so cover for it here.
8009 *
8010 * See Intel spec. 24.11.1 "Software Use of Virtual-Machine Control Structures".
8011 */
8012 if ( pVmcsInfo->pvShadowVmcs
8013 && pVmcsInfo->fShadowVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
8014 {
8015 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
8016 AssertRCReturn(rc, rc);
8017 }
8018
8019 /*
8020 * Flag that we need to re-export the host state if we switch to this VMCS before
8021 * executing guest or nested-guest code.
8022 */
8023 pVmcsInfo->idHostCpuState = NIL_RTCPUID;
8024#endif
8025
8026 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
8027 NOREF(idCpu);
8028 return VINF_SUCCESS;
8029}
8030
8031
8032/**
8033 * Leaves the VT-x session.
8034 *
8035 * @returns VBox status code.
8036 * @param pVCpu The cross context virtual CPU structure.
8037 *
8038 * @remarks No-long-jmp zone!!!
8039 */
8040static int hmR0VmxLeaveSession(PVMCPUCC pVCpu)
8041{
8042 HM_DISABLE_PREEMPT(pVCpu);
8043 HMVMX_ASSERT_CPU_SAFE(pVCpu);
8044 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8045 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8046
8047 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
8048 and done this from the VMXR0ThreadCtxCallback(). */
8049 if (!pVCpu->hm.s.fLeaveDone)
8050 {
8051 int rc2 = hmR0VmxLeave(pVCpu, true /* fImportState */);
8052 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
8053 pVCpu->hm.s.fLeaveDone = true;
8054 }
8055 Assert(!pVCpu->cpum.GstCtx.fExtrn);
8056
8057 /*
8058 * !!! IMPORTANT !!!
8059 * If you modify code here, make sure to check whether VMXR0CallRing3Callback() needs to be updated too.
8060 */
8061
8062 /* Deregister hook now that we've left HM context before re-enabling preemption. */
8063 /** @todo Deregistering here means we need to VMCLEAR always
8064 * (longjmp/exit-to-r3) in VT-x which is not efficient, eliminate need
8065 * for calling VMMR0ThreadCtxHookDisable here! */
8066 VMMR0ThreadCtxHookDisable(pVCpu);
8067
8068 /* Leave HM context. This takes care of local init (term) and deregistering the longjmp-to-ring-3 callback. */
8069 int rc = HMR0LeaveCpu(pVCpu);
8070 HM_RESTORE_PREEMPT();
8071 return rc;
8072}
8073
8074
8075/**
8076 * Does the necessary state syncing before doing a longjmp to ring-3.
8077 *
8078 * @returns VBox status code.
8079 * @param pVCpu The cross context virtual CPU structure.
8080 *
8081 * @remarks No-long-jmp zone!!!
8082 */
8083DECLINLINE(int) hmR0VmxLongJmpToRing3(PVMCPUCC pVCpu)
8084{
8085 return hmR0VmxLeaveSession(pVCpu);
8086}
8087
8088
8089/**
8090 * Take necessary actions before going back to ring-3.
8091 *
8092 * An action requires us to go back to ring-3. This function does the necessary
8093 * steps before we can safely return to ring-3. This is not the same as longjmps
8094 * to ring-3, this is voluntary and prepares the guest so it may continue
8095 * executing outside HM (recompiler/IEM).
8096 *
8097 * @returns VBox status code.
8098 * @param pVCpu The cross context virtual CPU structure.
8099 * @param rcExit The reason for exiting to ring-3. Can be
8100 * VINF_VMM_UNKNOWN_RING3_CALL.
8101 */
8102static int hmR0VmxExitToRing3(PVMCPUCC pVCpu, VBOXSTRICTRC rcExit)
8103{
8104 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8105
8106 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8107 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
8108 {
8109 VMXGetCurrentVmcs(&pVCpu->hm.s.vmx.LastError.HCPhysCurrentVmcs);
8110 pVCpu->hm.s.vmx.LastError.u32VmcsRev = *(uint32_t *)pVmcsInfo->pvVmcs;
8111 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
8112 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
8113 }
8114
8115 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
8116 VMMRZCallRing3Disable(pVCpu);
8117 Log4Func(("rcExit=%d\n", VBOXSTRICTRC_VAL(rcExit)));
8118
8119 /*
8120 * Convert any pending HM events back to TRPM due to premature exits to ring-3.
8121 * We need to do this only on returns to ring-3 and not for longjmps to ring3.
8122 *
8123 * This is because execution may continue from ring-3 and we would need to inject
8124 * the event from there (hence place it back in TRPM).
8125 */
8126 if (pVCpu->hm.s.Event.fPending)
8127 {
8128 hmR0VmxPendingEventToTrpmTrap(pVCpu);
8129 Assert(!pVCpu->hm.s.Event.fPending);
8130
8131 /* Clear the events from the VMCS. */
8132 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0); AssertRC(rc);
8133 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, 0); AssertRC(rc);
8134 }
8135#ifdef VBOX_STRICT
8136 else
8137 {
8138 /*
8139 * Ensure we don't accidentally clear a pending HM event without clearing the VMCS.
8140 * This can be pretty hard to debug otherwise, interrupts might get injected twice
8141 * occasionally, see @bugref{9180#c42}.
8142 *
8143 * However, if the VM-entry failed, any VM entry-interruption info. field would
8144 * be left unmodified as the event would not have been injected to the guest. In
8145 * such cases, don't assert, we're not going to continue guest execution anyway.
8146 */
8147 uint32_t uExitReason;
8148 uint32_t uEntryIntInfo;
8149 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8150 rc |= VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &uEntryIntInfo);
8151 AssertRC(rc);
8152 Assert(VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason) || !VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo));
8153 }
8154#endif
8155
8156 /*
8157 * Clear the interrupt-window and NMI-window VMCS controls as we could have got
8158 * a VM-exit with higher priority than interrupt-window or NMI-window VM-exits
8159 * (e.g. TPR below threshold).
8160 */
8161 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8162 {
8163 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
8164 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
8165 }
8166
8167 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
8168 and if we're injecting an event we should have a TRPM trap pending. */
8169 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8170#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a triple fault in progress. */
8171 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8172#endif
8173
8174 /* Save guest state and restore host state bits. */
8175 int rc = hmR0VmxLeaveSession(pVCpu);
8176 AssertRCReturn(rc, rc);
8177 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8178
8179 /* Thread-context hooks are unregistered at this point!!! */
8180 /* Ring-3 callback notifications are unregistered at this point!!! */
8181
8182 /* Sync recompiler state. */
8183 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
8184 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
8185 | CPUM_CHANGED_LDTR
8186 | CPUM_CHANGED_GDTR
8187 | CPUM_CHANGED_IDTR
8188 | CPUM_CHANGED_TR
8189 | CPUM_CHANGED_HIDDEN_SEL_REGS);
8190 if ( pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging
8191 && CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx))
8192 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
8193
8194 Assert(!pVCpu->hm.s.fClearTrapFlag);
8195
8196 /* Update the exit-to-ring 3 reason. */
8197 pVCpu->hm.s.rcLastExitToR3 = VBOXSTRICTRC_VAL(rcExit);
8198
8199 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
8200 if ( rcExit != VINF_EM_RAW_INTERRUPT
8201 || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8202 {
8203 Assert(!(pVCpu->cpum.GstCtx.fExtrn & HMVMX_CPUMCTX_EXTRN_ALL));
8204 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
8205 }
8206
8207 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
8208 VMMRZCallRing3Enable(pVCpu);
8209 return rc;
8210}
8211
8212
8213/**
8214 * VMMRZCallRing3() callback wrapper which saves the guest state before we
8215 * longjump to ring-3 and possibly get preempted.
8216 *
8217 * @returns VBox status code.
8218 * @param pVCpu The cross context virtual CPU structure.
8219 * @param enmOperation The operation causing the ring-3 longjump.
8220 */
8221VMMR0DECL(int) VMXR0CallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation)
8222{
8223 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
8224 {
8225 /*
8226 * !!! IMPORTANT !!!
8227 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
8228 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
8229 */
8230 VMMRZCallRing3RemoveNotification(pVCpu);
8231 VMMRZCallRing3Disable(pVCpu);
8232 HM_DISABLE_PREEMPT(pVCpu);
8233
8234 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8235 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8236 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8237 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8238
8239 /* Restore host-state bits that VT-x only restores partially. */
8240 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
8241 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
8242 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
8243 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
8244
8245 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8246 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8247 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8248
8249 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8250 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
8251 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8252
8253 /* Clear the current VMCS data back to memory (shadow VMCS if any would have been
8254 cleared as part of importing the guest state above. */
8255 hmR0VmxClearVmcs(pVmcsInfo);
8256
8257 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
8258 VMMR0ThreadCtxHookDisable(pVCpu);
8259
8260 /* Leave HM context. This takes care of local init (term). */
8261 HMR0LeaveCpu(pVCpu);
8262 HM_RESTORE_PREEMPT();
8263 return VINF_SUCCESS;
8264 }
8265
8266 Assert(pVCpu);
8267 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8268 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8269
8270 VMMRZCallRing3Disable(pVCpu);
8271 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8272
8273 Log4Func(("-> hmR0VmxLongJmpToRing3 enmOperation=%d\n", enmOperation));
8274
8275 int rc = hmR0VmxLongJmpToRing3(pVCpu);
8276 AssertRCReturn(rc, rc);
8277
8278 VMMRZCallRing3Enable(pVCpu);
8279 return VINF_SUCCESS;
8280}
8281
8282
8283/**
8284 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
8285 * stack.
8286 *
8287 * @returns Strict VBox status code (i.e. informational status codes too).
8288 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
8289 * @param pVCpu The cross context virtual CPU structure.
8290 * @param uValue The value to push to the guest stack.
8291 */
8292static VBOXSTRICTRC hmR0VmxRealModeGuestStackPush(PVMCPUCC pVCpu, uint16_t uValue)
8293{
8294 /*
8295 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
8296 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
8297 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
8298 */
8299 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8300 if (pCtx->sp == 1)
8301 return VINF_EM_RESET;
8302 pCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
8303 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), pCtx->ss.u64Base + pCtx->sp, &uValue, sizeof(uint16_t));
8304 AssertRC(rc);
8305 return rc;
8306}
8307
8308
8309/**
8310 * Injects an event into the guest upon VM-entry by updating the relevant fields
8311 * in the VM-entry area in the VMCS.
8312 *
8313 * @returns Strict VBox status code (i.e. informational status codes too).
8314 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
8315 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
8316 *
8317 * @param pVCpu The cross context virtual CPU structure.
8318 * @param pVmxTransient The VMX-transient structure.
8319 * @param pEvent The event being injected.
8320 * @param pfIntrState Pointer to the VT-x guest-interruptibility-state. This
8321 * will be updated if necessary. This cannot not be NULL.
8322 * @param fStepping Whether we're single-stepping guest execution and should
8323 * return VINF_EM_DBG_STEPPED if the event is injected
8324 * directly (registers modified by us, not by hardware on
8325 * VM-entry).
8326 */
8327static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PCHMEVENT pEvent, bool fStepping,
8328 uint32_t *pfIntrState)
8329{
8330 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
8331 AssertMsg(!RT_HI_U32(pEvent->u64IntInfo), ("%#RX64\n", pEvent->u64IntInfo));
8332 Assert(pfIntrState);
8333
8334 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8335 uint32_t u32IntInfo = pEvent->u64IntInfo;
8336 uint32_t const u32ErrCode = pEvent->u32ErrCode;
8337 uint32_t const cbInstr = pEvent->cbInstr;
8338 RTGCUINTPTR const GCPtrFault = pEvent->GCPtrFaultAddress;
8339 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(u32IntInfo);
8340 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(u32IntInfo);
8341
8342#ifdef VBOX_STRICT
8343 /*
8344 * Validate the error-code-valid bit for hardware exceptions.
8345 * No error codes for exceptions in real-mode.
8346 *
8347 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8348 */
8349 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8350 && !CPUMIsGuestInRealModeEx(pCtx))
8351 {
8352 switch (uVector)
8353 {
8354 case X86_XCPT_PF:
8355 case X86_XCPT_DF:
8356 case X86_XCPT_TS:
8357 case X86_XCPT_NP:
8358 case X86_XCPT_SS:
8359 case X86_XCPT_GP:
8360 case X86_XCPT_AC:
8361 AssertMsg(VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo),
8362 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
8363 RT_FALL_THRU();
8364 default:
8365 break;
8366 }
8367 }
8368
8369 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
8370 Assert( uIntType != VMX_EXIT_INT_INFO_TYPE_NMI
8371 || !(*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
8372#endif
8373
8374 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
8375
8376 /*
8377 * Hardware interrupts & exceptions cannot be delivered through the software interrupt
8378 * redirection bitmap to the real mode task in virtual-8086 mode. We must jump to the
8379 * interrupt handler in the (real-mode) guest.
8380 *
8381 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode".
8382 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
8383 */
8384 if (CPUMIsGuestInRealModeEx(pCtx)) /* CR0.PE bit changes are always intercepted, so it's up to date. */
8385 {
8386 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest)
8387 {
8388 /*
8389 * For CPUs with unrestricted guest execution enabled and with the guest
8390 * in real-mode, we must not set the deliver-error-code bit.
8391 *
8392 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8393 */
8394 u32IntInfo &= ~VMX_ENTRY_INT_INFO_ERROR_CODE_VALID;
8395 }
8396 else
8397 {
8398 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8399 Assert(PDMVmmDevHeapIsEnabled(pVM));
8400 Assert(pVM->hm.s.vmx.pRealModeTSS);
8401 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
8402
8403 /* We require RIP, RSP, RFLAGS, CS, IDTR, import them. */
8404 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8405 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TABLE_MASK
8406 | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS);
8407 AssertRCReturn(rc2, rc2);
8408
8409 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8410 size_t const cbIdtEntry = sizeof(X86IDTR16);
8411 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pCtx->idtr.cbIdt)
8412 {
8413 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8414 if (uVector == X86_XCPT_DF)
8415 return VINF_EM_RESET;
8416
8417 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault.
8418 No error codes for exceptions in real-mode. */
8419 if (uVector == X86_XCPT_GP)
8420 {
8421 uint32_t const uXcptDfInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
8422 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8423 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8424 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8425 HMEVENT EventXcptDf;
8426 RT_ZERO(EventXcptDf);
8427 EventXcptDf.u64IntInfo = uXcptDfInfo;
8428 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptDf, fStepping, pfIntrState);
8429 }
8430
8431 /*
8432 * If we're injecting an event with no valid IDT entry, inject a #GP.
8433 * No error codes for exceptions in real-mode.
8434 *
8435 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8436 */
8437 uint32_t const uXcptGpInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
8438 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8439 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8440 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8441 HMEVENT EventXcptGp;
8442 RT_ZERO(EventXcptGp);
8443 EventXcptGp.u64IntInfo = uXcptGpInfo;
8444 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptGp, fStepping, pfIntrState);
8445 }
8446
8447 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8448 uint16_t uGuestIp = pCtx->ip;
8449 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT)
8450 {
8451 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8452 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8453 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8454 }
8455 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_INT)
8456 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8457
8458 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8459 X86IDTR16 IdtEntry;
8460 RTGCPHYS const GCPhysIdtEntry = (RTGCPHYS)pCtx->idtr.pIdt + uVector * cbIdtEntry;
8461 rc2 = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8462 AssertRCReturn(rc2, rc2);
8463
8464 /* Construct the stack frame for the interrupt/exception handler. */
8465 VBOXSTRICTRC rcStrict;
8466 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->eflags.u32);
8467 if (rcStrict == VINF_SUCCESS)
8468 {
8469 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->cs.Sel);
8470 if (rcStrict == VINF_SUCCESS)
8471 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, uGuestIp);
8472 }
8473
8474 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8475 if (rcStrict == VINF_SUCCESS)
8476 {
8477 pCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8478 pCtx->rip = IdtEntry.offSel;
8479 pCtx->cs.Sel = IdtEntry.uSel;
8480 pCtx->cs.ValidSel = IdtEntry.uSel;
8481 pCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8482 if ( uIntType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
8483 && uVector == X86_XCPT_PF)
8484 pCtx->cr2 = GCPtrFault;
8485
8486 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CS | HM_CHANGED_GUEST_CR2
8487 | HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
8488 | HM_CHANGED_GUEST_RSP);
8489
8490 /*
8491 * If we delivered a hardware exception (other than an NMI) and if there was
8492 * block-by-STI in effect, we should clear it.
8493 */
8494 if (*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
8495 {
8496 Assert( uIntType != VMX_ENTRY_INT_INFO_TYPE_NMI
8497 && uIntType != VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
8498 Log4Func(("Clearing inhibition due to STI\n"));
8499 *pfIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
8500 }
8501
8502 Log4(("Injected real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8503 u32IntInfo, u32ErrCode, cbInstr, pCtx->eflags.u, pCtx->cs.Sel, pCtx->eip));
8504
8505 /*
8506 * The event has been truly dispatched to the guest. Mark it as no longer pending so
8507 * we don't attempt to undo it if we are returning to ring-3 before executing guest code.
8508 */
8509 pVCpu->hm.s.Event.fPending = false;
8510
8511 /*
8512 * If we eventually support nested-guest execution without unrestricted guest execution,
8513 * we should set fInterceptEvents here.
8514 */
8515 Assert(!pVmxTransient->fIsNestedGuest);
8516
8517 /* If we're stepping and we've changed cs:rip above, bail out of the VMX R0 execution loop. */
8518 if (fStepping)
8519 rcStrict = VINF_EM_DBG_STEPPED;
8520 }
8521 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8522 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8523 return rcStrict;
8524 }
8525 }
8526
8527 /*
8528 * Validate.
8529 */
8530 Assert(VMX_ENTRY_INT_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
8531 Assert(!(u32IntInfo & VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK)); /* Bits 30:12 MBZ. */
8532
8533 /*
8534 * Inject the event into the VMCS.
8535 */
8536 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8537 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8538 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8539 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8540 AssertRC(rc);
8541
8542 /*
8543 * Update guest CR2 if this is a page-fault.
8544 */
8545 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
8546 pCtx->cr2 = GCPtrFault;
8547
8548 Log4(("Injecting u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x CR2=%#RX64\n", u32IntInfo, u32ErrCode, cbInstr, pCtx->cr2));
8549 return VINF_SUCCESS;
8550}
8551
8552
8553/**
8554 * Evaluates the event to be delivered to the guest and sets it as the pending
8555 * event.
8556 *
8557 * Toggling of interrupt force-flags here is safe since we update TRPM on premature
8558 * exits to ring-3 before executing guest code, see hmR0VmxExitToRing3(). We must
8559 * NOT restore these force-flags.
8560 *
8561 * @returns Strict VBox status code (i.e. informational status codes too).
8562 * @param pVCpu The cross context virtual CPU structure.
8563 * @param pVmxTransient The VMX-transient structure.
8564 * @param pfIntrState Where to store the VT-x guest-interruptibility state.
8565 */
8566static VBOXSTRICTRC hmR0VmxEvaluatePendingEvent(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t *pfIntrState)
8567{
8568 Assert(pfIntrState);
8569 Assert(!TRPMHasTrap(pVCpu));
8570
8571 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8572 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8573 bool const fIsNestedGuest = pVmxTransient->fIsNestedGuest;
8574
8575 /*
8576 * Compute/update guest-interruptibility state related FFs.
8577 */
8578 /** @todo r=ramshankar: Move this outside this function to the caller. */
8579 {
8580 /* Get the current interruptibility-state of the guest or nested-guest (this updates FFs). */
8581 uint32_t const fIntrState = hmR0VmxGetGuestIntrState(pVCpu);
8582
8583#ifdef VBOX_STRICT
8584 /* Validate. */
8585 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
8586 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
8587 {
8588 /* Block-by-STI must not be set when interrupts are disabled. */
8589 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
8590 Assert(pCtx->eflags.Bits.u1IF);
8591 }
8592#endif
8593
8594 /* Update interruptibility state to the caller. */
8595 *pfIntrState = fIntrState;
8596 }
8597
8598 /*
8599 * Evaluate if a new event needs to be injected.
8600 * An event that's already pending has already performed all necessary checks.
8601 */
8602 if ( !pVCpu->hm.s.Event.fPending
8603 && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
8604 {
8605 /** @todo SMI. SMIs take priority over NMIs. */
8606
8607 /*
8608 * NMIs.
8609 * NMIs take priority over external interrupts.
8610 */
8611 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
8612 {
8613 /*
8614 * For a guest, the FF always indicates the guest's ability to receive an NMI.
8615 *
8616 * For a nested-guest, the FF always indicates the outer guest's ability to
8617 * receive an NMI while the guest-interruptibility state bit depends on whether
8618 * the nested-hypervisor is using virtual-NMIs.
8619 */
8620 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
8621 {
8622#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8623 if ( fIsNestedGuest
8624 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_NMI_EXIT))
8625 return IEMExecVmxVmexitXcptNmi(pVCpu);
8626#endif
8627 hmR0VmxSetPendingXcptNmi(pVCpu);
8628 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
8629 Log4Func(("NMI pending injection\n"));
8630
8631 /* We've injected the NMI, bail. */
8632 return VINF_SUCCESS;
8633 }
8634 else if (!fIsNestedGuest)
8635 hmR0VmxSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
8636 }
8637
8638 /*
8639 * External interrupts (PIC/APIC).
8640 * Once PDMGetInterrupt() returns a valid interrupt we -must- deliver it.
8641 * We cannot re-request the interrupt from the controller again.
8642 */
8643 if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
8644 && !pVCpu->hm.s.fSingleInstruction)
8645 {
8646 Assert(!DBGFIsStepping(pVCpu));
8647 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
8648 AssertRC(rc);
8649
8650 if (pCtx->eflags.u32 & X86_EFL_IF)
8651 {
8652#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8653 if ( fIsNestedGuest
8654 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
8655 && !CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
8656 {
8657 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
8658 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8659 return rcStrict;
8660 }
8661#endif
8662 uint8_t u8Interrupt;
8663 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
8664 if (RT_SUCCESS(rc))
8665 {
8666#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8667 if ( fIsNestedGuest
8668 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
8669 && CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
8670 {
8671 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, u8Interrupt, false /* fIntPending */);
8672 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8673 return rcStrict;
8674 }
8675#endif
8676 hmR0VmxSetPendingExtInt(pVCpu, u8Interrupt);
8677 Log4Func(("External interrupt (%#x) pending injection\n", u8Interrupt));
8678 }
8679 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
8680 {
8681 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
8682
8683 if ( !fIsNestedGuest
8684 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
8685 hmR0VmxApicSetTprThreshold(pVmcsInfo, u8Interrupt >> 4);
8686 /* else: for nested-guests, TPR threshold is picked up while merging VMCS controls. */
8687
8688 /*
8689 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
8690 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
8691 * need to re-set this force-flag here.
8692 */
8693 }
8694 else
8695 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
8696
8697 /* We've injected the interrupt or taken necessary action, bail. */
8698 return VINF_SUCCESS;
8699 }
8700 else if (!fIsNestedGuest)
8701 hmR0VmxSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
8702 }
8703 }
8704 else if (!fIsNestedGuest)
8705 {
8706 /*
8707 * An event is being injected or we are in an interrupt shadow. Check if another event is
8708 * pending. If so, instruct VT-x to cause a VM-exit as soon as the guest is ready to accept
8709 * the pending event.
8710 */
8711 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
8712 hmR0VmxSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
8713 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
8714 && !pVCpu->hm.s.fSingleInstruction)
8715 hmR0VmxSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
8716 }
8717 /* else: for nested-guests, NMI/interrupt-window exiting will be picked up when merging VMCS controls. */
8718
8719 return VINF_SUCCESS;
8720}
8721
8722
8723/**
8724 * Injects any pending events into the guest if the guest is in a state to
8725 * receive them.
8726 *
8727 * @returns Strict VBox status code (i.e. informational status codes too).
8728 * @param pVCpu The cross context virtual CPU structure.
8729 * @param pVmxTransient The VMX-transient structure.
8730 * @param fIntrState The VT-x guest-interruptibility state.
8731 * @param fStepping Whether we are single-stepping the guest using the
8732 * hypervisor debugger and should return
8733 * VINF_EM_DBG_STEPPED if the event was dispatched
8734 * directly.
8735 */
8736static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t fIntrState, bool fStepping)
8737{
8738 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8739 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8740
8741#ifdef VBOX_STRICT
8742 /*
8743 * Verify guest-interruptibility state.
8744 *
8745 * We put this in a scoped block so we do not accidentally use fBlockSti or fBlockMovSS,
8746 * since injecting an event may modify the interruptibility state and we must thus always
8747 * use fIntrState.
8748 */
8749 {
8750 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
8751 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
8752 Assert(!fBlockSti || !(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_RFLAGS));
8753 Assert(!fBlockSti || pVCpu->cpum.GstCtx.eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
8754 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
8755 Assert(!TRPMHasTrap(pVCpu));
8756 NOREF(fBlockMovSS); NOREF(fBlockSti);
8757 }
8758#endif
8759
8760 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
8761 if (pVCpu->hm.s.Event.fPending)
8762 {
8763 /*
8764 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
8765 * pending even while injecting an event and in this case, we want a VM-exit as soon as
8766 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
8767 *
8768 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
8769 */
8770 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
8771#ifdef VBOX_STRICT
8772 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
8773 {
8774 Assert(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_IF);
8775 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI));
8776 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
8777 }
8778 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_NMI)
8779 {
8780 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI));
8781 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI));
8782 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
8783 }
8784#endif
8785 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
8786 uIntType));
8787
8788 /*
8789 * Inject the event and get any changes to the guest-interruptibility state.
8790 *
8791 * The guest-interruptibility state may need to be updated if we inject the event
8792 * into the guest IDT ourselves (for real-on-v86 guest injecting software interrupts).
8793 */
8794 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &pVCpu->hm.s.Event, fStepping, &fIntrState);
8795 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
8796
8797 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
8798 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
8799 else
8800 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
8801 }
8802
8803 /*
8804 * Deliver any pending debug exceptions if the guest is single-stepping using EFLAGS.TF and
8805 * is an interrupt shadow (block-by-STI or block-by-MOV SS).
8806 */
8807 if ( (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
8808 && !pVmxTransient->fIsNestedGuest)
8809 {
8810 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
8811
8812 if (!pVCpu->hm.s.fSingleInstruction)
8813 {
8814 /*
8815 * Set or clear the BS bit depending on whether the trap flag is active or not. We need
8816 * to do both since we clear the BS bit from the VMCS while exiting to ring-3.
8817 */
8818 Assert(!DBGFIsStepping(pVCpu));
8819 uint8_t const fTrapFlag = !!(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_TF);
8820 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, fTrapFlag << VMX_BF_VMCS_PENDING_DBG_XCPT_BS_SHIFT);
8821 AssertRC(rc);
8822 }
8823 else
8824 {
8825 /*
8826 * We must not deliver a debug exception when single-stepping over STI/Mov-SS in the
8827 * hypervisor debugger using EFLAGS.TF but rather clear interrupt inhibition. However,
8828 * we take care of this case in hmR0VmxExportSharedDebugState and also the case if
8829 * we use MTF, so just make sure it's called before executing guest-code.
8830 */
8831 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR_MASK);
8832 }
8833 }
8834 /* else: for nested-guest currently handling while merging controls. */
8835
8836 /*
8837 * Finally, update the guest-interruptibility state.
8838 *
8839 * This is required for the real-on-v86 software interrupt injection, for
8840 * pending debug exceptions as well as updates to the guest state from ring-3 (IEM).
8841 */
8842 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
8843 AssertRC(rc);
8844
8845 /*
8846 * There's no need to clear the VM-entry interruption-information field here if we're not
8847 * injecting anything. VT-x clears the valid bit on every VM-exit.
8848 *
8849 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
8850 */
8851
8852 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
8853 return rcStrict;
8854}
8855
8856
8857/**
8858 * Enters the VT-x session.
8859 *
8860 * @returns VBox status code.
8861 * @param pVCpu The cross context virtual CPU structure.
8862 */
8863VMMR0DECL(int) VMXR0Enter(PVMCPUCC pVCpu)
8864{
8865 AssertPtr(pVCpu);
8866 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported);
8867 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8868
8869 LogFlowFunc(("pVCpu=%p\n", pVCpu));
8870 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
8871 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
8872
8873#ifdef VBOX_STRICT
8874 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
8875 RTCCUINTREG uHostCr4 = ASMGetCR4();
8876 if (!(uHostCr4 & X86_CR4_VMXE))
8877 {
8878 LogRelFunc(("X86_CR4_VMXE bit in CR4 is not set!\n"));
8879 return VERR_VMX_X86_CR4_VMXE_CLEARED;
8880 }
8881#endif
8882
8883 /*
8884 * Load the appropriate VMCS as the current and active one.
8885 */
8886 PVMXVMCSINFO pVmcsInfo;
8887 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx);
8888 if (!fInNestedGuestMode)
8889 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfo;
8890 else
8891 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
8892 int rc = hmR0VmxLoadVmcs(pVmcsInfo);
8893 if (RT_SUCCESS(rc))
8894 {
8895 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs = fInNestedGuestMode;
8896 pVCpu->hm.s.fLeaveDone = false;
8897 Log4Func(("Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8898
8899 /*
8900 * Do the EMT scheduled L1D flush here if needed.
8901 */
8902 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
8903 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
8904 else if (pVCpu->CTX_SUFF(pVM)->hm.s.fMdsClearOnSched)
8905 hmR0MdsClear();
8906 }
8907 return rc;
8908}
8909
8910
8911/**
8912 * The thread-context callback (only on platforms which support it).
8913 *
8914 * @param enmEvent The thread-context event.
8915 * @param pVCpu The cross context virtual CPU structure.
8916 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
8917 * @thread EMT(pVCpu)
8918 */
8919VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPUCC pVCpu, bool fGlobalInit)
8920{
8921 AssertPtr(pVCpu);
8922 RT_NOREF1(fGlobalInit);
8923
8924 switch (enmEvent)
8925 {
8926 case RTTHREADCTXEVENT_OUT:
8927 {
8928 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8929 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8930 VMCPU_ASSERT_EMT(pVCpu);
8931
8932 /* No longjmps (logger flushes, locks) in this fragile context. */
8933 VMMRZCallRing3Disable(pVCpu);
8934 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
8935
8936 /* Restore host-state (FPU, debug etc.) */
8937 if (!pVCpu->hm.s.fLeaveDone)
8938 {
8939 /*
8940 * Do -not- import the guest-state here as we might already be in the middle of importing
8941 * it, esp. bad if we're holding the PGM lock, see comment in hmR0VmxImportGuestState().
8942 */
8943 hmR0VmxLeave(pVCpu, false /* fImportState */);
8944 pVCpu->hm.s.fLeaveDone = true;
8945 }
8946
8947 /* Leave HM context, takes care of local init (term). */
8948 int rc = HMR0LeaveCpu(pVCpu);
8949 AssertRC(rc);
8950
8951 /* Restore longjmp state. */
8952 VMMRZCallRing3Enable(pVCpu);
8953 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
8954 break;
8955 }
8956
8957 case RTTHREADCTXEVENT_IN:
8958 {
8959 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8960 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8961 VMCPU_ASSERT_EMT(pVCpu);
8962
8963 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
8964 VMMRZCallRing3Disable(pVCpu);
8965 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
8966
8967 /* Initialize the bare minimum state required for HM. This takes care of
8968 initializing VT-x if necessary (onlined CPUs, local init etc.) */
8969 int rc = hmR0EnterCpu(pVCpu);
8970 AssertRC(rc);
8971 Assert( (pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
8972 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
8973
8974 /* Load the active VMCS as the current one. */
8975 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8976 rc = hmR0VmxLoadVmcs(pVmcsInfo);
8977 AssertRC(rc);
8978 Log4Func(("Resumed: Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8979 pVCpu->hm.s.fLeaveDone = false;
8980
8981 /* Do the EMT scheduled L1D flush if needed. */
8982 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
8983 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
8984
8985 /* Restore longjmp state. */
8986 VMMRZCallRing3Enable(pVCpu);
8987 break;
8988 }
8989
8990 default:
8991 break;
8992 }
8993}
8994
8995
8996/**
8997 * Exports the host state into the VMCS host-state area.
8998 * Sets up the VM-exit MSR-load area.
8999 *
9000 * The CPU state will be loaded from these fields on every successful VM-exit.
9001 *
9002 * @returns VBox status code.
9003 * @param pVCpu The cross context virtual CPU structure.
9004 *
9005 * @remarks No-long-jump zone!!!
9006 */
9007static int hmR0VmxExportHostState(PVMCPUCC pVCpu)
9008{
9009 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9010
9011 int rc = VINF_SUCCESS;
9012 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
9013 {
9014 hmR0VmxExportHostControlRegs();
9015
9016 rc = hmR0VmxExportHostSegmentRegs(pVCpu);
9017 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9018
9019 hmR0VmxExportHostMsrs(pVCpu);
9020
9021 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_HOST_CONTEXT;
9022 }
9023 return rc;
9024}
9025
9026
9027/**
9028 * Saves the host state in the VMCS host-state.
9029 *
9030 * @returns VBox status code.
9031 * @param pVCpu The cross context virtual CPU structure.
9032 *
9033 * @remarks No-long-jump zone!!!
9034 */
9035VMMR0DECL(int) VMXR0ExportHostState(PVMCPUCC pVCpu)
9036{
9037 AssertPtr(pVCpu);
9038 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9039
9040 /*
9041 * Export the host state here while entering HM context.
9042 * When thread-context hooks are used, we might get preempted and have to re-save the host
9043 * state but most of the time we won't be, so do it here before we disable interrupts.
9044 */
9045 return hmR0VmxExportHostState(pVCpu);
9046}
9047
9048
9049/**
9050 * Exports the guest state into the VMCS guest-state area.
9051 *
9052 * The will typically be done before VM-entry when the guest-CPU state and the
9053 * VMCS state may potentially be out of sync.
9054 *
9055 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
9056 * VM-entry controls.
9057 * Sets up the appropriate VMX non-root function to execute guest code based on
9058 * the guest CPU mode.
9059 *
9060 * @returns VBox strict status code.
9061 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9062 * without unrestricted guest execution and the VMMDev is not presently
9063 * mapped (e.g. EFI32).
9064 *
9065 * @param pVCpu The cross context virtual CPU structure.
9066 * @param pVmxTransient The VMX-transient structure.
9067 *
9068 * @remarks No-long-jump zone!!!
9069 */
9070static VBOXSTRICTRC hmR0VmxExportGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9071{
9072 AssertPtr(pVCpu);
9073 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9074 LogFlowFunc(("pVCpu=%p\n", pVCpu));
9075
9076 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExportGuestState, x);
9077
9078 /*
9079 * Determine real-on-v86 mode.
9080 * Used when the guest is in real-mode and unrestricted guest execution is not used.
9081 */
9082 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
9083 if ( pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest
9084 || !CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx))
9085 pVmcsInfo->RealMode.fRealOnV86Active = false;
9086 else
9087 {
9088 Assert(!pVmxTransient->fIsNestedGuest);
9089 pVmcsInfo->RealMode.fRealOnV86Active = true;
9090 }
9091
9092 /*
9093 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
9094 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
9095 */
9096 int rc = hmR0VmxExportGuestEntryExitCtls(pVCpu, pVmxTransient);
9097 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9098
9099 rc = hmR0VmxExportGuestCR0(pVCpu, pVmxTransient);
9100 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9101
9102 VBOXSTRICTRC rcStrict = hmR0VmxExportGuestCR3AndCR4(pVCpu, pVmxTransient);
9103 if (rcStrict == VINF_SUCCESS)
9104 { /* likely */ }
9105 else
9106 {
9107 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
9108 return rcStrict;
9109 }
9110
9111 rc = hmR0VmxExportGuestSegRegsXdtr(pVCpu, pVmxTransient);
9112 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9113
9114 rc = hmR0VmxExportGuestMsrs(pVCpu, pVmxTransient);
9115 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9116
9117 hmR0VmxExportGuestApicTpr(pVCpu, pVmxTransient);
9118 hmR0VmxExportGuestXcptIntercepts(pVCpu, pVmxTransient);
9119 hmR0VmxExportGuestRip(pVCpu);
9120 hmR0VmxExportGuestRsp(pVCpu);
9121 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9122
9123 rc = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9124 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9125
9126 /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
9127 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~( (HM_CHANGED_GUEST_GPRS_MASK & ~HM_CHANGED_GUEST_RSP)
9128 | HM_CHANGED_GUEST_CR2
9129 | (HM_CHANGED_GUEST_DR_MASK & ~HM_CHANGED_GUEST_DR7)
9130 | HM_CHANGED_GUEST_X87
9131 | HM_CHANGED_GUEST_SSE_AVX
9132 | HM_CHANGED_GUEST_OTHER_XSAVE
9133 | HM_CHANGED_GUEST_XCRx
9134 | HM_CHANGED_GUEST_KERNEL_GS_BASE /* Part of lazy or auto load-store MSRs. */
9135 | HM_CHANGED_GUEST_SYSCALL_MSRS /* Part of lazy or auto load-store MSRs. */
9136 | HM_CHANGED_GUEST_TSC_AUX
9137 | HM_CHANGED_GUEST_OTHER_MSRS
9138 | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
9139
9140 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExportGuestState, x);
9141 return rc;
9142}
9143
9144
9145/**
9146 * Exports the state shared between the host and guest into the VMCS.
9147 *
9148 * @param pVCpu The cross context virtual CPU structure.
9149 * @param pVmxTransient The VMX-transient structure.
9150 *
9151 * @remarks No-long-jump zone!!!
9152 */
9153static void hmR0VmxExportSharedState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9154{
9155 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9156 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9157
9158 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_DR_MASK)
9159 {
9160 int rc = hmR0VmxExportSharedDebugState(pVCpu, pVmxTransient);
9161 AssertRC(rc);
9162 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_GUEST_DR_MASK;
9163
9164 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
9165 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_RFLAGS)
9166 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9167 }
9168
9169 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_GUEST_LAZY_MSRS)
9170 {
9171 hmR0VmxLazyLoadGuestMsrs(pVCpu);
9172 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_VMX_GUEST_LAZY_MSRS;
9173 }
9174
9175 AssertMsg(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE),
9176 ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
9177}
9178
9179
9180/**
9181 * Worker for loading the guest-state bits in the inner VT-x execution loop.
9182 *
9183 * @returns Strict VBox status code (i.e. informational status codes too).
9184 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9185 * without unrestricted guest execution and the VMMDev is not presently
9186 * mapped (e.g. EFI32).
9187 *
9188 * @param pVCpu The cross context virtual CPU structure.
9189 * @param pVmxTransient The VMX-transient structure.
9190 *
9191 * @remarks No-long-jump zone!!!
9192 */
9193static VBOXSTRICTRC hmR0VmxExportGuestStateOptimal(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9194{
9195 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9196 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9197 Assert(VMMR0IsLogFlushDisabled(pVCpu));
9198
9199#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
9200 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
9201#endif
9202
9203 /*
9204 * For many VM-exits only RIP/RSP/RFLAGS (and HWVIRT state when executing a nested-guest)
9205 * changes. First try to export only these without going through all other changed-flag checks.
9206 */
9207 VBOXSTRICTRC rcStrict;
9208 uint64_t const fCtxMask = HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE;
9209 uint64_t const fMinimalMask = HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT;
9210 uint64_t const fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9211
9212 /* If only RIP/RSP/RFLAGS/HWVIRT changed, export only those (quicker, happens more often).*/
9213 if ( (fCtxChanged & fMinimalMask)
9214 && !(fCtxChanged & (fCtxMask & ~fMinimalMask)))
9215 {
9216 hmR0VmxExportGuestRip(pVCpu);
9217 hmR0VmxExportGuestRsp(pVCpu);
9218 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9219 rcStrict = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9220 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportMinimal);
9221 }
9222 /* If anything else also changed, go through the full export routine and export as required. */
9223 else if (fCtxChanged & fCtxMask)
9224 {
9225 rcStrict = hmR0VmxExportGuestState(pVCpu, pVmxTransient);
9226 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9227 { /* likely */}
9228 else
9229 {
9230 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM, ("Failed to export guest state! rc=%Rrc\n",
9231 VBOXSTRICTRC_VAL(rcStrict)));
9232 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9233 return rcStrict;
9234 }
9235 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportFull);
9236 }
9237 /* Nothing changed, nothing to load here. */
9238 else
9239 rcStrict = VINF_SUCCESS;
9240
9241#ifdef VBOX_STRICT
9242 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
9243 uint64_t const fCtxChangedCur = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9244 AssertMsg(!(fCtxChangedCur & fCtxMask), ("fCtxChangedCur=%#RX64\n", fCtxChangedCur));
9245#endif
9246 return rcStrict;
9247}
9248
9249
9250/**
9251 * Tries to determine what part of the guest-state VT-x has deemed as invalid
9252 * and update error record fields accordingly.
9253 *
9254 * @returns VMX_IGS_* error codes.
9255 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
9256 * wrong with the guest state.
9257 *
9258 * @param pVCpu The cross context virtual CPU structure.
9259 * @param pVmcsInfo The VMCS info. object.
9260 *
9261 * @remarks This function assumes our cache of the VMCS controls
9262 * are valid, i.e. hmR0VmxCheckCachedVmcsCtls() succeeded.
9263 */
9264static uint32_t hmR0VmxCheckGuestState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
9265{
9266#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
9267#define HMVMX_CHECK_BREAK(expr, err) do { \
9268 if (!(expr)) { uError = (err); break; } \
9269 } while (0)
9270
9271 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9272 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9273 uint32_t uError = VMX_IGS_ERROR;
9274 uint32_t u32IntrState = 0;
9275 bool const fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuest;
9276 do
9277 {
9278 int rc;
9279
9280 /*
9281 * Guest-interruptibility state.
9282 *
9283 * Read this first so that any check that fails prior to those that actually
9284 * require the guest-interruptibility state would still reflect the correct
9285 * VMCS value and avoids causing further confusion.
9286 */
9287 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32IntrState);
9288 AssertRC(rc);
9289
9290 uint32_t u32Val;
9291 uint64_t u64Val;
9292
9293 /*
9294 * CR0.
9295 */
9296 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9297 uint64_t fSetCr0 = (pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
9298 uint64_t const fZapCr0 = (pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
9299 /* Exceptions for unrestricted guest execution for CR0 fixed bits (PE, PG).
9300 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
9301 if (fUnrestrictedGuest)
9302 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
9303
9304 uint64_t u64GuestCr0;
9305 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64GuestCr0);
9306 AssertRC(rc);
9307 HMVMX_CHECK_BREAK((u64GuestCr0 & fSetCr0) == fSetCr0, VMX_IGS_CR0_FIXED1);
9308 HMVMX_CHECK_BREAK(!(u64GuestCr0 & ~fZapCr0), VMX_IGS_CR0_FIXED0);
9309 if ( !fUnrestrictedGuest
9310 && (u64GuestCr0 & X86_CR0_PG)
9311 && !(u64GuestCr0 & X86_CR0_PE))
9312 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
9313
9314 /*
9315 * CR4.
9316 */
9317 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9318 uint64_t const fSetCr4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
9319 uint64_t const fZapCr4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
9320
9321 uint64_t u64GuestCr4;
9322 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64GuestCr4);
9323 AssertRC(rc);
9324 HMVMX_CHECK_BREAK((u64GuestCr4 & fSetCr4) == fSetCr4, VMX_IGS_CR4_FIXED1);
9325 HMVMX_CHECK_BREAK(!(u64GuestCr4 & ~fZapCr4), VMX_IGS_CR4_FIXED0);
9326
9327 /*
9328 * IA32_DEBUGCTL MSR.
9329 */
9330 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
9331 AssertRC(rc);
9332 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9333 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
9334 {
9335 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
9336 }
9337 uint64_t u64DebugCtlMsr = u64Val;
9338
9339#ifdef VBOX_STRICT
9340 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
9341 AssertRC(rc);
9342 Assert(u32Val == pVmcsInfo->u32EntryCtls);
9343#endif
9344 bool const fLongModeGuest = RT_BOOL(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
9345
9346 /*
9347 * RIP and RFLAGS.
9348 */
9349 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
9350 AssertRC(rc);
9351 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
9352 if ( !fLongModeGuest
9353 || !pCtx->cs.Attr.n.u1Long)
9354 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
9355 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
9356 * must be identical if the "IA-32e mode guest" VM-entry
9357 * control is 1 and CS.L is 1. No check applies if the
9358 * CPU supports 64 linear-address bits. */
9359
9360 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
9361 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
9362 AssertRC(rc);
9363 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
9364 VMX_IGS_RFLAGS_RESERVED);
9365 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
9366 uint32_t const u32Eflags = u64Val;
9367
9368 if ( fLongModeGuest
9369 || ( fUnrestrictedGuest
9370 && !(u64GuestCr0 & X86_CR0_PE)))
9371 {
9372 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
9373 }
9374
9375 uint32_t u32EntryInfo;
9376 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
9377 AssertRC(rc);
9378 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9379 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
9380
9381 /*
9382 * 64-bit checks.
9383 */
9384 if (fLongModeGuest)
9385 {
9386 HMVMX_CHECK_BREAK(u64GuestCr0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
9387 HMVMX_CHECK_BREAK(u64GuestCr4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
9388 }
9389
9390 if ( !fLongModeGuest
9391 && (u64GuestCr4 & X86_CR4_PCIDE))
9392 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
9393
9394 /** @todo CR3 field must be such that bits 63:52 and bits in the range
9395 * 51:32 beyond the processor's physical-address width are 0. */
9396
9397 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9398 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
9399 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
9400
9401 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
9402 AssertRC(rc);
9403 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
9404
9405 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
9406 AssertRC(rc);
9407 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
9408
9409 /*
9410 * PERF_GLOBAL MSR.
9411 */
9412 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR)
9413 {
9414 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
9415 AssertRC(rc);
9416 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
9417 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
9418 }
9419
9420 /*
9421 * PAT MSR.
9422 */
9423 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
9424 {
9425 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
9426 AssertRC(rc);
9427 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
9428 for (unsigned i = 0; i < 8; i++)
9429 {
9430 uint8_t u8Val = (u64Val & 0xff);
9431 if ( u8Val != 0 /* UC */
9432 && u8Val != 1 /* WC */
9433 && u8Val != 4 /* WT */
9434 && u8Val != 5 /* WP */
9435 && u8Val != 6 /* WB */
9436 && u8Val != 7 /* UC- */)
9437 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
9438 u64Val >>= 8;
9439 }
9440 }
9441
9442 /*
9443 * EFER MSR.
9444 */
9445 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
9446 {
9447 Assert(pVM->hm.s.vmx.fSupportsVmcsEfer);
9448 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
9449 AssertRC(rc);
9450 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
9451 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
9452 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVmcsInfo->u32EntryCtls
9453 & VMX_ENTRY_CTLS_IA32E_MODE_GUEST),
9454 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
9455 /** @todo r=ramshankar: Unrestricted check here is probably wrong, see
9456 * iemVmxVmentryCheckGuestState(). */
9457 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9458 || !(u64GuestCr0 & X86_CR0_PG)
9459 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
9460 VMX_IGS_EFER_LMA_LME_MISMATCH);
9461 }
9462
9463 /*
9464 * Segment registers.
9465 */
9466 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9467 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
9468 if (!(u32Eflags & X86_EFL_VM))
9469 {
9470 /* CS */
9471 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
9472 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
9473 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
9474 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
9475 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9476 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
9477 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9478 /* CS cannot be loaded with NULL in protected mode. */
9479 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
9480 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
9481 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
9482 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
9483 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
9484 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
9485 else if (pVM->hm.s.vmx.fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
9486 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
9487 else
9488 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
9489
9490 /* SS */
9491 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9492 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
9493 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
9494 if ( !(pCtx->cr0 & X86_CR0_PE)
9495 || pCtx->cs.Attr.n.u4Type == 3)
9496 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
9497
9498 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
9499 {
9500 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
9501 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
9502 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
9503 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
9504 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
9505 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9506 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
9507 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9508 }
9509
9510 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSReg(). */
9511 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
9512 {
9513 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
9514 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
9515 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9516 || pCtx->ds.Attr.n.u4Type > 11
9517 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9518 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
9519 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
9520 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
9521 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9522 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
9523 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9524 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9525 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
9526 }
9527 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
9528 {
9529 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
9530 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
9531 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9532 || pCtx->es.Attr.n.u4Type > 11
9533 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9534 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
9535 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
9536 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
9537 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9538 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
9539 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9540 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9541 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
9542 }
9543 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
9544 {
9545 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
9546 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
9547 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9548 || pCtx->fs.Attr.n.u4Type > 11
9549 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
9550 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
9551 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
9552 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
9553 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9554 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
9555 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9556 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9557 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
9558 }
9559 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
9560 {
9561 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
9562 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
9563 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9564 || pCtx->gs.Attr.n.u4Type > 11
9565 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
9566 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
9567 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
9568 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
9569 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9570 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
9571 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9572 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9573 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
9574 }
9575 /* 64-bit capable CPUs. */
9576 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9577 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9578 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9579 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9580 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9581 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9582 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9583 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9584 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9585 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9586 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9587 }
9588 else
9589 {
9590 /* V86 mode checks. */
9591 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
9592 if (pVmcsInfo->RealMode.fRealOnV86Active)
9593 {
9594 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
9595 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
9596 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
9597 }
9598 else
9599 {
9600 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
9601 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
9602 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
9603 }
9604
9605 /* CS */
9606 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
9607 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
9608 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
9609 /* SS */
9610 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
9611 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
9612 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
9613 /* DS */
9614 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
9615 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
9616 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
9617 /* ES */
9618 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
9619 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
9620 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
9621 /* FS */
9622 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
9623 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
9624 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
9625 /* GS */
9626 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
9627 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
9628 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
9629 /* 64-bit capable CPUs. */
9630 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9631 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9632 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9633 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9634 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9635 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9636 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9637 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9638 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9639 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9640 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9641 }
9642
9643 /*
9644 * TR.
9645 */
9646 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
9647 /* 64-bit capable CPUs. */
9648 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
9649 if (fLongModeGuest)
9650 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
9651 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
9652 else
9653 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
9654 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
9655 VMX_IGS_TR_ATTR_TYPE_INVALID);
9656 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
9657 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
9658 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
9659 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
9660 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
9661 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
9662 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
9663 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
9664
9665 /*
9666 * GDTR and IDTR (64-bit capable checks).
9667 */
9668 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
9669 AssertRC(rc);
9670 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
9671
9672 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
9673 AssertRC(rc);
9674 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
9675
9676 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
9677 AssertRC(rc);
9678 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
9679
9680 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
9681 AssertRC(rc);
9682 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
9683
9684 /*
9685 * Guest Non-Register State.
9686 */
9687 /* Activity State. */
9688 uint32_t u32ActivityState;
9689 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
9690 AssertRC(rc);
9691 HMVMX_CHECK_BREAK( !u32ActivityState
9692 || (u32ActivityState & RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Misc, VMX_BF_MISC_ACTIVITY_STATES)),
9693 VMX_IGS_ACTIVITY_STATE_INVALID);
9694 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
9695 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
9696
9697 if ( u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS
9698 || u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9699 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
9700
9701 /** @todo Activity state and injecting interrupts. Left as a todo since we
9702 * currently don't use activity states but ACTIVE. */
9703
9704 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
9705 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
9706
9707 /* Guest interruptibility-state. */
9708 HMVMX_CHECK_BREAK(!(u32IntrState & 0xffffffe0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
9709 HMVMX_CHECK_BREAK((u32IntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
9710 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9711 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
9712 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
9713 || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
9714 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
9715 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9716 {
9717 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9718 && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9719 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
9720 }
9721 else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
9722 {
9723 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9724 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
9725 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
9726 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
9727 }
9728 /** @todo Assumes the processor is not in SMM. */
9729 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
9730 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
9731 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
9732 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
9733 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
9734 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
9735 && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
9736 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI), VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
9737
9738 /* Pending debug exceptions. */
9739 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &u64Val);
9740 AssertRC(rc);
9741 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
9742 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
9743 u32Val = u64Val; /* For pending debug exceptions checks below. */
9744
9745 if ( (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9746 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
9747 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
9748 {
9749 if ( (u32Eflags & X86_EFL_TF)
9750 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
9751 {
9752 /* Bit 14 is PendingDebug.BS. */
9753 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
9754 }
9755 if ( !(u32Eflags & X86_EFL_TF)
9756 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
9757 {
9758 /* Bit 14 is PendingDebug.BS. */
9759 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
9760 }
9761 }
9762
9763 /* VMCS link pointer. */
9764 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
9765 AssertRC(rc);
9766 if (u64Val != UINT64_C(0xffffffffffffffff))
9767 {
9768 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
9769 /** @todo Bits beyond the processor's physical-address width MBZ. */
9770 /** @todo SMM checks. */
9771 Assert(pVmcsInfo->HCPhysShadowVmcs == u64Val);
9772 Assert(pVmcsInfo->pvShadowVmcs);
9773 VMXVMCSREVID VmcsRevId;
9774 VmcsRevId.u = *(uint32_t *)pVmcsInfo->pvShadowVmcs;
9775 HMVMX_CHECK_BREAK(VmcsRevId.n.u31RevisionId == RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID),
9776 VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID);
9777 HMVMX_CHECK_BREAK(VmcsRevId.n.fIsShadowVmcs == (uint32_t)!!(pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING),
9778 VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW);
9779 }
9780
9781 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
9782 * not using nested paging? */
9783 if ( pVM->hm.s.fNestedPaging
9784 && !fLongModeGuest
9785 && CPUMIsGuestInPAEModeEx(pCtx))
9786 {
9787 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
9788 AssertRC(rc);
9789 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9790
9791 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
9792 AssertRC(rc);
9793 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9794
9795 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
9796 AssertRC(rc);
9797 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9798
9799 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
9800 AssertRC(rc);
9801 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9802 }
9803
9804 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
9805 if (uError == VMX_IGS_ERROR)
9806 uError = VMX_IGS_REASON_NOT_FOUND;
9807 } while (0);
9808
9809 pVCpu->hm.s.u32HMError = uError;
9810 pVCpu->hm.s.vmx.LastError.u32GuestIntrState = u32IntrState;
9811 return uError;
9812
9813#undef HMVMX_ERROR_BREAK
9814#undef HMVMX_CHECK_BREAK
9815}
9816
9817
9818/**
9819 * Map the APIC-access page for virtualizing APIC accesses.
9820 *
9821 * This can cause a longjumps to R3 due to the acquisition of the PGM lock. Hence,
9822 * this not done as part of exporting guest state, see @bugref{8721}.
9823 *
9824 * @returns VBox status code.
9825 * @param pVCpu The cross context virtual CPU structure.
9826 */
9827static int hmR0VmxMapHCApicAccessPage(PVMCPUCC pVCpu)
9828{
9829 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9830 uint64_t const u64MsrApicBase = APICGetBaseMsrNoCheck(pVCpu);
9831
9832 Assert(PDMHasApic(pVM));
9833 Assert(u64MsrApicBase);
9834
9835 RTGCPHYS const GCPhysApicBase = u64MsrApicBase & PAGE_BASE_GC_MASK;
9836 Log4Func(("Mappping HC APIC-access page at %#RGp\n", GCPhysApicBase));
9837
9838 /* Unalias the existing mapping. */
9839 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
9840 AssertRCReturn(rc, rc);
9841
9842 /* Map the HC APIC-access page in place of the MMIO page, also updates the shadow page tables if necessary. */
9843 Assert(pVM->hm.s.vmx.HCPhysApicAccess != NIL_RTHCPHYS);
9844 rc = IOMR0MmioMapMmioHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hm.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
9845 AssertRCReturn(rc, rc);
9846
9847 /* Update the per-VCPU cache of the APIC base MSR. */
9848 pVCpu->hm.s.vmx.u64GstMsrApicBase = u64MsrApicBase;
9849 return VINF_SUCCESS;
9850}
9851
9852
9853/**
9854 * Worker function passed to RTMpOnSpecific() that is to be called on the target
9855 * CPU.
9856 *
9857 * @param idCpu The ID for the CPU the function is called on.
9858 * @param pvUser1 Null, not used.
9859 * @param pvUser2 Null, not used.
9860 */
9861static DECLCALLBACK(void) hmR0DispatchHostNmi(RTCPUID idCpu, void *pvUser1, void *pvUser2)
9862{
9863 RT_NOREF3(idCpu, pvUser1, pvUser2);
9864 VMXDispatchHostNmi();
9865}
9866
9867
9868/**
9869 * Dispatching an NMI on the host CPU that received it.
9870 *
9871 * @returns VBox status code.
9872 * @param pVCpu The cross context virtual CPU structure.
9873 * @param pVmcsInfo The VMCS info. object corresponding to the VMCS that was
9874 * executing when receiving the host NMI in VMX non-root
9875 * operation.
9876 */
9877static int hmR0VmxExitHostNmi(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
9878{
9879 RTCPUID const idCpu = pVmcsInfo->idHostCpuExec;
9880 Assert(idCpu != NIL_RTCPUID);
9881
9882 /*
9883 * We don't want to delay dispatching the NMI any more than we have to. However,
9884 * we have already chosen -not- to dispatch NMIs when interrupts were still disabled
9885 * after executing guest or nested-guest code for the following reasons:
9886 *
9887 * - We would need to perform VMREADs with interrupts disabled and is orders of
9888 * magnitude worse when we run as a nested hypervisor without VMCS shadowing
9889 * supported by the host hypervisor.
9890 *
9891 * - It affects the common VM-exit scenario and keeps interrupts disabled for a
9892 * longer period of time just for handling an edge case like host NMIs which do
9893 * not occur nearly as frequently as other VM-exits.
9894 *
9895 * Let's cover the most likely scenario first. Check if we are on the target CPU
9896 * and dispatch the NMI right away. This should be much faster than calling into
9897 * RTMpOnSpecific() machinery.
9898 */
9899 bool fDispatched = false;
9900 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
9901 if (idCpu == RTMpCpuId())
9902 {
9903 VMXDispatchHostNmi();
9904 fDispatched = true;
9905 }
9906 ASMSetFlags(fEFlags);
9907 if (fDispatched)
9908 {
9909 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
9910 return VINF_SUCCESS;
9911 }
9912
9913 /*
9914 * RTMpOnSpecific() waits until the worker function has run on the target CPU. So
9915 * there should be no race or recursion even if we are unlucky enough to be preempted
9916 * (to the target CPU) without dispatching the host NMI above.
9917 */
9918 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGCIpi);
9919 return RTMpOnSpecific(idCpu, &hmR0DispatchHostNmi, NULL /* pvUser1 */, NULL /* pvUser2 */);
9920}
9921
9922
9923#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9924/**
9925 * Merges the guest with the nested-guest MSR bitmap in preparation of executing the
9926 * nested-guest using hardware-assisted VMX.
9927 *
9928 * @param pVCpu The cross context virtual CPU structure.
9929 * @param pVmcsInfoNstGst The nested-guest VMCS info. object.
9930 * @param pVmcsInfoGst The guest VMCS info. object.
9931 */
9932static void hmR0VmxMergeMsrBitmapNested(PCVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfoNstGst, PCVMXVMCSINFO pVmcsInfoGst)
9933{
9934 uint32_t const cbMsrBitmap = X86_PAGE_4K_SIZE;
9935 uint64_t *pu64MsrBitmap = (uint64_t *)pVmcsInfoNstGst->pvMsrBitmap;
9936 Assert(pu64MsrBitmap);
9937
9938 /*
9939 * We merge the guest MSR bitmap with the nested-guest MSR bitmap such that any
9940 * MSR that is intercepted by the guest is also intercepted while executing the
9941 * nested-guest using hardware-assisted VMX.
9942 *
9943 * Note! If the nested-guest is not using an MSR bitmap, ever MSR must cause a
9944 * nested-guest VM-exit even if the outer guest is not intercepting some
9945 * MSRs. We cannot assume the caller has initialized the nested-guest
9946 * MSR bitmap in this case.
9947 *
9948 * The nested hypervisor may also switch whether it uses MSR bitmaps for
9949 * each VM-entry, hence initializing it once per-VM while setting up the
9950 * nested-guest VMCS is not sufficient.
9951 */
9952 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
9953 if (pVmcsNstGst->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
9954 {
9955 uint64_t const *pu64MsrBitmapNstGst = (uint64_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
9956 uint64_t const *pu64MsrBitmapGst = (uint64_t const *)pVmcsInfoGst->pvMsrBitmap;
9957 Assert(pu64MsrBitmapNstGst);
9958 Assert(pu64MsrBitmapGst);
9959
9960 uint32_t const cFrags = cbMsrBitmap / sizeof(uint64_t);
9961 for (uint32_t i = 0; i < cFrags; i++)
9962 pu64MsrBitmap[i] = pu64MsrBitmapNstGst[i] | pu64MsrBitmapGst[i];
9963 }
9964 else
9965 ASMMemFill32(pu64MsrBitmap, cbMsrBitmap, UINT32_C(0xffffffff));
9966}
9967
9968
9969/**
9970 * Merges the guest VMCS in to the nested-guest VMCS controls in preparation of
9971 * hardware-assisted VMX execution of the nested-guest.
9972 *
9973 * For a guest, we don't modify these controls once we set up the VMCS and hence
9974 * this function is never called.
9975 *
9976 * For nested-guests since the nested hypervisor provides these controls on every
9977 * nested-guest VM-entry and could potentially change them everytime we need to
9978 * merge them before every nested-guest VM-entry.
9979 *
9980 * @returns VBox status code.
9981 * @param pVCpu The cross context virtual CPU structure.
9982 */
9983static int hmR0VmxMergeVmcsNested(PVMCPUCC pVCpu)
9984{
9985 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9986 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hm.s.vmx.VmcsInfo;
9987 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
9988 Assert(pVmcsNstGst);
9989
9990 /*
9991 * Merge the controls with the requirements of the guest VMCS.
9992 *
9993 * We do not need to validate the nested-guest VMX features specified in the nested-guest
9994 * VMCS with the features supported by the physical CPU as it's already done by the
9995 * VMLAUNCH/VMRESUME instruction emulation.
9996 *
9997 * This is because the VMX features exposed by CPUM (through CPUID/MSRs) to the guest are
9998 * derived from the VMX features supported by the physical CPU.
9999 */
10000
10001 /* Pin-based VM-execution controls. */
10002 uint32_t const u32PinCtls = pVmcsNstGst->u32PinCtls | pVmcsInfoGst->u32PinCtls;
10003
10004 /* Processor-based VM-execution controls. */
10005 uint32_t u32ProcCtls = (pVmcsNstGst->u32ProcCtls & ~VMX_PROC_CTLS_USE_IO_BITMAPS)
10006 | (pVmcsInfoGst->u32ProcCtls & ~( VMX_PROC_CTLS_INT_WINDOW_EXIT
10007 | VMX_PROC_CTLS_NMI_WINDOW_EXIT
10008 | VMX_PROC_CTLS_USE_TPR_SHADOW
10009 | VMX_PROC_CTLS_MONITOR_TRAP_FLAG));
10010
10011 /* Secondary processor-based VM-execution controls. */
10012 uint32_t const u32ProcCtls2 = (pVmcsNstGst->u32ProcCtls2 & ~VMX_PROC_CTLS2_VPID)
10013 | (pVmcsInfoGst->u32ProcCtls2 & ~( VMX_PROC_CTLS2_VIRT_APIC_ACCESS
10014 | VMX_PROC_CTLS2_INVPCID
10015 | VMX_PROC_CTLS2_VMCS_SHADOWING
10016 | VMX_PROC_CTLS2_RDTSCP
10017 | VMX_PROC_CTLS2_XSAVES_XRSTORS
10018 | VMX_PROC_CTLS2_APIC_REG_VIRT
10019 | VMX_PROC_CTLS2_VIRT_INT_DELIVERY
10020 | VMX_PROC_CTLS2_VMFUNC));
10021
10022 /*
10023 * VM-entry controls:
10024 * These controls contains state that depends on the nested-guest state (primarily
10025 * EFER MSR) and is thus not constant between VMLAUNCH/VMRESUME and the nested-guest
10026 * VM-exit. Although the nested hypervisor cannot change it, we need to in order to
10027 * properly continue executing the nested-guest if the EFER MSR changes but does not
10028 * cause a nested-guest VM-exits.
10029 *
10030 * VM-exit controls:
10031 * These controls specify the host state on return. We cannot use the controls from
10032 * the nested hypervisor state as is as it would contain the guest state rather than
10033 * the host state. Since the host state is subject to change (e.g. preemption, trips
10034 * to ring-3, longjmp and rescheduling to a different host CPU) they are not constant
10035 * through VMLAUNCH/VMRESUME and the nested-guest VM-exit.
10036 *
10037 * VM-entry MSR-load:
10038 * The guest MSRs from the VM-entry MSR-load area are already loaded into the guest-CPU
10039 * context by the VMLAUNCH/VMRESUME instruction emulation.
10040 *
10041 * VM-exit MSR-store:
10042 * The VM-exit emulation will take care of populating the MSRs from the guest-CPU context
10043 * back into the VM-exit MSR-store area.
10044 *
10045 * VM-exit MSR-load areas:
10046 * This must contain the real host MSRs with hardware-assisted VMX execution. Hence, we
10047 * can entirely ignore what the nested hypervisor wants to load here.
10048 */
10049
10050 /*
10051 * Exception bitmap.
10052 *
10053 * We could remove #UD from the guest bitmap and merge it with the nested-guest bitmap
10054 * here (and avoid doing anything while exporting nested-guest state), but to keep the
10055 * code more flexible if intercepting exceptions become more dynamic in the future we do
10056 * it as part of exporting the nested-guest state.
10057 */
10058 uint32_t const u32XcptBitmap = pVmcsNstGst->u32XcptBitmap | pVmcsInfoGst->u32XcptBitmap;
10059
10060 /*
10061 * CR0/CR4 guest/host mask.
10062 *
10063 * Modifications by the nested-guest to CR0/CR4 bits owned by the host and the guest must
10064 * cause VM-exits, so we need to merge them here.
10065 */
10066 uint64_t const u64Cr0Mask = pVmcsNstGst->u64Cr0Mask.u | pVmcsInfoGst->u64Cr0Mask;
10067 uint64_t const u64Cr4Mask = pVmcsNstGst->u64Cr4Mask.u | pVmcsInfoGst->u64Cr4Mask;
10068
10069 /*
10070 * Page-fault error-code mask and match.
10071 *
10072 * Although we require unrestricted guest execution (and thereby nested-paging) for
10073 * hardware-assisted VMX execution of nested-guests and thus the outer guest doesn't
10074 * normally intercept #PFs, it might intercept them for debugging purposes.
10075 *
10076 * If the outer guest is not intercepting #PFs, we can use the nested-guest #PF filters.
10077 * If the outer guest is intercepting #PFs, we must intercept all #PFs.
10078 */
10079 uint32_t u32XcptPFMask;
10080 uint32_t u32XcptPFMatch;
10081 if (!(pVmcsInfoGst->u32XcptBitmap & RT_BIT(X86_XCPT_PF)))
10082 {
10083 u32XcptPFMask = pVmcsNstGst->u32XcptPFMask;
10084 u32XcptPFMatch = pVmcsNstGst->u32XcptPFMatch;
10085 }
10086 else
10087 {
10088 u32XcptPFMask = 0;
10089 u32XcptPFMatch = 0;
10090 }
10091
10092 /*
10093 * Pause-Loop exiting.
10094 */
10095 uint32_t const cPleGapTicks = RT_MIN(pVM->hm.s.vmx.cPleGapTicks, pVmcsNstGst->u32PleGap);
10096 uint32_t const cPleWindowTicks = RT_MIN(pVM->hm.s.vmx.cPleWindowTicks, pVmcsNstGst->u32PleWindow);
10097
10098 /*
10099 * Pending debug exceptions.
10100 * Currently just copy whatever the nested-guest provides us.
10101 */
10102 uint64_t const uPendingDbgXcpts = pVmcsNstGst->u64GuestPendingDbgXcpts.u;
10103
10104 /*
10105 * I/O Bitmap.
10106 *
10107 * We do not use the I/O bitmap that may be provided by the nested hypervisor as we always
10108 * intercept all I/O port accesses.
10109 */
10110 Assert(u32ProcCtls & VMX_PROC_CTLS_UNCOND_IO_EXIT);
10111 Assert(!(u32ProcCtls & VMX_PROC_CTLS_USE_IO_BITMAPS));
10112
10113 /*
10114 * VMCS shadowing.
10115 *
10116 * We do not yet expose VMCS shadowing to the guest and thus VMCS shadowing should not be
10117 * enabled while executing the nested-guest.
10118 */
10119 Assert(!(u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING));
10120
10121 /*
10122 * APIC-access page.
10123 */
10124 RTHCPHYS HCPhysApicAccess;
10125 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10126 {
10127 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
10128 RTGCPHYS const GCPhysApicAccess = pVmcsNstGst->u64AddrApicAccess.u;
10129
10130 /** @todo NSTVMX: This is not really correct but currently is required to make
10131 * things work. We need to re-enable the page handler when we fallback to
10132 * IEM execution of the nested-guest! */
10133 PGMHandlerPhysicalPageTempOff(pVM, GCPhysApicAccess, GCPhysApicAccess);
10134
10135 void *pvPage;
10136 PGMPAGEMAPLOCK PgLockApicAccess;
10137 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysApicAccess, &pvPage, &PgLockApicAccess);
10138 if (RT_SUCCESS(rc))
10139 {
10140 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysApicAccess, &HCPhysApicAccess);
10141 AssertMsgRCReturn(rc, ("Failed to get host-physical address for APIC-access page at %#RGp\n", GCPhysApicAccess), rc);
10142
10143 /** @todo Handle proper releasing of page-mapping lock later. */
10144 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockApicAccess);
10145 }
10146 else
10147 return rc;
10148 }
10149 else
10150 HCPhysApicAccess = 0;
10151
10152 /*
10153 * Virtual-APIC page and TPR threshold.
10154 */
10155 PVMXVMCSINFO pVmcsInfoNstGst = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
10156 RTHCPHYS HCPhysVirtApic;
10157 uint32_t u32TprThreshold;
10158 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10159 {
10160 Assert(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW);
10161 RTGCPHYS const GCPhysVirtApic = pVmcsNstGst->u64AddrVirtApic.u;
10162
10163 void *pvPage;
10164 PGMPAGEMAPLOCK PgLockVirtApic;
10165 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysVirtApic, &pvPage, &PgLockVirtApic);
10166 if (RT_SUCCESS(rc))
10167 {
10168 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysVirtApic, &HCPhysVirtApic);
10169 AssertMsgRCReturn(rc, ("Failed to get host-physical address for virtual-APIC page at %#RGp\n", GCPhysVirtApic), rc);
10170
10171 /** @todo Handle proper releasing of page-mapping lock later. */
10172 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockVirtApic);
10173 }
10174 else
10175 return rc;
10176
10177 u32TprThreshold = pVmcsNstGst->u32TprThreshold;
10178 }
10179 else
10180 {
10181 HCPhysVirtApic = 0;
10182 u32TprThreshold = 0;
10183
10184 /*
10185 * We must make sure CR8 reads/write must cause VM-exits when TPR shadowing is not
10186 * used by the nested hypervisor. Preventing MMIO accesses to the physical APIC will
10187 * be taken care of by EPT/shadow paging.
10188 */
10189 if (pVM->hm.s.fAllow64BitGuests)
10190 {
10191 u32ProcCtls |= VMX_PROC_CTLS_CR8_STORE_EXIT
10192 | VMX_PROC_CTLS_CR8_LOAD_EXIT;
10193 }
10194 }
10195
10196 /*
10197 * Validate basic assumptions.
10198 */
10199 Assert(pVM->hm.s.vmx.fAllowUnrestricted);
10200 Assert(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
10201 Assert(hmGetVmxActiveVmcsInfo(pVCpu) == pVmcsInfoNstGst);
10202
10203 /*
10204 * Commit it to the nested-guest VMCS.
10205 */
10206 int rc = VINF_SUCCESS;
10207 if (pVmcsInfoNstGst->u32PinCtls != u32PinCtls)
10208 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, u32PinCtls);
10209 if (pVmcsInfoNstGst->u32ProcCtls != u32ProcCtls)
10210 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, u32ProcCtls);
10211 if (pVmcsInfoNstGst->u32ProcCtls2 != u32ProcCtls2)
10212 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, u32ProcCtls2);
10213 if (pVmcsInfoNstGst->u32XcptBitmap != u32XcptBitmap)
10214 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
10215 if (pVmcsInfoNstGst->u64Cr0Mask != u64Cr0Mask)
10216 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask);
10217 if (pVmcsInfoNstGst->u64Cr4Mask != u64Cr4Mask)
10218 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask);
10219 if (pVmcsInfoNstGst->u32XcptPFMask != u32XcptPFMask)
10220 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, u32XcptPFMask);
10221 if (pVmcsInfoNstGst->u32XcptPFMatch != u32XcptPFMatch)
10222 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, u32XcptPFMatch);
10223 if ( !(u32ProcCtls & VMX_PROC_CTLS_PAUSE_EXIT)
10224 && (u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
10225 {
10226 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT);
10227 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, cPleGapTicks);
10228 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, cPleWindowTicks);
10229 }
10230 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10231 {
10232 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
10233 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
10234 }
10235 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10236 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
10237 rc |= VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, uPendingDbgXcpts);
10238 AssertRC(rc);
10239
10240 /*
10241 * Update the nested-guest VMCS cache.
10242 */
10243 pVmcsInfoNstGst->u32PinCtls = u32PinCtls;
10244 pVmcsInfoNstGst->u32ProcCtls = u32ProcCtls;
10245 pVmcsInfoNstGst->u32ProcCtls2 = u32ProcCtls2;
10246 pVmcsInfoNstGst->u32XcptBitmap = u32XcptBitmap;
10247 pVmcsInfoNstGst->u64Cr0Mask = u64Cr0Mask;
10248 pVmcsInfoNstGst->u64Cr4Mask = u64Cr4Mask;
10249 pVmcsInfoNstGst->u32XcptPFMask = u32XcptPFMask;
10250 pVmcsInfoNstGst->u32XcptPFMatch = u32XcptPFMatch;
10251 pVmcsInfoNstGst->HCPhysVirtApic = HCPhysVirtApic;
10252
10253 /*
10254 * We need to flush the TLB if we are switching the APIC-access page address.
10255 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
10256 */
10257 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10258 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = true;
10259
10260 /*
10261 * MSR bitmap.
10262 *
10263 * The MSR bitmap address has already been initialized while setting up the nested-guest
10264 * VMCS, here we need to merge the MSR bitmaps.
10265 */
10266 if (u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10267 hmR0VmxMergeMsrBitmapNested(pVCpu, pVmcsInfoNstGst, pVmcsInfoGst);
10268
10269 return VINF_SUCCESS;
10270}
10271#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10272
10273
10274/**
10275 * Does the preparations before executing guest code in VT-x.
10276 *
10277 * This may cause longjmps to ring-3 and may even result in rescheduling to the
10278 * recompiler/IEM. We must be cautious what we do here regarding committing
10279 * guest-state information into the VMCS assuming we assuredly execute the
10280 * guest in VT-x mode.
10281 *
10282 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
10283 * the common-state (TRPM/forceflags), we must undo those changes so that the
10284 * recompiler/IEM can (and should) use them when it resumes guest execution.
10285 * Otherwise such operations must be done when we can no longer exit to ring-3.
10286 *
10287 * @returns Strict VBox status code (i.e. informational status codes too).
10288 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
10289 * have been disabled.
10290 * @retval VINF_VMX_VMEXIT if a nested-guest VM-exit occurs (e.g., while evaluating
10291 * pending events).
10292 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
10293 * double-fault into the guest.
10294 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
10295 * dispatched directly.
10296 * @retval VINF_* scheduling changes, we have to go back to ring-3.
10297 *
10298 * @param pVCpu The cross context virtual CPU structure.
10299 * @param pVmxTransient The VMX-transient structure.
10300 * @param fStepping Whether we are single-stepping the guest in the
10301 * hypervisor debugger. Makes us ignore some of the reasons
10302 * for returning to ring-3, and return VINF_EM_DBG_STEPPED
10303 * if event dispatching took place.
10304 */
10305static VBOXSTRICTRC hmR0VmxPreRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, bool fStepping)
10306{
10307 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10308
10309 Log4Func(("fIsNested=%RTbool fStepping=%RTbool\n", pVmxTransient->fIsNestedGuest, fStepping));
10310
10311#ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
10312 if (pVmxTransient->fIsNestedGuest)
10313 {
10314 RT_NOREF2(pVCpu, fStepping);
10315 Log2Func(("Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
10316 return VINF_EM_RESCHEDULE_REM;
10317 }
10318#endif
10319
10320#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
10321 PGMRZDynMapFlushAutoSet(pVCpu);
10322#endif
10323
10324 /*
10325 * Check and process force flag actions, some of which might require us to go back to ring-3.
10326 */
10327 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVCpu, pVmxTransient, fStepping);
10328 if (rcStrict == VINF_SUCCESS)
10329 {
10330 /* FFs don't get set all the time. */
10331#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10332 if ( pVmxTransient->fIsNestedGuest
10333 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10334 {
10335 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10336 return VINF_VMX_VMEXIT;
10337 }
10338#endif
10339 }
10340 else
10341 return rcStrict;
10342
10343 /*
10344 * Virtualize memory-mapped accesses to the physical APIC (may take locks).
10345 */
10346 /** @todo Doing this from ring-3 after VM setup phase causes a
10347 * VERR_IOM_MMIO_RANGE_NOT_FOUND guru while booting Visa 64 SMP VM. No
10348 * idea why atm. */
10349 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10350 if ( !pVCpu->hm.s.vmx.u64GstMsrApicBase
10351 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10352 && PDMHasApic(pVM))
10353 {
10354 int rc = hmR0VmxMapHCApicAccessPage(pVCpu);
10355 AssertRCReturn(rc, rc);
10356 }
10357
10358#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10359 /*
10360 * Merge guest VMCS controls with the nested-guest VMCS controls.
10361 *
10362 * Even if we have not executed the guest prior to this (e.g. when resuming from a
10363 * saved state), we should be okay with merging controls as we initialize the
10364 * guest VMCS controls as part of VM setup phase.
10365 */
10366 if ( pVmxTransient->fIsNestedGuest
10367 && !pVCpu->hm.s.vmx.fMergedNstGstCtls)
10368 {
10369 int rc = hmR0VmxMergeVmcsNested(pVCpu);
10370 AssertRCReturn(rc, rc);
10371 pVCpu->hm.s.vmx.fMergedNstGstCtls = true;
10372 }
10373#endif
10374
10375 /*
10376 * Evaluate events to be injected into the guest.
10377 *
10378 * Events in TRPM can be injected without inspecting the guest state.
10379 * If any new events (interrupts/NMI) are pending currently, we try to set up the
10380 * guest to cause a VM-exit the next time they are ready to receive the event.
10381 *
10382 * With nested-guests, evaluating pending events may cause VM-exits. Also, verify
10383 * that the event in TRPM that we will inject using hardware-assisted VMX is -not-
10384 * subject to interecption. Otherwise, we should have checked and injected them
10385 * manually elsewhere (IEM).
10386 */
10387 if (TRPMHasTrap(pVCpu))
10388 {
10389 Assert(!pVmxTransient->fIsNestedGuest || !CPUMIsGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx));
10390 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
10391 }
10392
10393 uint32_t fIntrState;
10394 rcStrict = hmR0VmxEvaluatePendingEvent(pVCpu, pVmxTransient, &fIntrState);
10395
10396#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10397 /*
10398 * While evaluating pending events if something failed (unlikely) or if we were
10399 * preparing to run a nested-guest but performed a nested-guest VM-exit, we should bail.
10400 */
10401 if (rcStrict != VINF_SUCCESS)
10402 return rcStrict;
10403 if ( pVmxTransient->fIsNestedGuest
10404 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10405 {
10406 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10407 return VINF_VMX_VMEXIT;
10408 }
10409#else
10410 Assert(rcStrict == VINF_SUCCESS);
10411#endif
10412
10413 /*
10414 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus
10415 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might
10416 * also result in triple-faulting the VM.
10417 *
10418 * With nested-guests, the above does not apply since unrestricted guest execution is a
10419 * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
10420 */
10421 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pVmxTransient, fIntrState, fStepping);
10422 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10423 { /* likely */ }
10424 else
10425 {
10426 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
10427 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
10428 return rcStrict;
10429 }
10430
10431 /*
10432 * A longjump might result in importing CR3 even for VM-exits that don't necessarily
10433 * import CR3 themselves. We will need to update them here, as even as late as the above
10434 * hmR0VmxInjectPendingEvent() call may lazily import guest-CPU state on demand causing
10435 * the below force flags to be set.
10436 */
10437 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
10438 {
10439 Assert(!(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_CR3));
10440 int rc2 = PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
10441 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
10442 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
10443 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10444 }
10445 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
10446 {
10447 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
10448 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10449 }
10450
10451#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10452 /* Paranoia. */
10453 Assert(!pVmxTransient->fIsNestedGuest || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10454#endif
10455
10456 /*
10457 * No longjmps to ring-3 from this point on!!!
10458 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
10459 * This also disables flushing of the R0-logger instance (if any).
10460 */
10461 VMMRZCallRing3Disable(pVCpu);
10462
10463 /*
10464 * Export the guest state bits.
10465 *
10466 * We cannot perform longjmps while loading the guest state because we do not preserve the
10467 * host/guest state (although the VMCS will be preserved) across longjmps which can cause
10468 * CPU migration.
10469 *
10470 * If we are injecting events to a real-on-v86 mode guest, we would have updated RIP and some segment
10471 * registers. Hence, exporting of the guest state needs to be done -after- injection of events.
10472 */
10473 rcStrict = hmR0VmxExportGuestStateOptimal(pVCpu, pVmxTransient);
10474 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10475 { /* likely */ }
10476 else
10477 {
10478 VMMRZCallRing3Enable(pVCpu);
10479 return rcStrict;
10480 }
10481
10482 /*
10483 * We disable interrupts so that we don't miss any interrupts that would flag preemption
10484 * (IPI/timers etc.) when thread-context hooks aren't used and we've been running with
10485 * preemption disabled for a while. Since this is purely to aid the
10486 * RTThreadPreemptIsPending() code, it doesn't matter that it may temporarily reenable and
10487 * disable interrupt on NT.
10488 *
10489 * We need to check for force-flags that could've possible been altered since we last
10490 * checked them (e.g. by PDMGetInterrupt() leaving the PDM critical section,
10491 * see @bugref{6398}).
10492 *
10493 * We also check a couple of other force-flags as a last opportunity to get the EMT back
10494 * to ring-3 before executing guest code.
10495 */
10496 pVmxTransient->fEFlags = ASMIntDisableFlags();
10497
10498 if ( ( !VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
10499 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
10500 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
10501 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
10502 {
10503 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
10504 {
10505#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10506 /*
10507 * If we are executing a nested-guest make sure that we should intercept subsequent
10508 * events. The one we are injecting might be part of VM-entry. This is mainly to keep
10509 * the VM-exit instruction emulation happy.
10510 */
10511 if (pVmxTransient->fIsNestedGuest)
10512 CPUMSetGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx, true);
10513#endif
10514
10515 /*
10516 * We've injected any pending events. This is really the point of no return (to ring-3).
10517 *
10518 * Note! The caller expects to continue with interrupts & longjmps disabled on successful
10519 * returns from this function, so do -not- enable them here.
10520 */
10521 pVCpu->hm.s.Event.fPending = false;
10522 return VINF_SUCCESS;
10523 }
10524
10525 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPendingHostIrq);
10526 rcStrict = VINF_EM_RAW_INTERRUPT;
10527 }
10528 else
10529 {
10530 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
10531 rcStrict = VINF_EM_RAW_TO_R3;
10532 }
10533
10534 ASMSetFlags(pVmxTransient->fEFlags);
10535 VMMRZCallRing3Enable(pVCpu);
10536
10537 return rcStrict;
10538}
10539
10540
10541/**
10542 * Final preparations before executing guest code using hardware-assisted VMX.
10543 *
10544 * We can no longer get preempted to a different host CPU and there are no returns
10545 * to ring-3. We ignore any errors that may happen from this point (e.g. VMWRITE
10546 * failures), this function is not intended to fail sans unrecoverable hardware
10547 * errors.
10548 *
10549 * @param pVCpu The cross context virtual CPU structure.
10550 * @param pVmxTransient The VMX-transient structure.
10551 *
10552 * @remarks Called with preemption disabled.
10553 * @remarks No-long-jump zone!!!
10554 */
10555static void hmR0VmxPreRunGuestCommitted(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10556{
10557 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10558 Assert(VMMR0IsLogFlushDisabled(pVCpu));
10559 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
10560 Assert(!pVCpu->hm.s.Event.fPending);
10561
10562 /*
10563 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
10564 */
10565 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10566 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
10567
10568 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10569 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10570 PHMPHYSCPU pHostCpu = hmR0GetCurrentCpu();
10571 RTCPUID const idCurrentCpu = pHostCpu->idCpu;
10572
10573 if (!CPUMIsGuestFPUStateActive(pVCpu))
10574 {
10575 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10576 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
10577 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_HOST_CONTEXT;
10578 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10579 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadGuestFpu);
10580 }
10581
10582 /*
10583 * Re-export the host state bits as we may've been preempted (only happens when
10584 * thread-context hooks are used or when the VM start function changes) or if
10585 * the host CR0 is modified while loading the guest FPU state above.
10586 *
10587 * The 64-on-32 switcher saves the (64-bit) host state into the VMCS and if we
10588 * changed the switcher back to 32-bit, we *must* save the 32-bit host state here,
10589 * see @bugref{8432}.
10590 *
10591 * This may also happen when switching to/from a nested-guest VMCS without leaving
10592 * ring-0.
10593 */
10594 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
10595 {
10596 hmR0VmxExportHostState(pVCpu);
10597 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportHostState);
10598 }
10599 Assert(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT));
10600
10601 /*
10602 * Export the state shared between host and guest (FPU, debug, lazy MSRs).
10603 */
10604 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)
10605 hmR0VmxExportSharedState(pVCpu, pVmxTransient);
10606 AssertMsg(!pVCpu->hm.s.fCtxChanged, ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
10607
10608 /*
10609 * Store status of the shared guest/host debug state at the time of VM-entry.
10610 */
10611 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
10612 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
10613
10614 /*
10615 * Always cache the TPR-shadow if the virtual-APIC page exists, thereby skipping
10616 * more than one conditional check. The post-run side of our code shall determine
10617 * if it needs to sync. the virtual APIC TPR with the TPR-shadow.
10618 */
10619 if (pVmcsInfo->pbVirtApic)
10620 pVmxTransient->u8GuestTpr = pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR];
10621
10622 /*
10623 * Update the host MSRs values in the VM-exit MSR-load area.
10624 */
10625 if (!pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs)
10626 {
10627 if (pVmcsInfo->cExitMsrLoad > 0)
10628 hmR0VmxUpdateAutoLoadHostMsrs(pVCpu, pVmcsInfo);
10629 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = true;
10630 }
10631
10632 /*
10633 * Evaluate if we need to intercept guest RDTSC/P accesses. Set up the
10634 * VMX-preemption timer based on the next virtual sync clock deadline.
10635 */
10636 if ( !pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer
10637 || idCurrentCpu != pVCpu->hm.s.idLastCpu)
10638 {
10639 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVCpu, pVmxTransient);
10640 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = true;
10641 }
10642
10643 /* Record statistics of how often we use TSC offsetting as opposed to intercepting RDTSC/P. */
10644 bool const fIsRdtscIntercepted = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT);
10645 if (!fIsRdtscIntercepted)
10646 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
10647 else
10648 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
10649
10650 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
10651 hmR0VmxFlushTaggedTlb(pHostCpu, pVCpu, pVmcsInfo); /* Invalidate the appropriate guest entries from the TLB. */
10652 Assert(idCurrentCpu == pVCpu->hm.s.idLastCpu);
10653 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Record the error reporting info. with the current host CPU. */
10654 pVmcsInfo->idHostCpuState = idCurrentCpu; /* Record the CPU for which the host-state has been exported. */
10655 pVmcsInfo->idHostCpuExec = idCurrentCpu; /* Record the CPU on which we shall execute. */
10656
10657 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
10658
10659 TMNotifyStartOfExecution(pVM, pVCpu); /* Notify TM to resume its clocks when TSC is tied to execution,
10660 as we're about to start executing the guest. */
10661
10662 /*
10663 * Load the guest TSC_AUX MSR when we are not intercepting RDTSCP.
10664 *
10665 * This is done this late as updating the TSC offsetting/preemption timer above
10666 * figures out if we can skip intercepting RDTSCP by calculating the number of
10667 * host CPU ticks till the next virtual sync deadline (for the dynamic case).
10668 */
10669 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_RDTSCP)
10670 && !fIsRdtscIntercepted)
10671 {
10672 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_TSC_AUX);
10673
10674 /* NB: Because we call hmR0VmxAddAutoLoadStoreMsr with fUpdateHostMsr=true,
10675 it's safe even after hmR0VmxUpdateAutoLoadHostMsrs has already been done. */
10676 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX, CPUMGetGuestTscAux(pVCpu),
10677 true /* fSetReadWrite */, true /* fUpdateHostMsr */);
10678 AssertRC(rc);
10679 Assert(!pVmxTransient->fRemoveTscAuxMsr);
10680 pVmxTransient->fRemoveTscAuxMsr = true;
10681 }
10682
10683#ifdef VBOX_STRICT
10684 Assert(pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs);
10685 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
10686 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo);
10687 AssertRC(hmR0VmxCheckCachedVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest));
10688#endif
10689
10690#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
10691 /** @todo r=ramshankar: We can now probably use iemVmxVmentryCheckGuestState here.
10692 * Add a PVMXMSRS parameter to it, so that IEM can look at the host MSRs,
10693 * see @bugref{9180#c54}. */
10694 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
10695 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
10696 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
10697#endif
10698}
10699
10700
10701/**
10702 * First C routine invoked after running guest code using hardware-assisted VMX.
10703 *
10704 * @param pVCpu The cross context virtual CPU structure.
10705 * @param pVmxTransient The VMX-transient structure.
10706 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
10707 *
10708 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
10709 *
10710 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
10711 * unconditionally when it is safe to do so.
10712 */
10713static void hmR0VmxPostRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, int rcVMRun)
10714{
10715 uint64_t const uHostTsc = ASMReadTSC(); /** @todo We can do a lot better here, see @bugref{9180#c38}. */
10716
10717 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
10718 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
10719 pVCpu->hm.s.fCtxChanged = 0; /* Exits/longjmps to ring-3 requires saving the guest state. */
10720 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
10721 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
10722 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
10723
10724 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10725 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
10726 {
10727 uint64_t uGstTsc;
10728 if (!pVmxTransient->fIsNestedGuest)
10729 uGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
10730 else
10731 {
10732 uint64_t const uNstGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
10733 uGstTsc = CPUMRemoveNestedGuestTscOffset(pVCpu, uNstGstTsc);
10734 }
10735 TMCpuTickSetLastSeen(pVCpu, uGstTsc); /* Update TM with the guest TSC. */
10736 }
10737
10738 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatPreExit, x);
10739 TMNotifyEndOfExecution(pVCpu->CTX_SUFF(pVM), pVCpu); /* Notify TM that the guest is no longer running. */
10740 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10741
10742 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Some host state messed up by VMX needs restoring. */
10743 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
10744#ifdef VBOX_STRICT
10745 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo); /* Verify that the host EFER MSR wasn't modified. */
10746#endif
10747 Assert(!ASMIntAreEnabled());
10748 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
10749 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10750
10751#ifdef HMVMX_ALWAYS_CLEAN_TRANSIENT
10752 /*
10753 * Clean all the VMCS fields in the transient structure before reading
10754 * anything from the VMCS.
10755 */
10756 pVmxTransient->uExitReason = 0;
10757 pVmxTransient->uExitIntErrorCode = 0;
10758 pVmxTransient->uExitQual = 0;
10759 pVmxTransient->uGuestLinearAddr = 0;
10760 pVmxTransient->uExitIntInfo = 0;
10761 pVmxTransient->cbExitInstr = 0;
10762 pVmxTransient->ExitInstrInfo.u = 0;
10763 pVmxTransient->uEntryIntInfo = 0;
10764 pVmxTransient->uEntryXcptErrorCode = 0;
10765 pVmxTransient->cbEntryInstr = 0;
10766 pVmxTransient->uIdtVectoringInfo = 0;
10767 pVmxTransient->uIdtVectoringErrorCode = 0;
10768#endif
10769
10770 /*
10771 * Save the basic VM-exit reason and check if the VM-entry failed.
10772 * See Intel spec. 24.9.1 "Basic VM-exit Information".
10773 */
10774 uint32_t uExitReason;
10775 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
10776 AssertRC(rc);
10777 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason);
10778 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
10779
10780 /*
10781 * Log the VM-exit before logging anything else as otherwise it might be a
10782 * tad confusing what happens before and after the world-switch.
10783 */
10784 HMVMX_LOG_EXIT(pVCpu, uExitReason);
10785
10786 /*
10787 * Remove the TSC_AUX MSR from the auto-load/store MSR area and reset any MSR
10788 * bitmap permissions, if it was added before VM-entry.
10789 */
10790 if (pVmxTransient->fRemoveTscAuxMsr)
10791 {
10792 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX);
10793 pVmxTransient->fRemoveTscAuxMsr = false;
10794 }
10795
10796 /*
10797 * Check if VMLAUNCH/VMRESUME succeeded.
10798 * If this failed, we cause a guru meditation and cease further execution.
10799 *
10800 * However, if we are executing a nested-guest we might fail if we use the
10801 * fast path rather than fully emulating VMLAUNCH/VMRESUME instruction in IEM.
10802 */
10803 if (RT_LIKELY(rcVMRun == VINF_SUCCESS))
10804 {
10805 /*
10806 * Update the VM-exit history array here even if the VM-entry failed due to:
10807 * - Invalid guest state.
10808 * - MSR loading.
10809 * - Machine-check event.
10810 *
10811 * In any of the above cases we will still have a "valid" VM-exit reason
10812 * despite @a fVMEntryFailed being false.
10813 *
10814 * See Intel spec. 26.7 "VM-Entry failures during or after loading guest state".
10815 *
10816 * Note! We don't have CS or RIP at this point. Will probably address that later
10817 * by amending the history entry added here.
10818 */
10819 EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_VMX, pVmxTransient->uExitReason & EMEXIT_F_TYPE_MASK),
10820 UINT64_MAX, uHostTsc);
10821
10822 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
10823 {
10824 VMMRZCallRing3Enable(pVCpu);
10825
10826 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10827 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10828
10829#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
10830 hmR0VmxReadAllRoFieldsVmcs(pVmxTransient);
10831#endif
10832
10833 /*
10834 * Import the guest-interruptibility state always as we need it while evaluating
10835 * injecting events on re-entry.
10836 *
10837 * We don't import CR0 (when unrestricted guest execution is unavailable) despite
10838 * checking for real-mode while exporting the state because all bits that cause
10839 * mode changes wrt CR0 are intercepted.
10840 */
10841 uint64_t const fImportMask = CPUMCTX_EXTRN_HM_VMX_INT_STATE
10842#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
10843 | HMVMX_CPUMCTX_EXTRN_ALL
10844#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
10845 | CPUMCTX_EXTRN_RFLAGS
10846#endif
10847 ;
10848 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImportMask);
10849 AssertRC(rc);
10850
10851 /*
10852 * Sync the TPR shadow with our APIC state.
10853 */
10854 if ( !pVmxTransient->fIsNestedGuest
10855 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
10856 {
10857 Assert(pVmcsInfo->pbVirtApic);
10858 if (pVmxTransient->u8GuestTpr != pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR])
10859 {
10860 rc = APICSetTpr(pVCpu, pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR]);
10861 AssertRC(rc);
10862 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
10863 }
10864 }
10865
10866 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10867 return;
10868 }
10869 }
10870#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10871 else if (pVmxTransient->fIsNestedGuest)
10872 AssertMsgFailed(("VMLAUNCH/VMRESUME failed but shouldn't happen when VMLAUNCH/VMRESUME was emulated in IEM!\n"));
10873#endif
10874 else
10875 Log4Func(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
10876
10877 VMMRZCallRing3Enable(pVCpu);
10878}
10879
10880
10881/**
10882 * Runs the guest code using hardware-assisted VMX the normal way.
10883 *
10884 * @returns VBox status code.
10885 * @param pVCpu The cross context virtual CPU structure.
10886 * @param pcLoops Pointer to the number of executed loops.
10887 */
10888static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVMCPUCC pVCpu, uint32_t *pcLoops)
10889{
10890 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
10891 Assert(pcLoops);
10892 Assert(*pcLoops <= cMaxResumeLoops);
10893 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10894
10895#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10896 /*
10897 * Switch to the guest VMCS as we may have transitioned from executing the nested-guest
10898 * without leaving ring-0. Otherwise, if we came from ring-3 we would have loaded the
10899 * guest VMCS while entering the VMX ring-0 session.
10900 */
10901 if (pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs)
10902 {
10903 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, false /* fSwitchToNstGstVmcs */);
10904 if (RT_SUCCESS(rc))
10905 { /* likely */ }
10906 else
10907 {
10908 LogRelFunc(("Failed to switch to the guest VMCS. rc=%Rrc\n", rc));
10909 return rc;
10910 }
10911 }
10912#endif
10913
10914 VMXTRANSIENT VmxTransient;
10915 RT_ZERO(VmxTransient);
10916 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
10917
10918 /* Paranoia. */
10919 Assert(VmxTransient.pVmcsInfo == &pVCpu->hm.s.vmx.VmcsInfo);
10920
10921 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10922 for (;;)
10923 {
10924 Assert(!HMR0SuspendPending());
10925 HMVMX_ASSERT_CPU_SAFE(pVCpu);
10926 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10927
10928 /*
10929 * Preparatory work for running nested-guest code, this may force us to
10930 * return to ring-3.
10931 *
10932 * Warning! This bugger disables interrupts on VINF_SUCCESS!
10933 */
10934 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
10935 if (rcStrict != VINF_SUCCESS)
10936 break;
10937
10938 /* Interrupts are disabled at this point! */
10939 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
10940 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
10941 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
10942 /* Interrupts are re-enabled at this point! */
10943
10944 /*
10945 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
10946 */
10947 if (RT_SUCCESS(rcRun))
10948 { /* very likely */ }
10949 else
10950 {
10951 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
10952 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
10953 return rcRun;
10954 }
10955
10956 /*
10957 * Profile the VM-exit.
10958 */
10959 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10960 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10961 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10962 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
10963 HMVMX_START_EXIT_DISPATCH_PROF();
10964
10965 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
10966
10967 /*
10968 * Handle the VM-exit.
10969 */
10970#ifdef HMVMX_USE_FUNCTION_TABLE
10971 rcStrict = g_apfnVMExitHandlers[VmxTransient.uExitReason](pVCpu, &VmxTransient);
10972#else
10973 rcStrict = hmR0VmxHandleExit(pVCpu, &VmxTransient);
10974#endif
10975 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
10976 if (rcStrict == VINF_SUCCESS)
10977 {
10978 if (++(*pcLoops) <= cMaxResumeLoops)
10979 continue;
10980 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10981 rcStrict = VINF_EM_RAW_INTERRUPT;
10982 }
10983 break;
10984 }
10985
10986 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10987 return rcStrict;
10988}
10989
10990
10991#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10992/**
10993 * Runs the nested-guest code using hardware-assisted VMX.
10994 *
10995 * @returns VBox status code.
10996 * @param pVCpu The cross context virtual CPU structure.
10997 * @param pcLoops Pointer to the number of executed loops.
10998 *
10999 * @sa hmR0VmxRunGuestCodeNormal.
11000 */
11001static VBOXSTRICTRC hmR0VmxRunGuestCodeNested(PVMCPUCC pVCpu, uint32_t *pcLoops)
11002{
11003 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
11004 Assert(pcLoops);
11005 Assert(*pcLoops <= cMaxResumeLoops);
11006 Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
11007
11008 /*
11009 * Switch to the nested-guest VMCS as we may have transitioned from executing the
11010 * guest without leaving ring-0. Otherwise, if we came from ring-3 we would have
11011 * loaded the nested-guest VMCS while entering the VMX ring-0 session.
11012 */
11013 if (!pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs)
11014 {
11015 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, true /* fSwitchToNstGstVmcs */);
11016 if (RT_SUCCESS(rc))
11017 { /* likely */ }
11018 else
11019 {
11020 LogRelFunc(("Failed to switch to the nested-guest VMCS. rc=%Rrc\n", rc));
11021 return rc;
11022 }
11023 }
11024
11025 VMXTRANSIENT VmxTransient;
11026 RT_ZERO(VmxTransient);
11027 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
11028 VmxTransient.fIsNestedGuest = true;
11029
11030 /* Paranoia. */
11031 Assert(VmxTransient.pVmcsInfo == &pVCpu->hm.s.vmx.VmcsInfoNstGst);
11032
11033 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
11034 for (;;)
11035 {
11036 Assert(!HMR0SuspendPending());
11037 HMVMX_ASSERT_CPU_SAFE(pVCpu);
11038 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
11039
11040 /*
11041 * Preparatory work for running guest code, this may force us to
11042 * return to ring-3.
11043 *
11044 * Warning! This bugger disables interrupts on VINF_SUCCESS!
11045 */
11046 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
11047 if (rcStrict != VINF_SUCCESS)
11048 break;
11049
11050 /* Interrupts are disabled at this point! */
11051 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
11052 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
11053 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
11054 /* Interrupts are re-enabled at this point! */
11055
11056 /*
11057 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
11058 */
11059 if (RT_SUCCESS(rcRun))
11060 { /* very likely */ }
11061 else
11062 {
11063 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
11064 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
11065 return rcRun;
11066 }
11067
11068 /*
11069 * Profile the VM-exit.
11070 */
11071 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
11072 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
11073 STAM_COUNTER_INC(&pVCpu->hm.s.StatNestedExitAll);
11074 STAM_COUNTER_INC(&pVCpu->hm.s.paStatNestedExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
11075 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
11076 HMVMX_START_EXIT_DISPATCH_PROF();
11077
11078 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
11079
11080 /*
11081 * Handle the VM-exit.
11082 */
11083 rcStrict = hmR0VmxHandleExitNested(pVCpu, &VmxTransient);
11084 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
11085 if (rcStrict == VINF_SUCCESS)
11086 {
11087 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
11088 {
11089 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
11090 rcStrict = VINF_VMX_VMEXIT;
11091 }
11092 else
11093 {
11094 if (++(*pcLoops) <= cMaxResumeLoops)
11095 continue;
11096 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
11097 rcStrict = VINF_EM_RAW_INTERRUPT;
11098 }
11099 }
11100 else
11101 Assert(rcStrict != VINF_VMX_VMEXIT);
11102 break;
11103 }
11104
11105 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
11106 return rcStrict;
11107}
11108#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
11109
11110
11111/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
11112 * probes.
11113 *
11114 * The following few functions and associated structure contains the bloat
11115 * necessary for providing detailed debug events and dtrace probes as well as
11116 * reliable host side single stepping. This works on the principle of
11117 * "subclassing" the normal execution loop and workers. We replace the loop
11118 * method completely and override selected helpers to add necessary adjustments
11119 * to their core operation.
11120 *
11121 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
11122 * any performance for debug and analysis features.
11123 *
11124 * @{
11125 */
11126
11127/**
11128 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
11129 * the debug run loop.
11130 */
11131typedef struct VMXRUNDBGSTATE
11132{
11133 /** The RIP we started executing at. This is for detecting that we stepped. */
11134 uint64_t uRipStart;
11135 /** The CS we started executing with. */
11136 uint16_t uCsStart;
11137
11138 /** Whether we've actually modified the 1st execution control field. */
11139 bool fModifiedProcCtls : 1;
11140 /** Whether we've actually modified the 2nd execution control field. */
11141 bool fModifiedProcCtls2 : 1;
11142 /** Whether we've actually modified the exception bitmap. */
11143 bool fModifiedXcptBitmap : 1;
11144
11145 /** We desire the modified the CR0 mask to be cleared. */
11146 bool fClearCr0Mask : 1;
11147 /** We desire the modified the CR4 mask to be cleared. */
11148 bool fClearCr4Mask : 1;
11149 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
11150 uint32_t fCpe1Extra;
11151 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
11152 uint32_t fCpe1Unwanted;
11153 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
11154 uint32_t fCpe2Extra;
11155 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
11156 uint32_t bmXcptExtra;
11157 /** The sequence number of the Dtrace provider settings the state was
11158 * configured against. */
11159 uint32_t uDtraceSettingsSeqNo;
11160 /** VM-exits to check (one bit per VM-exit). */
11161 uint32_t bmExitsToCheck[3];
11162
11163 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
11164 uint32_t fProcCtlsInitial;
11165 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
11166 uint32_t fProcCtls2Initial;
11167 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
11168 uint32_t bmXcptInitial;
11169} VMXRUNDBGSTATE;
11170AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
11171typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
11172
11173
11174/**
11175 * Initializes the VMXRUNDBGSTATE structure.
11176 *
11177 * @param pVCpu The cross context virtual CPU structure of the
11178 * calling EMT.
11179 * @param pVmxTransient The VMX-transient structure.
11180 * @param pDbgState The debug state to initialize.
11181 */
11182static void hmR0VmxRunDebugStateInit(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11183{
11184 pDbgState->uRipStart = pVCpu->cpum.GstCtx.rip;
11185 pDbgState->uCsStart = pVCpu->cpum.GstCtx.cs.Sel;
11186
11187 pDbgState->fModifiedProcCtls = false;
11188 pDbgState->fModifiedProcCtls2 = false;
11189 pDbgState->fModifiedXcptBitmap = false;
11190 pDbgState->fClearCr0Mask = false;
11191 pDbgState->fClearCr4Mask = false;
11192 pDbgState->fCpe1Extra = 0;
11193 pDbgState->fCpe1Unwanted = 0;
11194 pDbgState->fCpe2Extra = 0;
11195 pDbgState->bmXcptExtra = 0;
11196 pDbgState->fProcCtlsInitial = pVmxTransient->pVmcsInfo->u32ProcCtls;
11197 pDbgState->fProcCtls2Initial = pVmxTransient->pVmcsInfo->u32ProcCtls2;
11198 pDbgState->bmXcptInitial = pVmxTransient->pVmcsInfo->u32XcptBitmap;
11199}
11200
11201
11202/**
11203 * Updates the VMSC fields with changes requested by @a pDbgState.
11204 *
11205 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
11206 * immediately before executing guest code, i.e. when interrupts are disabled.
11207 * We don't check status codes here as we cannot easily assert or return in the
11208 * latter case.
11209 *
11210 * @param pVCpu The cross context virtual CPU structure.
11211 * @param pVmxTransient The VMX-transient structure.
11212 * @param pDbgState The debug state.
11213 */
11214static void hmR0VmxPreRunGuestDebugStateApply(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11215{
11216 /*
11217 * Ensure desired flags in VMCS control fields are set.
11218 * (Ignoring write failure here, as we're committed and it's just debug extras.)
11219 *
11220 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
11221 * there should be no stale data in pCtx at this point.
11222 */
11223 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11224 if ( (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
11225 || (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Unwanted))
11226 {
11227 pVmcsInfo->u32ProcCtls |= pDbgState->fCpe1Extra;
11228 pVmcsInfo->u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
11229 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
11230 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVmcsInfo->u32ProcCtls));
11231 pDbgState->fModifiedProcCtls = true;
11232 }
11233
11234 if ((pVmcsInfo->u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
11235 {
11236 pVmcsInfo->u32ProcCtls2 |= pDbgState->fCpe2Extra;
11237 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVmcsInfo->u32ProcCtls2);
11238 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVmcsInfo->u32ProcCtls2));
11239 pDbgState->fModifiedProcCtls2 = true;
11240 }
11241
11242 if ((pVmcsInfo->u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
11243 {
11244 pVmcsInfo->u32XcptBitmap |= pDbgState->bmXcptExtra;
11245 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVmcsInfo->u32XcptBitmap);
11246 Log6Func(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVmcsInfo->u32XcptBitmap));
11247 pDbgState->fModifiedXcptBitmap = true;
11248 }
11249
11250 if (pDbgState->fClearCr0Mask && pVmcsInfo->u64Cr0Mask != 0)
11251 {
11252 pVmcsInfo->u64Cr0Mask = 0;
11253 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, 0);
11254 Log6Func(("VMX_VMCS_CTRL_CR0_MASK: 0\n"));
11255 }
11256
11257 if (pDbgState->fClearCr4Mask && pVmcsInfo->u64Cr4Mask != 0)
11258 {
11259 pVmcsInfo->u64Cr4Mask = 0;
11260 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, 0);
11261 Log6Func(("VMX_VMCS_CTRL_CR4_MASK: 0\n"));
11262 }
11263
11264 NOREF(pVCpu);
11265}
11266
11267
11268/**
11269 * Restores VMCS fields that were changed by hmR0VmxPreRunGuestDebugStateApply for
11270 * re-entry next time around.
11271 *
11272 * @returns Strict VBox status code (i.e. informational status codes too).
11273 * @param pVCpu The cross context virtual CPU structure.
11274 * @param pVmxTransient The VMX-transient structure.
11275 * @param pDbgState The debug state.
11276 * @param rcStrict The return code from executing the guest using single
11277 * stepping.
11278 */
11279static VBOXSTRICTRC hmR0VmxRunDebugStateRevert(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState,
11280 VBOXSTRICTRC rcStrict)
11281{
11282 /*
11283 * Restore VM-exit control settings as we may not reenter this function the
11284 * next time around.
11285 */
11286 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11287
11288 /* We reload the initial value, trigger what we can of recalculations the
11289 next time around. From the looks of things, that's all that's required atm. */
11290 if (pDbgState->fModifiedProcCtls)
11291 {
11292 if (!(pDbgState->fProcCtlsInitial & VMX_PROC_CTLS_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
11293 pDbgState->fProcCtlsInitial |= VMX_PROC_CTLS_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
11294 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
11295 AssertRC(rc2);
11296 pVmcsInfo->u32ProcCtls = pDbgState->fProcCtlsInitial;
11297 }
11298
11299 /* We're currently the only ones messing with this one, so just restore the
11300 cached value and reload the field. */
11301 if ( pDbgState->fModifiedProcCtls2
11302 && pVmcsInfo->u32ProcCtls2 != pDbgState->fProcCtls2Initial)
11303 {
11304 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
11305 AssertRC(rc2);
11306 pVmcsInfo->u32ProcCtls2 = pDbgState->fProcCtls2Initial;
11307 }
11308
11309 /* If we've modified the exception bitmap, we restore it and trigger
11310 reloading and partial recalculation the next time around. */
11311 if (pDbgState->fModifiedXcptBitmap)
11312 pVmcsInfo->u32XcptBitmap = pDbgState->bmXcptInitial;
11313
11314 return rcStrict;
11315}
11316
11317
11318/**
11319 * Configures VM-exit controls for current DBGF and DTrace settings.
11320 *
11321 * This updates @a pDbgState and the VMCS execution control fields to reflect
11322 * the necessary VM-exits demanded by DBGF and DTrace.
11323 *
11324 * @param pVCpu The cross context virtual CPU structure.
11325 * @param pVmxTransient The VMX-transient structure. May update
11326 * fUpdatedTscOffsettingAndPreemptTimer.
11327 * @param pDbgState The debug state.
11328 */
11329static void hmR0VmxPreRunGuestDebugStateUpdate(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11330{
11331 /*
11332 * Take down the dtrace serial number so we can spot changes.
11333 */
11334 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
11335 ASMCompilerBarrier();
11336
11337 /*
11338 * We'll rebuild most of the middle block of data members (holding the
11339 * current settings) as we go along here, so start by clearing it all.
11340 */
11341 pDbgState->bmXcptExtra = 0;
11342 pDbgState->fCpe1Extra = 0;
11343 pDbgState->fCpe1Unwanted = 0;
11344 pDbgState->fCpe2Extra = 0;
11345 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
11346 pDbgState->bmExitsToCheck[i] = 0;
11347
11348 /*
11349 * Software interrupts (INT XXh) - no idea how to trigger these...
11350 */
11351 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11352 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
11353 || VBOXVMM_INT_SOFTWARE_ENABLED())
11354 {
11355 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11356 }
11357
11358 /*
11359 * INT3 breakpoints - triggered by #BP exceptions.
11360 */
11361 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
11362 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11363
11364 /*
11365 * Exception bitmap and XCPT events+probes.
11366 */
11367 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
11368 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
11369 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
11370
11371 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
11372 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
11373 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11374 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
11375 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
11376 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
11377 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
11378 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
11379 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
11380 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
11381 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
11382 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
11383 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
11384 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
11385 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
11386 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
11387 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
11388 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
11389
11390 if (pDbgState->bmXcptExtra)
11391 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11392
11393 /*
11394 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
11395 *
11396 * Note! This is the reverse of what hmR0VmxHandleExitDtraceEvents does.
11397 * So, when adding/changing/removing please don't forget to update it.
11398 *
11399 * Some of the macros are picking up local variables to save horizontal space,
11400 * (being able to see it in a table is the lesser evil here).
11401 */
11402#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
11403 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
11404 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
11405#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
11406 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11407 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11408 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11409 } else do { } while (0)
11410#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
11411 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11412 { \
11413 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
11414 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11415 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11416 } else do { } while (0)
11417#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
11418 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11419 { \
11420 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
11421 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11422 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11423 } else do { } while (0)
11424#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
11425 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11426 { \
11427 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
11428 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11429 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11430 } else do { } while (0)
11431
11432 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
11433 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
11434 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
11435 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
11436 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
11437
11438 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
11439 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
11440 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
11441 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
11442 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_PROC_CTLS_HLT_EXIT); /* paranoia */
11443 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
11444 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
11445 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
11446 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_PROC_CTLS_INVLPG_EXIT);
11447 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
11448 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_PROC_CTLS_RDPMC_EXIT);
11449 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
11450 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_PROC_CTLS_RDTSC_EXIT);
11451 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
11452 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
11453 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
11454 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
11455 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
11456 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
11457 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
11458 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
11459 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
11460 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
11461 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
11462 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
11463 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
11464 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
11465 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
11466 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
11467 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
11468 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
11469 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
11470 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
11471 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
11472 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
11473 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
11474
11475 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
11476 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11477 {
11478 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4
11479 | CPUMCTX_EXTRN_APIC_TPR);
11480 AssertRC(rc);
11481
11482#if 0 /** @todo fix me */
11483 pDbgState->fClearCr0Mask = true;
11484 pDbgState->fClearCr4Mask = true;
11485#endif
11486 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
11487 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_STORE_EXIT | VMX_PROC_CTLS_CR8_STORE_EXIT;
11488 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11489 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_LOAD_EXIT | VMX_PROC_CTLS_CR8_LOAD_EXIT;
11490 pDbgState->fCpe1Unwanted |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* risky? */
11491 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
11492 require clearing here and in the loop if we start using it. */
11493 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
11494 }
11495 else
11496 {
11497 if (pDbgState->fClearCr0Mask)
11498 {
11499 pDbgState->fClearCr0Mask = false;
11500 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR0);
11501 }
11502 if (pDbgState->fClearCr4Mask)
11503 {
11504 pDbgState->fClearCr4Mask = false;
11505 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR4);
11506 }
11507 }
11508 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
11509 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
11510
11511 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
11512 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
11513 {
11514 /** @todo later, need to fix handler as it assumes this won't usually happen. */
11515 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
11516 }
11517 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
11518 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
11519
11520 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS); /* risky clearing this? */
11521 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
11522 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS);
11523 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
11524 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_PROC_CTLS_MWAIT_EXIT); /* paranoia */
11525 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
11526 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_PROC_CTLS_MONITOR_EXIT); /* paranoia */
11527 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
11528#if 0 /** @todo too slow, fix handler. */
11529 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_PROC_CTLS_PAUSE_EXIT);
11530#endif
11531 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
11532
11533 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
11534 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
11535 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
11536 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
11537 {
11538 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11539 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_GDTR_IDTR_ACCESS);
11540 }
11541 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11542 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11543 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11544 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11545
11546 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
11547 || IS_EITHER_ENABLED(pVM, INSTR_STR)
11548 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
11549 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
11550 {
11551 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11552 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_LDTR_TR_ACCESS);
11553 }
11554 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_LDTR_TR_ACCESS);
11555 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_LDTR_TR_ACCESS);
11556 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_LDTR_TR_ACCESS);
11557 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_LDTR_TR_ACCESS);
11558
11559 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
11560 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
11561 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_PROC_CTLS_RDTSC_EXIT);
11562 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
11563 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
11564 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
11565 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_PROC_CTLS2_WBINVD_EXIT);
11566 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
11567 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
11568 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
11569 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_PROC_CTLS2_RDRAND_EXIT);
11570 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
11571 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_PROC_CTLS_INVLPG_EXIT);
11572 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
11573 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
11574 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
11575 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_PROC_CTLS2_RDSEED_EXIT);
11576 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
11577 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
11578 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
11579 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
11580 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
11581
11582#undef IS_EITHER_ENABLED
11583#undef SET_ONLY_XBM_IF_EITHER_EN
11584#undef SET_CPE1_XBM_IF_EITHER_EN
11585#undef SET_CPEU_XBM_IF_EITHER_EN
11586#undef SET_CPE2_XBM_IF_EITHER_EN
11587
11588 /*
11589 * Sanitize the control stuff.
11590 */
11591 pDbgState->fCpe2Extra &= pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1;
11592 if (pDbgState->fCpe2Extra)
11593 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
11594 pDbgState->fCpe1Extra &= pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1;
11595 pDbgState->fCpe1Unwanted &= ~pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0;
11596 if (pVCpu->hm.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_PROC_CTLS_RDTSC_EXIT))
11597 {
11598 pVCpu->hm.s.fDebugWantRdTscExit ^= true;
11599 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
11600 }
11601
11602 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
11603 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
11604 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
11605 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
11606}
11607
11608
11609/**
11610 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
11611 * appropriate.
11612 *
11613 * The caller has checked the VM-exit against the
11614 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
11615 * already, so we don't have to do that either.
11616 *
11617 * @returns Strict VBox status code (i.e. informational status codes too).
11618 * @param pVCpu The cross context virtual CPU structure.
11619 * @param pVmxTransient The VMX-transient structure.
11620 * @param uExitReason The VM-exit reason.
11621 *
11622 * @remarks The name of this function is displayed by dtrace, so keep it short
11623 * and to the point. No longer than 33 chars long, please.
11624 */
11625static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
11626{
11627 /*
11628 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
11629 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
11630 *
11631 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
11632 * does. Must add/change/remove both places. Same ordering, please.
11633 *
11634 * Added/removed events must also be reflected in the next section
11635 * where we dispatch dtrace events.
11636 */
11637 bool fDtrace1 = false;
11638 bool fDtrace2 = false;
11639 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
11640 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
11641 uint32_t uEventArg = 0;
11642#define SET_EXIT(a_EventSubName) \
11643 do { \
11644 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11645 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11646 } while (0)
11647#define SET_BOTH(a_EventSubName) \
11648 do { \
11649 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
11650 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11651 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
11652 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11653 } while (0)
11654 switch (uExitReason)
11655 {
11656 case VMX_EXIT_MTF:
11657 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
11658
11659 case VMX_EXIT_XCPT_OR_NMI:
11660 {
11661 uint8_t const idxVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
11662 switch (VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo))
11663 {
11664 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
11665 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
11666 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
11667 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
11668 {
11669 if (VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uExitIntInfo))
11670 {
11671 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
11672 uEventArg = pVmxTransient->uExitIntErrorCode;
11673 }
11674 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
11675 switch (enmEvent1)
11676 {
11677 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
11678 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
11679 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
11680 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
11681 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
11682 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
11683 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
11684 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
11685 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
11686 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
11687 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
11688 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
11689 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
11690 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
11691 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
11692 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
11693 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
11694 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
11695 default: break;
11696 }
11697 }
11698 else
11699 AssertFailed();
11700 break;
11701
11702 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
11703 uEventArg = idxVector;
11704 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
11705 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
11706 break;
11707 }
11708 break;
11709 }
11710
11711 case VMX_EXIT_TRIPLE_FAULT:
11712 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
11713 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
11714 break;
11715 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
11716 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
11717 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
11718 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
11719 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
11720
11721 /* Instruction specific VM-exits: */
11722 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
11723 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
11724 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
11725 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
11726 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
11727 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
11728 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
11729 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
11730 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
11731 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
11732 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
11733 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
11734 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
11735 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
11736 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
11737 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
11738 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
11739 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
11740 case VMX_EXIT_MOV_CRX:
11741 hmR0VmxReadExitQualVmcs(pVmxTransient);
11742 if (VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_CRX_ACCESS_READ)
11743 SET_BOTH(CRX_READ);
11744 else
11745 SET_BOTH(CRX_WRITE);
11746 uEventArg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
11747 break;
11748 case VMX_EXIT_MOV_DRX:
11749 hmR0VmxReadExitQualVmcs(pVmxTransient);
11750 if ( VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual)
11751 == VMX_EXIT_QUAL_DRX_DIRECTION_READ)
11752 SET_BOTH(DRX_READ);
11753 else
11754 SET_BOTH(DRX_WRITE);
11755 uEventArg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
11756 break;
11757 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
11758 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
11759 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
11760 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
11761 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
11762 case VMX_EXIT_GDTR_IDTR_ACCESS:
11763 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
11764 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_XDTR_INSINFO_INSTR_ID))
11765 {
11766 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
11767 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
11768 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
11769 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
11770 }
11771 break;
11772
11773 case VMX_EXIT_LDTR_TR_ACCESS:
11774 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
11775 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_YYTR_INSINFO_INSTR_ID))
11776 {
11777 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
11778 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
11779 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
11780 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
11781 }
11782 break;
11783
11784 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
11785 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
11786 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
11787 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
11788 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
11789 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
11790 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
11791 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
11792 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
11793 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
11794 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
11795
11796 /* Events that aren't relevant at this point. */
11797 case VMX_EXIT_EXT_INT:
11798 case VMX_EXIT_INT_WINDOW:
11799 case VMX_EXIT_NMI_WINDOW:
11800 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11801 case VMX_EXIT_PREEMPT_TIMER:
11802 case VMX_EXIT_IO_INSTR:
11803 break;
11804
11805 /* Errors and unexpected events. */
11806 case VMX_EXIT_INIT_SIGNAL:
11807 case VMX_EXIT_SIPI:
11808 case VMX_EXIT_IO_SMI:
11809 case VMX_EXIT_SMI:
11810 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
11811 case VMX_EXIT_ERR_MSR_LOAD:
11812 case VMX_EXIT_ERR_MACHINE_CHECK:
11813 case VMX_EXIT_PML_FULL:
11814 case VMX_EXIT_VIRTUALIZED_EOI:
11815 break;
11816
11817 default:
11818 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
11819 break;
11820 }
11821#undef SET_BOTH
11822#undef SET_EXIT
11823
11824 /*
11825 * Dtrace tracepoints go first. We do them here at once so we don't
11826 * have to copy the guest state saving and stuff a few dozen times.
11827 * Down side is that we've got to repeat the switch, though this time
11828 * we use enmEvent since the probes are a subset of what DBGF does.
11829 */
11830 if (fDtrace1 || fDtrace2)
11831 {
11832 hmR0VmxReadExitQualVmcs(pVmxTransient);
11833 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
11834 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
11835 switch (enmEvent1)
11836 {
11837 /** @todo consider which extra parameters would be helpful for each probe. */
11838 case DBGFEVENT_END: break;
11839 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pCtx); break;
11840 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pCtx, pCtx->dr[6]); break;
11841 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pCtx); break;
11842 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pCtx); break;
11843 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pCtx); break;
11844 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pCtx); break;
11845 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pCtx); break;
11846 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pCtx); break;
11847 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pCtx, uEventArg); break;
11848 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pCtx, uEventArg); break;
11849 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pCtx, uEventArg); break;
11850 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pCtx, uEventArg); break;
11851 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pCtx, uEventArg, pCtx->cr2); break;
11852 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pCtx); break;
11853 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pCtx); break;
11854 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pCtx); break;
11855 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pCtx); break;
11856 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pCtx, uEventArg); break;
11857 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11858 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11859 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pCtx); break;
11860 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pCtx); break;
11861 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pCtx); break;
11862 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pCtx); break;
11863 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pCtx); break;
11864 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pCtx); break;
11865 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pCtx); break;
11866 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11867 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11868 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11869 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11870 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11871 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pCtx, pCtx->ecx,
11872 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11873 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pCtx); break;
11874 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pCtx); break;
11875 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pCtx); break;
11876 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pCtx); break;
11877 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pCtx); break;
11878 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pCtx); break;
11879 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pCtx); break;
11880 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pCtx); break;
11881 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pCtx); break;
11882 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pCtx); break;
11883 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pCtx); break;
11884 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pCtx); break;
11885 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pCtx); break;
11886 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pCtx); break;
11887 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pCtx); break;
11888 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pCtx); break;
11889 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pCtx); break;
11890 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pCtx); break;
11891 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pCtx); break;
11892 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pCtx); break;
11893 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pCtx); break;
11894 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pCtx); break;
11895 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pCtx); break;
11896 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pCtx); break;
11897 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pCtx); break;
11898 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pCtx); break;
11899 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pCtx); break;
11900 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pCtx); break;
11901 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pCtx); break;
11902 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pCtx); break;
11903 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pCtx); break;
11904 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pCtx); break;
11905 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
11906 }
11907 switch (enmEvent2)
11908 {
11909 /** @todo consider which extra parameters would be helpful for each probe. */
11910 case DBGFEVENT_END: break;
11911 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pCtx); break;
11912 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11913 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pCtx); break;
11914 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pCtx); break;
11915 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pCtx); break;
11916 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pCtx); break;
11917 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pCtx); break;
11918 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pCtx); break;
11919 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pCtx); break;
11920 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11921 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11922 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11923 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11924 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11925 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pCtx, pCtx->ecx,
11926 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11927 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pCtx); break;
11928 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pCtx); break;
11929 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pCtx); break;
11930 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pCtx); break;
11931 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pCtx); break;
11932 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pCtx); break;
11933 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pCtx); break;
11934 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pCtx); break;
11935 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pCtx); break;
11936 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pCtx); break;
11937 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pCtx); break;
11938 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pCtx); break;
11939 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pCtx); break;
11940 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pCtx); break;
11941 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pCtx); break;
11942 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pCtx); break;
11943 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pCtx); break;
11944 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pCtx); break;
11945 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pCtx); break;
11946 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pCtx); break;
11947 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pCtx); break;
11948 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pCtx); break;
11949 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pCtx); break;
11950 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pCtx); break;
11951 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pCtx); break;
11952 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pCtx); break;
11953 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pCtx); break;
11954 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pCtx); break;
11955 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pCtx); break;
11956 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pCtx); break;
11957 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pCtx); break;
11958 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pCtx); break;
11959 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pCtx); break;
11960 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pCtx); break;
11961 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pCtx); break;
11962 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pCtx); break;
11963 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
11964 }
11965 }
11966
11967 /*
11968 * Fire of the DBGF event, if enabled (our check here is just a quick one,
11969 * the DBGF call will do a full check).
11970 *
11971 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
11972 * Note! If we have to events, we prioritize the first, i.e. the instruction
11973 * one, in order to avoid event nesting.
11974 */
11975 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11976 if ( enmEvent1 != DBGFEVENT_END
11977 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
11978 {
11979 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11980 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent1, DBGFEVENTCTX_HM, 1, uEventArg);
11981 if (rcStrict != VINF_SUCCESS)
11982 return rcStrict;
11983 }
11984 else if ( enmEvent2 != DBGFEVENT_END
11985 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
11986 {
11987 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11988 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent2, DBGFEVENTCTX_HM, 1, uEventArg);
11989 if (rcStrict != VINF_SUCCESS)
11990 return rcStrict;
11991 }
11992
11993 return VINF_SUCCESS;
11994}
11995
11996
11997/**
11998 * Single-stepping VM-exit filtering.
11999 *
12000 * This is preprocessing the VM-exits and deciding whether we've gotten far
12001 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
12002 * handling is performed.
12003 *
12004 * @returns Strict VBox status code (i.e. informational status codes too).
12005 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
12006 * @param pVmxTransient The VMX-transient structure.
12007 * @param pDbgState The debug state.
12008 */
12009DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
12010{
12011 /*
12012 * Expensive (saves context) generic dtrace VM-exit probe.
12013 */
12014 uint32_t const uExitReason = pVmxTransient->uExitReason;
12015 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
12016 { /* more likely */ }
12017 else
12018 {
12019 hmR0VmxReadExitQualVmcs(pVmxTransient);
12020 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
12021 AssertRC(rc);
12022 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, &pVCpu->cpum.GstCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
12023 }
12024
12025 /*
12026 * Check for host NMI, just to get that out of the way.
12027 */
12028 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
12029 { /* normally likely */ }
12030 else
12031 {
12032 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
12033 uint32_t const uIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
12034 if (uIntType == VMX_EXIT_INT_INFO_TYPE_NMI)
12035 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
12036 }
12037
12038 /*
12039 * Check for single stepping event if we're stepping.
12040 */
12041 if (pVCpu->hm.s.fSingleInstruction)
12042 {
12043 switch (uExitReason)
12044 {
12045 case VMX_EXIT_MTF:
12046 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
12047
12048 /* Various events: */
12049 case VMX_EXIT_XCPT_OR_NMI:
12050 case VMX_EXIT_EXT_INT:
12051 case VMX_EXIT_TRIPLE_FAULT:
12052 case VMX_EXIT_INT_WINDOW:
12053 case VMX_EXIT_NMI_WINDOW:
12054 case VMX_EXIT_TASK_SWITCH:
12055 case VMX_EXIT_TPR_BELOW_THRESHOLD:
12056 case VMX_EXIT_APIC_ACCESS:
12057 case VMX_EXIT_EPT_VIOLATION:
12058 case VMX_EXIT_EPT_MISCONFIG:
12059 case VMX_EXIT_PREEMPT_TIMER:
12060
12061 /* Instruction specific VM-exits: */
12062 case VMX_EXIT_CPUID:
12063 case VMX_EXIT_GETSEC:
12064 case VMX_EXIT_HLT:
12065 case VMX_EXIT_INVD:
12066 case VMX_EXIT_INVLPG:
12067 case VMX_EXIT_RDPMC:
12068 case VMX_EXIT_RDTSC:
12069 case VMX_EXIT_RSM:
12070 case VMX_EXIT_VMCALL:
12071 case VMX_EXIT_VMCLEAR:
12072 case VMX_EXIT_VMLAUNCH:
12073 case VMX_EXIT_VMPTRLD:
12074 case VMX_EXIT_VMPTRST:
12075 case VMX_EXIT_VMREAD:
12076 case VMX_EXIT_VMRESUME:
12077 case VMX_EXIT_VMWRITE:
12078 case VMX_EXIT_VMXOFF:
12079 case VMX_EXIT_VMXON:
12080 case VMX_EXIT_MOV_CRX:
12081 case VMX_EXIT_MOV_DRX:
12082 case VMX_EXIT_IO_INSTR:
12083 case VMX_EXIT_RDMSR:
12084 case VMX_EXIT_WRMSR:
12085 case VMX_EXIT_MWAIT:
12086 case VMX_EXIT_MONITOR:
12087 case VMX_EXIT_PAUSE:
12088 case VMX_EXIT_GDTR_IDTR_ACCESS:
12089 case VMX_EXIT_LDTR_TR_ACCESS:
12090 case VMX_EXIT_INVEPT:
12091 case VMX_EXIT_RDTSCP:
12092 case VMX_EXIT_INVVPID:
12093 case VMX_EXIT_WBINVD:
12094 case VMX_EXIT_XSETBV:
12095 case VMX_EXIT_RDRAND:
12096 case VMX_EXIT_INVPCID:
12097 case VMX_EXIT_VMFUNC:
12098 case VMX_EXIT_RDSEED:
12099 case VMX_EXIT_XSAVES:
12100 case VMX_EXIT_XRSTORS:
12101 {
12102 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12103 AssertRCReturn(rc, rc);
12104 if ( pVCpu->cpum.GstCtx.rip != pDbgState->uRipStart
12105 || pVCpu->cpum.GstCtx.cs.Sel != pDbgState->uCsStart)
12106 return VINF_EM_DBG_STEPPED;
12107 break;
12108 }
12109
12110 /* Errors and unexpected events: */
12111 case VMX_EXIT_INIT_SIGNAL:
12112 case VMX_EXIT_SIPI:
12113 case VMX_EXIT_IO_SMI:
12114 case VMX_EXIT_SMI:
12115 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
12116 case VMX_EXIT_ERR_MSR_LOAD:
12117 case VMX_EXIT_ERR_MACHINE_CHECK:
12118 case VMX_EXIT_PML_FULL:
12119 case VMX_EXIT_VIRTUALIZED_EOI:
12120 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
12121 break;
12122
12123 default:
12124 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12125 break;
12126 }
12127 }
12128
12129 /*
12130 * Check for debugger event breakpoints and dtrace probes.
12131 */
12132 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
12133 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
12134 {
12135 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVCpu, pVmxTransient, uExitReason);
12136 if (rcStrict != VINF_SUCCESS)
12137 return rcStrict;
12138 }
12139
12140 /*
12141 * Normal processing.
12142 */
12143#ifdef HMVMX_USE_FUNCTION_TABLE
12144 return g_apfnVMExitHandlers[uExitReason](pVCpu, pVmxTransient);
12145#else
12146 return hmR0VmxHandleExit(pVCpu, pVmxTransient, uExitReason);
12147#endif
12148}
12149
12150
12151/**
12152 * Single steps guest code using hardware-assisted VMX.
12153 *
12154 * This is -not- the same as the guest single-stepping itself (say using EFLAGS.TF)
12155 * but single-stepping through the hypervisor debugger.
12156 *
12157 * @returns Strict VBox status code (i.e. informational status codes too).
12158 * @param pVCpu The cross context virtual CPU structure.
12159 * @param pcLoops Pointer to the number of executed loops.
12160 *
12161 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
12162 */
12163static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVMCPUCC pVCpu, uint32_t *pcLoops)
12164{
12165 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
12166 Assert(pcLoops);
12167 Assert(*pcLoops <= cMaxResumeLoops);
12168
12169 VMXTRANSIENT VmxTransient;
12170 RT_ZERO(VmxTransient);
12171 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
12172
12173 /* Set HMCPU indicators. */
12174 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
12175 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
12176 pVCpu->hm.s.fDebugWantRdTscExit = false;
12177 pVCpu->hm.s.fUsingDebugLoop = true;
12178
12179 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
12180 VMXRUNDBGSTATE DbgState;
12181 hmR0VmxRunDebugStateInit(pVCpu, &VmxTransient, &DbgState);
12182 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12183
12184 /*
12185 * The loop.
12186 */
12187 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
12188 for (;;)
12189 {
12190 Assert(!HMR0SuspendPending());
12191 HMVMX_ASSERT_CPU_SAFE(pVCpu);
12192 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
12193 bool fStepping = pVCpu->hm.s.fSingleInstruction;
12194
12195 /* Set up VM-execution controls the next two can respond to. */
12196 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12197
12198 /*
12199 * Preparatory work for running guest code, this may force us to
12200 * return to ring-3.
12201 *
12202 * Warning! This bugger disables interrupts on VINF_SUCCESS!
12203 */
12204 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, fStepping);
12205 if (rcStrict != VINF_SUCCESS)
12206 break;
12207
12208 /* Interrupts are disabled at this point! */
12209 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
12210
12211 /* Override any obnoxious code in the above two calls. */
12212 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12213
12214 /*
12215 * Finally execute the guest.
12216 */
12217 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
12218
12219 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
12220 /* Interrupts are re-enabled at this point! */
12221
12222 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
12223 if (RT_SUCCESS(rcRun))
12224 { /* very likely */ }
12225 else
12226 {
12227 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
12228 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
12229 return rcRun;
12230 }
12231
12232 /* Profile the VM-exit. */
12233 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
12234 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
12235 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
12236 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
12237 HMVMX_START_EXIT_DISPATCH_PROF();
12238
12239 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
12240
12241 /*
12242 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
12243 */
12244 rcStrict = hmR0VmxRunDebugHandleExit(pVCpu, &VmxTransient, &DbgState);
12245 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
12246 if (rcStrict != VINF_SUCCESS)
12247 break;
12248 if (++(*pcLoops) > cMaxResumeLoops)
12249 {
12250 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
12251 rcStrict = VINF_EM_RAW_INTERRUPT;
12252 break;
12253 }
12254
12255 /*
12256 * Stepping: Did the RIP change, if so, consider it a single step.
12257 * Otherwise, make sure one of the TFs gets set.
12258 */
12259 if (fStepping)
12260 {
12261 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12262 AssertRC(rc);
12263 if ( pVCpu->cpum.GstCtx.rip != DbgState.uRipStart
12264 || pVCpu->cpum.GstCtx.cs.Sel != DbgState.uCsStart)
12265 {
12266 rcStrict = VINF_EM_DBG_STEPPED;
12267 break;
12268 }
12269 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
12270 }
12271
12272 /*
12273 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
12274 */
12275 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
12276 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12277 }
12278
12279 /*
12280 * Clear the X86_EFL_TF if necessary.
12281 */
12282 if (pVCpu->hm.s.fClearTrapFlag)
12283 {
12284 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
12285 AssertRC(rc);
12286 pVCpu->hm.s.fClearTrapFlag = false;
12287 pVCpu->cpum.GstCtx.eflags.Bits.u1TF = 0;
12288 }
12289 /** @todo there seems to be issues with the resume flag when the monitor trap
12290 * flag is pending without being used. Seen early in bios init when
12291 * accessing APIC page in protected mode. */
12292
12293 /*
12294 * Restore VM-exit control settings as we may not re-enter this function the
12295 * next time around.
12296 */
12297 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &VmxTransient, &DbgState, rcStrict);
12298
12299 /* Restore HMCPU indicators. */
12300 pVCpu->hm.s.fUsingDebugLoop = false;
12301 pVCpu->hm.s.fDebugWantRdTscExit = false;
12302 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
12303
12304 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
12305 return rcStrict;
12306}
12307
12308
12309/** @} */
12310
12311
12312/**
12313 * Checks if any expensive dtrace probes are enabled and we should go to the
12314 * debug loop.
12315 *
12316 * @returns true if we should use debug loop, false if not.
12317 */
12318static bool hmR0VmxAnyExpensiveProbesEnabled(void)
12319{
12320 /* It's probably faster to OR the raw 32-bit counter variables together.
12321 Since the variables are in an array and the probes are next to one
12322 another (more or less), we have good locality. So, better read
12323 eight-nine cache lines ever time and only have one conditional, than
12324 128+ conditionals, right? */
12325 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
12326 | VBOXVMM_XCPT_DE_ENABLED_RAW()
12327 | VBOXVMM_XCPT_DB_ENABLED_RAW()
12328 | VBOXVMM_XCPT_BP_ENABLED_RAW()
12329 | VBOXVMM_XCPT_OF_ENABLED_RAW()
12330 | VBOXVMM_XCPT_BR_ENABLED_RAW()
12331 | VBOXVMM_XCPT_UD_ENABLED_RAW()
12332 | VBOXVMM_XCPT_NM_ENABLED_RAW()
12333 | VBOXVMM_XCPT_DF_ENABLED_RAW()
12334 | VBOXVMM_XCPT_TS_ENABLED_RAW()
12335 | VBOXVMM_XCPT_NP_ENABLED_RAW()
12336 | VBOXVMM_XCPT_SS_ENABLED_RAW()
12337 | VBOXVMM_XCPT_GP_ENABLED_RAW()
12338 | VBOXVMM_XCPT_PF_ENABLED_RAW()
12339 | VBOXVMM_XCPT_MF_ENABLED_RAW()
12340 | VBOXVMM_XCPT_AC_ENABLED_RAW()
12341 | VBOXVMM_XCPT_XF_ENABLED_RAW()
12342 | VBOXVMM_XCPT_VE_ENABLED_RAW()
12343 | VBOXVMM_XCPT_SX_ENABLED_RAW()
12344 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
12345 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
12346 ) != 0
12347 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
12348 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
12349 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
12350 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
12351 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
12352 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
12353 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
12354 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
12355 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
12356 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
12357 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
12358 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
12359 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
12360 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
12361 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
12362 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
12363 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
12364 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
12365 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
12366 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
12367 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
12368 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
12369 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
12370 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
12371 | VBOXVMM_INSTR_STR_ENABLED_RAW()
12372 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
12373 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
12374 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
12375 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
12376 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
12377 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
12378 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
12379 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
12380 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
12381 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
12382 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
12383 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
12384 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
12385 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
12386 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
12387 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
12388 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
12389 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
12390 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
12391 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
12392 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
12393 ) != 0
12394 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
12395 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
12396 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
12397 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
12398 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
12399 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
12400 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
12401 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
12402 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
12403 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
12404 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
12405 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
12406 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
12407 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
12408 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
12409 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
12410 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
12411 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
12412 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
12413 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
12414 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
12415 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
12416 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
12417 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
12418 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
12419 | VBOXVMM_EXIT_STR_ENABLED_RAW()
12420 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
12421 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
12422 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
12423 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
12424 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
12425 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
12426 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
12427 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
12428 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
12429 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
12430 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
12431 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
12432 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
12433 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
12434 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
12435 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
12436 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
12437 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
12438 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
12439 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
12440 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
12441 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
12442 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
12443 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
12444 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
12445 ) != 0;
12446}
12447
12448
12449/**
12450 * Runs the guest using hardware-assisted VMX.
12451 *
12452 * @returns Strict VBox status code (i.e. informational status codes too).
12453 * @param pVCpu The cross context virtual CPU structure.
12454 */
12455VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVMCPUCC pVCpu)
12456{
12457 AssertPtr(pVCpu);
12458 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12459 Assert(VMMRZCallRing3IsEnabled(pVCpu));
12460 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12461 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
12462
12463 VBOXSTRICTRC rcStrict;
12464 uint32_t cLoops = 0;
12465 for (;;)
12466 {
12467#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12468 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(pCtx);
12469#else
12470 NOREF(pCtx);
12471 bool const fInNestedGuestMode = false;
12472#endif
12473 if (!fInNestedGuestMode)
12474 {
12475 if ( !pVCpu->hm.s.fUseDebugLoop
12476 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
12477 && !DBGFIsStepping(pVCpu)
12478 && !pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
12479 rcStrict = hmR0VmxRunGuestCodeNormal(pVCpu, &cLoops);
12480 else
12481 rcStrict = hmR0VmxRunGuestCodeDebug(pVCpu, &cLoops);
12482 }
12483#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12484 else
12485 rcStrict = hmR0VmxRunGuestCodeNested(pVCpu, &cLoops);
12486
12487 if (rcStrict == VINF_VMX_VMLAUNCH_VMRESUME)
12488 {
12489 Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
12490 continue;
12491 }
12492 if (rcStrict == VINF_VMX_VMEXIT)
12493 {
12494 Assert(!CPUMIsGuestInVmxNonRootMode(pCtx));
12495 continue;
12496 }
12497#endif
12498 break;
12499 }
12500
12501 int const rcLoop = VBOXSTRICTRC_VAL(rcStrict);
12502 switch (rcLoop)
12503 {
12504 case VERR_EM_INTERPRETER: rcStrict = VINF_EM_RAW_EMULATE_INSTR; break;
12505 case VINF_EM_RESET: rcStrict = VINF_EM_TRIPLE_FAULT; break;
12506 }
12507
12508 int rc2 = hmR0VmxExitToRing3(pVCpu, rcStrict);
12509 if (RT_FAILURE(rc2))
12510 {
12511 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
12512 rcStrict = rc2;
12513 }
12514 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12515 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
12516 return rcStrict;
12517}
12518
12519
12520#ifndef HMVMX_USE_FUNCTION_TABLE
12521/**
12522 * Handles a guest VM-exit from hardware-assisted VMX execution.
12523 *
12524 * @returns Strict VBox status code (i.e. informational status codes too).
12525 * @param pVCpu The cross context virtual CPU structure.
12526 * @param pVmxTransient The VMX-transient structure.
12527 */
12528DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12529{
12530#ifdef DEBUG_ramshankar
12531# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) \
12532 do { \
12533 if (a_fSave != 0) \
12534 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL); \
12535 VBOXSTRICTRC rcStrict = a_CallExpr; \
12536 if (a_fSave != 0) \
12537 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST); \
12538 return rcStrict; \
12539 } while (0)
12540#else
12541# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) return a_CallExpr
12542#endif
12543 uint32_t const uExitReason = pVmxTransient->uExitReason;
12544 switch (uExitReason)
12545 {
12546 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient));
12547 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, hmR0VmxExitEptViolation(pVCpu, pVmxTransient));
12548 case VMX_EXIT_IO_INSTR: VMEXIT_CALL_RET(0, hmR0VmxExitIoInstr(pVCpu, pVmxTransient));
12549 case VMX_EXIT_CPUID: VMEXIT_CALL_RET(0, hmR0VmxExitCpuid(pVCpu, pVmxTransient));
12550 case VMX_EXIT_RDTSC: VMEXIT_CALL_RET(0, hmR0VmxExitRdtsc(pVCpu, pVmxTransient));
12551 case VMX_EXIT_RDTSCP: VMEXIT_CALL_RET(0, hmR0VmxExitRdtscp(pVCpu, pVmxTransient));
12552 case VMX_EXIT_APIC_ACCESS: VMEXIT_CALL_RET(0, hmR0VmxExitApicAccess(pVCpu, pVmxTransient));
12553 case VMX_EXIT_XCPT_OR_NMI: VMEXIT_CALL_RET(0, hmR0VmxExitXcptOrNmi(pVCpu, pVmxTransient));
12554 case VMX_EXIT_MOV_CRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovCRx(pVCpu, pVmxTransient));
12555 case VMX_EXIT_EXT_INT: VMEXIT_CALL_RET(0, hmR0VmxExitExtInt(pVCpu, pVmxTransient));
12556 case VMX_EXIT_INT_WINDOW: VMEXIT_CALL_RET(0, hmR0VmxExitIntWindow(pVCpu, pVmxTransient));
12557 case VMX_EXIT_TPR_BELOW_THRESHOLD: VMEXIT_CALL_RET(0, hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient));
12558 case VMX_EXIT_MWAIT: VMEXIT_CALL_RET(0, hmR0VmxExitMwait(pVCpu, pVmxTransient));
12559 case VMX_EXIT_MONITOR: VMEXIT_CALL_RET(0, hmR0VmxExitMonitor(pVCpu, pVmxTransient));
12560 case VMX_EXIT_TASK_SWITCH: VMEXIT_CALL_RET(0, hmR0VmxExitTaskSwitch(pVCpu, pVmxTransient));
12561 case VMX_EXIT_PREEMPT_TIMER: VMEXIT_CALL_RET(0, hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient));
12562 case VMX_EXIT_RDMSR: VMEXIT_CALL_RET(0, hmR0VmxExitRdmsr(pVCpu, pVmxTransient));
12563 case VMX_EXIT_WRMSR: VMEXIT_CALL_RET(0, hmR0VmxExitWrmsr(pVCpu, pVmxTransient));
12564 case VMX_EXIT_VMCALL: VMEXIT_CALL_RET(0, hmR0VmxExitVmcall(pVCpu, pVmxTransient));
12565 case VMX_EXIT_MOV_DRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovDRx(pVCpu, pVmxTransient));
12566 case VMX_EXIT_HLT: VMEXIT_CALL_RET(0, hmR0VmxExitHlt(pVCpu, pVmxTransient));
12567 case VMX_EXIT_INVD: VMEXIT_CALL_RET(0, hmR0VmxExitInvd(pVCpu, pVmxTransient));
12568 case VMX_EXIT_INVLPG: VMEXIT_CALL_RET(0, hmR0VmxExitInvlpg(pVCpu, pVmxTransient));
12569 case VMX_EXIT_MTF: VMEXIT_CALL_RET(0, hmR0VmxExitMtf(pVCpu, pVmxTransient));
12570 case VMX_EXIT_PAUSE: VMEXIT_CALL_RET(0, hmR0VmxExitPause(pVCpu, pVmxTransient));
12571 case VMX_EXIT_WBINVD: VMEXIT_CALL_RET(0, hmR0VmxExitWbinvd(pVCpu, pVmxTransient));
12572 case VMX_EXIT_XSETBV: VMEXIT_CALL_RET(0, hmR0VmxExitXsetbv(pVCpu, pVmxTransient));
12573 case VMX_EXIT_INVPCID: VMEXIT_CALL_RET(0, hmR0VmxExitInvpcid(pVCpu, pVmxTransient));
12574 case VMX_EXIT_GETSEC: VMEXIT_CALL_RET(0, hmR0VmxExitGetsec(pVCpu, pVmxTransient));
12575 case VMX_EXIT_RDPMC: VMEXIT_CALL_RET(0, hmR0VmxExitRdpmc(pVCpu, pVmxTransient));
12576#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12577 case VMX_EXIT_VMCLEAR: VMEXIT_CALL_RET(0, hmR0VmxExitVmclear(pVCpu, pVmxTransient));
12578 case VMX_EXIT_VMLAUNCH: VMEXIT_CALL_RET(0, hmR0VmxExitVmlaunch(pVCpu, pVmxTransient));
12579 case VMX_EXIT_VMPTRLD: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrld(pVCpu, pVmxTransient));
12580 case VMX_EXIT_VMPTRST: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrst(pVCpu, pVmxTransient));
12581 case VMX_EXIT_VMREAD: VMEXIT_CALL_RET(0, hmR0VmxExitVmread(pVCpu, pVmxTransient));
12582 case VMX_EXIT_VMRESUME: VMEXIT_CALL_RET(0, hmR0VmxExitVmwrite(pVCpu, pVmxTransient));
12583 case VMX_EXIT_VMWRITE: VMEXIT_CALL_RET(0, hmR0VmxExitVmresume(pVCpu, pVmxTransient));
12584 case VMX_EXIT_VMXOFF: VMEXIT_CALL_RET(0, hmR0VmxExitVmxoff(pVCpu, pVmxTransient));
12585 case VMX_EXIT_VMXON: VMEXIT_CALL_RET(0, hmR0VmxExitVmxon(pVCpu, pVmxTransient));
12586 case VMX_EXIT_INVVPID: VMEXIT_CALL_RET(0, hmR0VmxExitInvvpid(pVCpu, pVmxTransient));
12587 case VMX_EXIT_INVEPT: VMEXIT_CALL_RET(0, hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient));
12588#else
12589 case VMX_EXIT_VMCLEAR:
12590 case VMX_EXIT_VMLAUNCH:
12591 case VMX_EXIT_VMPTRLD:
12592 case VMX_EXIT_VMPTRST:
12593 case VMX_EXIT_VMREAD:
12594 case VMX_EXIT_VMRESUME:
12595 case VMX_EXIT_VMWRITE:
12596 case VMX_EXIT_VMXOFF:
12597 case VMX_EXIT_VMXON:
12598 case VMX_EXIT_INVVPID:
12599 case VMX_EXIT_INVEPT:
12600 return hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient);
12601#endif
12602
12603 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pVmxTransient);
12604 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pVmxTransient);
12605 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
12606
12607 case VMX_EXIT_INIT_SIGNAL:
12608 case VMX_EXIT_SIPI:
12609 case VMX_EXIT_IO_SMI:
12610 case VMX_EXIT_SMI:
12611 case VMX_EXIT_ERR_MSR_LOAD:
12612 case VMX_EXIT_ERR_MACHINE_CHECK:
12613 case VMX_EXIT_PML_FULL:
12614 case VMX_EXIT_VIRTUALIZED_EOI:
12615 case VMX_EXIT_GDTR_IDTR_ACCESS:
12616 case VMX_EXIT_LDTR_TR_ACCESS:
12617 case VMX_EXIT_APIC_WRITE:
12618 case VMX_EXIT_RDRAND:
12619 case VMX_EXIT_RSM:
12620 case VMX_EXIT_VMFUNC:
12621 case VMX_EXIT_ENCLS:
12622 case VMX_EXIT_RDSEED:
12623 case VMX_EXIT_XSAVES:
12624 case VMX_EXIT_XRSTORS:
12625 case VMX_EXIT_UMWAIT:
12626 case VMX_EXIT_TPAUSE:
12627 default:
12628 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
12629 }
12630#undef VMEXIT_CALL_RET
12631}
12632#endif /* !HMVMX_USE_FUNCTION_TABLE */
12633
12634
12635#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12636/**
12637 * Handles a nested-guest VM-exit from hardware-assisted VMX execution.
12638 *
12639 * @returns Strict VBox status code (i.e. informational status codes too).
12640 * @param pVCpu The cross context virtual CPU structure.
12641 * @param pVmxTransient The VMX-transient structure.
12642 */
12643DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12644{
12645 /** @todo NSTVMX: Remove after debugging page-fault issue. */
12646#ifdef DEBUG_ramshankar
12647 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
12648 Log4Func(("cs:rip=%#04x:%#RX64 rsp=%#RX64 eflags=%#RX32 cr3=%#RX64\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
12649 pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u32, pVCpu->cpum.GstCtx.cr3));
12650#endif
12651
12652 uint32_t const uExitReason = pVmxTransient->uExitReason;
12653 switch (uExitReason)
12654 {
12655 case VMX_EXIT_EPT_MISCONFIG: return hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient);
12656 case VMX_EXIT_EPT_VIOLATION: return hmR0VmxExitEptViolation(pVCpu, pVmxTransient);
12657 case VMX_EXIT_XCPT_OR_NMI: return hmR0VmxExitXcptOrNmiNested(pVCpu, pVmxTransient);
12658 case VMX_EXIT_IO_INSTR: return hmR0VmxExitIoInstrNested(pVCpu, pVmxTransient);
12659 case VMX_EXIT_HLT: return hmR0VmxExitHltNested(pVCpu, pVmxTransient);
12660
12661 /*
12662 * We shouldn't direct host physical interrupts to the nested-guest.
12663 */
12664 case VMX_EXIT_EXT_INT:
12665 return hmR0VmxExitExtInt(pVCpu, pVmxTransient);
12666
12667 /*
12668 * Instructions that cause VM-exits unconditionally or the condition is
12669 * always is taken solely from the nested hypervisor (meaning if the VM-exit
12670 * happens, it's guaranteed to be a nested-guest VM-exit).
12671 *
12672 * - Provides VM-exit instruction length ONLY.
12673 */
12674 case VMX_EXIT_CPUID: /* Unconditional. */
12675 case VMX_EXIT_VMCALL:
12676 case VMX_EXIT_GETSEC:
12677 case VMX_EXIT_INVD:
12678 case VMX_EXIT_XSETBV:
12679 case VMX_EXIT_VMLAUNCH:
12680 case VMX_EXIT_VMRESUME:
12681 case VMX_EXIT_VMXOFF:
12682 case VMX_EXIT_ENCLS: /* Condition specified solely by nested hypervisor. */
12683 case VMX_EXIT_VMFUNC:
12684 return hmR0VmxExitInstrNested(pVCpu, pVmxTransient);
12685
12686 /*
12687 * Instructions that cause VM-exits unconditionally or the condition is
12688 * always is taken solely from the nested hypervisor (meaning if the VM-exit
12689 * happens, it's guaranteed to be a nested-guest VM-exit).
12690 *
12691 * - Provides VM-exit instruction length.
12692 * - Provides VM-exit information.
12693 * - Optionally provides Exit qualification.
12694 *
12695 * Since Exit qualification is 0 for all VM-exits where it is not
12696 * applicable, reading and passing it to the guest should produce
12697 * defined behavior.
12698 *
12699 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
12700 */
12701 case VMX_EXIT_INVEPT: /* Unconditional. */
12702 case VMX_EXIT_INVVPID:
12703 case VMX_EXIT_VMCLEAR:
12704 case VMX_EXIT_VMPTRLD:
12705 case VMX_EXIT_VMPTRST:
12706 case VMX_EXIT_VMXON:
12707 case VMX_EXIT_GDTR_IDTR_ACCESS: /* Condition specified solely by nested hypervisor. */
12708 case VMX_EXIT_LDTR_TR_ACCESS:
12709 case VMX_EXIT_RDRAND:
12710 case VMX_EXIT_RDSEED:
12711 case VMX_EXIT_XSAVES:
12712 case VMX_EXIT_XRSTORS:
12713 case VMX_EXIT_UMWAIT:
12714 case VMX_EXIT_TPAUSE:
12715 return hmR0VmxExitInstrWithInfoNested(pVCpu, pVmxTransient);
12716
12717 case VMX_EXIT_RDTSC: return hmR0VmxExitRdtscNested(pVCpu, pVmxTransient);
12718 case VMX_EXIT_RDTSCP: return hmR0VmxExitRdtscpNested(pVCpu, pVmxTransient);
12719 case VMX_EXIT_RDMSR: return hmR0VmxExitRdmsrNested(pVCpu, pVmxTransient);
12720 case VMX_EXIT_WRMSR: return hmR0VmxExitWrmsrNested(pVCpu, pVmxTransient);
12721 case VMX_EXIT_INVLPG: return hmR0VmxExitInvlpgNested(pVCpu, pVmxTransient);
12722 case VMX_EXIT_INVPCID: return hmR0VmxExitInvpcidNested(pVCpu, pVmxTransient);
12723 case VMX_EXIT_TASK_SWITCH: return hmR0VmxExitTaskSwitchNested(pVCpu, pVmxTransient);
12724 case VMX_EXIT_WBINVD: return hmR0VmxExitWbinvdNested(pVCpu, pVmxTransient);
12725 case VMX_EXIT_MTF: return hmR0VmxExitMtfNested(pVCpu, pVmxTransient);
12726 case VMX_EXIT_APIC_ACCESS: return hmR0VmxExitApicAccessNested(pVCpu, pVmxTransient);
12727 case VMX_EXIT_APIC_WRITE: return hmR0VmxExitApicWriteNested(pVCpu, pVmxTransient);
12728 case VMX_EXIT_VIRTUALIZED_EOI: return hmR0VmxExitVirtEoiNested(pVCpu, pVmxTransient);
12729 case VMX_EXIT_MOV_CRX: return hmR0VmxExitMovCRxNested(pVCpu, pVmxTransient);
12730 case VMX_EXIT_INT_WINDOW: return hmR0VmxExitIntWindowNested(pVCpu, pVmxTransient);
12731 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindowNested(pVCpu, pVmxTransient);
12732 case VMX_EXIT_TPR_BELOW_THRESHOLD: return hmR0VmxExitTprBelowThresholdNested(pVCpu, pVmxTransient);
12733 case VMX_EXIT_MWAIT: return hmR0VmxExitMwaitNested(pVCpu, pVmxTransient);
12734 case VMX_EXIT_MONITOR: return hmR0VmxExitMonitorNested(pVCpu, pVmxTransient);
12735 case VMX_EXIT_PAUSE: return hmR0VmxExitPauseNested(pVCpu, pVmxTransient);
12736
12737 case VMX_EXIT_PREEMPT_TIMER:
12738 {
12739 /** @todo NSTVMX: Preempt timer. */
12740 return hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient);
12741 }
12742
12743 case VMX_EXIT_MOV_DRX: return hmR0VmxExitMovDRxNested(pVCpu, pVmxTransient);
12744 case VMX_EXIT_RDPMC: return hmR0VmxExitRdpmcNested(pVCpu, pVmxTransient);
12745
12746 case VMX_EXIT_VMREAD:
12747 case VMX_EXIT_VMWRITE: return hmR0VmxExitVmreadVmwriteNested(pVCpu, pVmxTransient);
12748
12749 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFaultNested(pVCpu, pVmxTransient);
12750 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestStateNested(pVCpu, pVmxTransient);
12751
12752 case VMX_EXIT_INIT_SIGNAL:
12753 case VMX_EXIT_SIPI:
12754 case VMX_EXIT_IO_SMI:
12755 case VMX_EXIT_SMI:
12756 case VMX_EXIT_ERR_MSR_LOAD:
12757 case VMX_EXIT_ERR_MACHINE_CHECK:
12758 case VMX_EXIT_PML_FULL:
12759 case VMX_EXIT_RSM:
12760 default:
12761 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
12762 }
12763}
12764#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
12765
12766
12767/** @name VM-exit helpers.
12768 * @{
12769 */
12770/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12771/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= VM-exit helpers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
12772/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12773
12774/** Macro for VM-exits called unexpectedly. */
12775#define HMVMX_UNEXPECTED_EXIT_RET(a_pVCpu, a_HmError) \
12776 do { \
12777 (a_pVCpu)->hm.s.u32HMError = (a_HmError); \
12778 return VERR_VMX_UNEXPECTED_EXIT; \
12779 } while (0)
12780
12781#ifdef VBOX_STRICT
12782/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
12783# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
12784 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
12785
12786# define HMVMX_ASSERT_PREEMPT_CPUID() \
12787 do { \
12788 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
12789 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
12790 } while (0)
12791
12792# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12793 do { \
12794 AssertPtr((a_pVCpu)); \
12795 AssertPtr((a_pVmxTransient)); \
12796 Assert((a_pVmxTransient)->fVMEntryFailed == false); \
12797 Assert((a_pVmxTransient)->pVmcsInfo); \
12798 Assert(ASMIntAreEnabled()); \
12799 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
12800 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
12801 Log4Func(("vcpu[%RU32]\n", (a_pVCpu)->idCpu)); \
12802 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
12803 if (VMMR0IsLogFlushDisabled((a_pVCpu))) \
12804 HMVMX_ASSERT_PREEMPT_CPUID(); \
12805 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
12806 } while (0)
12807
12808# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12809 do { \
12810 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); \
12811 Assert((a_pVmxTransient)->fIsNestedGuest); \
12812 } while (0)
12813
12814# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12815 do { \
12816 Log4Func(("\n")); \
12817 } while (0)
12818#else
12819# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12820 do { \
12821 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
12822 NOREF((a_pVCpu)); NOREF((a_pVmxTransient)); \
12823 } while (0)
12824
12825# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12826 do { HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); } while (0)
12827
12828# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) do { } while (0)
12829#endif
12830
12831#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12832/** Macro that does the necessary privilege checks and intercepted VM-exits for
12833 * guests that attempted to execute a VMX instruction. */
12834# define HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(a_pVCpu, a_uExitReason) \
12835 do \
12836 { \
12837 VBOXSTRICTRC rcStrictTmp = hmR0VmxCheckExitDueToVmxInstr((a_pVCpu), (a_uExitReason)); \
12838 if (rcStrictTmp == VINF_SUCCESS) \
12839 { /* likely */ } \
12840 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
12841 { \
12842 Assert((a_pVCpu)->hm.s.Event.fPending); \
12843 Log4Func(("Privilege checks failed -> %#x\n", VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo))); \
12844 return VINF_SUCCESS; \
12845 } \
12846 else \
12847 { \
12848 int rcTmp = VBOXSTRICTRC_VAL(rcStrictTmp); \
12849 AssertMsgFailedReturn(("Unexpected failure. rc=%Rrc", rcTmp), rcTmp); \
12850 } \
12851 } while (0)
12852
12853/** Macro that decodes a memory operand for an VM-exit caused by an instruction. */
12854# define HMVMX_DECODE_MEM_OPERAND(a_pVCpu, a_uExitInstrInfo, a_uExitQual, a_enmMemAccess, a_pGCPtrEffAddr) \
12855 do \
12856 { \
12857 VBOXSTRICTRC rcStrictTmp = hmR0VmxDecodeMemOperand((a_pVCpu), (a_uExitInstrInfo), (a_uExitQual), (a_enmMemAccess), \
12858 (a_pGCPtrEffAddr)); \
12859 if (rcStrictTmp == VINF_SUCCESS) \
12860 { /* likely */ } \
12861 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
12862 { \
12863 uint8_t const uXcptTmp = VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo); \
12864 Log4Func(("Memory operand decoding failed, raising xcpt %#x\n", uXcptTmp)); \
12865 NOREF(uXcptTmp); \
12866 return VINF_SUCCESS; \
12867 } \
12868 else \
12869 { \
12870 Log4Func(("hmR0VmxDecodeMemOperand failed. rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrictTmp))); \
12871 return rcStrictTmp; \
12872 } \
12873 } while (0)
12874#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
12875
12876
12877/**
12878 * Advances the guest RIP by the specified number of bytes.
12879 *
12880 * @param pVCpu The cross context virtual CPU structure.
12881 * @param cbInstr Number of bytes to advance the RIP by.
12882 *
12883 * @remarks No-long-jump zone!!!
12884 */
12885DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPUCC pVCpu, uint32_t cbInstr)
12886{
12887 /* Advance the RIP. */
12888 pVCpu->cpum.GstCtx.rip += cbInstr;
12889 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
12890
12891 /* Update interrupt inhibition. */
12892 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
12893 && pVCpu->cpum.GstCtx.rip != EMGetInhibitInterruptsPC(pVCpu))
12894 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
12895}
12896
12897
12898/**
12899 * Advances the guest RIP after reading it from the VMCS.
12900 *
12901 * @returns VBox status code, no informational status codes.
12902 * @param pVCpu The cross context virtual CPU structure.
12903 * @param pVmxTransient The VMX-transient structure.
12904 *
12905 * @remarks No-long-jump zone!!!
12906 */
12907static int hmR0VmxAdvanceGuestRip(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12908{
12909 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12910 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
12911 AssertRCReturn(rc, rc);
12912
12913 hmR0VmxAdvanceGuestRipBy(pVCpu, pVmxTransient->cbExitInstr);
12914 return VINF_SUCCESS;
12915}
12916
12917
12918/**
12919 * Handle a condition that occurred while delivering an event through the guest or
12920 * nested-guest IDT.
12921 *
12922 * @returns Strict VBox status code (i.e. informational status codes too).
12923 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
12924 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
12925 * to continue execution of the guest which will delivery the \#DF.
12926 * @retval VINF_EM_RESET if we detected a triple-fault condition.
12927 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
12928 *
12929 * @param pVCpu The cross context virtual CPU structure.
12930 * @param pVmxTransient The VMX-transient structure.
12931 *
12932 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
12933 * Additionally, HMVMX_READ_EXIT_QUALIFICATION is required if the VM-exit
12934 * is due to an EPT violation, PML full or SPP-related event.
12935 *
12936 * @remarks No-long-jump zone!!!
12937 */
12938static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12939{
12940 Assert(!pVCpu->hm.s.Event.fPending);
12941 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
12942 if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
12943 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
12944 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
12945 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_EXIT_QUALIFICATION);
12946
12947 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
12948 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
12949 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo;
12950 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
12951 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo))
12952 {
12953 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo);
12954 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo);
12955
12956 /*
12957 * If the event was a software interrupt (generated with INT n) or a software exception
12958 * (generated by INT3/INTO) or a privileged software exception (generated by INT1), we
12959 * can handle the VM-exit and continue guest execution which will re-execute the
12960 * instruction rather than re-injecting the exception, as that can cause premature
12961 * trips to ring-3 before injection and involve TRPM which currently has no way of
12962 * storing that these exceptions were caused by these instructions (ICEBP's #DB poses
12963 * the problem).
12964 */
12965 IEMXCPTRAISE enmRaise;
12966 IEMXCPTRAISEINFO fRaiseInfo;
12967 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
12968 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
12969 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
12970 {
12971 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
12972 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
12973 }
12974 else if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo))
12975 {
12976 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
12977 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo);
12978 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT);
12979
12980 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
12981 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
12982
12983 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo);
12984
12985 /* Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF(). */
12986 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
12987 {
12988 pVmxTransient->fVectoringPF = true;
12989 enmRaise = IEMXCPTRAISE_PREV_EVENT;
12990 }
12991 }
12992 else
12993 {
12994 /*
12995 * If an exception or hardware interrupt delivery caused an EPT violation/misconfig or APIC access
12996 * VM-exit, then the VM-exit interruption-information will not be valid and we end up here.
12997 * It is sufficient to reflect the original event to the guest after handling the VM-exit.
12998 */
12999 Assert( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
13000 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
13001 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
13002 enmRaise = IEMXCPTRAISE_PREV_EVENT;
13003 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
13004 }
13005
13006 /*
13007 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
13008 * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
13009 * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
13010 * subsequent VM-entry would fail, see @bugref{7445}.
13011 *
13012 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception".
13013 */
13014 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
13015 && enmRaise == IEMXCPTRAISE_PREV_EVENT
13016 && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
13017 && CPUMIsGuestNmiBlocking(pVCpu))
13018 {
13019 CPUMSetGuestNmiBlocking(pVCpu, false);
13020 }
13021
13022 switch (enmRaise)
13023 {
13024 case IEMXCPTRAISE_CURRENT_XCPT:
13025 {
13026 Log4Func(("IDT: Pending secondary Xcpt: idtinfo=%#RX64 exitinfo=%#RX64\n", uIdtVectorInfo, uExitIntInfo));
13027 Assert(rcStrict == VINF_SUCCESS);
13028 break;
13029 }
13030
13031 case IEMXCPTRAISE_PREV_EVENT:
13032 {
13033 uint32_t u32ErrCode;
13034 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo))
13035 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
13036 else
13037 u32ErrCode = 0;
13038
13039 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
13040 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflect);
13041 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(uIdtVectorInfo), 0 /* cbInstr */,
13042 u32ErrCode, pVCpu->cpum.GstCtx.cr2);
13043
13044 Log4Func(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntInfo,
13045 pVCpu->hm.s.Event.u32ErrCode));
13046 Assert(rcStrict == VINF_SUCCESS);
13047 break;
13048 }
13049
13050 case IEMXCPTRAISE_REEXEC_INSTR:
13051 Assert(rcStrict == VINF_SUCCESS);
13052 break;
13053
13054 case IEMXCPTRAISE_DOUBLE_FAULT:
13055 {
13056 /*
13057 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
13058 * second #PF as a guest #PF (and not a shadow #PF) and needs to be converted into a #DF.
13059 */
13060 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
13061 {
13062 pVmxTransient->fVectoringDoublePF = true;
13063 Log4Func(("IDT: Vectoring double #PF %#RX64 cr2=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo,
13064 pVCpu->cpum.GstCtx.cr2));
13065 rcStrict = VINF_SUCCESS;
13066 }
13067 else
13068 {
13069 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectConvertDF);
13070 hmR0VmxSetPendingXcptDF(pVCpu);
13071 Log4Func(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntInfo,
13072 uIdtVector, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
13073 rcStrict = VINF_HM_DOUBLE_FAULT;
13074 }
13075 break;
13076 }
13077
13078 case IEMXCPTRAISE_TRIPLE_FAULT:
13079 {
13080 Log4Func(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector,
13081 VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
13082 rcStrict = VINF_EM_RESET;
13083 break;
13084 }
13085
13086 case IEMXCPTRAISE_CPU_HANG:
13087 {
13088 Log4Func(("IDT: Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", fRaiseInfo));
13089 rcStrict = VERR_EM_GUEST_CPU_HANG;
13090 break;
13091 }
13092
13093 default:
13094 {
13095 AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
13096 rcStrict = VERR_VMX_IPE_2;
13097 break;
13098 }
13099 }
13100 }
13101 else if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
13102 && !CPUMIsGuestNmiBlocking(pVCpu))
13103 {
13104 if ( VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)
13105 && VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo) != X86_XCPT_DF
13106 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(uExitIntInfo))
13107 {
13108 /*
13109 * Execution of IRET caused a fault when NMI blocking was in effect (i.e we're in
13110 * the guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13111 * that virtual NMIs remain blocked until the IRET execution is completed.
13112 *
13113 * See Intel spec. 31.7.1.2 "Resuming Guest Software After Handling An Exception".
13114 */
13115 CPUMSetGuestNmiBlocking(pVCpu, true);
13116 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13117 }
13118 else if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
13119 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
13120 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
13121 {
13122 /*
13123 * Execution of IRET caused an EPT violation, page-modification log-full event or
13124 * SPP-related event VM-exit when NMI blocking was in effect (i.e. we're in the
13125 * guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13126 * that virtual NMIs remain blocked until the IRET execution is completed.
13127 *
13128 * See Intel spec. 27.2.3 "Information about NMI unblocking due to IRET"
13129 */
13130 if (VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(pVmxTransient->uExitQual))
13131 {
13132 CPUMSetGuestNmiBlocking(pVCpu, true);
13133 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13134 }
13135 }
13136 }
13137
13138 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
13139 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
13140 return rcStrict;
13141}
13142
13143
13144#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13145/**
13146 * Perform the relevant VMX instruction checks for VM-exits that occurred due to the
13147 * guest attempting to execute a VMX instruction.
13148 *
13149 * @returns Strict VBox status code (i.e. informational status codes too).
13150 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13151 * @retval VINF_HM_PENDING_XCPT if an exception was raised.
13152 *
13153 * @param pVCpu The cross context virtual CPU structure.
13154 * @param uExitReason The VM-exit reason.
13155 *
13156 * @todo NSTVMX: Document other error codes when VM-exit is implemented.
13157 * @remarks No-long-jump zone!!!
13158 */
13159static VBOXSTRICTRC hmR0VmxCheckExitDueToVmxInstr(PVMCPUCC pVCpu, uint32_t uExitReason)
13160{
13161 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS
13162 | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
13163
13164 /*
13165 * The physical CPU would have already checked the CPU mode/code segment.
13166 * We shall just assert here for paranoia.
13167 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
13168 */
13169 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13170 Assert( !CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx)
13171 || CPUMIsGuestIn64BitCodeEx(&pVCpu->cpum.GstCtx));
13172
13173 if (uExitReason == VMX_EXIT_VMXON)
13174 {
13175 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
13176
13177 /*
13178 * We check CR4.VMXE because it is required to be always set while in VMX operation
13179 * by physical CPUs and our CR4 read-shadow is only consulted when executing specific
13180 * instructions (CLTS, LMSW, MOV CR, and SMSW) and thus doesn't affect CPU operation
13181 * otherwise (i.e. physical CPU won't automatically #UD if Cr4Shadow.VMXE is 0).
13182 */
13183 if (!CPUMIsGuestVmxEnabled(&pVCpu->cpum.GstCtx))
13184 {
13185 Log4Func(("CR4.VMXE is not set -> #UD\n"));
13186 hmR0VmxSetPendingXcptUD(pVCpu);
13187 return VINF_HM_PENDING_XCPT;
13188 }
13189 }
13190 else if (!CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx))
13191 {
13192 /*
13193 * The guest has not entered VMX operation but attempted to execute a VMX instruction
13194 * (other than VMXON), we need to raise a #UD.
13195 */
13196 Log4Func(("Not in VMX root mode -> #UD\n"));
13197 hmR0VmxSetPendingXcptUD(pVCpu);
13198 return VINF_HM_PENDING_XCPT;
13199 }
13200
13201 /* All other checks (including VM-exit intercepts) are handled by IEM instruction emulation. */
13202 return VINF_SUCCESS;
13203}
13204
13205
13206/**
13207 * Decodes the memory operand of an instruction that caused a VM-exit.
13208 *
13209 * The Exit qualification field provides the displacement field for memory
13210 * operand instructions, if any.
13211 *
13212 * @returns Strict VBox status code (i.e. informational status codes too).
13213 * @retval VINF_SUCCESS if the operand was successfully decoded.
13214 * @retval VINF_HM_PENDING_XCPT if an exception was raised while decoding the
13215 * operand.
13216 * @param pVCpu The cross context virtual CPU structure.
13217 * @param uExitInstrInfo The VM-exit instruction information field.
13218 * @param enmMemAccess The memory operand's access type (read or write).
13219 * @param GCPtrDisp The instruction displacement field, if any. For
13220 * RIP-relative addressing pass RIP + displacement here.
13221 * @param pGCPtrMem Where to store the effective destination memory address.
13222 *
13223 * @remarks Warning! This function ASSUMES the instruction cannot be used in real or
13224 * virtual-8086 mode hence skips those checks while verifying if the
13225 * segment is valid.
13226 */
13227static VBOXSTRICTRC hmR0VmxDecodeMemOperand(PVMCPUCC pVCpu, uint32_t uExitInstrInfo, RTGCPTR GCPtrDisp, VMXMEMACCESS enmMemAccess,
13228 PRTGCPTR pGCPtrMem)
13229{
13230 Assert(pGCPtrMem);
13231 Assert(!CPUMIsGuestInRealOrV86Mode(pVCpu));
13232 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_EFER
13233 | CPUMCTX_EXTRN_CR0);
13234
13235 static uint64_t const s_auAddrSizeMasks[] = { UINT64_C(0xffff), UINT64_C(0xffffffff), UINT64_C(0xffffffffffffffff) };
13236 static uint64_t const s_auAccessSizeMasks[] = { sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t) };
13237 AssertCompile(RT_ELEMENTS(s_auAccessSizeMasks) == RT_ELEMENTS(s_auAddrSizeMasks));
13238
13239 VMXEXITINSTRINFO ExitInstrInfo;
13240 ExitInstrInfo.u = uExitInstrInfo;
13241 uint8_t const uAddrSize = ExitInstrInfo.All.u3AddrSize;
13242 uint8_t const iSegReg = ExitInstrInfo.All.iSegReg;
13243 bool const fIdxRegValid = !ExitInstrInfo.All.fIdxRegInvalid;
13244 uint8_t const iIdxReg = ExitInstrInfo.All.iIdxReg;
13245 uint8_t const uScale = ExitInstrInfo.All.u2Scaling;
13246 bool const fBaseRegValid = !ExitInstrInfo.All.fBaseRegInvalid;
13247 uint8_t const iBaseReg = ExitInstrInfo.All.iBaseReg;
13248 bool const fIsMemOperand = !ExitInstrInfo.All.fIsRegOperand;
13249 bool const fIsLongMode = CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx);
13250
13251 /*
13252 * Validate instruction information.
13253 * This shouldn't happen on real hardware but useful while testing our nested hardware-virtualization code.
13254 */
13255 AssertLogRelMsgReturn(uAddrSize < RT_ELEMENTS(s_auAddrSizeMasks),
13256 ("Invalid address size. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_1);
13257 AssertLogRelMsgReturn(iSegReg < X86_SREG_COUNT,
13258 ("Invalid segment register. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_2);
13259 AssertLogRelMsgReturn(fIsMemOperand,
13260 ("Expected memory operand. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_3);
13261
13262 /*
13263 * Compute the complete effective address.
13264 *
13265 * See AMD instruction spec. 1.4.2 "SIB Byte Format"
13266 * See AMD spec. 4.5.2 "Segment Registers".
13267 */
13268 RTGCPTR GCPtrMem = GCPtrDisp;
13269 if (fBaseRegValid)
13270 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iBaseReg].u64;
13271 if (fIdxRegValid)
13272 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iIdxReg].u64 << uScale;
13273
13274 RTGCPTR const GCPtrOff = GCPtrMem;
13275 if ( !fIsLongMode
13276 || iSegReg >= X86_SREG_FS)
13277 GCPtrMem += pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
13278 GCPtrMem &= s_auAddrSizeMasks[uAddrSize];
13279
13280 /*
13281 * Validate effective address.
13282 * See AMD spec. 4.5.3 "Segment Registers in 64-Bit Mode".
13283 */
13284 uint8_t const cbAccess = s_auAccessSizeMasks[uAddrSize];
13285 Assert(cbAccess > 0);
13286 if (fIsLongMode)
13287 {
13288 if (X86_IS_CANONICAL(GCPtrMem))
13289 {
13290 *pGCPtrMem = GCPtrMem;
13291 return VINF_SUCCESS;
13292 }
13293
13294 /** @todo r=ramshankar: We should probably raise \#SS or \#GP. See AMD spec. 4.12.2
13295 * "Data Limit Checks in 64-bit Mode". */
13296 Log4Func(("Long mode effective address is not canonical GCPtrMem=%#RX64\n", GCPtrMem));
13297 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13298 return VINF_HM_PENDING_XCPT;
13299 }
13300
13301 /*
13302 * This is a watered down version of iemMemApplySegment().
13303 * Parts that are not applicable for VMX instructions like real-or-v8086 mode
13304 * and segment CPL/DPL checks are skipped.
13305 */
13306 RTGCPTR32 const GCPtrFirst32 = (RTGCPTR32)GCPtrOff;
13307 RTGCPTR32 const GCPtrLast32 = GCPtrFirst32 + cbAccess - 1;
13308 PCCPUMSELREG pSel = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
13309
13310 /* Check if the segment is present and usable. */
13311 if ( pSel->Attr.n.u1Present
13312 && !pSel->Attr.n.u1Unusable)
13313 {
13314 Assert(pSel->Attr.n.u1DescType);
13315 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
13316 {
13317 /* Check permissions for the data segment. */
13318 if ( enmMemAccess == VMXMEMACCESS_WRITE
13319 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE))
13320 {
13321 Log4Func(("Data segment access invalid. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13322 hmR0VmxSetPendingXcptGP(pVCpu, iSegReg);
13323 return VINF_HM_PENDING_XCPT;
13324 }
13325
13326 /* Check limits if it's a normal data segment. */
13327 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
13328 {
13329 if ( GCPtrFirst32 > pSel->u32Limit
13330 || GCPtrLast32 > pSel->u32Limit)
13331 {
13332 Log4Func(("Data segment limit exceeded. "
13333 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13334 GCPtrLast32, pSel->u32Limit));
13335 if (iSegReg == X86_SREG_SS)
13336 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13337 else
13338 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13339 return VINF_HM_PENDING_XCPT;
13340 }
13341 }
13342 else
13343 {
13344 /* Check limits if it's an expand-down data segment.
13345 Note! The upper boundary is defined by the B bit, not the G bit! */
13346 if ( GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
13347 || GCPtrLast32 > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
13348 {
13349 Log4Func(("Expand-down data segment limit exceeded. "
13350 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13351 GCPtrLast32, pSel->u32Limit));
13352 if (iSegReg == X86_SREG_SS)
13353 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13354 else
13355 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13356 return VINF_HM_PENDING_XCPT;
13357 }
13358 }
13359 }
13360 else
13361 {
13362 /* Check permissions for the code segment. */
13363 if ( enmMemAccess == VMXMEMACCESS_WRITE
13364 || ( enmMemAccess == VMXMEMACCESS_READ
13365 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)))
13366 {
13367 Log4Func(("Code segment access invalid. Attr=%#RX32\n", pSel->Attr.u));
13368 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13369 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13370 return VINF_HM_PENDING_XCPT;
13371 }
13372
13373 /* Check limits for the code segment (normal/expand-down not applicable for code segments). */
13374 if ( GCPtrFirst32 > pSel->u32Limit
13375 || GCPtrLast32 > pSel->u32Limit)
13376 {
13377 Log4Func(("Code segment limit exceeded. GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n",
13378 GCPtrFirst32, GCPtrLast32, pSel->u32Limit));
13379 if (iSegReg == X86_SREG_SS)
13380 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13381 else
13382 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13383 return VINF_HM_PENDING_XCPT;
13384 }
13385 }
13386 }
13387 else
13388 {
13389 Log4Func(("Not present or unusable segment. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13390 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13391 return VINF_HM_PENDING_XCPT;
13392 }
13393
13394 *pGCPtrMem = GCPtrMem;
13395 return VINF_SUCCESS;
13396}
13397#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13398
13399
13400/**
13401 * VM-exit helper for LMSW.
13402 */
13403static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst)
13404{
13405 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13406 AssertRCReturn(rc, rc);
13407
13408 VBOXSTRICTRC rcStrict = IEMExecDecodedLmsw(pVCpu, cbInstr, uMsw, GCPtrEffDst);
13409 AssertMsg( rcStrict == VINF_SUCCESS
13410 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13411
13412 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13413 if (rcStrict == VINF_IEM_RAISED_XCPT)
13414 {
13415 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13416 rcStrict = VINF_SUCCESS;
13417 }
13418
13419 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
13420 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13421 return rcStrict;
13422}
13423
13424
13425/**
13426 * VM-exit helper for CLTS.
13427 */
13428static VBOXSTRICTRC hmR0VmxExitClts(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
13429{
13430 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13431 AssertRCReturn(rc, rc);
13432
13433 VBOXSTRICTRC rcStrict = IEMExecDecodedClts(pVCpu, cbInstr);
13434 AssertMsg( rcStrict == VINF_SUCCESS
13435 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13436
13437 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13438 if (rcStrict == VINF_IEM_RAISED_XCPT)
13439 {
13440 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13441 rcStrict = VINF_SUCCESS;
13442 }
13443
13444 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
13445 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13446 return rcStrict;
13447}
13448
13449
13450/**
13451 * VM-exit helper for MOV from CRx (CRx read).
13452 */
13453static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13454{
13455 Assert(iCrReg < 16);
13456 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
13457
13458 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13459 AssertRCReturn(rc, rc);
13460
13461 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxRead(pVCpu, cbInstr, iGReg, iCrReg);
13462 AssertMsg( rcStrict == VINF_SUCCESS
13463 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13464
13465 if (iGReg == X86_GREG_xSP)
13466 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_RSP);
13467 else
13468 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13469#ifdef VBOX_WITH_STATISTICS
13470 switch (iCrReg)
13471 {
13472 case 0: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Read); break;
13473 case 2: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Read); break;
13474 case 3: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Read); break;
13475 case 4: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Read); break;
13476 case 8: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Read); break;
13477 }
13478#endif
13479 Log4Func(("CR%d Read access rcStrict=%Rrc\n", iCrReg, VBOXSTRICTRC_VAL(rcStrict)));
13480 return rcStrict;
13481}
13482
13483
13484/**
13485 * VM-exit helper for MOV to CRx (CRx write).
13486 */
13487static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13488{
13489 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13490 AssertRCReturn(rc, rc);
13491
13492 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, cbInstr, iCrReg, iGReg);
13493 AssertMsg( rcStrict == VINF_SUCCESS
13494 || rcStrict == VINF_IEM_RAISED_XCPT
13495 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13496
13497 switch (iCrReg)
13498 {
13499 case 0:
13500 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0
13501 | HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
13502 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Write);
13503 Log4Func(("CR0 write. rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr0));
13504 break;
13505
13506 case 2:
13507 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Write);
13508 /* Nothing to do here, CR2 it's not part of the VMCS. */
13509 break;
13510
13511 case 3:
13512 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR3);
13513 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Write);
13514 Log4Func(("CR3 write. rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr3));
13515 break;
13516
13517 case 4:
13518 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR4);
13519 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Write);
13520 Log4Func(("CR4 write. rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n", VBOXSTRICTRC_VAL(rcStrict),
13521 pVCpu->cpum.GstCtx.cr4, pVCpu->hm.s.fLoadSaveGuestXcr0));
13522 break;
13523
13524 case 8:
13525 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged,
13526 HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_APIC_TPR);
13527 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Write);
13528 break;
13529
13530 default:
13531 AssertMsgFailed(("Invalid CRx register %#x\n", iCrReg));
13532 break;
13533 }
13534
13535 if (rcStrict == VINF_IEM_RAISED_XCPT)
13536 {
13537 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13538 rcStrict = VINF_SUCCESS;
13539 }
13540 return rcStrict;
13541}
13542
13543
13544/**
13545 * VM-exit exception handler for \#PF (Page-fault exception).
13546 *
13547 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13548 */
13549static VBOXSTRICTRC hmR0VmxExitXcptPF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13550{
13551 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13552 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
13553 hmR0VmxReadExitQualVmcs(pVmxTransient);
13554
13555 if (!pVM->hm.s.fNestedPaging)
13556 { /* likely */ }
13557 else
13558 {
13559#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13560 Assert(pVmxTransient->fIsNestedGuest || pVCpu->hm.s.fUsingDebugLoop);
13561#endif
13562 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13563 if (!pVmxTransient->fVectoringDoublePF)
13564 {
13565 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13566 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual);
13567 }
13568 else
13569 {
13570 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13571 Assert(!pVmxTransient->fIsNestedGuest);
13572 hmR0VmxSetPendingXcptDF(pVCpu);
13573 Log4Func(("Pending #DF due to vectoring #PF w/ NestedPaging\n"));
13574 }
13575 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13576 return VINF_SUCCESS;
13577 }
13578
13579 Assert(!pVmxTransient->fIsNestedGuest);
13580
13581 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
13582 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
13583 if (pVmxTransient->fVectoringPF)
13584 {
13585 Assert(pVCpu->hm.s.Event.fPending);
13586 return VINF_EM_RAW_INJECT_TRPM_EVENT;
13587 }
13588
13589 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13590 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13591 AssertRCReturn(rc, rc);
13592
13593 Log4Func(("#PF: cs:rip=%#04x:%#RX64 err_code=%#RX32 exit_qual=%#RX64 cr3=%#RX64\n", pCtx->cs.Sel, pCtx->rip,
13594 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual, pCtx->cr3));
13595
13596 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQual, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
13597 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pCtx), (RTGCPTR)pVmxTransient->uExitQual);
13598
13599 Log4Func(("#PF: rc=%Rrc\n", rc));
13600 if (rc == VINF_SUCCESS)
13601 {
13602 /*
13603 * This is typically a shadow page table sync or a MMIO instruction. But we may have
13604 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
13605 */
13606 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13607 TRPMResetTrap(pVCpu);
13608 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
13609 return rc;
13610 }
13611
13612 if (rc == VINF_EM_RAW_GUEST_TRAP)
13613 {
13614 if (!pVmxTransient->fVectoringDoublePF)
13615 {
13616 /* It's a guest page fault and needs to be reflected to the guest. */
13617 uint32_t const uGstErrorCode = TRPMGetErrorCode(pVCpu);
13618 TRPMResetTrap(pVCpu);
13619 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
13620 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13621 uGstErrorCode, pVmxTransient->uExitQual);
13622 }
13623 else
13624 {
13625 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13626 TRPMResetTrap(pVCpu);
13627 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
13628 hmR0VmxSetPendingXcptDF(pVCpu);
13629 Log4Func(("#PF: Pending #DF due to vectoring #PF\n"));
13630 }
13631
13632 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13633 return VINF_SUCCESS;
13634 }
13635
13636 TRPMResetTrap(pVCpu);
13637 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
13638 return rc;
13639}
13640
13641
13642/**
13643 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
13644 *
13645 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13646 */
13647static VBOXSTRICTRC hmR0VmxExitXcptMF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13648{
13649 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13650 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
13651
13652 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0);
13653 AssertRCReturn(rc, rc);
13654
13655 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_NE))
13656 {
13657 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
13658 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
13659
13660 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
13661 * provides VM-exit instruction length. If this causes problem later,
13662 * disassemble the instruction like it's done on AMD-V. */
13663 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
13664 AssertRCReturn(rc2, rc2);
13665 return rc;
13666 }
13667
13668 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbExitInstr,
13669 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13670 return VINF_SUCCESS;
13671}
13672
13673
13674/**
13675 * VM-exit exception handler for \#BP (Breakpoint exception).
13676 *
13677 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13678 */
13679static VBOXSTRICTRC hmR0VmxExitXcptBP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13680{
13681 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13682 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
13683
13684 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13685 AssertRCReturn(rc, rc);
13686
13687 if (!pVmxTransient->fIsNestedGuest)
13688 rc = DBGFRZTrap03Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(&pVCpu->cpum.GstCtx));
13689 else
13690 rc = VINF_EM_RAW_GUEST_TRAP;
13691
13692 if (rc == VINF_EM_RAW_GUEST_TRAP)
13693 {
13694 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13695 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13696 rc = VINF_SUCCESS;
13697 }
13698
13699 Assert(rc == VINF_SUCCESS || rc == VINF_EM_DBG_BREAKPOINT);
13700 return rc;
13701}
13702
13703
13704/**
13705 * VM-exit exception handler for \#AC (Alignment-check exception).
13706 *
13707 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13708 */
13709static VBOXSTRICTRC hmR0VmxExitXcptAC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13710{
13711 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13712 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC);
13713
13714 /* Re-inject it. We'll detect any nesting before getting here. */
13715 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13716 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13717 return VINF_SUCCESS;
13718}
13719
13720
13721/**
13722 * VM-exit exception handler for \#DB (Debug exception).
13723 *
13724 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13725 */
13726static VBOXSTRICTRC hmR0VmxExitXcptDB(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13727{
13728 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13729 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
13730
13731 /*
13732 * Get the DR6-like values from the Exit qualification and pass it to DBGF for processing.
13733 */
13734 hmR0VmxReadExitQualVmcs(pVmxTransient);
13735
13736 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
13737 uint64_t const uDR6 = X86_DR6_INIT_VAL
13738 | (pVmxTransient->uExitQual & ( X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3
13739 | X86_DR6_BD | X86_DR6_BS));
13740
13741 int rc;
13742 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13743 if (!pVmxTransient->fIsNestedGuest)
13744 {
13745 rc = DBGFRZTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
13746
13747 /*
13748 * Prevents stepping twice over the same instruction when the guest is stepping using
13749 * EFLAGS.TF and the hypervisor debugger is stepping using MTF.
13750 * Testcase: DOSQEMM, break (using "ba x 1") at cs:rip 0x70:0x774 and step (using "t").
13751 */
13752 if ( rc == VINF_EM_DBG_STEPPED
13753 && (pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MONITOR_TRAP_FLAG))
13754 {
13755 Assert(pVCpu->hm.s.fSingleInstruction);
13756 rc = VINF_EM_RAW_GUEST_TRAP;
13757 }
13758 }
13759 else
13760 rc = VINF_EM_RAW_GUEST_TRAP;
13761 Log6Func(("rc=%Rrc\n", rc));
13762 if (rc == VINF_EM_RAW_GUEST_TRAP)
13763 {
13764 /*
13765 * The exception was for the guest. Update DR6, DR7.GD and
13766 * IA32_DEBUGCTL.LBR before forwarding it.
13767 * See Intel spec. 27.1 "Architectural State before a VM-Exit".
13768 */
13769 VMMRZCallRing3Disable(pVCpu);
13770 HM_DISABLE_PREEMPT(pVCpu);
13771
13772 pCtx->dr[6] &= ~X86_DR6_B_MASK;
13773 pCtx->dr[6] |= uDR6;
13774 if (CPUMIsGuestDebugStateActive(pVCpu))
13775 ASMSetDR6(pCtx->dr[6]);
13776
13777 HM_RESTORE_PREEMPT();
13778 VMMRZCallRing3Enable(pVCpu);
13779
13780 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_DR7);
13781 AssertRCReturn(rc, rc);
13782
13783 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
13784 pCtx->dr[7] &= ~(uint64_t)X86_DR7_GD;
13785
13786 /* Paranoia. */
13787 pCtx->dr[7] &= ~(uint64_t)X86_DR7_RAZ_MASK;
13788 pCtx->dr[7] |= X86_DR7_RA1_MASK;
13789
13790 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, pCtx->dr[7]);
13791 AssertRC(rc);
13792
13793 /*
13794 * Raise #DB in the guest.
13795 *
13796 * It is important to reflect exactly what the VM-exit gave us (preserving the
13797 * interruption-type) rather than use hmR0VmxSetPendingXcptDB() as the #DB could've
13798 * been raised while executing ICEBP (INT1) and not the regular #DB. Thus it may
13799 * trigger different handling in the CPU (like skipping DPL checks), see @bugref{6398}.
13800 *
13801 * Intel re-documented ICEBP/INT1 on May 2018 previously documented as part of
13802 * Intel 386, see Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
13803 */
13804 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13805 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13806 return VINF_SUCCESS;
13807 }
13808
13809 /*
13810 * Not a guest trap, must be a hypervisor related debug event then.
13811 * Update DR6 in case someone is interested in it.
13812 */
13813 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
13814 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
13815 CPUMSetHyperDR6(pVCpu, uDR6);
13816
13817 return rc;
13818}
13819
13820
13821/**
13822 * Hacks its way around the lovely mesa driver's backdoor accesses.
13823 *
13824 * @sa hmR0SvmHandleMesaDrvGp.
13825 */
13826static int hmR0VmxHandleMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
13827{
13828 LogFunc(("cs:rip=%#04x:%#RX64 rcx=%#RX64 rbx=%#RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->rcx, pCtx->rbx));
13829 RT_NOREF(pCtx);
13830
13831 /* For now we'll just skip the instruction. */
13832 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
13833}
13834
13835
13836/**
13837 * Checks if the \#GP'ing instruction is the mesa driver doing it's lovely
13838 * backdoor logging w/o checking what it is running inside.
13839 *
13840 * This recognizes an "IN EAX,DX" instruction executed in flat ring-3, with the
13841 * backdoor port and magic numbers loaded in registers.
13842 *
13843 * @returns true if it is, false if it isn't.
13844 * @sa hmR0SvmIsMesaDrvGp.
13845 */
13846DECLINLINE(bool) hmR0VmxIsMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
13847{
13848 /* 0xed: IN eAX,dx */
13849 uint8_t abInstr[1];
13850 if (pVmxTransient->cbExitInstr != sizeof(abInstr))
13851 return false;
13852
13853 /* Check that it is #GP(0). */
13854 if (pVmxTransient->uExitIntErrorCode != 0)
13855 return false;
13856
13857 /* Check magic and port. */
13858 Assert(!(pCtx->fExtrn & (CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX)));
13859 /*Log(("hmR0VmxIsMesaDrvGp: rax=%RX64 rdx=%RX64\n", pCtx->rax, pCtx->rdx));*/
13860 if (pCtx->rax != UINT32_C(0x564d5868))
13861 return false;
13862 if (pCtx->dx != UINT32_C(0x5658))
13863 return false;
13864
13865 /* Flat ring-3 CS. */
13866 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_CS);
13867 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_CS));
13868 /*Log(("hmR0VmxIsMesaDrvGp: cs.Attr.n.u2Dpl=%d base=%Rx64\n", pCtx->cs.Attr.n.u2Dpl, pCtx->cs.u64Base));*/
13869 if (pCtx->cs.Attr.n.u2Dpl != 3)
13870 return false;
13871 if (pCtx->cs.u64Base != 0)
13872 return false;
13873
13874 /* Check opcode. */
13875 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_RIP);
13876 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_RIP));
13877 int rc = PGMPhysSimpleReadGCPtr(pVCpu, abInstr, pCtx->rip, sizeof(abInstr));
13878 /*Log(("hmR0VmxIsMesaDrvGp: PGMPhysSimpleReadGCPtr -> %Rrc %#x\n", rc, abInstr[0]));*/
13879 if (RT_FAILURE(rc))
13880 return false;
13881 if (abInstr[0] != 0xed)
13882 return false;
13883
13884 return true;
13885}
13886
13887
13888/**
13889 * VM-exit exception handler for \#GP (General-protection exception).
13890 *
13891 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13892 */
13893static VBOXSTRICTRC hmR0VmxExitXcptGP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13894{
13895 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13896 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
13897
13898 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13899 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13900 if (pVmcsInfo->RealMode.fRealOnV86Active)
13901 { /* likely */ }
13902 else
13903 {
13904#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13905 Assert(pVCpu->hm.s.fUsingDebugLoop || pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
13906#endif
13907 /*
13908 * If the guest is not in real-mode or we have unrestricted guest execution support, or if we are
13909 * executing a nested-guest, reflect #GP to the guest or nested-guest.
13910 */
13911 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13912 AssertRCReturn(rc, rc);
13913 Log4Func(("Gst: cs:rip=%#04x:%#RX64 ErrorCode=%#x cr0=%#RX64 cpl=%u tr=%#04x\n", pCtx->cs.Sel, pCtx->rip,
13914 pVmxTransient->uExitIntErrorCode, pCtx->cr0, CPUMGetGuestCPL(pVCpu), pCtx->tr.Sel));
13915
13916 if ( pVmxTransient->fIsNestedGuest
13917 || !pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv
13918 || !hmR0VmxIsMesaDrvGp(pVCpu, pVmxTransient, pCtx))
13919 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13920 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13921 else
13922 rc = hmR0VmxHandleMesaDrvGp(pVCpu, pVmxTransient, pCtx);
13923 return rc;
13924 }
13925
13926 Assert(CPUMIsGuestInRealModeEx(pCtx));
13927 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest);
13928 Assert(!pVmxTransient->fIsNestedGuest);
13929
13930 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13931 AssertRCReturn(rc, rc);
13932
13933 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
13934 if (rcStrict == VINF_SUCCESS)
13935 {
13936 if (!CPUMIsGuestInRealModeEx(pCtx))
13937 {
13938 /*
13939 * The guest is no longer in real-mode, check if we can continue executing the
13940 * guest using hardware-assisted VMX. Otherwise, fall back to emulation.
13941 */
13942 pVmcsInfo->RealMode.fRealOnV86Active = false;
13943 if (HMCanExecuteVmxGuest(pVCpu->pVMR0, pVCpu, pCtx))
13944 {
13945 Log4Func(("Mode changed but guest still suitable for executing using hardware-assisted VMX\n"));
13946 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13947 }
13948 else
13949 {
13950 Log4Func(("Mode changed -> VINF_EM_RESCHEDULE\n"));
13951 rcStrict = VINF_EM_RESCHEDULE;
13952 }
13953 }
13954 else
13955 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13956 }
13957 else if (rcStrict == VINF_IEM_RAISED_XCPT)
13958 {
13959 rcStrict = VINF_SUCCESS;
13960 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13961 }
13962 return VBOXSTRICTRC_VAL(rcStrict);
13963}
13964
13965
13966/**
13967 * VM-exit exception handler wrapper for all other exceptions that are not handled
13968 * by a specific handler.
13969 *
13970 * This simply re-injects the exception back into the VM without any special
13971 * processing.
13972 *
13973 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13974 */
13975static VBOXSTRICTRC hmR0VmxExitXcptOthers(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13976{
13977 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13978
13979#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13980 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13981 AssertMsg(pVCpu->hm.s.fUsingDebugLoop || pVmcsInfo->RealMode.fRealOnV86Active || pVmxTransient->fIsNestedGuest,
13982 ("uVector=%#x u32XcptBitmap=%#X32\n",
13983 VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVmcsInfo->u32XcptBitmap));
13984 NOREF(pVmcsInfo);
13985#endif
13986
13987 /*
13988 * Re-inject the exception into the guest. This cannot be a double-fault condition which
13989 * would have been handled while checking exits due to event delivery.
13990 */
13991 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13992
13993#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13994 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
13995 AssertRCReturn(rc, rc);
13996 Log4Func(("Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
13997#endif
13998
13999#ifdef VBOX_WITH_STATISTICS
14000 switch (uVector)
14001 {
14002 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE); break;
14003 case X86_XCPT_DB: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB); break;
14004 case X86_XCPT_BP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP); break;
14005 case X86_XCPT_OF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
14006 case X86_XCPT_BR: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBR); break;
14007 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD); break;
14008 case X86_XCPT_NM: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
14009 case X86_XCPT_DF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDF); break;
14010 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS); break;
14011 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP); break;
14012 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS); break;
14013 case X86_XCPT_GP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP); break;
14014 case X86_XCPT_PF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF); break;
14015 case X86_XCPT_MF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF); break;
14016 case X86_XCPT_AC: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC); break;
14017 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF); break;
14018 default:
14019 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
14020 break;
14021 }
14022#endif
14023
14024 /* We should never call this function for a page-fault, we'd need to pass on the fault address below otherwise. */
14025 Assert(!VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo));
14026 NOREF(uVector);
14027
14028 /* Re-inject the original exception into the guest. */
14029 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14030 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14031 return VINF_SUCCESS;
14032}
14033
14034
14035/**
14036 * VM-exit exception handler for all exceptions (except NMIs!).
14037 *
14038 * @remarks This may be called for both guests and nested-guests. Take care to not
14039 * make assumptions and avoid doing anything that is not relevant when
14040 * executing a nested-guest (e.g., Mesa driver hacks).
14041 */
14042static VBOXSTRICTRC hmR0VmxExitXcpt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14043{
14044 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
14045
14046 /*
14047 * If this VM-exit occurred while delivering an event through the guest IDT, take
14048 * action based on the return code and additional hints (e.g. for page-faults)
14049 * that will be updated in the VMX transient structure.
14050 */
14051 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
14052 if (rcStrict == VINF_SUCCESS)
14053 {
14054 /*
14055 * If an exception caused a VM-exit due to delivery of an event, the original
14056 * event may have to be re-injected into the guest. We shall reinject it and
14057 * continue guest execution. However, page-fault is a complicated case and
14058 * needs additional processing done in hmR0VmxExitXcptPF().
14059 */
14060 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
14061 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14062 if ( !pVCpu->hm.s.Event.fPending
14063 || uVector == X86_XCPT_PF)
14064 {
14065 switch (uVector)
14066 {
14067 case X86_XCPT_PF: return hmR0VmxExitXcptPF(pVCpu, pVmxTransient);
14068 case X86_XCPT_GP: return hmR0VmxExitXcptGP(pVCpu, pVmxTransient);
14069 case X86_XCPT_MF: return hmR0VmxExitXcptMF(pVCpu, pVmxTransient);
14070 case X86_XCPT_DB: return hmR0VmxExitXcptDB(pVCpu, pVmxTransient);
14071 case X86_XCPT_BP: return hmR0VmxExitXcptBP(pVCpu, pVmxTransient);
14072 case X86_XCPT_AC: return hmR0VmxExitXcptAC(pVCpu, pVmxTransient);
14073 default:
14074 return hmR0VmxExitXcptOthers(pVCpu, pVmxTransient);
14075 }
14076 }
14077 /* else: inject pending event before resuming guest execution. */
14078 }
14079 else if (rcStrict == VINF_HM_DOUBLE_FAULT)
14080 {
14081 Assert(pVCpu->hm.s.Event.fPending);
14082 rcStrict = VINF_SUCCESS;
14083 }
14084
14085 return rcStrict;
14086}
14087/** @} */
14088
14089
14090/** @name VM-exit handlers.
14091 * @{
14092 */
14093/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
14094/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
14095/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
14096
14097/**
14098 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
14099 */
14100HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14101{
14102 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14103 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
14104 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
14105 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
14106 return VINF_SUCCESS;
14107 return VINF_EM_RAW_INTERRUPT;
14108}
14109
14110
14111/**
14112 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI). Conditional
14113 * VM-exit.
14114 */
14115HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14116{
14117 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14118 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
14119
14120 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
14121
14122 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
14123 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14124 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
14125
14126 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14127 Assert( !(pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT)
14128 && uExitIntType != VMX_EXIT_INT_INFO_TYPE_EXT_INT);
14129 NOREF(pVmcsInfo);
14130
14131 VBOXSTRICTRC rcStrict;
14132 switch (uExitIntType)
14133 {
14134 /*
14135 * Host physical NMIs:
14136 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we
14137 * injected it ourselves and anything we inject is not going to cause a VM-exit directly
14138 * for the event being injected[1]. Go ahead and dispatch the NMI to the host[2].
14139 *
14140 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
14141 * See Intel spec. 27.5.5 "Updating Non-Register State".
14142 */
14143 case VMX_EXIT_INT_INFO_TYPE_NMI:
14144 {
14145 rcStrict = hmR0VmxExitHostNmi(pVCpu, pVmcsInfo);
14146 break;
14147 }
14148
14149 /*
14150 * Privileged software exceptions (#DB from ICEBP),
14151 * Software exceptions (#BP and #OF),
14152 * Hardware exceptions:
14153 * Process the required exceptions and resume guest execution if possible.
14154 */
14155 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
14156 Assert(uVector == X86_XCPT_DB);
14157 RT_FALL_THRU();
14158 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
14159 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uExitIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT);
14160 RT_FALL_THRU();
14161 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
14162 {
14163 NOREF(uVector);
14164 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
14165 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14166 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
14167 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
14168
14169 rcStrict = hmR0VmxExitXcpt(pVCpu, pVmxTransient);
14170 break;
14171 }
14172
14173 default:
14174 {
14175 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
14176 rcStrict = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
14177 AssertMsgFailed(("Invalid/unexpected VM-exit interruption info %#x\n", pVmxTransient->uExitIntInfo));
14178 break;
14179 }
14180 }
14181
14182 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
14183 return rcStrict;
14184}
14185
14186
14187/**
14188 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
14189 */
14190HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14191{
14192 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14193
14194 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
14195 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14196 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
14197
14198 /* Evaluate and deliver pending events and resume guest execution. */
14199 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
14200 return VINF_SUCCESS;
14201}
14202
14203
14204/**
14205 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
14206 */
14207HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14208{
14209 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14210
14211 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14212 if (RT_UNLIKELY(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))) /** @todo NSTVMX: Turn this into an assertion. */
14213 {
14214 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
14215 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14216 }
14217
14218 Assert(!CPUMIsGuestNmiBlocking(pVCpu));
14219
14220 /*
14221 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
14222 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
14223 */
14224 uint32_t fIntrState;
14225 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
14226 AssertRC(rc);
14227 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
14228 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
14229 {
14230 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
14231 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
14232
14233 fIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
14234 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
14235 AssertRC(rc);
14236 }
14237
14238 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
14239 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
14240
14241 /* Evaluate and deliver pending events and resume guest execution. */
14242 return VINF_SUCCESS;
14243}
14244
14245
14246/**
14247 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
14248 */
14249HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14250{
14251 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14252 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14253}
14254
14255
14256/**
14257 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
14258 */
14259HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14260{
14261 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14262 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14263}
14264
14265
14266/**
14267 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
14268 */
14269HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14270{
14271 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14272
14273 /*
14274 * Get the state we need and update the exit history entry.
14275 */
14276 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14277 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14278
14279 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14280 AssertRCReturn(rc, rc);
14281
14282 VBOXSTRICTRC rcStrict;
14283 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
14284 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_CPUID),
14285 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
14286 if (!pExitRec)
14287 {
14288 /*
14289 * Regular CPUID instruction execution.
14290 */
14291 rcStrict = IEMExecDecodedCpuid(pVCpu, pVmxTransient->cbExitInstr);
14292 if (rcStrict == VINF_SUCCESS)
14293 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14294 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14295 {
14296 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14297 rcStrict = VINF_SUCCESS;
14298 }
14299 }
14300 else
14301 {
14302 /*
14303 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
14304 */
14305 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14306 AssertRCReturn(rc2, rc2);
14307
14308 Log4(("CpuIdExit/%u: %04x:%08RX64: %#x/%#x -> EMHistoryExec\n",
14309 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx));
14310
14311 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
14312 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14313
14314 Log4(("CpuIdExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
14315 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
14316 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
14317 }
14318 return rcStrict;
14319}
14320
14321
14322/**
14323 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
14324 */
14325HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14326{
14327 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14328
14329 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14330 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4);
14331 AssertRCReturn(rc, rc);
14332
14333 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_SMXE)
14334 return VINF_EM_RAW_EMULATE_INSTR;
14335
14336 AssertMsgFailed(("hmR0VmxExitGetsec: Unexpected VM-exit when CR4.SMXE is 0.\n"));
14337 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14338}
14339
14340
14341/**
14342 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
14343 */
14344HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14345{
14346 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14347
14348 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14349 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14350 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14351 AssertRCReturn(rc, rc);
14352
14353 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtsc(pVCpu, pVmxTransient->cbExitInstr);
14354 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14355 {
14356 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14357 we must reset offsetting on VM-entry. See @bugref{6634}. */
14358 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14359 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14360 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14361 }
14362 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14363 {
14364 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14365 rcStrict = VINF_SUCCESS;
14366 }
14367 return rcStrict;
14368}
14369
14370
14371/**
14372 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
14373 */
14374HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14375{
14376 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14377
14378 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14379 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14380 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_TSC_AUX);
14381 AssertRCReturn(rc, rc);
14382
14383 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtscp(pVCpu, pVmxTransient->cbExitInstr);
14384 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14385 {
14386 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14387 we must reset offsetting on VM-reentry. See @bugref{6634}. */
14388 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14389 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14390 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14391 }
14392 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14393 {
14394 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14395 rcStrict = VINF_SUCCESS;
14396 }
14397 return rcStrict;
14398}
14399
14400
14401/**
14402 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
14403 */
14404HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14405{
14406 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14407
14408 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14409 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_CR0
14410 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS);
14411 AssertRCReturn(rc, rc);
14412
14413 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14414 rc = EMInterpretRdpmc(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
14415 if (RT_LIKELY(rc == VINF_SUCCESS))
14416 {
14417 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14418 Assert(pVmxTransient->cbExitInstr == 2);
14419 }
14420 else
14421 {
14422 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
14423 rc = VERR_EM_INTERPRETER;
14424 }
14425 return rc;
14426}
14427
14428
14429/**
14430 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
14431 */
14432HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14433{
14434 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14435
14436 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
14437 if (EMAreHypercallInstructionsEnabled(pVCpu))
14438 {
14439 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14440 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CR0
14441 | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
14442 AssertRCReturn(rc, rc);
14443
14444 /* Perform the hypercall. */
14445 rcStrict = GIMHypercall(pVCpu, &pVCpu->cpum.GstCtx);
14446 if (rcStrict == VINF_SUCCESS)
14447 {
14448 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14449 AssertRCReturn(rc, rc);
14450 }
14451 else
14452 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
14453 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
14454 || RT_FAILURE(rcStrict));
14455
14456 /* If the hypercall changes anything other than guest's general-purpose registers,
14457 we would need to reload the guest changed bits here before VM-entry. */
14458 }
14459 else
14460 Log4Func(("Hypercalls not enabled\n"));
14461
14462 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
14463 if (RT_FAILURE(rcStrict))
14464 {
14465 hmR0VmxSetPendingXcptUD(pVCpu);
14466 rcStrict = VINF_SUCCESS;
14467 }
14468
14469 return rcStrict;
14470}
14471
14472
14473/**
14474 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
14475 */
14476HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14477{
14478 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14479 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging || pVCpu->hm.s.fUsingDebugLoop);
14480
14481 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14482 hmR0VmxReadExitQualVmcs(pVmxTransient);
14483 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14484 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
14485 AssertRCReturn(rc, rc);
14486
14487 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpg(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->uExitQual);
14488
14489 if (rcStrict == VINF_SUCCESS || rcStrict == VINF_PGM_SYNC_CR3)
14490 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14491 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14492 {
14493 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14494 rcStrict = VINF_SUCCESS;
14495 }
14496 else
14497 AssertMsgFailed(("Unexpected IEMExecDecodedInvlpg(%#RX64) status: %Rrc\n", pVmxTransient->uExitQual,
14498 VBOXSTRICTRC_VAL(rcStrict)));
14499 return rcStrict;
14500}
14501
14502
14503/**
14504 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
14505 */
14506HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14507{
14508 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14509
14510 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14511 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14512 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_DS);
14513 AssertRCReturn(rc, rc);
14514
14515 VBOXSTRICTRC rcStrict = IEMExecDecodedMonitor(pVCpu, pVmxTransient->cbExitInstr);
14516 if (rcStrict == VINF_SUCCESS)
14517 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14518 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14519 {
14520 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14521 rcStrict = VINF_SUCCESS;
14522 }
14523
14524 return rcStrict;
14525}
14526
14527
14528/**
14529 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
14530 */
14531HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14532{
14533 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14534
14535 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14536 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14537 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14538 AssertRCReturn(rc, rc);
14539
14540 VBOXSTRICTRC rcStrict = IEMExecDecodedMwait(pVCpu, pVmxTransient->cbExitInstr);
14541 if (RT_SUCCESS(rcStrict))
14542 {
14543 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14544 if (EMMonitorWaitShouldContinue(pVCpu, &pVCpu->cpum.GstCtx))
14545 rcStrict = VINF_SUCCESS;
14546 }
14547
14548 return rcStrict;
14549}
14550
14551
14552/**
14553 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
14554 * VM-exit.
14555 */
14556HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14557{
14558 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14559 return VINF_EM_RESET;
14560}
14561
14562
14563/**
14564 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
14565 */
14566HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14567{
14568 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14569
14570 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14571 AssertRCReturn(rc, rc);
14572
14573 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS); /* Advancing the RIP above should've imported eflags. */
14574 if (EMShouldContinueAfterHalt(pVCpu, &pVCpu->cpum.GstCtx)) /* Requires eflags. */
14575 rc = VINF_SUCCESS;
14576 else
14577 rc = VINF_EM_HALT;
14578
14579 if (rc != VINF_SUCCESS)
14580 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
14581 return rc;
14582}
14583
14584
14585/**
14586 * VM-exit handler for instructions that result in a \#UD exception delivered to
14587 * the guest.
14588 */
14589HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14590{
14591 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14592 hmR0VmxSetPendingXcptUD(pVCpu);
14593 return VINF_SUCCESS;
14594}
14595
14596
14597/**
14598 * VM-exit handler for expiry of the VMX-preemption timer.
14599 */
14600HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14601{
14602 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14603
14604 /* If the VMX-preemption timer has expired, reinitialize the preemption timer on next VM-entry. */
14605 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14606
14607 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
14608 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
14609 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
14610 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
14611 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
14612}
14613
14614
14615/**
14616 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
14617 */
14618HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14619{
14620 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14621
14622 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14623 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14624 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_CR4);
14625 AssertRCReturn(rc, rc);
14626
14627 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbExitInstr);
14628 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
14629 : HM_CHANGED_RAISED_XCPT_MASK);
14630
14631 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14632 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
14633
14634 return rcStrict;
14635}
14636
14637
14638/**
14639 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
14640 */
14641HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14642{
14643 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14644
14645#if 1
14646 /** @todo Use VM-exit instruction information. */
14647 return VERR_EM_INTERPRETER;
14648#else
14649 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14650 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
14651 hmR0VmxReadExitQualVmcs(pVmxTransient);
14652 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
14653 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
14654 AssertRCReturn(rc, rc);
14655
14656 /* Paranoia. Ensure this has a memory operand. */
14657 Assert(!pVmxTransient->ExitInstrInfo.Inv.u1Cleared0);
14658
14659 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
14660 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
14661 uint64_t const uType = CPUMIsGuestIn64BitCode(pVCpu) ? pVCpu->cpum.GstCtx.aGRegs[iGReg].u64
14662 : pVCpu->cpum.GstCtx.aGRegs[iGReg].u32;
14663
14664 RTGCPTR GCPtrDesc;
14665 HMVMX_DECODE_MEM_OPERAND(pVCpu, pVmxTransient->ExitInstrInfo.u, pVmxTransient->uExitQual, VMXMEMACCESS_READ, &GCPtrDesc);
14666
14667 VBOXSTRICTRC rcStrict = IEMExecDecodedInvpcid(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->ExitInstrInfo.Inv.iSegReg,
14668 GCPtrDesc, uType);
14669 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14670 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14671 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14672 {
14673 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14674 rcStrict = VINF_SUCCESS;
14675 }
14676 return rcStrict;
14677#endif
14678}
14679
14680
14681/**
14682 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error
14683 * VM-exit.
14684 */
14685HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14686{
14687 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14688 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14689 AssertRCReturn(rc, rc);
14690
14691 rc = hmR0VmxCheckCachedVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
14692 if (RT_FAILURE(rc))
14693 return rc;
14694
14695 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
14696 NOREF(uInvalidReason);
14697
14698#ifdef VBOX_STRICT
14699 uint32_t fIntrState;
14700 uint64_t u64Val;
14701 hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
14702 hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
14703 hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
14704
14705 Log4(("uInvalidReason %u\n", uInvalidReason));
14706 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
14707 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
14708 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
14709
14710 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState); AssertRC(rc);
14711 Log4(("VMX_VMCS32_GUEST_INT_STATE %#RX32\n", fIntrState));
14712 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Val); AssertRC(rc);
14713 Log4(("VMX_VMCS_GUEST_CR0 %#RX64\n", u64Val));
14714 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_MASK, &u64Val); AssertRC(rc);
14715 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RX64\n", u64Val));
14716 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Val); AssertRC(rc);
14717 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
14718 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_MASK, &u64Val); AssertRC(rc);
14719 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RX64\n", u64Val));
14720 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Val); AssertRC(rc);
14721 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
14722 if (pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging)
14723 {
14724 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
14725 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
14726 }
14727 hmR0DumpRegs(pVCpu, HM_DUMP_REG_FLAGS_ALL);
14728#endif
14729
14730 return VERR_VMX_INVALID_GUEST_STATE;
14731}
14732
14733/**
14734 * VM-exit handler for all undefined/unexpected reasons. Should never happen.
14735 */
14736HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUnexpected(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14737{
14738 /*
14739 * Cumulative notes of all recognized but unexpected VM-exits.
14740 *
14741 * 1. This does -not- cover scenarios like a page-fault VM-exit occurring when
14742 * nested-paging is used.
14743 *
14744 * 2. Any instruction that causes a VM-exit unconditionally (for e.g. VMXON) must be
14745 * emulated or a #UD must be raised in the guest. Therefore, we should -not- be using
14746 * this function (and thereby stop VM execution) for handling such instructions.
14747 *
14748 *
14749 * VMX_EXIT_INIT_SIGNAL:
14750 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
14751 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these
14752 * VM-exits. However, we should not receive INIT signals VM-exit while executing a VM.
14753 *
14754 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery"
14755 * See Intel spec. 29.3 "VMX Instructions" for "VMXON".
14756 * See Intel spec. "23.8 Restrictions on VMX operation".
14757 *
14758 * VMX_EXIT_SIPI:
14759 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest
14760 * activity state is used. We don't make use of it as our guests don't have direct
14761 * access to the host local APIC.
14762 *
14763 * See Intel spec. 25.3 "Other Causes of VM-exits".
14764 *
14765 * VMX_EXIT_IO_SMI:
14766 * VMX_EXIT_SMI:
14767 * This can only happen if we support dual-monitor treatment of SMI, which can be
14768 * activated by executing VMCALL in VMX root operation. Only an STM (SMM transfer
14769 * monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL in
14770 * VMX root mode or receive an SMI. If we get here, something funny is going on.
14771 *
14772 * See Intel spec. 33.15.6 "Activating the Dual-Monitor Treatment"
14773 * See Intel spec. 25.3 "Other Causes of VM-Exits"
14774 *
14775 * VMX_EXIT_ERR_MSR_LOAD:
14776 * Failures while loading MSRs are part of the VM-entry MSR-load area are unexpected
14777 * and typically indicates a bug in the hypervisor code. We thus cannot not resume
14778 * execution.
14779 *
14780 * See Intel spec. 26.7 "VM-Entry Failures During Or After Loading Guest State".
14781 *
14782 * VMX_EXIT_ERR_MACHINE_CHECK:
14783 * Machine check exceptions indicates a fatal/unrecoverable hardware condition
14784 * including but not limited to system bus, ECC, parity, cache and TLB errors. A
14785 * #MC exception abort class exception is raised. We thus cannot assume a
14786 * reasonable chance of continuing any sort of execution and we bail.
14787 *
14788 * See Intel spec. 15.1 "Machine-check Architecture".
14789 * See Intel spec. 27.1 "Architectural State Before A VM Exit".
14790 *
14791 * VMX_EXIT_PML_FULL:
14792 * VMX_EXIT_VIRTUALIZED_EOI:
14793 * VMX_EXIT_APIC_WRITE:
14794 * We do not currently support any of these features and thus they are all unexpected
14795 * VM-exits.
14796 *
14797 * VMX_EXIT_GDTR_IDTR_ACCESS:
14798 * VMX_EXIT_LDTR_TR_ACCESS:
14799 * VMX_EXIT_RDRAND:
14800 * VMX_EXIT_RSM:
14801 * VMX_EXIT_VMFUNC:
14802 * VMX_EXIT_ENCLS:
14803 * VMX_EXIT_RDSEED:
14804 * VMX_EXIT_XSAVES:
14805 * VMX_EXIT_XRSTORS:
14806 * VMX_EXIT_UMWAIT:
14807 * VMX_EXIT_TPAUSE:
14808 * These VM-exits are -not- caused unconditionally by execution of the corresponding
14809 * instruction. Any VM-exit for these instructions indicate a hardware problem,
14810 * unsupported CPU modes (like SMM) or potentially corrupt VMCS controls.
14811 *
14812 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
14813 */
14814 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14815 AssertMsgFailed(("Unexpected VM-exit %u\n", pVmxTransient->uExitReason));
14816 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14817}
14818
14819
14820/**
14821 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
14822 */
14823HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14824{
14825 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14826
14827 /** @todo Optimize this: We currently drag in the whole MSR state
14828 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
14829 * MSRs required. That would require changes to IEM and possibly CPUM too.
14830 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
14831 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14832 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
14833 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
14834 switch (idMsr)
14835 {
14836 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
14837 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
14838 }
14839
14840 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14841 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
14842 AssertRCReturn(rc, rc);
14843
14844 Log4Func(("ecx=%#RX32\n", idMsr));
14845
14846#ifdef VBOX_STRICT
14847 Assert(!pVmxTransient->fIsNestedGuest);
14848 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
14849 {
14850 if ( hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr)
14851 && idMsr != MSR_K6_EFER)
14852 {
14853 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", idMsr));
14854 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14855 }
14856 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14857 {
14858 Assert(pVmcsInfo->pvMsrBitmap);
14859 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
14860 if (fMsrpm & VMXMSRPM_ALLOW_RD)
14861 {
14862 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", idMsr));
14863 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14864 }
14865 }
14866 }
14867#endif
14868
14869 VBOXSTRICTRC rcStrict = IEMExecDecodedRdmsr(pVCpu, pVmxTransient->cbExitInstr);
14870 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
14871 if (rcStrict == VINF_SUCCESS)
14872 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14873 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14874 {
14875 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14876 rcStrict = VINF_SUCCESS;
14877 }
14878 else
14879 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_READ, ("Unexpected IEMExecDecodedRdmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
14880
14881 return rcStrict;
14882}
14883
14884
14885/**
14886 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
14887 */
14888HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14889{
14890 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14891
14892 /** @todo Optimize this: We currently drag in the whole MSR state
14893 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
14894 * MSRs required. That would require changes to IEM and possibly CPUM too.
14895 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
14896 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
14897 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
14898
14899 /*
14900 * The FS and GS base MSRs are not part of the above all-MSRs mask.
14901 * Although we don't need to fetch the base as it will be overwritten shortly, while
14902 * loading guest-state we would also load the entire segment register including limit
14903 * and attributes and thus we need to load them here.
14904 */
14905 switch (idMsr)
14906 {
14907 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
14908 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
14909 }
14910
14911 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14912 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14913 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
14914 AssertRCReturn(rc, rc);
14915
14916 Log4Func(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", idMsr, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.eax));
14917
14918 VBOXSTRICTRC rcStrict = IEMExecDecodedWrmsr(pVCpu, pVmxTransient->cbExitInstr);
14919 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
14920
14921 if (rcStrict == VINF_SUCCESS)
14922 {
14923 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14924
14925 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
14926 if ( idMsr == MSR_IA32_APICBASE
14927 || ( idMsr >= MSR_IA32_X2APIC_START
14928 && idMsr <= MSR_IA32_X2APIC_END))
14929 {
14930 /*
14931 * We've already saved the APIC related guest-state (TPR) in post-run phase.
14932 * When full APIC register virtualization is implemented we'll have to make
14933 * sure APIC state is saved from the VMCS before IEM changes it.
14934 */
14935 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
14936 }
14937 else if (idMsr == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
14938 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14939 else if (idMsr == MSR_K6_EFER)
14940 {
14941 /*
14942 * If the guest touches the EFER MSR we need to update the VM-Entry and VM-Exit controls
14943 * as well, even if it is -not- touching bits that cause paging mode changes (LMA/LME).
14944 * We care about the other bits as well, SCE and NXE. See @bugref{7368}.
14945 */
14946 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
14947 }
14948
14949 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not used. */
14950 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
14951 {
14952 switch (idMsr)
14953 {
14954 case MSR_IA32_SYSENTER_CS: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
14955 case MSR_IA32_SYSENTER_EIP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
14956 case MSR_IA32_SYSENTER_ESP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
14957 case MSR_K8_FS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_FS); break;
14958 case MSR_K8_GS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_GS); break;
14959 case MSR_K6_EFER: /* Nothing to do, already handled above. */ break;
14960 default:
14961 {
14962 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14963 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_LAZY_MSRS);
14964 else if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
14965 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
14966 break;
14967 }
14968 }
14969 }
14970#ifdef VBOX_STRICT
14971 else
14972 {
14973 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
14974 switch (idMsr)
14975 {
14976 case MSR_IA32_SYSENTER_CS:
14977 case MSR_IA32_SYSENTER_EIP:
14978 case MSR_IA32_SYSENTER_ESP:
14979 case MSR_K8_FS_BASE:
14980 case MSR_K8_GS_BASE:
14981 {
14982 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", idMsr));
14983 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14984 }
14985
14986 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
14987 default:
14988 {
14989 if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
14990 {
14991 /* EFER MSR writes are always intercepted. */
14992 if (idMsr != MSR_K6_EFER)
14993 {
14994 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
14995 idMsr));
14996 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14997 }
14998 }
14999
15000 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15001 {
15002 Assert(pVmcsInfo->pvMsrBitmap);
15003 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
15004 if (fMsrpm & VMXMSRPM_ALLOW_WR)
15005 {
15006 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", idMsr));
15007 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15008 }
15009 }
15010 break;
15011 }
15012 }
15013 }
15014#endif /* VBOX_STRICT */
15015 }
15016 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15017 {
15018 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15019 rcStrict = VINF_SUCCESS;
15020 }
15021 else
15022 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_WRITE, ("Unexpected IEMExecDecodedWrmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
15023
15024 return rcStrict;
15025}
15026
15027
15028/**
15029 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
15030 */
15031HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15032{
15033 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15034
15035 /** @todo The guest has likely hit a contended spinlock. We might want to
15036 * poke a schedule different guest VCPU. */
15037 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15038 if (RT_SUCCESS(rc))
15039 return VINF_EM_RAW_INTERRUPT;
15040
15041 AssertMsgFailed(("hmR0VmxExitPause: Failed to increment RIP. rc=%Rrc\n", rc));
15042 return rc;
15043}
15044
15045
15046/**
15047 * VM-exit handler for when the TPR value is lowered below the specified
15048 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
15049 */
15050HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15051{
15052 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15053 Assert(pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
15054
15055 /*
15056 * The TPR shadow would've been synced with the APIC TPR in the post-run phase.
15057 * We'll re-evaluate pending interrupts and inject them before the next VM
15058 * entry so we can just continue execution here.
15059 */
15060 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
15061 return VINF_SUCCESS;
15062}
15063
15064
15065/**
15066 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
15067 * VM-exit.
15068 *
15069 * @retval VINF_SUCCESS when guest execution can continue.
15070 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
15071 * @retval VERR_EM_RESCHEDULE_REM when we need to return to ring-3 due to
15072 * incompatible guest state for VMX execution (real-on-v86 case).
15073 */
15074HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15075{
15076 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15077 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
15078
15079 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15080 hmR0VmxReadExitQualVmcs(pVmxTransient);
15081 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15082
15083 VBOXSTRICTRC rcStrict;
15084 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15085 uint64_t const uExitQual = pVmxTransient->uExitQual;
15086 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(uExitQual);
15087 switch (uAccessType)
15088 {
15089 /*
15090 * MOV to CRx.
15091 */
15092 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
15093 {
15094 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15095 AssertRCReturn(rc, rc);
15096
15097 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
15098 uint32_t const uOldCr0 = pVCpu->cpum.GstCtx.cr0;
15099 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
15100 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
15101
15102 /*
15103 * MOV to CR3 only cause a VM-exit when one or more of the following are true:
15104 * - When nested paging isn't used.
15105 * - If the guest doesn't have paging enabled (intercept CR3 to update shadow page tables).
15106 * - We are executing in the VM debug loop.
15107 */
15108 Assert( iCrReg != 3
15109 || !pVM->hm.s.fNestedPaging
15110 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
15111 || pVCpu->hm.s.fUsingDebugLoop);
15112
15113 /* MOV to CR8 writes only cause VM-exits when TPR shadow is not used. */
15114 Assert( iCrReg != 8
15115 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
15116
15117 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
15118 AssertMsg( rcStrict == VINF_SUCCESS
15119 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15120
15121 /*
15122 * This is a kludge for handling switches back to real mode when we try to use
15123 * V86 mode to run real mode code directly. Problem is that V86 mode cannot
15124 * deal with special selector values, so we have to return to ring-3 and run
15125 * there till the selector values are V86 mode compatible.
15126 *
15127 * Note! Using VINF_EM_RESCHEDULE_REM here rather than VINF_EM_RESCHEDULE since the
15128 * latter is an alias for VINF_IEM_RAISED_XCPT which is asserted at the end of
15129 * this function.
15130 */
15131 if ( iCrReg == 0
15132 && rcStrict == VINF_SUCCESS
15133 && !pVM->hm.s.vmx.fUnrestrictedGuest
15134 && CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx)
15135 && (uOldCr0 & X86_CR0_PE)
15136 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
15137 {
15138 /** @todo Check selectors rather than returning all the time. */
15139 Assert(!pVmxTransient->fIsNestedGuest);
15140 Log4Func(("CR0 write, back to real mode -> VINF_EM_RESCHEDULE_REM\n"));
15141 rcStrict = VINF_EM_RESCHEDULE_REM;
15142 }
15143 break;
15144 }
15145
15146 /*
15147 * MOV from CRx.
15148 */
15149 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
15150 {
15151 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
15152 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
15153
15154 /*
15155 * MOV from CR3 only cause a VM-exit when one or more of the following are true:
15156 * - When nested paging isn't used.
15157 * - If the guest doesn't have paging enabled (pass guest's CR3 rather than our identity mapped CR3).
15158 * - We are executing in the VM debug loop.
15159 */
15160 Assert( iCrReg != 3
15161 || !pVM->hm.s.fNestedPaging
15162 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
15163 || pVCpu->hm.s.fUsingDebugLoop);
15164
15165 /* MOV from CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
15166 Assert( iCrReg != 8
15167 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
15168
15169 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
15170 break;
15171 }
15172
15173 /*
15174 * CLTS (Clear Task-Switch Flag in CR0).
15175 */
15176 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
15177 {
15178 rcStrict = hmR0VmxExitClts(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr);
15179 break;
15180 }
15181
15182 /*
15183 * LMSW (Load Machine-Status Word into CR0).
15184 * LMSW cannot clear CR0.PE, so no fRealOnV86Active kludge needed here.
15185 */
15186 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW:
15187 {
15188 RTGCPTR GCPtrEffDst;
15189 uint8_t const cbInstr = pVmxTransient->cbExitInstr;
15190 uint16_t const uMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(uExitQual);
15191 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(uExitQual);
15192 if (fMemOperand)
15193 {
15194 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
15195 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
15196 }
15197 else
15198 GCPtrEffDst = NIL_RTGCPTR;
15199 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmcsInfo, cbInstr, uMsw, GCPtrEffDst);
15200 break;
15201 }
15202
15203 default:
15204 {
15205 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
15206 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
15207 }
15208 }
15209
15210 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS))
15211 == (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS));
15212 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15213
15214 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
15215 NOREF(pVM);
15216 return rcStrict;
15217}
15218
15219
15220/**
15221 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
15222 * VM-exit.
15223 */
15224HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15225{
15226 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15227 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
15228
15229 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15230 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15231 hmR0VmxReadExitQualVmcs(pVmxTransient);
15232 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15233 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_SREG_MASK
15234 | CPUMCTX_EXTRN_EFER);
15235 /* EFER MSR also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
15236 AssertRCReturn(rc, rc);
15237
15238 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
15239 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
15240 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
15241 bool const fIOWrite = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
15242 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
15243 bool const fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
15244 bool const fDbgStepping = pVCpu->hm.s.fSingleInstruction;
15245 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
15246
15247 /*
15248 * Update exit history to see if this exit can be optimized.
15249 */
15250 VBOXSTRICTRC rcStrict;
15251 PCEMEXITREC pExitRec = NULL;
15252 if ( !fGstStepping
15253 && !fDbgStepping)
15254 pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15255 !fIOString
15256 ? !fIOWrite
15257 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_READ)
15258 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_WRITE)
15259 : !fIOWrite
15260 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_READ)
15261 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_WRITE),
15262 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15263 if (!pExitRec)
15264 {
15265 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
15266 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving result in AL/AX/EAX. */
15267
15268 uint32_t const cbValue = s_aIOSizes[uIOSize];
15269 uint32_t const cbInstr = pVmxTransient->cbExitInstr;
15270 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
15271 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15272 if (fIOString)
15273 {
15274 /*
15275 * INS/OUTS - I/O String instruction.
15276 *
15277 * Use instruction-information if available, otherwise fall back on
15278 * interpreting the instruction.
15279 */
15280 Log4Func(("cs:rip=%#04x:%#RX64 %#06x/%u %c str\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15281 AssertReturn(pCtx->dx == uIOPort, VERR_VMX_IPE_2);
15282 bool const fInsOutsInfo = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS);
15283 if (fInsOutsInfo)
15284 {
15285 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15286 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
15287 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
15288 IEMMODE const enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
15289 bool const fRep = VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual);
15290 if (fIOWrite)
15291 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
15292 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
15293 else
15294 {
15295 /*
15296 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
15297 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
15298 * See Intel Instruction spec. for "INS".
15299 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
15300 */
15301 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
15302 }
15303 }
15304 else
15305 rcStrict = IEMExecOne(pVCpu);
15306
15307 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15308 fUpdateRipAlready = true;
15309 }
15310 else
15311 {
15312 /*
15313 * IN/OUT - I/O instruction.
15314 */
15315 Log4Func(("cs:rip=%04x:%08RX64 %#06x/%u %c\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15316 uint32_t const uAndVal = s_aIOOpAnd[uIOSize];
15317 Assert(!VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual));
15318 if (fIOWrite)
15319 {
15320 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pCtx->eax & uAndVal, cbValue);
15321 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
15322 if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15323 && !pCtx->eflags.Bits.u1TF)
15324 rcStrict = EMRZSetPendingIoPortWrite(pVCpu, uIOPort, cbInstr, cbValue, pCtx->eax & uAndVal);
15325 }
15326 else
15327 {
15328 uint32_t u32Result = 0;
15329 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
15330 if (IOM_SUCCESS(rcStrict))
15331 {
15332 /* Save result of I/O IN instr. in AL/AX/EAX. */
15333 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Result & uAndVal);
15334 }
15335 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15336 && !pCtx->eflags.Bits.u1TF)
15337 rcStrict = EMRZSetPendingIoPortRead(pVCpu, uIOPort, cbInstr, cbValue);
15338 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
15339 }
15340 }
15341
15342 if (IOM_SUCCESS(rcStrict))
15343 {
15344 if (!fUpdateRipAlready)
15345 {
15346 hmR0VmxAdvanceGuestRipBy(pVCpu, cbInstr);
15347 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15348 }
15349
15350 /*
15351 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru
15352 * while booting Fedora 17 64-bit guest.
15353 *
15354 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
15355 */
15356 if (fIOString)
15357 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RFLAGS);
15358
15359 /*
15360 * If any I/O breakpoints are armed, we need to check if one triggered
15361 * and take appropriate action.
15362 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
15363 */
15364 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_DR7);
15365 AssertRCReturn(rc, rc);
15366
15367 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
15368 * execution engines about whether hyper BPs and such are pending. */
15369 uint32_t const uDr7 = pCtx->dr[7];
15370 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
15371 && X86_DR7_ANY_RW_IO(uDr7)
15372 && (pCtx->cr4 & X86_CR4_DE))
15373 || DBGFBpIsHwIoArmed(pVM)))
15374 {
15375 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
15376
15377 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
15378 VMMRZCallRing3Disable(pVCpu);
15379 HM_DISABLE_PREEMPT(pVCpu);
15380
15381 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
15382
15383 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, uIOPort, cbValue);
15384 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
15385 {
15386 /* Raise #DB. */
15387 if (fIsGuestDbgActive)
15388 ASMSetDR6(pCtx->dr[6]);
15389 if (pCtx->dr[7] != uDr7)
15390 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_DR7;
15391
15392 hmR0VmxSetPendingXcptDB(pVCpu);
15393 }
15394 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
15395 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
15396 else if ( rcStrict2 != VINF_SUCCESS
15397 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
15398 rcStrict = rcStrict2;
15399 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
15400
15401 HM_RESTORE_PREEMPT();
15402 VMMRZCallRing3Enable(pVCpu);
15403 }
15404 }
15405
15406#ifdef VBOX_STRICT
15407 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15408 || rcStrict == VINF_EM_PENDING_R3_IOPORT_READ)
15409 Assert(!fIOWrite);
15410 else if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15411 || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
15412 || rcStrict == VINF_EM_PENDING_R3_IOPORT_WRITE)
15413 Assert(fIOWrite);
15414 else
15415 {
15416# if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
15417 * statuses, that the VMM device and some others may return. See
15418 * IOM_SUCCESS() for guidance. */
15419 AssertMsg( RT_FAILURE(rcStrict)
15420 || rcStrict == VINF_SUCCESS
15421 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
15422 || rcStrict == VINF_EM_DBG_BREAKPOINT
15423 || rcStrict == VINF_EM_RAW_GUEST_TRAP
15424 || rcStrict == VINF_EM_RAW_TO_R3
15425 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15426# endif
15427 }
15428#endif
15429 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
15430 }
15431 else
15432 {
15433 /*
15434 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
15435 */
15436 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15437 AssertRCReturn(rc2, rc2);
15438 STAM_COUNTER_INC(!fIOString ? fIOWrite ? &pVCpu->hm.s.StatExitIOWrite : &pVCpu->hm.s.StatExitIORead
15439 : fIOWrite ? &pVCpu->hm.s.StatExitIOStringWrite : &pVCpu->hm.s.StatExitIOStringRead);
15440 Log4(("IOExit/%u: %04x:%08RX64: %s%s%s %#x LB %u -> EMHistoryExec\n",
15441 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15442 VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual) ? "REP " : "",
15443 fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOSize));
15444
15445 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15446 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15447
15448 Log4(("IOExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15449 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15450 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15451 }
15452 return rcStrict;
15453}
15454
15455
15456/**
15457 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
15458 * VM-exit.
15459 */
15460HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15461{
15462 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15463
15464 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
15465 hmR0VmxReadExitQualVmcs(pVmxTransient);
15466 if (VMX_EXIT_QUAL_TASK_SWITCH_TYPE(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT)
15467 {
15468 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15469 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
15470 {
15471 uint32_t uErrCode;
15472 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uIdtVectoringInfo))
15473 {
15474 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15475 uErrCode = pVmxTransient->uIdtVectoringErrorCode;
15476 }
15477 else
15478 uErrCode = 0;
15479
15480 RTGCUINTPTR GCPtrFaultAddress;
15481 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(pVmxTransient->uIdtVectoringInfo))
15482 GCPtrFaultAddress = pVCpu->cpum.GstCtx.cr2;
15483 else
15484 GCPtrFaultAddress = 0;
15485
15486 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15487
15488 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
15489 pVmxTransient->cbExitInstr, uErrCode, GCPtrFaultAddress);
15490
15491 Log4Func(("Pending event. uIntType=%#x uVector=%#x\n", VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo),
15492 VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo)));
15493 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15494 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15495 }
15496 }
15497
15498 /* Fall back to the interpreter to emulate the task-switch. */
15499 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15500 return VERR_EM_INTERPRETER;
15501}
15502
15503
15504/**
15505 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
15506 */
15507HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15508{
15509 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15510
15511 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15512 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
15513 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15514 AssertRC(rc);
15515 return VINF_EM_DBG_STEPPED;
15516}
15517
15518
15519/**
15520 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
15521 */
15522HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15523{
15524 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15525 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
15526
15527 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15528 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15529 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15530 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15531 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15532
15533 /*
15534 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15535 */
15536 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15537 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15538 {
15539 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
15540 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
15541 {
15542 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15543 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15544 }
15545 }
15546 else
15547 {
15548 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15549 return rcStrict;
15550 }
15551
15552 /* IOMMIOPhysHandler() below may call into IEM, save the necessary state. */
15553 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15554 hmR0VmxReadExitQualVmcs(pVmxTransient);
15555 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15556 AssertRCReturn(rc, rc);
15557
15558 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
15559 uint32_t const uAccessType = VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual);
15560 switch (uAccessType)
15561 {
15562 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
15563 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
15564 {
15565 AssertMsg( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
15566 || VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual) != XAPIC_OFF_TPR,
15567 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
15568
15569 RTGCPHYS GCPhys = pVCpu->hm.s.vmx.u64GstMsrApicBase; /* Always up-to-date, as it is not part of the VMCS. */
15570 GCPhys &= PAGE_BASE_GC_MASK;
15571 GCPhys += VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual);
15572 Log4Func(("Linear access uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
15573 VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual)));
15574
15575 rcStrict = IOMR0MmioPhysHandler(pVCpu->CTX_SUFF(pVM), pVCpu,
15576 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW, GCPhys);
15577 Log4Func(("IOMMMIOPhysHandler returned %Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15578 if ( rcStrict == VINF_SUCCESS
15579 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15580 || rcStrict == VERR_PAGE_NOT_PRESENT)
15581 {
15582 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15583 | HM_CHANGED_GUEST_APIC_TPR);
15584 rcStrict = VINF_SUCCESS;
15585 }
15586 break;
15587 }
15588
15589 default:
15590 {
15591 Log4Func(("uAccessType=%#x\n", uAccessType));
15592 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
15593 break;
15594 }
15595 }
15596
15597 if (rcStrict != VINF_SUCCESS)
15598 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
15599 return rcStrict;
15600}
15601
15602
15603/**
15604 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
15605 * VM-exit.
15606 */
15607HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15608{
15609 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15610 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15611
15612 /* We might get this VM-exit if the nested-guest is not intercepting MOV DRx accesses. */
15613 if (!pVmxTransient->fIsNestedGuest)
15614 {
15615 /* We should -not- get this VM-exit if the guest's debug registers were active. */
15616 if (pVmxTransient->fWasGuestDebugStateActive)
15617 {
15618 AssertMsgFailed(("Unexpected MOV DRx exit\n"));
15619 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
15620 }
15621
15622 if ( !pVCpu->hm.s.fSingleInstruction
15623 && !pVmxTransient->fWasHyperDebugStateActive)
15624 {
15625 Assert(!DBGFIsStepping(pVCpu));
15626 Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB));
15627
15628 /* Don't intercept MOV DRx any more. */
15629 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
15630 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15631 AssertRC(rc);
15632
15633 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
15634 VMMRZCallRing3Disable(pVCpu);
15635 HM_DISABLE_PREEMPT(pVCpu);
15636
15637 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
15638 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
15639 Assert(CPUMIsGuestDebugStateActive(pVCpu));
15640
15641 HM_RESTORE_PREEMPT();
15642 VMMRZCallRing3Enable(pVCpu);
15643
15644#ifdef VBOX_WITH_STATISTICS
15645 hmR0VmxReadExitQualVmcs(pVmxTransient);
15646 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
15647 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
15648 else
15649 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
15650#endif
15651 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
15652 return VINF_SUCCESS;
15653 }
15654 }
15655
15656 /*
15657 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER MSR, CS.
15658 * The EFER MSR is always up-to-date.
15659 * Update the segment registers and DR7 from the CPU.
15660 */
15661 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15662 hmR0VmxReadExitQualVmcs(pVmxTransient);
15663 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_DR7);
15664 AssertRCReturn(rc, rc);
15665 Log4Func(("cs:rip=%#04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
15666
15667 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15668 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
15669 {
15670 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pCtx),
15671 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual),
15672 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual));
15673 if (RT_SUCCESS(rc))
15674 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
15675 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
15676 }
15677 else
15678 {
15679 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pCtx),
15680 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual),
15681 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual));
15682 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
15683 }
15684
15685 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
15686 if (RT_SUCCESS(rc))
15687 {
15688 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15689 AssertRCReturn(rc2, rc2);
15690 return VINF_SUCCESS;
15691 }
15692 return rc;
15693}
15694
15695
15696/**
15697 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
15698 * Conditional VM-exit.
15699 */
15700HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15701{
15702 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15703 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
15704
15705 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15706 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15707 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15708 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15709 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15710
15711 /*
15712 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15713 */
15714 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15715 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15716 {
15717 /*
15718 * In the unlikely case where delivering an event causes an EPT misconfig (MMIO), go back to
15719 * instruction emulation to inject the original event. Otherwise, injecting the original event
15720 * using hardware-assisted VMX would trigger the same EPT misconfig VM-exit again.
15721 */
15722 if (!pVCpu->hm.s.Event.fPending)
15723 { /* likely */ }
15724 else
15725 {
15726 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15727#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
15728 /** @todo NSTVMX: Think about how this should be handled. */
15729 if (pVmxTransient->fIsNestedGuest)
15730 return VERR_VMX_IPE_3;
15731#endif
15732 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15733 }
15734 }
15735 else
15736 {
15737 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15738 return rcStrict;
15739 }
15740
15741 /*
15742 * Get sufficient state and update the exit history entry.
15743 */
15744 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15745 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
15746 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15747 AssertRCReturn(rc, rc);
15748
15749 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
15750 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15751 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_MMIO),
15752 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15753 if (!pExitRec)
15754 {
15755 /*
15756 * If we succeed, resume guest execution.
15757 * If we fail in interpreting the instruction because we couldn't get the guest physical address
15758 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
15759 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
15760 * weird case. See @bugref{6043}.
15761 */
15762 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15763 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15764 rcStrict = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pCtx), GCPhys, UINT32_MAX);
15765 Log4Func(("At %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pCtx->rip, VBOXSTRICTRC_VAL(rcStrict)));
15766 if ( rcStrict == VINF_SUCCESS
15767 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15768 || rcStrict == VERR_PAGE_NOT_PRESENT)
15769 {
15770 /* Successfully handled MMIO operation. */
15771 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15772 | HM_CHANGED_GUEST_APIC_TPR);
15773 rcStrict = VINF_SUCCESS;
15774 }
15775 }
15776 else
15777 {
15778 /*
15779 * Frequent exit or something needing probing. Call EMHistoryExec.
15780 */
15781 Log4(("EptMisscfgExit/%u: %04x:%08RX64: %RGp -> EMHistoryExec\n",
15782 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPhys));
15783
15784 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15785 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15786
15787 Log4(("EptMisscfgExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15788 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15789 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15790 }
15791 return rcStrict;
15792}
15793
15794
15795/**
15796 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
15797 * VM-exit.
15798 */
15799HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15800{
15801 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15802 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
15803
15804 hmR0VmxReadExitQualVmcs(pVmxTransient);
15805 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15806 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15807 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15808 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15809 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15810
15811 /*
15812 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15813 */
15814 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15815 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15816 {
15817 /*
15818 * If delivery of an event causes an EPT violation (true nested #PF and not MMIO),
15819 * we shall resolve the nested #PF and re-inject the original event.
15820 */
15821 if (pVCpu->hm.s.Event.fPending)
15822 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflectNPF);
15823 }
15824 else
15825 {
15826 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15827 return rcStrict;
15828 }
15829
15830 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15831 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
15832 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15833 AssertRCReturn(rc, rc);
15834
15835 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
15836 uint64_t const uExitQual = pVmxTransient->uExitQual;
15837 AssertMsg(((pVmxTransient->uExitQual >> 7) & 3) != 2, ("%#RX64", uExitQual));
15838
15839 RTGCUINT uErrorCode = 0;
15840 if (uExitQual & VMX_EXIT_QUAL_EPT_INSTR_FETCH)
15841 uErrorCode |= X86_TRAP_PF_ID;
15842 if (uExitQual & VMX_EXIT_QUAL_EPT_DATA_WRITE)
15843 uErrorCode |= X86_TRAP_PF_RW;
15844 if (uExitQual & VMX_EXIT_QUAL_EPT_ENTRY_PRESENT)
15845 uErrorCode |= X86_TRAP_PF_P;
15846
15847 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15848 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15849 Log4Func(("at %#RX64 (%#RX64 errcode=%#x) cs:rip=%#04x:%#RX64\n", GCPhys, uExitQual, uErrorCode, pCtx->cs.Sel, pCtx->rip));
15850
15851 /*
15852 * Handle the pagefault trap for the nested shadow table.
15853 */
15854 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
15855 rcStrict = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pCtx), GCPhys);
15856 TRPMResetTrap(pVCpu);
15857
15858 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
15859 if ( rcStrict == VINF_SUCCESS
15860 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15861 || rcStrict == VERR_PAGE_NOT_PRESENT)
15862 {
15863 /* Successfully synced our nested page tables. */
15864 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
15865 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS);
15866 return VINF_SUCCESS;
15867 }
15868
15869 Log4Func(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15870 return rcStrict;
15871}
15872
15873
15874#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
15875/**
15876 * VM-exit handler for VMCLEAR (VMX_EXIT_VMCLEAR). Unconditional VM-exit.
15877 */
15878HMVMX_EXIT_DECL hmR0VmxExitVmclear(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15879{
15880 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15881
15882 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15883 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15884 hmR0VmxReadExitQualVmcs(pVmxTransient);
15885 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15886 | CPUMCTX_EXTRN_HWVIRT
15887 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15888 AssertRCReturn(rc, rc);
15889
15890 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15891
15892 VMXVEXITINFO ExitInfo;
15893 RT_ZERO(ExitInfo);
15894 ExitInfo.uReason = pVmxTransient->uExitReason;
15895 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15896 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15897 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
15898 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15899
15900 VBOXSTRICTRC rcStrict = IEMExecDecodedVmclear(pVCpu, &ExitInfo);
15901 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15902 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15903 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15904 {
15905 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15906 rcStrict = VINF_SUCCESS;
15907 }
15908 return rcStrict;
15909}
15910
15911
15912/**
15913 * VM-exit handler for VMLAUNCH (VMX_EXIT_VMLAUNCH). Unconditional VM-exit.
15914 */
15915HMVMX_EXIT_DECL hmR0VmxExitVmlaunch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15916{
15917 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15918
15919 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMLAUNCH,
15920 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
15921 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15922 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15923 AssertRCReturn(rc, rc);
15924
15925 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15926
15927 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
15928 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMLAUNCH);
15929 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
15930 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15931 {
15932 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15933 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
15934 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
15935 }
15936 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15937 return rcStrict;
15938}
15939
15940
15941/**
15942 * VM-exit handler for VMPTRLD (VMX_EXIT_VMPTRLD). Unconditional VM-exit.
15943 */
15944HMVMX_EXIT_DECL hmR0VmxExitVmptrld(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15945{
15946 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15947
15948 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15949 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15950 hmR0VmxReadExitQualVmcs(pVmxTransient);
15951 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15952 | CPUMCTX_EXTRN_HWVIRT
15953 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15954 AssertRCReturn(rc, rc);
15955
15956 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15957
15958 VMXVEXITINFO ExitInfo;
15959 RT_ZERO(ExitInfo);
15960 ExitInfo.uReason = pVmxTransient->uExitReason;
15961 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15962 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15963 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
15964 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15965
15966 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrld(pVCpu, &ExitInfo);
15967 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15968 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15969 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15970 {
15971 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15972 rcStrict = VINF_SUCCESS;
15973 }
15974 return rcStrict;
15975}
15976
15977
15978/**
15979 * VM-exit handler for VMPTRST (VMX_EXIT_VMPTRST). Unconditional VM-exit.
15980 */
15981HMVMX_EXIT_DECL hmR0VmxExitVmptrst(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15982{
15983 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15984
15985 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15986 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15987 hmR0VmxReadExitQualVmcs(pVmxTransient);
15988 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15989 | CPUMCTX_EXTRN_HWVIRT
15990 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15991 AssertRCReturn(rc, rc);
15992
15993 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15994
15995 VMXVEXITINFO ExitInfo;
15996 RT_ZERO(ExitInfo);
15997 ExitInfo.uReason = pVmxTransient->uExitReason;
15998 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15999 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16000 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16001 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
16002
16003 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrst(pVCpu, &ExitInfo);
16004 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16005 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16006 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16007 {
16008 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16009 rcStrict = VINF_SUCCESS;
16010 }
16011 return rcStrict;
16012}
16013
16014
16015/**
16016 * VM-exit handler for VMREAD (VMX_EXIT_VMREAD). Conditional VM-exit.
16017 */
16018HMVMX_EXIT_DECL hmR0VmxExitVmread(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16019{
16020 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16021
16022 /*
16023 * Strictly speaking we should not get VMREAD VM-exits for shadow VMCS fields and
16024 * thus might not need to import the shadow VMCS state, it's safer just in case
16025 * code elsewhere dares look at unsynced VMCS fields.
16026 */
16027 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16028 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16029 hmR0VmxReadExitQualVmcs(pVmxTransient);
16030 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16031 | CPUMCTX_EXTRN_HWVIRT
16032 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16033 AssertRCReturn(rc, rc);
16034
16035 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16036
16037 VMXVEXITINFO ExitInfo;
16038 RT_ZERO(ExitInfo);
16039 ExitInfo.uReason = pVmxTransient->uExitReason;
16040 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16041 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16042 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16043 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
16044 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
16045
16046 VBOXSTRICTRC rcStrict = IEMExecDecodedVmread(pVCpu, &ExitInfo);
16047 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16048 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16049 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16050 {
16051 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16052 rcStrict = VINF_SUCCESS;
16053 }
16054 return rcStrict;
16055}
16056
16057
16058/**
16059 * VM-exit handler for VMRESUME (VMX_EXIT_VMRESUME). Unconditional VM-exit.
16060 */
16061HMVMX_EXIT_DECL hmR0VmxExitVmresume(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16062{
16063 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16064
16065 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMRESUME,
16066 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
16067 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16068 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16069 AssertRCReturn(rc, rc);
16070
16071 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16072
16073 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
16074 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMRESUME);
16075 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
16076 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16077 {
16078 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16079 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
16080 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
16081 }
16082 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
16083 return rcStrict;
16084}
16085
16086
16087/**
16088 * VM-exit handler for VMWRITE (VMX_EXIT_VMWRITE). Conditional VM-exit.
16089 */
16090HMVMX_EXIT_DECL hmR0VmxExitVmwrite(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16091{
16092 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16093
16094 /*
16095 * Although we should not get VMWRITE VM-exits for shadow VMCS fields, since our HM hook
16096 * gets invoked when IEM's VMWRITE instruction emulation modifies the current VMCS and it
16097 * flags re-loading the entire shadow VMCS, we should save the entire shadow VMCS here.
16098 */
16099 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16100 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16101 hmR0VmxReadExitQualVmcs(pVmxTransient);
16102 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16103 | CPUMCTX_EXTRN_HWVIRT
16104 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16105 AssertRCReturn(rc, rc);
16106
16107 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16108
16109 VMXVEXITINFO ExitInfo;
16110 RT_ZERO(ExitInfo);
16111 ExitInfo.uReason = pVmxTransient->uExitReason;
16112 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16113 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16114 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16115 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
16116 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16117
16118 VBOXSTRICTRC rcStrict = IEMExecDecodedVmwrite(pVCpu, &ExitInfo);
16119 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16120 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16121 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16122 {
16123 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16124 rcStrict = VINF_SUCCESS;
16125 }
16126 return rcStrict;
16127}
16128
16129
16130/**
16131 * VM-exit handler for VMXOFF (VMX_EXIT_VMXOFF). Unconditional VM-exit.
16132 */
16133HMVMX_EXIT_DECL hmR0VmxExitVmxoff(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16134{
16135 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16136
16137 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16138 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR4
16139 | CPUMCTX_EXTRN_HWVIRT
16140 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
16141 AssertRCReturn(rc, rc);
16142
16143 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16144
16145 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxoff(pVCpu, pVmxTransient->cbExitInstr);
16146 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16147 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_HWVIRT);
16148 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16149 {
16150 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16151 rcStrict = VINF_SUCCESS;
16152 }
16153 return rcStrict;
16154}
16155
16156
16157/**
16158 * VM-exit handler for VMXON (VMX_EXIT_VMXON). Unconditional VM-exit.
16159 */
16160HMVMX_EXIT_DECL hmR0VmxExitVmxon(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16161{
16162 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16163
16164 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16165 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16166 hmR0VmxReadExitQualVmcs(pVmxTransient);
16167 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16168 | CPUMCTX_EXTRN_HWVIRT
16169 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16170 AssertRCReturn(rc, rc);
16171
16172 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16173
16174 VMXVEXITINFO ExitInfo;
16175 RT_ZERO(ExitInfo);
16176 ExitInfo.uReason = pVmxTransient->uExitReason;
16177 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16178 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16179 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16180 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16181
16182 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxon(pVCpu, &ExitInfo);
16183 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16184 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16185 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16186 {
16187 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16188 rcStrict = VINF_SUCCESS;
16189 }
16190 return rcStrict;
16191}
16192
16193
16194/**
16195 * VM-exit handler for INVVPID (VMX_EXIT_INVVPID). Unconditional VM-exit.
16196 */
16197HMVMX_EXIT_DECL hmR0VmxExitInvvpid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16198{
16199 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16200
16201 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16202 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16203 hmR0VmxReadExitQualVmcs(pVmxTransient);
16204 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16205 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16206 AssertRCReturn(rc, rc);
16207
16208 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16209
16210 VMXVEXITINFO ExitInfo;
16211 RT_ZERO(ExitInfo);
16212 ExitInfo.uReason = pVmxTransient->uExitReason;
16213 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16214 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16215 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16216 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16217
16218 VBOXSTRICTRC rcStrict = IEMExecDecodedInvvpid(pVCpu, &ExitInfo);
16219 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16220 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16221 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16222 {
16223 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16224 rcStrict = VINF_SUCCESS;
16225 }
16226 return rcStrict;
16227}
16228#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16229/** @} */
16230
16231
16232#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16233/** @name Nested-guest VM-exit handlers.
16234 * @{
16235 */
16236/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16237/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Nested-guest VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16238/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16239
16240/**
16241 * Nested-guest VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
16242 * Conditional VM-exit.
16243 */
16244HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16245{
16246 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16247
16248 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16249
16250 uint64_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
16251 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
16252 Assert(VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo));
16253
16254 switch (uExitIntType)
16255 {
16256 /*
16257 * Physical NMIs:
16258 * We shouldn't direct host physical NMIs to the nested-guest. Dispatch it to the host.
16259 */
16260 case VMX_EXIT_INT_INFO_TYPE_NMI:
16261 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
16262
16263 /*
16264 * Hardware exceptions,
16265 * Software exceptions,
16266 * Privileged software exceptions:
16267 * Figure out if the exception must be delivered to the guest or the nested-guest.
16268 */
16269 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
16270 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
16271 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
16272 {
16273 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16274 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16275 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16276 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16277
16278 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16279 bool const fIntercept = CPUMIsGuestVmxXcptInterceptSet(pCtx, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo),
16280 pVmxTransient->uExitIntErrorCode);
16281 if (fIntercept)
16282 {
16283 /* Exit qualification is required for debug and page-fault exceptions. */
16284 hmR0VmxReadExitQualVmcs(pVmxTransient);
16285
16286 /*
16287 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged
16288 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
16289 * length. However, if delivery of a software interrupt, software exception or privileged
16290 * software exception causes a VM-exit, that too provides the VM-exit instruction length.
16291 */
16292 VMXVEXITINFO ExitInfo;
16293 RT_ZERO(ExitInfo);
16294 ExitInfo.uReason = pVmxTransient->uExitReason;
16295 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16296 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16297
16298 VMXVEXITEVENTINFO ExitEventInfo;
16299 RT_ZERO(ExitEventInfo);
16300 ExitEventInfo.uExitIntInfo = pVmxTransient->uExitIntInfo;
16301 ExitEventInfo.uExitIntErrCode = pVmxTransient->uExitIntErrorCode;
16302 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16303 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16304
16305#ifdef DEBUG_ramshankar
16306 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16307 Log4Func(("exit_int_info=%#RX32 err_code=%#RX32 exit_qual=%#RX64\n", pVmxTransient->uExitIntInfo,
16308 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual));
16309 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
16310 {
16311 Log4Func(("idt_info=%#RX32 idt_errcode=%#RX32 cr2=%#RX64\n", pVmxTransient->uIdtVectoringInfo,
16312 pVmxTransient->uIdtVectoringErrorCode, pCtx->cr2));
16313 }
16314#endif
16315 return IEMExecVmxVmexitXcpt(pVCpu, &ExitInfo, &ExitEventInfo);
16316 }
16317
16318 /* Nested paging is currently a requirement, otherwise we would need to handle shadow #PFs in hmR0VmxExitXcptPF. */
16319 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
16320 return hmR0VmxExitXcpt(pVCpu, pVmxTransient);
16321 }
16322
16323 /*
16324 * Software interrupts:
16325 * VM-exits cannot be caused by software interrupts.
16326 *
16327 * External interrupts:
16328 * This should only happen when "acknowledge external interrupts on VM-exit"
16329 * control is set. However, we never set this when executing a guest or
16330 * nested-guest. For nested-guests it is emulated while injecting interrupts into
16331 * the guest.
16332 */
16333 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
16334 case VMX_EXIT_INT_INFO_TYPE_EXT_INT:
16335 default:
16336 {
16337 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
16338 return VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
16339 }
16340 }
16341}
16342
16343
16344/**
16345 * Nested-guest VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT).
16346 * Unconditional VM-exit.
16347 */
16348HMVMX_EXIT_DECL hmR0VmxExitTripleFaultNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16349{
16350 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16351 return IEMExecVmxVmexitTripleFault(pVCpu);
16352}
16353
16354
16355/**
16356 * Nested-guest VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
16357 */
16358HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16359{
16360 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16361
16362 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
16363 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16364 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16365}
16366
16367
16368/**
16369 * Nested-guest VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
16370 */
16371HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16372{
16373 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16374
16375 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT))
16376 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16377 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16378}
16379
16380
16381/**
16382 * Nested-guest VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH).
16383 * Unconditional VM-exit.
16384 */
16385HMVMX_EXIT_DECL hmR0VmxExitTaskSwitchNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16386{
16387 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16388
16389 hmR0VmxReadExitQualVmcs(pVmxTransient);
16390 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16391 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16392 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16393
16394 VMXVEXITINFO ExitInfo;
16395 RT_ZERO(ExitInfo);
16396 ExitInfo.uReason = pVmxTransient->uExitReason;
16397 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16398 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16399
16400 VMXVEXITEVENTINFO ExitEventInfo;
16401 RT_ZERO(ExitEventInfo);
16402 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16403 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16404 return IEMExecVmxVmexitTaskSwitch(pVCpu, &ExitInfo, &ExitEventInfo);
16405}
16406
16407
16408/**
16409 * Nested-guest VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
16410 */
16411HMVMX_EXIT_DECL hmR0VmxExitHltNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16412{
16413 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16414
16415 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_HLT_EXIT))
16416 {
16417 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16418 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16419 }
16420 return hmR0VmxExitHlt(pVCpu, pVmxTransient);
16421}
16422
16423
16424/**
16425 * Nested-guest VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
16426 */
16427HMVMX_EXIT_DECL hmR0VmxExitInvlpgNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16428{
16429 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16430
16431 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16432 {
16433 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16434 hmR0VmxReadExitQualVmcs(pVmxTransient);
16435
16436 VMXVEXITINFO ExitInfo;
16437 RT_ZERO(ExitInfo);
16438 ExitInfo.uReason = pVmxTransient->uExitReason;
16439 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16440 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16441 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16442 }
16443 return hmR0VmxExitInvlpg(pVCpu, pVmxTransient);
16444}
16445
16446
16447/**
16448 * Nested-guest VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
16449 */
16450HMVMX_EXIT_DECL hmR0VmxExitRdpmcNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16451{
16452 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16453
16454 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDPMC_EXIT))
16455 {
16456 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16457 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16458 }
16459 return hmR0VmxExitRdpmc(pVCpu, pVmxTransient);
16460}
16461
16462
16463/**
16464 * Nested-guest VM-exit handler for VMREAD (VMX_EXIT_VMREAD) and VMWRITE
16465 * (VMX_EXIT_VMWRITE). Conditional VM-exit.
16466 */
16467HMVMX_EXIT_DECL hmR0VmxExitVmreadVmwriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16468{
16469 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16470
16471 Assert( pVmxTransient->uExitReason == VMX_EXIT_VMREAD
16472 || pVmxTransient->uExitReason == VMX_EXIT_VMWRITE);
16473
16474 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16475
16476 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
16477 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16478 uint64_t u64VmcsField = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16479
16480 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
16481 if (!CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
16482 u64VmcsField &= UINT64_C(0xffffffff);
16483
16484 if (CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, pVmxTransient->uExitReason, u64VmcsField))
16485 {
16486 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16487 hmR0VmxReadExitQualVmcs(pVmxTransient);
16488
16489 VMXVEXITINFO ExitInfo;
16490 RT_ZERO(ExitInfo);
16491 ExitInfo.uReason = pVmxTransient->uExitReason;
16492 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16493 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16494 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16495 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16496 }
16497
16498 if (pVmxTransient->uExitReason == VMX_EXIT_VMREAD)
16499 return hmR0VmxExitVmread(pVCpu, pVmxTransient);
16500 return hmR0VmxExitVmwrite(pVCpu, pVmxTransient);
16501}
16502
16503
16504/**
16505 * Nested-guest VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
16506 */
16507HMVMX_EXIT_DECL hmR0VmxExitRdtscNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16508{
16509 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16510
16511 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16512 {
16513 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16514 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16515 }
16516
16517 return hmR0VmxExitRdtsc(pVCpu, pVmxTransient);
16518}
16519
16520
16521/**
16522 * Nested-guest VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX).
16523 * Conditional VM-exit.
16524 */
16525HMVMX_EXIT_DECL hmR0VmxExitMovCRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16526{
16527 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16528
16529 hmR0VmxReadExitQualVmcs(pVmxTransient);
16530 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16531
16532 VBOXSTRICTRC rcStrict;
16533 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual);
16534 switch (uAccessType)
16535 {
16536 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
16537 {
16538 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16539 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
16540 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16541 uint64_t const uNewCrX = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16542
16543 bool fIntercept;
16544 switch (iCrReg)
16545 {
16546 case 0:
16547 case 4:
16548 fIntercept = CPUMIsGuestVmxMovToCr0Cr4InterceptSet(&pVCpu->cpum.GstCtx, iCrReg, uNewCrX);
16549 break;
16550
16551 case 3:
16552 fIntercept = CPUMIsGuestVmxMovToCr3InterceptSet(pVCpu, uNewCrX);
16553 break;
16554
16555 case 8:
16556 fIntercept = CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_CR8_LOAD_EXIT);
16557 break;
16558
16559 default:
16560 fIntercept = false;
16561 break;
16562 }
16563 if (fIntercept)
16564 {
16565 VMXVEXITINFO ExitInfo;
16566 RT_ZERO(ExitInfo);
16567 ExitInfo.uReason = pVmxTransient->uExitReason;
16568 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16569 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16570 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16571 }
16572 else
16573 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
16574 break;
16575 }
16576
16577 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
16578 {
16579 /*
16580 * CR0/CR4 reads do not cause VM-exits, the read-shadow is used (subject to masking).
16581 * CR2 reads do not cause a VM-exit.
16582 * CR3 reads cause a VM-exit depending on the "CR3 store exiting" control.
16583 * CR8 reads cause a VM-exit depending on the "CR8 store exiting" control.
16584 */
16585 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16586 if ( iCrReg == 3
16587 || iCrReg == 8)
16588 {
16589 static const uint32_t s_auCrXReadIntercepts[] = { 0, 0, 0, VMX_PROC_CTLS_CR3_STORE_EXIT, 0,
16590 0, 0, 0, VMX_PROC_CTLS_CR8_STORE_EXIT };
16591 uint32_t const uIntercept = s_auCrXReadIntercepts[iCrReg];
16592 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, uIntercept))
16593 {
16594 VMXVEXITINFO ExitInfo;
16595 RT_ZERO(ExitInfo);
16596 ExitInfo.uReason = pVmxTransient->uExitReason;
16597 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16598 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16599 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16600 }
16601 else
16602 {
16603 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
16604 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
16605 }
16606 }
16607 else
16608 {
16609 AssertMsgFailed(("MOV from CR%d VM-exit must not happen\n", iCrReg));
16610 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, iCrReg);
16611 }
16612 break;
16613 }
16614
16615 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
16616 {
16617 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
16618 Assert(pVmcsNstGst);
16619 uint64_t const uGstHostMask = pVmcsNstGst->u64Cr0Mask.u;
16620 uint64_t const uReadShadow = pVmcsNstGst->u64Cr0ReadShadow.u;
16621 if ( (uGstHostMask & X86_CR0_TS)
16622 && (uReadShadow & X86_CR0_TS))
16623 {
16624 VMXVEXITINFO ExitInfo;
16625 RT_ZERO(ExitInfo);
16626 ExitInfo.uReason = pVmxTransient->uExitReason;
16627 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16628 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16629 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16630 }
16631 else
16632 rcStrict = hmR0VmxExitClts(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr);
16633 break;
16634 }
16635
16636 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
16637 {
16638 RTGCPTR GCPtrEffDst;
16639 uint16_t const uNewMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(pVmxTransient->uExitQual);
16640 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(pVmxTransient->uExitQual);
16641 if (fMemOperand)
16642 {
16643 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
16644 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
16645 }
16646 else
16647 GCPtrEffDst = NIL_RTGCPTR;
16648
16649 if (CPUMIsGuestVmxLmswInterceptSet(&pVCpu->cpum.GstCtx, uNewMsw))
16650 {
16651 VMXVEXITINFO ExitInfo;
16652 RT_ZERO(ExitInfo);
16653 ExitInfo.uReason = pVmxTransient->uExitReason;
16654 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16655 ExitInfo.u64GuestLinearAddr = GCPtrEffDst;
16656 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16657 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16658 }
16659 else
16660 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, uNewMsw, GCPtrEffDst);
16661 break;
16662 }
16663
16664 default:
16665 {
16666 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
16667 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
16668 }
16669 }
16670
16671 if (rcStrict == VINF_IEM_RAISED_XCPT)
16672 {
16673 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16674 rcStrict = VINF_SUCCESS;
16675 }
16676 return rcStrict;
16677}
16678
16679
16680/**
16681 * Nested-guest VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX).
16682 * Conditional VM-exit.
16683 */
16684HMVMX_EXIT_DECL hmR0VmxExitMovDRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16685{
16686 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16687
16688 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MOV_DR_EXIT))
16689 {
16690 hmR0VmxReadExitQualVmcs(pVmxTransient);
16691 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16692
16693 VMXVEXITINFO ExitInfo;
16694 RT_ZERO(ExitInfo);
16695 ExitInfo.uReason = pVmxTransient->uExitReason;
16696 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16697 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16698 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16699 }
16700 return hmR0VmxExitMovDRx(pVCpu, pVmxTransient);
16701}
16702
16703
16704/**
16705 * Nested-guest VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR).
16706 * Conditional VM-exit.
16707 */
16708HMVMX_EXIT_DECL hmR0VmxExitIoInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16709{
16710 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16711
16712 hmR0VmxReadExitQualVmcs(pVmxTransient);
16713
16714 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
16715 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
16716 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
16717
16718 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
16719 uint8_t const cbAccess = s_aIOSizes[uIOSize];
16720 if (CPUMIsGuestVmxIoInterceptSet(pVCpu, uIOPort, cbAccess))
16721 {
16722 /*
16723 * IN/OUT instruction:
16724 * - Provides VM-exit instruction length.
16725 *
16726 * INS/OUTS instruction:
16727 * - Provides VM-exit instruction length.
16728 * - Provides Guest-linear address.
16729 * - Optionally provides VM-exit instruction info (depends on CPU feature).
16730 */
16731 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16732 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16733
16734 /* Make sure we don't use stale/uninitialized VMX-transient info. below. */
16735 pVmxTransient->ExitInstrInfo.u = 0;
16736 pVmxTransient->uGuestLinearAddr = 0;
16737
16738 bool const fVmxInsOutsInfo = pVM->cpum.ro.GuestFeatures.fVmxInsOutInfo;
16739 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
16740 if (fIOString)
16741 {
16742 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
16743 if (fVmxInsOutsInfo)
16744 {
16745 Assert(RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS)); /* Paranoia. */
16746 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16747 }
16748 }
16749
16750 VMXVEXITINFO ExitInfo;
16751 RT_ZERO(ExitInfo);
16752 ExitInfo.uReason = pVmxTransient->uExitReason;
16753 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16754 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16755 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16756 ExitInfo.u64GuestLinearAddr = pVmxTransient->uGuestLinearAddr;
16757 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16758 }
16759 return hmR0VmxExitIoInstr(pVCpu, pVmxTransient);
16760}
16761
16762
16763/**
16764 * Nested-guest VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
16765 */
16766HMVMX_EXIT_DECL hmR0VmxExitRdmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16767{
16768 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16769
16770 uint32_t fMsrpm;
16771 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
16772 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
16773 else
16774 fMsrpm = VMXMSRPM_EXIT_RD;
16775
16776 if (fMsrpm & VMXMSRPM_EXIT_RD)
16777 {
16778 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16779 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16780 }
16781 return hmR0VmxExitRdmsr(pVCpu, pVmxTransient);
16782}
16783
16784
16785/**
16786 * Nested-guest VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
16787 */
16788HMVMX_EXIT_DECL hmR0VmxExitWrmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16789{
16790 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16791
16792 uint32_t fMsrpm;
16793 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
16794 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
16795 else
16796 fMsrpm = VMXMSRPM_EXIT_WR;
16797
16798 if (fMsrpm & VMXMSRPM_EXIT_WR)
16799 {
16800 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16801 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16802 }
16803 return hmR0VmxExitWrmsr(pVCpu, pVmxTransient);
16804}
16805
16806
16807/**
16808 * Nested-guest VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
16809 */
16810HMVMX_EXIT_DECL hmR0VmxExitMwaitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16811{
16812 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16813
16814 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MWAIT_EXIT))
16815 {
16816 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16817 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16818 }
16819 return hmR0VmxExitMwait(pVCpu, pVmxTransient);
16820}
16821
16822
16823/**
16824 * Nested-guest VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional
16825 * VM-exit.
16826 */
16827HMVMX_EXIT_DECL hmR0VmxExitMtfNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16828{
16829 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16830
16831 /** @todo NSTVMX: Should consider debugging nested-guests using VM debugger. */
16832 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
16833 VMXVEXITINFO ExitInfo;
16834 RT_ZERO(ExitInfo);
16835 ExitInfo.uReason = pVmxTransient->uExitReason;
16836 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
16837 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
16838}
16839
16840
16841/**
16842 * Nested-guest VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
16843 */
16844HMVMX_EXIT_DECL hmR0VmxExitMonitorNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16845{
16846 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16847
16848 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MONITOR_EXIT))
16849 {
16850 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16851 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16852 }
16853 return hmR0VmxExitMonitor(pVCpu, pVmxTransient);
16854}
16855
16856
16857/**
16858 * Nested-guest VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
16859 */
16860HMVMX_EXIT_DECL hmR0VmxExitPauseNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16861{
16862 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16863
16864 /** @todo NSTVMX: Think about this more. Does the outer guest need to intercept
16865 * PAUSE when executing a nested-guest? If it does not, we would not need
16866 * to check for the intercepts here. Just call VM-exit... */
16867
16868 /* The CPU would have already performed the necessary CPL checks for PAUSE-loop exiting. */
16869 if ( CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_PAUSE_EXIT)
16870 || CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
16871 {
16872 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16873 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16874 }
16875 return hmR0VmxExitPause(pVCpu, pVmxTransient);
16876}
16877
16878
16879/**
16880 * Nested-guest VM-exit handler for when the TPR value is lowered below the
16881 * specified threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
16882 */
16883HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThresholdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16884{
16885 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16886
16887 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_TPR_SHADOW))
16888 {
16889 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
16890 VMXVEXITINFO ExitInfo;
16891 RT_ZERO(ExitInfo);
16892 ExitInfo.uReason = pVmxTransient->uExitReason;
16893 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
16894 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
16895 }
16896 return hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient);
16897}
16898
16899
16900/**
16901 * Nested-guest VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional
16902 * VM-exit.
16903 */
16904HMVMX_EXIT_DECL hmR0VmxExitApicAccessNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16905{
16906 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16907
16908 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16909 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16910 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16911 hmR0VmxReadExitQualVmcs(pVmxTransient);
16912
16913 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
16914
16915 Log4Func(("at offset %#x type=%u\n", VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual),
16916 VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual)));
16917
16918 VMXVEXITINFO ExitInfo;
16919 RT_ZERO(ExitInfo);
16920 ExitInfo.uReason = pVmxTransient->uExitReason;
16921 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16922 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16923
16924 VMXVEXITEVENTINFO ExitEventInfo;
16925 RT_ZERO(ExitEventInfo);
16926 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16927 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16928 return IEMExecVmxVmexitApicAccess(pVCpu, &ExitInfo, &ExitEventInfo);
16929}
16930
16931
16932/**
16933 * Nested-guest VM-exit handler for APIC write emulation (VMX_EXIT_APIC_WRITE).
16934 * Conditional VM-exit.
16935 */
16936HMVMX_EXIT_DECL hmR0VmxExitApicWriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16937{
16938 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16939
16940 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_APIC_REG_VIRT));
16941 hmR0VmxReadExitQualVmcs(pVmxTransient);
16942 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
16943}
16944
16945
16946/**
16947 * Nested-guest VM-exit handler for virtualized EOI (VMX_EXIT_VIRTUALIZED_EOI).
16948 * Conditional VM-exit.
16949 */
16950HMVMX_EXIT_DECL hmR0VmxExitVirtEoiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16951{
16952 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16953
16954 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_INT_DELIVERY));
16955 hmR0VmxReadExitQualVmcs(pVmxTransient);
16956 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
16957}
16958
16959
16960/**
16961 * Nested-guest VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
16962 */
16963HMVMX_EXIT_DECL hmR0VmxExitRdtscpNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16964{
16965 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16966
16967 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16968 {
16969 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_RDTSCP));
16970 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16971 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16972 }
16973 return hmR0VmxExitRdtscp(pVCpu, pVmxTransient);
16974}
16975
16976
16977/**
16978 * Nested-guest VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
16979 */
16980HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16981{
16982 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16983
16984 if (CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_WBINVD_EXIT))
16985 {
16986 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16987 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16988 }
16989 return hmR0VmxExitWbinvd(pVCpu, pVmxTransient);
16990}
16991
16992
16993/**
16994 * Nested-guest VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
16995 */
16996HMVMX_EXIT_DECL hmR0VmxExitInvpcidNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16997{
16998 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16999
17000 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
17001 {
17002 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_INVPCID));
17003 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17004 hmR0VmxReadExitQualVmcs(pVmxTransient);
17005 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17006
17007 VMXVEXITINFO ExitInfo;
17008 RT_ZERO(ExitInfo);
17009 ExitInfo.uReason = pVmxTransient->uExitReason;
17010 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17011 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17012 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17013 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17014 }
17015 return hmR0VmxExitInvpcid(pVCpu, pVmxTransient);
17016}
17017
17018
17019/**
17020 * Nested-guest VM-exit handler for invalid-guest state
17021 * (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error VM-exit.
17022 */
17023HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestStateNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17024{
17025 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17026
17027 /*
17028 * Currently this should never happen because we fully emulate VMLAUNCH/VMRESUME in IEM.
17029 * So if it does happen, it indicates a bug possibly in the hardware-assisted VMX code.
17030 * Handle it like it's in an invalid guest state of the outer guest.
17031 *
17032 * When the fast path is implemented, this should be changed to cause the corresponding
17033 * nested-guest VM-exit.
17034 */
17035 return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
17036}
17037
17038
17039/**
17040 * Nested-guest VM-exit handler for instructions that cause VM-exits uncondtionally
17041 * and only provide the instruction length.
17042 *
17043 * Unconditional VM-exit.
17044 */
17045HMVMX_EXIT_DECL hmR0VmxExitInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17046{
17047 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17048
17049#ifdef VBOX_STRICT
17050 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
17051 switch (pVmxTransient->uExitReason)
17052 {
17053 case VMX_EXIT_ENCLS:
17054 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_ENCLS_EXIT));
17055 break;
17056
17057 case VMX_EXIT_VMFUNC:
17058 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_VMFUNC));
17059 break;
17060 }
17061#endif
17062
17063 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17064 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17065}
17066
17067
17068/**
17069 * Nested-guest VM-exit handler for instructions that provide instruction length as
17070 * well as more information.
17071 *
17072 * Unconditional VM-exit.
17073 */
17074HMVMX_EXIT_DECL hmR0VmxExitInstrWithInfoNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17075{
17076 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17077
17078#ifdef VBOX_STRICT
17079 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
17080 switch (pVmxTransient->uExitReason)
17081 {
17082 case VMX_EXIT_GDTR_IDTR_ACCESS:
17083 case VMX_EXIT_LDTR_TR_ACCESS:
17084 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_DESC_TABLE_EXIT));
17085 break;
17086
17087 case VMX_EXIT_RDRAND:
17088 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_RDRAND_EXIT));
17089 break;
17090
17091 case VMX_EXIT_RDSEED:
17092 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_RDSEED_EXIT));
17093 break;
17094
17095 case VMX_EXIT_XSAVES:
17096 case VMX_EXIT_XRSTORS:
17097 /** @todo NSTVMX: Verify XSS-bitmap. */
17098 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_XSAVES_XRSTORS));
17099 break;
17100
17101 case VMX_EXIT_UMWAIT:
17102 case VMX_EXIT_TPAUSE:
17103 Assert(CPUMIsGuestVmxProcCtlsSet(pCtx, VMX_PROC_CTLS_RDTSC_EXIT));
17104 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_USER_WAIT_PAUSE));
17105 break;
17106 }
17107#endif
17108
17109 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17110 hmR0VmxReadExitQualVmcs(pVmxTransient);
17111 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17112
17113 VMXVEXITINFO ExitInfo;
17114 RT_ZERO(ExitInfo);
17115 ExitInfo.uReason = pVmxTransient->uExitReason;
17116 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17117 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17118 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17119 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17120}
17121
17122/** @} */
17123#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
17124
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