VirtualBox

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

Last change on this file since 91289 was 91271, checked in by vboxsync, 3 years ago

VMM: bugref:10092 Moved the PAE PDPTEs out of PGM into CPUMCTX.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 740.3 KB
Line 
1/* $Id: HMVMXR0.cpp 91271 2021-09-16 07:42:37Z vboxsync $ */
2/** @file
3 * HM VMX (Intel VT-x) - Host Context Ring-0.
4 */
5
6/*
7 * Copyright (C) 2012-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_HM
23#define VMCPU_INCL_CPUM_GST_CTX
24#include <iprt/x86.h>
25#include <iprt/asm-amd64-x86.h>
26#include <iprt/thread.h>
27#include <iprt/mem.h>
28#include <iprt/mp.h>
29
30#include <VBox/vmm/pdmapi.h>
31#include <VBox/vmm/dbgf.h>
32#include <VBox/vmm/iem.h>
33#include <VBox/vmm/iom.h>
34#include <VBox/vmm/tm.h>
35#include <VBox/vmm/em.h>
36#include <VBox/vmm/gim.h>
37#include <VBox/vmm/apic.h>
38#include "HMInternal.h"
39#include <VBox/vmm/vmcc.h>
40#include <VBox/vmm/hmvmxinline.h>
41#include "HMVMXR0.h"
42#include "dtrace/VBoxVMM.h"
43
44#ifdef DEBUG_ramshankar
45# define HMVMX_ALWAYS_SAVE_GUEST_RFLAGS
46# define HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
47# define HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE
48# define HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
49# define HMVMX_ALWAYS_CLEAN_TRANSIENT
50# define HMVMX_ALWAYS_CHECK_GUEST_STATE
51# define HMVMX_ALWAYS_TRAP_ALL_XCPTS
52# define HMVMX_ALWAYS_TRAP_PF
53# define HMVMX_ALWAYS_FLUSH_TLB
54# define HMVMX_ALWAYS_SWAP_EFER
55#endif
56
57
58/*********************************************************************************************************************************
59* Defined Constants And Macros *
60*********************************************************************************************************************************/
61/** Use the function table. */
62#define HMVMX_USE_FUNCTION_TABLE
63
64/** Determine which tagged-TLB flush handler to use. */
65#define HMVMX_FLUSH_TAGGED_TLB_EPT_VPID 0
66#define HMVMX_FLUSH_TAGGED_TLB_EPT 1
67#define HMVMX_FLUSH_TAGGED_TLB_VPID 2
68#define HMVMX_FLUSH_TAGGED_TLB_NONE 3
69
70/**
71 * Flags to skip redundant reads of some common VMCS fields that are not part of
72 * the guest-CPU or VCPU state but are needed while handling VM-exits.
73 */
74#define HMVMX_READ_IDT_VECTORING_INFO RT_BIT_32(0)
75#define HMVMX_READ_IDT_VECTORING_ERROR_CODE RT_BIT_32(1)
76#define HMVMX_READ_EXIT_QUALIFICATION RT_BIT_32(2)
77#define HMVMX_READ_EXIT_INSTR_LEN RT_BIT_32(3)
78#define HMVMX_READ_EXIT_INTERRUPTION_INFO RT_BIT_32(4)
79#define HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE RT_BIT_32(5)
80#define HMVMX_READ_EXIT_INSTR_INFO RT_BIT_32(6)
81#define HMVMX_READ_GUEST_LINEAR_ADDR RT_BIT_32(7)
82#define HMVMX_READ_GUEST_PHYSICAL_ADDR RT_BIT_32(8)
83#define HMVMX_READ_GUEST_PENDING_DBG_XCPTS RT_BIT_32(9)
84
85/** All the VMCS fields required for processing of exception/NMI VM-exits. */
86#define HMVMX_READ_XCPT_INFO ( HMVMX_READ_EXIT_INTERRUPTION_INFO \
87 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE \
88 | HMVMX_READ_EXIT_INSTR_LEN \
89 | HMVMX_READ_IDT_VECTORING_INFO \
90 | HMVMX_READ_IDT_VECTORING_ERROR_CODE)
91
92/** Assert that all the given fields have been read from the VMCS. */
93#ifdef VBOX_STRICT
94# define HMVMX_ASSERT_READ(a_pVmxTransient, a_fReadFields) \
95 do { \
96 uint32_t const fVmcsFieldRead = ASMAtomicUoReadU32(&pVmxTransient->fVmcsFieldsRead); \
97 Assert((fVmcsFieldRead & (a_fReadFields)) == (a_fReadFields)); \
98 } while (0)
99#else
100# define HMVMX_ASSERT_READ(a_pVmxTransient, a_fReadFields) do { } while (0)
101#endif
102
103/**
104 * Subset of the guest-CPU state that is kept by VMX R0 code while executing the
105 * guest using hardware-assisted VMX.
106 *
107 * This excludes state like GPRs (other than RSP) which are always are
108 * swapped and restored across the world-switch and also registers like EFER,
109 * MSR which cannot be modified by the guest without causing a VM-exit.
110 */
111#define HMVMX_CPUMCTX_EXTRN_ALL ( CPUMCTX_EXTRN_RIP \
112 | CPUMCTX_EXTRN_RFLAGS \
113 | CPUMCTX_EXTRN_RSP \
114 | CPUMCTX_EXTRN_SREG_MASK \
115 | CPUMCTX_EXTRN_TABLE_MASK \
116 | CPUMCTX_EXTRN_KERNEL_GS_BASE \
117 | CPUMCTX_EXTRN_SYSCALL_MSRS \
118 | CPUMCTX_EXTRN_SYSENTER_MSRS \
119 | CPUMCTX_EXTRN_TSC_AUX \
120 | CPUMCTX_EXTRN_OTHER_MSRS \
121 | CPUMCTX_EXTRN_CR0 \
122 | CPUMCTX_EXTRN_CR3 \
123 | CPUMCTX_EXTRN_CR4 \
124 | CPUMCTX_EXTRN_DR7 \
125 | CPUMCTX_EXTRN_HWVIRT \
126 | CPUMCTX_EXTRN_HM_VMX_MASK)
127
128/**
129 * Exception bitmap mask for real-mode guests (real-on-v86).
130 *
131 * We need to intercept all exceptions manually except:
132 * - \#AC and \#DB are always intercepted to prevent the CPU from deadlocking
133 * due to bugs in Intel CPUs.
134 * - \#PF need not be intercepted even in real-mode if we have nested paging
135 * support.
136 */
137#define HMVMX_REAL_MODE_XCPT_MASK ( RT_BIT(X86_XCPT_DE) /* always: | RT_BIT(X86_XCPT_DB) */ | RT_BIT(X86_XCPT_NMI) \
138 | RT_BIT(X86_XCPT_BP) | RT_BIT(X86_XCPT_OF) | RT_BIT(X86_XCPT_BR) \
139 | RT_BIT(X86_XCPT_UD) | RT_BIT(X86_XCPT_NM) | RT_BIT(X86_XCPT_DF) \
140 | RT_BIT(X86_XCPT_CO_SEG_OVERRUN) | RT_BIT(X86_XCPT_TS) | RT_BIT(X86_XCPT_NP) \
141 | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_GP) /* RT_BIT(X86_XCPT_PF) */ \
142 | RT_BIT(X86_XCPT_MF) /* always: | RT_BIT(X86_XCPT_AC) */ | RT_BIT(X86_XCPT_MC) \
143 | RT_BIT(X86_XCPT_XF))
144
145/** Maximum VM-instruction error number. */
146#define HMVMX_INSTR_ERROR_MAX 28
147
148/** Profiling macro. */
149#ifdef HM_PROFILE_EXIT_DISPATCH
150# define HMVMX_START_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitDispatch, ed)
151# define HMVMX_STOP_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitDispatch, ed)
152#else
153# define HMVMX_START_EXIT_DISPATCH_PROF() do { } while (0)
154# define HMVMX_STOP_EXIT_DISPATCH_PROF() do { } while (0)
155#endif
156
157/** Assert that preemption is disabled or covered by thread-context hooks. */
158#define HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu) Assert( VMMR0ThreadCtxHookIsEnabled((a_pVCpu)) \
159 || !RTThreadPreemptIsEnabled(NIL_RTTHREAD))
160
161/** Assert that we haven't migrated CPUs when thread-context hooks are not
162 * used. */
163#define HMVMX_ASSERT_CPU_SAFE(a_pVCpu) AssertMsg( VMMR0ThreadCtxHookIsEnabled((a_pVCpu)) \
164 || (a_pVCpu)->hmr0.s.idEnteredCpu == RTMpCpuId(), \
165 ("Illegal migration! Entered on CPU %u Current %u\n", \
166 (a_pVCpu)->hmr0.s.idEnteredCpu, RTMpCpuId()))
167
168/** Asserts that the given CPUMCTX_EXTRN_XXX bits are present in the guest-CPU
169 * context. */
170#define HMVMX_CPUMCTX_ASSERT(a_pVCpu, a_fExtrnMbz) AssertMsg(!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fExtrnMbz)), \
171 ("fExtrn=%#RX64 fExtrnMbz=%#RX64\n", \
172 (a_pVCpu)->cpum.GstCtx.fExtrn, (a_fExtrnMbz)))
173
174/** Log the VM-exit reason with an easily visible marker to identify it in a
175 * potential sea of logging data. */
176#define HMVMX_LOG_EXIT(a_pVCpu, a_uExitReason) \
177 do { \
178 Log4(("VM-exit: vcpu[%RU32] %85s -v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-\n", (a_pVCpu)->idCpu, \
179 HMGetVmxExitName(a_uExitReason))); \
180 } while (0) \
181
182
183/*********************************************************************************************************************************
184* Structures and Typedefs *
185*********************************************************************************************************************************/
186/**
187 * VMX per-VCPU transient state.
188 *
189 * A state structure for holding miscellaneous information across
190 * VMX non-root operation and restored after the transition.
191 *
192 * Note: The members are ordered and aligned such that the most
193 * frequently used ones (in the guest execution loop) fall within
194 * the first cache line.
195 */
196typedef struct VMXTRANSIENT
197{
198 /** Mask of currently read VMCS fields; HMVMX_READ_XXX. */
199 uint32_t fVmcsFieldsRead;
200 /** The guest's TPR value used for TPR shadowing. */
201 uint8_t u8GuestTpr;
202 uint8_t abAlignment0[3];
203
204 /** Whether the VM-exit was caused by a page-fault during delivery of an
205 * external interrupt or NMI. */
206 bool fVectoringPF;
207 /** Whether the VM-exit was caused by a page-fault during delivery of a
208 * contributory exception or a page-fault. */
209 bool fVectoringDoublePF;
210 /** Whether the VM-entry failed or not. */
211 bool fVMEntryFailed;
212 /** Whether the TSC_AUX MSR needs to be removed from the auto-load/store MSR
213 * area after VM-exit. */
214 bool fRemoveTscAuxMsr;
215 /** Whether TSC-offsetting and VMX-preemption timer was updated before VM-entry. */
216 bool fUpdatedTscOffsettingAndPreemptTimer;
217 /** Whether we are currently executing a nested-guest. */
218 bool fIsNestedGuest;
219 /** Whether the guest debug state was active at the time of VM-exit. */
220 bool fWasGuestDebugStateActive;
221 /** Whether the hyper debug state was active at the time of VM-exit. */
222 bool fWasHyperDebugStateActive;
223
224 /** The basic VM-exit reason. */
225 uint32_t uExitReason;
226 /** The VM-exit interruption error code. */
227 uint32_t uExitIntErrorCode;
228
229 /** The host's rflags/eflags. */
230 RTCCUINTREG fEFlags;
231
232 /** The VM-exit exit code qualification. */
233 uint64_t uExitQual;
234
235 /** The VMCS info. object. */
236 PVMXVMCSINFO pVmcsInfo;
237
238 /** The VM-exit interruption-information field. */
239 uint32_t uExitIntInfo;
240 /** The VM-exit instruction-length field. */
241 uint32_t cbExitInstr;
242
243 /** The VM-exit instruction-information field. */
244 VMXEXITINSTRINFO ExitInstrInfo;
245 /** IDT-vectoring information field. */
246 uint32_t uIdtVectoringInfo;
247
248 /** IDT-vectoring error code. */
249 uint32_t uIdtVectoringErrorCode;
250 uint32_t u32Alignment0;
251
252 /** The Guest-linear address. */
253 uint64_t uGuestLinearAddr;
254
255 /** The Guest-physical address. */
256 uint64_t uGuestPhysicalAddr;
257
258 /** The Guest pending-debug exceptions. */
259 uint64_t uGuestPendingDbgXcpts;
260
261 /** The VM-entry interruption-information field. */
262 uint32_t uEntryIntInfo;
263 /** The VM-entry exception error code field. */
264 uint32_t uEntryXcptErrorCode;
265
266 /** The VM-entry instruction length field. */
267 uint32_t cbEntryInstr;
268} VMXTRANSIENT;
269AssertCompileMemberSize(VMXTRANSIENT, ExitInstrInfo, sizeof(uint32_t));
270AssertCompileMemberAlignment(VMXTRANSIENT, fVmcsFieldsRead, 8);
271AssertCompileMemberAlignment(VMXTRANSIENT, fVectoringPF, 8);
272AssertCompileMemberAlignment(VMXTRANSIENT, uExitReason, 8);
273AssertCompileMemberAlignment(VMXTRANSIENT, fEFlags, 8);
274AssertCompileMemberAlignment(VMXTRANSIENT, uExitQual, 8);
275AssertCompileMemberAlignment(VMXTRANSIENT, pVmcsInfo, 8);
276AssertCompileMemberAlignment(VMXTRANSIENT, uExitIntInfo, 8);
277AssertCompileMemberAlignment(VMXTRANSIENT, ExitInstrInfo, 8);
278AssertCompileMemberAlignment(VMXTRANSIENT, uIdtVectoringErrorCode, 8);
279AssertCompileMemberAlignment(VMXTRANSIENT, uGuestLinearAddr, 8);
280AssertCompileMemberAlignment(VMXTRANSIENT, uGuestPhysicalAddr, 8);
281AssertCompileMemberAlignment(VMXTRANSIENT, uEntryIntInfo, 8);
282AssertCompileMemberAlignment(VMXTRANSIENT, cbEntryInstr, 8);
283/** Pointer to VMX transient state. */
284typedef VMXTRANSIENT *PVMXTRANSIENT;
285/** Pointer to a const VMX transient state. */
286typedef const VMXTRANSIENT *PCVMXTRANSIENT;
287
288/**
289 * VMX page allocation information.
290 */
291typedef struct
292{
293 uint32_t fValid; /**< Whether to allocate this page (e.g, based on a CPU feature). */
294 uint32_t uPadding0; /**< Padding to ensure array of these structs are aligned to a multiple of 8. */
295 PRTHCPHYS pHCPhys; /**< Where to store the host-physical address of the allocation. */
296 PRTR0PTR ppVirt; /**< Where to store the host-virtual address of the allocation. */
297} VMXPAGEALLOCINFO;
298/** Pointer to VMX page-allocation info. */
299typedef VMXPAGEALLOCINFO *PVMXPAGEALLOCINFO;
300/** Pointer to a const VMX page-allocation info. */
301typedef const VMXPAGEALLOCINFO *PCVMXPAGEALLOCINFO;
302AssertCompileSizeAlignment(VMXPAGEALLOCINFO, 8);
303
304/**
305 * Memory operand read or write access.
306 */
307typedef enum VMXMEMACCESS
308{
309 VMXMEMACCESS_READ = 0,
310 VMXMEMACCESS_WRITE = 1
311} VMXMEMACCESS;
312
313/**
314 * VMX VM-exit handler.
315 *
316 * @returns Strict VBox status code (i.e. informational status codes too).
317 * @param pVCpu The cross context virtual CPU structure.
318 * @param pVmxTransient The VMX-transient structure.
319 */
320#ifndef HMVMX_USE_FUNCTION_TABLE
321typedef VBOXSTRICTRC FNVMXEXITHANDLER(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
322#else
323typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNVMXEXITHANDLER,(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient));
324/** Pointer to VM-exit handler. */
325typedef FNVMXEXITHANDLER *PFNVMXEXITHANDLER;
326#endif
327
328/**
329 * VMX VM-exit handler, non-strict status code.
330 *
331 * This is generally the same as FNVMXEXITHANDLER, the NSRC bit is just FYI.
332 *
333 * @returns VBox status code, no informational status code returned.
334 * @param pVCpu The cross context virtual CPU structure.
335 * @param pVmxTransient The VMX-transient structure.
336 *
337 * @remarks This is not used on anything returning VERR_EM_INTERPRETER as the
338 * use of that status code will be replaced with VINF_EM_SOMETHING
339 * later when switching over to IEM.
340 */
341#ifndef HMVMX_USE_FUNCTION_TABLE
342typedef int FNVMXEXITHANDLERNSRC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
343#else
344typedef FNVMXEXITHANDLER FNVMXEXITHANDLERNSRC;
345#endif
346
347
348/*********************************************************************************************************************************
349* Internal Functions *
350*********************************************************************************************************************************/
351#ifndef HMVMX_USE_FUNCTION_TABLE
352DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
353# define HMVMX_EXIT_DECL DECLINLINE(VBOXSTRICTRC)
354# define HMVMX_EXIT_NSRC_DECL DECLINLINE(int)
355#else
356# define HMVMX_EXIT_DECL static DECLCALLBACK(VBOXSTRICTRC)
357# define HMVMX_EXIT_NSRC_DECL HMVMX_EXIT_DECL
358#endif
359#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
360DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
361#endif
362
363static int hmR0VmxImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat);
364
365/** @name VM-exit handler prototypes.
366 * @{
367 */
368static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmi;
369static FNVMXEXITHANDLER hmR0VmxExitExtInt;
370static FNVMXEXITHANDLER hmR0VmxExitTripleFault;
371static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindow;
372static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindow;
373static FNVMXEXITHANDLER hmR0VmxExitTaskSwitch;
374static FNVMXEXITHANDLER hmR0VmxExitCpuid;
375static FNVMXEXITHANDLER hmR0VmxExitGetsec;
376static FNVMXEXITHANDLER hmR0VmxExitHlt;
377static FNVMXEXITHANDLERNSRC hmR0VmxExitInvd;
378static FNVMXEXITHANDLER hmR0VmxExitInvlpg;
379static FNVMXEXITHANDLER hmR0VmxExitRdpmc;
380static FNVMXEXITHANDLER hmR0VmxExitVmcall;
381#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
382static FNVMXEXITHANDLER hmR0VmxExitVmclear;
383static FNVMXEXITHANDLER hmR0VmxExitVmlaunch;
384static FNVMXEXITHANDLER hmR0VmxExitVmptrld;
385static FNVMXEXITHANDLER hmR0VmxExitVmptrst;
386static FNVMXEXITHANDLER hmR0VmxExitVmread;
387static FNVMXEXITHANDLER hmR0VmxExitVmresume;
388static FNVMXEXITHANDLER hmR0VmxExitVmwrite;
389static FNVMXEXITHANDLER hmR0VmxExitVmxoff;
390static FNVMXEXITHANDLER hmR0VmxExitVmxon;
391static FNVMXEXITHANDLER hmR0VmxExitInvvpid;
392#endif
393static FNVMXEXITHANDLER hmR0VmxExitRdtsc;
394static FNVMXEXITHANDLER hmR0VmxExitMovCRx;
395static FNVMXEXITHANDLER hmR0VmxExitMovDRx;
396static FNVMXEXITHANDLER hmR0VmxExitIoInstr;
397static FNVMXEXITHANDLER hmR0VmxExitRdmsr;
398static FNVMXEXITHANDLER hmR0VmxExitWrmsr;
399static FNVMXEXITHANDLER hmR0VmxExitMwait;
400static FNVMXEXITHANDLER hmR0VmxExitMtf;
401static FNVMXEXITHANDLER hmR0VmxExitMonitor;
402static FNVMXEXITHANDLER hmR0VmxExitPause;
403static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThreshold;
404static FNVMXEXITHANDLER hmR0VmxExitApicAccess;
405static FNVMXEXITHANDLER hmR0VmxExitEptViolation;
406static FNVMXEXITHANDLER hmR0VmxExitEptMisconfig;
407static FNVMXEXITHANDLER hmR0VmxExitRdtscp;
408static FNVMXEXITHANDLER hmR0VmxExitPreemptTimer;
409static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvd;
410static FNVMXEXITHANDLER hmR0VmxExitXsetbv;
411static FNVMXEXITHANDLER hmR0VmxExitInvpcid;
412static FNVMXEXITHANDLERNSRC hmR0VmxExitSetPendingXcptUD;
413static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestState;
414static FNVMXEXITHANDLERNSRC hmR0VmxExitErrUnexpected;
415/** @} */
416
417#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
418/** @name Nested-guest VM-exit handler prototypes.
419 * @{
420 */
421static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmiNested;
422static FNVMXEXITHANDLER hmR0VmxExitTripleFaultNested;
423static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindowNested;
424static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindowNested;
425static FNVMXEXITHANDLER hmR0VmxExitTaskSwitchNested;
426static FNVMXEXITHANDLER hmR0VmxExitHltNested;
427static FNVMXEXITHANDLER hmR0VmxExitInvlpgNested;
428static FNVMXEXITHANDLER hmR0VmxExitRdpmcNested;
429static FNVMXEXITHANDLER hmR0VmxExitVmreadVmwriteNested;
430static FNVMXEXITHANDLER hmR0VmxExitRdtscNested;
431static FNVMXEXITHANDLER hmR0VmxExitMovCRxNested;
432static FNVMXEXITHANDLER hmR0VmxExitMovDRxNested;
433static FNVMXEXITHANDLER hmR0VmxExitIoInstrNested;
434static FNVMXEXITHANDLER hmR0VmxExitRdmsrNested;
435static FNVMXEXITHANDLER hmR0VmxExitWrmsrNested;
436static FNVMXEXITHANDLER hmR0VmxExitMwaitNested;
437static FNVMXEXITHANDLER hmR0VmxExitMtfNested;
438static FNVMXEXITHANDLER hmR0VmxExitMonitorNested;
439static FNVMXEXITHANDLER hmR0VmxExitPauseNested;
440static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThresholdNested;
441static FNVMXEXITHANDLER hmR0VmxExitApicAccessNested;
442static FNVMXEXITHANDLER hmR0VmxExitApicWriteNested;
443static FNVMXEXITHANDLER hmR0VmxExitVirtEoiNested;
444static FNVMXEXITHANDLER hmR0VmxExitRdtscpNested;
445static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvdNested;
446static FNVMXEXITHANDLER hmR0VmxExitInvpcidNested;
447static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestStateNested;
448static FNVMXEXITHANDLER hmR0VmxExitInstrNested;
449static FNVMXEXITHANDLER hmR0VmxExitInstrWithInfoNested;
450/** @} */
451#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
452
453
454/*********************************************************************************************************************************
455* Global Variables *
456*********************************************************************************************************************************/
457#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
458/**
459 * Array of all VMCS fields.
460 * Any fields added to the VT-x spec. should be added here.
461 *
462 * Currently only used to derive shadow VMCS fields for hardware-assisted execution
463 * of nested-guests.
464 */
465static const uint32_t g_aVmcsFields[] =
466{
467 /* 16-bit control fields. */
468 VMX_VMCS16_VPID,
469 VMX_VMCS16_POSTED_INT_NOTIFY_VECTOR,
470 VMX_VMCS16_EPTP_INDEX,
471
472 /* 16-bit guest-state fields. */
473 VMX_VMCS16_GUEST_ES_SEL,
474 VMX_VMCS16_GUEST_CS_SEL,
475 VMX_VMCS16_GUEST_SS_SEL,
476 VMX_VMCS16_GUEST_DS_SEL,
477 VMX_VMCS16_GUEST_FS_SEL,
478 VMX_VMCS16_GUEST_GS_SEL,
479 VMX_VMCS16_GUEST_LDTR_SEL,
480 VMX_VMCS16_GUEST_TR_SEL,
481 VMX_VMCS16_GUEST_INTR_STATUS,
482 VMX_VMCS16_GUEST_PML_INDEX,
483
484 /* 16-bits host-state fields. */
485 VMX_VMCS16_HOST_ES_SEL,
486 VMX_VMCS16_HOST_CS_SEL,
487 VMX_VMCS16_HOST_SS_SEL,
488 VMX_VMCS16_HOST_DS_SEL,
489 VMX_VMCS16_HOST_FS_SEL,
490 VMX_VMCS16_HOST_GS_SEL,
491 VMX_VMCS16_HOST_TR_SEL,
492
493 /* 64-bit control fields. */
494 VMX_VMCS64_CTRL_IO_BITMAP_A_FULL,
495 VMX_VMCS64_CTRL_IO_BITMAP_A_HIGH,
496 VMX_VMCS64_CTRL_IO_BITMAP_B_FULL,
497 VMX_VMCS64_CTRL_IO_BITMAP_B_HIGH,
498 VMX_VMCS64_CTRL_MSR_BITMAP_FULL,
499 VMX_VMCS64_CTRL_MSR_BITMAP_HIGH,
500 VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL,
501 VMX_VMCS64_CTRL_EXIT_MSR_STORE_HIGH,
502 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL,
503 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_HIGH,
504 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL,
505 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_HIGH,
506 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL,
507 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_HIGH,
508 VMX_VMCS64_CTRL_EXEC_PML_ADDR_FULL,
509 VMX_VMCS64_CTRL_EXEC_PML_ADDR_HIGH,
510 VMX_VMCS64_CTRL_TSC_OFFSET_FULL,
511 VMX_VMCS64_CTRL_TSC_OFFSET_HIGH,
512 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL,
513 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_HIGH,
514 VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL,
515 VMX_VMCS64_CTRL_APIC_ACCESSADDR_HIGH,
516 VMX_VMCS64_CTRL_POSTED_INTR_DESC_FULL,
517 VMX_VMCS64_CTRL_POSTED_INTR_DESC_HIGH,
518 VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL,
519 VMX_VMCS64_CTRL_VMFUNC_CTRLS_HIGH,
520 VMX_VMCS64_CTRL_EPTP_FULL,
521 VMX_VMCS64_CTRL_EPTP_HIGH,
522 VMX_VMCS64_CTRL_EOI_BITMAP_0_FULL,
523 VMX_VMCS64_CTRL_EOI_BITMAP_0_HIGH,
524 VMX_VMCS64_CTRL_EOI_BITMAP_1_FULL,
525 VMX_VMCS64_CTRL_EOI_BITMAP_1_HIGH,
526 VMX_VMCS64_CTRL_EOI_BITMAP_2_FULL,
527 VMX_VMCS64_CTRL_EOI_BITMAP_2_HIGH,
528 VMX_VMCS64_CTRL_EOI_BITMAP_3_FULL,
529 VMX_VMCS64_CTRL_EOI_BITMAP_3_HIGH,
530 VMX_VMCS64_CTRL_EPTP_LIST_FULL,
531 VMX_VMCS64_CTRL_EPTP_LIST_HIGH,
532 VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL,
533 VMX_VMCS64_CTRL_VMREAD_BITMAP_HIGH,
534 VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL,
535 VMX_VMCS64_CTRL_VMWRITE_BITMAP_HIGH,
536 VMX_VMCS64_CTRL_VE_XCPT_INFO_ADDR_FULL,
537 VMX_VMCS64_CTRL_VE_XCPT_INFO_ADDR_HIGH,
538 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_FULL,
539 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_HIGH,
540 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_FULL,
541 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_HIGH,
542 VMX_VMCS64_CTRL_SPPTP_FULL,
543 VMX_VMCS64_CTRL_SPPTP_HIGH,
544 VMX_VMCS64_CTRL_TSC_MULTIPLIER_FULL,
545 VMX_VMCS64_CTRL_TSC_MULTIPLIER_HIGH,
546 VMX_VMCS64_CTRL_PROC_EXEC3_FULL,
547 VMX_VMCS64_CTRL_PROC_EXEC3_HIGH,
548 VMX_VMCS64_CTRL_ENCLV_EXITING_BITMAP_FULL,
549 VMX_VMCS64_CTRL_ENCLV_EXITING_BITMAP_HIGH,
550
551 /* 64-bit read-only data fields. */
552 VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL,
553 VMX_VMCS64_RO_GUEST_PHYS_ADDR_HIGH,
554
555 /* 64-bit guest-state fields. */
556 VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL,
557 VMX_VMCS64_GUEST_VMCS_LINK_PTR_HIGH,
558 VMX_VMCS64_GUEST_DEBUGCTL_FULL,
559 VMX_VMCS64_GUEST_DEBUGCTL_HIGH,
560 VMX_VMCS64_GUEST_PAT_FULL,
561 VMX_VMCS64_GUEST_PAT_HIGH,
562 VMX_VMCS64_GUEST_EFER_FULL,
563 VMX_VMCS64_GUEST_EFER_HIGH,
564 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL,
565 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_HIGH,
566 VMX_VMCS64_GUEST_PDPTE0_FULL,
567 VMX_VMCS64_GUEST_PDPTE0_HIGH,
568 VMX_VMCS64_GUEST_PDPTE1_FULL,
569 VMX_VMCS64_GUEST_PDPTE1_HIGH,
570 VMX_VMCS64_GUEST_PDPTE2_FULL,
571 VMX_VMCS64_GUEST_PDPTE2_HIGH,
572 VMX_VMCS64_GUEST_PDPTE3_FULL,
573 VMX_VMCS64_GUEST_PDPTE3_HIGH,
574 VMX_VMCS64_GUEST_BNDCFGS_FULL,
575 VMX_VMCS64_GUEST_BNDCFGS_HIGH,
576 VMX_VMCS64_GUEST_RTIT_CTL_FULL,
577 VMX_VMCS64_GUEST_RTIT_CTL_HIGH,
578 VMX_VMCS64_GUEST_PKRS_FULL,
579 VMX_VMCS64_GUEST_PKRS_HIGH,
580
581 /* 64-bit host-state fields. */
582 VMX_VMCS64_HOST_PAT_FULL,
583 VMX_VMCS64_HOST_PAT_HIGH,
584 VMX_VMCS64_HOST_EFER_FULL,
585 VMX_VMCS64_HOST_EFER_HIGH,
586 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL,
587 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_HIGH,
588 VMX_VMCS64_HOST_PKRS_FULL,
589 VMX_VMCS64_HOST_PKRS_HIGH,
590
591 /* 32-bit control fields. */
592 VMX_VMCS32_CTRL_PIN_EXEC,
593 VMX_VMCS32_CTRL_PROC_EXEC,
594 VMX_VMCS32_CTRL_EXCEPTION_BITMAP,
595 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK,
596 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH,
597 VMX_VMCS32_CTRL_CR3_TARGET_COUNT,
598 VMX_VMCS32_CTRL_EXIT,
599 VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT,
600 VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT,
601 VMX_VMCS32_CTRL_ENTRY,
602 VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT,
603 VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO,
604 VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE,
605 VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH,
606 VMX_VMCS32_CTRL_TPR_THRESHOLD,
607 VMX_VMCS32_CTRL_PROC_EXEC2,
608 VMX_VMCS32_CTRL_PLE_GAP,
609 VMX_VMCS32_CTRL_PLE_WINDOW,
610
611 /* 32-bits read-only fields. */
612 VMX_VMCS32_RO_VM_INSTR_ERROR,
613 VMX_VMCS32_RO_EXIT_REASON,
614 VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO,
615 VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE,
616 VMX_VMCS32_RO_IDT_VECTORING_INFO,
617 VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE,
618 VMX_VMCS32_RO_EXIT_INSTR_LENGTH,
619 VMX_VMCS32_RO_EXIT_INSTR_INFO,
620
621 /* 32-bit guest-state fields. */
622 VMX_VMCS32_GUEST_ES_LIMIT,
623 VMX_VMCS32_GUEST_CS_LIMIT,
624 VMX_VMCS32_GUEST_SS_LIMIT,
625 VMX_VMCS32_GUEST_DS_LIMIT,
626 VMX_VMCS32_GUEST_FS_LIMIT,
627 VMX_VMCS32_GUEST_GS_LIMIT,
628 VMX_VMCS32_GUEST_LDTR_LIMIT,
629 VMX_VMCS32_GUEST_TR_LIMIT,
630 VMX_VMCS32_GUEST_GDTR_LIMIT,
631 VMX_VMCS32_GUEST_IDTR_LIMIT,
632 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
633 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
634 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
635 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
636 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
637 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS,
638 VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS,
639 VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS,
640 VMX_VMCS32_GUEST_INT_STATE,
641 VMX_VMCS32_GUEST_ACTIVITY_STATE,
642 VMX_VMCS32_GUEST_SMBASE,
643 VMX_VMCS32_GUEST_SYSENTER_CS,
644 VMX_VMCS32_PREEMPT_TIMER_VALUE,
645
646 /* 32-bit host-state fields. */
647 VMX_VMCS32_HOST_SYSENTER_CS,
648
649 /* Natural-width control fields. */
650 VMX_VMCS_CTRL_CR0_MASK,
651 VMX_VMCS_CTRL_CR4_MASK,
652 VMX_VMCS_CTRL_CR0_READ_SHADOW,
653 VMX_VMCS_CTRL_CR4_READ_SHADOW,
654 VMX_VMCS_CTRL_CR3_TARGET_VAL0,
655 VMX_VMCS_CTRL_CR3_TARGET_VAL1,
656 VMX_VMCS_CTRL_CR3_TARGET_VAL2,
657 VMX_VMCS_CTRL_CR3_TARGET_VAL3,
658
659 /* Natural-width read-only data fields. */
660 VMX_VMCS_RO_EXIT_QUALIFICATION,
661 VMX_VMCS_RO_IO_RCX,
662 VMX_VMCS_RO_IO_RSI,
663 VMX_VMCS_RO_IO_RDI,
664 VMX_VMCS_RO_IO_RIP,
665 VMX_VMCS_RO_GUEST_LINEAR_ADDR,
666
667 /* Natural-width guest-state field */
668 VMX_VMCS_GUEST_CR0,
669 VMX_VMCS_GUEST_CR3,
670 VMX_VMCS_GUEST_CR4,
671 VMX_VMCS_GUEST_ES_BASE,
672 VMX_VMCS_GUEST_CS_BASE,
673 VMX_VMCS_GUEST_SS_BASE,
674 VMX_VMCS_GUEST_DS_BASE,
675 VMX_VMCS_GUEST_FS_BASE,
676 VMX_VMCS_GUEST_GS_BASE,
677 VMX_VMCS_GUEST_LDTR_BASE,
678 VMX_VMCS_GUEST_TR_BASE,
679 VMX_VMCS_GUEST_GDTR_BASE,
680 VMX_VMCS_GUEST_IDTR_BASE,
681 VMX_VMCS_GUEST_DR7,
682 VMX_VMCS_GUEST_RSP,
683 VMX_VMCS_GUEST_RIP,
684 VMX_VMCS_GUEST_RFLAGS,
685 VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS,
686 VMX_VMCS_GUEST_SYSENTER_ESP,
687 VMX_VMCS_GUEST_SYSENTER_EIP,
688 VMX_VMCS_GUEST_S_CET,
689 VMX_VMCS_GUEST_SSP,
690 VMX_VMCS_GUEST_INTR_SSP_TABLE_ADDR,
691
692 /* Natural-width host-state fields */
693 VMX_VMCS_HOST_CR0,
694 VMX_VMCS_HOST_CR3,
695 VMX_VMCS_HOST_CR4,
696 VMX_VMCS_HOST_FS_BASE,
697 VMX_VMCS_HOST_GS_BASE,
698 VMX_VMCS_HOST_TR_BASE,
699 VMX_VMCS_HOST_GDTR_BASE,
700 VMX_VMCS_HOST_IDTR_BASE,
701 VMX_VMCS_HOST_SYSENTER_ESP,
702 VMX_VMCS_HOST_SYSENTER_EIP,
703 VMX_VMCS_HOST_RSP,
704 VMX_VMCS_HOST_RIP,
705 VMX_VMCS_HOST_S_CET,
706 VMX_VMCS_HOST_SSP,
707 VMX_VMCS_HOST_INTR_SSP_TABLE_ADDR
708};
709#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
710
711#ifdef VBOX_STRICT
712static const uint32_t g_aVmcsSegBase[] =
713{
714 VMX_VMCS_GUEST_ES_BASE,
715 VMX_VMCS_GUEST_CS_BASE,
716 VMX_VMCS_GUEST_SS_BASE,
717 VMX_VMCS_GUEST_DS_BASE,
718 VMX_VMCS_GUEST_FS_BASE,
719 VMX_VMCS_GUEST_GS_BASE
720};
721static const uint32_t g_aVmcsSegSel[] =
722{
723 VMX_VMCS16_GUEST_ES_SEL,
724 VMX_VMCS16_GUEST_CS_SEL,
725 VMX_VMCS16_GUEST_SS_SEL,
726 VMX_VMCS16_GUEST_DS_SEL,
727 VMX_VMCS16_GUEST_FS_SEL,
728 VMX_VMCS16_GUEST_GS_SEL
729};
730static const uint32_t g_aVmcsSegLimit[] =
731{
732 VMX_VMCS32_GUEST_ES_LIMIT,
733 VMX_VMCS32_GUEST_CS_LIMIT,
734 VMX_VMCS32_GUEST_SS_LIMIT,
735 VMX_VMCS32_GUEST_DS_LIMIT,
736 VMX_VMCS32_GUEST_FS_LIMIT,
737 VMX_VMCS32_GUEST_GS_LIMIT
738};
739static const uint32_t g_aVmcsSegAttr[] =
740{
741 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
742 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
743 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
744 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
745 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
746 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS
747};
748AssertCompile(RT_ELEMENTS(g_aVmcsSegSel) == X86_SREG_COUNT);
749AssertCompile(RT_ELEMENTS(g_aVmcsSegLimit) == X86_SREG_COUNT);
750AssertCompile(RT_ELEMENTS(g_aVmcsSegBase) == X86_SREG_COUNT);
751AssertCompile(RT_ELEMENTS(g_aVmcsSegAttr) == X86_SREG_COUNT);
752#endif /* VBOX_STRICT */
753
754#ifdef HMVMX_USE_FUNCTION_TABLE
755/**
756 * VMX_EXIT dispatch table.
757 */
758static const struct CLANG11NOTHROWWEIRDNESS { PFNVMXEXITHANDLER pfn; } g_aVMExitHandlers[VMX_EXIT_MAX + 1] =
759{
760 /* 0 VMX_EXIT_XCPT_OR_NMI */ { hmR0VmxExitXcptOrNmi },
761 /* 1 VMX_EXIT_EXT_INT */ { hmR0VmxExitExtInt },
762 /* 2 VMX_EXIT_TRIPLE_FAULT */ { hmR0VmxExitTripleFault },
763 /* 3 VMX_EXIT_INIT_SIGNAL */ { hmR0VmxExitErrUnexpected },
764 /* 4 VMX_EXIT_SIPI */ { hmR0VmxExitErrUnexpected },
765 /* 5 VMX_EXIT_IO_SMI */ { hmR0VmxExitErrUnexpected },
766 /* 6 VMX_EXIT_SMI */ { hmR0VmxExitErrUnexpected },
767 /* 7 VMX_EXIT_INT_WINDOW */ { hmR0VmxExitIntWindow },
768 /* 8 VMX_EXIT_NMI_WINDOW */ { hmR0VmxExitNmiWindow },
769 /* 9 VMX_EXIT_TASK_SWITCH */ { hmR0VmxExitTaskSwitch },
770 /* 10 VMX_EXIT_CPUID */ { hmR0VmxExitCpuid },
771 /* 11 VMX_EXIT_GETSEC */ { hmR0VmxExitGetsec },
772 /* 12 VMX_EXIT_HLT */ { hmR0VmxExitHlt },
773 /* 13 VMX_EXIT_INVD */ { hmR0VmxExitInvd },
774 /* 14 VMX_EXIT_INVLPG */ { hmR0VmxExitInvlpg },
775 /* 15 VMX_EXIT_RDPMC */ { hmR0VmxExitRdpmc },
776 /* 16 VMX_EXIT_RDTSC */ { hmR0VmxExitRdtsc },
777 /* 17 VMX_EXIT_RSM */ { hmR0VmxExitErrUnexpected },
778 /* 18 VMX_EXIT_VMCALL */ { hmR0VmxExitVmcall },
779#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
780 /* 19 VMX_EXIT_VMCLEAR */ { hmR0VmxExitVmclear },
781 /* 20 VMX_EXIT_VMLAUNCH */ { hmR0VmxExitVmlaunch },
782 /* 21 VMX_EXIT_VMPTRLD */ { hmR0VmxExitVmptrld },
783 /* 22 VMX_EXIT_VMPTRST */ { hmR0VmxExitVmptrst },
784 /* 23 VMX_EXIT_VMREAD */ { hmR0VmxExitVmread },
785 /* 24 VMX_EXIT_VMRESUME */ { hmR0VmxExitVmresume },
786 /* 25 VMX_EXIT_VMWRITE */ { hmR0VmxExitVmwrite },
787 /* 26 VMX_EXIT_VMXOFF */ { hmR0VmxExitVmxoff },
788 /* 27 VMX_EXIT_VMXON */ { hmR0VmxExitVmxon },
789#else
790 /* 19 VMX_EXIT_VMCLEAR */ { hmR0VmxExitSetPendingXcptUD },
791 /* 20 VMX_EXIT_VMLAUNCH */ { hmR0VmxExitSetPendingXcptUD },
792 /* 21 VMX_EXIT_VMPTRLD */ { hmR0VmxExitSetPendingXcptUD },
793 /* 22 VMX_EXIT_VMPTRST */ { hmR0VmxExitSetPendingXcptUD },
794 /* 23 VMX_EXIT_VMREAD */ { hmR0VmxExitSetPendingXcptUD },
795 /* 24 VMX_EXIT_VMRESUME */ { hmR0VmxExitSetPendingXcptUD },
796 /* 25 VMX_EXIT_VMWRITE */ { hmR0VmxExitSetPendingXcptUD },
797 /* 26 VMX_EXIT_VMXOFF */ { hmR0VmxExitSetPendingXcptUD },
798 /* 27 VMX_EXIT_VMXON */ { hmR0VmxExitSetPendingXcptUD },
799#endif
800 /* 28 VMX_EXIT_MOV_CRX */ { hmR0VmxExitMovCRx },
801 /* 29 VMX_EXIT_MOV_DRX */ { hmR0VmxExitMovDRx },
802 /* 30 VMX_EXIT_IO_INSTR */ { hmR0VmxExitIoInstr },
803 /* 31 VMX_EXIT_RDMSR */ { hmR0VmxExitRdmsr },
804 /* 32 VMX_EXIT_WRMSR */ { hmR0VmxExitWrmsr },
805 /* 33 VMX_EXIT_ERR_INVALID_GUEST_STATE */ { hmR0VmxExitErrInvalidGuestState },
806 /* 34 VMX_EXIT_ERR_MSR_LOAD */ { hmR0VmxExitErrUnexpected },
807 /* 35 UNDEFINED */ { hmR0VmxExitErrUnexpected },
808 /* 36 VMX_EXIT_MWAIT */ { hmR0VmxExitMwait },
809 /* 37 VMX_EXIT_MTF */ { hmR0VmxExitMtf },
810 /* 38 UNDEFINED */ { hmR0VmxExitErrUnexpected },
811 /* 39 VMX_EXIT_MONITOR */ { hmR0VmxExitMonitor },
812 /* 40 VMX_EXIT_PAUSE */ { hmR0VmxExitPause },
813 /* 41 VMX_EXIT_ERR_MACHINE_CHECK */ { hmR0VmxExitErrUnexpected },
814 /* 42 UNDEFINED */ { hmR0VmxExitErrUnexpected },
815 /* 43 VMX_EXIT_TPR_BELOW_THRESHOLD */ { hmR0VmxExitTprBelowThreshold },
816 /* 44 VMX_EXIT_APIC_ACCESS */ { hmR0VmxExitApicAccess },
817 /* 45 VMX_EXIT_VIRTUALIZED_EOI */ { hmR0VmxExitErrUnexpected },
818 /* 46 VMX_EXIT_GDTR_IDTR_ACCESS */ { hmR0VmxExitErrUnexpected },
819 /* 47 VMX_EXIT_LDTR_TR_ACCESS */ { hmR0VmxExitErrUnexpected },
820 /* 48 VMX_EXIT_EPT_VIOLATION */ { hmR0VmxExitEptViolation },
821 /* 49 VMX_EXIT_EPT_MISCONFIG */ { hmR0VmxExitEptMisconfig },
822 /* 50 VMX_EXIT_INVEPT */ { hmR0VmxExitSetPendingXcptUD },
823 /* 51 VMX_EXIT_RDTSCP */ { hmR0VmxExitRdtscp },
824 /* 52 VMX_EXIT_PREEMPT_TIMER */ { hmR0VmxExitPreemptTimer },
825#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
826 /* 53 VMX_EXIT_INVVPID */ { hmR0VmxExitInvvpid },
827#else
828 /* 53 VMX_EXIT_INVVPID */ { hmR0VmxExitSetPendingXcptUD },
829#endif
830 /* 54 VMX_EXIT_WBINVD */ { hmR0VmxExitWbinvd },
831 /* 55 VMX_EXIT_XSETBV */ { hmR0VmxExitXsetbv },
832 /* 56 VMX_EXIT_APIC_WRITE */ { hmR0VmxExitErrUnexpected },
833 /* 57 VMX_EXIT_RDRAND */ { hmR0VmxExitErrUnexpected },
834 /* 58 VMX_EXIT_INVPCID */ { hmR0VmxExitInvpcid },
835 /* 59 VMX_EXIT_VMFUNC */ { hmR0VmxExitErrUnexpected },
836 /* 60 VMX_EXIT_ENCLS */ { hmR0VmxExitErrUnexpected },
837 /* 61 VMX_EXIT_RDSEED */ { hmR0VmxExitErrUnexpected },
838 /* 62 VMX_EXIT_PML_FULL */ { hmR0VmxExitErrUnexpected },
839 /* 63 VMX_EXIT_XSAVES */ { hmR0VmxExitErrUnexpected },
840 /* 64 VMX_EXIT_XRSTORS */ { hmR0VmxExitErrUnexpected },
841 /* 65 UNDEFINED */ { hmR0VmxExitErrUnexpected },
842 /* 66 VMX_EXIT_SPP_EVENT */ { hmR0VmxExitErrUnexpected },
843 /* 67 VMX_EXIT_UMWAIT */ { hmR0VmxExitErrUnexpected },
844 /* 68 VMX_EXIT_TPAUSE */ { hmR0VmxExitErrUnexpected },
845 /* 69 VMX_EXIT_LOADIWKEY */ { hmR0VmxExitErrUnexpected },
846};
847#endif /* HMVMX_USE_FUNCTION_TABLE */
848
849#if defined(VBOX_STRICT) && defined(LOG_ENABLED)
850static const char * const g_apszVmxInstrErrors[HMVMX_INSTR_ERROR_MAX + 1] =
851{
852 /* 0 */ "(Not Used)",
853 /* 1 */ "VMCALL executed in VMX root operation.",
854 /* 2 */ "VMCLEAR with invalid physical address.",
855 /* 3 */ "VMCLEAR with VMXON pointer.",
856 /* 4 */ "VMLAUNCH with non-clear VMCS.",
857 /* 5 */ "VMRESUME with non-launched VMCS.",
858 /* 6 */ "VMRESUME after VMXOFF",
859 /* 7 */ "VM-entry with invalid control fields.",
860 /* 8 */ "VM-entry with invalid host state fields.",
861 /* 9 */ "VMPTRLD with invalid physical address.",
862 /* 10 */ "VMPTRLD with VMXON pointer.",
863 /* 11 */ "VMPTRLD with incorrect revision identifier.",
864 /* 12 */ "VMREAD/VMWRITE from/to unsupported VMCS component.",
865 /* 13 */ "VMWRITE to read-only VMCS component.",
866 /* 14 */ "(Not Used)",
867 /* 15 */ "VMXON executed in VMX root operation.",
868 /* 16 */ "VM-entry with invalid executive-VMCS pointer.",
869 /* 17 */ "VM-entry with non-launched executing VMCS.",
870 /* 18 */ "VM-entry with executive-VMCS pointer not VMXON pointer.",
871 /* 19 */ "VMCALL with non-clear VMCS.",
872 /* 20 */ "VMCALL with invalid VM-exit control fields.",
873 /* 21 */ "(Not Used)",
874 /* 22 */ "VMCALL with incorrect MSEG revision identifier.",
875 /* 23 */ "VMXOFF under dual monitor treatment of SMIs and SMM.",
876 /* 24 */ "VMCALL with invalid SMM-monitor features.",
877 /* 25 */ "VM-entry with invalid VM-execution control fields in executive VMCS.",
878 /* 26 */ "VM-entry with events blocked by MOV SS.",
879 /* 27 */ "(Not Used)",
880 /* 28 */ "Invalid operand to INVEPT/INVVPID."
881};
882#endif /* VBOX_STRICT && LOG_ENABLED */
883
884
885/**
886 * Checks if the given MSR is part of the lastbranch-from-IP MSR stack.
887 * @returns @c true if it's part of LBR stack, @c false otherwise.
888 *
889 * @param pVM The cross context VM structure.
890 * @param idMsr The MSR.
891 * @param pidxMsr Where to store the index of the MSR in the LBR MSR array.
892 * Optional, can be NULL.
893 *
894 * @remarks Must only be called when LBR is enabled.
895 */
896DECL_FORCE_INLINE(bool) hmR0VmxIsLbrBranchFromMsr(PCVMCC pVM, uint32_t idMsr, uint32_t *pidxMsr)
897{
898 Assert(pVM->hmr0.s.vmx.fLbr);
899 Assert(pVM->hmr0.s.vmx.idLbrFromIpMsrFirst);
900 uint32_t const cLbrStack = pVM->hmr0.s.vmx.idLbrFromIpMsrLast - pVM->hmr0.s.vmx.idLbrFromIpMsrFirst + 1;
901 uint32_t const idxMsr = idMsr - pVM->hmr0.s.vmx.idLbrFromIpMsrFirst;
902 if (idxMsr < cLbrStack)
903 {
904 if (pidxMsr)
905 *pidxMsr = idxMsr;
906 return true;
907 }
908 return false;
909}
910
911
912/**
913 * Checks if the given MSR is part of the lastbranch-to-IP MSR stack.
914 * @returns @c true if it's part of LBR stack, @c false otherwise.
915 *
916 * @param pVM The cross context VM structure.
917 * @param idMsr The MSR.
918 * @param pidxMsr Where to store the index of the MSR in the LBR MSR array.
919 * Optional, can be NULL.
920 *
921 * @remarks Must only be called when LBR is enabled and when lastbranch-to-IP MSRs
922 * are supported by the CPU (see hmR0VmxSetupLbrMsrRange).
923 */
924DECL_FORCE_INLINE(bool) hmR0VmxIsLbrBranchToMsr(PCVMCC pVM, uint32_t idMsr, uint32_t *pidxMsr)
925{
926 Assert(pVM->hmr0.s.vmx.fLbr);
927 if (pVM->hmr0.s.vmx.idLbrToIpMsrFirst)
928 {
929 uint32_t const cLbrStack = pVM->hmr0.s.vmx.idLbrToIpMsrLast - pVM->hmr0.s.vmx.idLbrToIpMsrFirst + 1;
930 uint32_t const idxMsr = idMsr - pVM->hmr0.s.vmx.idLbrToIpMsrFirst;
931 if (idxMsr < cLbrStack)
932 {
933 if (pidxMsr)
934 *pidxMsr = idxMsr;
935 return true;
936 }
937 }
938 return false;
939}
940
941
942/**
943 * Gets the CR0 guest/host mask.
944 *
945 * These bits typically does not change through the lifetime of a VM. Any bit set in
946 * this mask is owned by the host/hypervisor and would cause a VM-exit when modified
947 * by the guest.
948 *
949 * @returns The CR0 guest/host mask.
950 * @param pVCpu The cross context virtual CPU structure.
951 */
952static uint64_t hmR0VmxGetFixedCr0Mask(PCVMCPUCC pVCpu)
953{
954 /*
955 * Modifications to CR0 bits that VT-x ignores saving/restoring (CD, ET, NW) and
956 * to CR0 bits that we require for shadow paging (PG) by the guest must cause VM-exits.
957 *
958 * Furthermore, modifications to any bits that are reserved/unspecified currently
959 * by the Intel spec. must also cause a VM-exit. This prevents unpredictable behavior
960 * when future CPUs specify and use currently reserved/unspecified bits.
961 */
962 /** @todo Avoid intercepting CR0.PE with unrestricted guest execution. Fix PGM
963 * enmGuestMode to be in-sync with the current mode. See @bugref{6398}
964 * and @bugref{6944}. */
965 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
966 return ( X86_CR0_PE
967 | X86_CR0_NE
968 | (pVM->hmr0.s.fNestedPaging ? 0 : X86_CR0_WP)
969 | X86_CR0_PG
970 | VMX_EXIT_HOST_CR0_IGNORE_MASK);
971}
972
973
974/**
975 * Gets the CR4 guest/host mask.
976 *
977 * These bits typically does not change through the lifetime of a VM. Any bit set in
978 * this mask is owned by the host/hypervisor and would cause a VM-exit when modified
979 * by the guest.
980 *
981 * @returns The CR4 guest/host mask.
982 * @param pVCpu The cross context virtual CPU structure.
983 */
984static uint64_t hmR0VmxGetFixedCr4Mask(PCVMCPUCC pVCpu)
985{
986 /*
987 * We construct a mask of all CR4 bits that the guest can modify without causing
988 * a VM-exit. Then invert this mask to obtain all CR4 bits that should cause
989 * a VM-exit when the guest attempts to modify them when executing using
990 * hardware-assisted VMX.
991 *
992 * When a feature is not exposed to the guest (and may be present on the host),
993 * we want to intercept guest modifications to the bit so we can emulate proper
994 * behavior (e.g., #GP).
995 *
996 * Furthermore, only modifications to those bits that don't require immediate
997 * emulation is allowed. For e.g., PCIDE is excluded because the behavior
998 * depends on CR3 which might not always be the guest value while executing
999 * using hardware-assisted VMX.
1000 */
1001 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
1002 bool const fFsGsBase = pVM->cpum.ro.GuestFeatures.fFsGsBase;
1003 bool const fXSaveRstor = pVM->cpum.ro.GuestFeatures.fXSaveRstor;
1004 bool const fFxSaveRstor = pVM->cpum.ro.GuestFeatures.fFxSaveRstor;
1005
1006 /*
1007 * Paranoia.
1008 * Ensure features exposed to the guest are present on the host.
1009 */
1010 Assert(!fFsGsBase || pVM->cpum.ro.HostFeatures.fFsGsBase);
1011 Assert(!fXSaveRstor || pVM->cpum.ro.HostFeatures.fXSaveRstor);
1012 Assert(!fFxSaveRstor || pVM->cpum.ro.HostFeatures.fFxSaveRstor);
1013
1014 uint64_t const fGstMask = ( X86_CR4_PVI
1015 | X86_CR4_TSD
1016 | X86_CR4_DE
1017 | X86_CR4_MCE
1018 | X86_CR4_PCE
1019 | X86_CR4_OSXMMEEXCPT
1020 | (fFsGsBase ? X86_CR4_FSGSBASE : 0)
1021 | (fXSaveRstor ? X86_CR4_OSXSAVE : 0)
1022 | (fFxSaveRstor ? X86_CR4_OSFXSR : 0));
1023 return ~fGstMask;
1024}
1025
1026
1027/**
1028 * Gets the active (in use) VMCS info. object for the specified VCPU.
1029 *
1030 * This is either the guest or nested-guest VMCS info. and need not necessarily
1031 * pertain to the "current" VMCS (in the VMX definition of the term). For instance,
1032 * if the VM-entry failed due to an invalid-guest state, we may have "cleared" the
1033 * current VMCS while returning to ring-3. However, the VMCS info. object for that
1034 * VMCS would still be active and returned here so that we could dump the VMCS
1035 * fields to ring-3 for diagnostics. This function is thus only used to
1036 * distinguish between the nested-guest or guest VMCS.
1037 *
1038 * @returns The active VMCS information.
1039 * @param pVCpu The cross context virtual CPU structure.
1040 *
1041 * @thread EMT.
1042 * @remarks This function may be called with preemption or interrupts disabled!
1043 */
1044DECLINLINE(PVMXVMCSINFO) hmGetVmxActiveVmcsInfo(PVMCPUCC pVCpu)
1045{
1046 if (!pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs)
1047 return &pVCpu->hmr0.s.vmx.VmcsInfo;
1048 return &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1049}
1050
1051
1052/**
1053 * Returns whether the VM-exit MSR-store area differs from the VM-exit MSR-load
1054 * area.
1055 *
1056 * @returns @c true if it's different, @c false otherwise.
1057 * @param pVmcsInfo The VMCS info. object.
1058 */
1059DECL_FORCE_INLINE(bool) hmR0VmxIsSeparateExitMsrStoreAreaVmcs(PCVMXVMCSINFO pVmcsInfo)
1060{
1061 return RT_BOOL( pVmcsInfo->pvGuestMsrStore != pVmcsInfo->pvGuestMsrLoad
1062 && pVmcsInfo->pvGuestMsrStore);
1063}
1064
1065
1066/**
1067 * Sets the given Processor-based VM-execution controls.
1068 *
1069 * @param pVmxTransient The VMX-transient structure.
1070 * @param uProcCtls The Processor-based VM-execution controls to set.
1071 */
1072static void hmR0VmxSetProcCtlsVmcs(PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
1073{
1074 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1075 if ((pVmcsInfo->u32ProcCtls & uProcCtls) != uProcCtls)
1076 {
1077 pVmcsInfo->u32ProcCtls |= uProcCtls;
1078 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
1079 AssertRC(rc);
1080 }
1081}
1082
1083
1084/**
1085 * Removes the given Processor-based VM-execution controls.
1086 *
1087 * @param pVCpu The cross context virtual CPU structure.
1088 * @param pVmxTransient The VMX-transient structure.
1089 * @param uProcCtls The Processor-based VM-execution controls to remove.
1090 *
1091 * @remarks When executing a nested-guest, this will not remove any of the specified
1092 * controls if the nested hypervisor has set any one of them.
1093 */
1094static void hmR0VmxRemoveProcCtlsVmcs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
1095{
1096 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1097 if (pVmcsInfo->u32ProcCtls & uProcCtls)
1098 {
1099#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1100 if ( !pVmxTransient->fIsNestedGuest
1101 || !CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, uProcCtls))
1102#else
1103 NOREF(pVCpu);
1104 if (!pVmxTransient->fIsNestedGuest)
1105#endif
1106 {
1107 pVmcsInfo->u32ProcCtls &= ~uProcCtls;
1108 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
1109 AssertRC(rc);
1110 }
1111 }
1112}
1113
1114
1115/**
1116 * Sets the TSC offset for the current VMCS.
1117 *
1118 * @param uTscOffset The TSC offset to set.
1119 * @param pVmcsInfo The VMCS info. object.
1120 */
1121static void hmR0VmxSetTscOffsetVmcs(PVMXVMCSINFO pVmcsInfo, uint64_t uTscOffset)
1122{
1123 if (pVmcsInfo->u64TscOffset != uTscOffset)
1124 {
1125 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, uTscOffset);
1126 AssertRC(rc);
1127 pVmcsInfo->u64TscOffset = uTscOffset;
1128 }
1129}
1130
1131
1132/**
1133 * Adds one or more exceptions to the exception bitmap and commits it to the current
1134 * VMCS.
1135 *
1136 * @param pVmxTransient The VMX-transient structure.
1137 * @param uXcptMask The exception(s) to add.
1138 */
1139static void hmR0VmxAddXcptInterceptMask(PCVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1140{
1141 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1142 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
1143 if ((uXcptBitmap & uXcptMask) != uXcptMask)
1144 {
1145 uXcptBitmap |= uXcptMask;
1146 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
1147 AssertRC(rc);
1148 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
1149 }
1150}
1151
1152
1153/**
1154 * Adds an exception to the exception bitmap and commits it to the current VMCS.
1155 *
1156 * @param pVmxTransient The VMX-transient structure.
1157 * @param uXcpt The exception to add.
1158 */
1159static void hmR0VmxAddXcptIntercept(PCVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1160{
1161 Assert(uXcpt <= X86_XCPT_LAST);
1162 hmR0VmxAddXcptInterceptMask(pVmxTransient, RT_BIT_32(uXcpt));
1163}
1164
1165
1166/**
1167 * Remove one or more exceptions from the exception bitmap and commits it to the
1168 * current VMCS.
1169 *
1170 * This takes care of not removing the exception intercept if a nested-guest
1171 * requires the exception to be intercepted.
1172 *
1173 * @returns VBox status code.
1174 * @param pVCpu The cross context virtual CPU structure.
1175 * @param pVmxTransient The VMX-transient structure.
1176 * @param uXcptMask The exception(s) to remove.
1177 */
1178static int hmR0VmxRemoveXcptInterceptMask(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1179{
1180 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1181 uint32_t u32XcptBitmap = pVmcsInfo->u32XcptBitmap;
1182 if (u32XcptBitmap & uXcptMask)
1183 {
1184#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1185 if (!pVmxTransient->fIsNestedGuest)
1186 { /* likely */ }
1187 else
1188 {
1189 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
1190 uXcptMask &= ~pVmcsNstGst->u32XcptBitmap;
1191 }
1192#endif
1193#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
1194 uXcptMask &= ~( RT_BIT(X86_XCPT_BP)
1195 | RT_BIT(X86_XCPT_DE)
1196 | RT_BIT(X86_XCPT_NM)
1197 | RT_BIT(X86_XCPT_TS)
1198 | RT_BIT(X86_XCPT_UD)
1199 | RT_BIT(X86_XCPT_NP)
1200 | RT_BIT(X86_XCPT_SS)
1201 | RT_BIT(X86_XCPT_GP)
1202 | RT_BIT(X86_XCPT_PF)
1203 | RT_BIT(X86_XCPT_MF));
1204#elif defined(HMVMX_ALWAYS_TRAP_PF)
1205 uXcptMask &= ~RT_BIT(X86_XCPT_PF);
1206#endif
1207 if (uXcptMask)
1208 {
1209 /* Validate we are not removing any essential exception intercepts. */
1210 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging || !(uXcptMask & RT_BIT(X86_XCPT_PF)));
1211 NOREF(pVCpu);
1212 Assert(!(uXcptMask & RT_BIT(X86_XCPT_DB)));
1213 Assert(!(uXcptMask & RT_BIT(X86_XCPT_AC)));
1214
1215 /* Remove it from the exception bitmap. */
1216 u32XcptBitmap &= ~uXcptMask;
1217
1218 /* Commit and update the cache if necessary. */
1219 if (pVmcsInfo->u32XcptBitmap != u32XcptBitmap)
1220 {
1221 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
1222 AssertRC(rc);
1223 pVmcsInfo->u32XcptBitmap = u32XcptBitmap;
1224 }
1225 }
1226 }
1227 return VINF_SUCCESS;
1228}
1229
1230
1231/**
1232 * Remove an exceptions from the exception bitmap and commits it to the current
1233 * VMCS.
1234 *
1235 * @returns VBox status code.
1236 * @param pVCpu The cross context virtual CPU structure.
1237 * @param pVmxTransient The VMX-transient structure.
1238 * @param uXcpt The exception to remove.
1239 */
1240static int hmR0VmxRemoveXcptIntercept(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1241{
1242 return hmR0VmxRemoveXcptInterceptMask(pVCpu, pVmxTransient, RT_BIT(uXcpt));
1243}
1244
1245
1246/**
1247 * Loads the VMCS specified by the VMCS info. object.
1248 *
1249 * @returns VBox status code.
1250 * @param pVmcsInfo The VMCS info. object.
1251 *
1252 * @remarks Can be called with interrupts disabled.
1253 */
1254static int hmR0VmxLoadVmcs(PVMXVMCSINFO pVmcsInfo)
1255{
1256 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1257 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1258
1259 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysVmcs);
1260 if (RT_SUCCESS(rc))
1261 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1262 return rc;
1263}
1264
1265
1266/**
1267 * Clears the VMCS specified by the VMCS info. object.
1268 *
1269 * @returns VBox status code.
1270 * @param pVmcsInfo The VMCS info. object.
1271 *
1272 * @remarks Can be called with interrupts disabled.
1273 */
1274static int hmR0VmxClearVmcs(PVMXVMCSINFO pVmcsInfo)
1275{
1276 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1277 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1278
1279 int rc = VMXClearVmcs(pVmcsInfo->HCPhysVmcs);
1280 if (RT_SUCCESS(rc))
1281 pVmcsInfo->fVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1282 return rc;
1283}
1284
1285
1286#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1287/**
1288 * Loads the shadow VMCS specified by the VMCS info. object.
1289 *
1290 * @returns VBox status code.
1291 * @param pVmcsInfo The VMCS info. object.
1292 *
1293 * @remarks Can be called with interrupts disabled.
1294 */
1295static int hmR0VmxLoadShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1296{
1297 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1298 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1299
1300 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysShadowVmcs);
1301 if (RT_SUCCESS(rc))
1302 pVmcsInfo->fShadowVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1303 return rc;
1304}
1305
1306
1307/**
1308 * Clears the shadow VMCS specified by the VMCS info. object.
1309 *
1310 * @returns VBox status code.
1311 * @param pVmcsInfo The VMCS info. object.
1312 *
1313 * @remarks Can be called with interrupts disabled.
1314 */
1315static int hmR0VmxClearShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1316{
1317 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1318 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1319
1320 int rc = VMXClearVmcs(pVmcsInfo->HCPhysShadowVmcs);
1321 if (RT_SUCCESS(rc))
1322 pVmcsInfo->fShadowVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1323 return rc;
1324}
1325
1326
1327/**
1328 * Switches from and to the specified VMCSes.
1329 *
1330 * @returns VBox status code.
1331 * @param pVmcsInfoFrom The VMCS info. object we are switching from.
1332 * @param pVmcsInfoTo The VMCS info. object we are switching to.
1333 *
1334 * @remarks Called with interrupts disabled.
1335 */
1336static int hmR0VmxSwitchVmcs(PVMXVMCSINFO pVmcsInfoFrom, PVMXVMCSINFO pVmcsInfoTo)
1337{
1338 /*
1339 * Clear the VMCS we are switching out if it has not already been cleared.
1340 * This will sync any CPU internal data back to the VMCS.
1341 */
1342 if (pVmcsInfoFrom->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1343 {
1344 int rc = hmR0VmxClearVmcs(pVmcsInfoFrom);
1345 if (RT_SUCCESS(rc))
1346 {
1347 /*
1348 * The shadow VMCS, if any, would not be active at this point since we
1349 * would have cleared it while importing the virtual hardware-virtualization
1350 * state as part the VMLAUNCH/VMRESUME VM-exit. Hence, there's no need to
1351 * clear the shadow VMCS here, just assert for safety.
1352 */
1353 Assert(!pVmcsInfoFrom->pvShadowVmcs || pVmcsInfoFrom->fShadowVmcsState == VMX_V_VMCS_LAUNCH_STATE_CLEAR);
1354 }
1355 else
1356 return rc;
1357 }
1358
1359 /*
1360 * Clear the VMCS we are switching to if it has not already been cleared.
1361 * This will initialize the VMCS launch state to "clear" required for loading it.
1362 *
1363 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
1364 */
1365 if (pVmcsInfoTo->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1366 {
1367 int rc = hmR0VmxClearVmcs(pVmcsInfoTo);
1368 if (RT_SUCCESS(rc))
1369 { /* likely */ }
1370 else
1371 return rc;
1372 }
1373
1374 /*
1375 * Finally, load the VMCS we are switching to.
1376 */
1377 return hmR0VmxLoadVmcs(pVmcsInfoTo);
1378}
1379
1380
1381/**
1382 * Switches between the guest VMCS and the nested-guest VMCS as specified by the
1383 * caller.
1384 *
1385 * @returns VBox status code.
1386 * @param pVCpu The cross context virtual CPU structure.
1387 * @param fSwitchToNstGstVmcs Whether to switch to the nested-guest VMCS (pass
1388 * true) or guest VMCS (pass false).
1389 */
1390static int hmR0VmxSwitchToGstOrNstGstVmcs(PVMCPUCC pVCpu, bool fSwitchToNstGstVmcs)
1391{
1392 /* Ensure we have synced everything from the guest-CPU context to the VMCS before switching. */
1393 HMVMX_CPUMCTX_ASSERT(pVCpu, HMVMX_CPUMCTX_EXTRN_ALL);
1394
1395 PVMXVMCSINFO pVmcsInfoFrom;
1396 PVMXVMCSINFO pVmcsInfoTo;
1397 if (fSwitchToNstGstVmcs)
1398 {
1399 pVmcsInfoFrom = &pVCpu->hmr0.s.vmx.VmcsInfo;
1400 pVmcsInfoTo = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1401 }
1402 else
1403 {
1404 pVmcsInfoFrom = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1405 pVmcsInfoTo = &pVCpu->hmr0.s.vmx.VmcsInfo;
1406 }
1407
1408 /*
1409 * Disable interrupts to prevent being preempted while we switch the current VMCS as the
1410 * preemption hook code path acquires the current VMCS.
1411 */
1412 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1413
1414 int rc = hmR0VmxSwitchVmcs(pVmcsInfoFrom, pVmcsInfoTo);
1415 if (RT_SUCCESS(rc))
1416 {
1417 pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs = fSwitchToNstGstVmcs;
1418 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcsCopyForRing3 = fSwitchToNstGstVmcs;
1419
1420 /*
1421 * If we are switching to a VMCS that was executed on a different host CPU or was
1422 * never executed before, flag that we need to export the host state before executing
1423 * guest/nested-guest code using hardware-assisted VMX.
1424 *
1425 * This could probably be done in a preemptible context since the preemption hook
1426 * will flag the necessary change in host context. However, since preemption is
1427 * already disabled and to avoid making assumptions about host specific code in
1428 * RTMpCpuId when called with preemption enabled, we'll do this while preemption is
1429 * disabled.
1430 */
1431 if (pVmcsInfoTo->idHostCpuState == RTMpCpuId())
1432 { /* likely */ }
1433 else
1434 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE);
1435
1436 ASMSetFlags(fEFlags);
1437
1438 /*
1439 * We use a different VM-exit MSR-store areas for the guest and nested-guest. Hence,
1440 * flag that we need to update the host MSR values there. Even if we decide in the
1441 * future to share the VM-exit MSR-store area page between the guest and nested-guest,
1442 * if its content differs, we would have to update the host MSRs anyway.
1443 */
1444 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
1445 }
1446 else
1447 ASMSetFlags(fEFlags);
1448 return rc;
1449}
1450#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
1451
1452
1453/**
1454 * Updates the VM's last error record.
1455 *
1456 * If there was a VMX instruction error, reads the error data from the VMCS and
1457 * updates VCPU's last error record as well.
1458 *
1459 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1460 * Can be NULL if @a rc is not VERR_VMX_UNABLE_TO_START_VM or
1461 * VERR_VMX_INVALID_VMCS_FIELD.
1462 * @param rc The error code.
1463 */
1464static void hmR0VmxUpdateErrorRecord(PVMCPUCC pVCpu, int rc)
1465{
1466 if ( rc == VERR_VMX_INVALID_VMCS_FIELD
1467 || rc == VERR_VMX_UNABLE_TO_START_VM)
1468 {
1469 AssertPtrReturnVoid(pVCpu);
1470 VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
1471 }
1472 pVCpu->CTX_SUFF(pVM)->hm.s.ForR3.rcInit = rc;
1473}
1474
1475
1476#ifdef VBOX_STRICT
1477/**
1478 * Reads the VM-entry interruption-information field from the VMCS into the VMX
1479 * transient structure.
1480 *
1481 * @param pVmxTransient The VMX-transient structure.
1482 */
1483DECLINLINE(void) hmR0VmxReadEntryIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1484{
1485 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntInfo);
1486 AssertRC(rc);
1487}
1488
1489
1490/**
1491 * Reads the VM-entry exception error code field from the VMCS into
1492 * the VMX transient structure.
1493 *
1494 * @param pVmxTransient The VMX-transient structure.
1495 */
1496DECLINLINE(void) hmR0VmxReadEntryXcptErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1497{
1498 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
1499 AssertRC(rc);
1500}
1501
1502
1503/**
1504 * Reads the VM-entry exception error code field from the VMCS into
1505 * the VMX transient structure.
1506 *
1507 * @param pVmxTransient The VMX-transient structure.
1508 */
1509DECLINLINE(void) hmR0VmxReadEntryInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1510{
1511 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
1512 AssertRC(rc);
1513}
1514#endif /* VBOX_STRICT */
1515
1516
1517/**
1518 * Reads the VM-exit interruption-information field from the VMCS into the VMX
1519 * transient structure.
1520 *
1521 * @param pVmxTransient The VMX-transient structure.
1522 */
1523DECLINLINE(void) hmR0VmxReadExitIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1524{
1525 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_INFO))
1526 {
1527 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1528 AssertRC(rc);
1529 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_INFO;
1530 }
1531}
1532
1533
1534/**
1535 * Reads the VM-exit interruption error code from the VMCS into the VMX
1536 * transient structure.
1537 *
1538 * @param pVmxTransient The VMX-transient structure.
1539 */
1540DECLINLINE(void) hmR0VmxReadExitIntErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1541{
1542 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE))
1543 {
1544 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1545 AssertRC(rc);
1546 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE;
1547 }
1548}
1549
1550
1551/**
1552 * Reads the VM-exit instruction length field from the VMCS into the VMX
1553 * transient structure.
1554 *
1555 * @param pVmxTransient The VMX-transient structure.
1556 */
1557DECLINLINE(void) hmR0VmxReadExitInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1558{
1559 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_LEN))
1560 {
1561 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1562 AssertRC(rc);
1563 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_LEN;
1564 }
1565}
1566
1567
1568/**
1569 * Reads the VM-exit instruction-information field from the VMCS into
1570 * the VMX transient structure.
1571 *
1572 * @param pVmxTransient The VMX-transient structure.
1573 */
1574DECLINLINE(void) hmR0VmxReadExitInstrInfoVmcs(PVMXTRANSIENT pVmxTransient)
1575{
1576 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_INFO))
1577 {
1578 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1579 AssertRC(rc);
1580 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_INFO;
1581 }
1582}
1583
1584
1585/**
1586 * Reads the Exit Qualification from the VMCS into the VMX transient structure.
1587 *
1588 * @param pVmxTransient The VMX-transient structure.
1589 */
1590DECLINLINE(void) hmR0VmxReadExitQualVmcs(PVMXTRANSIENT pVmxTransient)
1591{
1592 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_QUALIFICATION))
1593 {
1594 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1595 AssertRC(rc);
1596 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION;
1597 }
1598}
1599
1600
1601/**
1602 * Reads the Guest-linear address from the VMCS into the VMX transient structure.
1603 *
1604 * @param pVmxTransient The VMX-transient structure.
1605 */
1606DECLINLINE(void) hmR0VmxReadGuestLinearAddrVmcs(PVMXTRANSIENT pVmxTransient)
1607{
1608 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_LINEAR_ADDR))
1609 {
1610 int rc = VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1611 AssertRC(rc);
1612 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_LINEAR_ADDR;
1613 }
1614}
1615
1616
1617/**
1618 * Reads the Guest-physical address from the VMCS into the VMX transient structure.
1619 *
1620 * @param pVmxTransient The VMX-transient structure.
1621 */
1622DECLINLINE(void) hmR0VmxReadGuestPhysicalAddrVmcs(PVMXTRANSIENT pVmxTransient)
1623{
1624 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PHYSICAL_ADDR))
1625 {
1626 int rc = VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1627 AssertRC(rc);
1628 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PHYSICAL_ADDR;
1629 }
1630}
1631
1632#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1633/**
1634 * Reads the Guest pending-debug exceptions from the VMCS into the VMX transient
1635 * structure.
1636 *
1637 * @param pVmxTransient The VMX-transient structure.
1638 */
1639DECLINLINE(void) hmR0VmxReadGuestPendingDbgXctps(PVMXTRANSIENT pVmxTransient)
1640{
1641 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PENDING_DBG_XCPTS))
1642 {
1643 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &pVmxTransient->uGuestPendingDbgXcpts);
1644 AssertRC(rc);
1645 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PENDING_DBG_XCPTS;
1646 }
1647}
1648#endif
1649
1650/**
1651 * Reads the IDT-vectoring information field from the VMCS into the VMX
1652 * transient structure.
1653 *
1654 * @param pVmxTransient The VMX-transient structure.
1655 *
1656 * @remarks No-long-jump zone!!!
1657 */
1658DECLINLINE(void) hmR0VmxReadIdtVectoringInfoVmcs(PVMXTRANSIENT pVmxTransient)
1659{
1660 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_INFO))
1661 {
1662 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1663 AssertRC(rc);
1664 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_INFO;
1665 }
1666}
1667
1668
1669/**
1670 * Reads the IDT-vectoring error code from the VMCS into the VMX
1671 * transient structure.
1672 *
1673 * @param pVmxTransient The VMX-transient structure.
1674 */
1675DECLINLINE(void) hmR0VmxReadIdtVectoringErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1676{
1677 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_ERROR_CODE))
1678 {
1679 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1680 AssertRC(rc);
1681 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_ERROR_CODE;
1682 }
1683}
1684
1685#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
1686/**
1687 * Reads all relevant read-only VMCS fields into the VMX transient structure.
1688 *
1689 * @param pVmxTransient The VMX-transient structure.
1690 */
1691static void hmR0VmxReadAllRoFieldsVmcs(PVMXTRANSIENT pVmxTransient)
1692{
1693 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1694 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1695 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1696 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1697 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1698 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1699 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1700 rc |= VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1701 rc |= VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1702 AssertRC(rc);
1703 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION
1704 | HMVMX_READ_EXIT_INSTR_LEN
1705 | HMVMX_READ_EXIT_INSTR_INFO
1706 | HMVMX_READ_IDT_VECTORING_INFO
1707 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
1708 | HMVMX_READ_EXIT_INTERRUPTION_INFO
1709 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
1710 | HMVMX_READ_GUEST_LINEAR_ADDR
1711 | HMVMX_READ_GUEST_PHYSICAL_ADDR;
1712}
1713#endif
1714
1715/**
1716 * Enters VMX root mode operation on the current CPU.
1717 *
1718 * @returns VBox status code.
1719 * @param pHostCpu The HM physical-CPU structure.
1720 * @param pVM The cross context VM structure. Can be
1721 * NULL, after a resume.
1722 * @param HCPhysCpuPage Physical address of the VMXON region.
1723 * @param pvCpuPage Pointer to the VMXON region.
1724 */
1725static int hmR0VmxEnterRootMode(PHMPHYSCPU pHostCpu, PVMCC pVM, RTHCPHYS HCPhysCpuPage, void *pvCpuPage)
1726{
1727 Assert(pHostCpu);
1728 Assert(HCPhysCpuPage && HCPhysCpuPage != NIL_RTHCPHYS);
1729 Assert(RT_ALIGN_T(HCPhysCpuPage, _4K, RTHCPHYS) == HCPhysCpuPage);
1730 Assert(pvCpuPage);
1731 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1732
1733 if (pVM)
1734 {
1735 /* Write the VMCS revision identifier to the VMXON region. */
1736 *(uint32_t *)pvCpuPage = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID);
1737 }
1738
1739 /* Paranoid: Disable interrupts as, in theory, interrupt handlers might mess with CR4. */
1740 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1741
1742 /* Enable the VMX bit in CR4 if necessary. */
1743 RTCCUINTREG const uOldCr4 = SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
1744
1745 /* Record whether VMXE was already prior to us enabling it above. */
1746 pHostCpu->fVmxeAlreadyEnabled = RT_BOOL(uOldCr4 & X86_CR4_VMXE);
1747
1748 /* Enter VMX root mode. */
1749 int rc = VMXEnable(HCPhysCpuPage);
1750 if (RT_FAILURE(rc))
1751 {
1752 /* Restore CR4.VMXE if it was not set prior to our attempt to set it above. */
1753 if (!pHostCpu->fVmxeAlreadyEnabled)
1754 SUPR0ChangeCR4(0 /* fOrMask */, ~(uint64_t)X86_CR4_VMXE);
1755
1756 if (pVM)
1757 pVM->hm.s.ForR3.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
1758 }
1759
1760 /* Restore interrupts. */
1761 ASMSetFlags(fEFlags);
1762 return rc;
1763}
1764
1765
1766/**
1767 * Exits VMX root mode operation on the current CPU.
1768 *
1769 * @returns VBox status code.
1770 * @param pHostCpu The HM physical-CPU structure.
1771 */
1772static int hmR0VmxLeaveRootMode(PHMPHYSCPU pHostCpu)
1773{
1774 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1775
1776 /* Paranoid: Disable interrupts as, in theory, interrupts handlers might mess with CR4. */
1777 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1778
1779 /* If we're for some reason not in VMX root mode, then don't leave it. */
1780 RTCCUINTREG const uHostCr4 = ASMGetCR4();
1781
1782 int rc;
1783 if (uHostCr4 & X86_CR4_VMXE)
1784 {
1785 /* Exit VMX root mode and clear the VMX bit in CR4. */
1786 VMXDisable();
1787
1788 /* Clear CR4.VMXE only if it was clear prior to use setting it. */
1789 if (!pHostCpu->fVmxeAlreadyEnabled)
1790 SUPR0ChangeCR4(0 /* fOrMask */, ~(uint64_t)X86_CR4_VMXE);
1791
1792 rc = VINF_SUCCESS;
1793 }
1794 else
1795 rc = VERR_VMX_NOT_IN_VMX_ROOT_MODE;
1796
1797 /* Restore interrupts. */
1798 ASMSetFlags(fEFlags);
1799 return rc;
1800}
1801
1802
1803/**
1804 * Allocates pages specified as specified by an array of VMX page allocation info
1805 * objects.
1806 *
1807 * The pages contents are zero'd after allocation.
1808 *
1809 * @returns VBox status code.
1810 * @param phMemObj Where to return the handle to the allocation.
1811 * @param paAllocInfo The pointer to the first element of the VMX
1812 * page-allocation info object array.
1813 * @param cEntries The number of elements in the @a paAllocInfo array.
1814 */
1815static int hmR0VmxPagesAllocZ(PRTR0MEMOBJ phMemObj, PVMXPAGEALLOCINFO paAllocInfo, uint32_t cEntries)
1816{
1817 *phMemObj = NIL_RTR0MEMOBJ;
1818
1819 /* Figure out how many pages to allocate. */
1820 uint32_t cPages = 0;
1821 for (uint32_t iPage = 0; iPage < cEntries; iPage++)
1822 cPages += !!paAllocInfo[iPage].fValid;
1823
1824 /* Allocate the pages. */
1825 if (cPages)
1826 {
1827 size_t const cbPages = cPages << PAGE_SHIFT;
1828 int rc = RTR0MemObjAllocPage(phMemObj, cbPages, false /* fExecutable */);
1829 if (RT_FAILURE(rc))
1830 return rc;
1831
1832 /* Zero the contents and assign each page to the corresponding VMX page-allocation entry. */
1833 void *pvFirstPage = RTR0MemObjAddress(*phMemObj);
1834 RT_BZERO(pvFirstPage, cbPages);
1835
1836 uint32_t iPage = 0;
1837 for (uint32_t i = 0; i < cEntries; i++)
1838 if (paAllocInfo[i].fValid)
1839 {
1840 RTHCPHYS const HCPhysPage = RTR0MemObjGetPagePhysAddr(*phMemObj, iPage);
1841 void *pvPage = (void *)((uintptr_t)pvFirstPage + (iPage << X86_PAGE_4K_SHIFT));
1842 Assert(HCPhysPage && HCPhysPage != NIL_RTHCPHYS);
1843 AssertPtr(pvPage);
1844
1845 Assert(paAllocInfo[iPage].pHCPhys);
1846 Assert(paAllocInfo[iPage].ppVirt);
1847 *paAllocInfo[iPage].pHCPhys = HCPhysPage;
1848 *paAllocInfo[iPage].ppVirt = pvPage;
1849
1850 /* Move to next page. */
1851 ++iPage;
1852 }
1853
1854 /* Make sure all valid (requested) pages have been assigned. */
1855 Assert(iPage == cPages);
1856 }
1857 return VINF_SUCCESS;
1858}
1859
1860
1861/**
1862 * Frees pages allocated using hmR0VmxPagesAllocZ.
1863 *
1864 * @param phMemObj Pointer to the memory object handle. Will be set to
1865 * NIL.
1866 */
1867DECL_FORCE_INLINE(void) hmR0VmxPagesFree(PRTR0MEMOBJ phMemObj)
1868{
1869 /* We can cleanup wholesale since it's all one allocation. */
1870 if (*phMemObj != NIL_RTR0MEMOBJ)
1871 {
1872 RTR0MemObjFree(*phMemObj, true /* fFreeMappings */);
1873 *phMemObj = NIL_RTR0MEMOBJ;
1874 }
1875}
1876
1877
1878/**
1879 * Initializes a VMCS info. object.
1880 *
1881 * @param pVmcsInfo The VMCS info. object.
1882 * @param pVmcsInfoShared The VMCS info. object shared with ring-3.
1883 */
1884static void hmR0VmxVmcsInfoInit(PVMXVMCSINFO pVmcsInfo, PVMXVMCSINFOSHARED pVmcsInfoShared)
1885{
1886 RT_ZERO(*pVmcsInfo);
1887 RT_ZERO(*pVmcsInfoShared);
1888
1889 pVmcsInfo->pShared = pVmcsInfoShared;
1890 Assert(pVmcsInfo->hMemObj == NIL_RTR0MEMOBJ);
1891 pVmcsInfo->HCPhysVmcs = NIL_RTHCPHYS;
1892 pVmcsInfo->HCPhysShadowVmcs = NIL_RTHCPHYS;
1893 pVmcsInfo->HCPhysMsrBitmap = NIL_RTHCPHYS;
1894 pVmcsInfo->HCPhysGuestMsrLoad = NIL_RTHCPHYS;
1895 pVmcsInfo->HCPhysGuestMsrStore = NIL_RTHCPHYS;
1896 pVmcsInfo->HCPhysHostMsrLoad = NIL_RTHCPHYS;
1897 pVmcsInfo->HCPhysVirtApic = NIL_RTHCPHYS;
1898 pVmcsInfo->HCPhysEPTP = NIL_RTHCPHYS;
1899 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
1900 pVmcsInfo->idHostCpuState = NIL_RTCPUID;
1901 pVmcsInfo->idHostCpuExec = NIL_RTCPUID;
1902}
1903
1904
1905/**
1906 * Frees the VT-x structures for a VMCS info. object.
1907 *
1908 * @param pVmcsInfo The VMCS info. object.
1909 * @param pVmcsInfoShared The VMCS info. object shared with ring-3.
1910 */
1911static void hmR0VmxVmcsInfoFree(PVMXVMCSINFO pVmcsInfo, PVMXVMCSINFOSHARED pVmcsInfoShared)
1912{
1913 hmR0VmxPagesFree(&pVmcsInfo->hMemObj);
1914 hmR0VmxVmcsInfoInit(pVmcsInfo, pVmcsInfoShared);
1915}
1916
1917
1918/**
1919 * Allocates the VT-x structures for a VMCS info. object.
1920 *
1921 * @returns VBox status code.
1922 * @param pVCpu The cross context virtual CPU structure.
1923 * @param pVmcsInfo The VMCS info. object.
1924 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
1925 *
1926 * @remarks The caller is expected to take care of any and all allocation failures.
1927 * This function will not perform any cleanup for failures half-way
1928 * through.
1929 */
1930static int hmR0VmxAllocVmcsInfo(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
1931{
1932 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
1933
1934 bool const fMsrBitmaps = RT_BOOL(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS);
1935 bool const fShadowVmcs = !fIsNstGstVmcs ? pVM->hmr0.s.vmx.fUseVmcsShadowing : pVM->cpum.ro.GuestFeatures.fVmxVmcsShadowing;
1936 Assert(!pVM->cpum.ro.GuestFeatures.fVmxVmcsShadowing); /* VMCS shadowing is not yet exposed to the guest. */
1937 VMXPAGEALLOCINFO aAllocInfo[] =
1938 {
1939 { true, 0 /* Unused */, &pVmcsInfo->HCPhysVmcs, &pVmcsInfo->pvVmcs },
1940 { true, 0 /* Unused */, &pVmcsInfo->HCPhysGuestMsrLoad, &pVmcsInfo->pvGuestMsrLoad },
1941 { true, 0 /* Unused */, &pVmcsInfo->HCPhysHostMsrLoad, &pVmcsInfo->pvHostMsrLoad },
1942 { fMsrBitmaps, 0 /* Unused */, &pVmcsInfo->HCPhysMsrBitmap, &pVmcsInfo->pvMsrBitmap },
1943 { fShadowVmcs, 0 /* Unused */, &pVmcsInfo->HCPhysShadowVmcs, &pVmcsInfo->pvShadowVmcs },
1944 };
1945
1946 int rc = hmR0VmxPagesAllocZ(&pVmcsInfo->hMemObj, &aAllocInfo[0], RT_ELEMENTS(aAllocInfo));
1947 if (RT_FAILURE(rc))
1948 return rc;
1949
1950 /*
1951 * We use the same page for VM-entry MSR-load and VM-exit MSR store areas.
1952 * Because they contain a symmetric list of guest MSRs to load on VM-entry and store on VM-exit.
1953 */
1954 AssertCompile(RT_ELEMENTS(aAllocInfo) > 0);
1955 Assert(pVmcsInfo->HCPhysGuestMsrLoad != NIL_RTHCPHYS);
1956 pVmcsInfo->pvGuestMsrStore = pVmcsInfo->pvGuestMsrLoad;
1957 pVmcsInfo->HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrLoad;
1958
1959 /*
1960 * Get the virtual-APIC page rather than allocating them again.
1961 */
1962 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW)
1963 {
1964 if (!fIsNstGstVmcs)
1965 {
1966 if (PDMHasApic(pVM))
1967 {
1968 rc = APICGetApicPageForCpu(pVCpu, &pVmcsInfo->HCPhysVirtApic, (PRTR0PTR)&pVmcsInfo->pbVirtApic, NULL /*pR3Ptr*/);
1969 if (RT_FAILURE(rc))
1970 return rc;
1971 Assert(pVmcsInfo->pbVirtApic);
1972 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1973 }
1974 }
1975 else
1976 {
1977 pVmcsInfo->pbVirtApic = (uint8_t *)CPUMGetGuestVmxVirtApicPage(&pVCpu->cpum.GstCtx, &pVmcsInfo->HCPhysVirtApic);
1978 Assert(pVmcsInfo->pbVirtApic);
1979 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1980 }
1981 }
1982
1983 return VINF_SUCCESS;
1984}
1985
1986
1987/**
1988 * Free all VT-x structures for the VM.
1989 *
1990 * @returns IPRT status code.
1991 * @param pVM The cross context VM structure.
1992 */
1993static void hmR0VmxStructsFree(PVMCC pVM)
1994{
1995 hmR0VmxPagesFree(&pVM->hmr0.s.vmx.hMemObj);
1996#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1997 if (pVM->hmr0.s.vmx.fUseVmcsShadowing)
1998 {
1999 RTMemFree(pVM->hmr0.s.vmx.paShadowVmcsFields);
2000 pVM->hmr0.s.vmx.paShadowVmcsFields = NULL;
2001 RTMemFree(pVM->hmr0.s.vmx.paShadowVmcsRoFields);
2002 pVM->hmr0.s.vmx.paShadowVmcsRoFields = NULL;
2003 }
2004#endif
2005
2006 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
2007 {
2008 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
2009 hmR0VmxVmcsInfoFree(&pVCpu->hmr0.s.vmx.VmcsInfo, &pVCpu->hm.s.vmx.VmcsInfo);
2010#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2011 if (pVM->cpum.ro.GuestFeatures.fVmx)
2012 hmR0VmxVmcsInfoFree(&pVCpu->hmr0.s.vmx.VmcsInfoNstGst, &pVCpu->hm.s.vmx.VmcsInfoNstGst);
2013#endif
2014 }
2015}
2016
2017
2018/**
2019 * Allocate all VT-x structures for the VM.
2020 *
2021 * @returns IPRT status code.
2022 * @param pVM The cross context VM structure.
2023 *
2024 * @remarks This functions will cleanup on memory allocation failures.
2025 */
2026static int hmR0VmxStructsAlloc(PVMCC pVM)
2027{
2028 /*
2029 * Sanity check the VMCS size reported by the CPU as we assume 4KB allocations.
2030 * The VMCS size cannot be more than 4096 bytes.
2031 *
2032 * See Intel spec. Appendix A.1 "Basic VMX Information".
2033 */
2034 uint32_t const cbVmcs = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_SIZE);
2035 if (cbVmcs <= X86_PAGE_4K_SIZE)
2036 { /* likely */ }
2037 else
2038 {
2039 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_INVALID_VMCS_SIZE;
2040 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2041 }
2042
2043 /*
2044 * Allocate per-VM VT-x structures.
2045 */
2046 bool const fVirtApicAccess = RT_BOOL(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
2047 bool const fUseVmcsShadowing = pVM->hmr0.s.vmx.fUseVmcsShadowing;
2048 VMXPAGEALLOCINFO aAllocInfo[] =
2049 {
2050 { fVirtApicAccess, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysApicAccess, (PRTR0PTR)&pVM->hmr0.s.vmx.pbApicAccess },
2051 { fUseVmcsShadowing, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysVmreadBitmap, &pVM->hmr0.s.vmx.pvVmreadBitmap },
2052 { fUseVmcsShadowing, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysVmwriteBitmap, &pVM->hmr0.s.vmx.pvVmwriteBitmap },
2053#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2054 { true, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysScratch, (PRTR0PTR)&pVM->hmr0.s.vmx.pbScratch },
2055#endif
2056 };
2057
2058 int rc = hmR0VmxPagesAllocZ(&pVM->hmr0.s.vmx.hMemObj, &aAllocInfo[0], RT_ELEMENTS(aAllocInfo));
2059 if (RT_SUCCESS(rc))
2060 {
2061#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2062 /* Allocate the shadow VMCS-fields array. */
2063 if (fUseVmcsShadowing)
2064 {
2065 Assert(!pVM->hmr0.s.vmx.cShadowVmcsFields);
2066 Assert(!pVM->hmr0.s.vmx.cShadowVmcsRoFields);
2067 pVM->hmr0.s.vmx.paShadowVmcsFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
2068 pVM->hmr0.s.vmx.paShadowVmcsRoFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
2069 if (!pVM->hmr0.s.vmx.paShadowVmcsFields || !pVM->hmr0.s.vmx.paShadowVmcsRoFields)
2070 rc = VERR_NO_MEMORY;
2071 }
2072#endif
2073
2074 /*
2075 * Allocate per-VCPU VT-x structures.
2076 */
2077 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus && RT_SUCCESS(rc); idCpu++)
2078 {
2079 /* Allocate the guest VMCS structures. */
2080 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
2081 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
2082
2083#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2084 /* Allocate the nested-guest VMCS structures, when the VMX feature is exposed to the guest. */
2085 if (pVM->cpum.ro.GuestFeatures.fVmx && RT_SUCCESS(rc))
2086 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
2087#endif
2088 }
2089 if (RT_SUCCESS(rc))
2090 return VINF_SUCCESS;
2091 }
2092 hmR0VmxStructsFree(pVM);
2093 return rc;
2094}
2095
2096
2097/**
2098 * Pre-initializes non-zero fields in VMX structures that will be allocated.
2099 *
2100 * @param pVM The cross context VM structure.
2101 */
2102static void hmR0VmxStructsInit(PVMCC pVM)
2103{
2104 /* Paranoia. */
2105 Assert(pVM->hmr0.s.vmx.pbApicAccess == NULL);
2106#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2107 Assert(pVM->hmr0.s.vmx.pbScratch == NULL);
2108#endif
2109
2110 /*
2111 * Initialize members up-front so we can cleanup en masse on allocation failures.
2112 */
2113#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2114 pVM->hmr0.s.vmx.HCPhysScratch = NIL_RTHCPHYS;
2115#endif
2116 pVM->hmr0.s.vmx.HCPhysApicAccess = NIL_RTHCPHYS;
2117 pVM->hmr0.s.vmx.HCPhysVmreadBitmap = NIL_RTHCPHYS;
2118 pVM->hmr0.s.vmx.HCPhysVmwriteBitmap = NIL_RTHCPHYS;
2119 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
2120 {
2121 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
2122 hmR0VmxVmcsInfoInit(&pVCpu->hmr0.s.vmx.VmcsInfo, &pVCpu->hm.s.vmx.VmcsInfo);
2123 hmR0VmxVmcsInfoInit(&pVCpu->hmr0.s.vmx.VmcsInfoNstGst, &pVCpu->hm.s.vmx.VmcsInfoNstGst);
2124 }
2125}
2126
2127#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2128/**
2129 * Returns whether an MSR at the given MSR-bitmap offset is intercepted or not.
2130 *
2131 * @returns @c true if the MSR is intercepted, @c false otherwise.
2132 * @param pvMsrBitmap The MSR bitmap.
2133 * @param offMsr The MSR byte offset.
2134 * @param iBit The bit offset from the byte offset.
2135 */
2136DECLINLINE(bool) hmR0VmxIsMsrBitSet(const void *pvMsrBitmap, uint16_t offMsr, int32_t iBit)
2137{
2138 uint8_t const * const pbMsrBitmap = (uint8_t const * const)pvMsrBitmap;
2139 Assert(pbMsrBitmap);
2140 Assert(offMsr + (iBit >> 3) <= X86_PAGE_4K_SIZE);
2141 return ASMBitTest(pbMsrBitmap + offMsr, iBit);
2142}
2143#endif
2144
2145/**
2146 * Sets the permission bits for the specified MSR in the given MSR bitmap.
2147 *
2148 * If the passed VMCS is a nested-guest VMCS, this function ensures that the
2149 * read/write intercept is cleared from the MSR bitmap used for hardware-assisted
2150 * VMX execution of the nested-guest, only if nested-guest is also not intercepting
2151 * the read/write access of this MSR.
2152 *
2153 * @param pVCpu The cross context virtual CPU structure.
2154 * @param pVmcsInfo The VMCS info. object.
2155 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2156 * @param idMsr The MSR value.
2157 * @param fMsrpm The MSR permissions (see VMXMSRPM_XXX). This must
2158 * include both a read -and- a write permission!
2159 *
2160 * @sa CPUMGetVmxMsrPermission.
2161 * @remarks Can be called with interrupts disabled.
2162 */
2163static void hmR0VmxSetMsrPermission(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs, uint32_t idMsr, uint32_t fMsrpm)
2164{
2165 uint8_t *pbMsrBitmap = (uint8_t *)pVmcsInfo->pvMsrBitmap;
2166 Assert(pbMsrBitmap);
2167 Assert(VMXMSRPM_IS_FLAG_VALID(fMsrpm));
2168
2169 /*
2170 * MSR-bitmap Layout:
2171 * Byte index MSR range Interpreted as
2172 * 0x000 - 0x3ff 0x00000000 - 0x00001fff Low MSR read bits.
2173 * 0x400 - 0x7ff 0xc0000000 - 0xc0001fff High MSR read bits.
2174 * 0x800 - 0xbff 0x00000000 - 0x00001fff Low MSR write bits.
2175 * 0xc00 - 0xfff 0xc0000000 - 0xc0001fff High MSR write bits.
2176 *
2177 * A bit corresponding to an MSR within the above range causes a VM-exit
2178 * if the bit is 1 on executions of RDMSR/WRMSR. If an MSR falls out of
2179 * the MSR range, it always cause a VM-exit.
2180 *
2181 * See Intel spec. 24.6.9 "MSR-Bitmap Address".
2182 */
2183 uint16_t const offBitmapRead = 0;
2184 uint16_t const offBitmapWrite = 0x800;
2185 uint16_t offMsr;
2186 int32_t iBit;
2187 if (idMsr <= UINT32_C(0x00001fff))
2188 {
2189 offMsr = 0;
2190 iBit = idMsr;
2191 }
2192 else if (idMsr - UINT32_C(0xc0000000) <= UINT32_C(0x00001fff))
2193 {
2194 offMsr = 0x400;
2195 iBit = idMsr - UINT32_C(0xc0000000);
2196 }
2197 else
2198 AssertMsgFailedReturnVoid(("Invalid MSR %#RX32\n", idMsr));
2199
2200 /*
2201 * Set the MSR read permission.
2202 */
2203 uint16_t const offMsrRead = offBitmapRead + offMsr;
2204 Assert(offMsrRead + (iBit >> 3) < offBitmapWrite);
2205 if (fMsrpm & VMXMSRPM_ALLOW_RD)
2206 {
2207#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2208 bool const fClear = !fIsNstGstVmcs ? true
2209 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrRead, iBit);
2210#else
2211 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2212 bool const fClear = true;
2213#endif
2214 if (fClear)
2215 ASMBitClear(pbMsrBitmap + offMsrRead, iBit);
2216 }
2217 else
2218 ASMBitSet(pbMsrBitmap + offMsrRead, iBit);
2219
2220 /*
2221 * Set the MSR write permission.
2222 */
2223 uint16_t const offMsrWrite = offBitmapWrite + offMsr;
2224 Assert(offMsrWrite + (iBit >> 3) < X86_PAGE_4K_SIZE);
2225 if (fMsrpm & VMXMSRPM_ALLOW_WR)
2226 {
2227#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2228 bool const fClear = !fIsNstGstVmcs ? true
2229 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrWrite, iBit);
2230#else
2231 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2232 bool const fClear = true;
2233#endif
2234 if (fClear)
2235 ASMBitClear(pbMsrBitmap + offMsrWrite, iBit);
2236 }
2237 else
2238 ASMBitSet(pbMsrBitmap + offMsrWrite, iBit);
2239}
2240
2241
2242/**
2243 * Updates the VMCS with the number of effective MSRs in the auto-load/store MSR
2244 * area.
2245 *
2246 * @returns VBox status code.
2247 * @param pVCpu The cross context virtual CPU structure.
2248 * @param pVmcsInfo The VMCS info. object.
2249 * @param cMsrs The number of MSRs.
2250 */
2251static int hmR0VmxSetAutoLoadStoreMsrCount(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t cMsrs)
2252{
2253 /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
2254 uint32_t const cMaxSupportedMsrs = VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc);
2255 if (RT_LIKELY(cMsrs < cMaxSupportedMsrs))
2256 {
2257 /* Commit the MSR counts to the VMCS and update the cache. */
2258 if (pVmcsInfo->cEntryMsrLoad != cMsrs)
2259 {
2260 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2261 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, cMsrs); AssertRC(rc);
2262 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2263 pVmcsInfo->cEntryMsrLoad = cMsrs;
2264 pVmcsInfo->cExitMsrStore = cMsrs;
2265 pVmcsInfo->cExitMsrLoad = cMsrs;
2266 }
2267 return VINF_SUCCESS;
2268 }
2269
2270 LogRel(("Auto-load/store MSR count exceeded! cMsrs=%u MaxSupported=%u\n", cMsrs, cMaxSupportedMsrs));
2271 pVCpu->hm.s.u32HMError = VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE;
2272 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2273}
2274
2275
2276/**
2277 * Adds a new (or updates the value of an existing) guest/host MSR
2278 * pair to be swapped during the world-switch as part of the
2279 * auto-load/store MSR area in the VMCS.
2280 *
2281 * @returns VBox status code.
2282 * @param pVCpu The cross context virtual CPU structure.
2283 * @param pVmxTransient The VMX-transient structure.
2284 * @param idMsr The MSR.
2285 * @param uGuestMsrValue Value of the guest MSR.
2286 * @param fSetReadWrite Whether to set the guest read/write access of this
2287 * MSR (thus not causing a VM-exit).
2288 * @param fUpdateHostMsr Whether to update the value of the host MSR if
2289 * necessary.
2290 */
2291static int hmR0VmxAddAutoLoadStoreMsr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t idMsr, uint64_t uGuestMsrValue,
2292 bool fSetReadWrite, bool fUpdateHostMsr)
2293{
2294 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2295 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2296 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2297 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2298 uint32_t i;
2299
2300 /* Paranoia. */
2301 Assert(pGuestMsrLoad);
2302
2303#ifndef DEBUG_bird
2304 LogFlowFunc(("pVCpu=%p idMsr=%#RX32 uGuestMsrValue=%#RX64\n", pVCpu, idMsr, uGuestMsrValue));
2305#endif
2306
2307 /* Check if the MSR already exists in the VM-entry MSR-load area. */
2308 for (i = 0; i < cMsrs; i++)
2309 {
2310 if (pGuestMsrLoad[i].u32Msr == idMsr)
2311 break;
2312 }
2313
2314 bool fAdded = false;
2315 if (i == cMsrs)
2316 {
2317 /* The MSR does not exist, bump the MSR count to make room for the new MSR. */
2318 ++cMsrs;
2319 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2320 AssertMsgRCReturn(rc, ("Insufficient space to add MSR to VM-entry MSR-load/store area %u\n", idMsr), rc);
2321
2322 /* Set the guest to read/write this MSR without causing VM-exits. */
2323 if ( fSetReadWrite
2324 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
2325 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_ALLOW_RD_WR);
2326
2327 Log4Func(("Added MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2328 fAdded = true;
2329 }
2330
2331 /* Update the MSR value for the newly added or already existing MSR. */
2332 pGuestMsrLoad[i].u32Msr = idMsr;
2333 pGuestMsrLoad[i].u64Value = uGuestMsrValue;
2334
2335 /* Create the corresponding slot in the VM-exit MSR-store area if we use a different page. */
2336 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2337 {
2338 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2339 pGuestMsrStore[i].u32Msr = idMsr;
2340 pGuestMsrStore[i].u64Value = uGuestMsrValue;
2341 }
2342
2343 /* Update the corresponding slot in the host MSR area. */
2344 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2345 Assert(pHostMsr != pVmcsInfo->pvGuestMsrLoad);
2346 Assert(pHostMsr != pVmcsInfo->pvGuestMsrStore);
2347 pHostMsr[i].u32Msr = idMsr;
2348
2349 /*
2350 * Only if the caller requests to update the host MSR value AND we've newly added the
2351 * MSR to the host MSR area do we actually update the value. Otherwise, it will be
2352 * updated by hmR0VmxUpdateAutoLoadHostMsrs().
2353 *
2354 * We do this for performance reasons since reading MSRs may be quite expensive.
2355 */
2356 if (fAdded)
2357 {
2358 if (fUpdateHostMsr)
2359 {
2360 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2361 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2362 pHostMsr[i].u64Value = ASMRdMsr(idMsr);
2363 }
2364 else
2365 {
2366 /* Someone else can do the work. */
2367 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
2368 }
2369 }
2370 return VINF_SUCCESS;
2371}
2372
2373
2374/**
2375 * Removes a guest/host MSR pair to be swapped during the world-switch from the
2376 * auto-load/store MSR area in the VMCS.
2377 *
2378 * @returns VBox status code.
2379 * @param pVCpu The cross context virtual CPU structure.
2380 * @param pVmxTransient The VMX-transient structure.
2381 * @param idMsr The MSR.
2382 */
2383static int hmR0VmxRemoveAutoLoadStoreMsr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t idMsr)
2384{
2385 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2386 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2387 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2388 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2389
2390#ifndef DEBUG_bird
2391 LogFlowFunc(("pVCpu=%p idMsr=%#RX32\n", pVCpu, idMsr));
2392#endif
2393
2394 for (uint32_t i = 0; i < cMsrs; i++)
2395 {
2396 /* Find the MSR. */
2397 if (pGuestMsrLoad[i].u32Msr == idMsr)
2398 {
2399 /*
2400 * If it's the last MSR, we only need to reduce the MSR count.
2401 * If it's -not- the last MSR, copy the last MSR in place of it and reduce the MSR count.
2402 */
2403 if (i < cMsrs - 1)
2404 {
2405 /* Remove it from the VM-entry MSR-load area. */
2406 pGuestMsrLoad[i].u32Msr = pGuestMsrLoad[cMsrs - 1].u32Msr;
2407 pGuestMsrLoad[i].u64Value = pGuestMsrLoad[cMsrs - 1].u64Value;
2408
2409 /* Remove it from the VM-exit MSR-store area if it's in a different page. */
2410 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2411 {
2412 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2413 Assert(pGuestMsrStore[i].u32Msr == idMsr);
2414 pGuestMsrStore[i].u32Msr = pGuestMsrStore[cMsrs - 1].u32Msr;
2415 pGuestMsrStore[i].u64Value = pGuestMsrStore[cMsrs - 1].u64Value;
2416 }
2417
2418 /* Remove it from the VM-exit MSR-load area. */
2419 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2420 Assert(pHostMsr[i].u32Msr == idMsr);
2421 pHostMsr[i].u32Msr = pHostMsr[cMsrs - 1].u32Msr;
2422 pHostMsr[i].u64Value = pHostMsr[cMsrs - 1].u64Value;
2423 }
2424
2425 /* Reduce the count to reflect the removed MSR and bail. */
2426 --cMsrs;
2427 break;
2428 }
2429 }
2430
2431 /* Update the VMCS if the count changed (meaning the MSR was found and removed). */
2432 if (cMsrs != pVmcsInfo->cEntryMsrLoad)
2433 {
2434 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2435 AssertRCReturn(rc, rc);
2436
2437 /* We're no longer swapping MSRs during the world-switch, intercept guest read/writes to them. */
2438 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2439 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR);
2440
2441 Log4Func(("Removed MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2442 return VINF_SUCCESS;
2443 }
2444
2445 return VERR_NOT_FOUND;
2446}
2447
2448
2449/**
2450 * Checks if the specified guest MSR is part of the VM-entry MSR-load area.
2451 *
2452 * @returns @c true if found, @c false otherwise.
2453 * @param pVmcsInfo The VMCS info. object.
2454 * @param idMsr The MSR to find.
2455 */
2456static bool hmR0VmxIsAutoLoadGuestMsr(PCVMXVMCSINFO pVmcsInfo, uint32_t idMsr)
2457{
2458 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2459 uint32_t const cMsrs = pVmcsInfo->cEntryMsrLoad;
2460 Assert(pMsrs);
2461 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
2462 for (uint32_t i = 0; i < cMsrs; i++)
2463 {
2464 if (pMsrs[i].u32Msr == idMsr)
2465 return true;
2466 }
2467 return false;
2468}
2469
2470
2471/**
2472 * Updates the value of all host MSRs in the VM-exit MSR-load area.
2473 *
2474 * @param pVCpu The cross context virtual CPU structure.
2475 * @param pVmcsInfo The VMCS info. object.
2476 *
2477 * @remarks No-long-jump zone!!!
2478 */
2479static void hmR0VmxUpdateAutoLoadHostMsrs(PCVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2480{
2481 RT_NOREF(pVCpu);
2482 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2483
2484 PVMXAUTOMSR pHostMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2485 uint32_t const cMsrs = pVmcsInfo->cExitMsrLoad;
2486 Assert(pHostMsrLoad);
2487 Assert(sizeof(*pHostMsrLoad) * cMsrs <= X86_PAGE_4K_SIZE);
2488 LogFlowFunc(("pVCpu=%p cMsrs=%u\n", pVCpu, cMsrs));
2489 for (uint32_t i = 0; i < cMsrs; i++)
2490 {
2491 /*
2492 * Performance hack for the host EFER MSR. We use the cached value rather than re-read it.
2493 * Strict builds will catch mismatches in hmR0VmxCheckAutoLoadStoreMsrs(). See @bugref{7368}.
2494 */
2495 if (pHostMsrLoad[i].u32Msr == MSR_K6_EFER)
2496 pHostMsrLoad[i].u64Value = g_uHmVmxHostMsrEfer;
2497 else
2498 pHostMsrLoad[i].u64Value = ASMRdMsr(pHostMsrLoad[i].u32Msr);
2499 }
2500}
2501
2502
2503/**
2504 * Saves a set of host MSRs to allow read/write passthru access to the guest and
2505 * perform lazy restoration of the host MSRs while leaving VT-x.
2506 *
2507 * @param pVCpu The cross context virtual CPU structure.
2508 *
2509 * @remarks No-long-jump zone!!!
2510 */
2511static void hmR0VmxLazySaveHostMsrs(PVMCPUCC pVCpu)
2512{
2513 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2514
2515 /*
2516 * Note: If you're adding MSRs here, make sure to update the MSR-bitmap accesses in hmR0VmxSetupVmcsProcCtls().
2517 */
2518 if (!(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST))
2519 {
2520 Assert(!(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)); /* Guest MSRs better not be loaded now. */
2521 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2522 {
2523 pVCpu->hmr0.s.vmx.u64HostMsrLStar = ASMRdMsr(MSR_K8_LSTAR);
2524 pVCpu->hmr0.s.vmx.u64HostMsrStar = ASMRdMsr(MSR_K6_STAR);
2525 pVCpu->hmr0.s.vmx.u64HostMsrSfMask = ASMRdMsr(MSR_K8_SF_MASK);
2526 pVCpu->hmr0.s.vmx.u64HostMsrKernelGsBase = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
2527 }
2528 pVCpu->hmr0.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_SAVED_HOST;
2529 }
2530}
2531
2532
2533/**
2534 * Checks whether the MSR belongs to the set of guest MSRs that we restore
2535 * lazily while leaving VT-x.
2536 *
2537 * @returns true if it does, false otherwise.
2538 * @param pVCpu The cross context virtual CPU structure.
2539 * @param idMsr The MSR to check.
2540 */
2541static bool hmR0VmxIsLazyGuestMsr(PCVMCPUCC pVCpu, uint32_t idMsr)
2542{
2543 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2544 {
2545 switch (idMsr)
2546 {
2547 case MSR_K8_LSTAR:
2548 case MSR_K6_STAR:
2549 case MSR_K8_SF_MASK:
2550 case MSR_K8_KERNEL_GS_BASE:
2551 return true;
2552 }
2553 }
2554 return false;
2555}
2556
2557
2558/**
2559 * Loads a set of guests MSRs to allow read/passthru to the guest.
2560 *
2561 * The name of this function is slightly confusing. This function does NOT
2562 * postpone loading, but loads the MSR right now. "hmR0VmxLazy" is simply a
2563 * common prefix for functions dealing with "lazy restoration" of the shared
2564 * MSRs.
2565 *
2566 * @param pVCpu The cross context virtual CPU structure.
2567 *
2568 * @remarks No-long-jump zone!!!
2569 */
2570static void hmR0VmxLazyLoadGuestMsrs(PVMCPUCC pVCpu)
2571{
2572 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2573 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2574
2575 Assert(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2576 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2577 {
2578 /*
2579 * If the guest MSRs are not loaded -and- if all the guest MSRs are identical
2580 * to the MSRs on the CPU (which are the saved host MSRs, see assertion above) then
2581 * we can skip a few MSR writes.
2582 *
2583 * Otherwise, it implies either 1. they're not loaded, or 2. they're loaded but the
2584 * guest MSR values in the guest-CPU context might be different to what's currently
2585 * loaded in the CPU. In either case, we need to write the new guest MSR values to the
2586 * CPU, see @bugref{8728}.
2587 */
2588 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
2589 if ( !(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2590 && pCtx->msrKERNELGSBASE == pVCpu->hmr0.s.vmx.u64HostMsrKernelGsBase
2591 && pCtx->msrLSTAR == pVCpu->hmr0.s.vmx.u64HostMsrLStar
2592 && pCtx->msrSTAR == pVCpu->hmr0.s.vmx.u64HostMsrStar
2593 && pCtx->msrSFMASK == pVCpu->hmr0.s.vmx.u64HostMsrSfMask)
2594 {
2595#ifdef VBOX_STRICT
2596 Assert(ASMRdMsr(MSR_K8_KERNEL_GS_BASE) == pCtx->msrKERNELGSBASE);
2597 Assert(ASMRdMsr(MSR_K8_LSTAR) == pCtx->msrLSTAR);
2598 Assert(ASMRdMsr(MSR_K6_STAR) == pCtx->msrSTAR);
2599 Assert(ASMRdMsr(MSR_K8_SF_MASK) == pCtx->msrSFMASK);
2600#endif
2601 }
2602 else
2603 {
2604 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pCtx->msrKERNELGSBASE);
2605 ASMWrMsr(MSR_K8_LSTAR, pCtx->msrLSTAR);
2606 ASMWrMsr(MSR_K6_STAR, pCtx->msrSTAR);
2607 /* The system call flag mask register isn't as benign and accepting of all
2608 values as the above, so mask it to avoid #GP'ing on corrupted input. */
2609 Assert(!(pCtx->msrSFMASK & ~(uint64_t)UINT32_MAX));
2610 ASMWrMsr(MSR_K8_SF_MASK, pCtx->msrSFMASK & UINT32_MAX);
2611 }
2612 }
2613 pVCpu->hmr0.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_LOADED_GUEST;
2614}
2615
2616
2617/**
2618 * Performs lazy restoration of the set of host MSRs if they were previously
2619 * loaded with guest MSR values.
2620 *
2621 * @param pVCpu The cross context virtual CPU structure.
2622 *
2623 * @remarks No-long-jump zone!!!
2624 * @remarks The guest MSRs should have been saved back into the guest-CPU
2625 * context by hmR0VmxImportGuestState()!!!
2626 */
2627static void hmR0VmxLazyRestoreHostMsrs(PVMCPUCC pVCpu)
2628{
2629 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2630 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2631
2632 if (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2633 {
2634 Assert(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2635 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2636 {
2637 ASMWrMsr(MSR_K8_LSTAR, pVCpu->hmr0.s.vmx.u64HostMsrLStar);
2638 ASMWrMsr(MSR_K6_STAR, pVCpu->hmr0.s.vmx.u64HostMsrStar);
2639 ASMWrMsr(MSR_K8_SF_MASK, pVCpu->hmr0.s.vmx.u64HostMsrSfMask);
2640 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pVCpu->hmr0.s.vmx.u64HostMsrKernelGsBase);
2641 }
2642 }
2643 pVCpu->hmr0.s.vmx.fLazyMsrs &= ~(VMX_LAZY_MSRS_LOADED_GUEST | VMX_LAZY_MSRS_SAVED_HOST);
2644}
2645
2646
2647/**
2648 * Verifies that our cached values of the VMCS fields are all consistent with
2649 * what's actually present in the VMCS.
2650 *
2651 * @returns VBox status code.
2652 * @retval VINF_SUCCESS if all our caches match their respective VMCS fields.
2653 * @retval VERR_VMX_VMCS_FIELD_CACHE_INVALID if a cache field doesn't match the
2654 * VMCS content. HMCPU error-field is
2655 * updated, see VMX_VCI_XXX.
2656 * @param pVCpu The cross context virtual CPU structure.
2657 * @param pVmcsInfo The VMCS info. object.
2658 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2659 */
2660static int hmR0VmxCheckCachedVmcsCtls(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2661{
2662 const char * const pcszVmcs = fIsNstGstVmcs ? "Nested-guest VMCS" : "VMCS";
2663
2664 uint32_t u32Val;
2665 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
2666 AssertRC(rc);
2667 AssertMsgReturnStmt(pVmcsInfo->u32EntryCtls == u32Val,
2668 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32EntryCtls, u32Val),
2669 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_ENTRY,
2670 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2671
2672 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val);
2673 AssertRC(rc);
2674 AssertMsgReturnStmt(pVmcsInfo->u32ExitCtls == u32Val,
2675 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ExitCtls, u32Val),
2676 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_EXIT,
2677 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2678
2679 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val);
2680 AssertRC(rc);
2681 AssertMsgReturnStmt(pVmcsInfo->u32PinCtls == u32Val,
2682 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32PinCtls, u32Val),
2683 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PIN_EXEC,
2684 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2685
2686 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val);
2687 AssertRC(rc);
2688 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls == u32Val,
2689 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls, u32Val),
2690 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC,
2691 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2692
2693 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
2694 {
2695 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val);
2696 AssertRC(rc);
2697 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls2 == u32Val,
2698 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls2, u32Val),
2699 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC2,
2700 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2701 }
2702
2703 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val);
2704 AssertRC(rc);
2705 AssertMsgReturnStmt(pVmcsInfo->u32XcptBitmap == u32Val,
2706 ("%s exception bitmap mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32XcptBitmap, u32Val),
2707 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_XCPT_BITMAP,
2708 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2709
2710 uint64_t u64Val;
2711 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, &u64Val);
2712 AssertRC(rc);
2713 AssertMsgReturnStmt(pVmcsInfo->u64TscOffset == u64Val,
2714 ("%s TSC offset mismatch: Cache=%#RX64 VMCS=%#RX64\n", pcszVmcs, pVmcsInfo->u64TscOffset, u64Val),
2715 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_TSC_OFFSET,
2716 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2717
2718 NOREF(pcszVmcs);
2719 return VINF_SUCCESS;
2720}
2721
2722#ifdef VBOX_STRICT
2723
2724/**
2725 * Verifies that our cached host EFER MSR value has not changed since we cached it.
2726 *
2727 * @param pVmcsInfo The VMCS info. object.
2728 */
2729static void hmR0VmxCheckHostEferMsr(PCVMXVMCSINFO pVmcsInfo)
2730{
2731 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2732
2733 if (pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_LOAD_EFER_MSR)
2734 {
2735 uint64_t const uHostEferMsr = ASMRdMsr(MSR_K6_EFER);
2736 uint64_t const uHostEferMsrCache = g_uHmVmxHostMsrEfer;
2737 uint64_t uVmcsEferMsrVmcs;
2738 int rc = VMXReadVmcs64(VMX_VMCS64_HOST_EFER_FULL, &uVmcsEferMsrVmcs);
2739 AssertRC(rc);
2740
2741 AssertMsgReturnVoid(uHostEferMsr == uVmcsEferMsrVmcs,
2742 ("EFER Host/VMCS mismatch! host=%#RX64 vmcs=%#RX64\n", uHostEferMsr, uVmcsEferMsrVmcs));
2743 AssertMsgReturnVoid(uHostEferMsr == uHostEferMsrCache,
2744 ("EFER Host/Cache mismatch! host=%#RX64 cache=%#RX64\n", uHostEferMsr, uHostEferMsrCache));
2745 }
2746}
2747
2748
2749/**
2750 * Verifies whether the guest/host MSR pairs in the auto-load/store area in the
2751 * VMCS are correct.
2752 *
2753 * @param pVCpu The cross context virtual CPU structure.
2754 * @param pVmcsInfo The VMCS info. object.
2755 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2756 */
2757static void hmR0VmxCheckAutoLoadStoreMsrs(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2758{
2759 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2760
2761 /* Read the various MSR-area counts from the VMCS. */
2762 uint32_t cEntryLoadMsrs;
2763 uint32_t cExitStoreMsrs;
2764 uint32_t cExitLoadMsrs;
2765 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &cEntryLoadMsrs); AssertRC(rc);
2766 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &cExitStoreMsrs); AssertRC(rc);
2767 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &cExitLoadMsrs); AssertRC(rc);
2768
2769 /* Verify all the MSR counts are the same. */
2770 Assert(cEntryLoadMsrs == cExitStoreMsrs);
2771 Assert(cExitStoreMsrs == cExitLoadMsrs);
2772 uint32_t const cMsrs = cExitLoadMsrs;
2773
2774 /* Verify the MSR counts do not exceed the maximum count supported by the hardware. */
2775 Assert(cMsrs < VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc));
2776
2777 /* Verify the MSR counts are within the allocated page size. */
2778 Assert(sizeof(VMXAUTOMSR) * cMsrs <= X86_PAGE_4K_SIZE);
2779
2780 /* Verify the relevant contents of the MSR areas match. */
2781 PCVMXAUTOMSR pGuestMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2782 PCVMXAUTOMSR pGuestMsrStore = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2783 PCVMXAUTOMSR pHostMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2784 bool const fSeparateExitMsrStorePage = hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo);
2785 for (uint32_t i = 0; i < cMsrs; i++)
2786 {
2787 /* Verify that the MSRs are paired properly and that the host MSR has the correct value. */
2788 if (fSeparateExitMsrStorePage)
2789 {
2790 AssertMsgReturnVoid(pGuestMsrLoad->u32Msr == pGuestMsrStore->u32Msr,
2791 ("GuestMsrLoad=%#RX32 GuestMsrStore=%#RX32 cMsrs=%u\n",
2792 pGuestMsrLoad->u32Msr, pGuestMsrStore->u32Msr, cMsrs));
2793 }
2794
2795 AssertMsgReturnVoid(pHostMsrLoad->u32Msr == pGuestMsrLoad->u32Msr,
2796 ("HostMsrLoad=%#RX32 GuestMsrLoad=%#RX32 cMsrs=%u\n",
2797 pHostMsrLoad->u32Msr, pGuestMsrLoad->u32Msr, cMsrs));
2798
2799 uint64_t const u64HostMsr = ASMRdMsr(pHostMsrLoad->u32Msr);
2800 AssertMsgReturnVoid(pHostMsrLoad->u64Value == u64HostMsr,
2801 ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2802 pHostMsrLoad->u32Msr, pHostMsrLoad->u64Value, u64HostMsr, cMsrs));
2803
2804 /* Verify that cached host EFER MSR matches what's loaded on the CPU. */
2805 bool const fIsEferMsr = RT_BOOL(pHostMsrLoad->u32Msr == MSR_K6_EFER);
2806 AssertMsgReturnVoid(!fIsEferMsr || u64HostMsr == g_uHmVmxHostMsrEfer,
2807 ("Cached=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n", g_uHmVmxHostMsrEfer, u64HostMsr, cMsrs));
2808
2809 /* Verify that the accesses are as expected in the MSR bitmap for auto-load/store MSRs. */
2810 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2811 {
2812 uint32_t const fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, pGuestMsrLoad->u32Msr);
2813 if (fIsEferMsr)
2814 {
2815 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_RD), ("Passthru read for EFER MSR!?\n"));
2816 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_WR), ("Passthru write for EFER MSR!?\n"));
2817 }
2818 else
2819 {
2820 /* Verify LBR MSRs (used only for debugging) are intercepted. We don't passthru these MSRs to the guest yet. */
2821 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
2822 if ( pVM->hmr0.s.vmx.fLbr
2823 && ( hmR0VmxIsLbrBranchFromMsr(pVM, pGuestMsrLoad->u32Msr, NULL /* pidxMsr */)
2824 || hmR0VmxIsLbrBranchToMsr(pVM, pGuestMsrLoad->u32Msr, NULL /* pidxMsr */)
2825 || pGuestMsrLoad->u32Msr == pVM->hmr0.s.vmx.idLbrTosMsr))
2826 {
2827 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_MASK) == VMXMSRPM_EXIT_RD_WR,
2828 ("u32Msr=%#RX32 cMsrs=%u Passthru read/write for LBR MSRs!\n",
2829 pGuestMsrLoad->u32Msr, cMsrs));
2830 }
2831 else if (!fIsNstGstVmcs)
2832 {
2833 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_MASK) == VMXMSRPM_ALLOW_RD_WR,
2834 ("u32Msr=%#RX32 cMsrs=%u No passthru read/write!\n", pGuestMsrLoad->u32Msr, cMsrs));
2835 }
2836 else
2837 {
2838 /*
2839 * A nested-guest VMCS must -also- allow read/write passthrough for the MSR for us to
2840 * execute a nested-guest with MSR passthrough.
2841 *
2842 * Check if the nested-guest MSR bitmap allows passthrough, and if so, assert that we
2843 * allow passthrough too.
2844 */
2845 void const *pvMsrBitmapNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
2846 Assert(pvMsrBitmapNstGst);
2847 uint32_t const fMsrpmNstGst = CPUMGetVmxMsrPermission(pvMsrBitmapNstGst, pGuestMsrLoad->u32Msr);
2848 AssertMsgReturnVoid(fMsrpm == fMsrpmNstGst,
2849 ("u32Msr=%#RX32 cMsrs=%u Permission mismatch fMsrpm=%#x fMsrpmNstGst=%#x!\n",
2850 pGuestMsrLoad->u32Msr, cMsrs, fMsrpm, fMsrpmNstGst));
2851 }
2852 }
2853 }
2854
2855 /* Move to the next MSR. */
2856 pHostMsrLoad++;
2857 pGuestMsrLoad++;
2858 pGuestMsrStore++;
2859 }
2860}
2861
2862#endif /* VBOX_STRICT */
2863
2864/**
2865 * Flushes the TLB using EPT.
2866 *
2867 * @returns VBox status code.
2868 * @param pVCpu The cross context virtual CPU structure of the calling
2869 * EMT. Can be NULL depending on @a enmTlbFlush.
2870 * @param pVmcsInfo The VMCS info. object. Can be NULL depending on @a
2871 * enmTlbFlush.
2872 * @param enmTlbFlush Type of flush.
2873 *
2874 * @remarks Caller is responsible for making sure this function is called only
2875 * when NestedPaging is supported and providing @a enmTlbFlush that is
2876 * supported by the CPU.
2877 * @remarks Can be called with interrupts disabled.
2878 */
2879static void hmR0VmxFlushEpt(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, VMXTLBFLUSHEPT enmTlbFlush)
2880{
2881 uint64_t au64Descriptor[2];
2882 if (enmTlbFlush == VMXTLBFLUSHEPT_ALL_CONTEXTS)
2883 au64Descriptor[0] = 0;
2884 else
2885 {
2886 Assert(pVCpu);
2887 Assert(pVmcsInfo);
2888 au64Descriptor[0] = pVmcsInfo->HCPhysEPTP;
2889 }
2890 au64Descriptor[1] = 0; /* MBZ. Intel spec. 33.3 "VMX Instructions" */
2891
2892 int rc = VMXR0InvEPT(enmTlbFlush, &au64Descriptor[0]);
2893 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %#RHp failed. rc=%Rrc\n", enmTlbFlush, au64Descriptor[0], rc));
2894
2895 if ( RT_SUCCESS(rc)
2896 && pVCpu)
2897 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushNestedPaging);
2898}
2899
2900
2901/**
2902 * Flushes the TLB using VPID.
2903 *
2904 * @returns VBox status code.
2905 * @param pVCpu The cross context virtual CPU structure of the calling
2906 * EMT. Can be NULL depending on @a enmTlbFlush.
2907 * @param enmTlbFlush Type of flush.
2908 * @param GCPtr Virtual address of the page to flush (can be 0 depending
2909 * on @a enmTlbFlush).
2910 *
2911 * @remarks Can be called with interrupts disabled.
2912 */
2913static void hmR0VmxFlushVpid(PVMCPUCC pVCpu, VMXTLBFLUSHVPID enmTlbFlush, RTGCPTR GCPtr)
2914{
2915 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fVpid);
2916
2917 uint64_t au64Descriptor[2];
2918 if (enmTlbFlush == VMXTLBFLUSHVPID_ALL_CONTEXTS)
2919 {
2920 au64Descriptor[0] = 0;
2921 au64Descriptor[1] = 0;
2922 }
2923 else
2924 {
2925 AssertPtr(pVCpu);
2926 AssertMsg(pVCpu->hmr0.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hmr0.s.uCurrentAsid));
2927 AssertMsg(pVCpu->hmr0.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hmr0.s.uCurrentAsid));
2928 au64Descriptor[0] = pVCpu->hmr0.s.uCurrentAsid;
2929 au64Descriptor[1] = GCPtr;
2930 }
2931
2932 int rc = VMXR0InvVPID(enmTlbFlush, &au64Descriptor[0]);
2933 AssertMsg(rc == VINF_SUCCESS,
2934 ("VMXR0InvVPID %#x %u %RGv failed with %Rrc\n", enmTlbFlush, pVCpu ? pVCpu->hmr0.s.uCurrentAsid : 0, GCPtr, rc));
2935
2936 if ( RT_SUCCESS(rc)
2937 && pVCpu)
2938 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
2939 NOREF(rc);
2940}
2941
2942
2943/**
2944 * Invalidates a guest page by guest virtual address. Only relevant for EPT/VPID,
2945 * otherwise there is nothing really to invalidate.
2946 *
2947 * @returns VBox status code.
2948 * @param pVCpu The cross context virtual CPU structure.
2949 * @param GCVirt Guest virtual address of the page to invalidate.
2950 */
2951VMMR0DECL(int) VMXR0InvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt)
2952{
2953 AssertPtr(pVCpu);
2954 LogFlowFunc(("pVCpu=%p GCVirt=%RGv\n", pVCpu, GCVirt));
2955
2956 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_TLB_FLUSH))
2957 {
2958 /*
2959 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for
2960 * the EPT case. See @bugref{6043} and @bugref{6177}.
2961 *
2962 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VM-entry in hmR0VmxFlushTLB*()
2963 * as this function maybe called in a loop with individual addresses.
2964 */
2965 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2966 if (pVM->hmr0.s.vmx.fVpid)
2967 {
2968 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
2969 {
2970 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_INDIV_ADDR, GCVirt);
2971 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
2972 }
2973 else
2974 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2975 }
2976 else if (pVM->hmr0.s.fNestedPaging)
2977 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2978 }
2979
2980 return VINF_SUCCESS;
2981}
2982
2983
2984/**
2985 * Dummy placeholder for tagged-TLB flush handling before VM-entry. Used in the
2986 * case where neither EPT nor VPID is supported by the CPU.
2987 *
2988 * @param pHostCpu The HM physical-CPU structure.
2989 * @param pVCpu The cross context virtual CPU structure.
2990 *
2991 * @remarks Called with interrupts disabled.
2992 */
2993static void hmR0VmxFlushTaggedTlbNone(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
2994{
2995 AssertPtr(pVCpu);
2996 AssertPtr(pHostCpu);
2997
2998 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
2999
3000 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3001 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3002 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3003 pVCpu->hmr0.s.fForceTLBFlush = false;
3004 return;
3005}
3006
3007
3008/**
3009 * Flushes the tagged-TLB entries for EPT+VPID CPUs as necessary.
3010 *
3011 * @param pHostCpu The HM physical-CPU structure.
3012 * @param pVCpu The cross context virtual CPU structure.
3013 * @param pVmcsInfo The VMCS info. object.
3014 *
3015 * @remarks All references to "ASID" in this function pertains to "VPID" in Intel's
3016 * nomenclature. The reason is, to avoid confusion in compare statements
3017 * since the host-CPU copies are named "ASID".
3018 *
3019 * @remarks Called with interrupts disabled.
3020 */
3021static void hmR0VmxFlushTaggedTlbBoth(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3022{
3023#ifdef VBOX_WITH_STATISTICS
3024 bool fTlbFlushed = false;
3025# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { fTlbFlushed = true; } while (0)
3026# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { \
3027 if (!fTlbFlushed) \
3028 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch); \
3029 } while (0)
3030#else
3031# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { } while (0)
3032# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { } while (0)
3033#endif
3034
3035 AssertPtr(pVCpu);
3036 AssertPtr(pHostCpu);
3037 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3038
3039 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3040 AssertMsg(pVM->hmr0.s.fNestedPaging && pVM->hmr0.s.vmx.fVpid,
3041 ("hmR0VmxFlushTaggedTlbBoth cannot be invoked unless NestedPaging & VPID are enabled."
3042 "fNestedPaging=%RTbool fVpid=%RTbool", pVM->hmr0.s.fNestedPaging, pVM->hmr0.s.vmx.fVpid));
3043
3044 /*
3045 * Force a TLB flush for the first world-switch if the current CPU differs from the one we
3046 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
3047 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
3048 * cannot reuse the current ASID anymore.
3049 */
3050 if ( pVCpu->hmr0.s.idLastCpu != pHostCpu->idCpu
3051 || pVCpu->hmr0.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3052 {
3053 ++pHostCpu->uCurrentAsid;
3054 if (pHostCpu->uCurrentAsid >= g_uHmMaxAsid)
3055 {
3056 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0. */
3057 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
3058 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
3059 }
3060
3061 pVCpu->hmr0.s.uCurrentAsid = pHostCpu->uCurrentAsid;
3062 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3063 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3064
3065 /*
3066 * Flush by EPT when we get rescheduled to a new host CPU to ensure EPT-only tagged mappings are also
3067 * invalidated. We don't need to flush-by-VPID here as flushing by EPT covers it. See @bugref{6568}.
3068 */
3069 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hmr0.s.vmx.enmTlbFlushEpt);
3070 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3071 HMVMX_SET_TAGGED_TLB_FLUSHED();
3072 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
3073 }
3074 else if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH)) /* Check for explicit TLB flushes. */
3075 {
3076 /*
3077 * Changes to the EPT paging structure by VMM requires flushing-by-EPT as the CPU
3078 * creates guest-physical (ie. only EPT-tagged) mappings while traversing the EPT
3079 * tables when EPT is in use. Flushing-by-VPID will only flush linear (only
3080 * VPID-tagged) and combined (EPT+VPID tagged) mappings but not guest-physical
3081 * mappings, see @bugref{6568}.
3082 *
3083 * See Intel spec. 28.3.2 "Creating and Using Cached Translation Information".
3084 */
3085 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hmr0.s.vmx.enmTlbFlushEpt);
3086 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3087 HMVMX_SET_TAGGED_TLB_FLUSHED();
3088 }
3089 else if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3090 {
3091 /*
3092 * The nested-guest specifies its own guest-physical address to use as the APIC-access
3093 * address which requires flushing the TLB of EPT cached structures.
3094 *
3095 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
3096 */
3097 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hmr0.s.vmx.enmTlbFlushEpt);
3098 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3099 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3100 HMVMX_SET_TAGGED_TLB_FLUSHED();
3101 }
3102
3103
3104 pVCpu->hmr0.s.fForceTLBFlush = false;
3105 HMVMX_UPDATE_FLUSH_SKIPPED_STAT();
3106
3107 Assert(pVCpu->hmr0.s.idLastCpu == pHostCpu->idCpu);
3108 Assert(pVCpu->hmr0.s.cTlbFlushes == pHostCpu->cTlbFlushes);
3109 AssertMsg(pVCpu->hmr0.s.cTlbFlushes == pHostCpu->cTlbFlushes,
3110 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hmr0.s.cTlbFlushes, pHostCpu->cTlbFlushes));
3111 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < g_uHmMaxAsid,
3112 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3113 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hmr0.s.idLastCpu, pVCpu->hmr0.s.cTlbFlushes));
3114 AssertMsg(pVCpu->hmr0.s.uCurrentAsid >= 1 && pVCpu->hmr0.s.uCurrentAsid < g_uHmMaxAsid,
3115 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hmr0.s.uCurrentAsid));
3116
3117 /* Update VMCS with the VPID. */
3118 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hmr0.s.uCurrentAsid);
3119 AssertRC(rc);
3120
3121#undef HMVMX_SET_TAGGED_TLB_FLUSHED
3122}
3123
3124
3125/**
3126 * Flushes the tagged-TLB entries for EPT CPUs as necessary.
3127 *
3128 * @param pHostCpu The HM physical-CPU structure.
3129 * @param pVCpu The cross context virtual CPU structure.
3130 * @param pVmcsInfo The VMCS info. object.
3131 *
3132 * @remarks Called with interrupts disabled.
3133 */
3134static void hmR0VmxFlushTaggedTlbEpt(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3135{
3136 AssertPtr(pVCpu);
3137 AssertPtr(pHostCpu);
3138 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3139 AssertMsg(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked without NestedPaging."));
3140 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fVpid, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with VPID."));
3141
3142 /*
3143 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
3144 * A change in the TLB flush count implies the host CPU is online after a suspend/resume.
3145 */
3146 if ( pVCpu->hmr0.s.idLastCpu != pHostCpu->idCpu
3147 || pVCpu->hmr0.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3148 {
3149 pVCpu->hmr0.s.fForceTLBFlush = true;
3150 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3151 }
3152
3153 /* Check for explicit TLB flushes. */
3154 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3155 {
3156 pVCpu->hmr0.s.fForceTLBFlush = true;
3157 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3158 }
3159
3160 /* Check for TLB flushes while switching to/from a nested-guest. */
3161 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3162 {
3163 pVCpu->hmr0.s.fForceTLBFlush = true;
3164 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3165 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3166 }
3167
3168 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3169 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3170
3171 if (pVCpu->hmr0.s.fForceTLBFlush)
3172 {
3173 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.enmTlbFlushEpt);
3174 pVCpu->hmr0.s.fForceTLBFlush = false;
3175 }
3176}
3177
3178
3179/**
3180 * Flushes the tagged-TLB entries for VPID CPUs as necessary.
3181 *
3182 * @param pHostCpu The HM physical-CPU structure.
3183 * @param pVCpu The cross context virtual CPU structure.
3184 *
3185 * @remarks Called with interrupts disabled.
3186 */
3187static void hmR0VmxFlushTaggedTlbVpid(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
3188{
3189 AssertPtr(pVCpu);
3190 AssertPtr(pHostCpu);
3191 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3192 AssertMsg(pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fVpid, ("hmR0VmxFlushTlbVpid cannot be invoked without VPID."));
3193 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging"));
3194
3195 /*
3196 * Force a TLB flush for the first world switch if the current CPU differs from the one we
3197 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
3198 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
3199 * cannot reuse the current ASID anymore.
3200 */
3201 if ( pVCpu->hmr0.s.idLastCpu != pHostCpu->idCpu
3202 || pVCpu->hmr0.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3203 {
3204 pVCpu->hmr0.s.fForceTLBFlush = true;
3205 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3206 }
3207
3208 /* Check for explicit TLB flushes. */
3209 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3210 {
3211 /*
3212 * If we ever support VPID flush combinations other than ALL or SINGLE-context (see
3213 * hmR0VmxSetupTaggedTlb()) we would need to explicitly flush in this case (add an
3214 * fExplicitFlush = true here and change the pHostCpu->fFlushAsidBeforeUse check below to
3215 * include fExplicitFlush's too) - an obscure corner case.
3216 */
3217 pVCpu->hmr0.s.fForceTLBFlush = true;
3218 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3219 }
3220
3221 /* Check for TLB flushes while switching to/from a nested-guest. */
3222 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3223 {
3224 pVCpu->hmr0.s.fForceTLBFlush = true;
3225 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3226 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3227 }
3228
3229 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3230 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3231 if (pVCpu->hmr0.s.fForceTLBFlush)
3232 {
3233 ++pHostCpu->uCurrentAsid;
3234 if (pHostCpu->uCurrentAsid >= g_uHmMaxAsid)
3235 {
3236 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0 */
3237 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
3238 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
3239 }
3240
3241 pVCpu->hmr0.s.fForceTLBFlush = false;
3242 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3243 pVCpu->hmr0.s.uCurrentAsid = pHostCpu->uCurrentAsid;
3244 if (pHostCpu->fFlushAsidBeforeUse)
3245 {
3246 if (pVM->hmr0.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_SINGLE_CONTEXT)
3247 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_SINGLE_CONTEXT, 0 /* GCPtr */);
3248 else if (pVM->hmr0.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_ALL_CONTEXTS)
3249 {
3250 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_ALL_CONTEXTS, 0 /* GCPtr */);
3251 pHostCpu->fFlushAsidBeforeUse = false;
3252 }
3253 else
3254 {
3255 /* hmR0VmxSetupTaggedTlb() ensures we never get here. Paranoia. */
3256 AssertMsgFailed(("Unsupported VPID-flush context type.\n"));
3257 }
3258 }
3259 }
3260
3261 AssertMsg(pVCpu->hmr0.s.cTlbFlushes == pHostCpu->cTlbFlushes,
3262 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hmr0.s.cTlbFlushes, pHostCpu->cTlbFlushes));
3263 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < g_uHmMaxAsid,
3264 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3265 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hmr0.s.idLastCpu, pVCpu->hmr0.s.cTlbFlushes));
3266 AssertMsg(pVCpu->hmr0.s.uCurrentAsid >= 1 && pVCpu->hmr0.s.uCurrentAsid < g_uHmMaxAsid,
3267 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hmr0.s.uCurrentAsid));
3268
3269 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hmr0.s.uCurrentAsid);
3270 AssertRC(rc);
3271}
3272
3273
3274/**
3275 * Flushes the guest TLB entry based on CPU capabilities.
3276 *
3277 * @param pHostCpu The HM physical-CPU structure.
3278 * @param pVCpu The cross context virtual CPU structure.
3279 * @param pVmcsInfo The VMCS info. object.
3280 *
3281 * @remarks Called with interrupts disabled.
3282 */
3283static void hmR0VmxFlushTaggedTlb(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3284{
3285#ifdef HMVMX_ALWAYS_FLUSH_TLB
3286 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
3287#endif
3288 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3289 switch (pVM->hmr0.s.vmx.enmTlbFlushType)
3290 {
3291 case VMXTLBFLUSHTYPE_EPT_VPID: hmR0VmxFlushTaggedTlbBoth(pHostCpu, pVCpu, pVmcsInfo); break;
3292 case VMXTLBFLUSHTYPE_EPT: hmR0VmxFlushTaggedTlbEpt(pHostCpu, pVCpu, pVmcsInfo); break;
3293 case VMXTLBFLUSHTYPE_VPID: hmR0VmxFlushTaggedTlbVpid(pHostCpu, pVCpu); break;
3294 case VMXTLBFLUSHTYPE_NONE: hmR0VmxFlushTaggedTlbNone(pHostCpu, pVCpu); break;
3295 default:
3296 AssertMsgFailed(("Invalid flush-tag function identifier\n"));
3297 break;
3298 }
3299 /* Don't assert that VMCPU_FF_TLB_FLUSH should no longer be pending. It can be set by other EMTs. */
3300}
3301
3302
3303/**
3304 * Sets up the appropriate tagged TLB-flush level and handler for flushing guest
3305 * TLB entries from the host TLB before VM-entry.
3306 *
3307 * @returns VBox status code.
3308 * @param pVM The cross context VM structure.
3309 */
3310static int hmR0VmxSetupTaggedTlb(PVMCC pVM)
3311{
3312 /*
3313 * Determine optimal flush type for nested paging.
3314 * We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup
3315 * unrestricted guest execution (see hmR3InitFinalizeR0()).
3316 */
3317 if (pVM->hmr0.s.fNestedPaging)
3318 {
3319 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT)
3320 {
3321 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT)
3322 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_SINGLE_CONTEXT;
3323 else if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
3324 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_ALL_CONTEXTS;
3325 else
3326 {
3327 /* Shouldn't happen. EPT is supported but no suitable flush-types supported. */
3328 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3329 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED;
3330 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3331 }
3332
3333 /* Make sure the write-back cacheable memory type for EPT is supported. */
3334 if (RT_UNLIKELY(!(g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EMT_WB)))
3335 {
3336 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3337 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_MEM_TYPE_NOT_WB;
3338 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3339 }
3340
3341 /* EPT requires a page-walk length of 4. */
3342 if (RT_UNLIKELY(!(g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4)))
3343 {
3344 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3345 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED;
3346 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3347 }
3348 }
3349 else
3350 {
3351 /* Shouldn't happen. EPT is supported but INVEPT instruction is not supported. */
3352 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3353 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_INVEPT_UNAVAILABLE;
3354 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3355 }
3356 }
3357
3358 /*
3359 * Determine optimal flush type for VPID.
3360 */
3361 if (pVM->hmr0.s.vmx.fVpid)
3362 {
3363 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID)
3364 {
3365 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT)
3366 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_SINGLE_CONTEXT;
3367 else if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS)
3368 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_ALL_CONTEXTS;
3369 else
3370 {
3371 /* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
3372 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
3373 LogRelFunc(("Only INDIV_ADDR supported. Ignoring VPID.\n"));
3374 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
3375 LogRelFunc(("Only SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
3376 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3377 pVM->hmr0.s.vmx.fVpid = false;
3378 }
3379 }
3380 else
3381 {
3382 /* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
3383 Log4Func(("VPID supported without INVEPT support. Ignoring VPID.\n"));
3384 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3385 pVM->hmr0.s.vmx.fVpid = false;
3386 }
3387 }
3388
3389 /*
3390 * Setup the handler for flushing tagged-TLBs.
3391 */
3392 if (pVM->hmr0.s.fNestedPaging && pVM->hmr0.s.vmx.fVpid)
3393 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT_VPID;
3394 else if (pVM->hmr0.s.fNestedPaging)
3395 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT;
3396 else if (pVM->hmr0.s.vmx.fVpid)
3397 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_VPID;
3398 else
3399 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_NONE;
3400
3401
3402 /*
3403 * Copy out the result to ring-3.
3404 */
3405 pVM->hm.s.ForR3.vmx.fVpid = pVM->hmr0.s.vmx.fVpid;
3406 pVM->hm.s.ForR3.vmx.enmTlbFlushType = pVM->hmr0.s.vmx.enmTlbFlushType;
3407 pVM->hm.s.ForR3.vmx.enmTlbFlushEpt = pVM->hmr0.s.vmx.enmTlbFlushEpt;
3408 pVM->hm.s.ForR3.vmx.enmTlbFlushVpid = pVM->hmr0.s.vmx.enmTlbFlushVpid;
3409 return VINF_SUCCESS;
3410}
3411
3412
3413/**
3414 * Sets up the LBR MSR ranges based on the host CPU.
3415 *
3416 * @returns VBox status code.
3417 * @param pVM The cross context VM structure.
3418 */
3419static int hmR0VmxSetupLbrMsrRange(PVMCC pVM)
3420{
3421 Assert(pVM->hmr0.s.vmx.fLbr);
3422 uint32_t idLbrFromIpMsrFirst;
3423 uint32_t idLbrFromIpMsrLast;
3424 uint32_t idLbrToIpMsrFirst;
3425 uint32_t idLbrToIpMsrLast;
3426 uint32_t idLbrTosMsr;
3427
3428 /*
3429 * Determine the LBR MSRs supported for this host CPU family and model.
3430 *
3431 * See Intel spec. 17.4.8 "LBR Stack".
3432 * See Intel "Model-Specific Registers" spec.
3433 */
3434 uint32_t const uFamilyModel = (pVM->cpum.ro.HostFeatures.uFamily << 8)
3435 | pVM->cpum.ro.HostFeatures.uModel;
3436 switch (uFamilyModel)
3437 {
3438 case 0x0f01: case 0x0f02:
3439 idLbrFromIpMsrFirst = MSR_P4_LASTBRANCH_0;
3440 idLbrFromIpMsrLast = MSR_P4_LASTBRANCH_3;
3441 idLbrToIpMsrFirst = 0x0;
3442 idLbrToIpMsrLast = 0x0;
3443 idLbrTosMsr = MSR_P4_LASTBRANCH_TOS;
3444 break;
3445
3446 case 0x065c: case 0x065f: case 0x064e: case 0x065e: case 0x068e:
3447 case 0x069e: case 0x0655: case 0x0666: case 0x067a: case 0x0667:
3448 case 0x066a: case 0x066c: case 0x067d: case 0x067e:
3449 idLbrFromIpMsrFirst = MSR_LASTBRANCH_0_FROM_IP;
3450 idLbrFromIpMsrLast = MSR_LASTBRANCH_31_FROM_IP;
3451 idLbrToIpMsrFirst = MSR_LASTBRANCH_0_TO_IP;
3452 idLbrToIpMsrLast = MSR_LASTBRANCH_31_TO_IP;
3453 idLbrTosMsr = MSR_LASTBRANCH_TOS;
3454 break;
3455
3456 case 0x063d: case 0x0647: case 0x064f: case 0x0656: case 0x063c:
3457 case 0x0645: case 0x0646: case 0x063f: case 0x062a: case 0x062d:
3458 case 0x063a: case 0x063e: case 0x061a: case 0x061e: case 0x061f:
3459 case 0x062e: case 0x0625: case 0x062c: case 0x062f:
3460 idLbrFromIpMsrFirst = MSR_LASTBRANCH_0_FROM_IP;
3461 idLbrFromIpMsrLast = MSR_LASTBRANCH_15_FROM_IP;
3462 idLbrToIpMsrFirst = MSR_LASTBRANCH_0_TO_IP;
3463 idLbrToIpMsrLast = MSR_LASTBRANCH_15_TO_IP;
3464 idLbrTosMsr = MSR_LASTBRANCH_TOS;
3465 break;
3466
3467 case 0x0617: case 0x061d: case 0x060f:
3468 idLbrFromIpMsrFirst = MSR_CORE2_LASTBRANCH_0_FROM_IP;
3469 idLbrFromIpMsrLast = MSR_CORE2_LASTBRANCH_3_FROM_IP;
3470 idLbrToIpMsrFirst = MSR_CORE2_LASTBRANCH_0_TO_IP;
3471 idLbrToIpMsrLast = MSR_CORE2_LASTBRANCH_3_TO_IP;
3472 idLbrTosMsr = MSR_CORE2_LASTBRANCH_TOS;
3473 break;
3474
3475 /* Atom and related microarchitectures we don't care about:
3476 case 0x0637: case 0x064a: case 0x064c: case 0x064d: case 0x065a:
3477 case 0x065d: case 0x061c: case 0x0626: case 0x0627: case 0x0635:
3478 case 0x0636: */
3479 /* All other CPUs: */
3480 default:
3481 {
3482 LogRelFunc(("Could not determine LBR stack size for the CPU model %#x\n", uFamilyModel));
3483 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_LBR_STACK_SIZE_UNKNOWN;
3484 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3485 }
3486 }
3487
3488 /*
3489 * Validate.
3490 */
3491 uint32_t const cLbrStack = idLbrFromIpMsrLast - idLbrFromIpMsrFirst + 1;
3492 PCVMCPU pVCpu0 = VMCC_GET_CPU_0(pVM);
3493 AssertCompile( RT_ELEMENTS(pVCpu0->hm.s.vmx.VmcsInfo.au64LbrFromIpMsr)
3494 == RT_ELEMENTS(pVCpu0->hm.s.vmx.VmcsInfo.au64LbrToIpMsr));
3495 if (cLbrStack > RT_ELEMENTS(pVCpu0->hm.s.vmx.VmcsInfo.au64LbrFromIpMsr))
3496 {
3497 LogRelFunc(("LBR stack size of the CPU (%u) exceeds our buffer size\n", cLbrStack));
3498 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_LBR_STACK_SIZE_OVERFLOW;
3499 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3500 }
3501 NOREF(pVCpu0);
3502
3503 /*
3504 * Update the LBR info. to the VM struct. for use later.
3505 */
3506 pVM->hmr0.s.vmx.idLbrTosMsr = idLbrTosMsr;
3507
3508 pVM->hm.s.ForR3.vmx.idLbrFromIpMsrFirst = pVM->hmr0.s.vmx.idLbrFromIpMsrFirst = idLbrFromIpMsrFirst;
3509 pVM->hm.s.ForR3.vmx.idLbrFromIpMsrLast = pVM->hmr0.s.vmx.idLbrFromIpMsrLast = idLbrFromIpMsrLast;
3510
3511 pVM->hm.s.ForR3.vmx.idLbrToIpMsrFirst = pVM->hmr0.s.vmx.idLbrToIpMsrFirst = idLbrToIpMsrFirst;
3512 pVM->hm.s.ForR3.vmx.idLbrToIpMsrLast = pVM->hmr0.s.vmx.idLbrToIpMsrLast = idLbrToIpMsrLast;
3513 return VINF_SUCCESS;
3514}
3515
3516
3517#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3518/**
3519 * Sets up the shadow VMCS fields arrays.
3520 *
3521 * This function builds arrays of VMCS fields to sync the shadow VMCS later while
3522 * executing the guest.
3523 *
3524 * @returns VBox status code.
3525 * @param pVM The cross context VM structure.
3526 */
3527static int hmR0VmxSetupShadowVmcsFieldsArrays(PVMCC pVM)
3528{
3529 /*
3530 * Paranoia. Ensure we haven't exposed the VMWRITE-All VMX feature to the guest
3531 * when the host does not support it.
3532 */
3533 bool const fGstVmwriteAll = pVM->cpum.ro.GuestFeatures.fVmxVmwriteAll;
3534 if ( !fGstVmwriteAll
3535 || (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL))
3536 { /* likely. */ }
3537 else
3538 {
3539 LogRelFunc(("VMX VMWRITE-All feature exposed to the guest but host CPU does not support it!\n"));
3540 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_GST_HOST_VMWRITE_ALL;
3541 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3542 }
3543
3544 uint32_t const cVmcsFields = RT_ELEMENTS(g_aVmcsFields);
3545 uint32_t cRwFields = 0;
3546 uint32_t cRoFields = 0;
3547 for (uint32_t i = 0; i < cVmcsFields; i++)
3548 {
3549 VMXVMCSFIELD VmcsField;
3550 VmcsField.u = g_aVmcsFields[i];
3551
3552 /*
3553 * We will be writing "FULL" (64-bit) fields while syncing the shadow VMCS.
3554 * Therefore, "HIGH" (32-bit portion of 64-bit) fields must not be included
3555 * in the shadow VMCS fields array as they would be redundant.
3556 *
3557 * If the VMCS field depends on a CPU feature that is not exposed to the guest,
3558 * we must not include it in the shadow VMCS fields array. Guests attempting to
3559 * VMREAD/VMWRITE such VMCS fields would cause a VM-exit and we shall emulate
3560 * the required behavior.
3561 */
3562 if ( VmcsField.n.fAccessType == VMX_VMCSFIELD_ACCESS_FULL
3563 && CPUMIsGuestVmxVmcsFieldValid(pVM, VmcsField.u))
3564 {
3565 /*
3566 * Read-only fields are placed in a separate array so that while syncing shadow
3567 * VMCS fields later (which is more performance critical) we can avoid branches.
3568 *
3569 * However, if the guest can write to all fields (including read-only fields),
3570 * we treat it a as read/write field. Otherwise, writing to these fields would
3571 * cause a VMWRITE instruction error while syncing the shadow VMCS.
3572 */
3573 if ( fGstVmwriteAll
3574 || !VMXIsVmcsFieldReadOnly(VmcsField.u))
3575 pVM->hmr0.s.vmx.paShadowVmcsFields[cRwFields++] = VmcsField.u;
3576 else
3577 pVM->hmr0.s.vmx.paShadowVmcsRoFields[cRoFields++] = VmcsField.u;
3578 }
3579 }
3580
3581 /* Update the counts. */
3582 pVM->hmr0.s.vmx.cShadowVmcsFields = cRwFields;
3583 pVM->hmr0.s.vmx.cShadowVmcsRoFields = cRoFields;
3584 return VINF_SUCCESS;
3585}
3586
3587
3588/**
3589 * Sets up the VMREAD and VMWRITE bitmaps.
3590 *
3591 * @param pVM The cross context VM structure.
3592 */
3593static void hmR0VmxSetupVmreadVmwriteBitmaps(PVMCC pVM)
3594{
3595 /*
3596 * By default, ensure guest attempts to access any VMCS fields cause VM-exits.
3597 */
3598 uint32_t const cbBitmap = X86_PAGE_4K_SIZE;
3599 uint8_t *pbVmreadBitmap = (uint8_t *)pVM->hmr0.s.vmx.pvVmreadBitmap;
3600 uint8_t *pbVmwriteBitmap = (uint8_t *)pVM->hmr0.s.vmx.pvVmwriteBitmap;
3601 ASMMemFill32(pbVmreadBitmap, cbBitmap, UINT32_C(0xffffffff));
3602 ASMMemFill32(pbVmwriteBitmap, cbBitmap, UINT32_C(0xffffffff));
3603
3604 /*
3605 * Skip intercepting VMREAD/VMWRITE to guest read/write fields in the
3606 * VMREAD and VMWRITE bitmaps.
3607 */
3608 {
3609 uint32_t const *paShadowVmcsFields = pVM->hmr0.s.vmx.paShadowVmcsFields;
3610 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
3611 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
3612 {
3613 uint32_t const uVmcsField = paShadowVmcsFields[i];
3614 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3615 Assert(uVmcsField >> 3 < cbBitmap);
3616 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3617 ASMBitClear(pbVmwriteBitmap + (uVmcsField >> 3), uVmcsField & 7);
3618 }
3619 }
3620
3621 /*
3622 * Skip intercepting VMREAD for guest read-only fields in the VMREAD bitmap
3623 * if the host supports VMWRITE to all supported VMCS fields.
3624 */
3625 if (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL)
3626 {
3627 uint32_t const *paShadowVmcsRoFields = pVM->hmr0.s.vmx.paShadowVmcsRoFields;
3628 uint32_t const cShadowVmcsRoFields = pVM->hmr0.s.vmx.cShadowVmcsRoFields;
3629 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
3630 {
3631 uint32_t const uVmcsField = paShadowVmcsRoFields[i];
3632 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3633 Assert(uVmcsField >> 3 < cbBitmap);
3634 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3635 }
3636 }
3637}
3638#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
3639
3640
3641/**
3642 * Sets up the virtual-APIC page address for the VMCS.
3643 *
3644 * @param pVmcsInfo The VMCS info. object.
3645 */
3646DECLINLINE(void) hmR0VmxSetupVmcsVirtApicAddr(PCVMXVMCSINFO pVmcsInfo)
3647{
3648 RTHCPHYS const HCPhysVirtApic = pVmcsInfo->HCPhysVirtApic;
3649 Assert(HCPhysVirtApic != NIL_RTHCPHYS);
3650 Assert(!(HCPhysVirtApic & 0xfff)); /* Bits 11:0 MBZ. */
3651 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
3652 AssertRC(rc);
3653}
3654
3655
3656/**
3657 * Sets up the MSR-bitmap address for the VMCS.
3658 *
3659 * @param pVmcsInfo The VMCS info. object.
3660 */
3661DECLINLINE(void) hmR0VmxSetupVmcsMsrBitmapAddr(PCVMXVMCSINFO pVmcsInfo)
3662{
3663 RTHCPHYS const HCPhysMsrBitmap = pVmcsInfo->HCPhysMsrBitmap;
3664 Assert(HCPhysMsrBitmap != NIL_RTHCPHYS);
3665 Assert(!(HCPhysMsrBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3666 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_MSR_BITMAP_FULL, HCPhysMsrBitmap);
3667 AssertRC(rc);
3668}
3669
3670
3671/**
3672 * Sets up the APIC-access page address for the VMCS.
3673 *
3674 * @param pVCpu The cross context virtual CPU structure.
3675 */
3676DECLINLINE(void) hmR0VmxSetupVmcsApicAccessAddr(PVMCPUCC pVCpu)
3677{
3678 RTHCPHYS const HCPhysApicAccess = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.HCPhysApicAccess;
3679 Assert(HCPhysApicAccess != NIL_RTHCPHYS);
3680 Assert(!(HCPhysApicAccess & 0xfff)); /* Bits 11:0 MBZ. */
3681 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
3682 AssertRC(rc);
3683}
3684
3685#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3686
3687/**
3688 * Sets up the VMREAD bitmap address for the VMCS.
3689 *
3690 * @param pVCpu The cross context virtual CPU structure.
3691 */
3692DECLINLINE(void) hmR0VmxSetupVmcsVmreadBitmapAddr(PVMCPUCC pVCpu)
3693{
3694 RTHCPHYS const HCPhysVmreadBitmap = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.HCPhysVmreadBitmap;
3695 Assert(HCPhysVmreadBitmap != NIL_RTHCPHYS);
3696 Assert(!(HCPhysVmreadBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3697 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL, HCPhysVmreadBitmap);
3698 AssertRC(rc);
3699}
3700
3701
3702/**
3703 * Sets up the VMWRITE bitmap address for the VMCS.
3704 *
3705 * @param pVCpu The cross context virtual CPU structure.
3706 */
3707DECLINLINE(void) hmR0VmxSetupVmcsVmwriteBitmapAddr(PVMCPUCC pVCpu)
3708{
3709 RTHCPHYS const HCPhysVmwriteBitmap = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.HCPhysVmwriteBitmap;
3710 Assert(HCPhysVmwriteBitmap != NIL_RTHCPHYS);
3711 Assert(!(HCPhysVmwriteBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3712 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL, HCPhysVmwriteBitmap);
3713 AssertRC(rc);
3714}
3715
3716#endif
3717
3718/**
3719 * Sets up the VM-entry MSR load, VM-exit MSR-store and VM-exit MSR-load addresses
3720 * in the VMCS.
3721 *
3722 * @returns VBox status code.
3723 * @param pVmcsInfo The VMCS info. object.
3724 */
3725DECLINLINE(int) hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(PVMXVMCSINFO pVmcsInfo)
3726{
3727 RTHCPHYS const HCPhysGuestMsrLoad = pVmcsInfo->HCPhysGuestMsrLoad;
3728 Assert(HCPhysGuestMsrLoad != NIL_RTHCPHYS);
3729 Assert(!(HCPhysGuestMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3730
3731 RTHCPHYS const HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrStore;
3732 Assert(HCPhysGuestMsrStore != NIL_RTHCPHYS);
3733 Assert(!(HCPhysGuestMsrStore & 0xf)); /* Bits 3:0 MBZ. */
3734
3735 RTHCPHYS const HCPhysHostMsrLoad = pVmcsInfo->HCPhysHostMsrLoad;
3736 Assert(HCPhysHostMsrLoad != NIL_RTHCPHYS);
3737 Assert(!(HCPhysHostMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3738
3739 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL, HCPhysGuestMsrLoad); AssertRC(rc);
3740 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL, HCPhysGuestMsrStore); AssertRC(rc);
3741 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL, HCPhysHostMsrLoad); AssertRC(rc);
3742 return VINF_SUCCESS;
3743}
3744
3745
3746/**
3747 * Sets up MSR permissions in the MSR bitmap of a VMCS info. object.
3748 *
3749 * @param pVCpu The cross context virtual CPU structure.
3750 * @param pVmcsInfo The VMCS info. object.
3751 */
3752static void hmR0VmxSetupVmcsMsrPermissions(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3753{
3754 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS);
3755
3756 /*
3757 * By default, ensure guest attempts to access any MSR cause VM-exits.
3758 * This shall later be relaxed for specific MSRs as necessary.
3759 *
3760 * Note: For nested-guests, the entire bitmap will be merged prior to
3761 * executing the nested-guest using hardware-assisted VMX and hence there
3762 * is no need to perform this operation. See hmR0VmxMergeMsrBitmapNested.
3763 */
3764 Assert(pVmcsInfo->pvMsrBitmap);
3765 ASMMemFill32(pVmcsInfo->pvMsrBitmap, X86_PAGE_4K_SIZE, UINT32_C(0xffffffff));
3766
3767 /*
3768 * The guest can access the following MSRs (read, write) without causing
3769 * VM-exits; they are loaded/stored automatically using fields in the VMCS.
3770 */
3771 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3772 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_CS, VMXMSRPM_ALLOW_RD_WR);
3773 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_ESP, VMXMSRPM_ALLOW_RD_WR);
3774 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_EIP, VMXMSRPM_ALLOW_RD_WR);
3775 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3776 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_FS_BASE, VMXMSRPM_ALLOW_RD_WR);
3777
3778 /*
3779 * The IA32_PRED_CMD and IA32_FLUSH_CMD MSRs are write-only and has no state
3780 * associated with then. We never need to intercept access (writes need to be
3781 * executed without causing a VM-exit, reads will #GP fault anyway).
3782 *
3783 * The IA32_SPEC_CTRL MSR is read/write and has state. We allow the guest to
3784 * read/write them. We swap the guest/host MSR value using the
3785 * auto-load/store MSR area.
3786 */
3787 if (pVM->cpum.ro.GuestFeatures.fIbpb)
3788 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_PRED_CMD, VMXMSRPM_ALLOW_RD_WR);
3789 if (pVM->cpum.ro.GuestFeatures.fFlushCmd)
3790 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_FLUSH_CMD, VMXMSRPM_ALLOW_RD_WR);
3791 if (pVM->cpum.ro.GuestFeatures.fIbrs)
3792 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SPEC_CTRL, VMXMSRPM_ALLOW_RD_WR);
3793
3794 /*
3795 * Allow full read/write access for the following MSRs (mandatory for VT-x)
3796 * required for 64-bit guests.
3797 */
3798 if (pVM->hmr0.s.fAllow64BitGuests)
3799 {
3800 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_LSTAR, VMXMSRPM_ALLOW_RD_WR);
3801 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K6_STAR, VMXMSRPM_ALLOW_RD_WR);
3802 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_SF_MASK, VMXMSRPM_ALLOW_RD_WR);
3803 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_KERNEL_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3804 }
3805
3806 /*
3807 * IA32_EFER MSR is always intercepted, see @bugref{9180#c37}.
3808 */
3809#ifdef VBOX_STRICT
3810 Assert(pVmcsInfo->pvMsrBitmap);
3811 uint32_t const fMsrpmEfer = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, MSR_K6_EFER);
3812 Assert(fMsrpmEfer == VMXMSRPM_EXIT_RD_WR);
3813#endif
3814}
3815
3816
3817/**
3818 * Sets up pin-based VM-execution controls in the VMCS.
3819 *
3820 * @returns VBox status code.
3821 * @param pVCpu The cross context virtual CPU structure.
3822 * @param pVmcsInfo The VMCS info. object.
3823 */
3824static int hmR0VmxSetupVmcsPinCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3825{
3826 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3827 uint32_t fVal = g_HmMsrs.u.vmx.PinCtls.n.allowed0; /* Bits set here must always be set. */
3828 uint32_t const fZap = g_HmMsrs.u.vmx.PinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
3829
3830 fVal |= VMX_PIN_CTLS_EXT_INT_EXIT /* External interrupts cause a VM-exit. */
3831 | VMX_PIN_CTLS_NMI_EXIT; /* Non-maskable interrupts (NMIs) cause a VM-exit. */
3832
3833 if (g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_VIRT_NMI)
3834 fVal |= VMX_PIN_CTLS_VIRT_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
3835
3836 /* Enable the VMX-preemption timer. */
3837 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
3838 {
3839 Assert(g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_PREEMPT_TIMER);
3840 fVal |= VMX_PIN_CTLS_PREEMPT_TIMER;
3841 }
3842
3843#if 0
3844 /* Enable posted-interrupt processing. */
3845 if (pVM->hm.s.fPostedIntrs)
3846 {
3847 Assert(g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_POSTED_INT);
3848 Assert(g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_ACK_EXT_INT);
3849 fVal |= VMX_PIN_CTLS_POSTED_INT;
3850 }
3851#endif
3852
3853 if ((fVal & fZap) != fVal)
3854 {
3855 LogRelFunc(("Invalid pin-based VM-execution controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3856 g_HmMsrs.u.vmx.PinCtls.n.allowed0, fVal, fZap));
3857 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
3858 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3859 }
3860
3861 /* Commit it to the VMCS and update our cache. */
3862 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, fVal);
3863 AssertRC(rc);
3864 pVmcsInfo->u32PinCtls = fVal;
3865
3866 return VINF_SUCCESS;
3867}
3868
3869
3870/**
3871 * Sets up secondary processor-based VM-execution controls in the VMCS.
3872 *
3873 * @returns VBox status code.
3874 * @param pVCpu The cross context virtual CPU structure.
3875 * @param pVmcsInfo The VMCS info. object.
3876 */
3877static int hmR0VmxSetupVmcsProcCtls2(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3878{
3879 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3880 uint32_t fVal = g_HmMsrs.u.vmx.ProcCtls2.n.allowed0; /* Bits set here must be set in the VMCS. */
3881 uint32_t const fZap = g_HmMsrs.u.vmx.ProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3882
3883 /* WBINVD causes a VM-exit. */
3884 if (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_WBINVD_EXIT)
3885 fVal |= VMX_PROC_CTLS2_WBINVD_EXIT;
3886
3887 /* Enable EPT (aka nested-paging). */
3888 if (pVM->hmr0.s.fNestedPaging)
3889 fVal |= VMX_PROC_CTLS2_EPT;
3890
3891 /* Enable the INVPCID instruction if we expose it to the guest and is supported
3892 by the hardware. Without this, guest executing INVPCID would cause a #UD. */
3893 if ( pVM->cpum.ro.GuestFeatures.fInvpcid
3894 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_INVPCID))
3895 fVal |= VMX_PROC_CTLS2_INVPCID;
3896
3897 /* Enable VPID. */
3898 if (pVM->hmr0.s.vmx.fVpid)
3899 fVal |= VMX_PROC_CTLS2_VPID;
3900
3901 /* Enable unrestricted guest execution. */
3902 if (pVM->hmr0.s.vmx.fUnrestrictedGuest)
3903 fVal |= VMX_PROC_CTLS2_UNRESTRICTED_GUEST;
3904
3905#if 0
3906 if (pVM->hm.s.fVirtApicRegs)
3907 {
3908 /* Enable APIC-register virtualization. */
3909 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_APIC_REG_VIRT);
3910 fVal |= VMX_PROC_CTLS2_APIC_REG_VIRT;
3911
3912 /* Enable virtual-interrupt delivery. */
3913 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_INTR_DELIVERY);
3914 fVal |= VMX_PROC_CTLS2_VIRT_INTR_DELIVERY;
3915 }
3916#endif
3917
3918 /* Virtualize-APIC accesses if supported by the CPU. The virtual-APIC page is
3919 where the TPR shadow resides. */
3920 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
3921 * done dynamically. */
3922 if (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
3923 {
3924 fVal |= VMX_PROC_CTLS2_VIRT_APIC_ACCESS;
3925 hmR0VmxSetupVmcsApicAccessAddr(pVCpu);
3926 }
3927
3928 /* Enable the RDTSCP instruction if we expose it to the guest and is supported
3929 by the hardware. Without this, guest executing RDTSCP would cause a #UD. */
3930 if ( pVM->cpum.ro.GuestFeatures.fRdTscP
3931 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_RDTSCP))
3932 fVal |= VMX_PROC_CTLS2_RDTSCP;
3933
3934 /* Enable Pause-Loop exiting. */
3935 if ( (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)
3936 && pVM->hm.s.vmx.cPleGapTicks
3937 && pVM->hm.s.vmx.cPleWindowTicks)
3938 {
3939 fVal |= VMX_PROC_CTLS2_PAUSE_LOOP_EXIT;
3940
3941 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, pVM->hm.s.vmx.cPleGapTicks); AssertRC(rc);
3942 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, pVM->hm.s.vmx.cPleWindowTicks); AssertRC(rc);
3943 }
3944
3945 if ((fVal & fZap) != fVal)
3946 {
3947 LogRelFunc(("Invalid secondary processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3948 g_HmMsrs.u.vmx.ProcCtls2.n.allowed0, fVal, fZap));
3949 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
3950 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3951 }
3952
3953 /* Commit it to the VMCS and update our cache. */
3954 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, fVal);
3955 AssertRC(rc);
3956 pVmcsInfo->u32ProcCtls2 = fVal;
3957
3958 return VINF_SUCCESS;
3959}
3960
3961
3962/**
3963 * Sets up processor-based VM-execution controls in the VMCS.
3964 *
3965 * @returns VBox status code.
3966 * @param pVCpu The cross context virtual CPU structure.
3967 * @param pVmcsInfo The VMCS info. object.
3968 */
3969static int hmR0VmxSetupVmcsProcCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3970{
3971 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3972 uint32_t fVal = g_HmMsrs.u.vmx.ProcCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
3973 uint32_t const fZap = g_HmMsrs.u.vmx.ProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3974
3975 fVal |= VMX_PROC_CTLS_HLT_EXIT /* HLT causes a VM-exit. */
3976 | VMX_PROC_CTLS_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
3977 | VMX_PROC_CTLS_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
3978 | VMX_PROC_CTLS_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
3979 | VMX_PROC_CTLS_RDPMC_EXIT /* RDPMC causes a VM-exit. */
3980 | VMX_PROC_CTLS_MONITOR_EXIT /* MONITOR causes a VM-exit. */
3981 | VMX_PROC_CTLS_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
3982
3983 /* We toggle VMX_PROC_CTLS_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
3984 if ( !(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MOV_DR_EXIT)
3985 || (g_HmMsrs.u.vmx.ProcCtls.n.allowed0 & VMX_PROC_CTLS_MOV_DR_EXIT))
3986 {
3987 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
3988 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3989 }
3990
3991 /* Without nested paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
3992 if (!pVM->hmr0.s.fNestedPaging)
3993 {
3994 Assert(!pVM->hmr0.s.vmx.fUnrestrictedGuest);
3995 fVal |= VMX_PROC_CTLS_INVLPG_EXIT
3996 | VMX_PROC_CTLS_CR3_LOAD_EXIT
3997 | VMX_PROC_CTLS_CR3_STORE_EXIT;
3998 }
3999
4000 /* Use TPR shadowing if supported by the CPU. */
4001 if ( PDMHasApic(pVM)
4002 && (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW))
4003 {
4004 fVal |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
4005 /* CR8 writes cause a VM-exit based on TPR threshold. */
4006 Assert(!(fVal & VMX_PROC_CTLS_CR8_STORE_EXIT));
4007 Assert(!(fVal & VMX_PROC_CTLS_CR8_LOAD_EXIT));
4008 hmR0VmxSetupVmcsVirtApicAddr(pVmcsInfo);
4009 }
4010 else
4011 {
4012 /* Some 32-bit CPUs do not support CR8 load/store exiting as MOV CR8 is
4013 invalid on 32-bit Intel CPUs. Set this control only for 64-bit guests. */
4014 if (pVM->hmr0.s.fAllow64BitGuests)
4015 fVal |= VMX_PROC_CTLS_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
4016 | VMX_PROC_CTLS_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
4017 }
4018
4019 /* Use MSR-bitmaps if supported by the CPU. */
4020 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
4021 {
4022 fVal |= VMX_PROC_CTLS_USE_MSR_BITMAPS;
4023 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
4024 }
4025
4026 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
4027 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
4028 fVal |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
4029
4030 if ((fVal & fZap) != fVal)
4031 {
4032 LogRelFunc(("Invalid processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
4033 g_HmMsrs.u.vmx.ProcCtls.n.allowed0, fVal, fZap));
4034 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
4035 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4036 }
4037
4038 /* Commit it to the VMCS and update our cache. */
4039 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, fVal);
4040 AssertRC(rc);
4041 pVmcsInfo->u32ProcCtls = fVal;
4042
4043 /* Set up MSR permissions that don't change through the lifetime of the VM. */
4044 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
4045 hmR0VmxSetupVmcsMsrPermissions(pVCpu, pVmcsInfo);
4046
4047 /* Set up secondary processor-based VM-execution controls if the CPU supports it. */
4048 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
4049 return hmR0VmxSetupVmcsProcCtls2(pVCpu, pVmcsInfo);
4050
4051 /* Sanity check, should not really happen. */
4052 if (RT_LIKELY(!pVM->hmr0.s.vmx.fUnrestrictedGuest))
4053 { /* likely */ }
4054 else
4055 {
4056 pVCpu->hm.s.u32HMError = VMX_UFC_INVALID_UX_COMBO;
4057 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4058 }
4059
4060 /* Old CPUs without secondary processor-based VM-execution controls would end up here. */
4061 return VINF_SUCCESS;
4062}
4063
4064
4065/**
4066 * Sets up miscellaneous (everything other than Pin, Processor and secondary
4067 * Processor-based VM-execution) control fields in the VMCS.
4068 *
4069 * @returns VBox status code.
4070 * @param pVCpu The cross context virtual CPU structure.
4071 * @param pVmcsInfo The VMCS info. object.
4072 */
4073static int hmR0VmxSetupVmcsMiscCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
4074{
4075#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4076 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUseVmcsShadowing)
4077 {
4078 hmR0VmxSetupVmcsVmreadBitmapAddr(pVCpu);
4079 hmR0VmxSetupVmcsVmwriteBitmapAddr(pVCpu);
4080 }
4081#endif
4082
4083 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
4084 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
4085 AssertRC(rc);
4086
4087 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
4088 if (RT_SUCCESS(rc))
4089 {
4090 uint64_t const u64Cr0Mask = hmR0VmxGetFixedCr0Mask(pVCpu);
4091 uint64_t const u64Cr4Mask = hmR0VmxGetFixedCr4Mask(pVCpu);
4092
4093 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask); AssertRC(rc);
4094 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask); AssertRC(rc);
4095
4096 pVmcsInfo->u64Cr0Mask = u64Cr0Mask;
4097 pVmcsInfo->u64Cr4Mask = u64Cr4Mask;
4098
4099 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fLbr)
4100 {
4101 rc = VMXWriteVmcsNw(VMX_VMCS64_GUEST_DEBUGCTL_FULL, MSR_IA32_DEBUGCTL_LBR);
4102 AssertRC(rc);
4103 }
4104 return VINF_SUCCESS;
4105 }
4106 else
4107 LogRelFunc(("Failed to initialize VMCS auto-load/store MSR addresses. rc=%Rrc\n", rc));
4108 return rc;
4109}
4110
4111
4112/**
4113 * Sets up the initial exception bitmap in the VMCS based on static conditions.
4114 *
4115 * We shall setup those exception intercepts that don't change during the
4116 * lifetime of the VM here. The rest are done dynamically while loading the
4117 * guest state.
4118 *
4119 * @param pVCpu The cross context virtual CPU structure.
4120 * @param pVmcsInfo The VMCS info. object.
4121 */
4122static void hmR0VmxSetupVmcsXcptBitmap(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
4123{
4124 /*
4125 * The following exceptions are always intercepted:
4126 *
4127 * #AC - To prevent the guest from hanging the CPU and for dealing with
4128 * split-lock detecting host configs.
4129 * #DB - To maintain the DR6 state even when intercepting DRx reads/writes and
4130 * recursive #DBs can cause a CPU hang.
4131 * #PF - To sync our shadow page tables when nested-paging is not used.
4132 */
4133 bool const fNestedPaging = pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging;
4134 uint32_t const uXcptBitmap = RT_BIT(X86_XCPT_AC)
4135 | RT_BIT(X86_XCPT_DB)
4136 | (fNestedPaging ? 0 : RT_BIT(X86_XCPT_PF));
4137
4138 /* Commit it to the VMCS. */
4139 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
4140 AssertRC(rc);
4141
4142 /* Update our cache of the exception bitmap. */
4143 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
4144}
4145
4146
4147#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4148/**
4149 * Sets up the VMCS for executing a nested-guest using hardware-assisted VMX.
4150 *
4151 * @returns VBox status code.
4152 * @param pVmcsInfo The VMCS info. object.
4153 */
4154static int hmR0VmxSetupVmcsCtlsNested(PVMXVMCSINFO pVmcsInfo)
4155{
4156 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
4157 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
4158 AssertRC(rc);
4159
4160 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
4161 if (RT_SUCCESS(rc))
4162 {
4163 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
4164 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
4165
4166 /* Paranoia - We've not yet initialized these, they shall be done while merging the VMCS. */
4167 Assert(!pVmcsInfo->u64Cr0Mask);
4168 Assert(!pVmcsInfo->u64Cr4Mask);
4169 return VINF_SUCCESS;
4170 }
4171 LogRelFunc(("Failed to set up the VMCS link pointer in the nested-guest VMCS. rc=%Rrc\n", rc));
4172 return rc;
4173}
4174#endif
4175
4176
4177/**
4178 * Sets pfnStartVm to the best suited variant.
4179 *
4180 * This must be called whenever anything changes relative to the hmR0VmXStartVm
4181 * variant selection:
4182 * - pVCpu->hm.s.fLoadSaveGuestXcr0
4183 * - HM_WSF_IBPB_ENTRY in pVCpu->hmr0.s.fWorldSwitcher
4184 * - HM_WSF_IBPB_EXIT in pVCpu->hmr0.s.fWorldSwitcher
4185 * - Perhaps: CPUMIsGuestFPUStateActive() (windows only)
4186 * - Perhaps: CPUMCTX.fXStateMask (windows only)
4187 *
4188 * We currently ASSUME that neither HM_WSF_IBPB_ENTRY nor HM_WSF_IBPB_EXIT
4189 * cannot be changed at runtime.
4190 */
4191static void hmR0VmxUpdateStartVmFunction(PVMCPUCC pVCpu)
4192{
4193 static const struct CLANGWORKAROUND { PFNHMVMXSTARTVM pfn; } s_aHmR0VmxStartVmFunctions[] =
4194 {
4195 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4196 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4197 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4198 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4199 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4200 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4201 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4202 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4203 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4204 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4205 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4206 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4207 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4208 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4209 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4210 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4211 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4212 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4213 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4214 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4215 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4216 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4217 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4218 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4219 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4220 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4221 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4222 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4223 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4224 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4225 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4226 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4227 };
4228 uintptr_t const idx = (pVCpu->hmr0.s.fLoadSaveGuestXcr0 ? 1 : 0)
4229 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_IBPB_ENTRY ? 2 : 0)
4230 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_L1D_ENTRY ? 4 : 0)
4231 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_MDS_ENTRY ? 8 : 0)
4232 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_IBPB_EXIT ? 16 : 0);
4233 PFNHMVMXSTARTVM const pfnStartVm = s_aHmR0VmxStartVmFunctions[idx].pfn;
4234 if (pVCpu->hmr0.s.vmx.pfnStartVm != pfnStartVm)
4235 pVCpu->hmr0.s.vmx.pfnStartVm = pfnStartVm;
4236}
4237
4238
4239/**
4240 * Selector FNHMSVMVMRUN implementation.
4241 */
4242static DECLCALLBACK(int) hmR0VmxStartVmSelector(PVMXVMCSINFO pVmcsInfo, PVMCPUCC pVCpu, bool fResume)
4243{
4244 hmR0VmxUpdateStartVmFunction(pVCpu);
4245 return pVCpu->hmr0.s.vmx.pfnStartVm(pVmcsInfo, pVCpu, fResume);
4246}
4247
4248
4249/**
4250 * Sets up the VMCS for executing a guest (or nested-guest) using hardware-assisted
4251 * VMX.
4252 *
4253 * @returns VBox status code.
4254 * @param pVCpu The cross context virtual CPU structure.
4255 * @param pVmcsInfo The VMCS info. object.
4256 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
4257 */
4258static int hmR0VmxSetupVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
4259{
4260 Assert(pVmcsInfo->pvVmcs);
4261 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4262
4263 /* Set the CPU specified revision identifier at the beginning of the VMCS structure. */
4264 *(uint32_t *)pVmcsInfo->pvVmcs = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID);
4265 const char * const pszVmcs = fIsNstGstVmcs ? "nested-guest VMCS" : "guest VMCS";
4266
4267 LogFlowFunc(("\n"));
4268
4269 /*
4270 * Initialize the VMCS using VMCLEAR before loading the VMCS.
4271 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
4272 */
4273 int rc = hmR0VmxClearVmcs(pVmcsInfo);
4274 if (RT_SUCCESS(rc))
4275 {
4276 rc = hmR0VmxLoadVmcs(pVmcsInfo);
4277 if (RT_SUCCESS(rc))
4278 {
4279 /*
4280 * Initialize the hardware-assisted VMX execution handler for guest and nested-guest VMCS.
4281 * The host is always 64-bit since we no longer support 32-bit hosts.
4282 * Currently we have just a single handler for all guest modes as well, see @bugref{6208#c73}.
4283 */
4284 if (!fIsNstGstVmcs)
4285 {
4286 rc = hmR0VmxSetupVmcsPinCtls(pVCpu, pVmcsInfo);
4287 if (RT_SUCCESS(rc))
4288 {
4289 rc = hmR0VmxSetupVmcsProcCtls(pVCpu, pVmcsInfo);
4290 if (RT_SUCCESS(rc))
4291 {
4292 rc = hmR0VmxSetupVmcsMiscCtls(pVCpu, pVmcsInfo);
4293 if (RT_SUCCESS(rc))
4294 {
4295 hmR0VmxSetupVmcsXcptBitmap(pVCpu, pVmcsInfo);
4296#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4297 /*
4298 * If a shadow VMCS is allocated for the VMCS info. object, initialize the
4299 * VMCS revision ID and shadow VMCS indicator bit. Also, clear the VMCS
4300 * making it fit for use when VMCS shadowing is later enabled.
4301 */
4302 if (pVmcsInfo->pvShadowVmcs)
4303 {
4304 VMXVMCSREVID VmcsRevId;
4305 VmcsRevId.u = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID);
4306 VmcsRevId.n.fIsShadowVmcs = 1;
4307 *(uint32_t *)pVmcsInfo->pvShadowVmcs = VmcsRevId.u;
4308 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
4309 if (RT_SUCCESS(rc))
4310 { /* likely */ }
4311 else
4312 LogRelFunc(("Failed to initialize shadow VMCS. rc=%Rrc\n", rc));
4313 }
4314#endif
4315 }
4316 else
4317 LogRelFunc(("Failed to setup miscellaneous controls. rc=%Rrc\n", rc));
4318 }
4319 else
4320 LogRelFunc(("Failed to setup processor-based VM-execution controls. rc=%Rrc\n", rc));
4321 }
4322 else
4323 LogRelFunc(("Failed to setup pin-based controls. rc=%Rrc\n", rc));
4324 }
4325 else
4326 {
4327#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4328 rc = hmR0VmxSetupVmcsCtlsNested(pVmcsInfo);
4329 if (RT_SUCCESS(rc))
4330 { /* likely */ }
4331 else
4332 LogRelFunc(("Failed to initialize nested-guest VMCS. rc=%Rrc\n", rc));
4333#else
4334 AssertFailed();
4335#endif
4336 }
4337 }
4338 else
4339 LogRelFunc(("Failed to load the %s. rc=%Rrc\n", rc, pszVmcs));
4340 }
4341 else
4342 LogRelFunc(("Failed to clear the %s. rc=%Rrc\n", rc, pszVmcs));
4343
4344 /* Sync any CPU internal VMCS data back into our VMCS in memory. */
4345 if (RT_SUCCESS(rc))
4346 {
4347 rc = hmR0VmxClearVmcs(pVmcsInfo);
4348 if (RT_SUCCESS(rc))
4349 { /* likely */ }
4350 else
4351 LogRelFunc(("Failed to clear the %s post setup. rc=%Rrc\n", rc, pszVmcs));
4352 }
4353
4354 /*
4355 * Update the last-error record both for failures and success, so we
4356 * can propagate the status code back to ring-3 for diagnostics.
4357 */
4358 hmR0VmxUpdateErrorRecord(pVCpu, rc);
4359 NOREF(pszVmcs);
4360 return rc;
4361}
4362
4363
4364/**
4365 * Does global VT-x initialization (called during module initialization).
4366 *
4367 * @returns VBox status code.
4368 */
4369VMMR0DECL(int) VMXR0GlobalInit(void)
4370{
4371#ifdef HMVMX_USE_FUNCTION_TABLE
4372 AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(g_aVMExitHandlers));
4373# ifdef VBOX_STRICT
4374 for (unsigned i = 0; i < RT_ELEMENTS(g_aVMExitHandlers); i++)
4375 Assert(g_aVMExitHandlers[i].pfn);
4376# endif
4377#endif
4378 return VINF_SUCCESS;
4379}
4380
4381
4382/**
4383 * Does global VT-x termination (called during module termination).
4384 */
4385VMMR0DECL(void) VMXR0GlobalTerm()
4386{
4387 /* Nothing to do currently. */
4388}
4389
4390
4391/**
4392 * Sets up and activates VT-x on the current CPU.
4393 *
4394 * @returns VBox status code.
4395 * @param pHostCpu The HM physical-CPU structure.
4396 * @param pVM The cross context VM structure. Can be
4397 * NULL after a host resume operation.
4398 * @param pvCpuPage Pointer to the VMXON region (can be NULL if @a
4399 * fEnabledByHost is @c true).
4400 * @param HCPhysCpuPage Physical address of the VMXON region (can be 0 if
4401 * @a fEnabledByHost is @c true).
4402 * @param fEnabledByHost Set if SUPR0EnableVTx() or similar was used to
4403 * enable VT-x on the host.
4404 * @param pHwvirtMsrs Pointer to the hardware-virtualization MSRs.
4405 */
4406VMMR0DECL(int) VMXR0EnableCpu(PHMPHYSCPU pHostCpu, PVMCC pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost,
4407 PCSUPHWVIRTMSRS pHwvirtMsrs)
4408{
4409 AssertPtr(pHostCpu);
4410 AssertPtr(pHwvirtMsrs);
4411 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4412
4413 /* Enable VT-x if it's not already enabled by the host. */
4414 if (!fEnabledByHost)
4415 {
4416 int rc = hmR0VmxEnterRootMode(pHostCpu, pVM, HCPhysCpuPage, pvCpuPage);
4417 if (RT_FAILURE(rc))
4418 return rc;
4419 }
4420
4421 /*
4422 * Flush all EPT tagged-TLB entries (in case VirtualBox or any other hypervisor have been
4423 * using EPTPs) so we don't retain any stale guest-physical mappings which won't get
4424 * invalidated when flushing by VPID.
4425 */
4426 if (pHwvirtMsrs->u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
4427 {
4428 hmR0VmxFlushEpt(NULL /* pVCpu */, NULL /* pVmcsInfo */, VMXTLBFLUSHEPT_ALL_CONTEXTS);
4429 pHostCpu->fFlushAsidBeforeUse = false;
4430 }
4431 else
4432 pHostCpu->fFlushAsidBeforeUse = true;
4433
4434 /* Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}. */
4435 ++pHostCpu->cTlbFlushes;
4436
4437 return VINF_SUCCESS;
4438}
4439
4440
4441/**
4442 * Deactivates VT-x on the current CPU.
4443 *
4444 * @returns VBox status code.
4445 * @param pHostCpu The HM physical-CPU structure.
4446 * @param pvCpuPage Pointer to the VMXON region.
4447 * @param HCPhysCpuPage Physical address of the VMXON region.
4448 *
4449 * @remarks This function should never be called when SUPR0EnableVTx() or
4450 * similar was used to enable VT-x on the host.
4451 */
4452VMMR0DECL(int) VMXR0DisableCpu(PHMPHYSCPU pHostCpu, void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
4453{
4454 RT_NOREF2(pvCpuPage, HCPhysCpuPage);
4455
4456 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4457 return hmR0VmxLeaveRootMode(pHostCpu);
4458}
4459
4460
4461/**
4462 * Does per-VM VT-x initialization.
4463 *
4464 * @returns VBox status code.
4465 * @param pVM The cross context VM structure.
4466 */
4467VMMR0DECL(int) VMXR0InitVM(PVMCC pVM)
4468{
4469 AssertPtr(pVM);
4470 LogFlowFunc(("pVM=%p\n", pVM));
4471
4472 hmR0VmxStructsInit(pVM);
4473 int rc = hmR0VmxStructsAlloc(pVM);
4474 if (RT_FAILURE(rc))
4475 {
4476 LogRelFunc(("Failed to allocated VMX structures. rc=%Rrc\n", rc));
4477 return rc;
4478 }
4479
4480 /* Setup the crash dump page. */
4481#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4482 strcpy((char *)pVM->hmr0.s.vmx.pbScratch, "SCRATCH Magic");
4483 *(uint64_t *)(pVM->hmr0.s.vmx.pbScratch + 16) = UINT64_C(0xdeadbeefdeadbeef);
4484#endif
4485 return VINF_SUCCESS;
4486}
4487
4488
4489/**
4490 * Does per-VM VT-x termination.
4491 *
4492 * @returns VBox status code.
4493 * @param pVM The cross context VM structure.
4494 */
4495VMMR0DECL(int) VMXR0TermVM(PVMCC pVM)
4496{
4497 AssertPtr(pVM);
4498 LogFlowFunc(("pVM=%p\n", pVM));
4499
4500#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4501 if (pVM->hmr0.s.vmx.pbScratch)
4502 RT_BZERO(pVM->hmr0.s.vmx.pbScratch, X86_PAGE_4K_SIZE);
4503#endif
4504 hmR0VmxStructsFree(pVM);
4505 return VINF_SUCCESS;
4506}
4507
4508
4509/**
4510 * Sets up the VM for execution using hardware-assisted VMX.
4511 * This function is only called once per-VM during initialization.
4512 *
4513 * @returns VBox status code.
4514 * @param pVM The cross context VM structure.
4515 */
4516VMMR0DECL(int) VMXR0SetupVM(PVMCC pVM)
4517{
4518 AssertPtr(pVM);
4519 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4520
4521 LogFlowFunc(("pVM=%p\n", pVM));
4522
4523 /*
4524 * At least verify if VMX is enabled, since we can't check if we're in VMX root mode or not
4525 * without causing a #GP.
4526 */
4527 RTCCUINTREG const uHostCr4 = ASMGetCR4();
4528 if (RT_LIKELY(uHostCr4 & X86_CR4_VMXE))
4529 { /* likely */ }
4530 else
4531 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
4532
4533 /*
4534 * Check that nested paging is supported if enabled and copy over the flag to the
4535 * ring-0 only structure.
4536 */
4537 bool const fNestedPaging = pVM->hm.s.fNestedPagingCfg;
4538 AssertReturn( !fNestedPaging
4539 || (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_EPT), /** @todo use a ring-0 copy of ProcCtls2.n.allowed1 */
4540 VERR_INCOMPATIBLE_CONFIG);
4541 pVM->hmr0.s.fNestedPaging = fNestedPaging;
4542 pVM->hmr0.s.fAllow64BitGuests = pVM->hm.s.fAllow64BitGuestsCfg;
4543
4544 /*
4545 * Without unrestricted guest execution, pRealModeTSS and pNonPagingModeEPTPageTable *must*
4546 * always be allocated. We no longer support the highly unlikely case of unrestricted guest
4547 * without pRealModeTSS, see hmR3InitFinalizeR0Intel().
4548 */
4549 bool const fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuestCfg;
4550 AssertReturn( !fUnrestrictedGuest
4551 || ( (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST)
4552 && fNestedPaging),
4553 VERR_INCOMPATIBLE_CONFIG);
4554 if ( !fUnrestrictedGuest
4555 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
4556 || !pVM->hm.s.vmx.pRealModeTSS))
4557 {
4558 LogRelFunc(("Invalid real-on-v86 state.\n"));
4559 return VERR_INTERNAL_ERROR;
4560 }
4561 pVM->hmr0.s.vmx.fUnrestrictedGuest = fUnrestrictedGuest;
4562
4563 /* Initialize these always, see hmR3InitFinalizeR0().*/
4564 pVM->hm.s.ForR3.vmx.enmTlbFlushEpt = pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NONE;
4565 pVM->hm.s.ForR3.vmx.enmTlbFlushVpid = pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NONE;
4566
4567 /* Setup the tagged-TLB flush handlers. */
4568 int rc = hmR0VmxSetupTaggedTlb(pVM);
4569 if (RT_FAILURE(rc))
4570 {
4571 LogRelFunc(("Failed to setup tagged TLB. rc=%Rrc\n", rc));
4572 return rc;
4573 }
4574
4575 /* Determine LBR capabilities. */
4576 pVM->hmr0.s.vmx.fLbr = pVM->hm.s.vmx.fLbrCfg;
4577 if (pVM->hmr0.s.vmx.fLbr)
4578 {
4579 rc = hmR0VmxSetupLbrMsrRange(pVM);
4580 if (RT_FAILURE(rc))
4581 {
4582 LogRelFunc(("Failed to setup LBR MSR range. rc=%Rrc\n", rc));
4583 return rc;
4584 }
4585 }
4586
4587#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4588 /* Setup the shadow VMCS fields array and VMREAD/VMWRITE bitmaps. */
4589 if (pVM->hmr0.s.vmx.fUseVmcsShadowing)
4590 {
4591 rc = hmR0VmxSetupShadowVmcsFieldsArrays(pVM);
4592 if (RT_SUCCESS(rc))
4593 hmR0VmxSetupVmreadVmwriteBitmaps(pVM);
4594 else
4595 {
4596 LogRelFunc(("Failed to setup shadow VMCS fields arrays. rc=%Rrc\n", rc));
4597 return rc;
4598 }
4599 }
4600#endif
4601
4602 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
4603 {
4604 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
4605 Log4Func(("pVCpu=%p idCpu=%RU32\n", pVCpu, pVCpu->idCpu));
4606
4607 pVCpu->hmr0.s.vmx.pfnStartVm = hmR0VmxStartVmSelector;
4608
4609 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
4610 if (RT_SUCCESS(rc))
4611 {
4612#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4613 if (pVM->cpum.ro.GuestFeatures.fVmx)
4614 {
4615 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
4616 if (RT_SUCCESS(rc))
4617 { /* likely */ }
4618 else
4619 {
4620 LogRelFunc(("Nested-guest VMCS setup failed. rc=%Rrc\n", rc));
4621 return rc;
4622 }
4623 }
4624#endif
4625 }
4626 else
4627 {
4628 LogRelFunc(("VMCS setup failed. rc=%Rrc\n", rc));
4629 return rc;
4630 }
4631 }
4632
4633 return VINF_SUCCESS;
4634}
4635
4636
4637/**
4638 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
4639 * the VMCS.
4640 * @returns CR4 for passing along to hmR0VmxExportHostSegmentRegs.
4641 */
4642static uint64_t hmR0VmxExportHostControlRegs(void)
4643{
4644 int rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR0, ASMGetCR0()); AssertRC(rc);
4645 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR3, ASMGetCR3()); AssertRC(rc);
4646 uint64_t uHostCr4 = ASMGetCR4();
4647 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR4, uHostCr4); AssertRC(rc);
4648 return uHostCr4;
4649}
4650
4651
4652/**
4653 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
4654 * the host-state area in the VMCS.
4655 *
4656 * @returns VBox status code.
4657 * @param pVCpu The cross context virtual CPU structure.
4658 * @param uHostCr4 The host CR4 value.
4659 */
4660static int hmR0VmxExportHostSegmentRegs(PVMCPUCC pVCpu, uint64_t uHostCr4)
4661{
4662 /*
4663 * If we've executed guest code using hardware-assisted VMX, the host-state bits
4664 * will be messed up. We should -not- save the messed up state without restoring
4665 * the original host-state, see @bugref{7240}.
4666 *
4667 * This apparently can happen (most likely the FPU changes), deal with it rather than
4668 * asserting. Was observed booting Solaris 10u10 32-bit guest.
4669 */
4670 if (pVCpu->hmr0.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED)
4671 {
4672 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hmr0.s.vmx.fRestoreHostFlags,
4673 pVCpu->idCpu));
4674 VMXRestoreHostState(pVCpu->hmr0.s.vmx.fRestoreHostFlags, &pVCpu->hmr0.s.vmx.RestoreHost);
4675 pVCpu->hmr0.s.vmx.fRestoreHostFlags = 0;
4676 }
4677
4678 /*
4679 * Get all the host info.
4680 * ASSUME it is safe to use rdfsbase and friends if the CR4.FSGSBASE bit is set
4681 * without also checking the cpuid bit.
4682 */
4683 uint32_t fRestoreHostFlags;
4684#if RT_INLINE_ASM_EXTERNAL
4685 if (uHostCr4 & X86_CR4_FSGSBASE)
4686 {
4687 hmR0VmxExportHostSegmentRegsAsmHlp(&pVCpu->hmr0.s.vmx.RestoreHost, true /*fHaveFsGsBase*/);
4688 fRestoreHostFlags = VMX_RESTORE_HOST_CAN_USE_WRFSBASE_AND_WRGSBASE;
4689 }
4690 else
4691 {
4692 hmR0VmxExportHostSegmentRegsAsmHlp(&pVCpu->hmr0.s.vmx.RestoreHost, false /*fHaveFsGsBase*/);
4693 fRestoreHostFlags = 0;
4694 }
4695 RTSEL uSelES = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelES;
4696 RTSEL uSelDS = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelDS;
4697 RTSEL uSelFS = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelFS;
4698 RTSEL uSelGS = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelGS;
4699#else
4700 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR = ASMGetTR();
4701 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS = ASMGetSS();
4702 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS = ASMGetCS();
4703 ASMGetGDTR((PRTGDTR)&pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr);
4704 ASMGetIDTR((PRTIDTR)&pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr);
4705 if (uHostCr4 & X86_CR4_FSGSBASE)
4706 {
4707 pVCpu->hmr0.s.vmx.RestoreHost.uHostFSBase = ASMGetFSBase();
4708 pVCpu->hmr0.s.vmx.RestoreHost.uHostGSBase = ASMGetGSBase();
4709 fRestoreHostFlags = VMX_RESTORE_HOST_CAN_USE_WRFSBASE_AND_WRGSBASE;
4710 }
4711 else
4712 {
4713 pVCpu->hmr0.s.vmx.RestoreHost.uHostFSBase = ASMRdMsr(MSR_K8_FS_BASE);
4714 pVCpu->hmr0.s.vmx.RestoreHost.uHostGSBase = ASMRdMsr(MSR_K8_GS_BASE);
4715 fRestoreHostFlags = 0;
4716 }
4717 RTSEL uSelES, uSelDS, uSelFS, uSelGS;
4718 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelDS = uSelDS = ASMGetDS();
4719 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelES = uSelES = ASMGetES();
4720 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelFS = uSelFS = ASMGetFS();
4721 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelGS = uSelGS = ASMGetGS();
4722#endif
4723
4724 /*
4725 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to
4726 * gain VM-entry and restore them before we get preempted.
4727 *
4728 * See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
4729 */
4730 RTSEL const uSelAll = uSelFS | uSelGS | uSelES | uSelDS;
4731 if (uSelAll & (X86_SEL_RPL | X86_SEL_LDT))
4732 {
4733 if (!(uSelAll & X86_SEL_LDT))
4734 {
4735#define VMXLOCAL_ADJUST_HOST_SEG(a_Seg, a_uVmcsVar) \
4736 do { \
4737 (a_uVmcsVar) = pVCpu->hmr0.s.vmx.RestoreHost.uHostSel##a_Seg; \
4738 if ((a_uVmcsVar) & X86_SEL_RPL) \
4739 { \
4740 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4741 (a_uVmcsVar) = 0; \
4742 } \
4743 } while (0)
4744 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
4745 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
4746 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
4747 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
4748#undef VMXLOCAL_ADJUST_HOST_SEG
4749 }
4750 else
4751 {
4752#define VMXLOCAL_ADJUST_HOST_SEG(a_Seg, a_uVmcsVar) \
4753 do { \
4754 (a_uVmcsVar) = pVCpu->hmr0.s.vmx.RestoreHost.uHostSel##a_Seg; \
4755 if ((a_uVmcsVar) & (X86_SEL_RPL | X86_SEL_LDT)) \
4756 { \
4757 if (!((a_uVmcsVar) & X86_SEL_LDT)) \
4758 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4759 else \
4760 { \
4761 uint32_t const fAttr = ASMGetSegAttr(a_uVmcsVar); \
4762 if ((fAttr & X86_DESC_P) && fAttr != UINT32_MAX) \
4763 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4764 } \
4765 (a_uVmcsVar) = 0; \
4766 } \
4767 } while (0)
4768 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
4769 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
4770 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
4771 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
4772#undef VMXLOCAL_ADJUST_HOST_SEG
4773 }
4774 }
4775
4776 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
4777 Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR & X86_SEL_RPL)); Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR & X86_SEL_LDT)); Assert(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR);
4778 Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS & X86_SEL_RPL)); Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS & X86_SEL_LDT)); Assert(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS);
4779 Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS & X86_SEL_RPL)); Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS & X86_SEL_LDT));
4780 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
4781 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
4782 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
4783 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
4784
4785 /*
4786 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps
4787 * them to the maximum limit (0xffff) on every VM-exit.
4788 */
4789 if (pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb != 0xffff)
4790 fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
4791
4792 /*
4793 * IDT limit is effectively capped at 0xfff. (See Intel spec. 6.14.1 "64-Bit Mode IDT" and
4794 * Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit
4795 * as 0xfff, VT-x bloating the limit to 0xffff shouldn't cause any different CPU behavior.
4796 * However, several hosts either insists on 0xfff being the limit (Windows Patch Guard) or
4797 * uses the limit for other purposes (darwin puts the CPU ID in there but botches sidt
4798 * alignment in at least one consumer). So, we're only allowing the IDTR.LIMIT to be left
4799 * at 0xffff on hosts where we are sure it won't cause trouble.
4800 */
4801#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
4802 if (pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr.cb < 0x0fff)
4803#else
4804 if (pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr.cb != 0xffff)
4805#endif
4806 fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
4807
4808 /*
4809 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI
4810 * and RPL bits is effectively what the CPU does for "scaling by 8". TI is always 0 and
4811 * RPL should be too in most cases.
4812 */
4813 RTSEL const uSelTR = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR;
4814 AssertMsgReturn((uSelTR | X86_SEL_RPL_LDT) <= pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb,
4815 ("TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb),
4816 VERR_VMX_INVALID_HOST_STATE);
4817
4818 PCX86DESCHC pDesc = (PCX86DESCHC)(pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.uAddr + (uSelTR & X86_SEL_MASK));
4819 uintptr_t const uTRBase = X86DESC64_BASE(pDesc);
4820
4821 /*
4822 * VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on
4823 * all VM-exits. The type is the same for 64-bit busy TSS[1]. The limit needs manual
4824 * restoration if the host has something else. Task switching is not supported in 64-bit
4825 * mode[2], but the limit still matters as IOPM is supported in 64-bit mode. Restoring the
4826 * limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
4827 *
4828 * [1] See Intel spec. 3.5 "System Descriptor Types".
4829 * [2] See Intel spec. 7.2.3 "TSS Descriptor in 64-bit mode".
4830 */
4831 Assert(pDesc->System.u4Type == 11);
4832 if ( pDesc->System.u16LimitLow != 0x67
4833 || pDesc->System.u4LimitHigh)
4834 {
4835 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_TR;
4836
4837 /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */
4838 if (g_fHmHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY)
4839 fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY;
4840 if (g_fHmHostKernelFeatures & SUPKERNELFEATURES_GDT_NEED_WRITABLE)
4841 {
4842 /* The GDT is read-only but the writable GDT is available. */
4843 fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_NEED_WRITABLE;
4844 pVCpu->hmr0.s.vmx.RestoreHost.HostGdtrRw.cb = pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb;
4845 int rc = SUPR0GetCurrentGdtRw(&pVCpu->hmr0.s.vmx.RestoreHost.HostGdtrRw.uAddr);
4846 AssertRCReturn(rc, rc);
4847 }
4848 }
4849
4850 pVCpu->hmr0.s.vmx.fRestoreHostFlags = fRestoreHostFlags;
4851
4852 /*
4853 * Do all the VMCS updates in one block to assist nested virtualization.
4854 */
4855 int rc;
4856 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_CS_SEL, pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS); AssertRC(rc);
4857 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_SS_SEL, pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS); AssertRC(rc);
4858 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_DS_SEL, uSelDS); AssertRC(rc);
4859 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_ES_SEL, uSelES); AssertRC(rc);
4860 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_FS_SEL, uSelFS); AssertRC(rc);
4861 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_GS_SEL, uSelGS); AssertRC(rc);
4862 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_TR_SEL, pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR); AssertRC(rc);
4863 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GDTR_BASE, pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.uAddr); AssertRC(rc);
4864 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_IDTR_BASE, pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr.uAddr); AssertRC(rc);
4865 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_TR_BASE, uTRBase); AssertRC(rc);
4866 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_FS_BASE, pVCpu->hmr0.s.vmx.RestoreHost.uHostFSBase); AssertRC(rc);
4867 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GS_BASE, pVCpu->hmr0.s.vmx.RestoreHost.uHostGSBase); AssertRC(rc);
4868
4869 return VINF_SUCCESS;
4870}
4871
4872
4873/**
4874 * Exports certain host MSRs in the VM-exit MSR-load area and some in the
4875 * host-state area of the VMCS.
4876 *
4877 * These MSRs will be automatically restored on the host after every successful
4878 * VM-exit.
4879 *
4880 * @param pVCpu The cross context virtual CPU structure.
4881 *
4882 * @remarks No-long-jump zone!!!
4883 */
4884static void hmR0VmxExportHostMsrs(PVMCPUCC pVCpu)
4885{
4886 AssertPtr(pVCpu);
4887
4888 /*
4889 * Save MSRs that we restore lazily (due to preemption or transition to ring-3)
4890 * rather than swapping them on every VM-entry.
4891 */
4892 hmR0VmxLazySaveHostMsrs(pVCpu);
4893
4894 /*
4895 * Host Sysenter MSRs.
4896 */
4897 int rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS)); AssertRC(rc);
4898 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP)); AssertRC(rc);
4899 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP)); AssertRC(rc);
4900
4901 /*
4902 * Host EFER MSR.
4903 *
4904 * If the CPU supports the newer VMCS controls for managing EFER, use it. Otherwise it's
4905 * done as part of auto-load/store MSR area in the VMCS, see hmR0VmxExportGuestMsrs().
4906 */
4907 if (g_fHmVmxSupportsVmcsEfer)
4908 {
4909 rc = VMXWriteVmcs64(VMX_VMCS64_HOST_EFER_FULL, g_uHmVmxHostMsrEfer);
4910 AssertRC(rc);
4911 }
4912
4913 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT also see
4914 * hmR0VmxExportGuestEntryExitCtls(). */
4915}
4916
4917
4918/**
4919 * Figures out if we need to swap the EFER MSR which is particularly expensive.
4920 *
4921 * We check all relevant bits. For now, that's everything besides LMA/LME, as
4922 * these two bits are handled by VM-entry, see hmR0VMxExportGuestEntryExitCtls().
4923 *
4924 * @returns true if we need to load guest EFER, false otherwise.
4925 * @param pVCpu The cross context virtual CPU structure.
4926 * @param pVmxTransient The VMX-transient structure.
4927 *
4928 * @remarks Requires EFER, CR4.
4929 * @remarks No-long-jump zone!!!
4930 */
4931static bool hmR0VmxShouldSwapEferMsr(PCVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
4932{
4933#ifdef HMVMX_ALWAYS_SWAP_EFER
4934 RT_NOREF2(pVCpu, pVmxTransient);
4935 return true;
4936#else
4937 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4938 uint64_t const u64HostEfer = g_uHmVmxHostMsrEfer;
4939 uint64_t const u64GuestEfer = pCtx->msrEFER;
4940
4941# ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4942 /*
4943 * For nested-guests, we shall honor swapping the EFER MSR when requested by
4944 * the nested-guest.
4945 */
4946 if ( pVmxTransient->fIsNestedGuest
4947 && ( CPUMIsGuestVmxEntryCtlsSet(pCtx, VMX_ENTRY_CTLS_LOAD_EFER_MSR)
4948 || CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_SAVE_EFER_MSR)
4949 || CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_LOAD_EFER_MSR)))
4950 return true;
4951# else
4952 RT_NOREF(pVmxTransient);
4953#endif
4954
4955 /*
4956 * For 64-bit guests, if EFER.SCE bit differs, we need to swap the EFER MSR
4957 * to ensure that the guest's SYSCALL behaviour isn't broken, see @bugref{7386}.
4958 */
4959 if ( CPUMIsGuestInLongModeEx(pCtx)
4960 && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
4961 return true;
4962
4963 /*
4964 * If the guest uses PAE and EFER.NXE bit differs, we need to swap the EFER MSR
4965 * as it affects guest paging. 64-bit paging implies CR4.PAE as well.
4966 *
4967 * See Intel spec. 4.5 "IA-32e Paging".
4968 * See Intel spec. 4.1.1 "Three Paging Modes".
4969 *
4970 * Verify that we always intercept CR4.PAE and CR0.PG bits, so we don't need to
4971 * import CR4 and CR0 from the VMCS here as those bits are always up to date.
4972 */
4973 Assert(hmR0VmxGetFixedCr4Mask(pVCpu) & X86_CR4_PAE);
4974 Assert(hmR0VmxGetFixedCr0Mask(pVCpu) & X86_CR0_PG);
4975 if ( (pCtx->cr4 & X86_CR4_PAE)
4976 && (pCtx->cr0 & X86_CR0_PG))
4977 {
4978 /*
4979 * If nested paging is not used, verify that the guest paging mode matches the
4980 * shadow paging mode which is/will be placed in the VMCS (which is what will
4981 * actually be used while executing the guest and not the CR4 shadow value).
4982 */
4983 AssertMsg( pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging
4984 || pVCpu->hm.s.enmShadowMode == PGMMODE_PAE
4985 || pVCpu->hm.s.enmShadowMode == PGMMODE_PAE_NX
4986 || pVCpu->hm.s.enmShadowMode == PGMMODE_AMD64
4987 || pVCpu->hm.s.enmShadowMode == PGMMODE_AMD64_NX,
4988 ("enmShadowMode=%u\n", pVCpu->hm.s.enmShadowMode));
4989 if ((u64GuestEfer & MSR_K6_EFER_NXE) != (u64HostEfer & MSR_K6_EFER_NXE))
4990 {
4991 /* Verify that the host is NX capable. */
4992 Assert(pVCpu->CTX_SUFF(pVM)->cpum.ro.HostFeatures.fNoExecute);
4993 return true;
4994 }
4995 }
4996
4997 return false;
4998#endif
4999}
5000
5001
5002/**
5003 * Exports the guest state with appropriate VM-entry and VM-exit controls in the
5004 * VMCS.
5005 *
5006 * This is typically required when the guest changes paging mode.
5007 *
5008 * @returns VBox status code.
5009 * @param pVCpu The cross context virtual CPU structure.
5010 * @param pVmxTransient The VMX-transient structure.
5011 *
5012 * @remarks Requires EFER.
5013 * @remarks No-long-jump zone!!!
5014 */
5015static int hmR0VmxExportGuestEntryExitCtls(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5016{
5017 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS)
5018 {
5019 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5020 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5021
5022 /*
5023 * VM-entry controls.
5024 */
5025 {
5026 uint32_t fVal = g_HmMsrs.u.vmx.EntryCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
5027 uint32_t const fZap = g_HmMsrs.u.vmx.EntryCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
5028
5029 /*
5030 * Load the guest debug controls (DR7 and IA32_DEBUGCTL MSR) on VM-entry.
5031 * The first VT-x capable CPUs only supported the 1-setting of this bit.
5032 *
5033 * For nested-guests, this is a mandatory VM-entry control. It's also
5034 * required because we do not want to leak host bits to the nested-guest.
5035 */
5036 fVal |= VMX_ENTRY_CTLS_LOAD_DEBUG;
5037
5038 /*
5039 * Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry.
5040 *
5041 * For nested-guests, the "IA-32e mode guest" control we initialize with what is
5042 * required to get the nested-guest working with hardware-assisted VMX execution.
5043 * It depends on the nested-guest's IA32_EFER.LMA bit. Remember, a nested hypervisor
5044 * can skip intercepting changes to the EFER MSR. This is why it needs to be done
5045 * here rather than while merging the guest VMCS controls.
5046 */
5047 if (CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
5048 {
5049 Assert(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LME);
5050 fVal |= VMX_ENTRY_CTLS_IA32E_MODE_GUEST;
5051 }
5052 else
5053 Assert(!(fVal & VMX_ENTRY_CTLS_IA32E_MODE_GUEST));
5054
5055 /*
5056 * If the CPU supports the newer VMCS controls for managing guest/host EFER, use it.
5057 *
5058 * For nested-guests, we use the "load IA32_EFER" if the hardware supports it,
5059 * regardless of whether the nested-guest VMCS specifies it because we are free to
5060 * load whatever MSRs we require and we do not need to modify the guest visible copy
5061 * of the VM-entry MSR load area.
5062 */
5063 if ( g_fHmVmxSupportsVmcsEfer
5064 && hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
5065 fVal |= VMX_ENTRY_CTLS_LOAD_EFER_MSR;
5066 else
5067 Assert(!(fVal & VMX_ENTRY_CTLS_LOAD_EFER_MSR));
5068
5069 /*
5070 * The following should -not- be set (since we're not in SMM mode):
5071 * - VMX_ENTRY_CTLS_ENTRY_TO_SMM
5072 * - VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON
5073 */
5074
5075 /** @todo VMX_ENTRY_CTLS_LOAD_PERF_MSR,
5076 * VMX_ENTRY_CTLS_LOAD_PAT_MSR. */
5077
5078 if ((fVal & fZap) == fVal)
5079 { /* likely */ }
5080 else
5081 {
5082 Log4Func(("Invalid VM-entry controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
5083 g_HmMsrs.u.vmx.EntryCtls.n.allowed0, fVal, fZap));
5084 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_ENTRY;
5085 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
5086 }
5087
5088 /* Commit it to the VMCS. */
5089 if (pVmcsInfo->u32EntryCtls != fVal)
5090 {
5091 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, fVal);
5092 AssertRC(rc);
5093 pVmcsInfo->u32EntryCtls = fVal;
5094 }
5095 }
5096
5097 /*
5098 * VM-exit controls.
5099 */
5100 {
5101 uint32_t fVal = g_HmMsrs.u.vmx.ExitCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
5102 uint32_t const fZap = g_HmMsrs.u.vmx.ExitCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
5103
5104 /*
5105 * Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only
5106 * supported the 1-setting of this bit.
5107 *
5108 * For nested-guests, we set the "save debug controls" as the converse
5109 * "load debug controls" is mandatory for nested-guests anyway.
5110 */
5111 fVal |= VMX_EXIT_CTLS_SAVE_DEBUG;
5112
5113 /*
5114 * Set the host long mode active (EFER.LMA) bit (which Intel calls
5115 * "Host address-space size") if necessary. On VM-exit, VT-x sets both the
5116 * host EFER.LMA and EFER.LME bit to this value. See assertion in
5117 * hmR0VmxExportHostMsrs().
5118 *
5119 * For nested-guests, we always set this bit as we do not support 32-bit
5120 * hosts.
5121 */
5122 fVal |= VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE;
5123
5124 /*
5125 * If the VMCS EFER MSR fields are supported by the hardware, we use it.
5126 *
5127 * For nested-guests, we should use the "save IA32_EFER" control if we also
5128 * used the "load IA32_EFER" control while exporting VM-entry controls.
5129 */
5130 if ( g_fHmVmxSupportsVmcsEfer
5131 && hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
5132 {
5133 fVal |= VMX_EXIT_CTLS_SAVE_EFER_MSR
5134 | VMX_EXIT_CTLS_LOAD_EFER_MSR;
5135 }
5136
5137 /*
5138 * Enable saving of the VMX-preemption timer value on VM-exit.
5139 * For nested-guests, currently not exposed/used.
5140 */
5141 /** @todo r=bird: Measure performance hit because of this vs. always rewriting
5142 * the timer value. */
5143 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
5144 {
5145 Assert(g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER);
5146 fVal |= VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER;
5147 }
5148
5149 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
5150 Assert(!(fVal & VMX_EXIT_CTLS_ACK_EXT_INT));
5151
5152 /** @todo VMX_EXIT_CTLS_LOAD_PERF_MSR,
5153 * VMX_EXIT_CTLS_SAVE_PAT_MSR,
5154 * VMX_EXIT_CTLS_LOAD_PAT_MSR. */
5155
5156 if ((fVal & fZap) == fVal)
5157 { /* likely */ }
5158 else
5159 {
5160 Log4Func(("Invalid VM-exit controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%R#X32\n",
5161 g_HmMsrs.u.vmx.ExitCtls.n.allowed0, fVal, fZap));
5162 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_EXIT;
5163 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
5164 }
5165
5166 /* Commit it to the VMCS. */
5167 if (pVmcsInfo->u32ExitCtls != fVal)
5168 {
5169 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, fVal);
5170 AssertRC(rc);
5171 pVmcsInfo->u32ExitCtls = fVal;
5172 }
5173 }
5174
5175 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
5176 }
5177 return VINF_SUCCESS;
5178}
5179
5180
5181/**
5182 * Sets the TPR threshold in the VMCS.
5183 *
5184 * @param pVmcsInfo The VMCS info. object.
5185 * @param u32TprThreshold The TPR threshold (task-priority class only).
5186 */
5187DECLINLINE(void) hmR0VmxApicSetTprThreshold(PVMXVMCSINFO pVmcsInfo, uint32_t u32TprThreshold)
5188{
5189 Assert(!(u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)); /* Bits 31:4 MBZ. */
5190 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
5191 RT_NOREF(pVmcsInfo);
5192 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
5193 AssertRC(rc);
5194}
5195
5196
5197/**
5198 * Exports the guest APIC TPR state into the VMCS.
5199 *
5200 * @param pVCpu The cross context virtual CPU structure.
5201 * @param pVmxTransient The VMX-transient structure.
5202 *
5203 * @remarks No-long-jump zone!!!
5204 */
5205static void hmR0VmxExportGuestApicTpr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5206{
5207 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_APIC_TPR)
5208 {
5209 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
5210
5211 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5212 if (!pVmxTransient->fIsNestedGuest)
5213 {
5214 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
5215 && APICIsEnabled(pVCpu))
5216 {
5217 /*
5218 * Setup TPR shadowing.
5219 */
5220 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
5221 {
5222 bool fPendingIntr = false;
5223 uint8_t u8Tpr = 0;
5224 uint8_t u8PendingIntr = 0;
5225 int rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
5226 AssertRC(rc);
5227
5228 /*
5229 * If there are interrupts pending but masked by the TPR, instruct VT-x to
5230 * cause a TPR-below-threshold VM-exit when the guest lowers its TPR below the
5231 * priority of the pending interrupt so we can deliver the interrupt. If there
5232 * are no interrupts pending, set threshold to 0 to not cause any
5233 * TPR-below-threshold VM-exits.
5234 */
5235 uint32_t u32TprThreshold = 0;
5236 if (fPendingIntr)
5237 {
5238 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR
5239 (which is the Task-Priority Class). */
5240 const uint8_t u8PendingPriority = u8PendingIntr >> 4;
5241 const uint8_t u8TprPriority = u8Tpr >> 4;
5242 if (u8PendingPriority <= u8TprPriority)
5243 u32TprThreshold = u8PendingPriority;
5244 }
5245
5246 hmR0VmxApicSetTprThreshold(pVmcsInfo, u32TprThreshold);
5247 }
5248 }
5249 }
5250 /* else: the TPR threshold has already been updated while merging the nested-guest VMCS. */
5251 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
5252 }
5253}
5254
5255
5256/**
5257 * Gets the guest interruptibility-state and updates related force-flags.
5258 *
5259 * @returns Guest's interruptibility-state.
5260 * @param pVCpu The cross context virtual CPU structure.
5261 *
5262 * @remarks No-long-jump zone!!!
5263 */
5264static uint32_t hmR0VmxGetGuestIntrStateAndUpdateFFs(PVMCPUCC pVCpu)
5265{
5266 /*
5267 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
5268 */
5269 uint32_t fIntrState = 0;
5270 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
5271 {
5272 /* If inhibition is active, RIP and RFLAGS should've been imported from the VMCS already. */
5273 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
5274
5275 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5276 if (pCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
5277 {
5278 if (pCtx->eflags.Bits.u1IF)
5279 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
5280 else
5281 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS;
5282 }
5283 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
5284 {
5285 /*
5286 * We can clear the inhibit force flag as even if we go back to the recompiler
5287 * without executing guest code in VT-x, the flag's condition to be cleared is
5288 * met and thus the cleared state is correct.
5289 */
5290 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
5291 }
5292 }
5293
5294 /*
5295 * Check if we should inhibit NMI delivery.
5296 */
5297 if (CPUMIsGuestNmiBlocking(pVCpu))
5298 fIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
5299
5300 /*
5301 * Validate.
5302 */
5303#ifdef VBOX_STRICT
5304 /* We don't support block-by-SMI yet.*/
5305 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI));
5306
5307 /* Block-by-STI must not be set when interrupts are disabled. */
5308 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
5309 {
5310 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
5311 Assert(pVCpu->cpum.GstCtx.eflags.u & X86_EFL_IF);
5312 }
5313#endif
5314
5315 return fIntrState;
5316}
5317
5318
5319/**
5320 * Exports the exception intercepts required for guest execution in the VMCS.
5321 *
5322 * @param pVCpu The cross context virtual CPU structure.
5323 * @param pVmxTransient The VMX-transient structure.
5324 *
5325 * @remarks No-long-jump zone!!!
5326 */
5327static void hmR0VmxExportGuestXcptIntercepts(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5328{
5329 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_XCPT_INTERCEPTS)
5330 {
5331 /* When executing a nested-guest, we do not need to trap GIM hypercalls by intercepting #UD. */
5332 if ( !pVmxTransient->fIsNestedGuest
5333 && pVCpu->hm.s.fGIMTrapXcptUD)
5334 hmR0VmxAddXcptIntercept(pVmxTransient, X86_XCPT_UD);
5335 else
5336 hmR0VmxRemoveXcptIntercept(pVCpu, pVmxTransient, X86_XCPT_UD);
5337
5338 /* Other exception intercepts are handled elsewhere, e.g. while exporting guest CR0. */
5339 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_XCPT_INTERCEPTS);
5340 }
5341}
5342
5343
5344/**
5345 * Exports the guest's RIP into the guest-state area in the VMCS.
5346 *
5347 * @param pVCpu The cross context virtual CPU structure.
5348 *
5349 * @remarks No-long-jump zone!!!
5350 */
5351static void hmR0VmxExportGuestRip(PVMCPUCC pVCpu)
5352{
5353 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RIP)
5354 {
5355 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP);
5356
5357 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RIP, pVCpu->cpum.GstCtx.rip);
5358 AssertRC(rc);
5359
5360 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RIP);
5361 Log4Func(("rip=%#RX64\n", pVCpu->cpum.GstCtx.rip));
5362 }
5363}
5364
5365
5366/**
5367 * Exports the guest's RSP into the guest-state area in the VMCS.
5368 *
5369 * @param pVCpu The cross context virtual CPU structure.
5370 *
5371 * @remarks No-long-jump zone!!!
5372 */
5373static void hmR0VmxExportGuestRsp(PVMCPUCC pVCpu)
5374{
5375 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RSP)
5376 {
5377 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RSP);
5378
5379 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RSP, pVCpu->cpum.GstCtx.rsp);
5380 AssertRC(rc);
5381
5382 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RSP);
5383 Log4Func(("rsp=%#RX64\n", pVCpu->cpum.GstCtx.rsp));
5384 }
5385}
5386
5387
5388/**
5389 * Exports the guest's RFLAGS into the guest-state area in the VMCS.
5390 *
5391 * @param pVCpu The cross context virtual CPU structure.
5392 * @param pVmxTransient The VMX-transient structure.
5393 *
5394 * @remarks No-long-jump zone!!!
5395 */
5396static void hmR0VmxExportGuestRflags(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5397{
5398 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RFLAGS)
5399 {
5400 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
5401
5402 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
5403 Let us assert it as such and use 32-bit VMWRITE. */
5404 Assert(!RT_HI_U32(pVCpu->cpum.GstCtx.rflags.u64));
5405 X86EFLAGS fEFlags = pVCpu->cpum.GstCtx.eflags;
5406 Assert(fEFlags.u32 & X86_EFL_RA1_MASK);
5407 Assert(!(fEFlags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
5408
5409 /*
5410 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so
5411 * we can restore them on VM-exit. Modify the real-mode guest's eflags so that VT-x
5412 * can run the real-mode guest code under Virtual 8086 mode.
5413 */
5414 PVMXVMCSINFOSHARED pVmcsInfo = pVmxTransient->pVmcsInfo->pShared;
5415 if (pVmcsInfo->RealMode.fRealOnV86Active)
5416 {
5417 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
5418 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
5419 Assert(!pVmxTransient->fIsNestedGuest);
5420 pVmcsInfo->RealMode.Eflags.u32 = fEFlags.u32; /* Save the original eflags of the real-mode guest. */
5421 fEFlags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
5422 fEFlags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
5423 }
5424
5425 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RFLAGS, fEFlags.u32);
5426 AssertRC(rc);
5427
5428 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RFLAGS);
5429 Log4Func(("eflags=%#RX32\n", fEFlags.u32));
5430 }
5431}
5432
5433
5434#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5435/**
5436 * Copies the nested-guest VMCS to the shadow VMCS.
5437 *
5438 * @returns VBox status code.
5439 * @param pVCpu The cross context virtual CPU structure.
5440 * @param pVmcsInfo The VMCS info. object.
5441 *
5442 * @remarks No-long-jump zone!!!
5443 */
5444static int hmR0VmxCopyNstGstToShadowVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5445{
5446 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5447 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5448
5449 /*
5450 * Disable interrupts so we don't get preempted while the shadow VMCS is the
5451 * current VMCS, as we may try saving guest lazy MSRs.
5452 *
5453 * Strictly speaking the lazy MSRs are not in the VMCS, but I'd rather not risk
5454 * calling the import VMCS code which is currently performing the guest MSR reads
5455 * (on 64-bit hosts) and accessing the auto-load/store MSR area on 32-bit hosts
5456 * and the rest of the VMX leave session machinery.
5457 */
5458 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
5459
5460 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5461 if (RT_SUCCESS(rc))
5462 {
5463 /*
5464 * Copy all guest read/write VMCS fields.
5465 *
5466 * We don't check for VMWRITE failures here for performance reasons and
5467 * because they are not expected to fail, barring irrecoverable conditions
5468 * like hardware errors.
5469 */
5470 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
5471 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5472 {
5473 uint64_t u64Val;
5474 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsFields[i];
5475 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5476 VMXWriteVmcs64(uVmcsField, u64Val);
5477 }
5478
5479 /*
5480 * If the host CPU supports writing all VMCS fields, copy the guest read-only
5481 * VMCS fields, so the guest can VMREAD them without causing a VM-exit.
5482 */
5483 if (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL)
5484 {
5485 uint32_t const cShadowVmcsRoFields = pVM->hmr0.s.vmx.cShadowVmcsRoFields;
5486 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
5487 {
5488 uint64_t u64Val;
5489 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsRoFields[i];
5490 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5491 VMXWriteVmcs64(uVmcsField, u64Val);
5492 }
5493 }
5494
5495 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5496 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5497 }
5498
5499 ASMSetFlags(fEFlags);
5500 return rc;
5501}
5502
5503
5504/**
5505 * Copies the shadow VMCS to the nested-guest VMCS.
5506 *
5507 * @returns VBox status code.
5508 * @param pVCpu The cross context virtual CPU structure.
5509 * @param pVmcsInfo The VMCS info. object.
5510 *
5511 * @remarks Called with interrupts disabled.
5512 */
5513static int hmR0VmxCopyShadowToNstGstVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5514{
5515 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5516 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5517 PVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5518
5519 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5520 if (RT_SUCCESS(rc))
5521 {
5522 /*
5523 * Copy guest read/write fields from the shadow VMCS.
5524 * Guest read-only fields cannot be modified, so no need to copy them.
5525 *
5526 * We don't check for VMREAD failures here for performance reasons and
5527 * because they are not expected to fail, barring irrecoverable conditions
5528 * like hardware errors.
5529 */
5530 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
5531 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5532 {
5533 uint64_t u64Val;
5534 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsFields[i];
5535 VMXReadVmcs64(uVmcsField, &u64Val);
5536 IEMWriteVmxVmcsField(pVmcsNstGst, uVmcsField, u64Val);
5537 }
5538
5539 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5540 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5541 }
5542 return rc;
5543}
5544
5545
5546/**
5547 * Enables VMCS shadowing for the given VMCS info. object.
5548 *
5549 * @param pVmcsInfo The VMCS info. object.
5550 *
5551 * @remarks No-long-jump zone!!!
5552 */
5553static void hmR0VmxEnableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5554{
5555 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5556 if (!(uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING))
5557 {
5558 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
5559 uProcCtls2 |= VMX_PROC_CTLS2_VMCS_SHADOWING;
5560 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5561 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, pVmcsInfo->HCPhysShadowVmcs); AssertRC(rc);
5562 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5563 pVmcsInfo->u64VmcsLinkPtr = pVmcsInfo->HCPhysShadowVmcs;
5564 Log4Func(("Enabled\n"));
5565 }
5566}
5567
5568
5569/**
5570 * Disables VMCS shadowing for the given VMCS info. object.
5571 *
5572 * @param pVmcsInfo The VMCS info. object.
5573 *
5574 * @remarks No-long-jump zone!!!
5575 */
5576static void hmR0VmxDisableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5577{
5578 /*
5579 * We want all VMREAD and VMWRITE instructions to cause VM-exits, so we clear the
5580 * VMCS shadowing control. However, VM-entry requires the shadow VMCS indicator bit
5581 * to match the VMCS shadowing control if the VMCS link pointer is not NIL_RTHCPHYS.
5582 * Hence, we must also reset the VMCS link pointer to ensure VM-entry does not fail.
5583 *
5584 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
5585 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5586 */
5587 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5588 if (uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
5589 {
5590 uProcCtls2 &= ~VMX_PROC_CTLS2_VMCS_SHADOWING;
5591 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5592 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS); AssertRC(rc);
5593 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5594 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
5595 Log4Func(("Disabled\n"));
5596 }
5597}
5598#endif
5599
5600
5601/**
5602 * Exports the guest hardware-virtualization state.
5603 *
5604 * @returns VBox status code.
5605 * @param pVCpu The cross context virtual CPU structure.
5606 * @param pVmxTransient The VMX-transient structure.
5607 *
5608 * @remarks No-long-jump zone!!!
5609 */
5610static int hmR0VmxExportGuestHwvirtState(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5611{
5612 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_HWVIRT)
5613 {
5614#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5615 /*
5616 * Check if the VMX feature is exposed to the guest and if the host CPU supports
5617 * VMCS shadowing.
5618 */
5619 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUseVmcsShadowing)
5620 {
5621 /*
5622 * If the nested hypervisor has loaded a current VMCS and is in VMX root mode,
5623 * copy the nested hypervisor's current VMCS into the shadow VMCS and enable
5624 * VMCS shadowing to skip intercepting some or all VMREAD/VMWRITE VM-exits.
5625 *
5626 * We check for VMX root mode here in case the guest executes VMXOFF without
5627 * clearing the current VMCS pointer and our VMXOFF instruction emulation does
5628 * not clear the current VMCS pointer.
5629 */
5630 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5631 if ( CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx)
5632 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx)
5633 && CPUMIsGuestVmxCurrentVmcsValid(&pVCpu->cpum.GstCtx))
5634 {
5635 /* Paranoia. */
5636 Assert(!pVmxTransient->fIsNestedGuest);
5637
5638 /*
5639 * For performance reasons, also check if the nested hypervisor's current VMCS
5640 * was newly loaded or modified before copying it to the shadow VMCS.
5641 */
5642 if (!pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs)
5643 {
5644 int rc = hmR0VmxCopyNstGstToShadowVmcs(pVCpu, pVmcsInfo);
5645 AssertRCReturn(rc, rc);
5646 pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs = true;
5647 }
5648 hmR0VmxEnableVmcsShadowing(pVmcsInfo);
5649 }
5650 else
5651 hmR0VmxDisableVmcsShadowing(pVmcsInfo);
5652 }
5653#else
5654 NOREF(pVmxTransient);
5655#endif
5656 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_HWVIRT);
5657 }
5658 return VINF_SUCCESS;
5659}
5660
5661
5662/**
5663 * Exports the guest CR0 control register into the guest-state area in the VMCS.
5664 *
5665 * The guest FPU state is always pre-loaded hence we don't need to bother about
5666 * sharing FPU related CR0 bits between the guest and host.
5667 *
5668 * @returns VBox status code.
5669 * @param pVCpu The cross context virtual CPU structure.
5670 * @param pVmxTransient The VMX-transient structure.
5671 *
5672 * @remarks No-long-jump zone!!!
5673 */
5674static int hmR0VmxExportGuestCR0(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5675{
5676 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR0)
5677 {
5678 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5679 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5680
5681 uint64_t fSetCr0 = g_HmMsrs.u.vmx.u64Cr0Fixed0;
5682 uint64_t const fZapCr0 = g_HmMsrs.u.vmx.u64Cr0Fixed1;
5683 if (pVM->hmr0.s.vmx.fUnrestrictedGuest)
5684 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
5685 else
5686 Assert((fSetCr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
5687
5688 if (!pVmxTransient->fIsNestedGuest)
5689 {
5690 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5691 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5692 uint64_t const u64ShadowCr0 = u64GuestCr0;
5693 Assert(!RT_HI_U32(u64GuestCr0));
5694
5695 /*
5696 * Setup VT-x's view of the guest CR0.
5697 */
5698 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5699 if (pVM->hmr0.s.fNestedPaging)
5700 {
5701 if (CPUMIsGuestPagingEnabled(pVCpu))
5702 {
5703 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
5704 uProcCtls &= ~( VMX_PROC_CTLS_CR3_LOAD_EXIT
5705 | VMX_PROC_CTLS_CR3_STORE_EXIT);
5706 }
5707 else
5708 {
5709 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
5710 uProcCtls |= VMX_PROC_CTLS_CR3_LOAD_EXIT
5711 | VMX_PROC_CTLS_CR3_STORE_EXIT;
5712 }
5713
5714 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
5715 if (pVM->hmr0.s.vmx.fUnrestrictedGuest)
5716 uProcCtls &= ~VMX_PROC_CTLS_CR3_STORE_EXIT;
5717 }
5718 else
5719 {
5720 /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
5721 u64GuestCr0 |= X86_CR0_WP;
5722 }
5723
5724 /*
5725 * Guest FPU bits.
5726 *
5727 * Since we pre-load the guest FPU always before VM-entry there is no need to track lazy state
5728 * using CR0.TS.
5729 *
5730 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be
5731 * set on the first CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
5732 */
5733 u64GuestCr0 |= X86_CR0_NE;
5734
5735 /* If CR0.NE isn't set, we need to intercept #MF exceptions and report them to the guest differently. */
5736 bool const fInterceptMF = !(u64ShadowCr0 & X86_CR0_NE);
5737
5738 /*
5739 * Update exception intercepts.
5740 */
5741 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
5742 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
5743 {
5744 Assert(PDMVmmDevHeapIsEnabled(pVM));
5745 Assert(pVM->hm.s.vmx.pRealModeTSS);
5746 uXcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
5747 }
5748 else
5749 {
5750 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
5751 uXcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
5752 if (fInterceptMF)
5753 uXcptBitmap |= RT_BIT(X86_XCPT_MF);
5754 }
5755
5756 /* Additional intercepts for debugging, define these yourself explicitly. */
5757#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
5758 uXcptBitmap |= 0
5759 | RT_BIT(X86_XCPT_BP)
5760 | RT_BIT(X86_XCPT_DE)
5761 | RT_BIT(X86_XCPT_NM)
5762 | RT_BIT(X86_XCPT_TS)
5763 | RT_BIT(X86_XCPT_UD)
5764 | RT_BIT(X86_XCPT_NP)
5765 | RT_BIT(X86_XCPT_SS)
5766 | RT_BIT(X86_XCPT_GP)
5767 | RT_BIT(X86_XCPT_PF)
5768 | RT_BIT(X86_XCPT_MF)
5769 ;
5770#elif defined(HMVMX_ALWAYS_TRAP_PF)
5771 uXcptBitmap |= RT_BIT(X86_XCPT_PF);
5772#endif
5773 if (pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv)
5774 uXcptBitmap |= RT_BIT(X86_XCPT_GP);
5775 Assert(pVM->hmr0.s.fNestedPaging || (uXcptBitmap & RT_BIT(X86_XCPT_PF)));
5776
5777 /* Apply the hardware specified CR0 fixed bits and enable caching. */
5778 u64GuestCr0 |= fSetCr0;
5779 u64GuestCr0 &= fZapCr0;
5780 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5781
5782 /* Commit the CR0 and related fields to the guest VMCS. */
5783 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5784 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5785 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5786 {
5787 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5788 AssertRC(rc);
5789 }
5790 if (uXcptBitmap != pVmcsInfo->u32XcptBitmap)
5791 {
5792 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
5793 AssertRC(rc);
5794 }
5795
5796 /* Update our caches. */
5797 pVmcsInfo->u32ProcCtls = uProcCtls;
5798 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
5799
5800 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5801 }
5802 else
5803 {
5804 /*
5805 * With nested-guests, we may have extended the guest/host mask here since we
5806 * merged in the outer guest's mask. Thus, the merged mask can include more bits
5807 * (to read from the nested-guest CR0 read-shadow) than the nested hypervisor
5808 * originally supplied. We must copy those bits from the nested-guest CR0 into
5809 * the nested-guest CR0 read-shadow.
5810 */
5811 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5812 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5813 uint64_t const u64ShadowCr0 = CPUMGetGuestVmxMaskedCr0(&pVCpu->cpum.GstCtx, pVmcsInfo->u64Cr0Mask);
5814 Assert(!RT_HI_U32(u64GuestCr0));
5815 Assert(u64GuestCr0 & X86_CR0_NE);
5816
5817 /* Apply the hardware specified CR0 fixed bits and enable caching. */
5818 u64GuestCr0 |= fSetCr0;
5819 u64GuestCr0 &= fZapCr0;
5820 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5821
5822 /* Commit the CR0 and CR0 read-shadow to the nested-guest VMCS. */
5823 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5824 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5825
5826 Log4Func(("cr0=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5827 }
5828
5829 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR0);
5830 }
5831
5832 return VINF_SUCCESS;
5833}
5834
5835
5836/**
5837 * Exports the guest control registers (CR3, CR4) into the guest-state area
5838 * in the VMCS.
5839 *
5840 * @returns VBox strict status code.
5841 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
5842 * without unrestricted guest access and the VMMDev is not presently
5843 * mapped (e.g. EFI32).
5844 *
5845 * @param pVCpu The cross context virtual CPU structure.
5846 * @param pVmxTransient The VMX-transient structure.
5847 *
5848 * @remarks No-long-jump zone!!!
5849 */
5850static VBOXSTRICTRC hmR0VmxExportGuestCR3AndCR4(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5851{
5852 int rc = VINF_SUCCESS;
5853 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5854
5855 /*
5856 * Guest CR2.
5857 * It's always loaded in the assembler code. Nothing to do here.
5858 */
5859
5860 /*
5861 * Guest CR3.
5862 */
5863 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR3)
5864 {
5865 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
5866
5867 if (pVM->hmr0.s.fNestedPaging)
5868 {
5869 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5870 pVmcsInfo->HCPhysEPTP = PGMGetHyperCR3(pVCpu);
5871
5872 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
5873 Assert(pVmcsInfo->HCPhysEPTP != NIL_RTHCPHYS);
5874 Assert(!(pVmcsInfo->HCPhysEPTP & UINT64_C(0xfff0000000000000)));
5875 Assert(!(pVmcsInfo->HCPhysEPTP & 0xfff));
5876
5877 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
5878 pVmcsInfo->HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
5879 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
5880
5881 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
5882 AssertMsg( ((pVmcsInfo->HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
5883 && ((pVmcsInfo->HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
5884 ("EPTP %#RX64\n", pVmcsInfo->HCPhysEPTP));
5885 AssertMsg( !((pVmcsInfo->HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
5886 || (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
5887 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVmcsInfo->HCPhysEPTP));
5888
5889 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVmcsInfo->HCPhysEPTP);
5890 AssertRC(rc);
5891
5892 uint64_t u64GuestCr3;
5893 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5894 if ( pVM->hmr0.s.vmx.fUnrestrictedGuest
5895 || CPUMIsGuestPagingEnabledEx(pCtx))
5896 {
5897 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
5898 if (CPUMIsGuestInPAEModeEx(pCtx))
5899 {
5900 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pCtx->aPaePdpes[0].u); AssertRC(rc);
5901 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pCtx->aPaePdpes[1].u); AssertRC(rc);
5902 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pCtx->aPaePdpes[2].u); AssertRC(rc);
5903 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pCtx->aPaePdpes[3].u); AssertRC(rc);
5904 }
5905
5906 /*
5907 * The guest's view of its CR3 is unblemished with nested paging when the
5908 * guest is using paging or we have unrestricted guest execution to handle
5909 * the guest when it's not using paging.
5910 */
5911 u64GuestCr3 = pCtx->cr3;
5912 }
5913 else
5914 {
5915 /*
5916 * The guest is not using paging, but the CPU (VT-x) has to. While the guest
5917 * thinks it accesses physical memory directly, we use our identity-mapped
5918 * page table to map guest-linear to guest-physical addresses. EPT takes care
5919 * of translating it to host-physical addresses.
5920 */
5921 RTGCPHYS GCPhys;
5922 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
5923
5924 /* We obtain it here every time as the guest could have relocated this PCI region. */
5925 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
5926 if (RT_SUCCESS(rc))
5927 { /* likely */ }
5928 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
5929 {
5930 Log4Func(("VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n"));
5931 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
5932 }
5933 else
5934 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
5935
5936 u64GuestCr3 = GCPhys;
5937 }
5938
5939 Log4Func(("guest_cr3=%#RX64 (GstN)\n", u64GuestCr3));
5940 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, u64GuestCr3);
5941 AssertRC(rc);
5942 }
5943 else
5944 {
5945 Assert(!pVmxTransient->fIsNestedGuest);
5946 /* Non-nested paging case, just use the hypervisor's CR3. */
5947 RTHCPHYS const HCPhysGuestCr3 = PGMGetHyperCR3(pVCpu);
5948
5949 Log4Func(("guest_cr3=%#RX64 (HstN)\n", HCPhysGuestCr3));
5950 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, HCPhysGuestCr3);
5951 AssertRC(rc);
5952 }
5953
5954 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR3);
5955 }
5956
5957 /*
5958 * Guest CR4.
5959 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
5960 */
5961 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR4)
5962 {
5963 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5964 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5965
5966 uint64_t const fSetCr4 = g_HmMsrs.u.vmx.u64Cr4Fixed0;
5967 uint64_t const fZapCr4 = g_HmMsrs.u.vmx.u64Cr4Fixed1;
5968
5969 /*
5970 * With nested-guests, we may have extended the guest/host mask here (since we
5971 * merged in the outer guest's mask, see hmR0VmxMergeVmcsNested). This means, the
5972 * mask can include more bits (to read from the nested-guest CR4 read-shadow) than
5973 * the nested hypervisor originally supplied. Thus, we should, in essence, copy
5974 * those bits from the nested-guest CR4 into the nested-guest CR4 read-shadow.
5975 */
5976 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
5977 uint64_t u64GuestCr4 = pCtx->cr4;
5978 uint64_t const u64ShadowCr4 = !pVmxTransient->fIsNestedGuest
5979 ? pCtx->cr4
5980 : CPUMGetGuestVmxMaskedCr4(pCtx, pVmcsInfo->u64Cr4Mask);
5981 Assert(!RT_HI_U32(u64GuestCr4));
5982
5983 /*
5984 * Setup VT-x's view of the guest CR4.
5985 *
5986 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software
5987 * interrupts to the 8086 program interrupt handler. Clear the VME bit (the interrupt
5988 * redirection bitmap is already all 0, see hmR3InitFinalizeR0())
5989 *
5990 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
5991 */
5992 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
5993 {
5994 Assert(pVM->hm.s.vmx.pRealModeTSS);
5995 Assert(PDMVmmDevHeapIsEnabled(pVM));
5996 u64GuestCr4 &= ~(uint64_t)X86_CR4_VME;
5997 }
5998
5999 if (pVM->hmr0.s.fNestedPaging)
6000 {
6001 if ( !CPUMIsGuestPagingEnabledEx(pCtx)
6002 && !pVM->hmr0.s.vmx.fUnrestrictedGuest)
6003 {
6004 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
6005 u64GuestCr4 |= X86_CR4_PSE;
6006 /* Our identity mapping is a 32-bit page directory. */
6007 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
6008 }
6009 /* else use guest CR4.*/
6010 }
6011 else
6012 {
6013 Assert(!pVmxTransient->fIsNestedGuest);
6014
6015 /*
6016 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
6017 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
6018 */
6019 switch (pVCpu->hm.s.enmShadowMode)
6020 {
6021 case PGMMODE_REAL: /* Real-mode. */
6022 case PGMMODE_PROTECTED: /* Protected mode without paging. */
6023 case PGMMODE_32_BIT: /* 32-bit paging. */
6024 {
6025 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
6026 break;
6027 }
6028
6029 case PGMMODE_PAE: /* PAE paging. */
6030 case PGMMODE_PAE_NX: /* PAE paging with NX. */
6031 {
6032 u64GuestCr4 |= X86_CR4_PAE;
6033 break;
6034 }
6035
6036 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
6037 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
6038 {
6039#ifdef VBOX_WITH_64_BITS_GUESTS
6040 /* For our assumption in hmR0VmxShouldSwapEferMsr. */
6041 Assert(u64GuestCr4 & X86_CR4_PAE);
6042 break;
6043#endif
6044 }
6045 default:
6046 AssertFailed();
6047 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
6048 }
6049 }
6050
6051 /* Apply the hardware specified CR4 fixed bits (mainly CR4.VMXE). */
6052 u64GuestCr4 |= fSetCr4;
6053 u64GuestCr4 &= fZapCr4;
6054
6055 /* Commit the CR4 and CR4 read-shadow to the guest VMCS. */
6056 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR4, u64GuestCr4); AssertRC(rc);
6057 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, u64ShadowCr4); AssertRC(rc);
6058
6059 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
6060 bool const fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
6061 if (fLoadSaveGuestXcr0 != pVCpu->hmr0.s.fLoadSaveGuestXcr0)
6062 {
6063 pVCpu->hmr0.s.fLoadSaveGuestXcr0 = fLoadSaveGuestXcr0;
6064 hmR0VmxUpdateStartVmFunction(pVCpu);
6065 }
6066
6067 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR4);
6068
6069 Log4Func(("cr4=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr4, u64ShadowCr4, fSetCr4, fZapCr4));
6070 }
6071 return rc;
6072}
6073
6074
6075/**
6076 * Exports the guest debug registers into the guest-state area in the VMCS.
6077 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
6078 *
6079 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
6080 *
6081 * @returns VBox status code.
6082 * @param pVCpu The cross context virtual CPU structure.
6083 * @param pVmxTransient The VMX-transient structure.
6084 *
6085 * @remarks No-long-jump zone!!!
6086 */
6087static int hmR0VmxExportSharedDebugState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6088{
6089 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
6090
6091 /** @todo NSTVMX: Figure out what we want to do with nested-guest instruction
6092 * stepping. */
6093 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6094 if (pVmxTransient->fIsNestedGuest)
6095 {
6096 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, CPUMGetGuestDR7(pVCpu));
6097 AssertRC(rc);
6098
6099 /*
6100 * We don't want to always intercept MOV DRx for nested-guests as it causes
6101 * problems when the nested hypervisor isn't intercepting them, see @bugref{10080}.
6102 * Instead, they are strictly only requested when the nested hypervisor intercepts
6103 * them -- handled while merging VMCS controls.
6104 *
6105 * If neither the outer nor the nested-hypervisor is intercepting MOV DRx,
6106 * then the nested-guest debug state should be actively loaded on the host so that
6107 * nested-guest reads its own debug registers without causing VM-exits.
6108 */
6109 if ( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT)
6110 && !CPUMIsGuestDebugStateActive(pVCpu))
6111 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
6112 return VINF_SUCCESS;
6113 }
6114
6115#ifdef VBOX_STRICT
6116 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
6117 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
6118 {
6119 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
6120 Assert((pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0);
6121 Assert((pVCpu->cpum.GstCtx.dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK);
6122 }
6123#endif
6124
6125 bool fSteppingDB = false;
6126 bool fInterceptMovDRx = false;
6127 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
6128 if (pVCpu->hm.s.fSingleInstruction)
6129 {
6130 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
6131 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
6132 {
6133 uProcCtls |= VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
6134 Assert(fSteppingDB == false);
6135 }
6136 else
6137 {
6138 pVCpu->cpum.GstCtx.eflags.u32 |= X86_EFL_TF;
6139 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_RFLAGS;
6140 pVCpu->hmr0.s.fClearTrapFlag = true;
6141 fSteppingDB = true;
6142 }
6143 }
6144
6145 uint64_t u64GuestDr7;
6146 if ( fSteppingDB
6147 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
6148 {
6149 /*
6150 * Use the combined guest and host DRx values found in the hypervisor register set
6151 * because the hypervisor debugger has breakpoints active or someone is single stepping
6152 * on the host side without a monitor trap flag.
6153 *
6154 * Note! DBGF expects a clean DR6 state before executing guest code.
6155 */
6156 if (!CPUMIsHyperDebugStateActive(pVCpu))
6157 {
6158 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
6159 Assert(CPUMIsHyperDebugStateActive(pVCpu));
6160 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
6161 }
6162
6163 /* Update DR7 with the hypervisor value (other DRx registers are handled by CPUM one way or another). */
6164 u64GuestDr7 = CPUMGetHyperDR7(pVCpu);
6165 pVCpu->hmr0.s.fUsingHyperDR7 = true;
6166 fInterceptMovDRx = true;
6167 }
6168 else
6169 {
6170 /*
6171 * If the guest has enabled debug registers, we need to load them prior to
6172 * executing guest code so they'll trigger at the right time.
6173 */
6174 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
6175 if (pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
6176 {
6177 if (!CPUMIsGuestDebugStateActive(pVCpu))
6178 {
6179 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
6180 Assert(CPUMIsGuestDebugStateActive(pVCpu));
6181 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
6182 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
6183 }
6184 Assert(!fInterceptMovDRx);
6185 }
6186 else if (!CPUMIsGuestDebugStateActive(pVCpu))
6187 {
6188 /*
6189 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
6190 * must intercept #DB in order to maintain a correct DR6 guest value, and
6191 * because we need to intercept it to prevent nested #DBs from hanging the
6192 * CPU, we end up always having to intercept it. See hmR0VmxSetupVmcsXcptBitmap().
6193 */
6194 fInterceptMovDRx = true;
6195 }
6196
6197 /* Update DR7 with the actual guest value. */
6198 u64GuestDr7 = pVCpu->cpum.GstCtx.dr[7];
6199 pVCpu->hmr0.s.fUsingHyperDR7 = false;
6200 }
6201
6202 if (fInterceptMovDRx)
6203 uProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
6204 else
6205 uProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
6206
6207 /*
6208 * Update the processor-based VM-execution controls with the MOV-DRx intercepts and the
6209 * monitor-trap flag and update our cache.
6210 */
6211 if (uProcCtls != pVmcsInfo->u32ProcCtls)
6212 {
6213 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
6214 AssertRC(rc);
6215 pVmcsInfo->u32ProcCtls = uProcCtls;
6216 }
6217
6218 /*
6219 * Update guest DR7.
6220 */
6221 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, u64GuestDr7);
6222 AssertRC(rc);
6223
6224 /*
6225 * If we have forced EFLAGS.TF to be set because we're single-stepping in the hypervisor debugger,
6226 * we need to clear interrupt inhibition if any as otherwise it causes a VM-entry failure.
6227 *
6228 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
6229 */
6230 if (fSteppingDB)
6231 {
6232 Assert(pVCpu->hm.s.fSingleInstruction);
6233 Assert(pVCpu->cpum.GstCtx.eflags.Bits.u1TF);
6234
6235 uint32_t fIntrState = 0;
6236 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
6237 AssertRC(rc);
6238
6239 if (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
6240 {
6241 fIntrState &= ~(VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
6242 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
6243 AssertRC(rc);
6244 }
6245 }
6246
6247 return VINF_SUCCESS;
6248}
6249
6250
6251#ifdef VBOX_STRICT
6252/**
6253 * Strict function to validate segment registers.
6254 *
6255 * @param pVCpu The cross context virtual CPU structure.
6256 * @param pVmcsInfo The VMCS info. object.
6257 *
6258 * @remarks Will import guest CR0 on strict builds during validation of
6259 * segments.
6260 */
6261static void hmR0VmxValidateSegmentRegs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
6262{
6263 /*
6264 * Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
6265 *
6266 * The reason we check for attribute value 0 in this function and not just the unusable bit is
6267 * because hmR0VmxExportGuestSegReg() only updates the VMCS' copy of the value with the
6268 * unusable bit and doesn't change the guest-context value.
6269 */
6270 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6271 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6272 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR0);
6273 if ( !pVM->hmr0.s.vmx.fUnrestrictedGuest
6274 && ( !CPUMIsGuestInRealModeEx(pCtx)
6275 && !CPUMIsGuestInV86ModeEx(pCtx)))
6276 {
6277 /* Protected mode checks */
6278 /* CS */
6279 Assert(pCtx->cs.Attr.n.u1Present);
6280 Assert(!(pCtx->cs.Attr.u & 0xf00));
6281 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
6282 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
6283 || !(pCtx->cs.Attr.n.u1Granularity));
6284 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
6285 || (pCtx->cs.Attr.n.u1Granularity));
6286 /* CS cannot be loaded with NULL in protected mode. */
6287 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
6288 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
6289 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
6290 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
6291 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
6292 else
6293 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
6294 /* SS */
6295 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
6296 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
6297 if ( !(pCtx->cr0 & X86_CR0_PE)
6298 || pCtx->cs.Attr.n.u4Type == 3)
6299 {
6300 Assert(!pCtx->ss.Attr.n.u2Dpl);
6301 }
6302 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
6303 {
6304 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
6305 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
6306 Assert(pCtx->ss.Attr.n.u1Present);
6307 Assert(!(pCtx->ss.Attr.u & 0xf00));
6308 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
6309 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
6310 || !(pCtx->ss.Attr.n.u1Granularity));
6311 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
6312 || (pCtx->ss.Attr.n.u1Granularity));
6313 }
6314 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSegReg(). */
6315 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
6316 {
6317 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6318 Assert(pCtx->ds.Attr.n.u1Present);
6319 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
6320 Assert(!(pCtx->ds.Attr.u & 0xf00));
6321 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
6322 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
6323 || !(pCtx->ds.Attr.n.u1Granularity));
6324 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
6325 || (pCtx->ds.Attr.n.u1Granularity));
6326 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6327 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
6328 }
6329 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
6330 {
6331 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6332 Assert(pCtx->es.Attr.n.u1Present);
6333 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
6334 Assert(!(pCtx->es.Attr.u & 0xf00));
6335 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
6336 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
6337 || !(pCtx->es.Attr.n.u1Granularity));
6338 Assert( !(pCtx->es.u32Limit & 0xfff00000)
6339 || (pCtx->es.Attr.n.u1Granularity));
6340 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6341 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
6342 }
6343 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
6344 {
6345 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6346 Assert(pCtx->fs.Attr.n.u1Present);
6347 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
6348 Assert(!(pCtx->fs.Attr.u & 0xf00));
6349 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
6350 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
6351 || !(pCtx->fs.Attr.n.u1Granularity));
6352 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
6353 || (pCtx->fs.Attr.n.u1Granularity));
6354 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6355 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
6356 }
6357 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
6358 {
6359 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6360 Assert(pCtx->gs.Attr.n.u1Present);
6361 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
6362 Assert(!(pCtx->gs.Attr.u & 0xf00));
6363 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
6364 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
6365 || !(pCtx->gs.Attr.n.u1Granularity));
6366 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
6367 || (pCtx->gs.Attr.n.u1Granularity));
6368 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6369 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
6370 }
6371 /* 64-bit capable CPUs. */
6372 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6373 Assert(!pCtx->ss.Attr.u || !RT_HI_U32(pCtx->ss.u64Base));
6374 Assert(!pCtx->ds.Attr.u || !RT_HI_U32(pCtx->ds.u64Base));
6375 Assert(!pCtx->es.Attr.u || !RT_HI_U32(pCtx->es.u64Base));
6376 }
6377 else if ( CPUMIsGuestInV86ModeEx(pCtx)
6378 || ( CPUMIsGuestInRealModeEx(pCtx)
6379 && !pVM->hmr0.s.vmx.fUnrestrictedGuest))
6380 {
6381 /* Real and v86 mode checks. */
6382 /* hmR0VmxExportGuestSegReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
6383 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
6384 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
6385 {
6386 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3;
6387 u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
6388 }
6389 else
6390 {
6391 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
6392 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
6393 }
6394
6395 /* CS */
6396 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
6397 Assert(pCtx->cs.u32Limit == 0xffff);
6398 Assert(u32CSAttr == 0xf3);
6399 /* SS */
6400 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
6401 Assert(pCtx->ss.u32Limit == 0xffff);
6402 Assert(u32SSAttr == 0xf3);
6403 /* DS */
6404 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
6405 Assert(pCtx->ds.u32Limit == 0xffff);
6406 Assert(u32DSAttr == 0xf3);
6407 /* ES */
6408 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
6409 Assert(pCtx->es.u32Limit == 0xffff);
6410 Assert(u32ESAttr == 0xf3);
6411 /* FS */
6412 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
6413 Assert(pCtx->fs.u32Limit == 0xffff);
6414 Assert(u32FSAttr == 0xf3);
6415 /* GS */
6416 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
6417 Assert(pCtx->gs.u32Limit == 0xffff);
6418 Assert(u32GSAttr == 0xf3);
6419 /* 64-bit capable CPUs. */
6420 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6421 Assert(!u32SSAttr || !RT_HI_U32(pCtx->ss.u64Base));
6422 Assert(!u32DSAttr || !RT_HI_U32(pCtx->ds.u64Base));
6423 Assert(!u32ESAttr || !RT_HI_U32(pCtx->es.u64Base));
6424 }
6425}
6426#endif /* VBOX_STRICT */
6427
6428
6429/**
6430 * Exports a guest segment register into the guest-state area in the VMCS.
6431 *
6432 * @returns VBox status code.
6433 * @param pVCpu The cross context virtual CPU structure.
6434 * @param pVmcsInfo The VMCS info. object.
6435 * @param iSegReg The segment register number (X86_SREG_XXX).
6436 * @param pSelReg Pointer to the segment selector.
6437 *
6438 * @remarks No-long-jump zone!!!
6439 */
6440static int hmR0VmxExportGuestSegReg(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, uint32_t iSegReg, PCCPUMSELREG pSelReg)
6441{
6442 Assert(iSegReg < X86_SREG_COUNT);
6443
6444 uint32_t u32Access = pSelReg->Attr.u;
6445 if (!pVmcsInfo->pShared->RealMode.fRealOnV86Active)
6446 {
6447 /*
6448 * The way to differentiate between whether this is really a null selector or was just
6449 * a selector loaded with 0 in real-mode is using the segment attributes. A selector
6450 * loaded in real-mode with the value 0 is valid and usable in protected-mode and we
6451 * should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures
6452 * NULL selectors loaded in protected-mode have their attribute as 0.
6453 */
6454 if (u32Access)
6455 { }
6456 else
6457 u32Access = X86DESCATTR_UNUSABLE;
6458 }
6459 else
6460 {
6461 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
6462 u32Access = 0xf3;
6463 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6464 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
6465 RT_NOREF_PV(pVCpu);
6466 }
6467
6468 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
6469 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
6470 ("Access bit not set for usable segment. %.2s sel=%#x attr %#x\n", "ESCSSSDSFSGS" + iSegReg * 2, pSelReg, pSelReg->Attr.u));
6471
6472 /*
6473 * Commit it to the VMCS.
6474 */
6475 Assert((uint32_t)VMX_VMCS16_GUEST_SEG_SEL(iSegReg) == g_aVmcsSegSel[iSegReg]);
6476 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg) == g_aVmcsSegLimit[iSegReg]);
6477 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg) == g_aVmcsSegAttr[iSegReg]);
6478 Assert((uint32_t)VMX_VMCS_GUEST_SEG_BASE(iSegReg) == g_aVmcsSegBase[iSegReg]);
6479 int rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_SEG_SEL(iSegReg), pSelReg->Sel); AssertRC(rc);
6480 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg), pSelReg->u32Limit); AssertRC(rc);
6481 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SEG_BASE(iSegReg), pSelReg->u64Base); AssertRC(rc);
6482 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg), u32Access); AssertRC(rc);
6483 return VINF_SUCCESS;
6484}
6485
6486
6487/**
6488 * Exports the guest segment registers, GDTR, IDTR, LDTR, TR into the guest-state
6489 * area in the VMCS.
6490 *
6491 * @returns VBox status code.
6492 * @param pVCpu The cross context virtual CPU structure.
6493 * @param pVmxTransient The VMX-transient structure.
6494 *
6495 * @remarks Will import guest CR0 on strict builds during validation of
6496 * segments.
6497 * @remarks No-long-jump zone!!!
6498 */
6499static int hmR0VmxExportGuestSegRegsXdtr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6500{
6501 int rc = VERR_INTERNAL_ERROR_5;
6502 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6503 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6504 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6505 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
6506
6507 /*
6508 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
6509 */
6510 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SREG_MASK)
6511 {
6512 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CS)
6513 {
6514 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CS);
6515 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6516 pVmcsInfoShared->RealMode.AttrCS.u = pCtx->cs.Attr.u;
6517 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_CS, &pCtx->cs);
6518 AssertRC(rc);
6519 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CS);
6520 }
6521
6522 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SS)
6523 {
6524 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SS);
6525 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6526 pVmcsInfoShared->RealMode.AttrSS.u = pCtx->ss.Attr.u;
6527 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_SS, &pCtx->ss);
6528 AssertRC(rc);
6529 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SS);
6530 }
6531
6532 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_DS)
6533 {
6534 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DS);
6535 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6536 pVmcsInfoShared->RealMode.AttrDS.u = pCtx->ds.Attr.u;
6537 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_DS, &pCtx->ds);
6538 AssertRC(rc);
6539 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_DS);
6540 }
6541
6542 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_ES)
6543 {
6544 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_ES);
6545 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6546 pVmcsInfoShared->RealMode.AttrES.u = pCtx->es.Attr.u;
6547 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_ES, &pCtx->es);
6548 AssertRC(rc);
6549 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_ES);
6550 }
6551
6552 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_FS)
6553 {
6554 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_FS);
6555 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6556 pVmcsInfoShared->RealMode.AttrFS.u = pCtx->fs.Attr.u;
6557 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_FS, &pCtx->fs);
6558 AssertRC(rc);
6559 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_FS);
6560 }
6561
6562 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GS)
6563 {
6564 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GS);
6565 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6566 pVmcsInfoShared->RealMode.AttrGS.u = pCtx->gs.Attr.u;
6567 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_GS, &pCtx->gs);
6568 AssertRC(rc);
6569 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GS);
6570 }
6571
6572#ifdef VBOX_STRICT
6573 hmR0VmxValidateSegmentRegs(pVCpu, pVmcsInfo);
6574#endif
6575 Log4Func(("cs={%#04x base=%#RX64 limit=%#RX32 attr=%#RX32}\n", pCtx->cs.Sel, pCtx->cs.u64Base, pCtx->cs.u32Limit,
6576 pCtx->cs.Attr.u));
6577 }
6578
6579 /*
6580 * Guest TR.
6581 */
6582 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_TR)
6583 {
6584 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_TR);
6585
6586 /*
6587 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is
6588 * achieved using the interrupt redirection bitmap (all bits cleared to let the guest
6589 * handle INT-n's) in the TSS. See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
6590 */
6591 uint16_t u16Sel;
6592 uint32_t u32Limit;
6593 uint64_t u64Base;
6594 uint32_t u32AccessRights;
6595 if (!pVmcsInfoShared->RealMode.fRealOnV86Active)
6596 {
6597 u16Sel = pCtx->tr.Sel;
6598 u32Limit = pCtx->tr.u32Limit;
6599 u64Base = pCtx->tr.u64Base;
6600 u32AccessRights = pCtx->tr.Attr.u;
6601 }
6602 else
6603 {
6604 Assert(!pVmxTransient->fIsNestedGuest);
6605 Assert(pVM->hm.s.vmx.pRealModeTSS);
6606 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMCanExecuteGuest() -XXX- what about inner loop changes? */
6607
6608 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
6609 RTGCPHYS GCPhys;
6610 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
6611 AssertRCReturn(rc, rc);
6612
6613 X86DESCATTR DescAttr;
6614 DescAttr.u = 0;
6615 DescAttr.n.u1Present = 1;
6616 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
6617
6618 u16Sel = 0;
6619 u32Limit = HM_VTX_TSS_SIZE;
6620 u64Base = GCPhys;
6621 u32AccessRights = DescAttr.u;
6622 }
6623
6624 /* Validate. */
6625 Assert(!(u16Sel & RT_BIT(2)));
6626 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
6627 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
6628 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
6629 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
6630 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
6631 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
6632 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
6633 Assert( (u32Limit & 0xfff) == 0xfff
6634 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
6635 Assert( !(pCtx->tr.u32Limit & 0xfff00000)
6636 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
6637
6638 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_TR_SEL, u16Sel); AssertRC(rc);
6639 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit); AssertRC(rc);
6640 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights); AssertRC(rc);
6641 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_TR_BASE, u64Base); AssertRC(rc);
6642
6643 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_TR);
6644 Log4Func(("tr base=%#RX64 limit=%#RX32\n", pCtx->tr.u64Base, pCtx->tr.u32Limit));
6645 }
6646
6647 /*
6648 * Guest GDTR.
6649 */
6650 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GDTR)
6651 {
6652 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GDTR);
6653
6654 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt); AssertRC(rc);
6655 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, pCtx->gdtr.pGdt); AssertRC(rc);
6656
6657 /* Validate. */
6658 Assert(!(pCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6659
6660 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GDTR);
6661 Log4Func(("gdtr base=%#RX64 limit=%#RX32\n", pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt));
6662 }
6663
6664 /*
6665 * Guest LDTR.
6666 */
6667 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_LDTR)
6668 {
6669 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_LDTR);
6670
6671 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
6672 uint32_t u32Access;
6673 if ( !pVmxTransient->fIsNestedGuest
6674 && !pCtx->ldtr.Attr.u)
6675 u32Access = X86DESCATTR_UNUSABLE;
6676 else
6677 u32Access = pCtx->ldtr.Attr.u;
6678
6679 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, pCtx->ldtr.Sel); AssertRC(rc);
6680 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtr.u32Limit); AssertRC(rc);
6681 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access); AssertRC(rc);
6682 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, pCtx->ldtr.u64Base); AssertRC(rc);
6683
6684 /* Validate. */
6685 if (!(u32Access & X86DESCATTR_UNUSABLE))
6686 {
6687 Assert(!(pCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
6688 Assert(pCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
6689 Assert(!pCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
6690 Assert(pCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
6691 Assert(!pCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
6692 Assert(!(pCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
6693 Assert( (pCtx->ldtr.u32Limit & 0xfff) == 0xfff
6694 || !pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
6695 Assert( !(pCtx->ldtr.u32Limit & 0xfff00000)
6696 || pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
6697 }
6698
6699 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_LDTR);
6700 Log4Func(("ldtr base=%#RX64 limit=%#RX32\n", pCtx->ldtr.u64Base, pCtx->ldtr.u32Limit));
6701 }
6702
6703 /*
6704 * Guest IDTR.
6705 */
6706 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_IDTR)
6707 {
6708 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_IDTR);
6709
6710 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt); AssertRC(rc);
6711 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, pCtx->idtr.pIdt); AssertRC(rc);
6712
6713 /* Validate. */
6714 Assert(!(pCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6715
6716 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_IDTR);
6717 Log4Func(("idtr base=%#RX64 limit=%#RX32\n", pCtx->idtr.pIdt, pCtx->idtr.cbIdt));
6718 }
6719
6720 return VINF_SUCCESS;
6721}
6722
6723
6724/**
6725 * Exports certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
6726 * areas.
6727 *
6728 * These MSRs will automatically be loaded to the host CPU on every successful
6729 * VM-entry and stored from the host CPU on every successful VM-exit.
6730 *
6731 * We creates/updates MSR slots for the host MSRs in the VM-exit MSR-load area. The
6732 * actual host MSR values are not- updated here for performance reasons. See
6733 * hmR0VmxExportHostMsrs().
6734 *
6735 * We also exports the guest sysenter MSRs into the guest-state area in the VMCS.
6736 *
6737 * @returns VBox status code.
6738 * @param pVCpu The cross context virtual CPU structure.
6739 * @param pVmxTransient The VMX-transient structure.
6740 *
6741 * @remarks No-long-jump zone!!!
6742 */
6743static int hmR0VmxExportGuestMsrs(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6744{
6745 AssertPtr(pVCpu);
6746 AssertPtr(pVmxTransient);
6747
6748 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6749 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6750
6751 /*
6752 * MSRs that we use the auto-load/store MSR area in the VMCS.
6753 * For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(),
6754 * nothing to do here. The host MSR values are updated when it's safe in
6755 * hmR0VmxLazySaveHostMsrs().
6756 *
6757 * For nested-guests, the guests MSRs from the VM-entry MSR-load area are already
6758 * loaded (into the guest-CPU context) by the VMLAUNCH/VMRESUME instruction
6759 * emulation. The merged MSR permission bitmap will ensure that we get VM-exits
6760 * for any MSR that are not part of the lazy MSRs so we do not need to place
6761 * those MSRs into the auto-load/store MSR area. Nothing to do here.
6762 */
6763 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_GUEST_AUTO_MSRS)
6764 {
6765 /* No auto-load/store MSRs currently. */
6766 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_GUEST_AUTO_MSRS);
6767 }
6768
6769 /*
6770 * Guest Sysenter MSRs.
6771 */
6772 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_MSR_MASK)
6773 {
6774 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SYSENTER_MSRS);
6775
6776 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_CS_MSR)
6777 {
6778 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pCtx->SysEnter.cs);
6779 AssertRC(rc);
6780 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_CS_MSR);
6781 }
6782
6783 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_EIP_MSR)
6784 {
6785 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, pCtx->SysEnter.eip);
6786 AssertRC(rc);
6787 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
6788 }
6789
6790 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_ESP_MSR)
6791 {
6792 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, pCtx->SysEnter.esp);
6793 AssertRC(rc);
6794 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
6795 }
6796 }
6797
6798 /*
6799 * Guest/host EFER MSR.
6800 */
6801 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_EFER_MSR)
6802 {
6803 /* Whether we are using the VMCS to swap the EFER MSR must have been
6804 determined earlier while exporting VM-entry/VM-exit controls. */
6805 Assert(!(ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS));
6806 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
6807
6808 if (hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
6809 {
6810 /*
6811 * EFER.LME is written by software, while EFER.LMA is set by the CPU to (CR0.PG & EFER.LME).
6812 * This means a guest can set EFER.LME=1 while CR0.PG=0 and EFER.LMA can remain 0.
6813 * VT-x requires that "IA-32e mode guest" VM-entry control must be identical to EFER.LMA
6814 * and to CR0.PG. Without unrestricted execution, CR0.PG (used for VT-x, not the shadow)
6815 * must always be 1. This forces us to effectively clear both EFER.LMA and EFER.LME until
6816 * the guest has also set CR0.PG=1. Otherwise, we would run into an invalid-guest state
6817 * during VM-entry.
6818 */
6819 uint64_t uGuestEferMsr = pCtx->msrEFER;
6820 if (!pVM->hmr0.s.vmx.fUnrestrictedGuest)
6821 {
6822 if (!(pCtx->msrEFER & MSR_K6_EFER_LMA))
6823 uGuestEferMsr &= ~MSR_K6_EFER_LME;
6824 else
6825 Assert((pCtx->msrEFER & (MSR_K6_EFER_LMA | MSR_K6_EFER_LME)) == (MSR_K6_EFER_LMA | MSR_K6_EFER_LME));
6826 }
6827
6828 /*
6829 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
6830 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
6831 */
6832 if (g_fHmVmxSupportsVmcsEfer)
6833 {
6834 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, uGuestEferMsr);
6835 AssertRC(rc);
6836 }
6837 else
6838 {
6839 /*
6840 * We shall use the auto-load/store MSR area only for loading the EFER MSR but we must
6841 * continue to intercept guest read and write accesses to it, see @bugref{7386#c16}.
6842 */
6843 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER, uGuestEferMsr,
6844 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6845 AssertRCReturn(rc, rc);
6846 }
6847
6848 Log4Func(("efer=%#RX64 shadow=%#RX64\n", uGuestEferMsr, pCtx->msrEFER));
6849 }
6850 else if (!g_fHmVmxSupportsVmcsEfer)
6851 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER);
6852
6853 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_EFER_MSR);
6854 }
6855
6856 /*
6857 * Other MSRs.
6858 */
6859 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_OTHER_MSRS)
6860 {
6861 /* Speculation Control (R/W). */
6862 HMVMX_CPUMCTX_ASSERT(pVCpu, HM_CHANGED_GUEST_OTHER_MSRS);
6863 if (pVM->cpum.ro.GuestFeatures.fIbrs)
6864 {
6865 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_IA32_SPEC_CTRL, CPUMGetGuestSpecCtrl(pVCpu),
6866 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6867 AssertRCReturn(rc, rc);
6868 }
6869
6870 /* Last Branch Record. */
6871 if (pVM->hmr0.s.vmx.fLbr)
6872 {
6873 PVMXVMCSINFOSHARED const pVmcsInfoShared = pVmxTransient->pVmcsInfo->pShared;
6874 uint32_t const idFromIpMsrStart = pVM->hmr0.s.vmx.idLbrFromIpMsrFirst;
6875 uint32_t const idToIpMsrStart = pVM->hmr0.s.vmx.idLbrToIpMsrFirst;
6876 uint32_t const cLbrStack = pVM->hmr0.s.vmx.idLbrFromIpMsrLast - pVM->hmr0.s.vmx.idLbrFromIpMsrFirst + 1;
6877 Assert(cLbrStack <= 32);
6878 for (uint32_t i = 0; i < cLbrStack; i++)
6879 {
6880 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, idFromIpMsrStart + i,
6881 pVmcsInfoShared->au64LbrFromIpMsr[i],
6882 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6883 AssertRCReturn(rc, rc);
6884
6885 /* Some CPUs don't have a Branch-To-IP MSR (P4 and related Xeons). */
6886 if (idToIpMsrStart != 0)
6887 {
6888 rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, idToIpMsrStart + i,
6889 pVmcsInfoShared->au64LbrToIpMsr[i],
6890 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6891 AssertRCReturn(rc, rc);
6892 }
6893 }
6894
6895 /* Add LBR top-of-stack MSR (which contains the index to the most recent record). */
6896 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, pVM->hmr0.s.vmx.idLbrTosMsr,
6897 pVmcsInfoShared->u64LbrTosMsr, false /* fSetReadWrite */,
6898 false /* fUpdateHostMsr */);
6899 AssertRCReturn(rc, rc);
6900 }
6901
6902 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
6903 }
6904
6905 return VINF_SUCCESS;
6906}
6907
6908
6909/**
6910 * Wrapper for running the guest code in VT-x.
6911 *
6912 * @returns VBox status code, no informational status codes.
6913 * @param pVCpu The cross context virtual CPU structure.
6914 * @param pVmxTransient The VMX-transient structure.
6915 *
6916 * @remarks No-long-jump zone!!!
6917 */
6918DECLINLINE(int) hmR0VmxRunGuest(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6919{
6920 /* Mark that HM is the keeper of all guest-CPU registers now that we're going to execute guest code. */
6921 pVCpu->cpum.GstCtx.fExtrn |= HMVMX_CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_KEEPER_HM;
6922
6923 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6924 bool const fResumeVM = RT_BOOL(pVmcsInfo->fVmcsState & VMX_V_VMCS_LAUNCH_STATE_LAUNCHED);
6925#ifdef VBOX_WITH_STATISTICS
6926 if (fResumeVM)
6927 STAM_COUNTER_INC(&pVCpu->hm.s.StatVmxVmResume);
6928 else
6929 STAM_COUNTER_INC(&pVCpu->hm.s.StatVmxVmLaunch);
6930#endif
6931 int rc = pVCpu->hmr0.s.vmx.pfnStartVm(pVmcsInfo, pVCpu, fResumeVM);
6932 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
6933 return rc;
6934}
6935
6936
6937/**
6938 * Reports world-switch error and dumps some useful debug info.
6939 *
6940 * @param pVCpu The cross context virtual CPU structure.
6941 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
6942 * @param pVmxTransient The VMX-transient structure (only
6943 * exitReason updated).
6944 */
6945static void hmR0VmxReportWorldSwitchError(PVMCPUCC pVCpu, int rcVMRun, PVMXTRANSIENT pVmxTransient)
6946{
6947 Assert(pVCpu);
6948 Assert(pVmxTransient);
6949 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
6950
6951 Log4Func(("VM-entry failure: %Rrc\n", rcVMRun));
6952 switch (rcVMRun)
6953 {
6954 case VERR_VMX_INVALID_VMXON_PTR:
6955 AssertFailed();
6956 break;
6957 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
6958 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
6959 {
6960 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
6961 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
6962 AssertRC(rc);
6963 hmR0VmxReadExitQualVmcs(pVmxTransient);
6964
6965 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hmr0.s.idEnteredCpu;
6966 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
6967 Cannot do it here as we may have been long preempted. */
6968
6969#ifdef VBOX_STRICT
6970 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6971 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
6972 pVmxTransient->uExitReason));
6973 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQual));
6974 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
6975 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
6976 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
6977 else
6978 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
6979 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
6980 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
6981
6982 static struct
6983 {
6984 /** Name of the field to log. */
6985 const char *pszName;
6986 /** The VMCS field. */
6987 uint32_t uVmcsField;
6988 /** Whether host support of this field needs to be checked. */
6989 bool fCheckSupport;
6990 } const s_aVmcsFields[] =
6991 {
6992 { "VMX_VMCS32_CTRL_PIN_EXEC", VMX_VMCS32_CTRL_PIN_EXEC, false },
6993 { "VMX_VMCS32_CTRL_PROC_EXEC", VMX_VMCS32_CTRL_PROC_EXEC, false },
6994 { "VMX_VMCS32_CTRL_PROC_EXEC2", VMX_VMCS32_CTRL_PROC_EXEC2, true },
6995 { "VMX_VMCS32_CTRL_ENTRY", VMX_VMCS32_CTRL_ENTRY, false },
6996 { "VMX_VMCS32_CTRL_EXIT", VMX_VMCS32_CTRL_EXIT, false },
6997 { "VMX_VMCS32_CTRL_CR3_TARGET_COUNT", VMX_VMCS32_CTRL_CR3_TARGET_COUNT, false },
6998 { "VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO", VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, false },
6999 { "VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE", VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, false },
7000 { "VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH", VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, false },
7001 { "VMX_VMCS32_CTRL_TPR_THRESHOLD", VMX_VMCS32_CTRL_TPR_THRESHOLD, false },
7002 { "VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, false },
7003 { "VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, false },
7004 { "VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, false },
7005 { "VMX_VMCS32_CTRL_EXCEPTION_BITMAP", VMX_VMCS32_CTRL_EXCEPTION_BITMAP, false },
7006 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, false },
7007 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, false },
7008 { "VMX_VMCS_CTRL_CR0_MASK", VMX_VMCS_CTRL_CR0_MASK, false },
7009 { "VMX_VMCS_CTRL_CR0_READ_SHADOW", VMX_VMCS_CTRL_CR0_READ_SHADOW, false },
7010 { "VMX_VMCS_CTRL_CR4_MASK", VMX_VMCS_CTRL_CR4_MASK, false },
7011 { "VMX_VMCS_CTRL_CR4_READ_SHADOW", VMX_VMCS_CTRL_CR4_READ_SHADOW, false },
7012 { "VMX_VMCS64_CTRL_EPTP_FULL", VMX_VMCS64_CTRL_EPTP_FULL, true },
7013 { "VMX_VMCS_GUEST_RIP", VMX_VMCS_GUEST_RIP, false },
7014 { "VMX_VMCS_GUEST_RSP", VMX_VMCS_GUEST_RSP, false },
7015 { "VMX_VMCS_GUEST_RFLAGS", VMX_VMCS_GUEST_RFLAGS, false },
7016 { "VMX_VMCS16_VPID", VMX_VMCS16_VPID, true, },
7017 { "VMX_VMCS_HOST_CR0", VMX_VMCS_HOST_CR0, false },
7018 { "VMX_VMCS_HOST_CR3", VMX_VMCS_HOST_CR3, false },
7019 { "VMX_VMCS_HOST_CR4", VMX_VMCS_HOST_CR4, false },
7020 /* The order of selector fields below are fixed! */
7021 { "VMX_VMCS16_HOST_ES_SEL", VMX_VMCS16_HOST_ES_SEL, false },
7022 { "VMX_VMCS16_HOST_CS_SEL", VMX_VMCS16_HOST_CS_SEL, false },
7023 { "VMX_VMCS16_HOST_SS_SEL", VMX_VMCS16_HOST_SS_SEL, false },
7024 { "VMX_VMCS16_HOST_DS_SEL", VMX_VMCS16_HOST_DS_SEL, false },
7025 { "VMX_VMCS16_HOST_FS_SEL", VMX_VMCS16_HOST_FS_SEL, false },
7026 { "VMX_VMCS16_HOST_GS_SEL", VMX_VMCS16_HOST_GS_SEL, false },
7027 { "VMX_VMCS16_HOST_TR_SEL", VMX_VMCS16_HOST_TR_SEL, false },
7028 /* End of ordered selector fields. */
7029 { "VMX_VMCS_HOST_TR_BASE", VMX_VMCS_HOST_TR_BASE, false },
7030 { "VMX_VMCS_HOST_GDTR_BASE", VMX_VMCS_HOST_GDTR_BASE, false },
7031 { "VMX_VMCS_HOST_IDTR_BASE", VMX_VMCS_HOST_IDTR_BASE, false },
7032 { "VMX_VMCS32_HOST_SYSENTER_CS", VMX_VMCS32_HOST_SYSENTER_CS, false },
7033 { "VMX_VMCS_HOST_SYSENTER_EIP", VMX_VMCS_HOST_SYSENTER_EIP, false },
7034 { "VMX_VMCS_HOST_SYSENTER_ESP", VMX_VMCS_HOST_SYSENTER_ESP, false },
7035 { "VMX_VMCS_HOST_RSP", VMX_VMCS_HOST_RSP, false },
7036 { "VMX_VMCS_HOST_RIP", VMX_VMCS_HOST_RIP, false }
7037 };
7038
7039 RTGDTR HostGdtr;
7040 ASMGetGDTR(&HostGdtr);
7041
7042 uint32_t const cVmcsFields = RT_ELEMENTS(s_aVmcsFields);
7043 for (uint32_t i = 0; i < cVmcsFields; i++)
7044 {
7045 uint32_t const uVmcsField = s_aVmcsFields[i].uVmcsField;
7046
7047 bool fSupported;
7048 if (!s_aVmcsFields[i].fCheckSupport)
7049 fSupported = true;
7050 else
7051 {
7052 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7053 switch (uVmcsField)
7054 {
7055 case VMX_VMCS64_CTRL_EPTP_FULL: fSupported = pVM->hmr0.s.fNestedPaging; break;
7056 case VMX_VMCS16_VPID: fSupported = pVM->hmr0.s.vmx.fVpid; break;
7057 case VMX_VMCS32_CTRL_PROC_EXEC2:
7058 fSupported = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
7059 break;
7060 default:
7061 AssertMsgFailedReturnVoid(("Failed to provide VMCS field support for %#RX32\n", uVmcsField));
7062 }
7063 }
7064
7065 if (fSupported)
7066 {
7067 uint8_t const uWidth = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH);
7068 switch (uWidth)
7069 {
7070 case VMX_VMCSFIELD_WIDTH_16BIT:
7071 {
7072 uint16_t u16Val;
7073 rc = VMXReadVmcs16(uVmcsField, &u16Val);
7074 AssertRC(rc);
7075 Log4(("%-40s = %#RX16\n", s_aVmcsFields[i].pszName, u16Val));
7076
7077 if ( uVmcsField >= VMX_VMCS16_HOST_ES_SEL
7078 && uVmcsField <= VMX_VMCS16_HOST_TR_SEL)
7079 {
7080 if (u16Val < HostGdtr.cbGdt)
7081 {
7082 /* Order of selectors in s_apszSel is fixed and matches the order in s_aVmcsFields. */
7083 static const char * const s_apszSel[] = { "Host ES", "Host CS", "Host SS", "Host DS",
7084 "Host FS", "Host GS", "Host TR" };
7085 uint8_t const idxSel = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_INDEX);
7086 Assert(idxSel < RT_ELEMENTS(s_apszSel));
7087 PCX86DESCHC pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u16Val & X86_SEL_MASK));
7088 hmR0DumpDescriptor(pDesc, u16Val, s_apszSel[idxSel]);
7089 }
7090 else
7091 Log4((" Selector value exceeds GDT limit!\n"));
7092 }
7093 break;
7094 }
7095
7096 case VMX_VMCSFIELD_WIDTH_32BIT:
7097 {
7098 uint32_t u32Val;
7099 rc = VMXReadVmcs32(uVmcsField, &u32Val);
7100 AssertRC(rc);
7101 Log4(("%-40s = %#RX32\n", s_aVmcsFields[i].pszName, u32Val));
7102 break;
7103 }
7104
7105 case VMX_VMCSFIELD_WIDTH_64BIT:
7106 case VMX_VMCSFIELD_WIDTH_NATURAL:
7107 {
7108 uint64_t u64Val;
7109 rc = VMXReadVmcs64(uVmcsField, &u64Val);
7110 AssertRC(rc);
7111 Log4(("%-40s = %#RX64\n", s_aVmcsFields[i].pszName, u64Val));
7112 break;
7113 }
7114 }
7115 }
7116 }
7117
7118 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
7119 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
7120 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
7121 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
7122 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
7123 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
7124#endif /* VBOX_STRICT */
7125 break;
7126 }
7127
7128 default:
7129 /* Impossible */
7130 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
7131 break;
7132 }
7133}
7134
7135
7136/**
7137 * Sets up the usage of TSC-offsetting and updates the VMCS.
7138 *
7139 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
7140 * VMX-preemption timer.
7141 *
7142 * @returns VBox status code.
7143 * @param pVCpu The cross context virtual CPU structure.
7144 * @param pVmxTransient The VMX-transient structure.
7145 * @param idCurrentCpu The current CPU number.
7146 *
7147 * @remarks No-long-jump zone!!!
7148 */
7149static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, RTCPUID idCurrentCpu)
7150{
7151 bool fOffsettedTsc;
7152 bool fParavirtTsc;
7153 uint64_t uTscOffset;
7154 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7155 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7156
7157 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
7158 {
7159 /* The TMCpuTickGetDeadlineAndTscOffset function is expensive (calling it on
7160 every entry slowed down the bs2-test1 CPUID testcase by ~33% (on an 10980xe). */
7161 uint64_t cTicksToDeadline;
7162 if ( idCurrentCpu == pVCpu->hmr0.s.idLastCpu
7163 && TMVirtualSyncIsCurrentDeadlineVersion(pVM, pVCpu->hmr0.s.vmx.uTscDeadlineVersion))
7164 {
7165 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatVmxPreemptionReusingDeadline);
7166 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
7167 cTicksToDeadline = pVCpu->hmr0.s.vmx.uTscDeadline - SUPReadTsc();
7168 if ((int64_t)cTicksToDeadline > 0)
7169 { /* hopefully */ }
7170 else
7171 {
7172 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatVmxPreemptionReusingDeadlineExpired);
7173 cTicksToDeadline = 0;
7174 }
7175 }
7176 else
7177 {
7178 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatVmxPreemptionRecalcingDeadline);
7179 cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &uTscOffset, &fOffsettedTsc, &fParavirtTsc,
7180 &pVCpu->hmr0.s.vmx.uTscDeadline,
7181 &pVCpu->hmr0.s.vmx.uTscDeadlineVersion);
7182 pVCpu->hmr0.s.vmx.uTscDeadline += cTicksToDeadline;
7183 if (cTicksToDeadline >= 128)
7184 { /* hopefully */ }
7185 else
7186 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatVmxPreemptionRecalcingDeadlineExpired);
7187 }
7188
7189 /* Make sure the returned values have sane upper and lower boundaries. */
7190 uint64_t const u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
7191 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second, 15.625ms. */ /** @todo r=bird: Once real+virtual timers move to separate thread, we can raise the upper limit (16ms isn't much). ASSUMES working poke cpu function. */
7192 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 32678); /* 1/32768th of a second, ~30us. */
7193 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
7194
7195 /** @todo r=ramshankar: We need to find a way to integrate nested-guest
7196 * preemption timers here. We probably need to clamp the preemption timer,
7197 * after converting the timer value to the host. */
7198 uint32_t const cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
7199 int rc = VMXWriteVmcs32(VMX_VMCS32_PREEMPT_TIMER_VALUE, cPreemptionTickCount);
7200 AssertRC(rc);
7201 }
7202 else
7203 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
7204
7205 if (fParavirtTsc)
7206 {
7207 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
7208 information before every VM-entry, hence disable it for performance sake. */
7209#if 0
7210 int rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
7211 AssertRC(rc);
7212#endif
7213 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
7214 }
7215
7216 if ( fOffsettedTsc
7217 && RT_LIKELY(!pVCpu->hmr0.s.fDebugWantRdTscExit))
7218 {
7219 if (pVmxTransient->fIsNestedGuest)
7220 uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
7221 hmR0VmxSetTscOffsetVmcs(pVmcsInfo, uTscOffset);
7222 hmR0VmxRemoveProcCtlsVmcs(pVCpu, pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
7223 }
7224 else
7225 {
7226 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
7227 hmR0VmxSetProcCtlsVmcs(pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
7228 }
7229}
7230
7231
7232/**
7233 * Gets the IEM exception flags for the specified vector and IDT vectoring /
7234 * VM-exit interruption info type.
7235 *
7236 * @returns The IEM exception flags.
7237 * @param uVector The event vector.
7238 * @param uVmxEventType The VMX event type.
7239 *
7240 * @remarks This function currently only constructs flags required for
7241 * IEMEvaluateRecursiveXcpt and not the complete flags (e.g, error-code
7242 * and CR2 aspects of an exception are not included).
7243 */
7244static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxEventType)
7245{
7246 uint32_t fIemXcptFlags;
7247 switch (uVmxEventType)
7248 {
7249 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
7250 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
7251 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
7252 break;
7253
7254 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
7255 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
7256 break;
7257
7258 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
7259 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
7260 break;
7261
7262 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
7263 {
7264 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
7265 if (uVector == X86_XCPT_BP)
7266 fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
7267 else if (uVector == X86_XCPT_OF)
7268 fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
7269 else
7270 {
7271 fIemXcptFlags = 0;
7272 AssertMsgFailed(("Unexpected vector for software exception. uVector=%#x", uVector));
7273 }
7274 break;
7275 }
7276
7277 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
7278 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
7279 break;
7280
7281 default:
7282 fIemXcptFlags = 0;
7283 AssertMsgFailed(("Unexpected vector type! uVmxEventType=%#x uVector=%#x", uVmxEventType, uVector));
7284 break;
7285 }
7286 return fIemXcptFlags;
7287}
7288
7289
7290/**
7291 * Sets an event as a pending event to be injected into the guest.
7292 *
7293 * @param pVCpu The cross context virtual CPU structure.
7294 * @param u32IntInfo The VM-entry interruption-information field.
7295 * @param cbInstr The VM-entry instruction length in bytes (for
7296 * software interrupts, exceptions and privileged
7297 * software exceptions).
7298 * @param u32ErrCode The VM-entry exception error code.
7299 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
7300 * page-fault.
7301 */
7302DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPUCC pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
7303 RTGCUINTPTR GCPtrFaultAddress)
7304{
7305 Assert(!pVCpu->hm.s.Event.fPending);
7306 pVCpu->hm.s.Event.fPending = true;
7307 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
7308 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
7309 pVCpu->hm.s.Event.cbInstr = cbInstr;
7310 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
7311}
7312
7313
7314/**
7315 * Sets an external interrupt as pending-for-injection into the VM.
7316 *
7317 * @param pVCpu The cross context virtual CPU structure.
7318 * @param u8Interrupt The external interrupt vector.
7319 */
7320DECLINLINE(void) hmR0VmxSetPendingExtInt(PVMCPUCC pVCpu, uint8_t u8Interrupt)
7321{
7322 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, u8Interrupt)
7323 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
7324 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7325 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7326 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7327}
7328
7329
7330/**
7331 * Sets an NMI (\#NMI) exception as pending-for-injection into the VM.
7332 *
7333 * @param pVCpu The cross context virtual CPU structure.
7334 */
7335DECLINLINE(void) hmR0VmxSetPendingXcptNmi(PVMCPUCC pVCpu)
7336{
7337 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI)
7338 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI)
7339 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7340 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7341 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7342}
7343
7344
7345/**
7346 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
7347 *
7348 * @param pVCpu The cross context virtual CPU structure.
7349 */
7350DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPUCC pVCpu)
7351{
7352 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
7353 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7354 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
7355 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7356 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7357}
7358
7359
7360/**
7361 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
7362 *
7363 * @param pVCpu The cross context virtual CPU structure.
7364 */
7365DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPUCC pVCpu)
7366{
7367 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_UD)
7368 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7369 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7370 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7371 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7372}
7373
7374
7375/**
7376 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
7377 *
7378 * @param pVCpu The cross context virtual CPU structure.
7379 */
7380DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPUCC pVCpu)
7381{
7382 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
7383 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7384 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7385 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7386 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7387}
7388
7389
7390#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7391/**
7392 * Sets a general-protection (\#GP) exception as pending-for-injection into the VM.
7393 *
7394 * @param pVCpu The cross context virtual CPU structure.
7395 * @param u32ErrCode The error code for the general-protection exception.
7396 */
7397DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPUCC pVCpu, uint32_t u32ErrCode)
7398{
7399 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
7400 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7401 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
7402 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7403 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
7404}
7405
7406
7407/**
7408 * Sets a stack (\#SS) exception as pending-for-injection into the VM.
7409 *
7410 * @param pVCpu The cross context virtual CPU structure.
7411 * @param u32ErrCode The error code for the stack exception.
7412 */
7413DECLINLINE(void) hmR0VmxSetPendingXcptSS(PVMCPUCC pVCpu, uint32_t u32ErrCode)
7414{
7415 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_SS)
7416 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7417 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
7418 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7419 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
7420}
7421#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
7422
7423
7424/**
7425 * Fixes up attributes for the specified segment register.
7426 *
7427 * @param pVCpu The cross context virtual CPU structure.
7428 * @param pSelReg The segment register that needs fixing.
7429 * @param pszRegName The register name (for logging and assertions).
7430 */
7431static void hmR0VmxFixUnusableSegRegAttr(PVMCPUCC pVCpu, PCPUMSELREG pSelReg, const char *pszRegName)
7432{
7433 Assert(pSelReg->Attr.u & X86DESCATTR_UNUSABLE);
7434
7435 /*
7436 * If VT-x marks the segment as unusable, most other bits remain undefined:
7437 * - For CS the L, D and G bits have meaning.
7438 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
7439 * - For the remaining data segments no bits are defined.
7440 *
7441 * The present bit and the unusable bit has been observed to be set at the
7442 * same time (the selector was supposed to be invalid as we started executing
7443 * a V8086 interrupt in ring-0).
7444 *
7445 * What should be important for the rest of the VBox code, is that the P bit is
7446 * cleared. Some of the other VBox code recognizes the unusable bit, but
7447 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
7448 * safe side here, we'll strip off P and other bits we don't care about. If
7449 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
7450 *
7451 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
7452 */
7453#ifdef VBOX_STRICT
7454 uint32_t const uAttr = pSelReg->Attr.u;
7455#endif
7456
7457 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
7458 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
7459 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
7460
7461#ifdef VBOX_STRICT
7462 VMMRZCallRing3Disable(pVCpu);
7463 Log4Func(("Unusable %s: sel=%#x attr=%#x -> %#x\n", pszRegName, pSelReg->Sel, uAttr, pSelReg->Attr.u));
7464# ifdef DEBUG_bird
7465 AssertMsg((uAttr & ~X86DESCATTR_P) == pSelReg->Attr.u,
7466 ("%s: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
7467 pszRegName, uAttr, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
7468# endif
7469 VMMRZCallRing3Enable(pVCpu);
7470 NOREF(uAttr);
7471#endif
7472 RT_NOREF2(pVCpu, pszRegName);
7473}
7474
7475
7476/**
7477 * Imports a guest segment register from the current VMCS into the guest-CPU
7478 * context.
7479 *
7480 * @param pVCpu The cross context virtual CPU structure.
7481 * @param iSegReg The segment register number (X86_SREG_XXX).
7482 *
7483 * @remarks Called with interrupts and/or preemption disabled.
7484 */
7485static void hmR0VmxImportGuestSegReg(PVMCPUCC pVCpu, uint32_t iSegReg)
7486{
7487 Assert(iSegReg < X86_SREG_COUNT);
7488 Assert((uint32_t)VMX_VMCS16_GUEST_SEG_SEL(iSegReg) == g_aVmcsSegSel[iSegReg]);
7489 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg) == g_aVmcsSegLimit[iSegReg]);
7490 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg) == g_aVmcsSegAttr[iSegReg]);
7491 Assert((uint32_t)VMX_VMCS_GUEST_SEG_BASE(iSegReg) == g_aVmcsSegBase[iSegReg]);
7492
7493 PCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
7494
7495 uint16_t u16Sel;
7496 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_SEG_SEL(iSegReg), &u16Sel); AssertRC(rc);
7497 pSelReg->Sel = u16Sel;
7498 pSelReg->ValidSel = u16Sel;
7499
7500 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg), &pSelReg->u32Limit); AssertRC(rc);
7501 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SEG_BASE(iSegReg), &pSelReg->u64Base); AssertRC(rc);
7502
7503 uint32_t u32Attr;
7504 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg), &u32Attr); AssertRC(rc);
7505 pSelReg->Attr.u = u32Attr;
7506 if (u32Attr & X86DESCATTR_UNUSABLE)
7507 hmR0VmxFixUnusableSegRegAttr(pVCpu, pSelReg, "ES\0CS\0SS\0DS\0FS\0GS" + iSegReg * 3);
7508
7509 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
7510}
7511
7512
7513/**
7514 * Imports the guest LDTR from the current VMCS into the guest-CPU context.
7515 *
7516 * @param pVCpu The cross context virtual CPU structure.
7517 *
7518 * @remarks Called with interrupts and/or preemption disabled.
7519 */
7520static void hmR0VmxImportGuestLdtr(PVMCPUCC pVCpu)
7521{
7522 uint16_t u16Sel;
7523 uint64_t u64Base;
7524 uint32_t u32Limit, u32Attr;
7525 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, &u16Sel); AssertRC(rc);
7526 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, &u32Limit); AssertRC(rc);
7527 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7528 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, &u64Base); AssertRC(rc);
7529
7530 pVCpu->cpum.GstCtx.ldtr.Sel = u16Sel;
7531 pVCpu->cpum.GstCtx.ldtr.ValidSel = u16Sel;
7532 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
7533 pVCpu->cpum.GstCtx.ldtr.u32Limit = u32Limit;
7534 pVCpu->cpum.GstCtx.ldtr.u64Base = u64Base;
7535 pVCpu->cpum.GstCtx.ldtr.Attr.u = u32Attr;
7536 if (u32Attr & X86DESCATTR_UNUSABLE)
7537 hmR0VmxFixUnusableSegRegAttr(pVCpu, &pVCpu->cpum.GstCtx.ldtr, "LDTR");
7538}
7539
7540
7541/**
7542 * Imports the guest TR from the current VMCS into the guest-CPU context.
7543 *
7544 * @param pVCpu The cross context virtual CPU structure.
7545 *
7546 * @remarks Called with interrupts and/or preemption disabled.
7547 */
7548static void hmR0VmxImportGuestTr(PVMCPUCC pVCpu)
7549{
7550 uint16_t u16Sel;
7551 uint64_t u64Base;
7552 uint32_t u32Limit, u32Attr;
7553 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_TR_SEL, &u16Sel); AssertRC(rc);
7554 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, &u32Limit); AssertRC(rc);
7555 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7556 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_TR_BASE, &u64Base); AssertRC(rc);
7557
7558 pVCpu->cpum.GstCtx.tr.Sel = u16Sel;
7559 pVCpu->cpum.GstCtx.tr.ValidSel = u16Sel;
7560 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
7561 pVCpu->cpum.GstCtx.tr.u32Limit = u32Limit;
7562 pVCpu->cpum.GstCtx.tr.u64Base = u64Base;
7563 pVCpu->cpum.GstCtx.tr.Attr.u = u32Attr;
7564 /* TR is the only selector that can never be unusable. */
7565 Assert(!(u32Attr & X86DESCATTR_UNUSABLE));
7566}
7567
7568
7569/**
7570 * Imports the guest RIP from the VMCS back into the guest-CPU context.
7571 *
7572 * @param pVCpu The cross context virtual CPU structure.
7573 *
7574 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7575 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7576 * instead!!!
7577 */
7578static void hmR0VmxImportGuestRip(PVMCPUCC pVCpu)
7579{
7580 uint64_t u64Val;
7581 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7582 if (pCtx->fExtrn & CPUMCTX_EXTRN_RIP)
7583 {
7584 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
7585 AssertRC(rc);
7586
7587 pCtx->rip = u64Val;
7588 EMR0HistoryUpdatePC(pVCpu, pCtx->rip, false);
7589 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RIP;
7590 }
7591}
7592
7593
7594/**
7595 * Imports the guest RFLAGS from the VMCS back into the guest-CPU context.
7596 *
7597 * @param pVCpu The cross context virtual CPU structure.
7598 * @param pVmcsInfo The VMCS info. object.
7599 *
7600 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7601 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7602 * instead!!!
7603 */
7604static void hmR0VmxImportGuestRFlags(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7605{
7606 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7607 if (pCtx->fExtrn & CPUMCTX_EXTRN_RFLAGS)
7608 {
7609 uint64_t u64Val;
7610 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
7611 AssertRC(rc);
7612
7613 pCtx->rflags.u64 = u64Val;
7614 PCVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7615 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
7616 {
7617 pCtx->eflags.Bits.u1VM = 0;
7618 pCtx->eflags.Bits.u2IOPL = pVmcsInfoShared->RealMode.Eflags.Bits.u2IOPL;
7619 }
7620 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RFLAGS;
7621 }
7622}
7623
7624
7625/**
7626 * Imports the guest interruptibility-state from the VMCS back into the guest-CPU
7627 * context.
7628 *
7629 * @param pVCpu The cross context virtual CPU structure.
7630 * @param pVmcsInfo The VMCS info. object.
7631 *
7632 * @remarks Called with interrupts and/or preemption disabled, try not to assert and
7633 * do not log!
7634 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7635 * instead!!!
7636 */
7637static void hmR0VmxImportGuestIntrState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7638{
7639 uint32_t u32Val;
7640 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32Val); AssertRC(rc);
7641 if (!u32Val)
7642 {
7643 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7644 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7645 CPUMSetGuestNmiBlocking(pVCpu, false);
7646 }
7647 else
7648 {
7649 /*
7650 * We must import RIP here to set our EM interrupt-inhibited state.
7651 * We also import RFLAGS as our code that evaluates pending interrupts
7652 * before VM-entry requires it.
7653 */
7654 hmR0VmxImportGuestRip(pVCpu);
7655 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7656
7657 if (u32Val & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
7658 EMSetInhibitInterruptsPC(pVCpu, pVCpu->cpum.GstCtx.rip);
7659 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7660 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7661
7662 bool const fNmiBlocking = RT_BOOL(u32Val & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
7663 CPUMSetGuestNmiBlocking(pVCpu, fNmiBlocking);
7664 }
7665}
7666
7667
7668/**
7669 * Worker for VMXR0ImportStateOnDemand.
7670 *
7671 * @returns VBox status code.
7672 * @param pVCpu The cross context virtual CPU structure.
7673 * @param pVmcsInfo The VMCS info. object.
7674 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7675 */
7676static int hmR0VmxImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
7677{
7678 int rc = VINF_SUCCESS;
7679 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7680 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7681 uint32_t u32Val;
7682
7683 /*
7684 * Note! This is hack to workaround a mysterious BSOD observed with release builds
7685 * on Windows 10 64-bit hosts. Profile and debug builds are not affected and
7686 * neither are other host platforms.
7687 *
7688 * Committing this temporarily as it prevents BSOD.
7689 *
7690 * Update: This is very likely a compiler optimization bug, see @bugref{9180}.
7691 */
7692#ifdef RT_OS_WINDOWS
7693 if (pVM == 0 || pVM == (void *)(uintptr_t)-1)
7694 return VERR_HM_IPE_1;
7695#endif
7696
7697 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatImportGuestState, x);
7698
7699 /*
7700 * We disable interrupts to make the updating of the state and in particular
7701 * the fExtrn modification atomic wrt to preemption hooks.
7702 */
7703 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
7704
7705 fWhat &= pCtx->fExtrn;
7706 if (fWhat)
7707 {
7708 do
7709 {
7710 if (fWhat & CPUMCTX_EXTRN_RIP)
7711 hmR0VmxImportGuestRip(pVCpu);
7712
7713 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
7714 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7715
7716 if (fWhat & CPUMCTX_EXTRN_HM_VMX_INT_STATE)
7717 hmR0VmxImportGuestIntrState(pVCpu, pVmcsInfo);
7718
7719 if (fWhat & CPUMCTX_EXTRN_RSP)
7720 {
7721 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RSP, &pCtx->rsp);
7722 AssertRC(rc);
7723 }
7724
7725 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
7726 {
7727 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7728 bool const fRealOnV86Active = pVmcsInfoShared->RealMode.fRealOnV86Active;
7729 if (fWhat & CPUMCTX_EXTRN_CS)
7730 {
7731 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_CS);
7732 hmR0VmxImportGuestRip(pVCpu);
7733 if (fRealOnV86Active)
7734 pCtx->cs.Attr.u = pVmcsInfoShared->RealMode.AttrCS.u;
7735 EMR0HistoryUpdatePC(pVCpu, pCtx->cs.u64Base + pCtx->rip, true /* fFlattened */);
7736 }
7737 if (fWhat & CPUMCTX_EXTRN_SS)
7738 {
7739 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_SS);
7740 if (fRealOnV86Active)
7741 pCtx->ss.Attr.u = pVmcsInfoShared->RealMode.AttrSS.u;
7742 }
7743 if (fWhat & CPUMCTX_EXTRN_DS)
7744 {
7745 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_DS);
7746 if (fRealOnV86Active)
7747 pCtx->ds.Attr.u = pVmcsInfoShared->RealMode.AttrDS.u;
7748 }
7749 if (fWhat & CPUMCTX_EXTRN_ES)
7750 {
7751 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_ES);
7752 if (fRealOnV86Active)
7753 pCtx->es.Attr.u = pVmcsInfoShared->RealMode.AttrES.u;
7754 }
7755 if (fWhat & CPUMCTX_EXTRN_FS)
7756 {
7757 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_FS);
7758 if (fRealOnV86Active)
7759 pCtx->fs.Attr.u = pVmcsInfoShared->RealMode.AttrFS.u;
7760 }
7761 if (fWhat & CPUMCTX_EXTRN_GS)
7762 {
7763 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_GS);
7764 if (fRealOnV86Active)
7765 pCtx->gs.Attr.u = pVmcsInfoShared->RealMode.AttrGS.u;
7766 }
7767 }
7768
7769 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
7770 {
7771 if (fWhat & CPUMCTX_EXTRN_LDTR)
7772 hmR0VmxImportGuestLdtr(pVCpu);
7773
7774 if (fWhat & CPUMCTX_EXTRN_GDTR)
7775 {
7776 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &pCtx->gdtr.pGdt); AssertRC(rc);
7777 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRC(rc);
7778 pCtx->gdtr.cbGdt = u32Val;
7779 }
7780
7781 /* Guest IDTR. */
7782 if (fWhat & CPUMCTX_EXTRN_IDTR)
7783 {
7784 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &pCtx->idtr.pIdt); AssertRC(rc);
7785 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRC(rc);
7786 pCtx->idtr.cbIdt = u32Val;
7787 }
7788
7789 /* Guest TR. */
7790 if (fWhat & CPUMCTX_EXTRN_TR)
7791 {
7792 /* Real-mode emulation using virtual-8086 mode has the fake TSS (pRealModeTSS) in TR,
7793 don't need to import that one. */
7794 if (!pVmcsInfo->pShared->RealMode.fRealOnV86Active)
7795 hmR0VmxImportGuestTr(pVCpu);
7796 }
7797 }
7798
7799 if (fWhat & CPUMCTX_EXTRN_DR7)
7800 {
7801 if (!pVCpu->hmr0.s.fUsingHyperDR7)
7802 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_DR7, &pCtx->dr[7]); AssertRC(rc);
7803 }
7804
7805 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
7806 {
7807 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, &pCtx->SysEnter.eip); AssertRC(rc);
7808 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, &pCtx->SysEnter.esp); AssertRC(rc);
7809 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRC(rc);
7810 pCtx->SysEnter.cs = u32Val;
7811 }
7812
7813 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
7814 {
7815 if ( pVM->hmr0.s.fAllow64BitGuests
7816 && (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7817 pCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
7818 }
7819
7820 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
7821 {
7822 if ( pVM->hmr0.s.fAllow64BitGuests
7823 && (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7824 {
7825 pCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
7826 pCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
7827 pCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
7828 }
7829 }
7830
7831 if (fWhat & (CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS))
7832 {
7833 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7834 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
7835 uint32_t const cMsrs = pVmcsInfo->cExitMsrStore;
7836 Assert(pMsrs);
7837 Assert(cMsrs <= VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc));
7838 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
7839 for (uint32_t i = 0; i < cMsrs; i++)
7840 {
7841 uint32_t const idMsr = pMsrs[i].u32Msr;
7842 switch (idMsr)
7843 {
7844 case MSR_K8_TSC_AUX: CPUMSetGuestTscAux(pVCpu, pMsrs[i].u64Value); break;
7845 case MSR_IA32_SPEC_CTRL: CPUMSetGuestSpecCtrl(pVCpu, pMsrs[i].u64Value); break;
7846 case MSR_K6_EFER: /* Can't be changed without causing a VM-exit */ break;
7847 default:
7848 {
7849 uint32_t idxLbrMsr;
7850 if (pVM->hmr0.s.vmx.fLbr)
7851 {
7852 if (hmR0VmxIsLbrBranchFromMsr(pVM, idMsr, &idxLbrMsr))
7853 {
7854 Assert(idxLbrMsr < RT_ELEMENTS(pVmcsInfoShared->au64LbrFromIpMsr));
7855 pVmcsInfoShared->au64LbrFromIpMsr[idxLbrMsr] = pMsrs[i].u64Value;
7856 break;
7857 }
7858 if (hmR0VmxIsLbrBranchToMsr(pVM, idMsr, &idxLbrMsr))
7859 {
7860 Assert(idxLbrMsr < RT_ELEMENTS(pVmcsInfoShared->au64LbrFromIpMsr));
7861 pVmcsInfoShared->au64LbrToIpMsr[idxLbrMsr] = pMsrs[i].u64Value;
7862 break;
7863 }
7864 if (idMsr == pVM->hmr0.s.vmx.idLbrTosMsr)
7865 {
7866 pVmcsInfoShared->u64LbrTosMsr = pMsrs[i].u64Value;
7867 break;
7868 }
7869 /* Fallthru (no break) */
7870 }
7871 pCtx->fExtrn = 0;
7872 pVCpu->hm.s.u32HMError = pMsrs->u32Msr;
7873 ASMSetFlags(fEFlags);
7874 AssertMsgFailed(("Unexpected MSR in auto-load/store area. idMsr=%#RX32 cMsrs=%u\n", idMsr, cMsrs));
7875 return VERR_HM_UNEXPECTED_LD_ST_MSR;
7876 }
7877 }
7878 }
7879 }
7880
7881 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
7882 {
7883 if (fWhat & CPUMCTX_EXTRN_CR0)
7884 {
7885 uint64_t u64Cr0;
7886 uint64_t u64Shadow;
7887 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Cr0); AssertRC(rc);
7888 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Shadow); AssertRC(rc);
7889#ifndef VBOX_WITH_NESTED_HWVIRT_VMX
7890 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7891 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7892#else
7893 if (!CPUMIsGuestInVmxNonRootMode(pCtx))
7894 {
7895 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7896 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7897 }
7898 else
7899 {
7900 /*
7901 * We've merged the guest and nested-guest's CR0 guest/host mask while executing
7902 * the nested-guest using hardware-assisted VMX. Accordingly we need to
7903 * re-construct CR0. See @bugref{9180#c95} for details.
7904 */
7905 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
7906 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
7907 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7908 | (pVmcsNstGst->u64GuestCr0.u & pVmcsNstGst->u64Cr0Mask.u)
7909 | (u64Shadow & (pVmcsInfoGst->u64Cr0Mask & ~pVmcsNstGst->u64Cr0Mask.u));
7910 }
7911#endif
7912 VMMRZCallRing3Disable(pVCpu); /* May call into PGM which has Log statements. */
7913 CPUMSetGuestCR0(pVCpu, u64Cr0);
7914 VMMRZCallRing3Enable(pVCpu);
7915 }
7916
7917 if (fWhat & CPUMCTX_EXTRN_CR4)
7918 {
7919 uint64_t u64Cr4;
7920 uint64_t u64Shadow;
7921 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64Cr4); AssertRC(rc);
7922 rc |= VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Shadow); AssertRC(rc);
7923#ifndef VBOX_WITH_NESTED_HWVIRT_VMX
7924 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7925 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7926#else
7927 if (!CPUMIsGuestInVmxNonRootMode(pCtx))
7928 {
7929 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7930 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7931 }
7932 else
7933 {
7934 /*
7935 * We've merged the guest and nested-guest's CR4 guest/host mask while executing
7936 * the nested-guest using hardware-assisted VMX. Accordingly we need to
7937 * re-construct CR4. See @bugref{9180#c95} for details.
7938 */
7939 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
7940 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
7941 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7942 | (pVmcsNstGst->u64GuestCr4.u & pVmcsNstGst->u64Cr4Mask.u)
7943 | (u64Shadow & (pVmcsInfoGst->u64Cr4Mask & ~pVmcsNstGst->u64Cr4Mask.u));
7944 }
7945#endif
7946 pCtx->cr4 = u64Cr4;
7947 }
7948
7949 if (fWhat & CPUMCTX_EXTRN_CR3)
7950 {
7951 /* CR0.PG bit changes are always intercepted, so it's up to date. */
7952 if ( pVM->hmr0.s.vmx.fUnrestrictedGuest
7953 || ( pVM->hmr0.s.fNestedPaging
7954 && CPUMIsGuestPagingEnabledEx(pCtx)))
7955 {
7956 uint64_t u64Cr3;
7957 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR3, &u64Cr3); AssertRC(rc);
7958 if (pCtx->cr3 != u64Cr3)
7959 {
7960 pCtx->cr3 = u64Cr3;
7961 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
7962 }
7963
7964 /*
7965 * If the guest is in PAE mode, sync back the PDPE's into the guest state.
7966 * CR4.PAE, CR0.PG, EFER MSR changes are always intercepted, so they're up to date.
7967 */
7968 if (CPUMIsGuestInPAEModeEx(pCtx))
7969 {
7970 X86PDPE aPaePdpes[4];
7971 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &aPaePdpes[0].u); AssertRC(rc);
7972 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &aPaePdpes[1].u); AssertRC(rc);
7973 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &aPaePdpes[2].u); AssertRC(rc);
7974 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &aPaePdpes[3].u); AssertRC(rc);
7975 if (memcmp(&aPaePdpes[0], &pCtx->aPaePdpes[0], sizeof(aPaePdpes)))
7976 {
7977 memcpy(&pCtx->aPaePdpes[0], &aPaePdpes[0], sizeof(aPaePdpes));
7978 /* PGM now updates PAE PDPTEs while updating CR3. */
7979 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
7980 }
7981 }
7982 }
7983 }
7984 }
7985
7986#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7987 if (fWhat & CPUMCTX_EXTRN_HWVIRT)
7988 {
7989 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
7990 && !CPUMIsGuestInVmxNonRootMode(pCtx))
7991 {
7992 Assert(CPUMIsGuestInVmxRootMode(pCtx));
7993 rc = hmR0VmxCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
7994 if (RT_SUCCESS(rc))
7995 { /* likely */ }
7996 else
7997 break;
7998 }
7999 }
8000#endif
8001 } while (0);
8002
8003 if (RT_SUCCESS(rc))
8004 {
8005 /* Update fExtrn. */
8006 pCtx->fExtrn &= ~fWhat;
8007
8008 /* If everything has been imported, clear the HM keeper bit. */
8009 if (!(pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL))
8010 {
8011 pCtx->fExtrn &= ~CPUMCTX_EXTRN_KEEPER_HM;
8012 Assert(!pCtx->fExtrn);
8013 }
8014 }
8015 }
8016 else
8017 AssertMsg(!pCtx->fExtrn || (pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL), ("%#RX64\n", pCtx->fExtrn));
8018
8019 /*
8020 * Restore interrupts.
8021 */
8022 ASMSetFlags(fEFlags);
8023
8024 STAM_PROFILE_ADV_STOP(& pVCpu->hm.s.StatImportGuestState, x);
8025
8026 if (RT_SUCCESS(rc))
8027 { /* likely */ }
8028 else
8029 return rc;
8030
8031 /*
8032 * Honor any pending CR3 updates.
8033 *
8034 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> VMXR0CallRing3Callback()
8035 * -> VMMRZCallRing3Disable() -> hmR0VmxImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
8036 * -> continue with VM-exit handling -> hmR0VmxImportGuestState() and here we are.
8037 *
8038 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
8039 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
8040 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
8041 * -NOT- check if CPUMCTX_EXTRN_CR3 is set!
8042 *
8043 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
8044 */
8045 if (VMMRZCallRing3IsEnabled(pVCpu))
8046 {
8047 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
8048 {
8049 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & CPUMCTX_EXTRN_CR3));
8050 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
8051 }
8052 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
8053 }
8054
8055 return VINF_SUCCESS;
8056}
8057
8058
8059/**
8060 * Saves the guest state from the VMCS into the guest-CPU context.
8061 *
8062 * @returns VBox status code.
8063 * @param pVCpu The cross context virtual CPU structure.
8064 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
8065 */
8066VMMR0DECL(int) VMXR0ImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat)
8067{
8068 AssertPtr(pVCpu);
8069 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8070 return hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fWhat);
8071}
8072
8073
8074/**
8075 * Check per-VM and per-VCPU force flag actions that require us to go back to
8076 * ring-3 for one reason or another.
8077 *
8078 * @returns Strict VBox status code (i.e. informational status codes too)
8079 * @retval VINF_SUCCESS if we don't have any actions that require going back to
8080 * ring-3.
8081 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
8082 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
8083 * interrupts)
8084 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
8085 * all EMTs to be in ring-3.
8086 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
8087 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
8088 * to the EM loop.
8089 *
8090 * @param pVCpu The cross context virtual CPU structure.
8091 * @param pVmxTransient The VMX-transient structure.
8092 * @param fStepping Whether we are single-stepping the guest using the
8093 * hypervisor debugger.
8094 *
8095 * @remarks This might cause nested-guest VM-exits, caller must check if the guest
8096 * is no longer in VMX non-root mode.
8097 */
8098static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, bool fStepping)
8099{
8100 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8101
8102 /*
8103 * Update pending interrupts into the APIC's IRR.
8104 */
8105 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
8106 APICUpdatePendingInterrupts(pVCpu);
8107
8108 /*
8109 * Anything pending? Should be more likely than not if we're doing a good job.
8110 */
8111 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8112 if ( !fStepping
8113 ? !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_MASK)
8114 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
8115 : !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
8116 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
8117 return VINF_SUCCESS;
8118
8119 /* Pending PGM C3 sync. */
8120 if (VMCPU_FF_IS_ANY_SET(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
8121 {
8122 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8123 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & (CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4)));
8124 VBOXSTRICTRC rcStrict = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4,
8125 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
8126 if (rcStrict != VINF_SUCCESS)
8127 {
8128 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
8129 Log4Func(("PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
8130 return rcStrict;
8131 }
8132 }
8133
8134 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
8135 if ( VM_FF_IS_ANY_SET(pVM, VM_FF_HM_TO_R3_MASK)
8136 || VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
8137 {
8138 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
8139 int rc = RT_LIKELY(!VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_RAW_TO_R3 : VINF_EM_NO_MEMORY;
8140 Log4Func(("HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc));
8141 return rc;
8142 }
8143
8144 /* Pending VM request packets, such as hardware interrupts. */
8145 if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
8146 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
8147 {
8148 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchVmReq);
8149 Log4Func(("Pending VM request forcing us back to ring-3\n"));
8150 return VINF_EM_PENDING_REQUEST;
8151 }
8152
8153 /* Pending PGM pool flushes. */
8154 if (VM_FF_IS_SET(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
8155 {
8156 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPgmPoolFlush);
8157 Log4Func(("PGM pool flush pending forcing us back to ring-3\n"));
8158 return VINF_PGM_POOL_FLUSH_PENDING;
8159 }
8160
8161 /* Pending DMA requests. */
8162 if (VM_FF_IS_SET(pVM, VM_FF_PDM_DMA))
8163 {
8164 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchDma);
8165 Log4Func(("Pending DMA request forcing us back to ring-3\n"));
8166 return VINF_EM_RAW_TO_R3;
8167 }
8168
8169#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8170 /*
8171 * Pending nested-guest events.
8172 *
8173 * Please note the priority of these events are specified and important.
8174 * See Intel spec. 29.4.3.2 "APIC-Write Emulation".
8175 * See Intel spec. 6.9 "Priority Among Simultaneous Exceptions And Interrupts".
8176 */
8177 if (pVmxTransient->fIsNestedGuest)
8178 {
8179 /* Pending nested-guest APIC-write. */
8180 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
8181 {
8182 Log4Func(("Pending nested-guest APIC-write\n"));
8183 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitApicWrite(pVCpu);
8184 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8185 return rcStrict;
8186 }
8187
8188 /* Pending nested-guest monitor-trap flag (MTF). */
8189 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF))
8190 {
8191 Log4Func(("Pending nested-guest MTF\n"));
8192 VBOXSTRICTRC rcStrict = IEMExecVmxVmexit(pVCpu, VMX_EXIT_MTF, 0 /* uExitQual */);
8193 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8194 return rcStrict;
8195 }
8196
8197 /* Pending nested-guest VMX-preemption timer expired. */
8198 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER))
8199 {
8200 Log4Func(("Pending nested-guest preempt timer\n"));
8201 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitPreemptTimer(pVCpu);
8202 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8203 return rcStrict;
8204 }
8205 }
8206#else
8207 NOREF(pVmxTransient);
8208#endif
8209
8210 return VINF_SUCCESS;
8211}
8212
8213
8214/**
8215 * Converts any TRPM trap into a pending HM event. This is typically used when
8216 * entering from ring-3 (not longjmp returns).
8217 *
8218 * @param pVCpu The cross context virtual CPU structure.
8219 */
8220static void hmR0VmxTrpmTrapToPendingEvent(PVMCPUCC pVCpu)
8221{
8222 Assert(TRPMHasTrap(pVCpu));
8223 Assert(!pVCpu->hm.s.Event.fPending);
8224
8225 uint8_t uVector;
8226 TRPMEVENT enmTrpmEvent;
8227 uint32_t uErrCode;
8228 RTGCUINTPTR GCPtrFaultAddress;
8229 uint8_t cbInstr;
8230 bool fIcebp;
8231
8232 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr, &fIcebp);
8233 AssertRC(rc);
8234
8235 uint32_t u32IntInfo;
8236 u32IntInfo = uVector | VMX_IDT_VECTORING_INFO_VALID;
8237 u32IntInfo |= HMTrpmEventTypeToVmxEventType(uVector, enmTrpmEvent, fIcebp);
8238
8239 rc = TRPMResetTrap(pVCpu);
8240 AssertRC(rc);
8241 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
8242 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
8243
8244 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
8245}
8246
8247
8248/**
8249 * Converts the pending HM event into a TRPM trap.
8250 *
8251 * @param pVCpu The cross context virtual CPU structure.
8252 */
8253static void hmR0VmxPendingEventToTrpmTrap(PVMCPUCC pVCpu)
8254{
8255 Assert(pVCpu->hm.s.Event.fPending);
8256
8257 /* If a trap was already pending, we did something wrong! */
8258 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
8259
8260 uint32_t const u32IntInfo = pVCpu->hm.s.Event.u64IntInfo;
8261 uint32_t const uVector = VMX_IDT_VECTORING_INFO_VECTOR(u32IntInfo);
8262 TRPMEVENT const enmTrapType = HMVmxEventTypeToTrpmEventType(u32IntInfo);
8263
8264 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
8265
8266 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
8267 AssertRC(rc);
8268
8269 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8270 TRPMSetErrorCode(pVCpu, pVCpu->hm.s.Event.u32ErrCode);
8271
8272 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(u32IntInfo))
8273 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
8274 else
8275 {
8276 uint8_t const uVectorType = VMX_IDT_VECTORING_INFO_TYPE(u32IntInfo);
8277 switch (uVectorType)
8278 {
8279 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
8280 TRPMSetTrapDueToIcebp(pVCpu);
8281 RT_FALL_THRU();
8282 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
8283 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
8284 {
8285 AssertMsg( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
8286 || ( uVector == X86_XCPT_BP /* INT3 */
8287 || uVector == X86_XCPT_OF /* INTO */
8288 || uVector == X86_XCPT_DB /* INT1 (ICEBP) */),
8289 ("Invalid vector: uVector=%#x uVectorType=%#x\n", uVector, uVectorType));
8290 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
8291 break;
8292 }
8293 }
8294 }
8295
8296 /* We're now done converting the pending event. */
8297 pVCpu->hm.s.Event.fPending = false;
8298}
8299
8300
8301/**
8302 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
8303 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
8304 *
8305 * @param pVmcsInfo The VMCS info. object.
8306 */
8307static void hmR0VmxSetIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8308{
8309 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_INT_WINDOW_EXIT)
8310 {
8311 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
8312 {
8313 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_INT_WINDOW_EXIT;
8314 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8315 AssertRC(rc);
8316 }
8317 } /* else we will deliver interrupts whenever the guest Vm-exits next and is in a state to receive the interrupt. */
8318}
8319
8320
8321/**
8322 * Clears the interrupt-window exiting control in the VMCS.
8323 *
8324 * @param pVmcsInfo The VMCS info. object.
8325 */
8326DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8327{
8328 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
8329 {
8330 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_INT_WINDOW_EXIT;
8331 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8332 AssertRC(rc);
8333 }
8334}
8335
8336
8337/**
8338 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
8339 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
8340 *
8341 * @param pVmcsInfo The VMCS info. object.
8342 */
8343static void hmR0VmxSetNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8344{
8345 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
8346 {
8347 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
8348 {
8349 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_NMI_WINDOW_EXIT;
8350 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8351 AssertRC(rc);
8352 Log4Func(("Setup NMI-window exiting\n"));
8353 }
8354 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
8355}
8356
8357
8358/**
8359 * Clears the NMI-window exiting control in the VMCS.
8360 *
8361 * @param pVmcsInfo The VMCS info. object.
8362 */
8363DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8364{
8365 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
8366 {
8367 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_NMI_WINDOW_EXIT;
8368 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8369 AssertRC(rc);
8370 }
8371}
8372
8373
8374/**
8375 * Does the necessary state syncing before returning to ring-3 for any reason
8376 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
8377 *
8378 * @returns VBox status code.
8379 * @param pVCpu The cross context virtual CPU structure.
8380 * @param fImportState Whether to import the guest state from the VMCS back
8381 * to the guest-CPU context.
8382 *
8383 * @remarks No-long-jmp zone!!!
8384 */
8385static int hmR0VmxLeave(PVMCPUCC pVCpu, bool fImportState)
8386{
8387 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8388 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8389
8390 RTCPUID const idCpu = RTMpCpuId();
8391 Log4Func(("HostCpuId=%u\n", idCpu));
8392
8393 /*
8394 * !!! IMPORTANT !!!
8395 * If you modify code here, check whether VMXR0CallRing3Callback() needs to be updated too.
8396 */
8397
8398 /* Save the guest state if necessary. */
8399 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8400 if (fImportState)
8401 {
8402 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8403 AssertRCReturn(rc, rc);
8404 }
8405
8406 /* Restore host FPU state if necessary. We will resync on next R0 reentry. */
8407 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8408 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
8409
8410 /* Restore host debug registers if necessary. We will resync on next R0 reentry. */
8411#ifdef VBOX_STRICT
8412 if (CPUMIsHyperDebugStateActive(pVCpu))
8413 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT);
8414#endif
8415 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8416 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
8417 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
8418
8419 /* Restore host-state bits that VT-x only restores partially. */
8420 if (pVCpu->hmr0.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED)
8421 {
8422 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hmr0.s.vmx.fRestoreHostFlags, idCpu));
8423 VMXRestoreHostState(pVCpu->hmr0.s.vmx.fRestoreHostFlags, &pVCpu->hmr0.s.vmx.RestoreHost);
8424 }
8425 pVCpu->hmr0.s.vmx.fRestoreHostFlags = 0;
8426
8427 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8428 if (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8429 {
8430 /* We shouldn't restore the host MSRs without saving the guest MSRs first. */
8431 if (!fImportState)
8432 {
8433 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS);
8434 AssertRCReturn(rc, rc);
8435 }
8436 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8437 Assert(!pVCpu->hmr0.s.vmx.fLazyMsrs);
8438 }
8439 else
8440 pVCpu->hmr0.s.vmx.fLazyMsrs = 0;
8441
8442 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8443 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
8444
8445 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
8446 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatImportGuestState);
8447 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExportGuestState);
8448 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatPreExit);
8449 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitHandling);
8450 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
8451 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
8452 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
8453 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitVmentry);
8454 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8455
8456 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8457
8458 /** @todo This partially defeats the purpose of having preemption hooks.
8459 * The problem is, deregistering the hooks should be moved to a place that
8460 * lasts until the EMT is about to be destroyed not everytime while leaving HM
8461 * context.
8462 */
8463 int rc = hmR0VmxClearVmcs(pVmcsInfo);
8464 AssertRCReturn(rc, rc);
8465
8466#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8467 /*
8468 * A valid shadow VMCS is made active as part of VM-entry. It is necessary to
8469 * clear a shadow VMCS before allowing that VMCS to become active on another
8470 * logical processor. We may or may not be importing guest state which clears
8471 * it, so cover for it here.
8472 *
8473 * See Intel spec. 24.11.1 "Software Use of Virtual-Machine Control Structures".
8474 */
8475 if ( pVmcsInfo->pvShadowVmcs
8476 && pVmcsInfo->fShadowVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
8477 {
8478 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
8479 AssertRCReturn(rc, rc);
8480 }
8481
8482 /*
8483 * Flag that we need to re-export the host state if we switch to this VMCS before
8484 * executing guest or nested-guest code.
8485 */
8486 pVmcsInfo->idHostCpuState = NIL_RTCPUID;
8487#endif
8488
8489 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
8490 NOREF(idCpu);
8491 return VINF_SUCCESS;
8492}
8493
8494
8495/**
8496 * Leaves the VT-x session.
8497 *
8498 * @returns VBox status code.
8499 * @param pVCpu The cross context virtual CPU structure.
8500 *
8501 * @remarks No-long-jmp zone!!!
8502 */
8503static int hmR0VmxLeaveSession(PVMCPUCC pVCpu)
8504{
8505 HM_DISABLE_PREEMPT(pVCpu);
8506 HMVMX_ASSERT_CPU_SAFE(pVCpu);
8507 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8508 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8509
8510 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
8511 and done this from the VMXR0ThreadCtxCallback(). */
8512 if (!pVCpu->hmr0.s.fLeaveDone)
8513 {
8514 int rc2 = hmR0VmxLeave(pVCpu, true /* fImportState */);
8515 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
8516 pVCpu->hmr0.s.fLeaveDone = true;
8517 }
8518 Assert(!pVCpu->cpum.GstCtx.fExtrn);
8519
8520 /*
8521 * !!! IMPORTANT !!!
8522 * If you modify code here, make sure to check whether VMXR0CallRing3Callback() needs to be updated too.
8523 */
8524
8525 /* Deregister hook now that we've left HM context before re-enabling preemption. */
8526 /** @todo Deregistering here means we need to VMCLEAR always
8527 * (longjmp/exit-to-r3) in VT-x which is not efficient, eliminate need
8528 * for calling VMMR0ThreadCtxHookDisable here! */
8529 VMMR0ThreadCtxHookDisable(pVCpu);
8530
8531 /* Leave HM context. This takes care of local init (term) and deregistering the longjmp-to-ring-3 callback. */
8532 int rc = HMR0LeaveCpu(pVCpu);
8533 HM_RESTORE_PREEMPT();
8534 return rc;
8535}
8536
8537
8538/**
8539 * Does the necessary state syncing before doing a longjmp to ring-3.
8540 *
8541 * @returns VBox status code.
8542 * @param pVCpu The cross context virtual CPU structure.
8543 *
8544 * @remarks No-long-jmp zone!!!
8545 */
8546DECLINLINE(int) hmR0VmxLongJmpToRing3(PVMCPUCC pVCpu)
8547{
8548 return hmR0VmxLeaveSession(pVCpu);
8549}
8550
8551
8552/**
8553 * Take necessary actions before going back to ring-3.
8554 *
8555 * An action requires us to go back to ring-3. This function does the necessary
8556 * steps before we can safely return to ring-3. This is not the same as longjmps
8557 * to ring-3, this is voluntary and prepares the guest so it may continue
8558 * executing outside HM (recompiler/IEM).
8559 *
8560 * @returns VBox status code.
8561 * @param pVCpu The cross context virtual CPU structure.
8562 * @param rcExit The reason for exiting to ring-3. Can be
8563 * VINF_VMM_UNKNOWN_RING3_CALL.
8564 */
8565static int hmR0VmxExitToRing3(PVMCPUCC pVCpu, VBOXSTRICTRC rcExit)
8566{
8567 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8568
8569 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8570 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
8571 {
8572 VMXGetCurrentVmcs(&pVCpu->hm.s.vmx.LastError.HCPhysCurrentVmcs);
8573 pVCpu->hm.s.vmx.LastError.u32VmcsRev = *(uint32_t *)pVmcsInfo->pvVmcs;
8574 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hmr0.s.idEnteredCpu;
8575 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
8576 }
8577
8578 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
8579 VMMRZCallRing3Disable(pVCpu);
8580 Log4Func(("rcExit=%d\n", VBOXSTRICTRC_VAL(rcExit)));
8581
8582 /*
8583 * Convert any pending HM events back to TRPM due to premature exits to ring-3.
8584 * We need to do this only on returns to ring-3 and not for longjmps to ring3.
8585 *
8586 * This is because execution may continue from ring-3 and we would need to inject
8587 * the event from there (hence place it back in TRPM).
8588 */
8589 if (pVCpu->hm.s.Event.fPending)
8590 {
8591 hmR0VmxPendingEventToTrpmTrap(pVCpu);
8592 Assert(!pVCpu->hm.s.Event.fPending);
8593
8594 /* Clear the events from the VMCS. */
8595 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0); AssertRC(rc);
8596 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, 0); AssertRC(rc);
8597 }
8598#ifdef VBOX_STRICT
8599 /*
8600 * We check for rcExit here since for errors like VERR_VMX_UNABLE_TO_START_VM (which are
8601 * fatal), we don't care about verifying duplicate injection of events. Errors like
8602 * VERR_EM_INTERPRET are converted to their VINF_* counterparts -prior- to calling this
8603 * function so those should and will be checked below.
8604 */
8605 else if (RT_SUCCESS(rcExit))
8606 {
8607 /*
8608 * Ensure we don't accidentally clear a pending HM event without clearing the VMCS.
8609 * This can be pretty hard to debug otherwise, interrupts might get injected twice
8610 * occasionally, see @bugref{9180#c42}.
8611 *
8612 * However, if the VM-entry failed, any VM entry-interruption info. field would
8613 * be left unmodified as the event would not have been injected to the guest. In
8614 * such cases, don't assert, we're not going to continue guest execution anyway.
8615 */
8616 uint32_t uExitReason;
8617 uint32_t uEntryIntInfo;
8618 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8619 rc |= VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &uEntryIntInfo);
8620 AssertRC(rc);
8621 AssertMsg(VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason) || !VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo),
8622 ("uExitReason=%#RX32 uEntryIntInfo=%#RX32 rcExit=%d\n", uExitReason, uEntryIntInfo, VBOXSTRICTRC_VAL(rcExit)));
8623 }
8624#endif
8625
8626 /*
8627 * Clear the interrupt-window and NMI-window VMCS controls as we could have got
8628 * a VM-exit with higher priority than interrupt-window or NMI-window VM-exits
8629 * (e.g. TPR below threshold).
8630 */
8631 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8632 {
8633 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
8634 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
8635 }
8636
8637 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
8638 and if we're injecting an event we should have a TRPM trap pending. */
8639 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8640#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a triple fault in progress. */
8641 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8642#endif
8643
8644 /* Save guest state and restore host state bits. */
8645 int rc = hmR0VmxLeaveSession(pVCpu);
8646 AssertRCReturn(rc, rc);
8647 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8648
8649 /* Thread-context hooks are unregistered at this point!!! */
8650 /* Ring-3 callback notifications are unregistered at this point!!! */
8651
8652 /* Sync recompiler state. */
8653 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
8654 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
8655 | CPUM_CHANGED_LDTR
8656 | CPUM_CHANGED_GDTR
8657 | CPUM_CHANGED_IDTR
8658 | CPUM_CHANGED_TR
8659 | CPUM_CHANGED_HIDDEN_SEL_REGS);
8660 if ( pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging
8661 && CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx))
8662 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
8663
8664 Assert(!pVCpu->hmr0.s.fClearTrapFlag);
8665
8666 /* Update the exit-to-ring 3 reason. */
8667 pVCpu->hm.s.rcLastExitToR3 = VBOXSTRICTRC_VAL(rcExit);
8668
8669 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
8670 if ( rcExit != VINF_EM_RAW_INTERRUPT
8671 || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8672 {
8673 Assert(!(pVCpu->cpum.GstCtx.fExtrn & HMVMX_CPUMCTX_EXTRN_ALL));
8674 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
8675 }
8676
8677 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
8678 VMMRZCallRing3Enable(pVCpu);
8679 return rc;
8680}
8681
8682
8683/**
8684 * VMMRZCallRing3() callback wrapper which saves the guest state before we
8685 * longjump to ring-3 and possibly get preempted.
8686 *
8687 * @returns VBox status code.
8688 * @param pVCpu The cross context virtual CPU structure.
8689 * @param enmOperation The operation causing the ring-3 longjump.
8690 */
8691VMMR0DECL(int) VMXR0CallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation)
8692{
8693 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
8694 {
8695 /*
8696 * !!! IMPORTANT !!!
8697 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
8698 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
8699 */
8700 VMMRZCallRing3RemoveNotification(pVCpu);
8701 VMMRZCallRing3Disable(pVCpu);
8702 HM_DISABLE_PREEMPT(pVCpu);
8703
8704 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8705 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8706 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8707 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8708
8709 /* Restore host-state bits that VT-x only restores partially. */
8710 if (pVCpu->hmr0.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED)
8711 VMXRestoreHostState(pVCpu->hmr0.s.vmx.fRestoreHostFlags, &pVCpu->hmr0.s.vmx.RestoreHost);
8712 pVCpu->hmr0.s.vmx.fRestoreHostFlags = 0;
8713
8714 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8715 if (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8716 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8717
8718 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8719 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
8720 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8721
8722 /* Clear the current VMCS data back to memory (shadow VMCS if any would have been
8723 cleared as part of importing the guest state above. */
8724 hmR0VmxClearVmcs(pVmcsInfo);
8725
8726 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
8727 VMMR0ThreadCtxHookDisable(pVCpu);
8728
8729 /* Leave HM context. This takes care of local init (term). */
8730 HMR0LeaveCpu(pVCpu);
8731 HM_RESTORE_PREEMPT();
8732 return VINF_SUCCESS;
8733 }
8734
8735 Assert(pVCpu);
8736 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8737 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8738
8739 VMMRZCallRing3Disable(pVCpu);
8740
8741 Log4Func(("-> hmR0VmxLongJmpToRing3 enmOperation=%d\n", enmOperation));
8742
8743 int rc = hmR0VmxLongJmpToRing3(pVCpu);
8744 AssertRCReturn(rc, rc);
8745
8746 VMMRZCallRing3Enable(pVCpu);
8747 return VINF_SUCCESS;
8748}
8749
8750
8751/**
8752 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
8753 * stack.
8754 *
8755 * @returns Strict VBox status code (i.e. informational status codes too).
8756 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
8757 * @param pVCpu The cross context virtual CPU structure.
8758 * @param uValue The value to push to the guest stack.
8759 */
8760static VBOXSTRICTRC hmR0VmxRealModeGuestStackPush(PVMCPUCC pVCpu, uint16_t uValue)
8761{
8762 /*
8763 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
8764 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
8765 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
8766 */
8767 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8768 if (pCtx->sp == 1)
8769 return VINF_EM_RESET;
8770 pCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
8771 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), pCtx->ss.u64Base + pCtx->sp, &uValue, sizeof(uint16_t));
8772 AssertRC(rc);
8773 return rc;
8774}
8775
8776
8777/**
8778 * Injects an event into the guest upon VM-entry by updating the relevant fields
8779 * in the VM-entry area in the VMCS.
8780 *
8781 * @returns Strict VBox status code (i.e. informational status codes too).
8782 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
8783 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
8784 *
8785 * @param pVCpu The cross context virtual CPU structure.
8786 * @param pVmxTransient The VMX-transient structure.
8787 * @param pEvent The event being injected.
8788 * @param pfIntrState Pointer to the VT-x guest-interruptibility-state. This
8789 * will be updated if necessary. This cannot not be NULL.
8790 * @param fStepping Whether we're single-stepping guest execution and should
8791 * return VINF_EM_DBG_STEPPED if the event is injected
8792 * directly (registers modified by us, not by hardware on
8793 * VM-entry).
8794 */
8795static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PCHMEVENT pEvent, bool fStepping,
8796 uint32_t *pfIntrState)
8797{
8798 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
8799 AssertMsg(!RT_HI_U32(pEvent->u64IntInfo), ("%#RX64\n", pEvent->u64IntInfo));
8800 Assert(pfIntrState);
8801
8802 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8803 uint32_t u32IntInfo = pEvent->u64IntInfo;
8804 uint32_t const u32ErrCode = pEvent->u32ErrCode;
8805 uint32_t const cbInstr = pEvent->cbInstr;
8806 RTGCUINTPTR const GCPtrFault = pEvent->GCPtrFaultAddress;
8807 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(u32IntInfo);
8808 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(u32IntInfo);
8809
8810#ifdef VBOX_STRICT
8811 /*
8812 * Validate the error-code-valid bit for hardware exceptions.
8813 * No error codes for exceptions in real-mode.
8814 *
8815 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8816 */
8817 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8818 && !CPUMIsGuestInRealModeEx(pCtx))
8819 {
8820 switch (uVector)
8821 {
8822 case X86_XCPT_PF:
8823 case X86_XCPT_DF:
8824 case X86_XCPT_TS:
8825 case X86_XCPT_NP:
8826 case X86_XCPT_SS:
8827 case X86_XCPT_GP:
8828 case X86_XCPT_AC:
8829 AssertMsg(VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo),
8830 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
8831 RT_FALL_THRU();
8832 default:
8833 break;
8834 }
8835 }
8836
8837 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
8838 Assert( uIntType != VMX_EXIT_INT_INFO_TYPE_NMI
8839 || !(*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
8840#endif
8841
8842 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8843 || uIntType == VMX_EXIT_INT_INFO_TYPE_NMI
8844 || uIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT
8845 || uIntType == VMX_EXIT_INT_INFO_TYPE_SW_XCPT)
8846 {
8847 Assert(uVector <= X86_XCPT_LAST);
8848 Assert(uIntType != VMX_EXIT_INT_INFO_TYPE_NMI || uVector == X86_XCPT_NMI);
8849 Assert(uIntType != VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT || uVector == X86_XCPT_DB);
8850 STAM_COUNTER_INC(&pVCpu->hm.s.aStatInjectedXcpts[uVector]);
8851 }
8852 else
8853 STAM_COUNTER_INC(&pVCpu->hm.s.aStatInjectedIrqs[uVector & MASK_INJECT_IRQ_STAT]);
8854
8855 /*
8856 * Hardware interrupts & exceptions cannot be delivered through the software interrupt
8857 * redirection bitmap to the real mode task in virtual-8086 mode. We must jump to the
8858 * interrupt handler in the (real-mode) guest.
8859 *
8860 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode".
8861 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
8862 */
8863 if (CPUMIsGuestInRealModeEx(pCtx)) /* CR0.PE bit changes are always intercepted, so it's up to date. */
8864 {
8865 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest)
8866 {
8867 /*
8868 * For CPUs with unrestricted guest execution enabled and with the guest
8869 * in real-mode, we must not set the deliver-error-code bit.
8870 *
8871 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8872 */
8873 u32IntInfo &= ~VMX_ENTRY_INT_INFO_ERROR_CODE_VALID;
8874 }
8875 else
8876 {
8877 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8878 Assert(PDMVmmDevHeapIsEnabled(pVM));
8879 Assert(pVM->hm.s.vmx.pRealModeTSS);
8880 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
8881
8882 /* We require RIP, RSP, RFLAGS, CS, IDTR, import them. */
8883 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8884 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TABLE_MASK
8885 | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS);
8886 AssertRCReturn(rc2, rc2);
8887
8888 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8889 size_t const cbIdtEntry = sizeof(X86IDTR16);
8890 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pCtx->idtr.cbIdt)
8891 {
8892 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8893 if (uVector == X86_XCPT_DF)
8894 return VINF_EM_RESET;
8895
8896 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault.
8897 No error codes for exceptions in real-mode. */
8898 if (uVector == X86_XCPT_GP)
8899 {
8900 uint32_t const uXcptDfInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
8901 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8902 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8903 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8904 HMEVENT EventXcptDf;
8905 RT_ZERO(EventXcptDf);
8906 EventXcptDf.u64IntInfo = uXcptDfInfo;
8907 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptDf, fStepping, pfIntrState);
8908 }
8909
8910 /*
8911 * If we're injecting an event with no valid IDT entry, inject a #GP.
8912 * No error codes for exceptions in real-mode.
8913 *
8914 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8915 */
8916 uint32_t const uXcptGpInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
8917 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8918 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8919 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8920 HMEVENT EventXcptGp;
8921 RT_ZERO(EventXcptGp);
8922 EventXcptGp.u64IntInfo = uXcptGpInfo;
8923 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptGp, fStepping, pfIntrState);
8924 }
8925
8926 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8927 uint16_t uGuestIp = pCtx->ip;
8928 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT)
8929 {
8930 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8931 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8932 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8933 }
8934 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_INT)
8935 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8936
8937 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8938 X86IDTR16 IdtEntry;
8939 RTGCPHYS const GCPhysIdtEntry = (RTGCPHYS)pCtx->idtr.pIdt + uVector * cbIdtEntry;
8940 rc2 = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8941 AssertRCReturn(rc2, rc2);
8942
8943 /* Construct the stack frame for the interrupt/exception handler. */
8944 VBOXSTRICTRC rcStrict;
8945 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->eflags.u32);
8946 if (rcStrict == VINF_SUCCESS)
8947 {
8948 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->cs.Sel);
8949 if (rcStrict == VINF_SUCCESS)
8950 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, uGuestIp);
8951 }
8952
8953 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8954 if (rcStrict == VINF_SUCCESS)
8955 {
8956 pCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8957 pCtx->rip = IdtEntry.offSel;
8958 pCtx->cs.Sel = IdtEntry.uSel;
8959 pCtx->cs.ValidSel = IdtEntry.uSel;
8960 pCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8961 if ( uIntType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
8962 && uVector == X86_XCPT_PF)
8963 pCtx->cr2 = GCPtrFault;
8964
8965 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CS | HM_CHANGED_GUEST_CR2
8966 | HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
8967 | HM_CHANGED_GUEST_RSP);
8968
8969 /*
8970 * If we delivered a hardware exception (other than an NMI) and if there was
8971 * block-by-STI in effect, we should clear it.
8972 */
8973 if (*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
8974 {
8975 Assert( uIntType != VMX_ENTRY_INT_INFO_TYPE_NMI
8976 && uIntType != VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
8977 Log4Func(("Clearing inhibition due to STI\n"));
8978 *pfIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
8979 }
8980
8981 Log4(("Injected real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8982 u32IntInfo, u32ErrCode, cbInstr, pCtx->eflags.u, pCtx->cs.Sel, pCtx->eip));
8983
8984 /*
8985 * The event has been truly dispatched to the guest. Mark it as no longer pending so
8986 * we don't attempt to undo it if we are returning to ring-3 before executing guest code.
8987 */
8988 pVCpu->hm.s.Event.fPending = false;
8989
8990 /*
8991 * If we eventually support nested-guest execution without unrestricted guest execution,
8992 * we should set fInterceptEvents here.
8993 */
8994 Assert(!pVmxTransient->fIsNestedGuest);
8995
8996 /* If we're stepping and we've changed cs:rip above, bail out of the VMX R0 execution loop. */
8997 if (fStepping)
8998 rcStrict = VINF_EM_DBG_STEPPED;
8999 }
9000 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
9001 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
9002 return rcStrict;
9003 }
9004 }
9005
9006 /*
9007 * Validate.
9008 */
9009 Assert(VMX_ENTRY_INT_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
9010 Assert(!(u32IntInfo & VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK)); /* Bits 30:12 MBZ. */
9011
9012 /*
9013 * Inject the event into the VMCS.
9014 */
9015 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
9016 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
9017 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
9018 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
9019 AssertRC(rc);
9020
9021 /*
9022 * Update guest CR2 if this is a page-fault.
9023 */
9024 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
9025 pCtx->cr2 = GCPtrFault;
9026
9027 Log4(("Injecting u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x CR2=%#RX64\n", u32IntInfo, u32ErrCode, cbInstr, pCtx->cr2));
9028 return VINF_SUCCESS;
9029}
9030
9031
9032/**
9033 * Evaluates the event to be delivered to the guest and sets it as the pending
9034 * event.
9035 *
9036 * Toggling of interrupt force-flags here is safe since we update TRPM on premature
9037 * exits to ring-3 before executing guest code, see hmR0VmxExitToRing3(). We must
9038 * NOT restore these force-flags.
9039 *
9040 * @returns Strict VBox status code (i.e. informational status codes too).
9041 * @param pVCpu The cross context virtual CPU structure.
9042 * @param pVmxTransient The VMX-transient structure.
9043 * @param pfIntrState Where to store the VT-x guest-interruptibility state.
9044 */
9045static VBOXSTRICTRC hmR0VmxEvaluatePendingEvent(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t *pfIntrState)
9046{
9047 Assert(pfIntrState);
9048 Assert(!TRPMHasTrap(pVCpu));
9049
9050 /*
9051 * Compute/update guest-interruptibility state related FFs.
9052 * The FFs will be used below while evaluating events to be injected.
9053 */
9054 *pfIntrState = hmR0VmxGetGuestIntrStateAndUpdateFFs(pVCpu);
9055
9056 /*
9057 * Evaluate if a new event needs to be injected.
9058 * An event that's already pending has already performed all necessary checks.
9059 */
9060 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
9061 bool const fIsNestedGuest = pVmxTransient->fIsNestedGuest;
9062 if ( !pVCpu->hm.s.Event.fPending
9063 && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
9064 {
9065 /** @todo SMI. SMIs take priority over NMIs. */
9066
9067 /*
9068 * NMIs.
9069 * NMIs take priority over external interrupts.
9070 */
9071 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9072 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
9073 {
9074 /*
9075 * For a guest, the FF always indicates the guest's ability to receive an NMI.
9076 *
9077 * For a nested-guest, the FF always indicates the outer guest's ability to
9078 * receive an NMI while the guest-interruptibility state bit depends on whether
9079 * the nested-hypervisor is using virtual-NMIs.
9080 */
9081 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
9082 {
9083#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9084 if ( fIsNestedGuest
9085 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_NMI_EXIT))
9086 return IEMExecVmxVmexitXcptNmi(pVCpu);
9087#endif
9088 hmR0VmxSetPendingXcptNmi(pVCpu);
9089 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
9090 Log4Func(("NMI pending injection\n"));
9091
9092 /* We've injected the NMI, bail. */
9093 return VINF_SUCCESS;
9094 }
9095 else if (!fIsNestedGuest)
9096 hmR0VmxSetNmiWindowExitVmcs(pVmcsInfo);
9097 }
9098
9099 /*
9100 * External interrupts (PIC/APIC).
9101 * Once PDMGetInterrupt() returns a valid interrupt we -must- deliver it.
9102 * We cannot re-request the interrupt from the controller again.
9103 */
9104 if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
9105 && !pVCpu->hm.s.fSingleInstruction)
9106 {
9107 Assert(!DBGFIsStepping(pVCpu));
9108 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
9109 AssertRC(rc);
9110
9111 /*
9112 * We must not check EFLAGS directly when executing a nested-guest, use
9113 * CPUMIsGuestPhysIntrEnabled() instead as EFLAGS.IF does not control the blocking of
9114 * external interrupts when "External interrupt exiting" is set. This fixes a nasty
9115 * SMP hang while executing nested-guest VCPUs on spinlocks which aren't rescued by
9116 * other VM-exits (like a preemption timer), see @bugref{9562#c18}.
9117 *
9118 * See Intel spec. 25.4.1 "Event Blocking".
9119 */
9120 if (CPUMIsGuestPhysIntrEnabled(pVCpu))
9121 {
9122#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9123 if ( fIsNestedGuest
9124 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
9125 {
9126 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
9127 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
9128 return rcStrict;
9129 }
9130#endif
9131 uint8_t u8Interrupt;
9132 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
9133 if (RT_SUCCESS(rc))
9134 {
9135#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9136 if ( fIsNestedGuest
9137 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
9138 {
9139 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, u8Interrupt, false /* fIntPending */);
9140 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
9141 return rcStrict;
9142 }
9143#endif
9144 hmR0VmxSetPendingExtInt(pVCpu, u8Interrupt);
9145 Log4Func(("External interrupt (%#x) pending injection\n", u8Interrupt));
9146 }
9147 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
9148 {
9149 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
9150
9151 if ( !fIsNestedGuest
9152 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
9153 hmR0VmxApicSetTprThreshold(pVmcsInfo, u8Interrupt >> 4);
9154 /* else: for nested-guests, TPR threshold is picked up while merging VMCS controls. */
9155
9156 /*
9157 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
9158 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
9159 * need to re-set this force-flag here.
9160 */
9161 }
9162 else
9163 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
9164
9165 /* We've injected the interrupt or taken necessary action, bail. */
9166 return VINF_SUCCESS;
9167 }
9168 if (!fIsNestedGuest)
9169 hmR0VmxSetIntWindowExitVmcs(pVmcsInfo);
9170 }
9171 }
9172 else if (!fIsNestedGuest)
9173 {
9174 /*
9175 * An event is being injected or we are in an interrupt shadow. Check if another event is
9176 * pending. If so, instruct VT-x to cause a VM-exit as soon as the guest is ready to accept
9177 * the pending event.
9178 */
9179 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
9180 hmR0VmxSetNmiWindowExitVmcs(pVmcsInfo);
9181 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
9182 && !pVCpu->hm.s.fSingleInstruction)
9183 hmR0VmxSetIntWindowExitVmcs(pVmcsInfo);
9184 }
9185 /* else: for nested-guests, NMI/interrupt-window exiting will be picked up when merging VMCS controls. */
9186
9187 return VINF_SUCCESS;
9188}
9189
9190
9191/**
9192 * Injects any pending events into the guest if the guest is in a state to
9193 * receive them.
9194 *
9195 * @returns Strict VBox status code (i.e. informational status codes too).
9196 * @param pVCpu The cross context virtual CPU structure.
9197 * @param pVmxTransient The VMX-transient structure.
9198 * @param fIntrState The VT-x guest-interruptibility state.
9199 * @param fStepping Whether we are single-stepping the guest using the
9200 * hypervisor debugger and should return
9201 * VINF_EM_DBG_STEPPED if the event was dispatched
9202 * directly.
9203 */
9204static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t fIntrState, bool fStepping)
9205{
9206 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9207 Assert(VMMRZCallRing3IsEnabled(pVCpu));
9208
9209#ifdef VBOX_STRICT
9210 /*
9211 * Verify guest-interruptibility state.
9212 *
9213 * We put this in a scoped block so we do not accidentally use fBlockSti or fBlockMovSS,
9214 * since injecting an event may modify the interruptibility state and we must thus always
9215 * use fIntrState.
9216 */
9217 {
9218 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
9219 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
9220 Assert(!fBlockSti || !(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_RFLAGS));
9221 Assert(!fBlockSti || pVCpu->cpum.GstCtx.eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
9222 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
9223 Assert(!TRPMHasTrap(pVCpu));
9224 NOREF(fBlockMovSS); NOREF(fBlockSti);
9225 }
9226#endif
9227
9228 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
9229 if (pVCpu->hm.s.Event.fPending)
9230 {
9231 /*
9232 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
9233 * pending even while injecting an event and in this case, we want a VM-exit as soon as
9234 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
9235 *
9236 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
9237 */
9238 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
9239#ifdef VBOX_STRICT
9240 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
9241 {
9242 Assert(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_IF);
9243 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI));
9244 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
9245 }
9246 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_NMI)
9247 {
9248 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI));
9249 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI));
9250 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
9251 }
9252#endif
9253 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
9254 uIntType));
9255
9256 /*
9257 * Inject the event and get any changes to the guest-interruptibility state.
9258 *
9259 * The guest-interruptibility state may need to be updated if we inject the event
9260 * into the guest IDT ourselves (for real-on-v86 guest injecting software interrupts).
9261 */
9262 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &pVCpu->hm.s.Event, fStepping, &fIntrState);
9263 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
9264
9265 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
9266 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
9267 else
9268 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
9269 }
9270
9271 /*
9272 * Deliver any pending debug exceptions if the guest is single-stepping using EFLAGS.TF and
9273 * is an interrupt shadow (block-by-STI or block-by-MOV SS).
9274 */
9275 if ( (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
9276 && !pVmxTransient->fIsNestedGuest)
9277 {
9278 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
9279
9280 if (!pVCpu->hm.s.fSingleInstruction)
9281 {
9282 /*
9283 * Set or clear the BS bit depending on whether the trap flag is active or not. We need
9284 * to do both since we clear the BS bit from the VMCS while exiting to ring-3.
9285 */
9286 Assert(!DBGFIsStepping(pVCpu));
9287 uint8_t const fTrapFlag = !!(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_TF);
9288 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, fTrapFlag << VMX_BF_VMCS_PENDING_DBG_XCPT_BS_SHIFT);
9289 AssertRC(rc);
9290 }
9291 else
9292 {
9293 /*
9294 * We must not deliver a debug exception when single-stepping over STI/Mov-SS in the
9295 * hypervisor debugger using EFLAGS.TF but rather clear interrupt inhibition. However,
9296 * we take care of this case in hmR0VmxExportSharedDebugState and also the case if
9297 * we use MTF, so just make sure it's called before executing guest-code.
9298 */
9299 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR_MASK);
9300 }
9301 }
9302 /* else: for nested-guest currently handling while merging controls. */
9303
9304 /*
9305 * Finally, update the guest-interruptibility state.
9306 *
9307 * This is required for the real-on-v86 software interrupt injection, for
9308 * pending debug exceptions as well as updates to the guest state from ring-3 (IEM).
9309 */
9310 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
9311 AssertRC(rc);
9312
9313 /*
9314 * There's no need to clear the VM-entry interruption-information field here if we're not
9315 * injecting anything. VT-x clears the valid bit on every VM-exit.
9316 *
9317 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
9318 */
9319
9320 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
9321 return rcStrict;
9322}
9323
9324
9325/**
9326 * Enters the VT-x session.
9327 *
9328 * @returns VBox status code.
9329 * @param pVCpu The cross context virtual CPU structure.
9330 */
9331VMMR0DECL(int) VMXR0Enter(PVMCPUCC pVCpu)
9332{
9333 AssertPtr(pVCpu);
9334 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported);
9335 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9336
9337 LogFlowFunc(("pVCpu=%p\n", pVCpu));
9338 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9339 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
9340
9341#ifdef VBOX_STRICT
9342 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
9343 RTCCUINTREG uHostCr4 = ASMGetCR4();
9344 if (!(uHostCr4 & X86_CR4_VMXE))
9345 {
9346 LogRelFunc(("X86_CR4_VMXE bit in CR4 is not set!\n"));
9347 return VERR_VMX_X86_CR4_VMXE_CLEARED;
9348 }
9349#endif
9350
9351 /*
9352 * Do the EMT scheduled L1D and MDS flush here if needed.
9353 */
9354 if (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_L1D_SCHED)
9355 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
9356 else if (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_MDS_SCHED)
9357 hmR0MdsClear();
9358
9359 /*
9360 * Load the appropriate VMCS as the current and active one.
9361 */
9362 PVMXVMCSINFO pVmcsInfo;
9363 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx);
9364 if (!fInNestedGuestMode)
9365 pVmcsInfo = &pVCpu->hmr0.s.vmx.VmcsInfo;
9366 else
9367 pVmcsInfo = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
9368 int rc = hmR0VmxLoadVmcs(pVmcsInfo);
9369 if (RT_SUCCESS(rc))
9370 {
9371 pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs = fInNestedGuestMode;
9372 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcsCopyForRing3 = fInNestedGuestMode;
9373 pVCpu->hmr0.s.fLeaveDone = false;
9374 Log4Func(("Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
9375 }
9376 return rc;
9377}
9378
9379
9380/**
9381 * The thread-context callback.
9382 *
9383 * This is used together with RTThreadCtxHookCreate() on platforms which
9384 * supports it, and directly from VMMR0EmtPrepareForBlocking() and
9385 * VMMR0EmtResumeAfterBlocking() on platforms which don't.
9386 *
9387 * @param enmEvent The thread-context event.
9388 * @param pVCpu The cross context virtual CPU structure.
9389 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
9390 * @thread EMT(pVCpu)
9391 */
9392VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPUCC pVCpu, bool fGlobalInit)
9393{
9394 AssertPtr(pVCpu);
9395 RT_NOREF1(fGlobalInit);
9396
9397 switch (enmEvent)
9398 {
9399 case RTTHREADCTXEVENT_OUT:
9400 {
9401 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9402 VMCPU_ASSERT_EMT(pVCpu);
9403
9404 /* No longjmps (logger flushes, locks) in this fragile context. */
9405 VMMRZCallRing3Disable(pVCpu);
9406 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
9407
9408 /* Restore host-state (FPU, debug etc.) */
9409 if (!pVCpu->hmr0.s.fLeaveDone)
9410 {
9411 /*
9412 * Do -not- import the guest-state here as we might already be in the middle of importing
9413 * it, esp. bad if we're holding the PGM lock, see comment in hmR0VmxImportGuestState().
9414 */
9415 hmR0VmxLeave(pVCpu, false /* fImportState */);
9416 pVCpu->hmr0.s.fLeaveDone = true;
9417 }
9418
9419 /* Leave HM context, takes care of local init (term). */
9420 int rc = HMR0LeaveCpu(pVCpu);
9421 AssertRC(rc);
9422
9423 /* Restore longjmp state. */
9424 VMMRZCallRing3Enable(pVCpu);
9425 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
9426 break;
9427 }
9428
9429 case RTTHREADCTXEVENT_IN:
9430 {
9431 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9432 VMCPU_ASSERT_EMT(pVCpu);
9433
9434 /* Do the EMT scheduled L1D and MDS flush here if needed. */
9435 if (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_L1D_SCHED)
9436 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
9437 else if (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_MDS_SCHED)
9438 hmR0MdsClear();
9439
9440 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
9441 VMMRZCallRing3Disable(pVCpu);
9442 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
9443
9444 /* Initialize the bare minimum state required for HM. This takes care of
9445 initializing VT-x if necessary (onlined CPUs, local init etc.) */
9446 int rc = hmR0EnterCpu(pVCpu);
9447 AssertRC(rc);
9448 Assert( (pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9449 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
9450
9451 /* Load the active VMCS as the current one. */
9452 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
9453 rc = hmR0VmxLoadVmcs(pVmcsInfo);
9454 AssertRC(rc);
9455 Log4Func(("Resumed: Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
9456 pVCpu->hmr0.s.fLeaveDone = false;
9457
9458 /* Restore longjmp state. */
9459 VMMRZCallRing3Enable(pVCpu);
9460 break;
9461 }
9462
9463 default:
9464 break;
9465 }
9466}
9467
9468
9469/**
9470 * Exports the host state into the VMCS host-state area.
9471 * Sets up the VM-exit MSR-load area.
9472 *
9473 * The CPU state will be loaded from these fields on every successful VM-exit.
9474 *
9475 * @returns VBox status code.
9476 * @param pVCpu The cross context virtual CPU structure.
9477 *
9478 * @remarks No-long-jump zone!!!
9479 */
9480static int hmR0VmxExportHostState(PVMCPUCC pVCpu)
9481{
9482 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9483
9484 int rc = VINF_SUCCESS;
9485 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
9486 {
9487 uint64_t uHostCr4 = hmR0VmxExportHostControlRegs();
9488
9489 rc = hmR0VmxExportHostSegmentRegs(pVCpu, uHostCr4);
9490 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9491
9492 hmR0VmxExportHostMsrs(pVCpu);
9493
9494 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_HOST_CONTEXT;
9495 }
9496 return rc;
9497}
9498
9499
9500/**
9501 * Saves the host state in the VMCS host-state.
9502 *
9503 * @returns VBox status code.
9504 * @param pVCpu The cross context virtual CPU structure.
9505 *
9506 * @remarks No-long-jump zone!!!
9507 */
9508VMMR0DECL(int) VMXR0ExportHostState(PVMCPUCC pVCpu)
9509{
9510 AssertPtr(pVCpu);
9511 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9512
9513 /*
9514 * Export the host state here while entering HM context.
9515 * When thread-context hooks are used, we might get preempted and have to re-save the host
9516 * state but most of the time we won't be, so do it here before we disable interrupts.
9517 */
9518 return hmR0VmxExportHostState(pVCpu);
9519}
9520
9521
9522/**
9523 * Exports the guest state into the VMCS guest-state area.
9524 *
9525 * The will typically be done before VM-entry when the guest-CPU state and the
9526 * VMCS state may potentially be out of sync.
9527 *
9528 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
9529 * VM-entry controls.
9530 * Sets up the appropriate VMX non-root function to execute guest code based on
9531 * the guest CPU mode.
9532 *
9533 * @returns VBox strict status code.
9534 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9535 * without unrestricted guest execution and the VMMDev is not presently
9536 * mapped (e.g. EFI32).
9537 *
9538 * @param pVCpu The cross context virtual CPU structure.
9539 * @param pVmxTransient The VMX-transient structure.
9540 *
9541 * @remarks No-long-jump zone!!!
9542 */
9543static VBOXSTRICTRC hmR0VmxExportGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9544{
9545 AssertPtr(pVCpu);
9546 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9547 LogFlowFunc(("pVCpu=%p\n", pVCpu));
9548
9549 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExportGuestState, x);
9550
9551 /*
9552 * Determine real-on-v86 mode.
9553 * Used when the guest is in real-mode and unrestricted guest execution is not used.
9554 */
9555 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmxTransient->pVmcsInfo->pShared;
9556 if ( pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest
9557 || !CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx))
9558 pVmcsInfoShared->RealMode.fRealOnV86Active = false;
9559 else
9560 {
9561 Assert(!pVmxTransient->fIsNestedGuest);
9562 pVmcsInfoShared->RealMode.fRealOnV86Active = true;
9563 }
9564
9565 /*
9566 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
9567 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
9568 */
9569 int rc = hmR0VmxExportGuestEntryExitCtls(pVCpu, pVmxTransient);
9570 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9571
9572 rc = hmR0VmxExportGuestCR0(pVCpu, pVmxTransient);
9573 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9574
9575 VBOXSTRICTRC rcStrict = hmR0VmxExportGuestCR3AndCR4(pVCpu, pVmxTransient);
9576 if (rcStrict == VINF_SUCCESS)
9577 { /* likely */ }
9578 else
9579 {
9580 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
9581 return rcStrict;
9582 }
9583
9584 rc = hmR0VmxExportGuestSegRegsXdtr(pVCpu, pVmxTransient);
9585 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9586
9587 rc = hmR0VmxExportGuestMsrs(pVCpu, pVmxTransient);
9588 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9589
9590 hmR0VmxExportGuestApicTpr(pVCpu, pVmxTransient);
9591 hmR0VmxExportGuestXcptIntercepts(pVCpu, pVmxTransient);
9592 hmR0VmxExportGuestRip(pVCpu);
9593 hmR0VmxExportGuestRsp(pVCpu);
9594 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9595
9596 rc = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9597 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9598
9599 /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
9600 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~( (HM_CHANGED_GUEST_GPRS_MASK & ~HM_CHANGED_GUEST_RSP)
9601 | HM_CHANGED_GUEST_CR2
9602 | (HM_CHANGED_GUEST_DR_MASK & ~HM_CHANGED_GUEST_DR7)
9603 | HM_CHANGED_GUEST_X87
9604 | HM_CHANGED_GUEST_SSE_AVX
9605 | HM_CHANGED_GUEST_OTHER_XSAVE
9606 | HM_CHANGED_GUEST_XCRx
9607 | HM_CHANGED_GUEST_KERNEL_GS_BASE /* Part of lazy or auto load-store MSRs. */
9608 | HM_CHANGED_GUEST_SYSCALL_MSRS /* Part of lazy or auto load-store MSRs. */
9609 | HM_CHANGED_GUEST_TSC_AUX
9610 | HM_CHANGED_GUEST_OTHER_MSRS
9611 | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
9612
9613 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExportGuestState, x);
9614 return rc;
9615}
9616
9617
9618/**
9619 * Exports the state shared between the host and guest into the VMCS.
9620 *
9621 * @param pVCpu The cross context virtual CPU structure.
9622 * @param pVmxTransient The VMX-transient structure.
9623 *
9624 * @remarks No-long-jump zone!!!
9625 */
9626static void hmR0VmxExportSharedState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9627{
9628 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9629 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9630
9631 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_DR_MASK)
9632 {
9633 int rc = hmR0VmxExportSharedDebugState(pVCpu, pVmxTransient);
9634 AssertRC(rc);
9635 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_GUEST_DR_MASK;
9636
9637 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
9638 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_RFLAGS)
9639 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9640 }
9641
9642 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_GUEST_LAZY_MSRS)
9643 {
9644 hmR0VmxLazyLoadGuestMsrs(pVCpu);
9645 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_VMX_GUEST_LAZY_MSRS;
9646 }
9647
9648 AssertMsg(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE),
9649 ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
9650}
9651
9652
9653/**
9654 * Worker for loading the guest-state bits in the inner VT-x execution loop.
9655 *
9656 * @returns Strict VBox status code (i.e. informational status codes too).
9657 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9658 * without unrestricted guest execution and the VMMDev is not presently
9659 * mapped (e.g. EFI32).
9660 *
9661 * @param pVCpu The cross context virtual CPU structure.
9662 * @param pVmxTransient The VMX-transient structure.
9663 *
9664 * @remarks No-long-jump zone!!!
9665 */
9666static VBOXSTRICTRC hmR0VmxExportGuestStateOptimal(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9667{
9668 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9669 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9670
9671#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
9672 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
9673#endif
9674
9675 /*
9676 * For many VM-exits only RIP/RSP/RFLAGS (and HWVIRT state when executing a nested-guest)
9677 * changes. First try to export only these without going through all other changed-flag checks.
9678 */
9679 VBOXSTRICTRC rcStrict;
9680 uint64_t const fCtxMask = HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE;
9681 uint64_t const fMinimalMask = HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT;
9682 uint64_t const fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9683
9684 /* If only RIP/RSP/RFLAGS/HWVIRT changed, export only those (quicker, happens more often).*/
9685 if ( (fCtxChanged & fMinimalMask)
9686 && !(fCtxChanged & (fCtxMask & ~fMinimalMask)))
9687 {
9688 hmR0VmxExportGuestRip(pVCpu);
9689 hmR0VmxExportGuestRsp(pVCpu);
9690 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9691 rcStrict = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9692 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportMinimal);
9693 }
9694 /* If anything else also changed, go through the full export routine and export as required. */
9695 else if (fCtxChanged & fCtxMask)
9696 {
9697 rcStrict = hmR0VmxExportGuestState(pVCpu, pVmxTransient);
9698 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9699 { /* likely */}
9700 else
9701 {
9702 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM, ("Failed to export guest state! rc=%Rrc\n",
9703 VBOXSTRICTRC_VAL(rcStrict)));
9704 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9705 return rcStrict;
9706 }
9707 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportFull);
9708 }
9709 /* Nothing changed, nothing to load here. */
9710 else
9711 rcStrict = VINF_SUCCESS;
9712
9713#ifdef VBOX_STRICT
9714 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
9715 uint64_t const fCtxChangedCur = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9716 AssertMsg(!(fCtxChangedCur & fCtxMask), ("fCtxChangedCur=%#RX64\n", fCtxChangedCur));
9717#endif
9718 return rcStrict;
9719}
9720
9721
9722/**
9723 * Tries to determine what part of the guest-state VT-x has deemed as invalid
9724 * and update error record fields accordingly.
9725 *
9726 * @returns VMX_IGS_* error codes.
9727 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
9728 * wrong with the guest state.
9729 *
9730 * @param pVCpu The cross context virtual CPU structure.
9731 * @param pVmcsInfo The VMCS info. object.
9732 *
9733 * @remarks This function assumes our cache of the VMCS controls
9734 * are valid, i.e. hmR0VmxCheckCachedVmcsCtls() succeeded.
9735 */
9736static uint32_t hmR0VmxCheckGuestState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
9737{
9738#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
9739#define HMVMX_CHECK_BREAK(expr, err) do { \
9740 if (!(expr)) { uError = (err); break; } \
9741 } while (0)
9742
9743 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9744 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9745 uint32_t uError = VMX_IGS_ERROR;
9746 uint32_t u32IntrState = 0;
9747 bool const fUnrestrictedGuest = pVM->hmr0.s.vmx.fUnrestrictedGuest;
9748 do
9749 {
9750 int rc;
9751
9752 /*
9753 * Guest-interruptibility state.
9754 *
9755 * Read this first so that any check that fails prior to those that actually
9756 * require the guest-interruptibility state would still reflect the correct
9757 * VMCS value and avoids causing further confusion.
9758 */
9759 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32IntrState);
9760 AssertRC(rc);
9761
9762 uint32_t u32Val;
9763 uint64_t u64Val;
9764
9765 /*
9766 * CR0.
9767 */
9768 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9769 uint64_t fSetCr0 = (g_HmMsrs.u.vmx.u64Cr0Fixed0 & g_HmMsrs.u.vmx.u64Cr0Fixed1);
9770 uint64_t const fZapCr0 = (g_HmMsrs.u.vmx.u64Cr0Fixed0 | g_HmMsrs.u.vmx.u64Cr0Fixed1);
9771 /* Exceptions for unrestricted guest execution for CR0 fixed bits (PE, PG).
9772 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
9773 if (fUnrestrictedGuest)
9774 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
9775
9776 uint64_t u64GuestCr0;
9777 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64GuestCr0);
9778 AssertRC(rc);
9779 HMVMX_CHECK_BREAK((u64GuestCr0 & fSetCr0) == fSetCr0, VMX_IGS_CR0_FIXED1);
9780 HMVMX_CHECK_BREAK(!(u64GuestCr0 & ~fZapCr0), VMX_IGS_CR0_FIXED0);
9781 if ( !fUnrestrictedGuest
9782 && (u64GuestCr0 & X86_CR0_PG)
9783 && !(u64GuestCr0 & X86_CR0_PE))
9784 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
9785
9786 /*
9787 * CR4.
9788 */
9789 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9790 uint64_t const fSetCr4 = (g_HmMsrs.u.vmx.u64Cr4Fixed0 & g_HmMsrs.u.vmx.u64Cr4Fixed1);
9791 uint64_t const fZapCr4 = (g_HmMsrs.u.vmx.u64Cr4Fixed0 | g_HmMsrs.u.vmx.u64Cr4Fixed1);
9792
9793 uint64_t u64GuestCr4;
9794 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64GuestCr4);
9795 AssertRC(rc);
9796 HMVMX_CHECK_BREAK((u64GuestCr4 & fSetCr4) == fSetCr4, VMX_IGS_CR4_FIXED1);
9797 HMVMX_CHECK_BREAK(!(u64GuestCr4 & ~fZapCr4), VMX_IGS_CR4_FIXED0);
9798
9799 /*
9800 * IA32_DEBUGCTL MSR.
9801 */
9802 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
9803 AssertRC(rc);
9804 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9805 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
9806 {
9807 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
9808 }
9809 uint64_t u64DebugCtlMsr = u64Val;
9810
9811#ifdef VBOX_STRICT
9812 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
9813 AssertRC(rc);
9814 Assert(u32Val == pVmcsInfo->u32EntryCtls);
9815#endif
9816 bool const fLongModeGuest = RT_BOOL(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
9817
9818 /*
9819 * RIP and RFLAGS.
9820 */
9821 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
9822 AssertRC(rc);
9823 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
9824 if ( !fLongModeGuest
9825 || !pCtx->cs.Attr.n.u1Long)
9826 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
9827 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
9828 * must be identical if the "IA-32e mode guest" VM-entry
9829 * control is 1 and CS.L is 1. No check applies if the
9830 * CPU supports 64 linear-address bits. */
9831
9832 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
9833 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
9834 AssertRC(rc);
9835 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
9836 VMX_IGS_RFLAGS_RESERVED);
9837 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
9838 uint32_t const u32Eflags = u64Val;
9839
9840 if ( fLongModeGuest
9841 || ( fUnrestrictedGuest
9842 && !(u64GuestCr0 & X86_CR0_PE)))
9843 {
9844 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
9845 }
9846
9847 uint32_t u32EntryInfo;
9848 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
9849 AssertRC(rc);
9850 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9851 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
9852
9853 /*
9854 * 64-bit checks.
9855 */
9856 if (fLongModeGuest)
9857 {
9858 HMVMX_CHECK_BREAK(u64GuestCr0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
9859 HMVMX_CHECK_BREAK(u64GuestCr4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
9860 }
9861
9862 if ( !fLongModeGuest
9863 && (u64GuestCr4 & X86_CR4_PCIDE))
9864 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
9865
9866 /** @todo CR3 field must be such that bits 63:52 and bits in the range
9867 * 51:32 beyond the processor's physical-address width are 0. */
9868
9869 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9870 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
9871 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
9872
9873 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
9874 AssertRC(rc);
9875 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
9876
9877 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
9878 AssertRC(rc);
9879 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
9880
9881 /*
9882 * PERF_GLOBAL MSR.
9883 */
9884 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR)
9885 {
9886 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
9887 AssertRC(rc);
9888 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
9889 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
9890 }
9891
9892 /*
9893 * PAT MSR.
9894 */
9895 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
9896 {
9897 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
9898 AssertRC(rc);
9899 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
9900 for (unsigned i = 0; i < 8; i++)
9901 {
9902 uint8_t u8Val = (u64Val & 0xff);
9903 if ( u8Val != 0 /* UC */
9904 && u8Val != 1 /* WC */
9905 && u8Val != 4 /* WT */
9906 && u8Val != 5 /* WP */
9907 && u8Val != 6 /* WB */
9908 && u8Val != 7 /* UC- */)
9909 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
9910 u64Val >>= 8;
9911 }
9912 }
9913
9914 /*
9915 * EFER MSR.
9916 */
9917 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
9918 {
9919 Assert(g_fHmVmxSupportsVmcsEfer);
9920 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
9921 AssertRC(rc);
9922 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
9923 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
9924 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVmcsInfo->u32EntryCtls
9925 & VMX_ENTRY_CTLS_IA32E_MODE_GUEST),
9926 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
9927 /** @todo r=ramshankar: Unrestricted check here is probably wrong, see
9928 * iemVmxVmentryCheckGuestState(). */
9929 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9930 || !(u64GuestCr0 & X86_CR0_PG)
9931 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
9932 VMX_IGS_EFER_LMA_LME_MISMATCH);
9933 }
9934
9935 /*
9936 * Segment registers.
9937 */
9938 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9939 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
9940 if (!(u32Eflags & X86_EFL_VM))
9941 {
9942 /* CS */
9943 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
9944 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
9945 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
9946 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
9947 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9948 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
9949 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9950 /* CS cannot be loaded with NULL in protected mode. */
9951 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
9952 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
9953 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
9954 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
9955 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
9956 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
9957 else if (fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
9958 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
9959 else
9960 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
9961
9962 /* SS */
9963 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9964 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
9965 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
9966 if ( !(pCtx->cr0 & X86_CR0_PE)
9967 || pCtx->cs.Attr.n.u4Type == 3)
9968 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
9969
9970 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
9971 {
9972 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
9973 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
9974 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
9975 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
9976 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
9977 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9978 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
9979 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9980 }
9981
9982 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSReg(). */
9983 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
9984 {
9985 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
9986 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
9987 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9988 || pCtx->ds.Attr.n.u4Type > 11
9989 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9990 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
9991 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
9992 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
9993 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9994 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
9995 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9996 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9997 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
9998 }
9999 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
10000 {
10001 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
10002 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
10003 HMVMX_CHECK_BREAK( fUnrestrictedGuest
10004 || pCtx->es.Attr.n.u4Type > 11
10005 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
10006 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
10007 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
10008 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
10009 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
10010 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
10011 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
10012 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10013 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
10014 }
10015 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
10016 {
10017 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
10018 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
10019 HMVMX_CHECK_BREAK( fUnrestrictedGuest
10020 || pCtx->fs.Attr.n.u4Type > 11
10021 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
10022 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
10023 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
10024 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
10025 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
10026 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
10027 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
10028 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10029 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
10030 }
10031 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
10032 {
10033 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
10034 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
10035 HMVMX_CHECK_BREAK( fUnrestrictedGuest
10036 || pCtx->gs.Attr.n.u4Type > 11
10037 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
10038 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
10039 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
10040 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
10041 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
10042 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
10043 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
10044 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10045 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
10046 }
10047 /* 64-bit capable CPUs. */
10048 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
10049 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
10050 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10051 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
10052 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
10053 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
10054 VMX_IGS_LONGMODE_SS_BASE_INVALID);
10055 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
10056 VMX_IGS_LONGMODE_DS_BASE_INVALID);
10057 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
10058 VMX_IGS_LONGMODE_ES_BASE_INVALID);
10059 }
10060 else
10061 {
10062 /* V86 mode checks. */
10063 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
10064 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
10065 {
10066 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
10067 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
10068 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
10069 }
10070 else
10071 {
10072 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
10073 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
10074 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
10075 }
10076
10077 /* CS */
10078 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
10079 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
10080 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
10081 /* SS */
10082 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
10083 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
10084 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
10085 /* DS */
10086 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
10087 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
10088 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
10089 /* ES */
10090 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
10091 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
10092 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
10093 /* FS */
10094 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
10095 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
10096 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
10097 /* GS */
10098 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
10099 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
10100 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
10101 /* 64-bit capable CPUs. */
10102 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
10103 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
10104 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10105 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
10106 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
10107 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
10108 VMX_IGS_LONGMODE_SS_BASE_INVALID);
10109 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
10110 VMX_IGS_LONGMODE_DS_BASE_INVALID);
10111 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
10112 VMX_IGS_LONGMODE_ES_BASE_INVALID);
10113 }
10114
10115 /*
10116 * TR.
10117 */
10118 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
10119 /* 64-bit capable CPUs. */
10120 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
10121 if (fLongModeGuest)
10122 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
10123 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
10124 else
10125 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
10126 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
10127 VMX_IGS_TR_ATTR_TYPE_INVALID);
10128 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
10129 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
10130 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
10131 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
10132 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
10133 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
10134 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
10135 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
10136
10137 /*
10138 * GDTR and IDTR (64-bit capable checks).
10139 */
10140 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
10141 AssertRC(rc);
10142 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
10143
10144 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
10145 AssertRC(rc);
10146 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
10147
10148 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
10149 AssertRC(rc);
10150 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
10151
10152 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
10153 AssertRC(rc);
10154 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
10155
10156 /*
10157 * Guest Non-Register State.
10158 */
10159 /* Activity State. */
10160 uint32_t u32ActivityState;
10161 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
10162 AssertRC(rc);
10163 HMVMX_CHECK_BREAK( !u32ActivityState
10164 || (u32ActivityState & RT_BF_GET(g_HmMsrs.u.vmx.u64Misc, VMX_BF_MISC_ACTIVITY_STATES)),
10165 VMX_IGS_ACTIVITY_STATE_INVALID);
10166 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
10167 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
10168
10169 if ( u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS
10170 || u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
10171 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
10172
10173 /** @todo Activity state and injecting interrupts. Left as a todo since we
10174 * currently don't use activity states but ACTIVE. */
10175
10176 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
10177 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
10178
10179 /* Guest interruptibility-state. */
10180 HMVMX_CHECK_BREAK(!(u32IntrState & 0xffffffe0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
10181 HMVMX_CHECK_BREAK((u32IntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
10182 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
10183 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
10184 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
10185 || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
10186 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
10187 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
10188 {
10189 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
10190 && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
10191 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
10192 }
10193 else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
10194 {
10195 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
10196 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
10197 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
10198 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
10199 }
10200 /** @todo Assumes the processor is not in SMM. */
10201 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
10202 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
10203 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
10204 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
10205 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
10206 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
10207 && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
10208 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI), VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
10209
10210 /* Pending debug exceptions. */
10211 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &u64Val);
10212 AssertRC(rc);
10213 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
10214 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
10215 u32Val = u64Val; /* For pending debug exceptions checks below. */
10216
10217 if ( (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
10218 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
10219 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
10220 {
10221 if ( (u32Eflags & X86_EFL_TF)
10222 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
10223 {
10224 /* Bit 14 is PendingDebug.BS. */
10225 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
10226 }
10227 if ( !(u32Eflags & X86_EFL_TF)
10228 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
10229 {
10230 /* Bit 14 is PendingDebug.BS. */
10231 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
10232 }
10233 }
10234
10235 /* VMCS link pointer. */
10236 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
10237 AssertRC(rc);
10238 if (u64Val != UINT64_C(0xffffffffffffffff))
10239 {
10240 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
10241 /** @todo Bits beyond the processor's physical-address width MBZ. */
10242 /** @todo SMM checks. */
10243 Assert(pVmcsInfo->HCPhysShadowVmcs == u64Val);
10244 Assert(pVmcsInfo->pvShadowVmcs);
10245 VMXVMCSREVID VmcsRevId;
10246 VmcsRevId.u = *(uint32_t *)pVmcsInfo->pvShadowVmcs;
10247 HMVMX_CHECK_BREAK(VmcsRevId.n.u31RevisionId == RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID),
10248 VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID);
10249 HMVMX_CHECK_BREAK(VmcsRevId.n.fIsShadowVmcs == (uint32_t)!!(pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING),
10250 VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW);
10251 }
10252
10253 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
10254 * not using nested paging? */
10255 if ( pVM->hmr0.s.fNestedPaging
10256 && !fLongModeGuest
10257 && CPUMIsGuestInPAEModeEx(pCtx))
10258 {
10259 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
10260 AssertRC(rc);
10261 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10262
10263 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
10264 AssertRC(rc);
10265 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10266
10267 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
10268 AssertRC(rc);
10269 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10270
10271 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
10272 AssertRC(rc);
10273 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10274 }
10275
10276 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
10277 if (uError == VMX_IGS_ERROR)
10278 uError = VMX_IGS_REASON_NOT_FOUND;
10279 } while (0);
10280
10281 pVCpu->hm.s.u32HMError = uError;
10282 pVCpu->hm.s.vmx.LastError.u32GuestIntrState = u32IntrState;
10283 return uError;
10284
10285#undef HMVMX_ERROR_BREAK
10286#undef HMVMX_CHECK_BREAK
10287}
10288
10289
10290/**
10291 * Map the APIC-access page for virtualizing APIC accesses.
10292 *
10293 * This can cause a longjumps to R3 due to the acquisition of the PGM lock. Hence,
10294 * this not done as part of exporting guest state, see @bugref{8721}.
10295 *
10296 * @returns VBox status code.
10297 * @param pVCpu The cross context virtual CPU structure.
10298 */
10299static int hmR0VmxMapHCApicAccessPage(PVMCPUCC pVCpu)
10300{
10301 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10302 uint64_t const u64MsrApicBase = APICGetBaseMsrNoCheck(pVCpu);
10303
10304 Assert(PDMHasApic(pVM));
10305 Assert(u64MsrApicBase);
10306
10307 RTGCPHYS const GCPhysApicBase = u64MsrApicBase & PAGE_BASE_GC_MASK;
10308 Log4Func(("Mappping HC APIC-access page at %#RGp\n", GCPhysApicBase));
10309
10310 /* Unalias the existing mapping. */
10311 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
10312 AssertRCReturn(rc, rc);
10313
10314 /* Map the HC APIC-access page in place of the MMIO page, also updates the shadow page tables if necessary. */
10315 Assert(pVM->hmr0.s.vmx.HCPhysApicAccess != NIL_RTHCPHYS);
10316 rc = IOMR0MmioMapMmioHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hmr0.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
10317 AssertRCReturn(rc, rc);
10318
10319 /* Update the per-VCPU cache of the APIC base MSR. */
10320 pVCpu->hm.s.vmx.u64GstMsrApicBase = u64MsrApicBase;
10321 return VINF_SUCCESS;
10322}
10323
10324
10325/**
10326 * Worker function passed to RTMpOnSpecific() that is to be called on the target
10327 * CPU.
10328 *
10329 * @param idCpu The ID for the CPU the function is called on.
10330 * @param pvUser1 Null, not used.
10331 * @param pvUser2 Null, not used.
10332 */
10333static DECLCALLBACK(void) hmR0DispatchHostNmi(RTCPUID idCpu, void *pvUser1, void *pvUser2)
10334{
10335 RT_NOREF3(idCpu, pvUser1, pvUser2);
10336 VMXDispatchHostNmi();
10337}
10338
10339
10340/**
10341 * Dispatching an NMI on the host CPU that received it.
10342 *
10343 * @returns VBox status code.
10344 * @param pVCpu The cross context virtual CPU structure.
10345 * @param pVmcsInfo The VMCS info. object corresponding to the VMCS that was
10346 * executing when receiving the host NMI in VMX non-root
10347 * operation.
10348 */
10349static int hmR0VmxExitHostNmi(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
10350{
10351 RTCPUID const idCpu = pVmcsInfo->idHostCpuExec;
10352 Assert(idCpu != NIL_RTCPUID);
10353
10354 /*
10355 * We don't want to delay dispatching the NMI any more than we have to. However,
10356 * we have already chosen -not- to dispatch NMIs when interrupts were still disabled
10357 * after executing guest or nested-guest code for the following reasons:
10358 *
10359 * - We would need to perform VMREADs with interrupts disabled and is orders of
10360 * magnitude worse when we run as a nested hypervisor without VMCS shadowing
10361 * supported by the host hypervisor.
10362 *
10363 * - It affects the common VM-exit scenario and keeps interrupts disabled for a
10364 * longer period of time just for handling an edge case like host NMIs which do
10365 * not occur nearly as frequently as other VM-exits.
10366 *
10367 * Let's cover the most likely scenario first. Check if we are on the target CPU
10368 * and dispatch the NMI right away. This should be much faster than calling into
10369 * RTMpOnSpecific() machinery.
10370 */
10371 bool fDispatched = false;
10372 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
10373 if (idCpu == RTMpCpuId())
10374 {
10375 VMXDispatchHostNmi();
10376 fDispatched = true;
10377 }
10378 ASMSetFlags(fEFlags);
10379 if (fDispatched)
10380 {
10381 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
10382 return VINF_SUCCESS;
10383 }
10384
10385 /*
10386 * RTMpOnSpecific() waits until the worker function has run on the target CPU. So
10387 * there should be no race or recursion even if we are unlucky enough to be preempted
10388 * (to the target CPU) without dispatching the host NMI above.
10389 */
10390 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGCIpi);
10391 return RTMpOnSpecific(idCpu, &hmR0DispatchHostNmi, NULL /* pvUser1 */, NULL /* pvUser2 */);
10392}
10393
10394
10395#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10396/**
10397 * Merges the guest with the nested-guest MSR bitmap in preparation of executing the
10398 * nested-guest using hardware-assisted VMX.
10399 *
10400 * @param pVCpu The cross context virtual CPU structure.
10401 * @param pVmcsInfoNstGst The nested-guest VMCS info. object.
10402 * @param pVmcsInfoGst The guest VMCS info. object.
10403 */
10404static void hmR0VmxMergeMsrBitmapNested(PCVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfoNstGst, PCVMXVMCSINFO pVmcsInfoGst)
10405{
10406 uint32_t const cbMsrBitmap = X86_PAGE_4K_SIZE;
10407 uint64_t *pu64MsrBitmap = (uint64_t *)pVmcsInfoNstGst->pvMsrBitmap;
10408 Assert(pu64MsrBitmap);
10409
10410 /*
10411 * We merge the guest MSR bitmap with the nested-guest MSR bitmap such that any
10412 * MSR that is intercepted by the guest is also intercepted while executing the
10413 * nested-guest using hardware-assisted VMX.
10414 *
10415 * Note! If the nested-guest is not using an MSR bitmap, every MSR must cause a
10416 * nested-guest VM-exit even if the outer guest is not intercepting some
10417 * MSRs. We cannot assume the caller has initialized the nested-guest
10418 * MSR bitmap in this case.
10419 *
10420 * The nested hypervisor may also switch whether it uses MSR bitmaps for
10421 * each of its VM-entry, hence initializing it once per-VM while setting
10422 * up the nested-guest VMCS is not sufficient.
10423 */
10424 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
10425 if (pVmcsNstGst->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10426 {
10427 uint64_t const *pu64MsrBitmapNstGst = (uint64_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
10428 uint64_t const *pu64MsrBitmapGst = (uint64_t const *)pVmcsInfoGst->pvMsrBitmap;
10429 Assert(pu64MsrBitmapNstGst);
10430 Assert(pu64MsrBitmapGst);
10431
10432 /** @todo Detect and use EVEX.POR? */
10433 uint32_t const cFrags = cbMsrBitmap / sizeof(uint64_t);
10434 for (uint32_t i = 0; i < cFrags; i++)
10435 pu64MsrBitmap[i] = pu64MsrBitmapNstGst[i] | pu64MsrBitmapGst[i];
10436 }
10437 else
10438 ASMMemFill32(pu64MsrBitmap, cbMsrBitmap, UINT32_C(0xffffffff));
10439}
10440
10441
10442/**
10443 * Merges the guest VMCS in to the nested-guest VMCS controls in preparation of
10444 * hardware-assisted VMX execution of the nested-guest.
10445 *
10446 * For a guest, we don't modify these controls once we set up the VMCS and hence
10447 * this function is never called.
10448 *
10449 * For nested-guests since the nested hypervisor provides these controls on every
10450 * nested-guest VM-entry and could potentially change them everytime we need to
10451 * merge them before every nested-guest VM-entry.
10452 *
10453 * @returns VBox status code.
10454 * @param pVCpu The cross context virtual CPU structure.
10455 */
10456static int hmR0VmxMergeVmcsNested(PVMCPUCC pVCpu)
10457{
10458 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10459 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
10460 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
10461 Assert(pVmcsNstGst);
10462
10463 /*
10464 * Merge the controls with the requirements of the guest VMCS.
10465 *
10466 * We do not need to validate the nested-guest VMX features specified in the nested-guest
10467 * VMCS with the features supported by the physical CPU as it's already done by the
10468 * VMLAUNCH/VMRESUME instruction emulation.
10469 *
10470 * This is because the VMX features exposed by CPUM (through CPUID/MSRs) to the guest are
10471 * derived from the VMX features supported by the physical CPU.
10472 */
10473
10474 /* Pin-based VM-execution controls. */
10475 uint32_t const u32PinCtls = pVmcsNstGst->u32PinCtls | pVmcsInfoGst->u32PinCtls;
10476
10477 /* Processor-based VM-execution controls. */
10478 uint32_t u32ProcCtls = (pVmcsNstGst->u32ProcCtls & ~VMX_PROC_CTLS_USE_IO_BITMAPS)
10479 | (pVmcsInfoGst->u32ProcCtls & ~( VMX_PROC_CTLS_INT_WINDOW_EXIT
10480 | VMX_PROC_CTLS_NMI_WINDOW_EXIT
10481 | VMX_PROC_CTLS_MOV_DR_EXIT
10482 | VMX_PROC_CTLS_USE_TPR_SHADOW
10483 | VMX_PROC_CTLS_MONITOR_TRAP_FLAG));
10484
10485 /* Secondary processor-based VM-execution controls. */
10486 uint32_t const u32ProcCtls2 = (pVmcsNstGst->u32ProcCtls2 & ~VMX_PROC_CTLS2_VPID)
10487 | (pVmcsInfoGst->u32ProcCtls2 & ~( VMX_PROC_CTLS2_VIRT_APIC_ACCESS
10488 | VMX_PROC_CTLS2_INVPCID
10489 | VMX_PROC_CTLS2_VMCS_SHADOWING
10490 | VMX_PROC_CTLS2_RDTSCP
10491 | VMX_PROC_CTLS2_XSAVES_XRSTORS
10492 | VMX_PROC_CTLS2_APIC_REG_VIRT
10493 | VMX_PROC_CTLS2_VIRT_INT_DELIVERY
10494 | VMX_PROC_CTLS2_VMFUNC));
10495
10496 /*
10497 * VM-entry controls:
10498 * These controls contains state that depends on the nested-guest state (primarily
10499 * EFER MSR) and is thus not constant between VMLAUNCH/VMRESUME and the nested-guest
10500 * VM-exit. Although the nested hypervisor cannot change it, we need to in order to
10501 * properly continue executing the nested-guest if the EFER MSR changes but does not
10502 * cause a nested-guest VM-exits.
10503 *
10504 * VM-exit controls:
10505 * These controls specify the host state on return. We cannot use the controls from
10506 * the nested hypervisor state as is as it would contain the guest state rather than
10507 * the host state. Since the host state is subject to change (e.g. preemption, trips
10508 * to ring-3, longjmp and rescheduling to a different host CPU) they are not constant
10509 * through VMLAUNCH/VMRESUME and the nested-guest VM-exit.
10510 *
10511 * VM-entry MSR-load:
10512 * The guest MSRs from the VM-entry MSR-load area are already loaded into the guest-CPU
10513 * context by the VMLAUNCH/VMRESUME instruction emulation.
10514 *
10515 * VM-exit MSR-store:
10516 * The VM-exit emulation will take care of populating the MSRs from the guest-CPU context
10517 * back into the VM-exit MSR-store area.
10518 *
10519 * VM-exit MSR-load areas:
10520 * This must contain the real host MSRs with hardware-assisted VMX execution. Hence, we
10521 * can entirely ignore what the nested hypervisor wants to load here.
10522 */
10523
10524 /*
10525 * Exception bitmap.
10526 *
10527 * We could remove #UD from the guest bitmap and merge it with the nested-guest bitmap
10528 * here (and avoid doing anything while exporting nested-guest state), but to keep the
10529 * code more flexible if intercepting exceptions become more dynamic in the future we do
10530 * it as part of exporting the nested-guest state.
10531 */
10532 uint32_t const u32XcptBitmap = pVmcsNstGst->u32XcptBitmap | pVmcsInfoGst->u32XcptBitmap;
10533
10534 /*
10535 * CR0/CR4 guest/host mask.
10536 *
10537 * Modifications by the nested-guest to CR0/CR4 bits owned by the host and the guest must
10538 * cause VM-exits, so we need to merge them here.
10539 */
10540 uint64_t const u64Cr0Mask = pVmcsNstGst->u64Cr0Mask.u | pVmcsInfoGst->u64Cr0Mask;
10541 uint64_t const u64Cr4Mask = pVmcsNstGst->u64Cr4Mask.u | pVmcsInfoGst->u64Cr4Mask;
10542
10543 /*
10544 * Page-fault error-code mask and match.
10545 *
10546 * Although we require unrestricted guest execution (and thereby nested-paging) for
10547 * hardware-assisted VMX execution of nested-guests and thus the outer guest doesn't
10548 * normally intercept #PFs, it might intercept them for debugging purposes.
10549 *
10550 * If the outer guest is not intercepting #PFs, we can use the nested-guest #PF filters.
10551 * If the outer guest is intercepting #PFs, we must intercept all #PFs.
10552 */
10553 uint32_t u32XcptPFMask;
10554 uint32_t u32XcptPFMatch;
10555 if (!(pVmcsInfoGst->u32XcptBitmap & RT_BIT(X86_XCPT_PF)))
10556 {
10557 u32XcptPFMask = pVmcsNstGst->u32XcptPFMask;
10558 u32XcptPFMatch = pVmcsNstGst->u32XcptPFMatch;
10559 }
10560 else
10561 {
10562 u32XcptPFMask = 0;
10563 u32XcptPFMatch = 0;
10564 }
10565
10566 /*
10567 * Pause-Loop exiting.
10568 */
10569 /** @todo r=bird: given that both pVM->hm.s.vmx.cPleGapTicks and
10570 * pVM->hm.s.vmx.cPleWindowTicks defaults to zero, I cannot see how
10571 * this will work... */
10572 uint32_t const cPleGapTicks = RT_MIN(pVM->hm.s.vmx.cPleGapTicks, pVmcsNstGst->u32PleGap);
10573 uint32_t const cPleWindowTicks = RT_MIN(pVM->hm.s.vmx.cPleWindowTicks, pVmcsNstGst->u32PleWindow);
10574
10575 /*
10576 * Pending debug exceptions.
10577 * Currently just copy whatever the nested-guest provides us.
10578 */
10579 uint64_t const uPendingDbgXcpts = pVmcsNstGst->u64GuestPendingDbgXcpts.u;
10580
10581 /*
10582 * I/O Bitmap.
10583 *
10584 * We do not use the I/O bitmap that may be provided by the nested hypervisor as we always
10585 * intercept all I/O port accesses.
10586 */
10587 Assert(u32ProcCtls & VMX_PROC_CTLS_UNCOND_IO_EXIT);
10588 Assert(!(u32ProcCtls & VMX_PROC_CTLS_USE_IO_BITMAPS));
10589
10590 /*
10591 * VMCS shadowing.
10592 *
10593 * We do not yet expose VMCS shadowing to the guest and thus VMCS shadowing should not be
10594 * enabled while executing the nested-guest.
10595 */
10596 Assert(!(u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING));
10597
10598 /*
10599 * APIC-access page.
10600 */
10601 RTHCPHYS HCPhysApicAccess;
10602 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10603 {
10604 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
10605 RTGCPHYS const GCPhysApicAccess = pVmcsNstGst->u64AddrApicAccess.u;
10606
10607 /** @todo NSTVMX: This is not really correct but currently is required to make
10608 * things work. We need to re-enable the page handler when we fallback to
10609 * IEM execution of the nested-guest! */
10610 PGMHandlerPhysicalPageTempOff(pVM, GCPhysApicAccess, GCPhysApicAccess);
10611
10612 void *pvPage;
10613 PGMPAGEMAPLOCK PgLockApicAccess;
10614 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysApicAccess, &pvPage, &PgLockApicAccess);
10615 if (RT_SUCCESS(rc))
10616 {
10617 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysApicAccess, &HCPhysApicAccess);
10618 AssertMsgRCReturn(rc, ("Failed to get host-physical address for APIC-access page at %#RGp\n", GCPhysApicAccess), rc);
10619
10620 /** @todo Handle proper releasing of page-mapping lock later. */
10621 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockApicAccess);
10622 }
10623 else
10624 return rc;
10625 }
10626 else
10627 HCPhysApicAccess = 0;
10628
10629 /*
10630 * Virtual-APIC page and TPR threshold.
10631 */
10632 RTHCPHYS HCPhysVirtApic;
10633 uint32_t u32TprThreshold;
10634 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10635 {
10636 Assert(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW);
10637 RTGCPHYS const GCPhysVirtApic = pVmcsNstGst->u64AddrVirtApic.u;
10638
10639 void *pvPage;
10640 PGMPAGEMAPLOCK PgLockVirtApic;
10641 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysVirtApic, &pvPage, &PgLockVirtApic);
10642 if (RT_SUCCESS(rc))
10643 {
10644 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysVirtApic, &HCPhysVirtApic);
10645 AssertMsgRCReturn(rc, ("Failed to get host-physical address for virtual-APIC page at %#RGp\n", GCPhysVirtApic), rc);
10646
10647 /** @todo Handle proper releasing of page-mapping lock later. */
10648 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockVirtApic);
10649 }
10650 else
10651 return rc;
10652
10653 u32TprThreshold = pVmcsNstGst->u32TprThreshold;
10654 }
10655 else
10656 {
10657 HCPhysVirtApic = 0;
10658 u32TprThreshold = 0;
10659
10660 /*
10661 * We must make sure CR8 reads/write must cause VM-exits when TPR shadowing is not
10662 * used by the nested hypervisor. Preventing MMIO accesses to the physical APIC will
10663 * be taken care of by EPT/shadow paging.
10664 */
10665 if (pVM->hmr0.s.fAllow64BitGuests)
10666 u32ProcCtls |= VMX_PROC_CTLS_CR8_STORE_EXIT
10667 | VMX_PROC_CTLS_CR8_LOAD_EXIT;
10668 }
10669
10670 /*
10671 * Validate basic assumptions.
10672 */
10673 PVMXVMCSINFO pVmcsInfoNstGst = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
10674 Assert(pVM->hmr0.s.vmx.fUnrestrictedGuest);
10675 Assert(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
10676 Assert(hmGetVmxActiveVmcsInfo(pVCpu) == pVmcsInfoNstGst);
10677
10678 /*
10679 * Commit it to the nested-guest VMCS.
10680 */
10681 int rc = VINF_SUCCESS;
10682 if (pVmcsInfoNstGst->u32PinCtls != u32PinCtls)
10683 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, u32PinCtls);
10684 if (pVmcsInfoNstGst->u32ProcCtls != u32ProcCtls)
10685 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, u32ProcCtls);
10686 if (pVmcsInfoNstGst->u32ProcCtls2 != u32ProcCtls2)
10687 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, u32ProcCtls2);
10688 if (pVmcsInfoNstGst->u32XcptBitmap != u32XcptBitmap)
10689 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
10690 if (pVmcsInfoNstGst->u64Cr0Mask != u64Cr0Mask)
10691 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask);
10692 if (pVmcsInfoNstGst->u64Cr4Mask != u64Cr4Mask)
10693 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask);
10694 if (pVmcsInfoNstGst->u32XcptPFMask != u32XcptPFMask)
10695 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, u32XcptPFMask);
10696 if (pVmcsInfoNstGst->u32XcptPFMatch != u32XcptPFMatch)
10697 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, u32XcptPFMatch);
10698 if ( !(u32ProcCtls & VMX_PROC_CTLS_PAUSE_EXIT)
10699 && (u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
10700 {
10701 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT);
10702 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, cPleGapTicks);
10703 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, cPleWindowTicks);
10704 }
10705 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10706 {
10707 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
10708 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
10709 }
10710 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10711 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
10712 rc |= VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, uPendingDbgXcpts);
10713 AssertRC(rc);
10714
10715 /*
10716 * Update the nested-guest VMCS cache.
10717 */
10718 pVmcsInfoNstGst->u32PinCtls = u32PinCtls;
10719 pVmcsInfoNstGst->u32ProcCtls = u32ProcCtls;
10720 pVmcsInfoNstGst->u32ProcCtls2 = u32ProcCtls2;
10721 pVmcsInfoNstGst->u32XcptBitmap = u32XcptBitmap;
10722 pVmcsInfoNstGst->u64Cr0Mask = u64Cr0Mask;
10723 pVmcsInfoNstGst->u64Cr4Mask = u64Cr4Mask;
10724 pVmcsInfoNstGst->u32XcptPFMask = u32XcptPFMask;
10725 pVmcsInfoNstGst->u32XcptPFMatch = u32XcptPFMatch;
10726 pVmcsInfoNstGst->HCPhysVirtApic = HCPhysVirtApic;
10727
10728 /*
10729 * We need to flush the TLB if we are switching the APIC-access page address.
10730 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
10731 */
10732 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10733 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = true;
10734
10735 /*
10736 * MSR bitmap.
10737 *
10738 * The MSR bitmap address has already been initialized while setting up the nested-guest
10739 * VMCS, here we need to merge the MSR bitmaps.
10740 */
10741 if (u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10742 hmR0VmxMergeMsrBitmapNested(pVCpu, pVmcsInfoNstGst, pVmcsInfoGst);
10743
10744 return VINF_SUCCESS;
10745}
10746#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10747
10748
10749/**
10750 * Does the preparations before executing guest code in VT-x.
10751 *
10752 * This may cause longjmps to ring-3 and may even result in rescheduling to the
10753 * recompiler/IEM. We must be cautious what we do here regarding committing
10754 * guest-state information into the VMCS assuming we assuredly execute the
10755 * guest in VT-x mode.
10756 *
10757 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
10758 * the common-state (TRPM/forceflags), we must undo those changes so that the
10759 * recompiler/IEM can (and should) use them when it resumes guest execution.
10760 * Otherwise such operations must be done when we can no longer exit to ring-3.
10761 *
10762 * @returns Strict VBox status code (i.e. informational status codes too).
10763 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
10764 * have been disabled.
10765 * @retval VINF_VMX_VMEXIT if a nested-guest VM-exit occurs (e.g., while evaluating
10766 * pending events).
10767 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
10768 * double-fault into the guest.
10769 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
10770 * dispatched directly.
10771 * @retval VINF_* scheduling changes, we have to go back to ring-3.
10772 *
10773 * @param pVCpu The cross context virtual CPU structure.
10774 * @param pVmxTransient The VMX-transient structure.
10775 * @param fStepping Whether we are single-stepping the guest in the
10776 * hypervisor debugger. Makes us ignore some of the reasons
10777 * for returning to ring-3, and return VINF_EM_DBG_STEPPED
10778 * if event dispatching took place.
10779 */
10780static VBOXSTRICTRC hmR0VmxPreRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, bool fStepping)
10781{
10782 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10783
10784 Log4Func(("fIsNested=%RTbool fStepping=%RTbool\n", pVmxTransient->fIsNestedGuest, fStepping));
10785
10786#ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
10787 if (pVmxTransient->fIsNestedGuest)
10788 {
10789 RT_NOREF2(pVCpu, fStepping);
10790 Log2Func(("Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
10791 return VINF_EM_RESCHEDULE_REM;
10792 }
10793#endif
10794
10795 /*
10796 * Check and process force flag actions, some of which might require us to go back to ring-3.
10797 */
10798 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVCpu, pVmxTransient, fStepping);
10799 if (rcStrict == VINF_SUCCESS)
10800 {
10801 /* FFs don't get set all the time. */
10802#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10803 if ( pVmxTransient->fIsNestedGuest
10804 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10805 {
10806 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10807 return VINF_VMX_VMEXIT;
10808 }
10809#endif
10810 }
10811 else
10812 return rcStrict;
10813
10814 /*
10815 * Virtualize memory-mapped accesses to the physical APIC (may take locks).
10816 */
10817 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10818 if ( !pVCpu->hm.s.vmx.u64GstMsrApicBase
10819 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10820 && PDMHasApic(pVM))
10821 {
10822 int rc = hmR0VmxMapHCApicAccessPage(pVCpu);
10823 AssertRCReturn(rc, rc);
10824 }
10825
10826#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10827 /*
10828 * Merge guest VMCS controls with the nested-guest VMCS controls.
10829 *
10830 * Even if we have not executed the guest prior to this (e.g. when resuming from a
10831 * saved state), we should be okay with merging controls as we initialize the
10832 * guest VMCS controls as part of VM setup phase.
10833 */
10834 if ( pVmxTransient->fIsNestedGuest
10835 && !pVCpu->hm.s.vmx.fMergedNstGstCtls)
10836 {
10837 int rc = hmR0VmxMergeVmcsNested(pVCpu);
10838 AssertRCReturn(rc, rc);
10839 pVCpu->hm.s.vmx.fMergedNstGstCtls = true;
10840 }
10841#endif
10842
10843 /*
10844 * Evaluate events to be injected into the guest.
10845 *
10846 * Events in TRPM can be injected without inspecting the guest state.
10847 * If any new events (interrupts/NMI) are pending currently, we try to set up the
10848 * guest to cause a VM-exit the next time they are ready to receive the event.
10849 */
10850 if (TRPMHasTrap(pVCpu))
10851 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
10852
10853 uint32_t fIntrState;
10854 rcStrict = hmR0VmxEvaluatePendingEvent(pVCpu, pVmxTransient, &fIntrState);
10855
10856#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10857 /*
10858 * While evaluating pending events if something failed (unlikely) or if we were
10859 * preparing to run a nested-guest but performed a nested-guest VM-exit, we should bail.
10860 */
10861 if (rcStrict != VINF_SUCCESS)
10862 return rcStrict;
10863 if ( pVmxTransient->fIsNestedGuest
10864 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10865 {
10866 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10867 return VINF_VMX_VMEXIT;
10868 }
10869#else
10870 Assert(rcStrict == VINF_SUCCESS);
10871#endif
10872
10873 /*
10874 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus
10875 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might
10876 * also result in triple-faulting the VM.
10877 *
10878 * With nested-guests, the above does not apply since unrestricted guest execution is a
10879 * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
10880 */
10881 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pVmxTransient, fIntrState, fStepping);
10882 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10883 { /* likely */ }
10884 else
10885 {
10886 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
10887 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
10888 return rcStrict;
10889 }
10890
10891 /*
10892 * A longjump might result in importing CR3 even for VM-exits that don't necessarily
10893 * import CR3 themselves. We will need to update them here, as even as late as the above
10894 * hmR0VmxInjectPendingEvent() call may lazily import guest-CPU state on demand causing
10895 * the below force flags to be set.
10896 */
10897 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
10898 {
10899 Assert(!(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_CR3));
10900 int rc2 = PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
10901 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
10902 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
10903 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10904 }
10905
10906#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10907 /* Paranoia. */
10908 Assert(!pVmxTransient->fIsNestedGuest || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10909#endif
10910
10911 /*
10912 * No longjmps to ring-3 from this point on!!!
10913 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
10914 * This also disables flushing of the R0-logger instance (if any).
10915 */
10916 VMMRZCallRing3Disable(pVCpu);
10917
10918 /*
10919 * Export the guest state bits.
10920 *
10921 * We cannot perform longjmps while loading the guest state because we do not preserve the
10922 * host/guest state (although the VMCS will be preserved) across longjmps which can cause
10923 * CPU migration.
10924 *
10925 * If we are injecting events to a real-on-v86 mode guest, we would have updated RIP and some segment
10926 * registers. Hence, exporting of the guest state needs to be done -after- injection of events.
10927 */
10928 rcStrict = hmR0VmxExportGuestStateOptimal(pVCpu, pVmxTransient);
10929 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10930 { /* likely */ }
10931 else
10932 {
10933 VMMRZCallRing3Enable(pVCpu);
10934 return rcStrict;
10935 }
10936
10937 /*
10938 * We disable interrupts so that we don't miss any interrupts that would flag preemption
10939 * (IPI/timers etc.) when thread-context hooks aren't used and we've been running with
10940 * preemption disabled for a while. Since this is purely to aid the
10941 * RTThreadPreemptIsPending() code, it doesn't matter that it may temporarily reenable and
10942 * disable interrupt on NT.
10943 *
10944 * We need to check for force-flags that could've possible been altered since we last
10945 * checked them (e.g. by PDMGetInterrupt() leaving the PDM critical section,
10946 * see @bugref{6398}).
10947 *
10948 * We also check a couple of other force-flags as a last opportunity to get the EMT back
10949 * to ring-3 before executing guest code.
10950 */
10951 pVmxTransient->fEFlags = ASMIntDisableFlags();
10952
10953 if ( ( !VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
10954 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
10955 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
10956 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
10957 {
10958 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
10959 {
10960#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10961 /*
10962 * If we are executing a nested-guest make sure that we should intercept subsequent
10963 * events. The one we are injecting might be part of VM-entry. This is mainly to keep
10964 * the VM-exit instruction emulation happy.
10965 */
10966 if (pVmxTransient->fIsNestedGuest)
10967 CPUMSetGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx, true);
10968#endif
10969
10970 /*
10971 * We've injected any pending events. This is really the point of no return (to ring-3).
10972 *
10973 * Note! The caller expects to continue with interrupts & longjmps disabled on successful
10974 * returns from this function, so do -not- enable them here.
10975 */
10976 pVCpu->hm.s.Event.fPending = false;
10977 return VINF_SUCCESS;
10978 }
10979
10980 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPendingHostIrq);
10981 rcStrict = VINF_EM_RAW_INTERRUPT;
10982 }
10983 else
10984 {
10985 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
10986 rcStrict = VINF_EM_RAW_TO_R3;
10987 }
10988
10989 ASMSetFlags(pVmxTransient->fEFlags);
10990 VMMRZCallRing3Enable(pVCpu);
10991
10992 return rcStrict;
10993}
10994
10995
10996/**
10997 * Final preparations before executing guest code using hardware-assisted VMX.
10998 *
10999 * We can no longer get preempted to a different host CPU and there are no returns
11000 * to ring-3. We ignore any errors that may happen from this point (e.g. VMWRITE
11001 * failures), this function is not intended to fail sans unrecoverable hardware
11002 * errors.
11003 *
11004 * @param pVCpu The cross context virtual CPU structure.
11005 * @param pVmxTransient The VMX-transient structure.
11006 *
11007 * @remarks Called with preemption disabled.
11008 * @remarks No-long-jump zone!!!
11009 */
11010static void hmR0VmxPreRunGuestCommitted(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
11011{
11012 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
11013 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
11014 Assert(!pVCpu->hm.s.Event.fPending);
11015
11016 /*
11017 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
11018 */
11019 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
11020 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
11021
11022 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11023 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11024 PHMPHYSCPU pHostCpu = hmR0GetCurrentCpu();
11025 RTCPUID const idCurrentCpu = pHostCpu->idCpu;
11026
11027 if (!CPUMIsGuestFPUStateActive(pVCpu))
11028 {
11029 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestFpuState, x);
11030 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
11031 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_HOST_CONTEXT;
11032 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestFpuState, x);
11033 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadGuestFpu);
11034 }
11035
11036 /*
11037 * Re-export the host state bits as we may've been preempted (only happens when
11038 * thread-context hooks are used or when the VM start function changes) or if
11039 * the host CR0 is modified while loading the guest FPU state above.
11040 *
11041 * The 64-on-32 switcher saves the (64-bit) host state into the VMCS and if we
11042 * changed the switcher back to 32-bit, we *must* save the 32-bit host state here,
11043 * see @bugref{8432}.
11044 *
11045 * This may also happen when switching to/from a nested-guest VMCS without leaving
11046 * ring-0.
11047 */
11048 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
11049 {
11050 hmR0VmxExportHostState(pVCpu);
11051 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportHostState);
11052 }
11053 Assert(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT));
11054
11055 /*
11056 * Export the state shared between host and guest (FPU, debug, lazy MSRs).
11057 */
11058 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)
11059 hmR0VmxExportSharedState(pVCpu, pVmxTransient);
11060 AssertMsg(!pVCpu->hm.s.fCtxChanged, ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
11061
11062 /*
11063 * Store status of the shared guest/host debug state at the time of VM-entry.
11064 */
11065 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
11066 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
11067
11068 /*
11069 * Always cache the TPR-shadow if the virtual-APIC page exists, thereby skipping
11070 * more than one conditional check. The post-run side of our code shall determine
11071 * if it needs to sync. the virtual APIC TPR with the TPR-shadow.
11072 */
11073 if (pVmcsInfo->pbVirtApic)
11074 pVmxTransient->u8GuestTpr = pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR];
11075
11076 /*
11077 * Update the host MSRs values in the VM-exit MSR-load area.
11078 */
11079 if (!pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs)
11080 {
11081 if (pVmcsInfo->cExitMsrLoad > 0)
11082 hmR0VmxUpdateAutoLoadHostMsrs(pVCpu, pVmcsInfo);
11083 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = true;
11084 }
11085
11086 /*
11087 * Evaluate if we need to intercept guest RDTSC/P accesses. Set up the
11088 * VMX-preemption timer based on the next virtual sync clock deadline.
11089 */
11090 if ( !pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer
11091 || idCurrentCpu != pVCpu->hmr0.s.idLastCpu)
11092 {
11093 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVCpu, pVmxTransient, idCurrentCpu);
11094 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = true;
11095 }
11096
11097 /* Record statistics of how often we use TSC offsetting as opposed to intercepting RDTSC/P. */
11098 bool const fIsRdtscIntercepted = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT);
11099 if (!fIsRdtscIntercepted)
11100 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
11101 else
11102 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
11103
11104 ASMAtomicUoWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
11105 hmR0VmxFlushTaggedTlb(pHostCpu, pVCpu, pVmcsInfo); /* Invalidate the appropriate guest entries from the TLB. */
11106 Assert(idCurrentCpu == pVCpu->hmr0.s.idLastCpu);
11107 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Record the error reporting info. with the current host CPU. */
11108 pVmcsInfo->idHostCpuState = idCurrentCpu; /* Record the CPU for which the host-state has been exported. */
11109 pVmcsInfo->idHostCpuExec = idCurrentCpu; /* Record the CPU on which we shall execute. */
11110
11111 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
11112
11113 TMNotifyStartOfExecution(pVM, pVCpu); /* Notify TM to resume its clocks when TSC is tied to execution,
11114 as we're about to start executing the guest. */
11115
11116 /*
11117 * Load the guest TSC_AUX MSR when we are not intercepting RDTSCP.
11118 *
11119 * This is done this late as updating the TSC offsetting/preemption timer above
11120 * figures out if we can skip intercepting RDTSCP by calculating the number of
11121 * host CPU ticks till the next virtual sync deadline (for the dynamic case).
11122 */
11123 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_RDTSCP)
11124 && !fIsRdtscIntercepted)
11125 {
11126 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_TSC_AUX);
11127
11128 /* NB: Because we call hmR0VmxAddAutoLoadStoreMsr with fUpdateHostMsr=true,
11129 it's safe even after hmR0VmxUpdateAutoLoadHostMsrs has already been done. */
11130 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX, CPUMGetGuestTscAux(pVCpu),
11131 true /* fSetReadWrite */, true /* fUpdateHostMsr */);
11132 AssertRC(rc);
11133 Assert(!pVmxTransient->fRemoveTscAuxMsr);
11134 pVmxTransient->fRemoveTscAuxMsr = true;
11135 }
11136
11137#ifdef VBOX_STRICT
11138 Assert(pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs);
11139 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
11140 hmR0VmxCheckHostEferMsr(pVmcsInfo);
11141 AssertRC(hmR0VmxCheckCachedVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest));
11142#endif
11143
11144#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
11145 /** @todo r=ramshankar: We can now probably use iemVmxVmentryCheckGuestState here.
11146 * Add a PVMXMSRS parameter to it, so that IEM can look at the host MSRs,
11147 * see @bugref{9180#c54}. */
11148 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
11149 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
11150 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
11151#endif
11152}
11153
11154
11155/**
11156 * First C routine invoked after running guest code using hardware-assisted VMX.
11157 *
11158 * @param pVCpu The cross context virtual CPU structure.
11159 * @param pVmxTransient The VMX-transient structure.
11160 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
11161 *
11162 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
11163 *
11164 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
11165 * unconditionally when it is safe to do so.
11166 */
11167static void hmR0VmxPostRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, int rcVMRun)
11168{
11169 ASMAtomicUoWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
11170 ASMAtomicIncU32(&pVCpu->hmr0.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
11171 pVCpu->hm.s.fCtxChanged = 0; /* Exits/longjmps to ring-3 requires saving the guest state. */
11172 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
11173 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
11174 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
11175
11176 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11177 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
11178 {
11179 uint64_t uGstTsc;
11180 if (!pVmxTransient->fIsNestedGuest)
11181 uGstTsc = pVCpu->hmr0.s.uTscExit + pVmcsInfo->u64TscOffset;
11182 else
11183 {
11184 uint64_t const uNstGstTsc = pVCpu->hmr0.s.uTscExit + pVmcsInfo->u64TscOffset;
11185 uGstTsc = CPUMRemoveNestedGuestTscOffset(pVCpu, uNstGstTsc);
11186 }
11187 TMCpuTickSetLastSeen(pVCpu, uGstTsc); /* Update TM with the guest TSC. */
11188 }
11189
11190 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatPreExit, x);
11191 TMNotifyEndOfExecution(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->hmr0.s.uTscExit); /* Notify TM that the guest is no longer running. */
11192 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
11193
11194 pVCpu->hmr0.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Some host state messed up by VMX needs restoring. */
11195 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
11196#ifdef VBOX_STRICT
11197 hmR0VmxCheckHostEferMsr(pVmcsInfo); /* Verify that the host EFER MSR wasn't modified. */
11198#endif
11199 Assert(!ASMIntAreEnabled());
11200 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
11201 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
11202
11203#ifdef HMVMX_ALWAYS_CLEAN_TRANSIENT
11204 /*
11205 * Clean all the VMCS fields in the transient structure before reading
11206 * anything from the VMCS.
11207 */
11208 pVmxTransient->uExitReason = 0;
11209 pVmxTransient->uExitIntErrorCode = 0;
11210 pVmxTransient->uExitQual = 0;
11211 pVmxTransient->uGuestLinearAddr = 0;
11212 pVmxTransient->uExitIntInfo = 0;
11213 pVmxTransient->cbExitInstr = 0;
11214 pVmxTransient->ExitInstrInfo.u = 0;
11215 pVmxTransient->uEntryIntInfo = 0;
11216 pVmxTransient->uEntryXcptErrorCode = 0;
11217 pVmxTransient->cbEntryInstr = 0;
11218 pVmxTransient->uIdtVectoringInfo = 0;
11219 pVmxTransient->uIdtVectoringErrorCode = 0;
11220#endif
11221
11222 /*
11223 * Save the basic VM-exit reason and check if the VM-entry failed.
11224 * See Intel spec. 24.9.1 "Basic VM-exit Information".
11225 */
11226 uint32_t uExitReason;
11227 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
11228 AssertRC(rc);
11229 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason);
11230 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
11231
11232 /*
11233 * Log the VM-exit before logging anything else as otherwise it might be a
11234 * tad confusing what happens before and after the world-switch.
11235 */
11236 HMVMX_LOG_EXIT(pVCpu, uExitReason);
11237
11238 /*
11239 * Remove the TSC_AUX MSR from the auto-load/store MSR area and reset any MSR
11240 * bitmap permissions, if it was added before VM-entry.
11241 */
11242 if (pVmxTransient->fRemoveTscAuxMsr)
11243 {
11244 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX);
11245 pVmxTransient->fRemoveTscAuxMsr = false;
11246 }
11247
11248 /*
11249 * Check if VMLAUNCH/VMRESUME succeeded.
11250 * If this failed, we cause a guru meditation and cease further execution.
11251 *
11252 * However, if we are executing a nested-guest we might fail if we use the
11253 * fast path rather than fully emulating VMLAUNCH/VMRESUME instruction in IEM.
11254 */
11255 if (RT_LIKELY(rcVMRun == VINF_SUCCESS))
11256 {
11257 /*
11258 * Update the VM-exit history array here even if the VM-entry failed due to:
11259 * - Invalid guest state.
11260 * - MSR loading.
11261 * - Machine-check event.
11262 *
11263 * In any of the above cases we will still have a "valid" VM-exit reason
11264 * despite @a fVMEntryFailed being false.
11265 *
11266 * See Intel spec. 26.7 "VM-Entry failures during or after loading guest state".
11267 *
11268 * Note! We don't have CS or RIP at this point. Will probably address that later
11269 * by amending the history entry added here.
11270 */
11271 EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_VMX, pVmxTransient->uExitReason & EMEXIT_F_TYPE_MASK),
11272 UINT64_MAX, pVCpu->hmr0.s.uTscExit);
11273
11274 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
11275 {
11276 VMMRZCallRing3Enable(pVCpu);
11277 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
11278
11279#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
11280 hmR0VmxReadAllRoFieldsVmcs(pVmxTransient);
11281#endif
11282
11283 /*
11284 * Import the guest-interruptibility state always as we need it while evaluating
11285 * injecting events on re-entry.
11286 *
11287 * We don't import CR0 (when unrestricted guest execution is unavailable) despite
11288 * checking for real-mode while exporting the state because all bits that cause
11289 * mode changes wrt CR0 are intercepted.
11290 */
11291 uint64_t const fImportMask = CPUMCTX_EXTRN_HM_VMX_INT_STATE
11292#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
11293 | HMVMX_CPUMCTX_EXTRN_ALL
11294#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
11295 | CPUMCTX_EXTRN_RFLAGS
11296#endif
11297 ;
11298 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImportMask);
11299 AssertRC(rc);
11300
11301 /*
11302 * Sync the TPR shadow with our APIC state.
11303 */
11304 if ( !pVmxTransient->fIsNestedGuest
11305 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
11306 {
11307 Assert(pVmcsInfo->pbVirtApic);
11308 if (pVmxTransient->u8GuestTpr != pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR])
11309 {
11310 rc = APICSetTpr(pVCpu, pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR]);
11311 AssertRC(rc);
11312 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
11313 }
11314 }
11315
11316 Assert(VMMRZCallRing3IsEnabled(pVCpu));
11317 Assert( pVmxTransient->fWasGuestDebugStateActive == false
11318 || pVmxTransient->fWasHyperDebugStateActive == false);
11319 return;
11320 }
11321 }
11322#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
11323 else if (pVmxTransient->fIsNestedGuest)
11324 AssertMsgFailed(("VMLAUNCH/VMRESUME failed but shouldn't happen when VMLAUNCH/VMRESUME was emulated in IEM!\n"));
11325#endif
11326 else
11327 Log4Func(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
11328
11329 VMMRZCallRing3Enable(pVCpu);
11330}
11331
11332
11333/**
11334 * Runs the guest code using hardware-assisted VMX the normal way.
11335 *
11336 * @returns VBox status code.
11337 * @param pVCpu The cross context virtual CPU structure.
11338 * @param pcLoops Pointer to the number of executed loops.
11339 */
11340static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVMCPUCC pVCpu, uint32_t *pcLoops)
11341{
11342 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hmr0.s.cMaxResumeLoops;
11343 Assert(pcLoops);
11344 Assert(*pcLoops <= cMaxResumeLoops);
11345 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
11346
11347#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
11348 /*
11349 * Switch to the guest VMCS as we may have transitioned from executing the nested-guest
11350 * without leaving ring-0. Otherwise, if we came from ring-3 we would have loaded the
11351 * guest VMCS while entering the VMX ring-0 session.
11352 */
11353 if (pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs)
11354 {
11355 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, false /* fSwitchToNstGstVmcs */);
11356 if (RT_SUCCESS(rc))
11357 { /* likely */ }
11358 else
11359 {
11360 LogRelFunc(("Failed to switch to the guest VMCS. rc=%Rrc\n", rc));
11361 return rc;
11362 }
11363 }
11364#endif
11365
11366 VMXTRANSIENT VmxTransient;
11367 RT_ZERO(VmxTransient);
11368 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
11369
11370 /* Paranoia. */
11371 Assert(VmxTransient.pVmcsInfo == &pVCpu->hmr0.s.vmx.VmcsInfo);
11372
11373 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
11374 for (;;)
11375 {
11376 Assert(!HMR0SuspendPending());
11377 HMVMX_ASSERT_CPU_SAFE(pVCpu);
11378 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
11379
11380 /*
11381 * Preparatory work for running nested-guest code, this may force us to
11382 * return to ring-3.
11383 *
11384 * Warning! This bugger disables interrupts on VINF_SUCCESS!
11385 */
11386 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
11387 if (rcStrict != VINF_SUCCESS)
11388 break;
11389
11390 /* Interrupts are disabled at this point! */
11391 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
11392 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
11393 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
11394 /* Interrupts are re-enabled at this point! */
11395
11396 /*
11397 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
11398 */
11399 if (RT_SUCCESS(rcRun))
11400 { /* very likely */ }
11401 else
11402 {
11403 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
11404 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
11405 return rcRun;
11406 }
11407
11408 /*
11409 * Profile the VM-exit.
11410 */
11411 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
11412 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
11413 STAM_COUNTER_INC(&pVCpu->hm.s.aStatExitReason[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
11414 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
11415 HMVMX_START_EXIT_DISPATCH_PROF();
11416
11417 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
11418
11419 /*
11420 * Handle the VM-exit.
11421 */
11422#ifdef HMVMX_USE_FUNCTION_TABLE
11423 rcStrict = g_aVMExitHandlers[VmxTransient.uExitReason].pfn(pVCpu, &VmxTransient);
11424#else
11425 rcStrict = hmR0VmxHandleExit(pVCpu, &VmxTransient);
11426#endif
11427 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
11428 if (rcStrict == VINF_SUCCESS)
11429 {
11430 if (++(*pcLoops) <= cMaxResumeLoops)
11431 continue;
11432 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
11433 rcStrict = VINF_EM_RAW_INTERRUPT;
11434 }
11435 break;
11436 }
11437
11438 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
11439 return rcStrict;
11440}
11441
11442
11443#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
11444/**
11445 * Runs the nested-guest code using hardware-assisted VMX.
11446 *
11447 * @returns VBox status code.
11448 * @param pVCpu The cross context virtual CPU structure.
11449 * @param pcLoops Pointer to the number of executed loops.
11450 *
11451 * @sa hmR0VmxRunGuestCodeNormal.
11452 */
11453static VBOXSTRICTRC hmR0VmxRunGuestCodeNested(PVMCPUCC pVCpu, uint32_t *pcLoops)
11454{
11455 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hmr0.s.cMaxResumeLoops;
11456 Assert(pcLoops);
11457 Assert(*pcLoops <= cMaxResumeLoops);
11458 Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
11459
11460 /*
11461 * Switch to the nested-guest VMCS as we may have transitioned from executing the
11462 * guest without leaving ring-0. Otherwise, if we came from ring-3 we would have
11463 * loaded the nested-guest VMCS while entering the VMX ring-0 session.
11464 */
11465 if (!pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs)
11466 {
11467 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, true /* fSwitchToNstGstVmcs */);
11468 if (RT_SUCCESS(rc))
11469 { /* likely */ }
11470 else
11471 {
11472 LogRelFunc(("Failed to switch to the nested-guest VMCS. rc=%Rrc\n", rc));
11473 return rc;
11474 }
11475 }
11476
11477 VMXTRANSIENT VmxTransient;
11478 RT_ZERO(VmxTransient);
11479 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
11480 VmxTransient.fIsNestedGuest = true;
11481
11482 /* Paranoia. */
11483 Assert(VmxTransient.pVmcsInfo == &pVCpu->hmr0.s.vmx.VmcsInfoNstGst);
11484
11485 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
11486 for (;;)
11487 {
11488 Assert(!HMR0SuspendPending());
11489 HMVMX_ASSERT_CPU_SAFE(pVCpu);
11490 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
11491
11492 /*
11493 * Preparatory work for running guest code, this may force us to
11494 * return to ring-3.
11495 *
11496 * Warning! This bugger disables interrupts on VINF_SUCCESS!
11497 */
11498 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
11499 if (rcStrict != VINF_SUCCESS)
11500 break;
11501
11502 /* Interrupts are disabled at this point! */
11503 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
11504 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
11505 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
11506 /* Interrupts are re-enabled at this point! */
11507
11508 /*
11509 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
11510 */
11511 if (RT_SUCCESS(rcRun))
11512 { /* very likely */ }
11513 else
11514 {
11515 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
11516 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
11517 return rcRun;
11518 }
11519
11520 /*
11521 * Profile the VM-exit.
11522 */
11523 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
11524 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
11525 STAM_COUNTER_INC(&pVCpu->hm.s.StatNestedExitAll);
11526 STAM_COUNTER_INC(&pVCpu->hm.s.aStatNestedExitReason[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
11527 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
11528 HMVMX_START_EXIT_DISPATCH_PROF();
11529
11530 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
11531
11532 /*
11533 * Handle the VM-exit.
11534 */
11535 rcStrict = hmR0VmxHandleExitNested(pVCpu, &VmxTransient);
11536 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
11537 if (rcStrict == VINF_SUCCESS)
11538 {
11539 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
11540 {
11541 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
11542 rcStrict = VINF_VMX_VMEXIT;
11543 }
11544 else
11545 {
11546 if (++(*pcLoops) <= cMaxResumeLoops)
11547 continue;
11548 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
11549 rcStrict = VINF_EM_RAW_INTERRUPT;
11550 }
11551 }
11552 else
11553 Assert(rcStrict != VINF_VMX_VMEXIT);
11554 break;
11555 }
11556
11557 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
11558 return rcStrict;
11559}
11560#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
11561
11562
11563/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
11564 * probes.
11565 *
11566 * The following few functions and associated structure contains the bloat
11567 * necessary for providing detailed debug events and dtrace probes as well as
11568 * reliable host side single stepping. This works on the principle of
11569 * "subclassing" the normal execution loop and workers. We replace the loop
11570 * method completely and override selected helpers to add necessary adjustments
11571 * to their core operation.
11572 *
11573 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
11574 * any performance for debug and analysis features.
11575 *
11576 * @{
11577 */
11578
11579/**
11580 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
11581 * the debug run loop.
11582 */
11583typedef struct VMXRUNDBGSTATE
11584{
11585 /** The RIP we started executing at. This is for detecting that we stepped. */
11586 uint64_t uRipStart;
11587 /** The CS we started executing with. */
11588 uint16_t uCsStart;
11589
11590 /** Whether we've actually modified the 1st execution control field. */
11591 bool fModifiedProcCtls : 1;
11592 /** Whether we've actually modified the 2nd execution control field. */
11593 bool fModifiedProcCtls2 : 1;
11594 /** Whether we've actually modified the exception bitmap. */
11595 bool fModifiedXcptBitmap : 1;
11596
11597 /** We desire the modified the CR0 mask to be cleared. */
11598 bool fClearCr0Mask : 1;
11599 /** We desire the modified the CR4 mask to be cleared. */
11600 bool fClearCr4Mask : 1;
11601 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
11602 uint32_t fCpe1Extra;
11603 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
11604 uint32_t fCpe1Unwanted;
11605 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
11606 uint32_t fCpe2Extra;
11607 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
11608 uint32_t bmXcptExtra;
11609 /** The sequence number of the Dtrace provider settings the state was
11610 * configured against. */
11611 uint32_t uDtraceSettingsSeqNo;
11612 /** VM-exits to check (one bit per VM-exit). */
11613 uint32_t bmExitsToCheck[3];
11614
11615 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
11616 uint32_t fProcCtlsInitial;
11617 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
11618 uint32_t fProcCtls2Initial;
11619 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
11620 uint32_t bmXcptInitial;
11621} VMXRUNDBGSTATE;
11622AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
11623typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
11624
11625
11626/**
11627 * Initializes the VMXRUNDBGSTATE structure.
11628 *
11629 * @param pVCpu The cross context virtual CPU structure of the
11630 * calling EMT.
11631 * @param pVmxTransient The VMX-transient structure.
11632 * @param pDbgState The debug state to initialize.
11633 */
11634static void hmR0VmxRunDebugStateInit(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11635{
11636 pDbgState->uRipStart = pVCpu->cpum.GstCtx.rip;
11637 pDbgState->uCsStart = pVCpu->cpum.GstCtx.cs.Sel;
11638
11639 pDbgState->fModifiedProcCtls = false;
11640 pDbgState->fModifiedProcCtls2 = false;
11641 pDbgState->fModifiedXcptBitmap = false;
11642 pDbgState->fClearCr0Mask = false;
11643 pDbgState->fClearCr4Mask = false;
11644 pDbgState->fCpe1Extra = 0;
11645 pDbgState->fCpe1Unwanted = 0;
11646 pDbgState->fCpe2Extra = 0;
11647 pDbgState->bmXcptExtra = 0;
11648 pDbgState->fProcCtlsInitial = pVmxTransient->pVmcsInfo->u32ProcCtls;
11649 pDbgState->fProcCtls2Initial = pVmxTransient->pVmcsInfo->u32ProcCtls2;
11650 pDbgState->bmXcptInitial = pVmxTransient->pVmcsInfo->u32XcptBitmap;
11651}
11652
11653
11654/**
11655 * Updates the VMSC fields with changes requested by @a pDbgState.
11656 *
11657 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
11658 * immediately before executing guest code, i.e. when interrupts are disabled.
11659 * We don't check status codes here as we cannot easily assert or return in the
11660 * latter case.
11661 *
11662 * @param pVCpu The cross context virtual CPU structure.
11663 * @param pVmxTransient The VMX-transient structure.
11664 * @param pDbgState The debug state.
11665 */
11666static void hmR0VmxPreRunGuestDebugStateApply(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11667{
11668 /*
11669 * Ensure desired flags in VMCS control fields are set.
11670 * (Ignoring write failure here, as we're committed and it's just debug extras.)
11671 *
11672 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
11673 * there should be no stale data in pCtx at this point.
11674 */
11675 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11676 if ( (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
11677 || (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Unwanted))
11678 {
11679 pVmcsInfo->u32ProcCtls |= pDbgState->fCpe1Extra;
11680 pVmcsInfo->u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
11681 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
11682 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVmcsInfo->u32ProcCtls));
11683 pDbgState->fModifiedProcCtls = true;
11684 }
11685
11686 if ((pVmcsInfo->u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
11687 {
11688 pVmcsInfo->u32ProcCtls2 |= pDbgState->fCpe2Extra;
11689 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVmcsInfo->u32ProcCtls2);
11690 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVmcsInfo->u32ProcCtls2));
11691 pDbgState->fModifiedProcCtls2 = true;
11692 }
11693
11694 if ((pVmcsInfo->u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
11695 {
11696 pVmcsInfo->u32XcptBitmap |= pDbgState->bmXcptExtra;
11697 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVmcsInfo->u32XcptBitmap);
11698 Log6Func(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVmcsInfo->u32XcptBitmap));
11699 pDbgState->fModifiedXcptBitmap = true;
11700 }
11701
11702 if (pDbgState->fClearCr0Mask && pVmcsInfo->u64Cr0Mask != 0)
11703 {
11704 pVmcsInfo->u64Cr0Mask = 0;
11705 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, 0);
11706 Log6Func(("VMX_VMCS_CTRL_CR0_MASK: 0\n"));
11707 }
11708
11709 if (pDbgState->fClearCr4Mask && pVmcsInfo->u64Cr4Mask != 0)
11710 {
11711 pVmcsInfo->u64Cr4Mask = 0;
11712 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, 0);
11713 Log6Func(("VMX_VMCS_CTRL_CR4_MASK: 0\n"));
11714 }
11715
11716 NOREF(pVCpu);
11717}
11718
11719
11720/**
11721 * Restores VMCS fields that were changed by hmR0VmxPreRunGuestDebugStateApply for
11722 * re-entry next time around.
11723 *
11724 * @returns Strict VBox status code (i.e. informational status codes too).
11725 * @param pVCpu The cross context virtual CPU structure.
11726 * @param pVmxTransient The VMX-transient structure.
11727 * @param pDbgState The debug state.
11728 * @param rcStrict The return code from executing the guest using single
11729 * stepping.
11730 */
11731static VBOXSTRICTRC hmR0VmxRunDebugStateRevert(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState,
11732 VBOXSTRICTRC rcStrict)
11733{
11734 /*
11735 * Restore VM-exit control settings as we may not reenter this function the
11736 * next time around.
11737 */
11738 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11739
11740 /* We reload the initial value, trigger what we can of recalculations the
11741 next time around. From the looks of things, that's all that's required atm. */
11742 if (pDbgState->fModifiedProcCtls)
11743 {
11744 if (!(pDbgState->fProcCtlsInitial & VMX_PROC_CTLS_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
11745 pDbgState->fProcCtlsInitial |= VMX_PROC_CTLS_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
11746 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
11747 AssertRC(rc2);
11748 pVmcsInfo->u32ProcCtls = pDbgState->fProcCtlsInitial;
11749 }
11750
11751 /* We're currently the only ones messing with this one, so just restore the
11752 cached value and reload the field. */
11753 if ( pDbgState->fModifiedProcCtls2
11754 && pVmcsInfo->u32ProcCtls2 != pDbgState->fProcCtls2Initial)
11755 {
11756 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
11757 AssertRC(rc2);
11758 pVmcsInfo->u32ProcCtls2 = pDbgState->fProcCtls2Initial;
11759 }
11760
11761 /* If we've modified the exception bitmap, we restore it and trigger
11762 reloading and partial recalculation the next time around. */
11763 if (pDbgState->fModifiedXcptBitmap)
11764 pVmcsInfo->u32XcptBitmap = pDbgState->bmXcptInitial;
11765
11766 return rcStrict;
11767}
11768
11769
11770/**
11771 * Configures VM-exit controls for current DBGF and DTrace settings.
11772 *
11773 * This updates @a pDbgState and the VMCS execution control fields to reflect
11774 * the necessary VM-exits demanded by DBGF and DTrace.
11775 *
11776 * @param pVCpu The cross context virtual CPU structure.
11777 * @param pVmxTransient The VMX-transient structure. May update
11778 * fUpdatedTscOffsettingAndPreemptTimer.
11779 * @param pDbgState The debug state.
11780 */
11781static void hmR0VmxPreRunGuestDebugStateUpdate(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11782{
11783 /*
11784 * Take down the dtrace serial number so we can spot changes.
11785 */
11786 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
11787 ASMCompilerBarrier();
11788
11789 /*
11790 * We'll rebuild most of the middle block of data members (holding the
11791 * current settings) as we go along here, so start by clearing it all.
11792 */
11793 pDbgState->bmXcptExtra = 0;
11794 pDbgState->fCpe1Extra = 0;
11795 pDbgState->fCpe1Unwanted = 0;
11796 pDbgState->fCpe2Extra = 0;
11797 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
11798 pDbgState->bmExitsToCheck[i] = 0;
11799
11800 /*
11801 * Software interrupts (INT XXh) - no idea how to trigger these...
11802 */
11803 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11804 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
11805 || VBOXVMM_INT_SOFTWARE_ENABLED())
11806 {
11807 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11808 }
11809
11810 /*
11811 * INT3 breakpoints - triggered by #BP exceptions.
11812 */
11813 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
11814 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11815
11816 /*
11817 * Exception bitmap and XCPT events+probes.
11818 */
11819 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
11820 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
11821 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
11822
11823 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
11824 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
11825 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11826 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
11827 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
11828 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
11829 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
11830 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
11831 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
11832 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
11833 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
11834 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
11835 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
11836 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
11837 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
11838 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
11839 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
11840 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
11841
11842 if (pDbgState->bmXcptExtra)
11843 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11844
11845 /*
11846 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
11847 *
11848 * Note! This is the reverse of what hmR0VmxHandleExitDtraceEvents does.
11849 * So, when adding/changing/removing please don't forget to update it.
11850 *
11851 * Some of the macros are picking up local variables to save horizontal space,
11852 * (being able to see it in a table is the lesser evil here).
11853 */
11854#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
11855 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
11856 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
11857#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
11858 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11859 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11860 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11861 } else do { } while (0)
11862#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
11863 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11864 { \
11865 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
11866 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11867 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11868 } else do { } while (0)
11869#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
11870 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11871 { \
11872 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
11873 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11874 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11875 } else do { } while (0)
11876#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
11877 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11878 { \
11879 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
11880 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11881 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11882 } else do { } while (0)
11883
11884 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
11885 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
11886 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
11887 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
11888 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
11889
11890 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
11891 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
11892 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
11893 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
11894 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_PROC_CTLS_HLT_EXIT); /* paranoia */
11895 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
11896 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
11897 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
11898 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_PROC_CTLS_INVLPG_EXIT);
11899 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
11900 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_PROC_CTLS_RDPMC_EXIT);
11901 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
11902 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_PROC_CTLS_RDTSC_EXIT);
11903 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
11904 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
11905 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
11906 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
11907 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
11908 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
11909 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
11910 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
11911 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
11912 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
11913 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
11914 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
11915 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
11916 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
11917 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
11918 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
11919 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
11920 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
11921 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
11922 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
11923 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
11924 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
11925 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
11926
11927 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
11928 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11929 {
11930 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4
11931 | CPUMCTX_EXTRN_APIC_TPR);
11932 AssertRC(rc);
11933
11934#if 0 /** @todo fix me */
11935 pDbgState->fClearCr0Mask = true;
11936 pDbgState->fClearCr4Mask = true;
11937#endif
11938 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
11939 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_STORE_EXIT | VMX_PROC_CTLS_CR8_STORE_EXIT;
11940 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11941 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_LOAD_EXIT | VMX_PROC_CTLS_CR8_LOAD_EXIT;
11942 pDbgState->fCpe1Unwanted |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* risky? */
11943 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
11944 require clearing here and in the loop if we start using it. */
11945 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
11946 }
11947 else
11948 {
11949 if (pDbgState->fClearCr0Mask)
11950 {
11951 pDbgState->fClearCr0Mask = false;
11952 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR0);
11953 }
11954 if (pDbgState->fClearCr4Mask)
11955 {
11956 pDbgState->fClearCr4Mask = false;
11957 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR4);
11958 }
11959 }
11960 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
11961 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
11962
11963 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
11964 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
11965 {
11966 /** @todo later, need to fix handler as it assumes this won't usually happen. */
11967 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
11968 }
11969 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
11970 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
11971
11972 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS); /* risky clearing this? */
11973 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
11974 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS);
11975 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
11976 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_PROC_CTLS_MWAIT_EXIT); /* paranoia */
11977 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
11978 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_PROC_CTLS_MONITOR_EXIT); /* paranoia */
11979 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
11980#if 0 /** @todo too slow, fix handler. */
11981 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_PROC_CTLS_PAUSE_EXIT);
11982#endif
11983 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
11984
11985 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
11986 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
11987 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
11988 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
11989 {
11990 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11991 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_GDTR_IDTR_ACCESS);
11992 }
11993 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11994 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11995 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11996 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11997
11998 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
11999 || IS_EITHER_ENABLED(pVM, INSTR_STR)
12000 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
12001 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
12002 {
12003 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
12004 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_LDTR_TR_ACCESS);
12005 }
12006 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_LDTR_TR_ACCESS);
12007 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_LDTR_TR_ACCESS);
12008 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_LDTR_TR_ACCESS);
12009 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_LDTR_TR_ACCESS);
12010
12011 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
12012 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
12013 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_PROC_CTLS_RDTSC_EXIT);
12014 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
12015 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
12016 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
12017 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_PROC_CTLS2_WBINVD_EXIT);
12018 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
12019 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
12020 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
12021 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_PROC_CTLS2_RDRAND_EXIT);
12022 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
12023 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_PROC_CTLS_INVLPG_EXIT);
12024 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
12025 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
12026 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
12027 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_PROC_CTLS2_RDSEED_EXIT);
12028 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
12029 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
12030 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
12031 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
12032 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
12033
12034#undef IS_EITHER_ENABLED
12035#undef SET_ONLY_XBM_IF_EITHER_EN
12036#undef SET_CPE1_XBM_IF_EITHER_EN
12037#undef SET_CPEU_XBM_IF_EITHER_EN
12038#undef SET_CPE2_XBM_IF_EITHER_EN
12039
12040 /*
12041 * Sanitize the control stuff.
12042 */
12043 pDbgState->fCpe2Extra &= g_HmMsrs.u.vmx.ProcCtls2.n.allowed1;
12044 if (pDbgState->fCpe2Extra)
12045 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
12046 pDbgState->fCpe1Extra &= g_HmMsrs.u.vmx.ProcCtls.n.allowed1;
12047 pDbgState->fCpe1Unwanted &= ~g_HmMsrs.u.vmx.ProcCtls.n.allowed0;
12048 if (pVCpu->hmr0.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_PROC_CTLS_RDTSC_EXIT))
12049 {
12050 pVCpu->hmr0.s.fDebugWantRdTscExit ^= true;
12051 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
12052 }
12053
12054 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
12055 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
12056 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
12057 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
12058}
12059
12060
12061/**
12062 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
12063 * appropriate.
12064 *
12065 * The caller has checked the VM-exit against the
12066 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
12067 * already, so we don't have to do that either.
12068 *
12069 * @returns Strict VBox status code (i.e. informational status codes too).
12070 * @param pVCpu The cross context virtual CPU structure.
12071 * @param pVmxTransient The VMX-transient structure.
12072 * @param uExitReason The VM-exit reason.
12073 *
12074 * @remarks The name of this function is displayed by dtrace, so keep it short
12075 * and to the point. No longer than 33 chars long, please.
12076 */
12077static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
12078{
12079 /*
12080 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
12081 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
12082 *
12083 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
12084 * does. Must add/change/remove both places. Same ordering, please.
12085 *
12086 * Added/removed events must also be reflected in the next section
12087 * where we dispatch dtrace events.
12088 */
12089 bool fDtrace1 = false;
12090 bool fDtrace2 = false;
12091 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
12092 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
12093 uint32_t uEventArg = 0;
12094#define SET_EXIT(a_EventSubName) \
12095 do { \
12096 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
12097 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
12098 } while (0)
12099#define SET_BOTH(a_EventSubName) \
12100 do { \
12101 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
12102 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
12103 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
12104 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
12105 } while (0)
12106 switch (uExitReason)
12107 {
12108 case VMX_EXIT_MTF:
12109 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
12110
12111 case VMX_EXIT_XCPT_OR_NMI:
12112 {
12113 uint8_t const idxVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
12114 switch (VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo))
12115 {
12116 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
12117 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
12118 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
12119 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
12120 {
12121 if (VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uExitIntInfo))
12122 {
12123 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
12124 uEventArg = pVmxTransient->uExitIntErrorCode;
12125 }
12126 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
12127 switch (enmEvent1)
12128 {
12129 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
12130 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
12131 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
12132 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
12133 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
12134 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
12135 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
12136 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
12137 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
12138 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
12139 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
12140 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
12141 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
12142 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
12143 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
12144 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
12145 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
12146 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
12147 default: break;
12148 }
12149 }
12150 else
12151 AssertFailed();
12152 break;
12153
12154 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
12155 uEventArg = idxVector;
12156 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
12157 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
12158 break;
12159 }
12160 break;
12161 }
12162
12163 case VMX_EXIT_TRIPLE_FAULT:
12164 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
12165 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
12166 break;
12167 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
12168 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
12169 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
12170 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
12171 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
12172
12173 /* Instruction specific VM-exits: */
12174 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
12175 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
12176 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
12177 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
12178 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
12179 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
12180 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
12181 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
12182 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
12183 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
12184 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
12185 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
12186 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
12187 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
12188 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
12189 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
12190 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
12191 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
12192 case VMX_EXIT_MOV_CRX:
12193 hmR0VmxReadExitQualVmcs(pVmxTransient);
12194 if (VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_CRX_ACCESS_READ)
12195 SET_BOTH(CRX_READ);
12196 else
12197 SET_BOTH(CRX_WRITE);
12198 uEventArg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
12199 break;
12200 case VMX_EXIT_MOV_DRX:
12201 hmR0VmxReadExitQualVmcs(pVmxTransient);
12202 if ( VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual)
12203 == VMX_EXIT_QUAL_DRX_DIRECTION_READ)
12204 SET_BOTH(DRX_READ);
12205 else
12206 SET_BOTH(DRX_WRITE);
12207 uEventArg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
12208 break;
12209 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
12210 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
12211 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
12212 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
12213 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
12214 case VMX_EXIT_GDTR_IDTR_ACCESS:
12215 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
12216 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_XDTR_INSINFO_INSTR_ID))
12217 {
12218 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
12219 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
12220 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
12221 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
12222 }
12223 break;
12224
12225 case VMX_EXIT_LDTR_TR_ACCESS:
12226 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
12227 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_YYTR_INSINFO_INSTR_ID))
12228 {
12229 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
12230 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
12231 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
12232 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
12233 }
12234 break;
12235
12236 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
12237 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
12238 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
12239 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
12240 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
12241 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
12242 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
12243 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
12244 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
12245 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
12246 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
12247
12248 /* Events that aren't relevant at this point. */
12249 case VMX_EXIT_EXT_INT:
12250 case VMX_EXIT_INT_WINDOW:
12251 case VMX_EXIT_NMI_WINDOW:
12252 case VMX_EXIT_TPR_BELOW_THRESHOLD:
12253 case VMX_EXIT_PREEMPT_TIMER:
12254 case VMX_EXIT_IO_INSTR:
12255 break;
12256
12257 /* Errors and unexpected events. */
12258 case VMX_EXIT_INIT_SIGNAL:
12259 case VMX_EXIT_SIPI:
12260 case VMX_EXIT_IO_SMI:
12261 case VMX_EXIT_SMI:
12262 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
12263 case VMX_EXIT_ERR_MSR_LOAD:
12264 case VMX_EXIT_ERR_MACHINE_CHECK:
12265 case VMX_EXIT_PML_FULL:
12266 case VMX_EXIT_VIRTUALIZED_EOI:
12267 break;
12268
12269 default:
12270 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12271 break;
12272 }
12273#undef SET_BOTH
12274#undef SET_EXIT
12275
12276 /*
12277 * Dtrace tracepoints go first. We do them here at once so we don't
12278 * have to copy the guest state saving and stuff a few dozen times.
12279 * Down side is that we've got to repeat the switch, though this time
12280 * we use enmEvent since the probes are a subset of what DBGF does.
12281 */
12282 if (fDtrace1 || fDtrace2)
12283 {
12284 hmR0VmxReadExitQualVmcs(pVmxTransient);
12285 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
12286 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12287 switch (enmEvent1)
12288 {
12289 /** @todo consider which extra parameters would be helpful for each probe. */
12290 case DBGFEVENT_END: break;
12291 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pCtx); break;
12292 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pCtx, pCtx->dr[6]); break;
12293 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pCtx); break;
12294 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pCtx); break;
12295 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pCtx); break;
12296 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pCtx); break;
12297 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pCtx); break;
12298 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pCtx); break;
12299 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pCtx, uEventArg); break;
12300 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pCtx, uEventArg); break;
12301 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pCtx, uEventArg); break;
12302 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pCtx, uEventArg); break;
12303 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pCtx, uEventArg, pCtx->cr2); break;
12304 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pCtx); break;
12305 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pCtx); break;
12306 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pCtx); break;
12307 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pCtx); break;
12308 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pCtx, uEventArg); break;
12309 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12310 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
12311 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pCtx); break;
12312 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pCtx); break;
12313 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pCtx); break;
12314 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pCtx); break;
12315 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pCtx); break;
12316 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pCtx); break;
12317 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pCtx); break;
12318 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12319 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12320 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12321 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12322 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
12323 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pCtx, pCtx->ecx,
12324 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
12325 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pCtx); break;
12326 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pCtx); break;
12327 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pCtx); break;
12328 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pCtx); break;
12329 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pCtx); break;
12330 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pCtx); break;
12331 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pCtx); break;
12332 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pCtx); break;
12333 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pCtx); break;
12334 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pCtx); break;
12335 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pCtx); break;
12336 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pCtx); break;
12337 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pCtx); break;
12338 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pCtx); break;
12339 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pCtx); break;
12340 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pCtx); break;
12341 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pCtx); break;
12342 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pCtx); break;
12343 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pCtx); break;
12344 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pCtx); break;
12345 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pCtx); break;
12346 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pCtx); break;
12347 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pCtx); break;
12348 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pCtx); break;
12349 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pCtx); break;
12350 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pCtx); break;
12351 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pCtx); break;
12352 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pCtx); break;
12353 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pCtx); break;
12354 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pCtx); break;
12355 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pCtx); break;
12356 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pCtx); break;
12357 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
12358 }
12359 switch (enmEvent2)
12360 {
12361 /** @todo consider which extra parameters would be helpful for each probe. */
12362 case DBGFEVENT_END: break;
12363 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pCtx); break;
12364 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
12365 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pCtx); break;
12366 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pCtx); break;
12367 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pCtx); break;
12368 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pCtx); break;
12369 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pCtx); break;
12370 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pCtx); break;
12371 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pCtx); break;
12372 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12373 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12374 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12375 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12376 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
12377 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pCtx, pCtx->ecx,
12378 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
12379 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pCtx); break;
12380 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pCtx); break;
12381 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pCtx); break;
12382 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pCtx); break;
12383 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pCtx); break;
12384 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pCtx); break;
12385 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pCtx); break;
12386 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pCtx); break;
12387 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pCtx); break;
12388 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pCtx); break;
12389 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pCtx); break;
12390 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pCtx); break;
12391 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pCtx); break;
12392 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pCtx); break;
12393 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pCtx); break;
12394 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pCtx); break;
12395 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pCtx); break;
12396 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pCtx); break;
12397 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pCtx); break;
12398 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pCtx); break;
12399 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pCtx); break;
12400 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pCtx); break;
12401 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pCtx); break;
12402 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pCtx); break;
12403 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pCtx); break;
12404 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pCtx); break;
12405 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pCtx); break;
12406 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pCtx); break;
12407 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pCtx); break;
12408 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pCtx); break;
12409 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pCtx); break;
12410 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pCtx); break;
12411 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pCtx); break;
12412 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pCtx); break;
12413 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pCtx); break;
12414 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pCtx); break;
12415 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
12416 }
12417 }
12418
12419 /*
12420 * Fire of the DBGF event, if enabled (our check here is just a quick one,
12421 * the DBGF call will do a full check).
12422 *
12423 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
12424 * Note! If we have to events, we prioritize the first, i.e. the instruction
12425 * one, in order to avoid event nesting.
12426 */
12427 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
12428 if ( enmEvent1 != DBGFEVENT_END
12429 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
12430 {
12431 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12432 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent1, DBGFEVENTCTX_HM, 1, uEventArg);
12433 if (rcStrict != VINF_SUCCESS)
12434 return rcStrict;
12435 }
12436 else if ( enmEvent2 != DBGFEVENT_END
12437 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
12438 {
12439 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12440 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent2, DBGFEVENTCTX_HM, 1, uEventArg);
12441 if (rcStrict != VINF_SUCCESS)
12442 return rcStrict;
12443 }
12444
12445 return VINF_SUCCESS;
12446}
12447
12448
12449/**
12450 * Single-stepping VM-exit filtering.
12451 *
12452 * This is preprocessing the VM-exits and deciding whether we've gotten far
12453 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
12454 * handling is performed.
12455 *
12456 * @returns Strict VBox status code (i.e. informational status codes too).
12457 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
12458 * @param pVmxTransient The VMX-transient structure.
12459 * @param pDbgState The debug state.
12460 */
12461DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
12462{
12463 /*
12464 * Expensive (saves context) generic dtrace VM-exit probe.
12465 */
12466 uint32_t const uExitReason = pVmxTransient->uExitReason;
12467 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
12468 { /* more likely */ }
12469 else
12470 {
12471 hmR0VmxReadExitQualVmcs(pVmxTransient);
12472 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
12473 AssertRC(rc);
12474 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, &pVCpu->cpum.GstCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
12475 }
12476
12477 /*
12478 * Check for host NMI, just to get that out of the way.
12479 */
12480 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
12481 { /* normally likely */ }
12482 else
12483 {
12484 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
12485 uint32_t const uIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
12486 if (uIntType == VMX_EXIT_INT_INFO_TYPE_NMI)
12487 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
12488 }
12489
12490 /*
12491 * Check for single stepping event if we're stepping.
12492 */
12493 if (pVCpu->hm.s.fSingleInstruction)
12494 {
12495 switch (uExitReason)
12496 {
12497 case VMX_EXIT_MTF:
12498 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
12499
12500 /* Various events: */
12501 case VMX_EXIT_XCPT_OR_NMI:
12502 case VMX_EXIT_EXT_INT:
12503 case VMX_EXIT_TRIPLE_FAULT:
12504 case VMX_EXIT_INT_WINDOW:
12505 case VMX_EXIT_NMI_WINDOW:
12506 case VMX_EXIT_TASK_SWITCH:
12507 case VMX_EXIT_TPR_BELOW_THRESHOLD:
12508 case VMX_EXIT_APIC_ACCESS:
12509 case VMX_EXIT_EPT_VIOLATION:
12510 case VMX_EXIT_EPT_MISCONFIG:
12511 case VMX_EXIT_PREEMPT_TIMER:
12512
12513 /* Instruction specific VM-exits: */
12514 case VMX_EXIT_CPUID:
12515 case VMX_EXIT_GETSEC:
12516 case VMX_EXIT_HLT:
12517 case VMX_EXIT_INVD:
12518 case VMX_EXIT_INVLPG:
12519 case VMX_EXIT_RDPMC:
12520 case VMX_EXIT_RDTSC:
12521 case VMX_EXIT_RSM:
12522 case VMX_EXIT_VMCALL:
12523 case VMX_EXIT_VMCLEAR:
12524 case VMX_EXIT_VMLAUNCH:
12525 case VMX_EXIT_VMPTRLD:
12526 case VMX_EXIT_VMPTRST:
12527 case VMX_EXIT_VMREAD:
12528 case VMX_EXIT_VMRESUME:
12529 case VMX_EXIT_VMWRITE:
12530 case VMX_EXIT_VMXOFF:
12531 case VMX_EXIT_VMXON:
12532 case VMX_EXIT_MOV_CRX:
12533 case VMX_EXIT_MOV_DRX:
12534 case VMX_EXIT_IO_INSTR:
12535 case VMX_EXIT_RDMSR:
12536 case VMX_EXIT_WRMSR:
12537 case VMX_EXIT_MWAIT:
12538 case VMX_EXIT_MONITOR:
12539 case VMX_EXIT_PAUSE:
12540 case VMX_EXIT_GDTR_IDTR_ACCESS:
12541 case VMX_EXIT_LDTR_TR_ACCESS:
12542 case VMX_EXIT_INVEPT:
12543 case VMX_EXIT_RDTSCP:
12544 case VMX_EXIT_INVVPID:
12545 case VMX_EXIT_WBINVD:
12546 case VMX_EXIT_XSETBV:
12547 case VMX_EXIT_RDRAND:
12548 case VMX_EXIT_INVPCID:
12549 case VMX_EXIT_VMFUNC:
12550 case VMX_EXIT_RDSEED:
12551 case VMX_EXIT_XSAVES:
12552 case VMX_EXIT_XRSTORS:
12553 {
12554 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12555 AssertRCReturn(rc, rc);
12556 if ( pVCpu->cpum.GstCtx.rip != pDbgState->uRipStart
12557 || pVCpu->cpum.GstCtx.cs.Sel != pDbgState->uCsStart)
12558 return VINF_EM_DBG_STEPPED;
12559 break;
12560 }
12561
12562 /* Errors and unexpected events: */
12563 case VMX_EXIT_INIT_SIGNAL:
12564 case VMX_EXIT_SIPI:
12565 case VMX_EXIT_IO_SMI:
12566 case VMX_EXIT_SMI:
12567 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
12568 case VMX_EXIT_ERR_MSR_LOAD:
12569 case VMX_EXIT_ERR_MACHINE_CHECK:
12570 case VMX_EXIT_PML_FULL:
12571 case VMX_EXIT_VIRTUALIZED_EOI:
12572 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
12573 break;
12574
12575 default:
12576 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12577 break;
12578 }
12579 }
12580
12581 /*
12582 * Check for debugger event breakpoints and dtrace probes.
12583 */
12584 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
12585 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
12586 {
12587 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVCpu, pVmxTransient, uExitReason);
12588 if (rcStrict != VINF_SUCCESS)
12589 return rcStrict;
12590 }
12591
12592 /*
12593 * Normal processing.
12594 */
12595#ifdef HMVMX_USE_FUNCTION_TABLE
12596 return g_aVMExitHandlers[uExitReason].pfn(pVCpu, pVmxTransient);
12597#else
12598 return hmR0VmxHandleExit(pVCpu, pVmxTransient, uExitReason);
12599#endif
12600}
12601
12602
12603/**
12604 * Single steps guest code using hardware-assisted VMX.
12605 *
12606 * This is -not- the same as the guest single-stepping itself (say using EFLAGS.TF)
12607 * but single-stepping through the hypervisor debugger.
12608 *
12609 * @returns Strict VBox status code (i.e. informational status codes too).
12610 * @param pVCpu The cross context virtual CPU structure.
12611 * @param pcLoops Pointer to the number of executed loops.
12612 *
12613 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
12614 */
12615static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVMCPUCC pVCpu, uint32_t *pcLoops)
12616{
12617 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hmr0.s.cMaxResumeLoops;
12618 Assert(pcLoops);
12619 Assert(*pcLoops <= cMaxResumeLoops);
12620
12621 VMXTRANSIENT VmxTransient;
12622 RT_ZERO(VmxTransient);
12623 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
12624
12625 /* Set HMCPU indicators. */
12626 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
12627 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
12628 pVCpu->hmr0.s.fDebugWantRdTscExit = false;
12629 pVCpu->hmr0.s.fUsingDebugLoop = true;
12630
12631 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
12632 VMXRUNDBGSTATE DbgState;
12633 hmR0VmxRunDebugStateInit(pVCpu, &VmxTransient, &DbgState);
12634 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12635
12636 /*
12637 * The loop.
12638 */
12639 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
12640 for (;;)
12641 {
12642 Assert(!HMR0SuspendPending());
12643 HMVMX_ASSERT_CPU_SAFE(pVCpu);
12644 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
12645 bool fStepping = pVCpu->hm.s.fSingleInstruction;
12646
12647 /* Set up VM-execution controls the next two can respond to. */
12648 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12649
12650 /*
12651 * Preparatory work for running guest code, this may force us to
12652 * return to ring-3.
12653 *
12654 * Warning! This bugger disables interrupts on VINF_SUCCESS!
12655 */
12656 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, fStepping);
12657 if (rcStrict != VINF_SUCCESS)
12658 break;
12659
12660 /* Interrupts are disabled at this point! */
12661 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
12662
12663 /* Override any obnoxious code in the above two calls. */
12664 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12665
12666 /*
12667 * Finally execute the guest.
12668 */
12669 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
12670
12671 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
12672 /* Interrupts are re-enabled at this point! */
12673
12674 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
12675 if (RT_SUCCESS(rcRun))
12676 { /* very likely */ }
12677 else
12678 {
12679 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
12680 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
12681 return rcRun;
12682 }
12683
12684 /* Profile the VM-exit. */
12685 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
12686 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
12687 STAM_COUNTER_INC(&pVCpu->hm.s.aStatExitReason[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
12688 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
12689 HMVMX_START_EXIT_DISPATCH_PROF();
12690
12691 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
12692
12693 /*
12694 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
12695 */
12696 rcStrict = hmR0VmxRunDebugHandleExit(pVCpu, &VmxTransient, &DbgState);
12697 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
12698 if (rcStrict != VINF_SUCCESS)
12699 break;
12700 if (++(*pcLoops) > cMaxResumeLoops)
12701 {
12702 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
12703 rcStrict = VINF_EM_RAW_INTERRUPT;
12704 break;
12705 }
12706
12707 /*
12708 * Stepping: Did the RIP change, if so, consider it a single step.
12709 * Otherwise, make sure one of the TFs gets set.
12710 */
12711 if (fStepping)
12712 {
12713 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12714 AssertRC(rc);
12715 if ( pVCpu->cpum.GstCtx.rip != DbgState.uRipStart
12716 || pVCpu->cpum.GstCtx.cs.Sel != DbgState.uCsStart)
12717 {
12718 rcStrict = VINF_EM_DBG_STEPPED;
12719 break;
12720 }
12721 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
12722 }
12723
12724 /*
12725 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
12726 */
12727 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
12728 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12729
12730 /* Restore all controls applied by hmR0VmxPreRunGuestDebugStateApply above. */
12731 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &VmxTransient, &DbgState, rcStrict);
12732 Assert(rcStrict == VINF_SUCCESS);
12733 }
12734
12735 /*
12736 * Clear the X86_EFL_TF if necessary.
12737 */
12738 if (pVCpu->hmr0.s.fClearTrapFlag)
12739 {
12740 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
12741 AssertRC(rc);
12742 pVCpu->hmr0.s.fClearTrapFlag = false;
12743 pVCpu->cpum.GstCtx.eflags.Bits.u1TF = 0;
12744 }
12745 /** @todo there seems to be issues with the resume flag when the monitor trap
12746 * flag is pending without being used. Seen early in bios init when
12747 * accessing APIC page in protected mode. */
12748
12749 /* Restore HMCPU indicators. */
12750 pVCpu->hmr0.s.fUsingDebugLoop = false;
12751 pVCpu->hmr0.s.fDebugWantRdTscExit = false;
12752 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
12753
12754 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
12755 return rcStrict;
12756}
12757
12758
12759/** @} */
12760
12761
12762/**
12763 * Checks if any expensive dtrace probes are enabled and we should go to the
12764 * debug loop.
12765 *
12766 * @returns true if we should use debug loop, false if not.
12767 */
12768static bool hmR0VmxAnyExpensiveProbesEnabled(void)
12769{
12770 /* It's probably faster to OR the raw 32-bit counter variables together.
12771 Since the variables are in an array and the probes are next to one
12772 another (more or less), we have good locality. So, better read
12773 eight-nine cache lines ever time and only have one conditional, than
12774 128+ conditionals, right? */
12775 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
12776 | VBOXVMM_XCPT_DE_ENABLED_RAW()
12777 | VBOXVMM_XCPT_DB_ENABLED_RAW()
12778 | VBOXVMM_XCPT_BP_ENABLED_RAW()
12779 | VBOXVMM_XCPT_OF_ENABLED_RAW()
12780 | VBOXVMM_XCPT_BR_ENABLED_RAW()
12781 | VBOXVMM_XCPT_UD_ENABLED_RAW()
12782 | VBOXVMM_XCPT_NM_ENABLED_RAW()
12783 | VBOXVMM_XCPT_DF_ENABLED_RAW()
12784 | VBOXVMM_XCPT_TS_ENABLED_RAW()
12785 | VBOXVMM_XCPT_NP_ENABLED_RAW()
12786 | VBOXVMM_XCPT_SS_ENABLED_RAW()
12787 | VBOXVMM_XCPT_GP_ENABLED_RAW()
12788 | VBOXVMM_XCPT_PF_ENABLED_RAW()
12789 | VBOXVMM_XCPT_MF_ENABLED_RAW()
12790 | VBOXVMM_XCPT_AC_ENABLED_RAW()
12791 | VBOXVMM_XCPT_XF_ENABLED_RAW()
12792 | VBOXVMM_XCPT_VE_ENABLED_RAW()
12793 | VBOXVMM_XCPT_SX_ENABLED_RAW()
12794 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
12795 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
12796 ) != 0
12797 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
12798 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
12799 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
12800 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
12801 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
12802 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
12803 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
12804 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
12805 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
12806 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
12807 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
12808 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
12809 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
12810 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
12811 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
12812 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
12813 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
12814 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
12815 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
12816 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
12817 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
12818 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
12819 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
12820 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
12821 | VBOXVMM_INSTR_STR_ENABLED_RAW()
12822 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
12823 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
12824 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
12825 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
12826 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
12827 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
12828 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
12829 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
12830 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
12831 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
12832 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
12833 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
12834 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
12835 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
12836 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
12837 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
12838 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
12839 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
12840 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
12841 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
12842 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
12843 ) != 0
12844 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
12845 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
12846 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
12847 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
12848 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
12849 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
12850 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
12851 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
12852 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
12853 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
12854 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
12855 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
12856 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
12857 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
12858 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
12859 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
12860 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
12861 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
12862 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
12863 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
12864 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
12865 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
12866 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
12867 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
12868 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
12869 | VBOXVMM_EXIT_STR_ENABLED_RAW()
12870 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
12871 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
12872 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
12873 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
12874 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
12875 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
12876 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
12877 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
12878 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
12879 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
12880 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
12881 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
12882 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
12883 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
12884 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
12885 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
12886 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
12887 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
12888 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
12889 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
12890 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
12891 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
12892 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
12893 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
12894 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
12895 ) != 0;
12896}
12897
12898
12899/**
12900 * Runs the guest using hardware-assisted VMX.
12901 *
12902 * @returns Strict VBox status code (i.e. informational status codes too).
12903 * @param pVCpu The cross context virtual CPU structure.
12904 */
12905VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVMCPUCC pVCpu)
12906{
12907 AssertPtr(pVCpu);
12908 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12909 Assert(VMMRZCallRing3IsEnabled(pVCpu));
12910 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12911 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
12912
12913 VBOXSTRICTRC rcStrict;
12914 uint32_t cLoops = 0;
12915 for (;;)
12916 {
12917#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12918 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(pCtx);
12919#else
12920 NOREF(pCtx);
12921 bool const fInNestedGuestMode = false;
12922#endif
12923 if (!fInNestedGuestMode)
12924 {
12925 if ( !pVCpu->hm.s.fUseDebugLoop
12926 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
12927 && !DBGFIsStepping(pVCpu)
12928 && !pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
12929 rcStrict = hmR0VmxRunGuestCodeNormal(pVCpu, &cLoops);
12930 else
12931 rcStrict = hmR0VmxRunGuestCodeDebug(pVCpu, &cLoops);
12932 }
12933#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12934 else
12935 rcStrict = hmR0VmxRunGuestCodeNested(pVCpu, &cLoops);
12936
12937 if (rcStrict == VINF_VMX_VMLAUNCH_VMRESUME)
12938 {
12939 Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
12940 continue;
12941 }
12942 if (rcStrict == VINF_VMX_VMEXIT)
12943 {
12944 Assert(!CPUMIsGuestInVmxNonRootMode(pCtx));
12945 continue;
12946 }
12947#endif
12948 break;
12949 }
12950
12951 int const rcLoop = VBOXSTRICTRC_VAL(rcStrict);
12952 switch (rcLoop)
12953 {
12954 case VERR_EM_INTERPRETER: rcStrict = VINF_EM_RAW_EMULATE_INSTR; break;
12955 case VINF_EM_RESET: rcStrict = VINF_EM_TRIPLE_FAULT; break;
12956 }
12957
12958 int rc2 = hmR0VmxExitToRing3(pVCpu, rcStrict);
12959 if (RT_FAILURE(rc2))
12960 {
12961 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
12962 rcStrict = rc2;
12963 }
12964 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12965 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
12966 return rcStrict;
12967}
12968
12969
12970#ifndef HMVMX_USE_FUNCTION_TABLE
12971/**
12972 * Handles a guest VM-exit from hardware-assisted VMX execution.
12973 *
12974 * @returns Strict VBox status code (i.e. informational status codes too).
12975 * @param pVCpu The cross context virtual CPU structure.
12976 * @param pVmxTransient The VMX-transient structure.
12977 */
12978DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12979{
12980#ifdef DEBUG_ramshankar
12981# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) \
12982 do { \
12983 if (a_fSave != 0) \
12984 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL); \
12985 VBOXSTRICTRC rcStrict = a_CallExpr; \
12986 if (a_fSave != 0) \
12987 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST); \
12988 return rcStrict; \
12989 } while (0)
12990#else
12991# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) return a_CallExpr
12992#endif
12993 uint32_t const uExitReason = pVmxTransient->uExitReason;
12994 switch (uExitReason)
12995 {
12996 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient));
12997 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, hmR0VmxExitEptViolation(pVCpu, pVmxTransient));
12998 case VMX_EXIT_IO_INSTR: VMEXIT_CALL_RET(0, hmR0VmxExitIoInstr(pVCpu, pVmxTransient));
12999 case VMX_EXIT_CPUID: VMEXIT_CALL_RET(0, hmR0VmxExitCpuid(pVCpu, pVmxTransient));
13000 case VMX_EXIT_RDTSC: VMEXIT_CALL_RET(0, hmR0VmxExitRdtsc(pVCpu, pVmxTransient));
13001 case VMX_EXIT_RDTSCP: VMEXIT_CALL_RET(0, hmR0VmxExitRdtscp(pVCpu, pVmxTransient));
13002 case VMX_EXIT_APIC_ACCESS: VMEXIT_CALL_RET(0, hmR0VmxExitApicAccess(pVCpu, pVmxTransient));
13003 case VMX_EXIT_XCPT_OR_NMI: VMEXIT_CALL_RET(0, hmR0VmxExitXcptOrNmi(pVCpu, pVmxTransient));
13004 case VMX_EXIT_MOV_CRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovCRx(pVCpu, pVmxTransient));
13005 case VMX_EXIT_EXT_INT: VMEXIT_CALL_RET(0, hmR0VmxExitExtInt(pVCpu, pVmxTransient));
13006 case VMX_EXIT_INT_WINDOW: VMEXIT_CALL_RET(0, hmR0VmxExitIntWindow(pVCpu, pVmxTransient));
13007 case VMX_EXIT_TPR_BELOW_THRESHOLD: VMEXIT_CALL_RET(0, hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient));
13008 case VMX_EXIT_MWAIT: VMEXIT_CALL_RET(0, hmR0VmxExitMwait(pVCpu, pVmxTransient));
13009 case VMX_EXIT_MONITOR: VMEXIT_CALL_RET(0, hmR0VmxExitMonitor(pVCpu, pVmxTransient));
13010 case VMX_EXIT_TASK_SWITCH: VMEXIT_CALL_RET(0, hmR0VmxExitTaskSwitch(pVCpu, pVmxTransient));
13011 case VMX_EXIT_PREEMPT_TIMER: VMEXIT_CALL_RET(0, hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient));
13012 case VMX_EXIT_RDMSR: VMEXIT_CALL_RET(0, hmR0VmxExitRdmsr(pVCpu, pVmxTransient));
13013 case VMX_EXIT_WRMSR: VMEXIT_CALL_RET(0, hmR0VmxExitWrmsr(pVCpu, pVmxTransient));
13014 case VMX_EXIT_VMCALL: VMEXIT_CALL_RET(0, hmR0VmxExitVmcall(pVCpu, pVmxTransient));
13015 case VMX_EXIT_MOV_DRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovDRx(pVCpu, pVmxTransient));
13016 case VMX_EXIT_HLT: VMEXIT_CALL_RET(0, hmR0VmxExitHlt(pVCpu, pVmxTransient));
13017 case VMX_EXIT_INVD: VMEXIT_CALL_RET(0, hmR0VmxExitInvd(pVCpu, pVmxTransient));
13018 case VMX_EXIT_INVLPG: VMEXIT_CALL_RET(0, hmR0VmxExitInvlpg(pVCpu, pVmxTransient));
13019 case VMX_EXIT_MTF: VMEXIT_CALL_RET(0, hmR0VmxExitMtf(pVCpu, pVmxTransient));
13020 case VMX_EXIT_PAUSE: VMEXIT_CALL_RET(0, hmR0VmxExitPause(pVCpu, pVmxTransient));
13021 case VMX_EXIT_WBINVD: VMEXIT_CALL_RET(0, hmR0VmxExitWbinvd(pVCpu, pVmxTransient));
13022 case VMX_EXIT_XSETBV: VMEXIT_CALL_RET(0, hmR0VmxExitXsetbv(pVCpu, pVmxTransient));
13023 case VMX_EXIT_INVPCID: VMEXIT_CALL_RET(0, hmR0VmxExitInvpcid(pVCpu, pVmxTransient));
13024 case VMX_EXIT_GETSEC: VMEXIT_CALL_RET(0, hmR0VmxExitGetsec(pVCpu, pVmxTransient));
13025 case VMX_EXIT_RDPMC: VMEXIT_CALL_RET(0, hmR0VmxExitRdpmc(pVCpu, pVmxTransient));
13026#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13027 case VMX_EXIT_VMCLEAR: VMEXIT_CALL_RET(0, hmR0VmxExitVmclear(pVCpu, pVmxTransient));
13028 case VMX_EXIT_VMLAUNCH: VMEXIT_CALL_RET(0, hmR0VmxExitVmlaunch(pVCpu, pVmxTransient));
13029 case VMX_EXIT_VMPTRLD: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrld(pVCpu, pVmxTransient));
13030 case VMX_EXIT_VMPTRST: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrst(pVCpu, pVmxTransient));
13031 case VMX_EXIT_VMREAD: VMEXIT_CALL_RET(0, hmR0VmxExitVmread(pVCpu, pVmxTransient));
13032 case VMX_EXIT_VMRESUME: VMEXIT_CALL_RET(0, hmR0VmxExitVmwrite(pVCpu, pVmxTransient));
13033 case VMX_EXIT_VMWRITE: VMEXIT_CALL_RET(0, hmR0VmxExitVmresume(pVCpu, pVmxTransient));
13034 case VMX_EXIT_VMXOFF: VMEXIT_CALL_RET(0, hmR0VmxExitVmxoff(pVCpu, pVmxTransient));
13035 case VMX_EXIT_VMXON: VMEXIT_CALL_RET(0, hmR0VmxExitVmxon(pVCpu, pVmxTransient));
13036 case VMX_EXIT_INVVPID: VMEXIT_CALL_RET(0, hmR0VmxExitInvvpid(pVCpu, pVmxTransient));
13037 case VMX_EXIT_INVEPT: VMEXIT_CALL_RET(0, hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient));
13038#else
13039 case VMX_EXIT_VMCLEAR:
13040 case VMX_EXIT_VMLAUNCH:
13041 case VMX_EXIT_VMPTRLD:
13042 case VMX_EXIT_VMPTRST:
13043 case VMX_EXIT_VMREAD:
13044 case VMX_EXIT_VMRESUME:
13045 case VMX_EXIT_VMWRITE:
13046 case VMX_EXIT_VMXOFF:
13047 case VMX_EXIT_VMXON:
13048 case VMX_EXIT_INVVPID:
13049 case VMX_EXIT_INVEPT:
13050 return hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient);
13051#endif
13052
13053 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pVmxTransient);
13054 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pVmxTransient);
13055 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
13056
13057 case VMX_EXIT_INIT_SIGNAL:
13058 case VMX_EXIT_SIPI:
13059 case VMX_EXIT_IO_SMI:
13060 case VMX_EXIT_SMI:
13061 case VMX_EXIT_ERR_MSR_LOAD:
13062 case VMX_EXIT_ERR_MACHINE_CHECK:
13063 case VMX_EXIT_PML_FULL:
13064 case VMX_EXIT_VIRTUALIZED_EOI:
13065 case VMX_EXIT_GDTR_IDTR_ACCESS:
13066 case VMX_EXIT_LDTR_TR_ACCESS:
13067 case VMX_EXIT_APIC_WRITE:
13068 case VMX_EXIT_RDRAND:
13069 case VMX_EXIT_RSM:
13070 case VMX_EXIT_VMFUNC:
13071 case VMX_EXIT_ENCLS:
13072 case VMX_EXIT_RDSEED:
13073 case VMX_EXIT_XSAVES:
13074 case VMX_EXIT_XRSTORS:
13075 case VMX_EXIT_UMWAIT:
13076 case VMX_EXIT_TPAUSE:
13077 case VMX_EXIT_LOADIWKEY:
13078 default:
13079 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
13080 }
13081#undef VMEXIT_CALL_RET
13082}
13083#endif /* !HMVMX_USE_FUNCTION_TABLE */
13084
13085
13086#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13087/**
13088 * Handles a nested-guest VM-exit from hardware-assisted VMX execution.
13089 *
13090 * @returns Strict VBox status code (i.e. informational status codes too).
13091 * @param pVCpu The cross context virtual CPU structure.
13092 * @param pVmxTransient The VMX-transient structure.
13093 */
13094DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13095{
13096 uint32_t const uExitReason = pVmxTransient->uExitReason;
13097 switch (uExitReason)
13098 {
13099 case VMX_EXIT_EPT_MISCONFIG: return hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient);
13100 case VMX_EXIT_EPT_VIOLATION: return hmR0VmxExitEptViolation(pVCpu, pVmxTransient);
13101 case VMX_EXIT_XCPT_OR_NMI: return hmR0VmxExitXcptOrNmiNested(pVCpu, pVmxTransient);
13102 case VMX_EXIT_IO_INSTR: return hmR0VmxExitIoInstrNested(pVCpu, pVmxTransient);
13103 case VMX_EXIT_HLT: return hmR0VmxExitHltNested(pVCpu, pVmxTransient);
13104
13105 /*
13106 * We shouldn't direct host physical interrupts to the nested-guest.
13107 */
13108 case VMX_EXIT_EXT_INT:
13109 return hmR0VmxExitExtInt(pVCpu, pVmxTransient);
13110
13111 /*
13112 * Instructions that cause VM-exits unconditionally or the condition is
13113 * always is taken solely from the nested hypervisor (meaning if the VM-exit
13114 * happens, it's guaranteed to be a nested-guest VM-exit).
13115 *
13116 * - Provides VM-exit instruction length ONLY.
13117 */
13118 case VMX_EXIT_CPUID: /* Unconditional. */
13119 case VMX_EXIT_VMCALL:
13120 case VMX_EXIT_GETSEC:
13121 case VMX_EXIT_INVD:
13122 case VMX_EXIT_XSETBV:
13123 case VMX_EXIT_VMLAUNCH:
13124 case VMX_EXIT_VMRESUME:
13125 case VMX_EXIT_VMXOFF:
13126 case VMX_EXIT_ENCLS: /* Condition specified solely by nested hypervisor. */
13127 case VMX_EXIT_VMFUNC:
13128 return hmR0VmxExitInstrNested(pVCpu, pVmxTransient);
13129
13130 /*
13131 * Instructions that cause VM-exits unconditionally or the condition is
13132 * always is taken solely from the nested hypervisor (meaning if the VM-exit
13133 * happens, it's guaranteed to be a nested-guest VM-exit).
13134 *
13135 * - Provides VM-exit instruction length.
13136 * - Provides VM-exit information.
13137 * - Optionally provides Exit qualification.
13138 *
13139 * Since Exit qualification is 0 for all VM-exits where it is not
13140 * applicable, reading and passing it to the guest should produce
13141 * defined behavior.
13142 *
13143 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
13144 */
13145 case VMX_EXIT_INVEPT: /* Unconditional. */
13146 case VMX_EXIT_INVVPID:
13147 case VMX_EXIT_VMCLEAR:
13148 case VMX_EXIT_VMPTRLD:
13149 case VMX_EXIT_VMPTRST:
13150 case VMX_EXIT_VMXON:
13151 case VMX_EXIT_GDTR_IDTR_ACCESS: /* Condition specified solely by nested hypervisor. */
13152 case VMX_EXIT_LDTR_TR_ACCESS:
13153 case VMX_EXIT_RDRAND:
13154 case VMX_EXIT_RDSEED:
13155 case VMX_EXIT_XSAVES:
13156 case VMX_EXIT_XRSTORS:
13157 case VMX_EXIT_UMWAIT:
13158 case VMX_EXIT_TPAUSE:
13159 return hmR0VmxExitInstrWithInfoNested(pVCpu, pVmxTransient);
13160
13161 case VMX_EXIT_RDTSC: return hmR0VmxExitRdtscNested(pVCpu, pVmxTransient);
13162 case VMX_EXIT_RDTSCP: return hmR0VmxExitRdtscpNested(pVCpu, pVmxTransient);
13163 case VMX_EXIT_RDMSR: return hmR0VmxExitRdmsrNested(pVCpu, pVmxTransient);
13164 case VMX_EXIT_WRMSR: return hmR0VmxExitWrmsrNested(pVCpu, pVmxTransient);
13165 case VMX_EXIT_INVLPG: return hmR0VmxExitInvlpgNested(pVCpu, pVmxTransient);
13166 case VMX_EXIT_INVPCID: return hmR0VmxExitInvpcidNested(pVCpu, pVmxTransient);
13167 case VMX_EXIT_TASK_SWITCH: return hmR0VmxExitTaskSwitchNested(pVCpu, pVmxTransient);
13168 case VMX_EXIT_WBINVD: return hmR0VmxExitWbinvdNested(pVCpu, pVmxTransient);
13169 case VMX_EXIT_MTF: return hmR0VmxExitMtfNested(pVCpu, pVmxTransient);
13170 case VMX_EXIT_APIC_ACCESS: return hmR0VmxExitApicAccessNested(pVCpu, pVmxTransient);
13171 case VMX_EXIT_APIC_WRITE: return hmR0VmxExitApicWriteNested(pVCpu, pVmxTransient);
13172 case VMX_EXIT_VIRTUALIZED_EOI: return hmR0VmxExitVirtEoiNested(pVCpu, pVmxTransient);
13173 case VMX_EXIT_MOV_CRX: return hmR0VmxExitMovCRxNested(pVCpu, pVmxTransient);
13174 case VMX_EXIT_INT_WINDOW: return hmR0VmxExitIntWindowNested(pVCpu, pVmxTransient);
13175 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindowNested(pVCpu, pVmxTransient);
13176 case VMX_EXIT_TPR_BELOW_THRESHOLD: return hmR0VmxExitTprBelowThresholdNested(pVCpu, pVmxTransient);
13177 case VMX_EXIT_MWAIT: return hmR0VmxExitMwaitNested(pVCpu, pVmxTransient);
13178 case VMX_EXIT_MONITOR: return hmR0VmxExitMonitorNested(pVCpu, pVmxTransient);
13179 case VMX_EXIT_PAUSE: return hmR0VmxExitPauseNested(pVCpu, pVmxTransient);
13180
13181 case VMX_EXIT_PREEMPT_TIMER:
13182 {
13183 /** @todo NSTVMX: Preempt timer. */
13184 return hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient);
13185 }
13186
13187 case VMX_EXIT_MOV_DRX: return hmR0VmxExitMovDRxNested(pVCpu, pVmxTransient);
13188 case VMX_EXIT_RDPMC: return hmR0VmxExitRdpmcNested(pVCpu, pVmxTransient);
13189
13190 case VMX_EXIT_VMREAD:
13191 case VMX_EXIT_VMWRITE: return hmR0VmxExitVmreadVmwriteNested(pVCpu, pVmxTransient);
13192
13193 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFaultNested(pVCpu, pVmxTransient);
13194 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestStateNested(pVCpu, pVmxTransient);
13195
13196 case VMX_EXIT_INIT_SIGNAL:
13197 case VMX_EXIT_SIPI:
13198 case VMX_EXIT_IO_SMI:
13199 case VMX_EXIT_SMI:
13200 case VMX_EXIT_ERR_MSR_LOAD:
13201 case VMX_EXIT_ERR_MACHINE_CHECK:
13202 case VMX_EXIT_PML_FULL:
13203 case VMX_EXIT_RSM:
13204 default:
13205 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
13206 }
13207}
13208#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13209
13210
13211/** @name VM-exit helpers.
13212 * @{
13213 */
13214/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13215/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= VM-exit helpers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
13216/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13217
13218/** Macro for VM-exits called unexpectedly. */
13219#define HMVMX_UNEXPECTED_EXIT_RET(a_pVCpu, a_HmError) \
13220 do { \
13221 (a_pVCpu)->hm.s.u32HMError = (a_HmError); \
13222 return VERR_VMX_UNEXPECTED_EXIT; \
13223 } while (0)
13224
13225#ifdef VBOX_STRICT
13226/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
13227# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
13228 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
13229
13230# define HMVMX_ASSERT_PREEMPT_CPUID() \
13231 do { \
13232 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
13233 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
13234 } while (0)
13235
13236# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13237 do { \
13238 AssertPtr((a_pVCpu)); \
13239 AssertPtr((a_pVmxTransient)); \
13240 Assert((a_pVmxTransient)->fVMEntryFailed == false); \
13241 Assert((a_pVmxTransient)->pVmcsInfo); \
13242 Assert(ASMIntAreEnabled()); \
13243 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
13244 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
13245 Log4Func(("vcpu[%RU32]\n", (a_pVCpu)->idCpu)); \
13246 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
13247 if (!VMMRZCallRing3IsEnabled((a_pVCpu))) \
13248 HMVMX_ASSERT_PREEMPT_CPUID(); \
13249 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
13250 } while (0)
13251
13252# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13253 do { \
13254 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); \
13255 Assert((a_pVmxTransient)->fIsNestedGuest); \
13256 } while (0)
13257
13258# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13259 do { \
13260 Log4Func(("\n")); \
13261 } while (0)
13262#else
13263# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13264 do { \
13265 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
13266 NOREF((a_pVCpu)); NOREF((a_pVmxTransient)); \
13267 } while (0)
13268
13269# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13270 do { HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); } while (0)
13271
13272# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) do { } while (0)
13273#endif
13274
13275#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13276/** Macro that does the necessary privilege checks and intercepted VM-exits for
13277 * guests that attempted to execute a VMX instruction. */
13278# define HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(a_pVCpu, a_uExitReason) \
13279 do \
13280 { \
13281 VBOXSTRICTRC rcStrictTmp = hmR0VmxCheckExitDueToVmxInstr((a_pVCpu), (a_uExitReason)); \
13282 if (rcStrictTmp == VINF_SUCCESS) \
13283 { /* likely */ } \
13284 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
13285 { \
13286 Assert((a_pVCpu)->hm.s.Event.fPending); \
13287 Log4Func(("Privilege checks failed -> %#x\n", VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo))); \
13288 return VINF_SUCCESS; \
13289 } \
13290 else \
13291 { \
13292 int rcTmp = VBOXSTRICTRC_VAL(rcStrictTmp); \
13293 AssertMsgFailedReturn(("Unexpected failure. rc=%Rrc", rcTmp), rcTmp); \
13294 } \
13295 } while (0)
13296
13297/** Macro that decodes a memory operand for an VM-exit caused by an instruction. */
13298# define HMVMX_DECODE_MEM_OPERAND(a_pVCpu, a_uExitInstrInfo, a_uExitQual, a_enmMemAccess, a_pGCPtrEffAddr) \
13299 do \
13300 { \
13301 VBOXSTRICTRC rcStrictTmp = hmR0VmxDecodeMemOperand((a_pVCpu), (a_uExitInstrInfo), (a_uExitQual), (a_enmMemAccess), \
13302 (a_pGCPtrEffAddr)); \
13303 if (rcStrictTmp == VINF_SUCCESS) \
13304 { /* likely */ } \
13305 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
13306 { \
13307 uint8_t const uXcptTmp = VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo); \
13308 Log4Func(("Memory operand decoding failed, raising xcpt %#x\n", uXcptTmp)); \
13309 NOREF(uXcptTmp); \
13310 return VINF_SUCCESS; \
13311 } \
13312 else \
13313 { \
13314 Log4Func(("hmR0VmxDecodeMemOperand failed. rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrictTmp))); \
13315 return rcStrictTmp; \
13316 } \
13317 } while (0)
13318#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13319
13320
13321/**
13322 * Advances the guest RIP by the specified number of bytes.
13323 *
13324 * @param pVCpu The cross context virtual CPU structure.
13325 * @param cbInstr Number of bytes to advance the RIP by.
13326 *
13327 * @remarks No-long-jump zone!!!
13328 */
13329DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPUCC pVCpu, uint32_t cbInstr)
13330{
13331 /* Advance the RIP. */
13332 pVCpu->cpum.GstCtx.rip += cbInstr;
13333 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
13334
13335 /* Update interrupt inhibition. */
13336 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
13337 && pVCpu->cpum.GstCtx.rip != EMGetInhibitInterruptsPC(pVCpu))
13338 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
13339}
13340
13341
13342/**
13343 * Advances the guest RIP after reading it from the VMCS.
13344 *
13345 * @returns VBox status code, no informational status codes.
13346 * @param pVCpu The cross context virtual CPU structure.
13347 * @param pVmxTransient The VMX-transient structure.
13348 *
13349 * @remarks No-long-jump zone!!!
13350 */
13351static int hmR0VmxAdvanceGuestRip(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13352{
13353 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13354 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
13355 AssertRCReturn(rc, rc);
13356
13357 hmR0VmxAdvanceGuestRipBy(pVCpu, pVmxTransient->cbExitInstr);
13358 return VINF_SUCCESS;
13359}
13360
13361
13362/**
13363 * Handle a condition that occurred while delivering an event through the guest or
13364 * nested-guest IDT.
13365 *
13366 * @returns Strict VBox status code (i.e. informational status codes too).
13367 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13368 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
13369 * to continue execution of the guest which will delivery the \#DF.
13370 * @retval VINF_EM_RESET if we detected a triple-fault condition.
13371 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
13372 *
13373 * @param pVCpu The cross context virtual CPU structure.
13374 * @param pVmxTransient The VMX-transient structure.
13375 *
13376 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13377 * Additionally, HMVMX_READ_EXIT_QUALIFICATION is required if the VM-exit
13378 * is due to an EPT violation, PML full or SPP-related event.
13379 *
13380 * @remarks No-long-jump zone!!!
13381 */
13382static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13383{
13384 Assert(!pVCpu->hm.s.Event.fPending);
13385 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
13386 if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
13387 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
13388 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
13389 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_EXIT_QUALIFICATION);
13390
13391 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
13392 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13393 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo;
13394 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
13395 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo))
13396 {
13397 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo);
13398 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo);
13399
13400 /*
13401 * If the event was a software interrupt (generated with INT n) or a software exception
13402 * (generated by INT3/INTO) or a privileged software exception (generated by INT1), we
13403 * can handle the VM-exit and continue guest execution which will re-execute the
13404 * instruction rather than re-injecting the exception, as that can cause premature
13405 * trips to ring-3 before injection and involve TRPM which currently has no way of
13406 * storing that these exceptions were caused by these instructions (ICEBP's #DB poses
13407 * the problem).
13408 */
13409 IEMXCPTRAISE enmRaise;
13410 IEMXCPTRAISEINFO fRaiseInfo;
13411 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
13412 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
13413 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
13414 {
13415 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
13416 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
13417 }
13418 else if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo))
13419 {
13420 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
13421 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo);
13422 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT);
13423
13424 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
13425 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
13426
13427 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo);
13428
13429 /* Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF(). */
13430 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
13431 {
13432 pVmxTransient->fVectoringPF = true;
13433 enmRaise = IEMXCPTRAISE_PREV_EVENT;
13434 }
13435 }
13436 else
13437 {
13438 /*
13439 * If an exception or hardware interrupt delivery caused an EPT violation/misconfig or APIC access
13440 * VM-exit, then the VM-exit interruption-information will not be valid and we end up here.
13441 * It is sufficient to reflect the original event to the guest after handling the VM-exit.
13442 */
13443 Assert( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
13444 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
13445 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
13446 enmRaise = IEMXCPTRAISE_PREV_EVENT;
13447 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
13448 }
13449
13450 /*
13451 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
13452 * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
13453 * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
13454 * subsequent VM-entry would fail, see @bugref{7445}.
13455 *
13456 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception".
13457 */
13458 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
13459 && enmRaise == IEMXCPTRAISE_PREV_EVENT
13460 && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
13461 && CPUMIsGuestNmiBlocking(pVCpu))
13462 {
13463 CPUMSetGuestNmiBlocking(pVCpu, false);
13464 }
13465
13466 switch (enmRaise)
13467 {
13468 case IEMXCPTRAISE_CURRENT_XCPT:
13469 {
13470 Log4Func(("IDT: Pending secondary Xcpt: idtinfo=%#RX64 exitinfo=%#RX64\n", uIdtVectorInfo, uExitIntInfo));
13471 Assert(rcStrict == VINF_SUCCESS);
13472 break;
13473 }
13474
13475 case IEMXCPTRAISE_PREV_EVENT:
13476 {
13477 uint32_t u32ErrCode;
13478 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo))
13479 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
13480 else
13481 u32ErrCode = 0;
13482
13483 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
13484 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflect);
13485 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(uIdtVectorInfo), 0 /* cbInstr */,
13486 u32ErrCode, pVCpu->cpum.GstCtx.cr2);
13487
13488 Log4Func(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntInfo,
13489 pVCpu->hm.s.Event.u32ErrCode));
13490 Assert(rcStrict == VINF_SUCCESS);
13491 break;
13492 }
13493
13494 case IEMXCPTRAISE_REEXEC_INSTR:
13495 Assert(rcStrict == VINF_SUCCESS);
13496 break;
13497
13498 case IEMXCPTRAISE_DOUBLE_FAULT:
13499 {
13500 /*
13501 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
13502 * second #PF as a guest #PF (and not a shadow #PF) and needs to be converted into a #DF.
13503 */
13504 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
13505 {
13506 pVmxTransient->fVectoringDoublePF = true;
13507 Log4Func(("IDT: Vectoring double #PF %#RX64 cr2=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo,
13508 pVCpu->cpum.GstCtx.cr2));
13509 rcStrict = VINF_SUCCESS;
13510 }
13511 else
13512 {
13513 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectConvertDF);
13514 hmR0VmxSetPendingXcptDF(pVCpu);
13515 Log4Func(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntInfo,
13516 uIdtVector, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
13517 rcStrict = VINF_HM_DOUBLE_FAULT;
13518 }
13519 break;
13520 }
13521
13522 case IEMXCPTRAISE_TRIPLE_FAULT:
13523 {
13524 Log4Func(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector,
13525 VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
13526 rcStrict = VINF_EM_RESET;
13527 break;
13528 }
13529
13530 case IEMXCPTRAISE_CPU_HANG:
13531 {
13532 Log4Func(("IDT: Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", fRaiseInfo));
13533 rcStrict = VERR_EM_GUEST_CPU_HANG;
13534 break;
13535 }
13536
13537 default:
13538 {
13539 AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
13540 rcStrict = VERR_VMX_IPE_2;
13541 break;
13542 }
13543 }
13544 }
13545 else if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
13546 && !CPUMIsGuestNmiBlocking(pVCpu))
13547 {
13548 if ( VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)
13549 && VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo) != X86_XCPT_DF
13550 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(uExitIntInfo))
13551 {
13552 /*
13553 * Execution of IRET caused a fault when NMI blocking was in effect (i.e we're in
13554 * the guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13555 * that virtual NMIs remain blocked until the IRET execution is completed.
13556 *
13557 * See Intel spec. 31.7.1.2 "Resuming Guest Software After Handling An Exception".
13558 */
13559 CPUMSetGuestNmiBlocking(pVCpu, true);
13560 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13561 }
13562 else if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
13563 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
13564 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
13565 {
13566 /*
13567 * Execution of IRET caused an EPT violation, page-modification log-full event or
13568 * SPP-related event VM-exit when NMI blocking was in effect (i.e. we're in the
13569 * guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13570 * that virtual NMIs remain blocked until the IRET execution is completed.
13571 *
13572 * See Intel spec. 27.2.3 "Information about NMI unblocking due to IRET"
13573 */
13574 if (VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(pVmxTransient->uExitQual))
13575 {
13576 CPUMSetGuestNmiBlocking(pVCpu, true);
13577 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13578 }
13579 }
13580 }
13581
13582 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
13583 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
13584 return rcStrict;
13585}
13586
13587
13588#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13589/**
13590 * Perform the relevant VMX instruction checks for VM-exits that occurred due to the
13591 * guest attempting to execute a VMX instruction.
13592 *
13593 * @returns Strict VBox status code (i.e. informational status codes too).
13594 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13595 * @retval VINF_HM_PENDING_XCPT if an exception was raised.
13596 *
13597 * @param pVCpu The cross context virtual CPU structure.
13598 * @param uExitReason The VM-exit reason.
13599 *
13600 * @todo NSTVMX: Document other error codes when VM-exit is implemented.
13601 * @remarks No-long-jump zone!!!
13602 */
13603static VBOXSTRICTRC hmR0VmxCheckExitDueToVmxInstr(PVMCPUCC pVCpu, uint32_t uExitReason)
13604{
13605 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS
13606 | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
13607
13608 /*
13609 * The physical CPU would have already checked the CPU mode/code segment.
13610 * We shall just assert here for paranoia.
13611 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
13612 */
13613 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13614 Assert( !CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx)
13615 || CPUMIsGuestIn64BitCodeEx(&pVCpu->cpum.GstCtx));
13616
13617 if (uExitReason == VMX_EXIT_VMXON)
13618 {
13619 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
13620
13621 /*
13622 * We check CR4.VMXE because it is required to be always set while in VMX operation
13623 * by physical CPUs and our CR4 read-shadow is only consulted when executing specific
13624 * instructions (CLTS, LMSW, MOV CR, and SMSW) and thus doesn't affect CPU operation
13625 * otherwise (i.e. physical CPU won't automatically #UD if Cr4Shadow.VMXE is 0).
13626 */
13627 if (!CPUMIsGuestVmxEnabled(&pVCpu->cpum.GstCtx))
13628 {
13629 Log4Func(("CR4.VMXE is not set -> #UD\n"));
13630 hmR0VmxSetPendingXcptUD(pVCpu);
13631 return VINF_HM_PENDING_XCPT;
13632 }
13633 }
13634 else if (!CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx))
13635 {
13636 /*
13637 * The guest has not entered VMX operation but attempted to execute a VMX instruction
13638 * (other than VMXON), we need to raise a #UD.
13639 */
13640 Log4Func(("Not in VMX root mode -> #UD\n"));
13641 hmR0VmxSetPendingXcptUD(pVCpu);
13642 return VINF_HM_PENDING_XCPT;
13643 }
13644
13645 /* All other checks (including VM-exit intercepts) are handled by IEM instruction emulation. */
13646 return VINF_SUCCESS;
13647}
13648
13649
13650/**
13651 * Decodes the memory operand of an instruction that caused a VM-exit.
13652 *
13653 * The Exit qualification field provides the displacement field for memory
13654 * operand instructions, if any.
13655 *
13656 * @returns Strict VBox status code (i.e. informational status codes too).
13657 * @retval VINF_SUCCESS if the operand was successfully decoded.
13658 * @retval VINF_HM_PENDING_XCPT if an exception was raised while decoding the
13659 * operand.
13660 * @param pVCpu The cross context virtual CPU structure.
13661 * @param uExitInstrInfo The VM-exit instruction information field.
13662 * @param enmMemAccess The memory operand's access type (read or write).
13663 * @param GCPtrDisp The instruction displacement field, if any. For
13664 * RIP-relative addressing pass RIP + displacement here.
13665 * @param pGCPtrMem Where to store the effective destination memory address.
13666 *
13667 * @remarks Warning! This function ASSUMES the instruction cannot be used in real or
13668 * virtual-8086 mode hence skips those checks while verifying if the
13669 * segment is valid.
13670 */
13671static VBOXSTRICTRC hmR0VmxDecodeMemOperand(PVMCPUCC pVCpu, uint32_t uExitInstrInfo, RTGCPTR GCPtrDisp, VMXMEMACCESS enmMemAccess,
13672 PRTGCPTR pGCPtrMem)
13673{
13674 Assert(pGCPtrMem);
13675 Assert(!CPUMIsGuestInRealOrV86Mode(pVCpu));
13676 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_EFER
13677 | CPUMCTX_EXTRN_CR0);
13678
13679 static uint64_t const s_auAddrSizeMasks[] = { UINT64_C(0xffff), UINT64_C(0xffffffff), UINT64_C(0xffffffffffffffff) };
13680 static uint64_t const s_auAccessSizeMasks[] = { sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t) };
13681 AssertCompile(RT_ELEMENTS(s_auAccessSizeMasks) == RT_ELEMENTS(s_auAddrSizeMasks));
13682
13683 VMXEXITINSTRINFO ExitInstrInfo;
13684 ExitInstrInfo.u = uExitInstrInfo;
13685 uint8_t const uAddrSize = ExitInstrInfo.All.u3AddrSize;
13686 uint8_t const iSegReg = ExitInstrInfo.All.iSegReg;
13687 bool const fIdxRegValid = !ExitInstrInfo.All.fIdxRegInvalid;
13688 uint8_t const iIdxReg = ExitInstrInfo.All.iIdxReg;
13689 uint8_t const uScale = ExitInstrInfo.All.u2Scaling;
13690 bool const fBaseRegValid = !ExitInstrInfo.All.fBaseRegInvalid;
13691 uint8_t const iBaseReg = ExitInstrInfo.All.iBaseReg;
13692 bool const fIsMemOperand = !ExitInstrInfo.All.fIsRegOperand;
13693 bool const fIsLongMode = CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx);
13694
13695 /*
13696 * Validate instruction information.
13697 * This shouldn't happen on real hardware but useful while testing our nested hardware-virtualization code.
13698 */
13699 AssertLogRelMsgReturn(uAddrSize < RT_ELEMENTS(s_auAddrSizeMasks),
13700 ("Invalid address size. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_1);
13701 AssertLogRelMsgReturn(iSegReg < X86_SREG_COUNT,
13702 ("Invalid segment register. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_2);
13703 AssertLogRelMsgReturn(fIsMemOperand,
13704 ("Expected memory operand. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_3);
13705
13706 /*
13707 * Compute the complete effective address.
13708 *
13709 * See AMD instruction spec. 1.4.2 "SIB Byte Format"
13710 * See AMD spec. 4.5.2 "Segment Registers".
13711 */
13712 RTGCPTR GCPtrMem = GCPtrDisp;
13713 if (fBaseRegValid)
13714 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iBaseReg].u64;
13715 if (fIdxRegValid)
13716 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iIdxReg].u64 << uScale;
13717
13718 RTGCPTR const GCPtrOff = GCPtrMem;
13719 if ( !fIsLongMode
13720 || iSegReg >= X86_SREG_FS)
13721 GCPtrMem += pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
13722 GCPtrMem &= s_auAddrSizeMasks[uAddrSize];
13723
13724 /*
13725 * Validate effective address.
13726 * See AMD spec. 4.5.3 "Segment Registers in 64-Bit Mode".
13727 */
13728 uint8_t const cbAccess = s_auAccessSizeMasks[uAddrSize];
13729 Assert(cbAccess > 0);
13730 if (fIsLongMode)
13731 {
13732 if (X86_IS_CANONICAL(GCPtrMem))
13733 {
13734 *pGCPtrMem = GCPtrMem;
13735 return VINF_SUCCESS;
13736 }
13737
13738 /** @todo r=ramshankar: We should probably raise \#SS or \#GP. See AMD spec. 4.12.2
13739 * "Data Limit Checks in 64-bit Mode". */
13740 Log4Func(("Long mode effective address is not canonical GCPtrMem=%#RX64\n", GCPtrMem));
13741 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13742 return VINF_HM_PENDING_XCPT;
13743 }
13744
13745 /*
13746 * This is a watered down version of iemMemApplySegment().
13747 * Parts that are not applicable for VMX instructions like real-or-v8086 mode
13748 * and segment CPL/DPL checks are skipped.
13749 */
13750 RTGCPTR32 const GCPtrFirst32 = (RTGCPTR32)GCPtrOff;
13751 RTGCPTR32 const GCPtrLast32 = GCPtrFirst32 + cbAccess - 1;
13752 PCCPUMSELREG pSel = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
13753
13754 /* Check if the segment is present and usable. */
13755 if ( pSel->Attr.n.u1Present
13756 && !pSel->Attr.n.u1Unusable)
13757 {
13758 Assert(pSel->Attr.n.u1DescType);
13759 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
13760 {
13761 /* Check permissions for the data segment. */
13762 if ( enmMemAccess == VMXMEMACCESS_WRITE
13763 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE))
13764 {
13765 Log4Func(("Data segment access invalid. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13766 hmR0VmxSetPendingXcptGP(pVCpu, iSegReg);
13767 return VINF_HM_PENDING_XCPT;
13768 }
13769
13770 /* Check limits if it's a normal data segment. */
13771 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
13772 {
13773 if ( GCPtrFirst32 > pSel->u32Limit
13774 || GCPtrLast32 > pSel->u32Limit)
13775 {
13776 Log4Func(("Data segment limit exceeded. "
13777 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13778 GCPtrLast32, pSel->u32Limit));
13779 if (iSegReg == X86_SREG_SS)
13780 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13781 else
13782 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13783 return VINF_HM_PENDING_XCPT;
13784 }
13785 }
13786 else
13787 {
13788 /* Check limits if it's an expand-down data segment.
13789 Note! The upper boundary is defined by the B bit, not the G bit! */
13790 if ( GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
13791 || GCPtrLast32 > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
13792 {
13793 Log4Func(("Expand-down data segment limit exceeded. "
13794 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13795 GCPtrLast32, pSel->u32Limit));
13796 if (iSegReg == X86_SREG_SS)
13797 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13798 else
13799 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13800 return VINF_HM_PENDING_XCPT;
13801 }
13802 }
13803 }
13804 else
13805 {
13806 /* Check permissions for the code segment. */
13807 if ( enmMemAccess == VMXMEMACCESS_WRITE
13808 || ( enmMemAccess == VMXMEMACCESS_READ
13809 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)))
13810 {
13811 Log4Func(("Code segment access invalid. Attr=%#RX32\n", pSel->Attr.u));
13812 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13813 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13814 return VINF_HM_PENDING_XCPT;
13815 }
13816
13817 /* Check limits for the code segment (normal/expand-down not applicable for code segments). */
13818 if ( GCPtrFirst32 > pSel->u32Limit
13819 || GCPtrLast32 > pSel->u32Limit)
13820 {
13821 Log4Func(("Code segment limit exceeded. GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n",
13822 GCPtrFirst32, GCPtrLast32, pSel->u32Limit));
13823 if (iSegReg == X86_SREG_SS)
13824 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13825 else
13826 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13827 return VINF_HM_PENDING_XCPT;
13828 }
13829 }
13830 }
13831 else
13832 {
13833 Log4Func(("Not present or unusable segment. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13834 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13835 return VINF_HM_PENDING_XCPT;
13836 }
13837
13838 *pGCPtrMem = GCPtrMem;
13839 return VINF_SUCCESS;
13840}
13841#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13842
13843
13844/**
13845 * VM-exit helper for LMSW.
13846 */
13847static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst)
13848{
13849 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13850 AssertRCReturn(rc, rc);
13851
13852 VBOXSTRICTRC rcStrict = IEMExecDecodedLmsw(pVCpu, cbInstr, uMsw, GCPtrEffDst);
13853 AssertMsg( rcStrict == VINF_SUCCESS
13854 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13855
13856 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13857 if (rcStrict == VINF_IEM_RAISED_XCPT)
13858 {
13859 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13860 rcStrict = VINF_SUCCESS;
13861 }
13862
13863 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
13864 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13865 return rcStrict;
13866}
13867
13868
13869/**
13870 * VM-exit helper for CLTS.
13871 */
13872static VBOXSTRICTRC hmR0VmxExitClts(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
13873{
13874 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13875 AssertRCReturn(rc, rc);
13876
13877 VBOXSTRICTRC rcStrict = IEMExecDecodedClts(pVCpu, cbInstr);
13878 AssertMsg( rcStrict == VINF_SUCCESS
13879 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13880
13881 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13882 if (rcStrict == VINF_IEM_RAISED_XCPT)
13883 {
13884 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13885 rcStrict = VINF_SUCCESS;
13886 }
13887
13888 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
13889 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13890 return rcStrict;
13891}
13892
13893
13894/**
13895 * VM-exit helper for MOV from CRx (CRx read).
13896 */
13897static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13898{
13899 Assert(iCrReg < 16);
13900 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
13901
13902 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13903 AssertRCReturn(rc, rc);
13904
13905 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxRead(pVCpu, cbInstr, iGReg, iCrReg);
13906 AssertMsg( rcStrict == VINF_SUCCESS
13907 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13908
13909 if (iGReg == X86_GREG_xSP)
13910 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_RSP);
13911 else
13912 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13913#ifdef VBOX_WITH_STATISTICS
13914 switch (iCrReg)
13915 {
13916 case 0: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Read); break;
13917 case 2: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Read); break;
13918 case 3: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Read); break;
13919 case 4: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Read); break;
13920 case 8: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Read); break;
13921 }
13922#endif
13923 Log4Func(("CR%d Read access rcStrict=%Rrc\n", iCrReg, VBOXSTRICTRC_VAL(rcStrict)));
13924 return rcStrict;
13925}
13926
13927
13928/**
13929 * VM-exit helper for MOV to CRx (CRx write).
13930 */
13931static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13932{
13933 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13934 AssertRCReturn(rc, rc);
13935
13936 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, cbInstr, iCrReg, iGReg);
13937 AssertMsg( rcStrict == VINF_SUCCESS
13938 || rcStrict == VINF_IEM_RAISED_XCPT
13939 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13940
13941 switch (iCrReg)
13942 {
13943 case 0:
13944 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0
13945 | HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
13946 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Write);
13947 Log4Func(("CR0 write. rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr0));
13948 break;
13949
13950 case 2:
13951 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Write);
13952 /* Nothing to do here, CR2 it's not part of the VMCS. */
13953 break;
13954
13955 case 3:
13956 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR3);
13957 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Write);
13958 Log4Func(("CR3 write. rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr3));
13959 break;
13960
13961 case 4:
13962 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR4);
13963 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Write);
13964 Log4Func(("CR4 write. rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n", VBOXSTRICTRC_VAL(rcStrict),
13965 pVCpu->cpum.GstCtx.cr4, pVCpu->hmr0.s.fLoadSaveGuestXcr0));
13966 break;
13967
13968 case 8:
13969 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged,
13970 HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_APIC_TPR);
13971 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Write);
13972 break;
13973
13974 default:
13975 AssertMsgFailed(("Invalid CRx register %#x\n", iCrReg));
13976 break;
13977 }
13978
13979 if (rcStrict == VINF_IEM_RAISED_XCPT)
13980 {
13981 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13982 rcStrict = VINF_SUCCESS;
13983 }
13984 return rcStrict;
13985}
13986
13987
13988/**
13989 * VM-exit exception handler for \#PF (Page-fault exception).
13990 *
13991 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13992 */
13993static VBOXSTRICTRC hmR0VmxExitXcptPF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13994{
13995 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13996 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
13997 hmR0VmxReadExitQualVmcs(pVmxTransient);
13998
13999 if (!pVM->hmr0.s.fNestedPaging)
14000 { /* likely */ }
14001 else
14002 {
14003#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
14004 Assert(pVmxTransient->fIsNestedGuest || pVCpu->hmr0.s.fUsingDebugLoop);
14005#endif
14006 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
14007 if (!pVmxTransient->fVectoringDoublePF)
14008 {
14009 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
14010 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual);
14011 }
14012 else
14013 {
14014 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
14015 Assert(!pVmxTransient->fIsNestedGuest);
14016 hmR0VmxSetPendingXcptDF(pVCpu);
14017 Log4Func(("Pending #DF due to vectoring #PF w/ NestedPaging\n"));
14018 }
14019 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
14020 return VINF_SUCCESS;
14021 }
14022
14023 Assert(!pVmxTransient->fIsNestedGuest);
14024
14025 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
14026 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
14027 if (pVmxTransient->fVectoringPF)
14028 {
14029 Assert(pVCpu->hm.s.Event.fPending);
14030 return VINF_EM_RAW_INJECT_TRPM_EVENT;
14031 }
14032
14033 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14034 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14035 AssertRCReturn(rc, rc);
14036
14037 Log4Func(("#PF: cs:rip=%#04x:%#RX64 err_code=%#RX32 exit_qual=%#RX64 cr3=%#RX64\n", pCtx->cs.Sel, pCtx->rip,
14038 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual, pCtx->cr3));
14039
14040 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQual, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
14041 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pCtx), (RTGCPTR)pVmxTransient->uExitQual);
14042
14043 Log4Func(("#PF: rc=%Rrc\n", rc));
14044 if (rc == VINF_SUCCESS)
14045 {
14046 /*
14047 * This is typically a shadow page table sync or a MMIO instruction. But we may have
14048 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
14049 */
14050 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14051 TRPMResetTrap(pVCpu);
14052 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
14053 return rc;
14054 }
14055
14056 if (rc == VINF_EM_RAW_GUEST_TRAP)
14057 {
14058 if (!pVmxTransient->fVectoringDoublePF)
14059 {
14060 /* It's a guest page fault and needs to be reflected to the guest. */
14061 uint32_t const uGstErrorCode = TRPMGetErrorCode(pVCpu);
14062 TRPMResetTrap(pVCpu);
14063 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
14064 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
14065 uGstErrorCode, pVmxTransient->uExitQual);
14066 }
14067 else
14068 {
14069 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
14070 TRPMResetTrap(pVCpu);
14071 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
14072 hmR0VmxSetPendingXcptDF(pVCpu);
14073 Log4Func(("#PF: Pending #DF due to vectoring #PF\n"));
14074 }
14075
14076 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
14077 return VINF_SUCCESS;
14078 }
14079
14080 TRPMResetTrap(pVCpu);
14081 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
14082 return rc;
14083}
14084
14085
14086/**
14087 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
14088 *
14089 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14090 */
14091static VBOXSTRICTRC hmR0VmxExitXcptMF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14092{
14093 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14094 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
14095
14096 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0);
14097 AssertRCReturn(rc, rc);
14098
14099 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_NE))
14100 {
14101 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
14102 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
14103
14104 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
14105 * provides VM-exit instruction length. If this causes problem later,
14106 * disassemble the instruction like it's done on AMD-V. */
14107 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14108 AssertRCReturn(rc2, rc2);
14109 return rc;
14110 }
14111
14112 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbExitInstr,
14113 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14114 return VINF_SUCCESS;
14115}
14116
14117
14118/**
14119 * VM-exit exception handler for \#BP (Breakpoint exception).
14120 *
14121 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14122 */
14123static VBOXSTRICTRC hmR0VmxExitXcptBP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14124{
14125 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14126 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
14127
14128 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14129 AssertRCReturn(rc, rc);
14130
14131 if (!pVmxTransient->fIsNestedGuest)
14132 rc = DBGFTrap03Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(&pVCpu->cpum.GstCtx));
14133 else
14134 rc = VINF_EM_RAW_GUEST_TRAP;
14135
14136 if (rc == VINF_EM_RAW_GUEST_TRAP)
14137 {
14138 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14139 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14140 rc = VINF_SUCCESS;
14141 }
14142
14143 Assert(rc == VINF_SUCCESS || rc == VINF_EM_DBG_BREAKPOINT);
14144 return rc;
14145}
14146
14147
14148/**
14149 * VM-exit exception handler for \#AC (Alignment-check exception).
14150 *
14151 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14152 */
14153static VBOXSTRICTRC hmR0VmxExitXcptAC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14154{
14155 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14156
14157 /*
14158 * Detect #ACs caused by host having enabled split-lock detection.
14159 * Emulate such instructions.
14160 */
14161 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo,
14162 CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS);
14163 AssertRCReturn(rc, rc);
14164 /** @todo detect split lock in cpu feature? */
14165 if ( /* 1. If 486-style alignment checks aren't enabled, then this must be a split-lock exception */
14166 !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_AM)
14167 /* 2. #AC cannot happen in rings 0-2 except for split-lock detection. */
14168 || CPUMGetGuestCPL(pVCpu) != 3
14169 /* 3. When the EFLAGS.AC != 0 this can only be a split-lock case. */
14170 || !(pVCpu->cpum.GstCtx.eflags.u & X86_EFL_AC) )
14171 {
14172 /*
14173 * Check for debug/trace events and import state accordingly.
14174 */
14175 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitGuestACSplitLock);
14176 PVMCC pVM = pVCpu->pVMR0;
14177 if ( !DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_VMX_SPLIT_LOCK)
14178 && !VBOXVMM_VMX_SPLIT_LOCK_ENABLED())
14179 {
14180 if (pVM->cCpus == 1)
14181 {
14182#if 0 /** @todo r=bird: This is potentially wrong. Might have to just do a whole state sync above and mark everything changed to be safe... */
14183 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14184#else
14185 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14186#endif
14187 AssertRCReturn(rc, rc);
14188 }
14189 }
14190 else
14191 {
14192 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14193 AssertRCReturn(rc, rc);
14194
14195 VBOXVMM_XCPT_DF(pVCpu, &pVCpu->cpum.GstCtx);
14196
14197 if (DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_VMX_SPLIT_LOCK))
14198 {
14199 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, DBGFEVENT_VMX_SPLIT_LOCK, DBGFEVENTCTX_HM, 0);
14200 if (rcStrict != VINF_SUCCESS)
14201 return rcStrict;
14202 }
14203 }
14204
14205 /*
14206 * Emulate the instruction.
14207 *
14208 * We have to ignore the LOCK prefix here as we must not retrigger the
14209 * detection on the host. This isn't all that satisfactory, though...
14210 */
14211 if (pVM->cCpus == 1)
14212 {
14213 Log8Func(("cs:rip=%#04x:%#RX64 rflags=%#RX64 cr0=%#RX64 split-lock #AC\n", pVCpu->cpum.GstCtx.cs.Sel,
14214 pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags, pVCpu->cpum.GstCtx.cr0));
14215
14216 /** @todo For SMP configs we should do a rendezvous here. */
14217 VBOXSTRICTRC rcStrict = IEMExecOneIgnoreLock(pVCpu);
14218 if (rcStrict == VINF_SUCCESS)
14219#if 0 /** @todo r=bird: This is potentially wrong. Might have to just do a whole state sync above and mark everything changed to be safe... */
14220 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged,
14221 HM_CHANGED_GUEST_RIP
14222 | HM_CHANGED_GUEST_RFLAGS
14223 | HM_CHANGED_GUEST_GPRS_MASK
14224 | HM_CHANGED_GUEST_CS
14225 | HM_CHANGED_GUEST_SS);
14226#else
14227 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14228#endif
14229 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14230 {
14231 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14232 rcStrict = VINF_SUCCESS;
14233 }
14234 return rcStrict;
14235 }
14236 Log8Func(("cs:rip=%#04x:%#RX64 rflags=%#RX64 cr0=%#RX64 split-lock #AC -> VINF_EM_EMULATE_SPLIT_LOCK\n",
14237 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags, pVCpu->cpum.GstCtx.cr0));
14238 return VINF_EM_EMULATE_SPLIT_LOCK;
14239 }
14240
14241 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC);
14242 Log8Func(("cs:rip=%#04x:%#RX64 rflags=%#RX64 cr0=%#RX64 cpl=%d -> #AC\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
14243 pVCpu->cpum.GstCtx.rflags, pVCpu->cpum.GstCtx.cr0, CPUMGetGuestCPL(pVCpu) ));
14244
14245 /* Re-inject it. We'll detect any nesting before getting here. */
14246 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14247 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14248 return VINF_SUCCESS;
14249}
14250
14251
14252/**
14253 * VM-exit exception handler for \#DB (Debug exception).
14254 *
14255 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14256 */
14257static VBOXSTRICTRC hmR0VmxExitXcptDB(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14258{
14259 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14260 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
14261
14262 /*
14263 * Get the DR6-like values from the Exit qualification and pass it to DBGF for processing.
14264 */
14265 hmR0VmxReadExitQualVmcs(pVmxTransient);
14266
14267 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
14268 uint64_t const uDR6 = X86_DR6_INIT_VAL
14269 | (pVmxTransient->uExitQual & ( X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3
14270 | X86_DR6_BD | X86_DR6_BS));
14271
14272 int rc;
14273 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14274 if (!pVmxTransient->fIsNestedGuest)
14275 {
14276 rc = DBGFTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
14277
14278 /*
14279 * Prevents stepping twice over the same instruction when the guest is stepping using
14280 * EFLAGS.TF and the hypervisor debugger is stepping using MTF.
14281 * Testcase: DOSQEMM, break (using "ba x 1") at cs:rip 0x70:0x774 and step (using "t").
14282 */
14283 if ( rc == VINF_EM_DBG_STEPPED
14284 && (pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MONITOR_TRAP_FLAG))
14285 {
14286 Assert(pVCpu->hm.s.fSingleInstruction);
14287 rc = VINF_EM_RAW_GUEST_TRAP;
14288 }
14289 }
14290 else
14291 rc = VINF_EM_RAW_GUEST_TRAP;
14292 Log6Func(("rc=%Rrc\n", rc));
14293 if (rc == VINF_EM_RAW_GUEST_TRAP)
14294 {
14295 /*
14296 * The exception was for the guest. Update DR6, DR7.GD and
14297 * IA32_DEBUGCTL.LBR before forwarding it.
14298 * See Intel spec. 27.1 "Architectural State before a VM-Exit".
14299 */
14300 VMMRZCallRing3Disable(pVCpu);
14301 HM_DISABLE_PREEMPT(pVCpu);
14302
14303 pCtx->dr[6] &= ~X86_DR6_B_MASK;
14304 pCtx->dr[6] |= uDR6;
14305 if (CPUMIsGuestDebugStateActive(pVCpu))
14306 ASMSetDR6(pCtx->dr[6]);
14307
14308 HM_RESTORE_PREEMPT();
14309 VMMRZCallRing3Enable(pVCpu);
14310
14311 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_DR7);
14312 AssertRCReturn(rc, rc);
14313
14314 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
14315 pCtx->dr[7] &= ~(uint64_t)X86_DR7_GD;
14316
14317 /* Paranoia. */
14318 pCtx->dr[7] &= ~(uint64_t)X86_DR7_RAZ_MASK;
14319 pCtx->dr[7] |= X86_DR7_RA1_MASK;
14320
14321 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, pCtx->dr[7]);
14322 AssertRC(rc);
14323
14324 /*
14325 * Raise #DB in the guest.
14326 *
14327 * It is important to reflect exactly what the VM-exit gave us (preserving the
14328 * interruption-type) rather than use hmR0VmxSetPendingXcptDB() as the #DB could've
14329 * been raised while executing ICEBP (INT1) and not the regular #DB. Thus it may
14330 * trigger different handling in the CPU (like skipping DPL checks), see @bugref{6398}.
14331 *
14332 * Intel re-documented ICEBP/INT1 on May 2018 previously documented as part of
14333 * Intel 386, see Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
14334 */
14335 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14336 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14337 return VINF_SUCCESS;
14338 }
14339
14340 /*
14341 * Not a guest trap, must be a hypervisor related debug event then.
14342 * Update DR6 in case someone is interested in it.
14343 */
14344 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
14345 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
14346 CPUMSetHyperDR6(pVCpu, uDR6);
14347
14348 return rc;
14349}
14350
14351
14352/**
14353 * Hacks its way around the lovely mesa driver's backdoor accesses.
14354 *
14355 * @sa hmR0SvmHandleMesaDrvGp.
14356 */
14357static int hmR0VmxHandleMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
14358{
14359 LogFunc(("cs:rip=%#04x:%#RX64 rcx=%#RX64 rbx=%#RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->rcx, pCtx->rbx));
14360 RT_NOREF(pCtx);
14361
14362 /* For now we'll just skip the instruction. */
14363 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14364}
14365
14366
14367/**
14368 * Checks if the \#GP'ing instruction is the mesa driver doing it's lovely
14369 * backdoor logging w/o checking what it is running inside.
14370 *
14371 * This recognizes an "IN EAX,DX" instruction executed in flat ring-3, with the
14372 * backdoor port and magic numbers loaded in registers.
14373 *
14374 * @returns true if it is, false if it isn't.
14375 * @sa hmR0SvmIsMesaDrvGp.
14376 */
14377DECLINLINE(bool) hmR0VmxIsMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
14378{
14379 /* 0xed: IN eAX,dx */
14380 uint8_t abInstr[1];
14381 if (pVmxTransient->cbExitInstr != sizeof(abInstr))
14382 return false;
14383
14384 /* Check that it is #GP(0). */
14385 if (pVmxTransient->uExitIntErrorCode != 0)
14386 return false;
14387
14388 /* Check magic and port. */
14389 Assert(!(pCtx->fExtrn & (CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX)));
14390 /*Log(("hmR0VmxIsMesaDrvGp: rax=%RX64 rdx=%RX64\n", pCtx->rax, pCtx->rdx));*/
14391 if (pCtx->rax != UINT32_C(0x564d5868))
14392 return false;
14393 if (pCtx->dx != UINT32_C(0x5658))
14394 return false;
14395
14396 /* Flat ring-3 CS. */
14397 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_CS);
14398 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_CS));
14399 /*Log(("hmR0VmxIsMesaDrvGp: cs.Attr.n.u2Dpl=%d base=%Rx64\n", pCtx->cs.Attr.n.u2Dpl, pCtx->cs.u64Base));*/
14400 if (pCtx->cs.Attr.n.u2Dpl != 3)
14401 return false;
14402 if (pCtx->cs.u64Base != 0)
14403 return false;
14404
14405 /* Check opcode. */
14406 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_RIP);
14407 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_RIP));
14408 int rc = PGMPhysSimpleReadGCPtr(pVCpu, abInstr, pCtx->rip, sizeof(abInstr));
14409 /*Log(("hmR0VmxIsMesaDrvGp: PGMPhysSimpleReadGCPtr -> %Rrc %#x\n", rc, abInstr[0]));*/
14410 if (RT_FAILURE(rc))
14411 return false;
14412 if (abInstr[0] != 0xed)
14413 return false;
14414
14415 return true;
14416}
14417
14418
14419/**
14420 * VM-exit exception handler for \#GP (General-protection exception).
14421 *
14422 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14423 */
14424static VBOXSTRICTRC hmR0VmxExitXcptGP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14425{
14426 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14427 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
14428
14429 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14430 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14431 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
14432 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
14433 { /* likely */ }
14434 else
14435 {
14436#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
14437 Assert(pVCpu->hmr0.s.fUsingDebugLoop || pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
14438#endif
14439 /*
14440 * If the guest is not in real-mode or we have unrestricted guest execution support, or if we are
14441 * executing a nested-guest, reflect #GP to the guest or nested-guest.
14442 */
14443 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14444 AssertRCReturn(rc, rc);
14445 Log4Func(("Gst: cs:rip=%#04x:%#RX64 ErrorCode=%#x cr0=%#RX64 cpl=%u tr=%#04x\n", pCtx->cs.Sel, pCtx->rip,
14446 pVmxTransient->uExitIntErrorCode, pCtx->cr0, CPUMGetGuestCPL(pVCpu), pCtx->tr.Sel));
14447
14448 if ( pVmxTransient->fIsNestedGuest
14449 || !pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv
14450 || !hmR0VmxIsMesaDrvGp(pVCpu, pVmxTransient, pCtx))
14451 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14452 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14453 else
14454 rc = hmR0VmxHandleMesaDrvGp(pVCpu, pVmxTransient, pCtx);
14455 return rc;
14456 }
14457
14458 Assert(CPUMIsGuestInRealModeEx(pCtx));
14459 Assert(!pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest);
14460 Assert(!pVmxTransient->fIsNestedGuest);
14461
14462 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14463 AssertRCReturn(rc, rc);
14464
14465 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
14466 if (rcStrict == VINF_SUCCESS)
14467 {
14468 if (!CPUMIsGuestInRealModeEx(pCtx))
14469 {
14470 /*
14471 * The guest is no longer in real-mode, check if we can continue executing the
14472 * guest using hardware-assisted VMX. Otherwise, fall back to emulation.
14473 */
14474 pVmcsInfoShared->RealMode.fRealOnV86Active = false;
14475 if (HMCanExecuteVmxGuest(pVCpu->pVMR0, pVCpu, pCtx))
14476 {
14477 Log4Func(("Mode changed but guest still suitable for executing using hardware-assisted VMX\n"));
14478 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14479 }
14480 else
14481 {
14482 Log4Func(("Mode changed -> VINF_EM_RESCHEDULE\n"));
14483 rcStrict = VINF_EM_RESCHEDULE;
14484 }
14485 }
14486 else
14487 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14488 }
14489 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14490 {
14491 rcStrict = VINF_SUCCESS;
14492 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14493 }
14494 return VBOXSTRICTRC_VAL(rcStrict);
14495}
14496
14497
14498/**
14499 * VM-exit exception handler wrapper for all other exceptions that are not handled
14500 * by a specific handler.
14501 *
14502 * This simply re-injects the exception back into the VM without any special
14503 * processing.
14504 *
14505 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14506 */
14507static VBOXSTRICTRC hmR0VmxExitXcptOthers(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14508{
14509 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14510
14511#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
14512 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14513 AssertMsg(pVCpu->hmr0.s.fUsingDebugLoop || pVmcsInfo->pShared->RealMode.fRealOnV86Active || pVmxTransient->fIsNestedGuest,
14514 ("uVector=%#x u32XcptBitmap=%#X32\n",
14515 VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVmcsInfo->u32XcptBitmap));
14516 NOREF(pVmcsInfo);
14517#endif
14518
14519 /*
14520 * Re-inject the exception into the guest. This cannot be a double-fault condition which
14521 * would have been handled while checking exits due to event delivery.
14522 */
14523 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14524
14525#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
14526 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
14527 AssertRCReturn(rc, rc);
14528 Log4Func(("Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
14529#endif
14530
14531#ifdef VBOX_WITH_STATISTICS
14532 switch (uVector)
14533 {
14534 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE); break;
14535 case X86_XCPT_DB: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB); break;
14536 case X86_XCPT_BP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP); break;
14537 case X86_XCPT_OF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
14538 case X86_XCPT_BR: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBR); break;
14539 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD); break;
14540 case X86_XCPT_NM: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
14541 case X86_XCPT_DF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDF); break;
14542 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS); break;
14543 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP); break;
14544 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS); break;
14545 case X86_XCPT_GP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP); break;
14546 case X86_XCPT_PF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF); break;
14547 case X86_XCPT_MF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF); break;
14548 case X86_XCPT_AC: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC); break;
14549 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF); break;
14550 default:
14551 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
14552 break;
14553 }
14554#endif
14555
14556 /* We should never call this function for a page-fault, we'd need to pass on the fault address below otherwise. */
14557 Assert(!VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo));
14558 NOREF(uVector);
14559
14560 /* Re-inject the original exception into the guest. */
14561 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14562 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14563 return VINF_SUCCESS;
14564}
14565
14566
14567/**
14568 * VM-exit exception handler for all exceptions (except NMIs!).
14569 *
14570 * @remarks This may be called for both guests and nested-guests. Take care to not
14571 * make assumptions and avoid doing anything that is not relevant when
14572 * executing a nested-guest (e.g., Mesa driver hacks).
14573 */
14574static VBOXSTRICTRC hmR0VmxExitXcpt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14575{
14576 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
14577
14578 /*
14579 * If this VM-exit occurred while delivering an event through the guest IDT, take
14580 * action based on the return code and additional hints (e.g. for page-faults)
14581 * that will be updated in the VMX transient structure.
14582 */
14583 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
14584 if (rcStrict == VINF_SUCCESS)
14585 {
14586 /*
14587 * If an exception caused a VM-exit due to delivery of an event, the original
14588 * event may have to be re-injected into the guest. We shall reinject it and
14589 * continue guest execution. However, page-fault is a complicated case and
14590 * needs additional processing done in hmR0VmxExitXcptPF().
14591 */
14592 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
14593 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14594 if ( !pVCpu->hm.s.Event.fPending
14595 || uVector == X86_XCPT_PF)
14596 {
14597 switch (uVector)
14598 {
14599 case X86_XCPT_PF: return hmR0VmxExitXcptPF(pVCpu, pVmxTransient);
14600 case X86_XCPT_GP: return hmR0VmxExitXcptGP(pVCpu, pVmxTransient);
14601 case X86_XCPT_MF: return hmR0VmxExitXcptMF(pVCpu, pVmxTransient);
14602 case X86_XCPT_DB: return hmR0VmxExitXcptDB(pVCpu, pVmxTransient);
14603 case X86_XCPT_BP: return hmR0VmxExitXcptBP(pVCpu, pVmxTransient);
14604 case X86_XCPT_AC: return hmR0VmxExitXcptAC(pVCpu, pVmxTransient);
14605 default:
14606 return hmR0VmxExitXcptOthers(pVCpu, pVmxTransient);
14607 }
14608 }
14609 /* else: inject pending event before resuming guest execution. */
14610 }
14611 else if (rcStrict == VINF_HM_DOUBLE_FAULT)
14612 {
14613 Assert(pVCpu->hm.s.Event.fPending);
14614 rcStrict = VINF_SUCCESS;
14615 }
14616
14617 return rcStrict;
14618}
14619/** @} */
14620
14621
14622/** @name VM-exit handlers.
14623 * @{
14624 */
14625/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
14626/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
14627/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
14628
14629/**
14630 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
14631 */
14632HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14633{
14634 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14635 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
14636 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
14637 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
14638 return VINF_SUCCESS;
14639 return VINF_EM_RAW_INTERRUPT;
14640}
14641
14642
14643/**
14644 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI). Conditional
14645 * VM-exit.
14646 */
14647HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14648{
14649 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14650 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
14651
14652 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
14653
14654 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
14655 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14656 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
14657
14658 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14659 Assert( !(pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT)
14660 && uExitIntType != VMX_EXIT_INT_INFO_TYPE_EXT_INT);
14661 NOREF(pVmcsInfo);
14662
14663 VBOXSTRICTRC rcStrict;
14664 switch (uExitIntType)
14665 {
14666 /*
14667 * Host physical NMIs:
14668 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we
14669 * injected it ourselves and anything we inject is not going to cause a VM-exit directly
14670 * for the event being injected[1]. Go ahead and dispatch the NMI to the host[2].
14671 *
14672 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
14673 * See Intel spec. 27.5.5 "Updating Non-Register State".
14674 */
14675 case VMX_EXIT_INT_INFO_TYPE_NMI:
14676 {
14677 rcStrict = hmR0VmxExitHostNmi(pVCpu, pVmcsInfo);
14678 break;
14679 }
14680
14681 /*
14682 * Privileged software exceptions (#DB from ICEBP),
14683 * Software exceptions (#BP and #OF),
14684 * Hardware exceptions:
14685 * Process the required exceptions and resume guest execution if possible.
14686 */
14687 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
14688 Assert(uVector == X86_XCPT_DB);
14689 RT_FALL_THRU();
14690 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
14691 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uExitIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT);
14692 RT_FALL_THRU();
14693 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
14694 {
14695 NOREF(uVector);
14696 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
14697 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14698 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
14699 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
14700
14701 rcStrict = hmR0VmxExitXcpt(pVCpu, pVmxTransient);
14702 break;
14703 }
14704
14705 default:
14706 {
14707 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
14708 rcStrict = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
14709 AssertMsgFailed(("Invalid/unexpected VM-exit interruption info %#x\n", pVmxTransient->uExitIntInfo));
14710 break;
14711 }
14712 }
14713
14714 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
14715 return rcStrict;
14716}
14717
14718
14719/**
14720 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
14721 */
14722HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14723{
14724 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14725
14726 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
14727 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14728 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
14729
14730 /* Evaluate and deliver pending events and resume guest execution. */
14731 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
14732 return VINF_SUCCESS;
14733}
14734
14735
14736/**
14737 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
14738 */
14739HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14740{
14741 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14742
14743 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14744 if (RT_UNLIKELY(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))) /** @todo NSTVMX: Turn this into an assertion. */
14745 {
14746 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
14747 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14748 }
14749
14750 Assert(!CPUMIsGuestNmiBlocking(pVCpu));
14751
14752 /*
14753 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
14754 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
14755 */
14756 uint32_t fIntrState;
14757 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
14758 AssertRC(rc);
14759 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
14760 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
14761 {
14762 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
14763 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
14764
14765 fIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
14766 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
14767 AssertRC(rc);
14768 }
14769
14770 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
14771 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
14772
14773 /* Evaluate and deliver pending events and resume guest execution. */
14774 return VINF_SUCCESS;
14775}
14776
14777
14778/**
14779 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
14780 */
14781HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14782{
14783 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14784 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14785}
14786
14787
14788/**
14789 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
14790 */
14791HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14792{
14793 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14794 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14795}
14796
14797
14798/**
14799 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
14800 */
14801HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14802{
14803 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14804
14805 /*
14806 * Get the state we need and update the exit history entry.
14807 */
14808 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14809 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14810
14811 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14812 AssertRCReturn(rc, rc);
14813
14814 VBOXSTRICTRC rcStrict;
14815 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
14816 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_CPUID),
14817 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
14818 if (!pExitRec)
14819 {
14820 /*
14821 * Regular CPUID instruction execution.
14822 */
14823 rcStrict = IEMExecDecodedCpuid(pVCpu, pVmxTransient->cbExitInstr);
14824 if (rcStrict == VINF_SUCCESS)
14825 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14826 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14827 {
14828 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14829 rcStrict = VINF_SUCCESS;
14830 }
14831 }
14832 else
14833 {
14834 /*
14835 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
14836 */
14837 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14838 AssertRCReturn(rc2, rc2);
14839
14840 Log4(("CpuIdExit/%u: %04x:%08RX64: %#x/%#x -> EMHistoryExec\n",
14841 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx));
14842
14843 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
14844 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14845
14846 Log4(("CpuIdExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
14847 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
14848 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
14849 }
14850 return rcStrict;
14851}
14852
14853
14854/**
14855 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
14856 */
14857HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14858{
14859 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14860
14861 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14862 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4);
14863 AssertRCReturn(rc, rc);
14864
14865 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_SMXE)
14866 return VINF_EM_RAW_EMULATE_INSTR;
14867
14868 AssertMsgFailed(("hmR0VmxExitGetsec: Unexpected VM-exit when CR4.SMXE is 0.\n"));
14869 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14870}
14871
14872
14873/**
14874 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
14875 */
14876HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14877{
14878 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14879
14880 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14881 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14882 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14883 AssertRCReturn(rc, rc);
14884
14885 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtsc(pVCpu, pVmxTransient->cbExitInstr);
14886 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14887 {
14888 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14889 we must reset offsetting on VM-entry. See @bugref{6634}. */
14890 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14891 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14892 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14893 }
14894 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14895 {
14896 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14897 rcStrict = VINF_SUCCESS;
14898 }
14899 return rcStrict;
14900}
14901
14902
14903/**
14904 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
14905 */
14906HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14907{
14908 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14909
14910 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14911 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14912 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_TSC_AUX);
14913 AssertRCReturn(rc, rc);
14914
14915 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtscp(pVCpu, pVmxTransient->cbExitInstr);
14916 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14917 {
14918 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14919 we must reset offsetting on VM-reentry. See @bugref{6634}. */
14920 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14921 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14922 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14923 }
14924 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14925 {
14926 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14927 rcStrict = VINF_SUCCESS;
14928 }
14929 return rcStrict;
14930}
14931
14932
14933/**
14934 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
14935 */
14936HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14937{
14938 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14939
14940 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14941 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_CR0
14942 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS);
14943 AssertRCReturn(rc, rc);
14944
14945 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14946 rc = EMInterpretRdpmc(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
14947 if (RT_LIKELY(rc == VINF_SUCCESS))
14948 {
14949 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14950 Assert(pVmxTransient->cbExitInstr == 2);
14951 }
14952 else
14953 {
14954 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
14955 rc = VERR_EM_INTERPRETER;
14956 }
14957 return rc;
14958}
14959
14960
14961/**
14962 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
14963 */
14964HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14965{
14966 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14967
14968 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
14969 if (EMAreHypercallInstructionsEnabled(pVCpu))
14970 {
14971 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14972 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CR0
14973 | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
14974 AssertRCReturn(rc, rc);
14975
14976 /* Perform the hypercall. */
14977 rcStrict = GIMHypercall(pVCpu, &pVCpu->cpum.GstCtx);
14978 if (rcStrict == VINF_SUCCESS)
14979 {
14980 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14981 AssertRCReturn(rc, rc);
14982 }
14983 else
14984 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
14985 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
14986 || RT_FAILURE(rcStrict));
14987
14988 /* If the hypercall changes anything other than guest's general-purpose registers,
14989 we would need to reload the guest changed bits here before VM-entry. */
14990 }
14991 else
14992 Log4Func(("Hypercalls not enabled\n"));
14993
14994 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
14995 if (RT_FAILURE(rcStrict))
14996 {
14997 hmR0VmxSetPendingXcptUD(pVCpu);
14998 rcStrict = VINF_SUCCESS;
14999 }
15000
15001 return rcStrict;
15002}
15003
15004
15005/**
15006 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
15007 */
15008HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15009{
15010 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15011 Assert(!pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging || pVCpu->hmr0.s.fUsingDebugLoop);
15012
15013 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15014 hmR0VmxReadExitQualVmcs(pVmxTransient);
15015 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15016 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15017 AssertRCReturn(rc, rc);
15018
15019 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpg(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->uExitQual);
15020
15021 if (rcStrict == VINF_SUCCESS || rcStrict == VINF_PGM_SYNC_CR3)
15022 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15023 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15024 {
15025 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15026 rcStrict = VINF_SUCCESS;
15027 }
15028 else
15029 AssertMsgFailed(("Unexpected IEMExecDecodedInvlpg(%#RX64) status: %Rrc\n", pVmxTransient->uExitQual,
15030 VBOXSTRICTRC_VAL(rcStrict)));
15031 return rcStrict;
15032}
15033
15034
15035/**
15036 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
15037 */
15038HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15039{
15040 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15041
15042 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15043 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15044 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_DS);
15045 AssertRCReturn(rc, rc);
15046
15047 VBOXSTRICTRC rcStrict = IEMExecDecodedMonitor(pVCpu, pVmxTransient->cbExitInstr);
15048 if (rcStrict == VINF_SUCCESS)
15049 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15050 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15051 {
15052 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15053 rcStrict = VINF_SUCCESS;
15054 }
15055
15056 return rcStrict;
15057}
15058
15059
15060/**
15061 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
15062 */
15063HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15064{
15065 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15066
15067 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15068 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15069 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
15070 AssertRCReturn(rc, rc);
15071
15072 VBOXSTRICTRC rcStrict = IEMExecDecodedMwait(pVCpu, pVmxTransient->cbExitInstr);
15073 if (RT_SUCCESS(rcStrict))
15074 {
15075 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15076 if (EMMonitorWaitShouldContinue(pVCpu, &pVCpu->cpum.GstCtx))
15077 rcStrict = VINF_SUCCESS;
15078 }
15079
15080 return rcStrict;
15081}
15082
15083
15084/**
15085 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
15086 * VM-exit.
15087 */
15088HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15089{
15090 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15091 return VINF_EM_RESET;
15092}
15093
15094
15095/**
15096 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
15097 */
15098HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15099{
15100 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15101
15102 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15103 AssertRCReturn(rc, rc);
15104
15105 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS); /* Advancing the RIP above should've imported eflags. */
15106 if (EMShouldContinueAfterHalt(pVCpu, &pVCpu->cpum.GstCtx)) /* Requires eflags. */
15107 rc = VINF_SUCCESS;
15108 else
15109 rc = VINF_EM_HALT;
15110
15111 if (rc != VINF_SUCCESS)
15112 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
15113 return rc;
15114}
15115
15116
15117/**
15118 * VM-exit handler for instructions that result in a \#UD exception delivered to
15119 * the guest.
15120 */
15121HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15122{
15123 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15124 hmR0VmxSetPendingXcptUD(pVCpu);
15125 return VINF_SUCCESS;
15126}
15127
15128
15129/**
15130 * VM-exit handler for expiry of the VMX-preemption timer.
15131 */
15132HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15133{
15134 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15135
15136 /* If the VMX-preemption timer has expired, reinitialize the preemption timer on next VM-entry. */
15137 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
15138Log12(("hmR0VmxExitPreemptTimer:\n"));
15139
15140 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
15141 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15142 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
15143 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
15144 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
15145}
15146
15147
15148/**
15149 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
15150 */
15151HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15152{
15153 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15154
15155 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15156 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15157 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_CR4);
15158 AssertRCReturn(rc, rc);
15159
15160 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbExitInstr);
15161 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
15162 : HM_CHANGED_RAISED_XCPT_MASK);
15163
15164 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15165 bool const fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
15166 if (fLoadSaveGuestXcr0 != pVCpu->hmr0.s.fLoadSaveGuestXcr0)
15167 {
15168 pVCpu->hmr0.s.fLoadSaveGuestXcr0 = fLoadSaveGuestXcr0;
15169 hmR0VmxUpdateStartVmFunction(pVCpu);
15170 }
15171
15172 return rcStrict;
15173}
15174
15175
15176/**
15177 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
15178 */
15179HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15180{
15181 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15182
15183 /** @todo Enable the new code after finding a reliably guest test-case. */
15184#if 1
15185 return VERR_EM_INTERPRETER;
15186#else
15187 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15188 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15189 hmR0VmxReadExitQualVmcs(pVmxTransient);
15190 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15191 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15192 AssertRCReturn(rc, rc);
15193
15194 /* Paranoia. Ensure this has a memory operand. */
15195 Assert(!pVmxTransient->ExitInstrInfo.Inv.u1Cleared0);
15196
15197 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
15198 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
15199 uint64_t const uType = CPUMIsGuestIn64BitCode(pVCpu) ? pVCpu->cpum.GstCtx.aGRegs[iGReg].u64
15200 : pVCpu->cpum.GstCtx.aGRegs[iGReg].u32;
15201
15202 RTGCPTR GCPtrDesc;
15203 HMVMX_DECODE_MEM_OPERAND(pVCpu, pVmxTransient->ExitInstrInfo.u, pVmxTransient->uExitQual, VMXMEMACCESS_READ, &GCPtrDesc);
15204
15205 VBOXSTRICTRC rcStrict = IEMExecDecodedInvpcid(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->ExitInstrInfo.Inv.iSegReg,
15206 GCPtrDesc, uType);
15207 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15208 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15209 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15210 {
15211 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15212 rcStrict = VINF_SUCCESS;
15213 }
15214 return rcStrict;
15215#endif
15216}
15217
15218
15219/**
15220 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error
15221 * VM-exit.
15222 */
15223HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15224{
15225 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15226 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15227 AssertRCReturn(rc, rc);
15228
15229 rc = hmR0VmxCheckCachedVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
15230 if (RT_FAILURE(rc))
15231 return rc;
15232
15233 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
15234 NOREF(uInvalidReason);
15235
15236#ifdef VBOX_STRICT
15237 uint32_t fIntrState;
15238 uint64_t u64Val;
15239 hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
15240 hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
15241 hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
15242
15243 Log4(("uInvalidReason %u\n", uInvalidReason));
15244 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
15245 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
15246 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
15247
15248 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState); AssertRC(rc);
15249 Log4(("VMX_VMCS32_GUEST_INT_STATE %#RX32\n", fIntrState));
15250 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Val); AssertRC(rc);
15251 Log4(("VMX_VMCS_GUEST_CR0 %#RX64\n", u64Val));
15252 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_MASK, &u64Val); AssertRC(rc);
15253 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RX64\n", u64Val));
15254 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Val); AssertRC(rc);
15255 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
15256 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_MASK, &u64Val); AssertRC(rc);
15257 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RX64\n", u64Val));
15258 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Val); AssertRC(rc);
15259 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
15260 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging)
15261 {
15262 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
15263 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
15264 }
15265 hmR0DumpRegs(pVCpu, HM_DUMP_REG_FLAGS_ALL);
15266#endif
15267
15268 return VERR_VMX_INVALID_GUEST_STATE;
15269}
15270
15271/**
15272 * VM-exit handler for all undefined/unexpected reasons. Should never happen.
15273 */
15274HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUnexpected(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15275{
15276 /*
15277 * Cumulative notes of all recognized but unexpected VM-exits.
15278 *
15279 * 1. This does -not- cover scenarios like a page-fault VM-exit occurring when
15280 * nested-paging is used.
15281 *
15282 * 2. Any instruction that causes a VM-exit unconditionally (for e.g. VMXON) must be
15283 * emulated or a #UD must be raised in the guest. Therefore, we should -not- be using
15284 * this function (and thereby stop VM execution) for handling such instructions.
15285 *
15286 *
15287 * VMX_EXIT_INIT_SIGNAL:
15288 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
15289 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these
15290 * VM-exits. However, we should not receive INIT signals VM-exit while executing a VM.
15291 *
15292 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery"
15293 * See Intel spec. 29.3 "VMX Instructions" for "VMXON".
15294 * See Intel spec. "23.8 Restrictions on VMX operation".
15295 *
15296 * VMX_EXIT_SIPI:
15297 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest
15298 * activity state is used. We don't make use of it as our guests don't have direct
15299 * access to the host local APIC.
15300 *
15301 * See Intel spec. 25.3 "Other Causes of VM-exits".
15302 *
15303 * VMX_EXIT_IO_SMI:
15304 * VMX_EXIT_SMI:
15305 * This can only happen if we support dual-monitor treatment of SMI, which can be
15306 * activated by executing VMCALL in VMX root operation. Only an STM (SMM transfer
15307 * monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL in
15308 * VMX root mode or receive an SMI. If we get here, something funny is going on.
15309 *
15310 * See Intel spec. 33.15.6 "Activating the Dual-Monitor Treatment"
15311 * See Intel spec. 25.3 "Other Causes of VM-Exits"
15312 *
15313 * VMX_EXIT_ERR_MSR_LOAD:
15314 * Failures while loading MSRs are part of the VM-entry MSR-load area are unexpected
15315 * and typically indicates a bug in the hypervisor code. We thus cannot not resume
15316 * execution.
15317 *
15318 * See Intel spec. 26.7 "VM-Entry Failures During Or After Loading Guest State".
15319 *
15320 * VMX_EXIT_ERR_MACHINE_CHECK:
15321 * Machine check exceptions indicates a fatal/unrecoverable hardware condition
15322 * including but not limited to system bus, ECC, parity, cache and TLB errors. A
15323 * #MC exception abort class exception is raised. We thus cannot assume a
15324 * reasonable chance of continuing any sort of execution and we bail.
15325 *
15326 * See Intel spec. 15.1 "Machine-check Architecture".
15327 * See Intel spec. 27.1 "Architectural State Before A VM Exit".
15328 *
15329 * VMX_EXIT_PML_FULL:
15330 * VMX_EXIT_VIRTUALIZED_EOI:
15331 * VMX_EXIT_APIC_WRITE:
15332 * We do not currently support any of these features and thus they are all unexpected
15333 * VM-exits.
15334 *
15335 * VMX_EXIT_GDTR_IDTR_ACCESS:
15336 * VMX_EXIT_LDTR_TR_ACCESS:
15337 * VMX_EXIT_RDRAND:
15338 * VMX_EXIT_RSM:
15339 * VMX_EXIT_VMFUNC:
15340 * VMX_EXIT_ENCLS:
15341 * VMX_EXIT_RDSEED:
15342 * VMX_EXIT_XSAVES:
15343 * VMX_EXIT_XRSTORS:
15344 * VMX_EXIT_UMWAIT:
15345 * VMX_EXIT_TPAUSE:
15346 * VMX_EXIT_LOADIWKEY:
15347 * These VM-exits are -not- caused unconditionally by execution of the corresponding
15348 * instruction. Any VM-exit for these instructions indicate a hardware problem,
15349 * unsupported CPU modes (like SMM) or potentially corrupt VMCS controls.
15350 *
15351 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
15352 */
15353 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15354 AssertMsgFailed(("Unexpected VM-exit %u\n", pVmxTransient->uExitReason));
15355 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
15356}
15357
15358
15359/**
15360 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
15361 */
15362HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15363{
15364 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15365
15366 /** @todo Optimize this: We currently drag in the whole MSR state
15367 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
15368 * MSRs required. That would require changes to IEM and possibly CPUM too.
15369 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
15370 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15371 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
15372 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
15373 switch (idMsr)
15374 {
15375 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
15376 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
15377 }
15378
15379 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15380 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
15381 AssertRCReturn(rc, rc);
15382
15383 Log4Func(("ecx=%#RX32\n", idMsr));
15384
15385#ifdef VBOX_STRICT
15386 Assert(!pVmxTransient->fIsNestedGuest);
15387 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
15388 {
15389 if ( hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr)
15390 && idMsr != MSR_K6_EFER)
15391 {
15392 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", idMsr));
15393 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15394 }
15395 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15396 {
15397 Assert(pVmcsInfo->pvMsrBitmap);
15398 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
15399 if (fMsrpm & VMXMSRPM_ALLOW_RD)
15400 {
15401 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", idMsr));
15402 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15403 }
15404 }
15405 }
15406#endif
15407
15408 VBOXSTRICTRC rcStrict = IEMExecDecodedRdmsr(pVCpu, pVmxTransient->cbExitInstr);
15409 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
15410 if (rcStrict == VINF_SUCCESS)
15411 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15412 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15413 {
15414 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15415 rcStrict = VINF_SUCCESS;
15416 }
15417 else
15418 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_READ || rcStrict == VINF_EM_TRIPLE_FAULT,
15419 ("Unexpected IEMExecDecodedRdmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
15420
15421 return rcStrict;
15422}
15423
15424
15425/**
15426 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
15427 */
15428HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15429{
15430 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15431
15432 /** @todo Optimize this: We currently drag in the whole MSR state
15433 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
15434 * MSRs required. That would require changes to IEM and possibly CPUM too.
15435 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
15436 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
15437 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
15438
15439 /*
15440 * The FS and GS base MSRs are not part of the above all-MSRs mask.
15441 * Although we don't need to fetch the base as it will be overwritten shortly, while
15442 * loading guest-state we would also load the entire segment register including limit
15443 * and attributes and thus we need to load them here.
15444 */
15445 switch (idMsr)
15446 {
15447 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
15448 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
15449 }
15450
15451 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15452 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15453 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
15454 AssertRCReturn(rc, rc);
15455
15456 Log4Func(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", idMsr, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.eax));
15457
15458 VBOXSTRICTRC rcStrict = IEMExecDecodedWrmsr(pVCpu, pVmxTransient->cbExitInstr);
15459 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
15460
15461 if (rcStrict == VINF_SUCCESS)
15462 {
15463 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15464
15465 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
15466 if ( idMsr == MSR_IA32_APICBASE
15467 || ( idMsr >= MSR_IA32_X2APIC_START
15468 && idMsr <= MSR_IA32_X2APIC_END))
15469 {
15470 /*
15471 * We've already saved the APIC related guest-state (TPR) in post-run phase.
15472 * When full APIC register virtualization is implemented we'll have to make
15473 * sure APIC state is saved from the VMCS before IEM changes it.
15474 */
15475 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
15476 }
15477 else if (idMsr == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
15478 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
15479 else if (idMsr == MSR_K6_EFER)
15480 {
15481 /*
15482 * If the guest touches the EFER MSR we need to update the VM-Entry and VM-Exit controls
15483 * as well, even if it is -not- touching bits that cause paging mode changes (LMA/LME).
15484 * We care about the other bits as well, SCE and NXE. See @bugref{7368}.
15485 */
15486 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
15487 }
15488
15489 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not used. */
15490 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
15491 {
15492 switch (idMsr)
15493 {
15494 case MSR_IA32_SYSENTER_CS: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
15495 case MSR_IA32_SYSENTER_EIP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
15496 case MSR_IA32_SYSENTER_ESP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
15497 case MSR_K8_FS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_FS); break;
15498 case MSR_K8_GS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_GS); break;
15499 case MSR_K6_EFER: /* Nothing to do, already handled above. */ break;
15500 default:
15501 {
15502 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15503 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_LAZY_MSRS);
15504 else if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
15505 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
15506 break;
15507 }
15508 }
15509 }
15510#ifdef VBOX_STRICT
15511 else
15512 {
15513 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
15514 switch (idMsr)
15515 {
15516 case MSR_IA32_SYSENTER_CS:
15517 case MSR_IA32_SYSENTER_EIP:
15518 case MSR_IA32_SYSENTER_ESP:
15519 case MSR_K8_FS_BASE:
15520 case MSR_K8_GS_BASE:
15521 {
15522 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", idMsr));
15523 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15524 }
15525
15526 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
15527 default:
15528 {
15529 if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
15530 {
15531 /* EFER MSR writes are always intercepted. */
15532 if (idMsr != MSR_K6_EFER)
15533 {
15534 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
15535 idMsr));
15536 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15537 }
15538 }
15539
15540 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15541 {
15542 Assert(pVmcsInfo->pvMsrBitmap);
15543 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
15544 if (fMsrpm & VMXMSRPM_ALLOW_WR)
15545 {
15546 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", idMsr));
15547 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15548 }
15549 }
15550 break;
15551 }
15552 }
15553 }
15554#endif /* VBOX_STRICT */
15555 }
15556 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15557 {
15558 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15559 rcStrict = VINF_SUCCESS;
15560 }
15561 else
15562 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_WRITE || rcStrict == VINF_EM_TRIPLE_FAULT,
15563 ("Unexpected IEMExecDecodedWrmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
15564
15565 return rcStrict;
15566}
15567
15568
15569/**
15570 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
15571 */
15572HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15573{
15574 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15575
15576 /** @todo The guest has likely hit a contended spinlock. We might want to
15577 * poke a schedule different guest VCPU. */
15578 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15579 if (RT_SUCCESS(rc))
15580 return VINF_EM_RAW_INTERRUPT;
15581
15582 AssertMsgFailed(("hmR0VmxExitPause: Failed to increment RIP. rc=%Rrc\n", rc));
15583 return rc;
15584}
15585
15586
15587/**
15588 * VM-exit handler for when the TPR value is lowered below the specified
15589 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
15590 */
15591HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15592{
15593 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15594 Assert(pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
15595
15596 /*
15597 * The TPR shadow would've been synced with the APIC TPR in the post-run phase.
15598 * We'll re-evaluate pending interrupts and inject them before the next VM
15599 * entry so we can just continue execution here.
15600 */
15601 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
15602 return VINF_SUCCESS;
15603}
15604
15605
15606/**
15607 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
15608 * VM-exit.
15609 *
15610 * @retval VINF_SUCCESS when guest execution can continue.
15611 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
15612 * @retval VERR_EM_RESCHEDULE_REM when we need to return to ring-3 due to
15613 * incompatible guest state for VMX execution (real-on-v86 case).
15614 */
15615HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15616{
15617 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15618 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
15619
15620 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15621 hmR0VmxReadExitQualVmcs(pVmxTransient);
15622 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15623
15624 VBOXSTRICTRC rcStrict;
15625 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15626 uint64_t const uExitQual = pVmxTransient->uExitQual;
15627 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(uExitQual);
15628 switch (uAccessType)
15629 {
15630 /*
15631 * MOV to CRx.
15632 */
15633 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
15634 {
15635 /*
15636 * When PAE paging is used, the CPU will reload PAE PDPTEs from CR3 when the guest
15637 * changes certain bits even in CR0, CR4 (and not just CR3). We are currently fine
15638 * since IEM_CPUMCTX_EXTRN_MUST_MASK (used below) includes CR3 which will import
15639 * PAE PDPTEs as well.
15640 */
15641 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15642 AssertRCReturn(rc, rc);
15643
15644 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
15645 uint32_t const uOldCr0 = pVCpu->cpum.GstCtx.cr0;
15646 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
15647 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
15648
15649 /*
15650 * MOV to CR3 only cause a VM-exit when one or more of the following are true:
15651 * - When nested paging isn't used.
15652 * - If the guest doesn't have paging enabled (intercept CR3 to update shadow page tables).
15653 * - We are executing in the VM debug loop.
15654 */
15655 Assert( iCrReg != 3
15656 || !pVM->hmr0.s.fNestedPaging
15657 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
15658 || pVCpu->hmr0.s.fUsingDebugLoop);
15659
15660 /* MOV to CR8 writes only cause VM-exits when TPR shadow is not used. */
15661 Assert( iCrReg != 8
15662 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
15663
15664 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
15665 AssertMsg( rcStrict == VINF_SUCCESS
15666 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15667
15668 /*
15669 * This is a kludge for handling switches back to real mode when we try to use
15670 * V86 mode to run real mode code directly. Problem is that V86 mode cannot
15671 * deal with special selector values, so we have to return to ring-3 and run
15672 * there till the selector values are V86 mode compatible.
15673 *
15674 * Note! Using VINF_EM_RESCHEDULE_REM here rather than VINF_EM_RESCHEDULE since the
15675 * latter is an alias for VINF_IEM_RAISED_XCPT which is asserted at the end of
15676 * this function.
15677 */
15678 if ( iCrReg == 0
15679 && rcStrict == VINF_SUCCESS
15680 && !pVM->hmr0.s.vmx.fUnrestrictedGuest
15681 && CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx)
15682 && (uOldCr0 & X86_CR0_PE)
15683 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
15684 {
15685 /** @todo Check selectors rather than returning all the time. */
15686 Assert(!pVmxTransient->fIsNestedGuest);
15687 Log4Func(("CR0 write, back to real mode -> VINF_EM_RESCHEDULE_REM\n"));
15688 rcStrict = VINF_EM_RESCHEDULE_REM;
15689 }
15690 break;
15691 }
15692
15693 /*
15694 * MOV from CRx.
15695 */
15696 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
15697 {
15698 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
15699 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
15700
15701 /*
15702 * MOV from CR3 only cause a VM-exit when one or more of the following are true:
15703 * - When nested paging isn't used.
15704 * - If the guest doesn't have paging enabled (pass guest's CR3 rather than our identity mapped CR3).
15705 * - We are executing in the VM debug loop.
15706 */
15707 Assert( iCrReg != 3
15708 || !pVM->hmr0.s.fNestedPaging
15709 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
15710 || pVCpu->hmr0.s.fLeaveDone);
15711
15712 /* MOV from CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
15713 Assert( iCrReg != 8
15714 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
15715
15716 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
15717 break;
15718 }
15719
15720 /*
15721 * CLTS (Clear Task-Switch Flag in CR0).
15722 */
15723 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
15724 {
15725 rcStrict = hmR0VmxExitClts(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr);
15726 break;
15727 }
15728
15729 /*
15730 * LMSW (Load Machine-Status Word into CR0).
15731 * LMSW cannot clear CR0.PE, so no fRealOnV86Active kludge needed here.
15732 */
15733 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW:
15734 {
15735 RTGCPTR GCPtrEffDst;
15736 uint8_t const cbInstr = pVmxTransient->cbExitInstr;
15737 uint16_t const uMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(uExitQual);
15738 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(uExitQual);
15739 if (fMemOperand)
15740 {
15741 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
15742 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
15743 }
15744 else
15745 GCPtrEffDst = NIL_RTGCPTR;
15746 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmcsInfo, cbInstr, uMsw, GCPtrEffDst);
15747 break;
15748 }
15749
15750 default:
15751 {
15752 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
15753 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
15754 }
15755 }
15756
15757 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS))
15758 == (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS));
15759 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15760
15761 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
15762 NOREF(pVM);
15763 return rcStrict;
15764}
15765
15766
15767/**
15768 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
15769 * VM-exit.
15770 */
15771HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15772{
15773 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15774 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
15775
15776 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15777 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15778 hmR0VmxReadExitQualVmcs(pVmxTransient);
15779 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15780 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_SREG_MASK
15781 | CPUMCTX_EXTRN_EFER);
15782 /* EFER MSR also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
15783 AssertRCReturn(rc, rc);
15784
15785 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
15786 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
15787 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
15788 bool const fIOWrite = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
15789 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
15790 bool const fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
15791 bool const fDbgStepping = pVCpu->hm.s.fSingleInstruction;
15792 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
15793
15794 /*
15795 * Update exit history to see if this exit can be optimized.
15796 */
15797 VBOXSTRICTRC rcStrict;
15798 PCEMEXITREC pExitRec = NULL;
15799 if ( !fGstStepping
15800 && !fDbgStepping)
15801 pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15802 !fIOString
15803 ? !fIOWrite
15804 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_READ)
15805 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_WRITE)
15806 : !fIOWrite
15807 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_READ)
15808 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_WRITE),
15809 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15810 if (!pExitRec)
15811 {
15812 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
15813 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving result in AL/AX/EAX. */
15814
15815 uint32_t const cbValue = s_aIOSizes[uIOSize];
15816 uint32_t const cbInstr = pVmxTransient->cbExitInstr;
15817 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
15818 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15819 if (fIOString)
15820 {
15821 /*
15822 * INS/OUTS - I/O String instruction.
15823 *
15824 * Use instruction-information if available, otherwise fall back on
15825 * interpreting the instruction.
15826 */
15827 Log4Func(("cs:rip=%#04x:%#RX64 %#06x/%u %c str\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15828 AssertReturn(pCtx->dx == uIOPort, VERR_VMX_IPE_2);
15829 bool const fInsOutsInfo = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS);
15830 if (fInsOutsInfo)
15831 {
15832 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15833 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
15834 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
15835 IEMMODE const enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
15836 bool const fRep = VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual);
15837 if (fIOWrite)
15838 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
15839 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
15840 else
15841 {
15842 /*
15843 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
15844 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
15845 * See Intel Instruction spec. for "INS".
15846 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
15847 */
15848 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
15849 }
15850 }
15851 else
15852 rcStrict = IEMExecOne(pVCpu);
15853
15854 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15855 fUpdateRipAlready = true;
15856 }
15857 else
15858 {
15859 /*
15860 * IN/OUT - I/O instruction.
15861 */
15862 Log4Func(("cs:rip=%04x:%08RX64 %#06x/%u %c\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15863 uint32_t const uAndVal = s_aIOOpAnd[uIOSize];
15864 Assert(!VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual));
15865 if (fIOWrite)
15866 {
15867 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pCtx->eax & uAndVal, cbValue);
15868 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
15869 if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15870 && !pCtx->eflags.Bits.u1TF)
15871 rcStrict = EMRZSetPendingIoPortWrite(pVCpu, uIOPort, cbInstr, cbValue, pCtx->eax & uAndVal);
15872 }
15873 else
15874 {
15875 uint32_t u32Result = 0;
15876 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
15877 if (IOM_SUCCESS(rcStrict))
15878 {
15879 /* Save result of I/O IN instr. in AL/AX/EAX. */
15880 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Result & uAndVal);
15881 }
15882 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15883 && !pCtx->eflags.Bits.u1TF)
15884 rcStrict = EMRZSetPendingIoPortRead(pVCpu, uIOPort, cbInstr, cbValue);
15885 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
15886 }
15887 }
15888
15889 if (IOM_SUCCESS(rcStrict))
15890 {
15891 if (!fUpdateRipAlready)
15892 {
15893 hmR0VmxAdvanceGuestRipBy(pVCpu, cbInstr);
15894 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15895 }
15896
15897 /*
15898 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru
15899 * while booting Fedora 17 64-bit guest.
15900 *
15901 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
15902 */
15903 if (fIOString)
15904 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RFLAGS);
15905
15906 /*
15907 * If any I/O breakpoints are armed, we need to check if one triggered
15908 * and take appropriate action.
15909 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
15910 */
15911 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_DR7);
15912 AssertRCReturn(rc, rc);
15913
15914 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
15915 * execution engines about whether hyper BPs and such are pending. */
15916 uint32_t const uDr7 = pCtx->dr[7];
15917 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
15918 && X86_DR7_ANY_RW_IO(uDr7)
15919 && (pCtx->cr4 & X86_CR4_DE))
15920 || DBGFBpIsHwIoArmed(pVM)))
15921 {
15922 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
15923
15924 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
15925 VMMRZCallRing3Disable(pVCpu);
15926 HM_DISABLE_PREEMPT(pVCpu);
15927
15928 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
15929
15930 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, uIOPort, cbValue);
15931 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
15932 {
15933 /* Raise #DB. */
15934 if (fIsGuestDbgActive)
15935 ASMSetDR6(pCtx->dr[6]);
15936 if (pCtx->dr[7] != uDr7)
15937 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_DR7;
15938
15939 hmR0VmxSetPendingXcptDB(pVCpu);
15940 }
15941 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
15942 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
15943 else if ( rcStrict2 != VINF_SUCCESS
15944 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
15945 rcStrict = rcStrict2;
15946 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
15947
15948 HM_RESTORE_PREEMPT();
15949 VMMRZCallRing3Enable(pVCpu);
15950 }
15951 }
15952
15953#ifdef VBOX_STRICT
15954 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15955 || rcStrict == VINF_EM_PENDING_R3_IOPORT_READ)
15956 Assert(!fIOWrite);
15957 else if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15958 || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
15959 || rcStrict == VINF_EM_PENDING_R3_IOPORT_WRITE)
15960 Assert(fIOWrite);
15961 else
15962 {
15963# if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
15964 * statuses, that the VMM device and some others may return. See
15965 * IOM_SUCCESS() for guidance. */
15966 AssertMsg( RT_FAILURE(rcStrict)
15967 || rcStrict == VINF_SUCCESS
15968 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
15969 || rcStrict == VINF_EM_DBG_BREAKPOINT
15970 || rcStrict == VINF_EM_RAW_GUEST_TRAP
15971 || rcStrict == VINF_EM_RAW_TO_R3
15972 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15973# endif
15974 }
15975#endif
15976 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
15977 }
15978 else
15979 {
15980 /*
15981 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
15982 */
15983 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15984 AssertRCReturn(rc2, rc2);
15985 STAM_COUNTER_INC(!fIOString ? fIOWrite ? &pVCpu->hm.s.StatExitIOWrite : &pVCpu->hm.s.StatExitIORead
15986 : fIOWrite ? &pVCpu->hm.s.StatExitIOStringWrite : &pVCpu->hm.s.StatExitIOStringRead);
15987 Log4(("IOExit/%u: %04x:%08RX64: %s%s%s %#x LB %u -> EMHistoryExec\n",
15988 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15989 VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual) ? "REP " : "",
15990 fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOSize));
15991
15992 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15993 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15994
15995 Log4(("IOExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15996 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15997 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15998 }
15999 return rcStrict;
16000}
16001
16002
16003/**
16004 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
16005 * VM-exit.
16006 */
16007HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16008{
16009 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16010
16011 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
16012 hmR0VmxReadExitQualVmcs(pVmxTransient);
16013 if (VMX_EXIT_QUAL_TASK_SWITCH_TYPE(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT)
16014 {
16015 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16016 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
16017 {
16018 uint32_t uErrCode;
16019 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uIdtVectoringInfo))
16020 {
16021 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16022 uErrCode = pVmxTransient->uIdtVectoringErrorCode;
16023 }
16024 else
16025 uErrCode = 0;
16026
16027 RTGCUINTPTR GCPtrFaultAddress;
16028 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(pVmxTransient->uIdtVectoringInfo))
16029 GCPtrFaultAddress = pVCpu->cpum.GstCtx.cr2;
16030 else
16031 GCPtrFaultAddress = 0;
16032
16033 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16034
16035 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
16036 pVmxTransient->cbExitInstr, uErrCode, GCPtrFaultAddress);
16037
16038 Log4Func(("Pending event. uIntType=%#x uVector=%#x\n", VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo),
16039 VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo)));
16040 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
16041 return VINF_EM_RAW_INJECT_TRPM_EVENT;
16042 }
16043 }
16044
16045 /* Fall back to the interpreter to emulate the task-switch. */
16046 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
16047 return VERR_EM_INTERPRETER;
16048}
16049
16050
16051/**
16052 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
16053 */
16054HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16055{
16056 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16057
16058 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16059 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
16060 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
16061 AssertRC(rc);
16062 return VINF_EM_DBG_STEPPED;
16063}
16064
16065
16066/**
16067 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
16068 */
16069HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16070{
16071 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16072 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
16073
16074 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16075 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16076 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16077 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16078 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16079
16080 /*
16081 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
16082 */
16083 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
16084 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16085 {
16086 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
16087 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
16088 {
16089 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
16090 return VINF_EM_RAW_INJECT_TRPM_EVENT;
16091 }
16092 }
16093 else
16094 {
16095 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
16096 return rcStrict;
16097 }
16098
16099 /* IOMMIOPhysHandler() below may call into IEM, save the necessary state. */
16100 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16101 hmR0VmxReadExitQualVmcs(pVmxTransient);
16102 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
16103 AssertRCReturn(rc, rc);
16104
16105 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
16106 uint32_t const uAccessType = VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual);
16107 switch (uAccessType)
16108 {
16109 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
16110 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
16111 {
16112 AssertMsg( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
16113 || VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual) != XAPIC_OFF_TPR,
16114 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
16115
16116 RTGCPHYS GCPhys = pVCpu->hm.s.vmx.u64GstMsrApicBase; /* Always up-to-date, as it is not part of the VMCS. */
16117 GCPhys &= PAGE_BASE_GC_MASK;
16118 GCPhys += VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual);
16119 Log4Func(("Linear access uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
16120 VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual)));
16121
16122 rcStrict = IOMR0MmioPhysHandler(pVCpu->CTX_SUFF(pVM), pVCpu,
16123 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW, GCPhys);
16124 Log4Func(("IOMMMIOPhysHandler returned %Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
16125 if ( rcStrict == VINF_SUCCESS
16126 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
16127 || rcStrict == VERR_PAGE_NOT_PRESENT)
16128 {
16129 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
16130 | HM_CHANGED_GUEST_APIC_TPR);
16131 rcStrict = VINF_SUCCESS;
16132 }
16133 break;
16134 }
16135
16136 default:
16137 {
16138 Log4Func(("uAccessType=%#x\n", uAccessType));
16139 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
16140 break;
16141 }
16142 }
16143
16144 if (rcStrict != VINF_SUCCESS)
16145 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
16146 return rcStrict;
16147}
16148
16149
16150/**
16151 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
16152 * VM-exit.
16153 */
16154HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16155{
16156 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16157 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16158
16159 /*
16160 * We might also get this VM-exit if the nested-guest isn't intercepting MOV DRx accesses.
16161 * In such a case, rather than disabling MOV DRx intercepts and resuming execution, we
16162 * must emulate the MOV DRx access.
16163 */
16164 if (!pVmxTransient->fIsNestedGuest)
16165 {
16166 /* We should -not- get this VM-exit if the guest's debug registers were active. */
16167 if (pVmxTransient->fWasGuestDebugStateActive)
16168 {
16169 AssertMsgFailed(("Unexpected MOV DRx exit\n"));
16170 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
16171 }
16172
16173 if ( !pVCpu->hm.s.fSingleInstruction
16174 && !pVmxTransient->fWasHyperDebugStateActive)
16175 {
16176 Assert(!DBGFIsStepping(pVCpu));
16177 Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB));
16178
16179 /* Don't intercept MOV DRx any more. */
16180 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
16181 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
16182 AssertRC(rc);
16183
16184 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
16185 VMMRZCallRing3Disable(pVCpu);
16186 HM_DISABLE_PREEMPT(pVCpu);
16187
16188 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
16189 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
16190 Assert(CPUMIsGuestDebugStateActive(pVCpu));
16191
16192 HM_RESTORE_PREEMPT();
16193 VMMRZCallRing3Enable(pVCpu);
16194
16195#ifdef VBOX_WITH_STATISTICS
16196 hmR0VmxReadExitQualVmcs(pVmxTransient);
16197 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
16198 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
16199 else
16200 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
16201#endif
16202 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
16203 return VINF_SUCCESS;
16204 }
16205 }
16206
16207 /*
16208 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER MSR, CS.
16209 * The EFER MSR is always up-to-date.
16210 * Update the segment registers and DR7 from the CPU.
16211 */
16212 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16213 hmR0VmxReadExitQualVmcs(pVmxTransient);
16214 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_DR7);
16215 AssertRCReturn(rc, rc);
16216 Log4Func(("cs:rip=%#04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
16217
16218 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16219 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
16220 {
16221 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pCtx),
16222 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual),
16223 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual));
16224 if (RT_SUCCESS(rc))
16225 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
16226 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
16227 }
16228 else
16229 {
16230 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pCtx),
16231 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual),
16232 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual));
16233 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
16234 }
16235
16236 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
16237 if (RT_SUCCESS(rc))
16238 {
16239 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
16240 AssertRCReturn(rc2, rc2);
16241 return VINF_SUCCESS;
16242 }
16243 return rc;
16244}
16245
16246
16247/**
16248 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
16249 * Conditional VM-exit.
16250 */
16251HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16252{
16253 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16254 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
16255
16256 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16257 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16258 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16259 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16260 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16261
16262 /*
16263 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
16264 */
16265 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
16266 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16267 {
16268 /*
16269 * In the unlikely case where delivering an event causes an EPT misconfig (MMIO), go back to
16270 * instruction emulation to inject the original event. Otherwise, injecting the original event
16271 * using hardware-assisted VMX would trigger the same EPT misconfig VM-exit again.
16272 */
16273 if (!pVCpu->hm.s.Event.fPending)
16274 { /* likely */ }
16275 else
16276 {
16277 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
16278#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16279 /** @todo NSTVMX: Think about how this should be handled. */
16280 if (pVmxTransient->fIsNestedGuest)
16281 return VERR_VMX_IPE_3;
16282#endif
16283 return VINF_EM_RAW_INJECT_TRPM_EVENT;
16284 }
16285 }
16286 else
16287 {
16288 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
16289 return rcStrict;
16290 }
16291
16292 /*
16293 * Get sufficient state and update the exit history entry.
16294 */
16295 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16296 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
16297 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
16298 AssertRCReturn(rc, rc);
16299
16300 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
16301 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
16302 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_MMIO),
16303 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
16304 if (!pExitRec)
16305 {
16306 /*
16307 * If we succeed, resume guest execution.
16308 * If we fail in interpreting the instruction because we couldn't get the guest physical address
16309 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
16310 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
16311 * weird case. See @bugref{6043}.
16312 */
16313 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16314 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16315/** @todo bird: We can probably just go straight to IOM here and assume that
16316 * it's MMIO, then fall back on PGM if that hunch didn't work out so
16317 * well. However, we need to address that aliasing workarounds that
16318 * PGMR0Trap0eHandlerNPMisconfig implements. So, some care is needed.
16319 *
16320 * Might also be interesting to see if we can get this done more or
16321 * less locklessly inside IOM. Need to consider the lookup table
16322 * updating and use a bit more carefully first (or do all updates via
16323 * rendezvous) */
16324 rcStrict = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pCtx), GCPhys, UINT32_MAX);
16325 Log4Func(("At %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pCtx->rip, VBOXSTRICTRC_VAL(rcStrict)));
16326 if ( rcStrict == VINF_SUCCESS
16327 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
16328 || rcStrict == VERR_PAGE_NOT_PRESENT)
16329 {
16330 /* Successfully handled MMIO operation. */
16331 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
16332 | HM_CHANGED_GUEST_APIC_TPR);
16333 rcStrict = VINF_SUCCESS;
16334 }
16335 }
16336 else
16337 {
16338 /*
16339 * Frequent exit or something needing probing. Call EMHistoryExec.
16340 */
16341 Log4(("EptMisscfgExit/%u: %04x:%08RX64: %RGp -> EMHistoryExec\n",
16342 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPhys));
16343
16344 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
16345 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16346
16347 Log4(("EptMisscfgExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
16348 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
16349 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
16350 }
16351 return rcStrict;
16352}
16353
16354
16355/**
16356 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
16357 * VM-exit.
16358 */
16359HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16360{
16361 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16362 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
16363
16364 hmR0VmxReadExitQualVmcs(pVmxTransient);
16365 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16366 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16367 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16368 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16369 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16370
16371 /*
16372 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
16373 */
16374 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
16375 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16376 {
16377 /*
16378 * If delivery of an event causes an EPT violation (true nested #PF and not MMIO),
16379 * we shall resolve the nested #PF and re-inject the original event.
16380 */
16381 if (pVCpu->hm.s.Event.fPending)
16382 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflectNPF);
16383 }
16384 else
16385 {
16386 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
16387 return rcStrict;
16388 }
16389
16390 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16391 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
16392 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
16393 AssertRCReturn(rc, rc);
16394
16395 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
16396 uint64_t const uExitQual = pVmxTransient->uExitQual;
16397 AssertMsg(((pVmxTransient->uExitQual >> 7) & 3) != 2, ("%#RX64", uExitQual));
16398
16399 RTGCUINT uErrorCode = 0;
16400 if (uExitQual & VMX_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH)
16401 uErrorCode |= X86_TRAP_PF_ID;
16402 if (uExitQual & VMX_EXIT_QUAL_EPT_ACCESS_WRITE)
16403 uErrorCode |= X86_TRAP_PF_RW;
16404 if (uExitQual & (VMX_EXIT_QUAL_EPT_ENTRY_READ | VMX_EXIT_QUAL_EPT_ENTRY_WRITE | VMX_EXIT_QUAL_EPT_ENTRY_EXECUTE))
16405 uErrorCode |= X86_TRAP_PF_P;
16406
16407 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16408 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16409 Log4Func(("at %#RX64 (%#RX64 errcode=%#x) cs:rip=%#04x:%#RX64\n", GCPhys, uExitQual, uErrorCode, pCtx->cs.Sel, pCtx->rip));
16410
16411 /*
16412 * Handle the pagefault trap for the nested shadow table.
16413 */
16414 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
16415 rcStrict = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pCtx), GCPhys);
16416 TRPMResetTrap(pVCpu);
16417
16418 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
16419 if ( rcStrict == VINF_SUCCESS
16420 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
16421 || rcStrict == VERR_PAGE_NOT_PRESENT)
16422 {
16423 /* Successfully synced our nested page tables. */
16424 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
16425 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS);
16426 return VINF_SUCCESS;
16427 }
16428
16429 Log4Func(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
16430 return rcStrict;
16431}
16432
16433
16434#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16435/**
16436 * VM-exit handler for VMCLEAR (VMX_EXIT_VMCLEAR). Unconditional VM-exit.
16437 */
16438HMVMX_EXIT_DECL hmR0VmxExitVmclear(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16439{
16440 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16441
16442 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16443 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16444 hmR0VmxReadExitQualVmcs(pVmxTransient);
16445 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16446 | CPUMCTX_EXTRN_HWVIRT
16447 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16448 AssertRCReturn(rc, rc);
16449
16450 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16451
16452 VMXVEXITINFO ExitInfo;
16453 RT_ZERO(ExitInfo);
16454 ExitInfo.uReason = pVmxTransient->uExitReason;
16455 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16456 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16457 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16458 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16459
16460 VBOXSTRICTRC rcStrict = IEMExecDecodedVmclear(pVCpu, &ExitInfo);
16461 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16462 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16463 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16464 {
16465 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16466 rcStrict = VINF_SUCCESS;
16467 }
16468 return rcStrict;
16469}
16470
16471
16472/**
16473 * VM-exit handler for VMLAUNCH (VMX_EXIT_VMLAUNCH). Unconditional VM-exit.
16474 */
16475HMVMX_EXIT_DECL hmR0VmxExitVmlaunch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16476{
16477 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16478
16479 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMLAUNCH,
16480 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
16481 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16482 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16483 AssertRCReturn(rc, rc);
16484
16485 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16486
16487 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
16488 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMLAUNCH);
16489 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
16490 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16491 {
16492 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16493 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
16494 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
16495 }
16496 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
16497 return rcStrict;
16498}
16499
16500
16501/**
16502 * VM-exit handler for VMPTRLD (VMX_EXIT_VMPTRLD). Unconditional VM-exit.
16503 */
16504HMVMX_EXIT_DECL hmR0VmxExitVmptrld(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16505{
16506 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16507
16508 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16509 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16510 hmR0VmxReadExitQualVmcs(pVmxTransient);
16511 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16512 | CPUMCTX_EXTRN_HWVIRT
16513 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16514 AssertRCReturn(rc, rc);
16515
16516 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16517
16518 VMXVEXITINFO ExitInfo;
16519 RT_ZERO(ExitInfo);
16520 ExitInfo.uReason = pVmxTransient->uExitReason;
16521 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16522 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16523 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16524 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16525
16526 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrld(pVCpu, &ExitInfo);
16527 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16528 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16529 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16530 {
16531 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16532 rcStrict = VINF_SUCCESS;
16533 }
16534 return rcStrict;
16535}
16536
16537
16538/**
16539 * VM-exit handler for VMPTRST (VMX_EXIT_VMPTRST). Unconditional VM-exit.
16540 */
16541HMVMX_EXIT_DECL hmR0VmxExitVmptrst(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16542{
16543 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16544
16545 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16546 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16547 hmR0VmxReadExitQualVmcs(pVmxTransient);
16548 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16549 | CPUMCTX_EXTRN_HWVIRT
16550 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16551 AssertRCReturn(rc, rc);
16552
16553 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16554
16555 VMXVEXITINFO ExitInfo;
16556 RT_ZERO(ExitInfo);
16557 ExitInfo.uReason = pVmxTransient->uExitReason;
16558 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16559 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16560 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16561 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
16562
16563 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrst(pVCpu, &ExitInfo);
16564 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16565 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16566 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16567 {
16568 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16569 rcStrict = VINF_SUCCESS;
16570 }
16571 return rcStrict;
16572}
16573
16574
16575/**
16576 * VM-exit handler for VMREAD (VMX_EXIT_VMREAD). Conditional VM-exit.
16577 */
16578HMVMX_EXIT_DECL hmR0VmxExitVmread(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16579{
16580 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16581
16582 /*
16583 * Strictly speaking we should not get VMREAD VM-exits for shadow VMCS fields and
16584 * thus might not need to import the shadow VMCS state, it's safer just in case
16585 * code elsewhere dares look at unsynced VMCS fields.
16586 */
16587 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16588 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16589 hmR0VmxReadExitQualVmcs(pVmxTransient);
16590 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16591 | CPUMCTX_EXTRN_HWVIRT
16592 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16593 AssertRCReturn(rc, rc);
16594
16595 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16596
16597 VMXVEXITINFO ExitInfo;
16598 RT_ZERO(ExitInfo);
16599 ExitInfo.uReason = pVmxTransient->uExitReason;
16600 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16601 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16602 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16603 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
16604 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
16605
16606 VBOXSTRICTRC rcStrict = IEMExecDecodedVmread(pVCpu, &ExitInfo);
16607 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16608 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16609 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16610 {
16611 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16612 rcStrict = VINF_SUCCESS;
16613 }
16614 return rcStrict;
16615}
16616
16617
16618/**
16619 * VM-exit handler for VMRESUME (VMX_EXIT_VMRESUME). Unconditional VM-exit.
16620 */
16621HMVMX_EXIT_DECL hmR0VmxExitVmresume(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16622{
16623 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16624
16625 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMRESUME,
16626 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
16627 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16628 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16629 AssertRCReturn(rc, rc);
16630
16631 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16632
16633 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
16634 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMRESUME);
16635 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
16636 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16637 {
16638 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16639 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
16640 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
16641 }
16642 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
16643 return rcStrict;
16644}
16645
16646
16647/**
16648 * VM-exit handler for VMWRITE (VMX_EXIT_VMWRITE). Conditional VM-exit.
16649 */
16650HMVMX_EXIT_DECL hmR0VmxExitVmwrite(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16651{
16652 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16653
16654 /*
16655 * Although we should not get VMWRITE VM-exits for shadow VMCS fields, since our HM hook
16656 * gets invoked when IEM's VMWRITE instruction emulation modifies the current VMCS and it
16657 * flags re-loading the entire shadow VMCS, we should save the entire shadow VMCS here.
16658 */
16659 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16660 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16661 hmR0VmxReadExitQualVmcs(pVmxTransient);
16662 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16663 | CPUMCTX_EXTRN_HWVIRT
16664 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16665 AssertRCReturn(rc, rc);
16666
16667 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16668
16669 VMXVEXITINFO ExitInfo;
16670 RT_ZERO(ExitInfo);
16671 ExitInfo.uReason = pVmxTransient->uExitReason;
16672 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16673 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16674 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16675 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
16676 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16677
16678 VBOXSTRICTRC rcStrict = IEMExecDecodedVmwrite(pVCpu, &ExitInfo);
16679 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16680 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16681 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16682 {
16683 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16684 rcStrict = VINF_SUCCESS;
16685 }
16686 return rcStrict;
16687}
16688
16689
16690/**
16691 * VM-exit handler for VMXOFF (VMX_EXIT_VMXOFF). Unconditional VM-exit.
16692 */
16693HMVMX_EXIT_DECL hmR0VmxExitVmxoff(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16694{
16695 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16696
16697 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16698 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR4
16699 | CPUMCTX_EXTRN_HWVIRT
16700 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
16701 AssertRCReturn(rc, rc);
16702
16703 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16704
16705 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxoff(pVCpu, pVmxTransient->cbExitInstr);
16706 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16707 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_HWVIRT);
16708 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16709 {
16710 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16711 rcStrict = VINF_SUCCESS;
16712 }
16713 return rcStrict;
16714}
16715
16716
16717/**
16718 * VM-exit handler for VMXON (VMX_EXIT_VMXON). Unconditional VM-exit.
16719 */
16720HMVMX_EXIT_DECL hmR0VmxExitVmxon(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16721{
16722 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16723
16724 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16725 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16726 hmR0VmxReadExitQualVmcs(pVmxTransient);
16727 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16728 | CPUMCTX_EXTRN_HWVIRT
16729 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16730 AssertRCReturn(rc, rc);
16731
16732 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16733
16734 VMXVEXITINFO ExitInfo;
16735 RT_ZERO(ExitInfo);
16736 ExitInfo.uReason = pVmxTransient->uExitReason;
16737 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16738 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16739 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16740 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16741
16742 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxon(pVCpu, &ExitInfo);
16743 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16744 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16745 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16746 {
16747 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16748 rcStrict = VINF_SUCCESS;
16749 }
16750 return rcStrict;
16751}
16752
16753
16754/**
16755 * VM-exit handler for INVVPID (VMX_EXIT_INVVPID). Unconditional VM-exit.
16756 */
16757HMVMX_EXIT_DECL hmR0VmxExitInvvpid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16758{
16759 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16760
16761 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16762 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16763 hmR0VmxReadExitQualVmcs(pVmxTransient);
16764 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16765 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16766 AssertRCReturn(rc, rc);
16767
16768 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16769
16770 VMXVEXITINFO ExitInfo;
16771 RT_ZERO(ExitInfo);
16772 ExitInfo.uReason = pVmxTransient->uExitReason;
16773 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16774 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16775 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16776 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16777
16778 VBOXSTRICTRC rcStrict = IEMExecDecodedInvvpid(pVCpu, &ExitInfo);
16779 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16780 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16781 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16782 {
16783 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16784 rcStrict = VINF_SUCCESS;
16785 }
16786 return rcStrict;
16787}
16788#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16789/** @} */
16790
16791
16792#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16793/** @name Nested-guest VM-exit handlers.
16794 * @{
16795 */
16796/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16797/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Nested-guest VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16798/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16799
16800/**
16801 * Nested-guest VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
16802 * Conditional VM-exit.
16803 */
16804HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16805{
16806 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16807
16808 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16809
16810 uint64_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
16811 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
16812 Assert(VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo));
16813
16814 switch (uExitIntType)
16815 {
16816 /*
16817 * Physical NMIs:
16818 * We shouldn't direct host physical NMIs to the nested-guest. Dispatch it to the host.
16819 */
16820 case VMX_EXIT_INT_INFO_TYPE_NMI:
16821 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
16822
16823 /*
16824 * Hardware exceptions,
16825 * Software exceptions,
16826 * Privileged software exceptions:
16827 * Figure out if the exception must be delivered to the guest or the nested-guest.
16828 */
16829 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
16830 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
16831 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
16832 {
16833 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16834 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16835 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16836 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16837
16838 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16839 bool const fIntercept = CPUMIsGuestVmxXcptInterceptSet(pCtx, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo),
16840 pVmxTransient->uExitIntErrorCode);
16841 if (fIntercept)
16842 {
16843 /* Exit qualification is required for debug and page-fault exceptions. */
16844 hmR0VmxReadExitQualVmcs(pVmxTransient);
16845
16846 /*
16847 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged
16848 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
16849 * length. However, if delivery of a software interrupt, software exception or privileged
16850 * software exception causes a VM-exit, that too provides the VM-exit instruction length.
16851 */
16852 VMXVEXITINFO ExitInfo;
16853 RT_ZERO(ExitInfo);
16854 ExitInfo.uReason = pVmxTransient->uExitReason;
16855 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16856 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16857
16858 VMXVEXITEVENTINFO ExitEventInfo;
16859 RT_ZERO(ExitEventInfo);
16860 ExitEventInfo.uExitIntInfo = pVmxTransient->uExitIntInfo;
16861 ExitEventInfo.uExitIntErrCode = pVmxTransient->uExitIntErrorCode;
16862 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16863 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16864
16865#ifdef DEBUG_ramshankar
16866 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16867 Log4Func(("exit_int_info=%#RX32 err_code=%#RX32 exit_qual=%#RX64\n", pVmxTransient->uExitIntInfo,
16868 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual));
16869 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
16870 {
16871 Log4Func(("idt_info=%#RX32 idt_errcode=%#RX32 cr2=%#RX64\n", pVmxTransient->uIdtVectoringInfo,
16872 pVmxTransient->uIdtVectoringErrorCode, pCtx->cr2));
16873 }
16874#endif
16875 return IEMExecVmxVmexitXcpt(pVCpu, &ExitInfo, &ExitEventInfo);
16876 }
16877
16878 /* Nested paging is currently a requirement, otherwise we would need to handle shadow #PFs in hmR0VmxExitXcptPF. */
16879 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
16880 return hmR0VmxExitXcpt(pVCpu, pVmxTransient);
16881 }
16882
16883 /*
16884 * Software interrupts:
16885 * VM-exits cannot be caused by software interrupts.
16886 *
16887 * External interrupts:
16888 * This should only happen when "acknowledge external interrupts on VM-exit"
16889 * control is set. However, we never set this when executing a guest or
16890 * nested-guest. For nested-guests it is emulated while injecting interrupts into
16891 * the guest.
16892 */
16893 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
16894 case VMX_EXIT_INT_INFO_TYPE_EXT_INT:
16895 default:
16896 {
16897 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
16898 return VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
16899 }
16900 }
16901}
16902
16903
16904/**
16905 * Nested-guest VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT).
16906 * Unconditional VM-exit.
16907 */
16908HMVMX_EXIT_DECL hmR0VmxExitTripleFaultNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16909{
16910 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16911 return IEMExecVmxVmexitTripleFault(pVCpu);
16912}
16913
16914
16915/**
16916 * Nested-guest VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
16917 */
16918HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16919{
16920 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16921
16922 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
16923 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16924 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16925}
16926
16927
16928/**
16929 * Nested-guest VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
16930 */
16931HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16932{
16933 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16934
16935 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT))
16936 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16937 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16938}
16939
16940
16941/**
16942 * Nested-guest VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH).
16943 * Unconditional VM-exit.
16944 */
16945HMVMX_EXIT_DECL hmR0VmxExitTaskSwitchNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16946{
16947 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16948
16949 hmR0VmxReadExitQualVmcs(pVmxTransient);
16950 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16951 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16952 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16953
16954 VMXVEXITINFO ExitInfo;
16955 RT_ZERO(ExitInfo);
16956 ExitInfo.uReason = pVmxTransient->uExitReason;
16957 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16958 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16959
16960 VMXVEXITEVENTINFO ExitEventInfo;
16961 RT_ZERO(ExitEventInfo);
16962 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16963 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16964 return IEMExecVmxVmexitTaskSwitch(pVCpu, &ExitInfo, &ExitEventInfo);
16965}
16966
16967
16968/**
16969 * Nested-guest VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
16970 */
16971HMVMX_EXIT_DECL hmR0VmxExitHltNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16972{
16973 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16974
16975 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_HLT_EXIT))
16976 {
16977 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16978 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16979 }
16980 return hmR0VmxExitHlt(pVCpu, pVmxTransient);
16981}
16982
16983
16984/**
16985 * Nested-guest VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
16986 */
16987HMVMX_EXIT_DECL hmR0VmxExitInvlpgNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16988{
16989 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16990
16991 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16992 {
16993 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16994 hmR0VmxReadExitQualVmcs(pVmxTransient);
16995
16996 VMXVEXITINFO ExitInfo;
16997 RT_ZERO(ExitInfo);
16998 ExitInfo.uReason = pVmxTransient->uExitReason;
16999 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17000 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17001 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17002 }
17003 return hmR0VmxExitInvlpg(pVCpu, pVmxTransient);
17004}
17005
17006
17007/**
17008 * Nested-guest VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
17009 */
17010HMVMX_EXIT_DECL hmR0VmxExitRdpmcNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17011{
17012 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17013
17014 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDPMC_EXIT))
17015 {
17016 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17017 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17018 }
17019 return hmR0VmxExitRdpmc(pVCpu, pVmxTransient);
17020}
17021
17022
17023/**
17024 * Nested-guest VM-exit handler for VMREAD (VMX_EXIT_VMREAD) and VMWRITE
17025 * (VMX_EXIT_VMWRITE). Conditional VM-exit.
17026 */
17027HMVMX_EXIT_DECL hmR0VmxExitVmreadVmwriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17028{
17029 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17030
17031 Assert( pVmxTransient->uExitReason == VMX_EXIT_VMREAD
17032 || pVmxTransient->uExitReason == VMX_EXIT_VMWRITE);
17033
17034 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17035
17036 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
17037 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
17038 uint64_t u64VmcsField = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
17039
17040 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
17041 if (!CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
17042 u64VmcsField &= UINT64_C(0xffffffff);
17043
17044 if (CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, pVmxTransient->uExitReason, u64VmcsField))
17045 {
17046 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17047 hmR0VmxReadExitQualVmcs(pVmxTransient);
17048
17049 VMXVEXITINFO ExitInfo;
17050 RT_ZERO(ExitInfo);
17051 ExitInfo.uReason = pVmxTransient->uExitReason;
17052 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17053 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17054 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17055 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17056 }
17057
17058 if (pVmxTransient->uExitReason == VMX_EXIT_VMREAD)
17059 return hmR0VmxExitVmread(pVCpu, pVmxTransient);
17060 return hmR0VmxExitVmwrite(pVCpu, pVmxTransient);
17061}
17062
17063
17064/**
17065 * Nested-guest VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
17066 */
17067HMVMX_EXIT_DECL hmR0VmxExitRdtscNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17068{
17069 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17070
17071 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
17072 {
17073 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17074 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17075 }
17076
17077 return hmR0VmxExitRdtsc(pVCpu, pVmxTransient);
17078}
17079
17080
17081/**
17082 * Nested-guest VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX).
17083 * Conditional VM-exit.
17084 */
17085HMVMX_EXIT_DECL hmR0VmxExitMovCRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17086{
17087 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17088
17089 hmR0VmxReadExitQualVmcs(pVmxTransient);
17090 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17091
17092 VBOXSTRICTRC rcStrict;
17093 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual);
17094 switch (uAccessType)
17095 {
17096 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
17097 {
17098 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
17099 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
17100 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
17101 uint64_t const uNewCrX = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
17102
17103 bool fIntercept;
17104 switch (iCrReg)
17105 {
17106 case 0:
17107 case 4:
17108 fIntercept = CPUMIsGuestVmxMovToCr0Cr4InterceptSet(&pVCpu->cpum.GstCtx, iCrReg, uNewCrX);
17109 break;
17110
17111 case 3:
17112 fIntercept = CPUMIsGuestVmxMovToCr3InterceptSet(pVCpu, uNewCrX);
17113 break;
17114
17115 case 8:
17116 fIntercept = CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_CR8_LOAD_EXIT);
17117 break;
17118
17119 default:
17120 fIntercept = false;
17121 break;
17122 }
17123 if (fIntercept)
17124 {
17125 VMXVEXITINFO ExitInfo;
17126 RT_ZERO(ExitInfo);
17127 ExitInfo.uReason = pVmxTransient->uExitReason;
17128 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17129 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17130 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17131 }
17132 else
17133 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
17134 break;
17135 }
17136
17137 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
17138 {
17139 /*
17140 * CR0/CR4 reads do not cause VM-exits, the read-shadow is used (subject to masking).
17141 * CR2 reads do not cause a VM-exit.
17142 * CR3 reads cause a VM-exit depending on the "CR3 store exiting" control.
17143 * CR8 reads cause a VM-exit depending on the "CR8 store exiting" control.
17144 */
17145 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
17146 if ( iCrReg == 3
17147 || iCrReg == 8)
17148 {
17149 static const uint32_t s_auCrXReadIntercepts[] = { 0, 0, 0, VMX_PROC_CTLS_CR3_STORE_EXIT, 0,
17150 0, 0, 0, VMX_PROC_CTLS_CR8_STORE_EXIT };
17151 uint32_t const uIntercept = s_auCrXReadIntercepts[iCrReg];
17152 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, uIntercept))
17153 {
17154 VMXVEXITINFO ExitInfo;
17155 RT_ZERO(ExitInfo);
17156 ExitInfo.uReason = pVmxTransient->uExitReason;
17157 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17158 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17159 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17160 }
17161 else
17162 {
17163 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
17164 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
17165 }
17166 }
17167 else
17168 {
17169 AssertMsgFailed(("MOV from CR%d VM-exit must not happen\n", iCrReg));
17170 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, iCrReg);
17171 }
17172 break;
17173 }
17174
17175 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
17176 {
17177 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
17178 Assert(pVmcsNstGst);
17179 uint64_t const uGstHostMask = pVmcsNstGst->u64Cr0Mask.u;
17180 uint64_t const uReadShadow = pVmcsNstGst->u64Cr0ReadShadow.u;
17181 if ( (uGstHostMask & X86_CR0_TS)
17182 && (uReadShadow & X86_CR0_TS))
17183 {
17184 VMXVEXITINFO ExitInfo;
17185 RT_ZERO(ExitInfo);
17186 ExitInfo.uReason = pVmxTransient->uExitReason;
17187 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17188 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17189 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17190 }
17191 else
17192 rcStrict = hmR0VmxExitClts(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr);
17193 break;
17194 }
17195
17196 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
17197 {
17198 RTGCPTR GCPtrEffDst;
17199 uint16_t const uNewMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(pVmxTransient->uExitQual);
17200 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(pVmxTransient->uExitQual);
17201 if (fMemOperand)
17202 {
17203 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
17204 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
17205 }
17206 else
17207 GCPtrEffDst = NIL_RTGCPTR;
17208
17209 if (CPUMIsGuestVmxLmswInterceptSet(&pVCpu->cpum.GstCtx, uNewMsw))
17210 {
17211 VMXVEXITINFO ExitInfo;
17212 RT_ZERO(ExitInfo);
17213 ExitInfo.uReason = pVmxTransient->uExitReason;
17214 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17215 ExitInfo.u64GuestLinearAddr = GCPtrEffDst;
17216 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17217 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17218 }
17219 else
17220 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, uNewMsw, GCPtrEffDst);
17221 break;
17222 }
17223
17224 default:
17225 {
17226 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
17227 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
17228 }
17229 }
17230
17231 if (rcStrict == VINF_IEM_RAISED_XCPT)
17232 {
17233 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
17234 rcStrict = VINF_SUCCESS;
17235 }
17236 return rcStrict;
17237}
17238
17239
17240/**
17241 * Nested-guest VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX).
17242 * Conditional VM-exit.
17243 */
17244HMVMX_EXIT_DECL hmR0VmxExitMovDRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17245{
17246 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17247
17248 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MOV_DR_EXIT))
17249 {
17250 hmR0VmxReadExitQualVmcs(pVmxTransient);
17251 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17252
17253 VMXVEXITINFO ExitInfo;
17254 RT_ZERO(ExitInfo);
17255 ExitInfo.uReason = pVmxTransient->uExitReason;
17256 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17257 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17258 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17259 }
17260 return hmR0VmxExitMovDRx(pVCpu, pVmxTransient);
17261}
17262
17263
17264/**
17265 * Nested-guest VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR).
17266 * Conditional VM-exit.
17267 */
17268HMVMX_EXIT_DECL hmR0VmxExitIoInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17269{
17270 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17271
17272 hmR0VmxReadExitQualVmcs(pVmxTransient);
17273
17274 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
17275 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
17276 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
17277
17278 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
17279 uint8_t const cbAccess = s_aIOSizes[uIOSize];
17280 if (CPUMIsGuestVmxIoInterceptSet(pVCpu, uIOPort, cbAccess))
17281 {
17282 /*
17283 * IN/OUT instruction:
17284 * - Provides VM-exit instruction length.
17285 *
17286 * INS/OUTS instruction:
17287 * - Provides VM-exit instruction length.
17288 * - Provides Guest-linear address.
17289 * - Optionally provides VM-exit instruction info (depends on CPU feature).
17290 */
17291 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
17292 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17293
17294 /* Make sure we don't use stale/uninitialized VMX-transient info. below. */
17295 pVmxTransient->ExitInstrInfo.u = 0;
17296 pVmxTransient->uGuestLinearAddr = 0;
17297
17298 bool const fVmxInsOutsInfo = pVM->cpum.ro.GuestFeatures.fVmxInsOutInfo;
17299 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
17300 if (fIOString)
17301 {
17302 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
17303 if (fVmxInsOutsInfo)
17304 {
17305 Assert(RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS)); /* Paranoia. */
17306 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17307 }
17308 }
17309
17310 VMXVEXITINFO ExitInfo;
17311 RT_ZERO(ExitInfo);
17312 ExitInfo.uReason = pVmxTransient->uExitReason;
17313 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17314 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17315 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17316 ExitInfo.u64GuestLinearAddr = pVmxTransient->uGuestLinearAddr;
17317 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17318 }
17319 return hmR0VmxExitIoInstr(pVCpu, pVmxTransient);
17320}
17321
17322
17323/**
17324 * Nested-guest VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
17325 */
17326HMVMX_EXIT_DECL hmR0VmxExitRdmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17327{
17328 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17329
17330 uint32_t fMsrpm;
17331 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
17332 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
17333 else
17334 fMsrpm = VMXMSRPM_EXIT_RD;
17335
17336 if (fMsrpm & VMXMSRPM_EXIT_RD)
17337 {
17338 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17339 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17340 }
17341 return hmR0VmxExitRdmsr(pVCpu, pVmxTransient);
17342}
17343
17344
17345/**
17346 * Nested-guest VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
17347 */
17348HMVMX_EXIT_DECL hmR0VmxExitWrmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17349{
17350 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17351
17352 uint32_t fMsrpm;
17353 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
17354 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
17355 else
17356 fMsrpm = VMXMSRPM_EXIT_WR;
17357
17358 if (fMsrpm & VMXMSRPM_EXIT_WR)
17359 {
17360 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17361 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17362 }
17363 return hmR0VmxExitWrmsr(pVCpu, pVmxTransient);
17364}
17365
17366
17367/**
17368 * Nested-guest VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
17369 */
17370HMVMX_EXIT_DECL hmR0VmxExitMwaitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17371{
17372 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17373
17374 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MWAIT_EXIT))
17375 {
17376 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17377 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17378 }
17379 return hmR0VmxExitMwait(pVCpu, pVmxTransient);
17380}
17381
17382
17383/**
17384 * Nested-guest VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional
17385 * VM-exit.
17386 */
17387HMVMX_EXIT_DECL hmR0VmxExitMtfNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17388{
17389 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17390
17391 /** @todo NSTVMX: Should consider debugging nested-guests using VM debugger. */
17392 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
17393 VMXVEXITINFO ExitInfo;
17394 RT_ZERO(ExitInfo);
17395 ExitInfo.uReason = pVmxTransient->uExitReason;
17396 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
17397 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
17398}
17399
17400
17401/**
17402 * Nested-guest VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
17403 */
17404HMVMX_EXIT_DECL hmR0VmxExitMonitorNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17405{
17406 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17407
17408 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MONITOR_EXIT))
17409 {
17410 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17411 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17412 }
17413 return hmR0VmxExitMonitor(pVCpu, pVmxTransient);
17414}
17415
17416
17417/**
17418 * Nested-guest VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
17419 */
17420HMVMX_EXIT_DECL hmR0VmxExitPauseNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17421{
17422 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17423
17424 /** @todo NSTVMX: Think about this more. Does the outer guest need to intercept
17425 * PAUSE when executing a nested-guest? If it does not, we would not need
17426 * to check for the intercepts here. Just call VM-exit... */
17427
17428 /* The CPU would have already performed the necessary CPL checks for PAUSE-loop exiting. */
17429 if ( CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_PAUSE_EXIT)
17430 || CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
17431 {
17432 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17433 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17434 }
17435 return hmR0VmxExitPause(pVCpu, pVmxTransient);
17436}
17437
17438
17439/**
17440 * Nested-guest VM-exit handler for when the TPR value is lowered below the
17441 * specified threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
17442 */
17443HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThresholdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17444{
17445 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17446
17447 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_TPR_SHADOW))
17448 {
17449 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
17450 VMXVEXITINFO ExitInfo;
17451 RT_ZERO(ExitInfo);
17452 ExitInfo.uReason = pVmxTransient->uExitReason;
17453 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
17454 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
17455 }
17456 return hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient);
17457}
17458
17459
17460/**
17461 * Nested-guest VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional
17462 * VM-exit.
17463 */
17464HMVMX_EXIT_DECL hmR0VmxExitApicAccessNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17465{
17466 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17467
17468 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17469 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
17470 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
17471 hmR0VmxReadExitQualVmcs(pVmxTransient);
17472
17473 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
17474
17475 Log4Func(("at offset %#x type=%u\n", VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual),
17476 VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual)));
17477
17478 VMXVEXITINFO ExitInfo;
17479 RT_ZERO(ExitInfo);
17480 ExitInfo.uReason = pVmxTransient->uExitReason;
17481 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17482 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17483
17484 VMXVEXITEVENTINFO ExitEventInfo;
17485 RT_ZERO(ExitEventInfo);
17486 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
17487 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
17488 return IEMExecVmxVmexitApicAccess(pVCpu, &ExitInfo, &ExitEventInfo);
17489}
17490
17491
17492/**
17493 * Nested-guest VM-exit handler for APIC write emulation (VMX_EXIT_APIC_WRITE).
17494 * Conditional VM-exit.
17495 */
17496HMVMX_EXIT_DECL hmR0VmxExitApicWriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17497{
17498 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17499
17500 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_APIC_REG_VIRT));
17501 hmR0VmxReadExitQualVmcs(pVmxTransient);
17502 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
17503}
17504
17505
17506/**
17507 * Nested-guest VM-exit handler for virtualized EOI (VMX_EXIT_VIRTUALIZED_EOI).
17508 * Conditional VM-exit.
17509 */
17510HMVMX_EXIT_DECL hmR0VmxExitVirtEoiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17511{
17512 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17513
17514 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_INT_DELIVERY));
17515 hmR0VmxReadExitQualVmcs(pVmxTransient);
17516 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
17517}
17518
17519
17520/**
17521 * Nested-guest VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
17522 */
17523HMVMX_EXIT_DECL hmR0VmxExitRdtscpNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17524{
17525 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17526
17527 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
17528 {
17529 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_RDTSCP));
17530 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17531 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17532 }
17533 return hmR0VmxExitRdtscp(pVCpu, pVmxTransient);
17534}
17535
17536
17537/**
17538 * Nested-guest VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
17539 */
17540HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17541{
17542 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17543
17544 if (CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_WBINVD_EXIT))
17545 {
17546 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17547 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17548 }
17549 return hmR0VmxExitWbinvd(pVCpu, pVmxTransient);
17550}
17551
17552
17553/**
17554 * Nested-guest VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
17555 */
17556HMVMX_EXIT_DECL hmR0VmxExitInvpcidNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17557{
17558 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17559
17560 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
17561 {
17562 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_INVPCID));
17563 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17564 hmR0VmxReadExitQualVmcs(pVmxTransient);
17565 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17566
17567 VMXVEXITINFO ExitInfo;
17568 RT_ZERO(ExitInfo);
17569 ExitInfo.uReason = pVmxTransient->uExitReason;
17570 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17571 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17572 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17573 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17574 }
17575 return hmR0VmxExitInvpcid(pVCpu, pVmxTransient);
17576}
17577
17578
17579/**
17580 * Nested-guest VM-exit handler for invalid-guest state
17581 * (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error VM-exit.
17582 */
17583HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestStateNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17584{
17585 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17586
17587 /*
17588 * Currently this should never happen because we fully emulate VMLAUNCH/VMRESUME in IEM.
17589 * So if it does happen, it indicates a bug possibly in the hardware-assisted VMX code.
17590 * Handle it like it's in an invalid guest state of the outer guest.
17591 *
17592 * When the fast path is implemented, this should be changed to cause the corresponding
17593 * nested-guest VM-exit.
17594 */
17595 return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
17596}
17597
17598
17599/**
17600 * Nested-guest VM-exit handler for instructions that cause VM-exits uncondtionally
17601 * and only provide the instruction length.
17602 *
17603 * Unconditional VM-exit.
17604 */
17605HMVMX_EXIT_DECL hmR0VmxExitInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17606{
17607 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17608
17609#ifdef VBOX_STRICT
17610 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
17611 switch (pVmxTransient->uExitReason)
17612 {
17613 case VMX_EXIT_ENCLS:
17614 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_ENCLS_EXIT));
17615 break;
17616
17617 case VMX_EXIT_VMFUNC:
17618 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_VMFUNC));
17619 break;
17620 }
17621#endif
17622
17623 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17624 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17625}
17626
17627
17628/**
17629 * Nested-guest VM-exit handler for instructions that provide instruction length as
17630 * well as more information.
17631 *
17632 * Unconditional VM-exit.
17633 */
17634HMVMX_EXIT_DECL hmR0VmxExitInstrWithInfoNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17635{
17636 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17637
17638#ifdef VBOX_STRICT
17639 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
17640 switch (pVmxTransient->uExitReason)
17641 {
17642 case VMX_EXIT_GDTR_IDTR_ACCESS:
17643 case VMX_EXIT_LDTR_TR_ACCESS:
17644 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_DESC_TABLE_EXIT));
17645 break;
17646
17647 case VMX_EXIT_RDRAND:
17648 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_RDRAND_EXIT));
17649 break;
17650
17651 case VMX_EXIT_RDSEED:
17652 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_RDSEED_EXIT));
17653 break;
17654
17655 case VMX_EXIT_XSAVES:
17656 case VMX_EXIT_XRSTORS:
17657 /** @todo NSTVMX: Verify XSS-bitmap. */
17658 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_XSAVES_XRSTORS));
17659 break;
17660
17661 case VMX_EXIT_UMWAIT:
17662 case VMX_EXIT_TPAUSE:
17663 Assert(CPUMIsGuestVmxProcCtlsSet(pCtx, VMX_PROC_CTLS_RDTSC_EXIT));
17664 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_USER_WAIT_PAUSE));
17665 break;
17666
17667 case VMX_EXIT_LOADIWKEY:
17668 Assert(CPUMIsGuestVmxProcCtls3Set(pCtx, VMX_PROC_CTLS3_LOADIWKEY_EXIT));
17669 break;
17670 }
17671#endif
17672
17673 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17674 hmR0VmxReadExitQualVmcs(pVmxTransient);
17675 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17676
17677 VMXVEXITINFO ExitInfo;
17678 RT_ZERO(ExitInfo);
17679 ExitInfo.uReason = pVmxTransient->uExitReason;
17680 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17681 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17682 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17683 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17684}
17685
17686/** @} */
17687#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
17688
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