VirtualBox

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

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

VMM/HMVMXR0: Space nit.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 702.9 KB
Line 
1/* $Id: HMVMXR0.cpp 80440 2019-08-27 10:56:18Z vboxsync $ */
2/** @file
3 * HM VMX (Intel VT-x) - Host Context Ring-0.
4 */
5
6/*
7 * Copyright (C) 2012-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_HM
23#define VMCPU_INCL_CPUM_GST_CTX
24#include <iprt/x86.h>
25#include <iprt/asm-amd64-x86.h>
26#include <iprt/thread.h>
27#include <iprt/mem.h>
28#include <iprt/mp.h>
29
30#include <VBox/vmm/pdmapi.h>
31#include <VBox/vmm/dbgf.h>
32#include <VBox/vmm/iem.h>
33#include <VBox/vmm/iom.h>
34#include <VBox/vmm/tm.h>
35#include <VBox/vmm/em.h>
36#include <VBox/vmm/gim.h>
37#include <VBox/vmm/apic.h>
38#ifdef VBOX_WITH_REM
39# include <VBox/vmm/rem.h>
40#endif
41#include "HMInternal.h"
42#include <VBox/vmm/vmcc.h>
43#include <VBox/vmm/hmvmxinline.h>
44#include "HMVMXR0.h"
45#include "dtrace/VBoxVMM.h"
46
47#ifdef DEBUG_ramshankar
48# define HMVMX_ALWAYS_SAVE_GUEST_RFLAGS
49# define HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
50# define HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE
51# define HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
52# define HMVMX_ALWAYS_CLEAN_TRANSIENT
53# define HMVMX_ALWAYS_CHECK_GUEST_STATE
54# define HMVMX_ALWAYS_TRAP_ALL_XCPTS
55# define HMVMX_ALWAYS_TRAP_PF
56# define HMVMX_ALWAYS_FLUSH_TLB
57# define HMVMX_ALWAYS_SWAP_EFER
58#endif
59
60
61/*********************************************************************************************************************************
62* Defined Constants And Macros *
63*********************************************************************************************************************************/
64/** Use the function table. */
65#define HMVMX_USE_FUNCTION_TABLE
66
67/** Determine which tagged-TLB flush handler to use. */
68#define HMVMX_FLUSH_TAGGED_TLB_EPT_VPID 0
69#define HMVMX_FLUSH_TAGGED_TLB_EPT 1
70#define HMVMX_FLUSH_TAGGED_TLB_VPID 2
71#define HMVMX_FLUSH_TAGGED_TLB_NONE 3
72
73/**
74 * Flags to skip redundant reads of some common VMCS fields that are not part of
75 * the guest-CPU or VCPU state but are needed while handling VM-exits.
76 */
77#define HMVMX_READ_IDT_VECTORING_INFO RT_BIT_32(0)
78#define HMVMX_READ_IDT_VECTORING_ERROR_CODE RT_BIT_32(1)
79#define HMVMX_READ_EXIT_QUALIFICATION RT_BIT_32(2)
80#define HMVMX_READ_EXIT_INSTR_LEN RT_BIT_32(3)
81#define HMVMX_READ_EXIT_INTERRUPTION_INFO RT_BIT_32(4)
82#define HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE RT_BIT_32(5)
83#define HMVMX_READ_EXIT_INSTR_INFO RT_BIT_32(6)
84#define HMVMX_READ_GUEST_LINEAR_ADDR RT_BIT_32(7)
85#define HMVMX_READ_GUEST_PHYSICAL_ADDR RT_BIT_32(8)
86#define HMVMX_READ_GUEST_PENDING_DBG_XCPTS RT_BIT_32(9)
87
88/** All the VMCS fields required for processing of exception/NMI VM-exits. */
89#define HMVMX_READ_XCPT_INFO ( HMVMX_READ_EXIT_INTERRUPTION_INFO \
90 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE \
91 | HMVMX_READ_EXIT_INSTR_LEN \
92 | HMVMX_READ_IDT_VECTORING_INFO \
93 | HMVMX_READ_IDT_VECTORING_ERROR_CODE)
94
95/** Assert that all the given fields have been read from the VMCS. */
96#ifdef VBOX_STRICT
97# define HMVMX_ASSERT_READ(a_pVmxTransient, a_fReadFields) \
98 do { \
99 uint32_t const fVmcsFieldRead = ASMAtomicUoReadU32(&pVmxTransient->fVmcsFieldsRead); \
100 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE(); \
101 Assert((fVmcsFieldRead & (a_fReadFields)) == (a_fReadFields)); \
102 } while (0)
103#else
104# define HMVMX_ASSERT_READ(a_pVmxTransient, a_fReadFields) do { } while (0)
105#endif
106
107/**
108 * Subset of the guest-CPU state that is kept by VMX R0 code while executing the
109 * guest using hardware-assisted VMX.
110 *
111 * This excludes state like GPRs (other than RSP) which are always are
112 * swapped and restored across the world-switch and also registers like EFER,
113 * MSR which cannot be modified by the guest without causing a VM-exit.
114 */
115#define HMVMX_CPUMCTX_EXTRN_ALL ( CPUMCTX_EXTRN_RIP \
116 | CPUMCTX_EXTRN_RFLAGS \
117 | CPUMCTX_EXTRN_RSP \
118 | CPUMCTX_EXTRN_SREG_MASK \
119 | CPUMCTX_EXTRN_TABLE_MASK \
120 | CPUMCTX_EXTRN_KERNEL_GS_BASE \
121 | CPUMCTX_EXTRN_SYSCALL_MSRS \
122 | CPUMCTX_EXTRN_SYSENTER_MSRS \
123 | CPUMCTX_EXTRN_TSC_AUX \
124 | CPUMCTX_EXTRN_OTHER_MSRS \
125 | CPUMCTX_EXTRN_CR0 \
126 | CPUMCTX_EXTRN_CR3 \
127 | CPUMCTX_EXTRN_CR4 \
128 | CPUMCTX_EXTRN_DR7 \
129 | CPUMCTX_EXTRN_HWVIRT \
130 | CPUMCTX_EXTRN_HM_VMX_MASK)
131
132/**
133 * Exception bitmap mask for real-mode guests (real-on-v86).
134 *
135 * We need to intercept all exceptions manually except:
136 * - \#AC and \#DB are always intercepted to prevent the CPU from deadlocking
137 * due to bugs in Intel CPUs.
138 * - \#PF need not be intercepted even in real-mode if we have nested paging
139 * support.
140 */
141#define HMVMX_REAL_MODE_XCPT_MASK ( RT_BIT(X86_XCPT_DE) /* always: | RT_BIT(X86_XCPT_DB) */ | RT_BIT(X86_XCPT_NMI) \
142 | RT_BIT(X86_XCPT_BP) | RT_BIT(X86_XCPT_OF) | RT_BIT(X86_XCPT_BR) \
143 | RT_BIT(X86_XCPT_UD) | RT_BIT(X86_XCPT_NM) | RT_BIT(X86_XCPT_DF) \
144 | RT_BIT(X86_XCPT_CO_SEG_OVERRUN) | RT_BIT(X86_XCPT_TS) | RT_BIT(X86_XCPT_NP) \
145 | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_GP) /* RT_BIT(X86_XCPT_PF) */ \
146 | RT_BIT(X86_XCPT_MF) /* always: | RT_BIT(X86_XCPT_AC) */ | RT_BIT(X86_XCPT_MC) \
147 | RT_BIT(X86_XCPT_XF))
148
149/** Maximum VM-instruction error number. */
150#define HMVMX_INSTR_ERROR_MAX 28
151
152/** Profiling macro. */
153#ifdef HM_PROFILE_EXIT_DISPATCH
154# define HMVMX_START_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitDispatch, ed)
155# define HMVMX_STOP_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitDispatch, ed)
156#else
157# define HMVMX_START_EXIT_DISPATCH_PROF() do { } while (0)
158# define HMVMX_STOP_EXIT_DISPATCH_PROF() do { } while (0)
159#endif
160
161/** Assert that preemption is disabled or covered by thread-context hooks. */
162#define HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu) Assert( VMMR0ThreadCtxHookIsEnabled((a_pVCpu)) \
163 || !RTThreadPreemptIsEnabled(NIL_RTTHREAD))
164
165/** Assert that we haven't migrated CPUs when thread-context hooks are not
166 * used. */
167#define HMVMX_ASSERT_CPU_SAFE(a_pVCpu) AssertMsg( VMMR0ThreadCtxHookIsEnabled((a_pVCpu)) \
168 || (a_pVCpu)->hm.s.idEnteredCpu == RTMpCpuId(), \
169 ("Illegal migration! Entered on CPU %u Current %u\n", \
170 (a_pVCpu)->hm.s.idEnteredCpu, RTMpCpuId()))
171
172/** Asserts that the given CPUMCTX_EXTRN_XXX bits are present in the guest-CPU
173 * context. */
174#define HMVMX_CPUMCTX_ASSERT(a_pVCpu, a_fExtrnMbz) AssertMsg(!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fExtrnMbz)), \
175 ("fExtrn=%#RX64 fExtrnMbz=%#RX64\n", \
176 (a_pVCpu)->cpum.GstCtx.fExtrn, (a_fExtrnMbz)))
177
178/** Log the VM-exit reason with an easily visible marker to identify it in a
179 * potential sea of logging data. */
180#define HMVMX_LOG_EXIT(a_pVCpu, a_uExitReason) \
181 do { \
182 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, \
183 HMGetVmxExitName(a_uExitReason))); \
184 } while (0) \
185
186
187/*********************************************************************************************************************************
188* Structures and Typedefs *
189*********************************************************************************************************************************/
190/**
191 * VMX per-VCPU transient state.
192 *
193 * A state structure for holding miscellaneous information across
194 * VMX non-root operation and restored after the transition.
195 */
196typedef struct VMXTRANSIENT
197{
198 /** The host's rflags/eflags. */
199 RTCCUINTREG fEFlags;
200
201 /** The guest's TPR value used for TPR shadowing. */
202 uint8_t u8GuestTpr;
203 /** Alignment. */
204 uint8_t abAlignment0[7];
205
206 /** The basic VM-exit reason. */
207 uint16_t uExitReason;
208 /** Alignment. */
209 uint16_t u16Alignment0;
210 /** The VM-exit interruption error code. */
211 uint32_t uExitIntErrorCode;
212 /** The VM-exit exit code qualification. */
213 uint64_t uExitQual;
214 /** The Guest-linear address. */
215 uint64_t uGuestLinearAddr;
216 /** The Guest-physical address. */
217 uint64_t uGuestPhysicalAddr;
218 /** The Guest pending-debug exceptions. */
219 uint64_t uGuestPendingDbgXcpts;
220
221 /** The VM-exit interruption-information field. */
222 uint32_t uExitIntInfo;
223 /** The VM-exit instruction-length field. */
224 uint32_t cbExitInstr;
225 /** The VM-exit instruction-information field. */
226 VMXEXITINSTRINFO ExitInstrInfo;
227 /** Whether the VM-entry failed or not. */
228 bool fVMEntryFailed;
229 /** Whether we are currently executing a nested-guest. */
230 bool fIsNestedGuest;
231 /** Alignment. */
232 uint8_t abAlignment1[2];
233
234 /** The VM-entry interruption-information field. */
235 uint32_t uEntryIntInfo;
236 /** The VM-entry exception error code field. */
237 uint32_t uEntryXcptErrorCode;
238 /** The VM-entry instruction length field. */
239 uint32_t cbEntryInstr;
240
241 /** IDT-vectoring information field. */
242 uint32_t uIdtVectoringInfo;
243 /** IDT-vectoring error code. */
244 uint32_t uIdtVectoringErrorCode;
245
246 /** Mask of currently read VMCS fields; HMVMX_READ_XXX. */
247 uint32_t fVmcsFieldsRead;
248
249 /** Whether the guest debug state was active at the time of VM-exit. */
250 bool fWasGuestDebugStateActive;
251 /** Whether the hyper debug state was active at the time of VM-exit. */
252 bool fWasHyperDebugStateActive;
253 /** Whether TSC-offsetting and VMX-preemption timer was updated before VM-entry. */
254 bool fUpdatedTscOffsettingAndPreemptTimer;
255 /** Whether the VM-exit was caused by a page-fault during delivery of a
256 * contributory exception or a page-fault. */
257 bool fVectoringDoublePF;
258 /** Whether the VM-exit was caused by a page-fault during delivery of an
259 * external interrupt or NMI. */
260 bool fVectoringPF;
261 /** Whether the TSC_AUX MSR needs to be removed from the auto-load/store MSR
262 * area after VM-exit. */
263 bool fRemoveTscAuxMsr;
264 bool afAlignment0[2];
265
266 /** The VMCS info. object. */
267 PVMXVMCSINFO pVmcsInfo;
268} VMXTRANSIENT;
269AssertCompileMemberAlignment(VMXTRANSIENT, uExitReason, sizeof(uint64_t));
270AssertCompileMemberAlignment(VMXTRANSIENT, uExitIntInfo, sizeof(uint64_t));
271AssertCompileMemberAlignment(VMXTRANSIENT, uEntryIntInfo, sizeof(uint64_t));
272AssertCompileMemberAlignment(VMXTRANSIENT, fWasGuestDebugStateActive, sizeof(uint64_t));
273AssertCompileMemberAlignment(VMXTRANSIENT, pVmcsInfo, sizeof(uint64_t));
274AssertCompileMemberSize(VMXTRANSIENT, ExitInstrInfo, sizeof(uint32_t));
275/** Pointer to VMX transient state. */
276typedef VMXTRANSIENT *PVMXTRANSIENT;
277/** Pointer to a const VMX transient state. */
278typedef const VMXTRANSIENT *PCVMXTRANSIENT;
279
280/**
281 * Memory operand read or write access.
282 */
283typedef enum VMXMEMACCESS
284{
285 VMXMEMACCESS_READ = 0,
286 VMXMEMACCESS_WRITE = 1
287} VMXMEMACCESS;
288
289/**
290 * VMX VM-exit handler.
291 *
292 * @returns Strict VBox status code (i.e. informational status codes too).
293 * @param pVCpu The cross context virtual CPU structure.
294 * @param pVmxTransient The VMX-transient structure.
295 */
296#ifndef HMVMX_USE_FUNCTION_TABLE
297typedef VBOXSTRICTRC FNVMXEXITHANDLER(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
298#else
299typedef DECLCALLBACK(VBOXSTRICTRC) FNVMXEXITHANDLER(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
300/** Pointer to VM-exit handler. */
301typedef FNVMXEXITHANDLER *PFNVMXEXITHANDLER;
302#endif
303
304/**
305 * VMX VM-exit handler, non-strict status code.
306 *
307 * This is generally the same as FNVMXEXITHANDLER, the NSRC bit is just FYI.
308 *
309 * @returns VBox status code, no informational status code returned.
310 * @param pVCpu The cross context virtual CPU structure.
311 * @param pVmxTransient The VMX-transient structure.
312 *
313 * @remarks This is not used on anything returning VERR_EM_INTERPRETER as the
314 * use of that status code will be replaced with VINF_EM_SOMETHING
315 * later when switching over to IEM.
316 */
317#ifndef HMVMX_USE_FUNCTION_TABLE
318typedef int FNVMXEXITHANDLERNSRC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
319#else
320typedef FNVMXEXITHANDLER FNVMXEXITHANDLERNSRC;
321#endif
322
323
324/*********************************************************************************************************************************
325* Internal Functions *
326*********************************************************************************************************************************/
327#ifndef HMVMX_USE_FUNCTION_TABLE
328DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
329# define HMVMX_EXIT_DECL DECLINLINE(VBOXSTRICTRC)
330# define HMVMX_EXIT_NSRC_DECL DECLINLINE(int)
331#else
332# define HMVMX_EXIT_DECL static DECLCALLBACK(VBOXSTRICTRC)
333# define HMVMX_EXIT_NSRC_DECL HMVMX_EXIT_DECL
334#endif
335#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
336DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
337#endif
338
339static int hmR0VmxImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat);
340
341/** @name VM-exit handler prototypes.
342 * @{
343 */
344static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmi;
345static FNVMXEXITHANDLER hmR0VmxExitExtInt;
346static FNVMXEXITHANDLER hmR0VmxExitTripleFault;
347static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindow;
348static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindow;
349static FNVMXEXITHANDLER hmR0VmxExitTaskSwitch;
350static FNVMXEXITHANDLER hmR0VmxExitCpuid;
351static FNVMXEXITHANDLER hmR0VmxExitGetsec;
352static FNVMXEXITHANDLER hmR0VmxExitHlt;
353static FNVMXEXITHANDLERNSRC hmR0VmxExitInvd;
354static FNVMXEXITHANDLER hmR0VmxExitInvlpg;
355static FNVMXEXITHANDLER hmR0VmxExitRdpmc;
356static FNVMXEXITHANDLER hmR0VmxExitVmcall;
357#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
358static FNVMXEXITHANDLER hmR0VmxExitVmclear;
359static FNVMXEXITHANDLER hmR0VmxExitVmlaunch;
360static FNVMXEXITHANDLER hmR0VmxExitVmptrld;
361static FNVMXEXITHANDLER hmR0VmxExitVmptrst;
362static FNVMXEXITHANDLER hmR0VmxExitVmread;
363static FNVMXEXITHANDLER hmR0VmxExitVmresume;
364static FNVMXEXITHANDLER hmR0VmxExitVmwrite;
365static FNVMXEXITHANDLER hmR0VmxExitVmxoff;
366static FNVMXEXITHANDLER hmR0VmxExitVmxon;
367static FNVMXEXITHANDLER hmR0VmxExitInvvpid;
368#endif
369static FNVMXEXITHANDLER hmR0VmxExitRdtsc;
370static FNVMXEXITHANDLER hmR0VmxExitMovCRx;
371static FNVMXEXITHANDLER hmR0VmxExitMovDRx;
372static FNVMXEXITHANDLER hmR0VmxExitIoInstr;
373static FNVMXEXITHANDLER hmR0VmxExitRdmsr;
374static FNVMXEXITHANDLER hmR0VmxExitWrmsr;
375static FNVMXEXITHANDLER hmR0VmxExitMwait;
376static FNVMXEXITHANDLER hmR0VmxExitMtf;
377static FNVMXEXITHANDLER hmR0VmxExitMonitor;
378static FNVMXEXITHANDLER hmR0VmxExitPause;
379static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThreshold;
380static FNVMXEXITHANDLER hmR0VmxExitApicAccess;
381static FNVMXEXITHANDLER hmR0VmxExitEptViolation;
382static FNVMXEXITHANDLER hmR0VmxExitEptMisconfig;
383static FNVMXEXITHANDLER hmR0VmxExitRdtscp;
384static FNVMXEXITHANDLER hmR0VmxExitPreemptTimer;
385static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvd;
386static FNVMXEXITHANDLER hmR0VmxExitXsetbv;
387static FNVMXEXITHANDLER hmR0VmxExitInvpcid;
388static FNVMXEXITHANDLERNSRC hmR0VmxExitSetPendingXcptUD;
389static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestState;
390static FNVMXEXITHANDLERNSRC hmR0VmxExitErrUnexpected;
391/** @} */
392
393#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
394/** @name Nested-guest VM-exit handler prototypes.
395 * @{
396 */
397static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmiNested;
398static FNVMXEXITHANDLER hmR0VmxExitTripleFaultNested;
399static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindowNested;
400static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindowNested;
401static FNVMXEXITHANDLER hmR0VmxExitTaskSwitchNested;
402static FNVMXEXITHANDLER hmR0VmxExitHltNested;
403static FNVMXEXITHANDLER hmR0VmxExitInvlpgNested;
404static FNVMXEXITHANDLER hmR0VmxExitRdpmcNested;
405static FNVMXEXITHANDLER hmR0VmxExitVmreadVmwriteNested;
406static FNVMXEXITHANDLER hmR0VmxExitRdtscNested;
407static FNVMXEXITHANDLER hmR0VmxExitMovCRxNested;
408static FNVMXEXITHANDLER hmR0VmxExitMovDRxNested;
409static FNVMXEXITHANDLER hmR0VmxExitIoInstrNested;
410static FNVMXEXITHANDLER hmR0VmxExitRdmsrNested;
411static FNVMXEXITHANDLER hmR0VmxExitWrmsrNested;
412static FNVMXEXITHANDLER hmR0VmxExitMwaitNested;
413static FNVMXEXITHANDLER hmR0VmxExitMtfNested;
414static FNVMXEXITHANDLER hmR0VmxExitMonitorNested;
415static FNVMXEXITHANDLER hmR0VmxExitPauseNested;
416static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThresholdNested;
417static FNVMXEXITHANDLER hmR0VmxExitApicAccessNested;
418static FNVMXEXITHANDLER hmR0VmxExitApicWriteNested;
419static FNVMXEXITHANDLER hmR0VmxExitVirtEoiNested;
420static FNVMXEXITHANDLER hmR0VmxExitRdtscpNested;
421static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvdNested;
422static FNVMXEXITHANDLER hmR0VmxExitInvpcidNested;
423static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestStateNested;
424static FNVMXEXITHANDLER hmR0VmxExitInstrNested;
425static FNVMXEXITHANDLER hmR0VmxExitInstrWithInfoNested;
426/** @} */
427#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
428
429
430/*********************************************************************************************************************************
431* Global Variables *
432*********************************************************************************************************************************/
433#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
434/**
435 * Array of all VMCS fields.
436 * Any fields added to the VT-x spec. should be added here.
437 *
438 * Currently only used to derive shadow VMCS fields for hardware-assisted execution
439 * of nested-guests.
440 */
441static const uint32_t g_aVmcsFields[] =
442{
443 /* 16-bit control fields. */
444 VMX_VMCS16_VPID,
445 VMX_VMCS16_POSTED_INT_NOTIFY_VECTOR,
446 VMX_VMCS16_EPTP_INDEX,
447
448 /* 16-bit guest-state fields. */
449 VMX_VMCS16_GUEST_ES_SEL,
450 VMX_VMCS16_GUEST_CS_SEL,
451 VMX_VMCS16_GUEST_SS_SEL,
452 VMX_VMCS16_GUEST_DS_SEL,
453 VMX_VMCS16_GUEST_FS_SEL,
454 VMX_VMCS16_GUEST_GS_SEL,
455 VMX_VMCS16_GUEST_LDTR_SEL,
456 VMX_VMCS16_GUEST_TR_SEL,
457 VMX_VMCS16_GUEST_INTR_STATUS,
458 VMX_VMCS16_GUEST_PML_INDEX,
459
460 /* 16-bits host-state fields. */
461 VMX_VMCS16_HOST_ES_SEL,
462 VMX_VMCS16_HOST_CS_SEL,
463 VMX_VMCS16_HOST_SS_SEL,
464 VMX_VMCS16_HOST_DS_SEL,
465 VMX_VMCS16_HOST_FS_SEL,
466 VMX_VMCS16_HOST_GS_SEL,
467 VMX_VMCS16_HOST_TR_SEL,
468
469 /* 64-bit control fields. */
470 VMX_VMCS64_CTRL_IO_BITMAP_A_FULL,
471 VMX_VMCS64_CTRL_IO_BITMAP_A_HIGH,
472 VMX_VMCS64_CTRL_IO_BITMAP_B_FULL,
473 VMX_VMCS64_CTRL_IO_BITMAP_B_HIGH,
474 VMX_VMCS64_CTRL_MSR_BITMAP_FULL,
475 VMX_VMCS64_CTRL_MSR_BITMAP_HIGH,
476 VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL,
477 VMX_VMCS64_CTRL_EXIT_MSR_STORE_HIGH,
478 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL,
479 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_HIGH,
480 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL,
481 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_HIGH,
482 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL,
483 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_HIGH,
484 VMX_VMCS64_CTRL_EXEC_PML_ADDR_FULL,
485 VMX_VMCS64_CTRL_EXEC_PML_ADDR_HIGH,
486 VMX_VMCS64_CTRL_TSC_OFFSET_FULL,
487 VMX_VMCS64_CTRL_TSC_OFFSET_HIGH,
488 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL,
489 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_HIGH,
490 VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL,
491 VMX_VMCS64_CTRL_APIC_ACCESSADDR_HIGH,
492 VMX_VMCS64_CTRL_POSTED_INTR_DESC_FULL,
493 VMX_VMCS64_CTRL_POSTED_INTR_DESC_HIGH,
494 VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL,
495 VMX_VMCS64_CTRL_VMFUNC_CTRLS_HIGH,
496 VMX_VMCS64_CTRL_EPTP_FULL,
497 VMX_VMCS64_CTRL_EPTP_HIGH,
498 VMX_VMCS64_CTRL_EOI_BITMAP_0_FULL,
499 VMX_VMCS64_CTRL_EOI_BITMAP_0_HIGH,
500 VMX_VMCS64_CTRL_EOI_BITMAP_1_FULL,
501 VMX_VMCS64_CTRL_EOI_BITMAP_1_HIGH,
502 VMX_VMCS64_CTRL_EOI_BITMAP_2_FULL,
503 VMX_VMCS64_CTRL_EOI_BITMAP_2_HIGH,
504 VMX_VMCS64_CTRL_EOI_BITMAP_3_FULL,
505 VMX_VMCS64_CTRL_EOI_BITMAP_3_HIGH,
506 VMX_VMCS64_CTRL_EPTP_LIST_FULL,
507 VMX_VMCS64_CTRL_EPTP_LIST_HIGH,
508 VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL,
509 VMX_VMCS64_CTRL_VMREAD_BITMAP_HIGH,
510 VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL,
511 VMX_VMCS64_CTRL_VMWRITE_BITMAP_HIGH,
512 VMX_VMCS64_CTRL_VIRTXCPT_INFO_ADDR_FULL,
513 VMX_VMCS64_CTRL_VIRTXCPT_INFO_ADDR_HIGH,
514 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_FULL,
515 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_HIGH,
516 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_FULL,
517 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_HIGH,
518 VMX_VMCS64_CTRL_TSC_MULTIPLIER_FULL,
519 VMX_VMCS64_CTRL_TSC_MULTIPLIER_HIGH,
520
521 /* 64-bit read-only data fields. */
522 VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL,
523 VMX_VMCS64_RO_GUEST_PHYS_ADDR_HIGH,
524
525 /* 64-bit guest-state fields. */
526 VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL,
527 VMX_VMCS64_GUEST_VMCS_LINK_PTR_HIGH,
528 VMX_VMCS64_GUEST_DEBUGCTL_FULL,
529 VMX_VMCS64_GUEST_DEBUGCTL_HIGH,
530 VMX_VMCS64_GUEST_PAT_FULL,
531 VMX_VMCS64_GUEST_PAT_HIGH,
532 VMX_VMCS64_GUEST_EFER_FULL,
533 VMX_VMCS64_GUEST_EFER_HIGH,
534 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL,
535 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_HIGH,
536 VMX_VMCS64_GUEST_PDPTE0_FULL,
537 VMX_VMCS64_GUEST_PDPTE0_HIGH,
538 VMX_VMCS64_GUEST_PDPTE1_FULL,
539 VMX_VMCS64_GUEST_PDPTE1_HIGH,
540 VMX_VMCS64_GUEST_PDPTE2_FULL,
541 VMX_VMCS64_GUEST_PDPTE2_HIGH,
542 VMX_VMCS64_GUEST_PDPTE3_FULL,
543 VMX_VMCS64_GUEST_PDPTE3_HIGH,
544 VMX_VMCS64_GUEST_BNDCFGS_FULL,
545 VMX_VMCS64_GUEST_BNDCFGS_HIGH,
546
547 /* 64-bit host-state fields. */
548 VMX_VMCS64_HOST_PAT_FULL,
549 VMX_VMCS64_HOST_PAT_HIGH,
550 VMX_VMCS64_HOST_EFER_FULL,
551 VMX_VMCS64_HOST_EFER_HIGH,
552 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL,
553 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_HIGH,
554
555 /* 32-bit control fields. */
556 VMX_VMCS32_CTRL_PIN_EXEC,
557 VMX_VMCS32_CTRL_PROC_EXEC,
558 VMX_VMCS32_CTRL_EXCEPTION_BITMAP,
559 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK,
560 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH,
561 VMX_VMCS32_CTRL_CR3_TARGET_COUNT,
562 VMX_VMCS32_CTRL_EXIT,
563 VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT,
564 VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT,
565 VMX_VMCS32_CTRL_ENTRY,
566 VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT,
567 VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO,
568 VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE,
569 VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH,
570 VMX_VMCS32_CTRL_TPR_THRESHOLD,
571 VMX_VMCS32_CTRL_PROC_EXEC2,
572 VMX_VMCS32_CTRL_PLE_GAP,
573 VMX_VMCS32_CTRL_PLE_WINDOW,
574
575 /* 32-bits read-only fields. */
576 VMX_VMCS32_RO_VM_INSTR_ERROR,
577 VMX_VMCS32_RO_EXIT_REASON,
578 VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO,
579 VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE,
580 VMX_VMCS32_RO_IDT_VECTORING_INFO,
581 VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE,
582 VMX_VMCS32_RO_EXIT_INSTR_LENGTH,
583 VMX_VMCS32_RO_EXIT_INSTR_INFO,
584
585 /* 32-bit guest-state fields. */
586 VMX_VMCS32_GUEST_ES_LIMIT,
587 VMX_VMCS32_GUEST_CS_LIMIT,
588 VMX_VMCS32_GUEST_SS_LIMIT,
589 VMX_VMCS32_GUEST_DS_LIMIT,
590 VMX_VMCS32_GUEST_FS_LIMIT,
591 VMX_VMCS32_GUEST_GS_LIMIT,
592 VMX_VMCS32_GUEST_LDTR_LIMIT,
593 VMX_VMCS32_GUEST_TR_LIMIT,
594 VMX_VMCS32_GUEST_GDTR_LIMIT,
595 VMX_VMCS32_GUEST_IDTR_LIMIT,
596 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
597 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
598 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
599 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
600 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
601 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS,
602 VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS,
603 VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS,
604 VMX_VMCS32_GUEST_INT_STATE,
605 VMX_VMCS32_GUEST_ACTIVITY_STATE,
606 VMX_VMCS32_GUEST_SMBASE,
607 VMX_VMCS32_GUEST_SYSENTER_CS,
608 VMX_VMCS32_PREEMPT_TIMER_VALUE,
609
610 /* 32-bit host-state fields. */
611 VMX_VMCS32_HOST_SYSENTER_CS,
612
613 /* Natural-width control fields. */
614 VMX_VMCS_CTRL_CR0_MASK,
615 VMX_VMCS_CTRL_CR4_MASK,
616 VMX_VMCS_CTRL_CR0_READ_SHADOW,
617 VMX_VMCS_CTRL_CR4_READ_SHADOW,
618 VMX_VMCS_CTRL_CR3_TARGET_VAL0,
619 VMX_VMCS_CTRL_CR3_TARGET_VAL1,
620 VMX_VMCS_CTRL_CR3_TARGET_VAL2,
621 VMX_VMCS_CTRL_CR3_TARGET_VAL3,
622
623 /* Natural-width read-only data fields. */
624 VMX_VMCS_RO_EXIT_QUALIFICATION,
625 VMX_VMCS_RO_IO_RCX,
626 VMX_VMCS_RO_IO_RSI,
627 VMX_VMCS_RO_IO_RDI,
628 VMX_VMCS_RO_IO_RIP,
629 VMX_VMCS_RO_GUEST_LINEAR_ADDR,
630
631 /* Natural-width guest-state field */
632 VMX_VMCS_GUEST_CR0,
633 VMX_VMCS_GUEST_CR3,
634 VMX_VMCS_GUEST_CR4,
635 VMX_VMCS_GUEST_ES_BASE,
636 VMX_VMCS_GUEST_CS_BASE,
637 VMX_VMCS_GUEST_SS_BASE,
638 VMX_VMCS_GUEST_DS_BASE,
639 VMX_VMCS_GUEST_FS_BASE,
640 VMX_VMCS_GUEST_GS_BASE,
641 VMX_VMCS_GUEST_LDTR_BASE,
642 VMX_VMCS_GUEST_TR_BASE,
643 VMX_VMCS_GUEST_GDTR_BASE,
644 VMX_VMCS_GUEST_IDTR_BASE,
645 VMX_VMCS_GUEST_DR7,
646 VMX_VMCS_GUEST_RSP,
647 VMX_VMCS_GUEST_RIP,
648 VMX_VMCS_GUEST_RFLAGS,
649 VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS,
650 VMX_VMCS_GUEST_SYSENTER_ESP,
651 VMX_VMCS_GUEST_SYSENTER_EIP,
652
653 /* Natural-width host-state fields */
654 VMX_VMCS_HOST_CR0,
655 VMX_VMCS_HOST_CR3,
656 VMX_VMCS_HOST_CR4,
657 VMX_VMCS_HOST_FS_BASE,
658 VMX_VMCS_HOST_GS_BASE,
659 VMX_VMCS_HOST_TR_BASE,
660 VMX_VMCS_HOST_GDTR_BASE,
661 VMX_VMCS_HOST_IDTR_BASE,
662 VMX_VMCS_HOST_SYSENTER_ESP,
663 VMX_VMCS_HOST_SYSENTER_EIP,
664 VMX_VMCS_HOST_RSP,
665 VMX_VMCS_HOST_RIP
666};
667#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
668
669static const uint32_t g_aVmcsSegBase[] =
670{
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};
678static const uint32_t g_aVmcsSegSel[] =
679{
680 VMX_VMCS16_GUEST_ES_SEL,
681 VMX_VMCS16_GUEST_CS_SEL,
682 VMX_VMCS16_GUEST_SS_SEL,
683 VMX_VMCS16_GUEST_DS_SEL,
684 VMX_VMCS16_GUEST_FS_SEL,
685 VMX_VMCS16_GUEST_GS_SEL
686};
687static const uint32_t g_aVmcsSegLimit[] =
688{
689 VMX_VMCS32_GUEST_ES_LIMIT,
690 VMX_VMCS32_GUEST_CS_LIMIT,
691 VMX_VMCS32_GUEST_SS_LIMIT,
692 VMX_VMCS32_GUEST_DS_LIMIT,
693 VMX_VMCS32_GUEST_FS_LIMIT,
694 VMX_VMCS32_GUEST_GS_LIMIT
695};
696static const uint32_t g_aVmcsSegAttr[] =
697{
698 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
699 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
700 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
701 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
702 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
703 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS
704};
705AssertCompile(RT_ELEMENTS(g_aVmcsSegSel) == X86_SREG_COUNT);
706AssertCompile(RT_ELEMENTS(g_aVmcsSegLimit) == X86_SREG_COUNT);
707AssertCompile(RT_ELEMENTS(g_aVmcsSegBase) == X86_SREG_COUNT);
708AssertCompile(RT_ELEMENTS(g_aVmcsSegAttr) == X86_SREG_COUNT);
709
710#ifdef HMVMX_USE_FUNCTION_TABLE
711/**
712 * VMX_EXIT dispatch table.
713 */
714static const PFNVMXEXITHANDLER g_apfnVMExitHandlers[VMX_EXIT_MAX + 1] =
715{
716 /* 0 VMX_EXIT_XCPT_OR_NMI */ hmR0VmxExitXcptOrNmi,
717 /* 1 VMX_EXIT_EXT_INT */ hmR0VmxExitExtInt,
718 /* 2 VMX_EXIT_TRIPLE_FAULT */ hmR0VmxExitTripleFault,
719 /* 3 VMX_EXIT_INIT_SIGNAL */ hmR0VmxExitErrUnexpected,
720 /* 4 VMX_EXIT_SIPI */ hmR0VmxExitErrUnexpected,
721 /* 5 VMX_EXIT_IO_SMI */ hmR0VmxExitErrUnexpected,
722 /* 6 VMX_EXIT_SMI */ hmR0VmxExitErrUnexpected,
723 /* 7 VMX_EXIT_INT_WINDOW */ hmR0VmxExitIntWindow,
724 /* 8 VMX_EXIT_NMI_WINDOW */ hmR0VmxExitNmiWindow,
725 /* 9 VMX_EXIT_TASK_SWITCH */ hmR0VmxExitTaskSwitch,
726 /* 10 VMX_EXIT_CPUID */ hmR0VmxExitCpuid,
727 /* 11 VMX_EXIT_GETSEC */ hmR0VmxExitGetsec,
728 /* 12 VMX_EXIT_HLT */ hmR0VmxExitHlt,
729 /* 13 VMX_EXIT_INVD */ hmR0VmxExitInvd,
730 /* 14 VMX_EXIT_INVLPG */ hmR0VmxExitInvlpg,
731 /* 15 VMX_EXIT_RDPMC */ hmR0VmxExitRdpmc,
732 /* 16 VMX_EXIT_RDTSC */ hmR0VmxExitRdtsc,
733 /* 17 VMX_EXIT_RSM */ hmR0VmxExitErrUnexpected,
734 /* 18 VMX_EXIT_VMCALL */ hmR0VmxExitVmcall,
735#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
736 /* 19 VMX_EXIT_VMCLEAR */ hmR0VmxExitVmclear,
737 /* 20 VMX_EXIT_VMLAUNCH */ hmR0VmxExitVmlaunch,
738 /* 21 VMX_EXIT_VMPTRLD */ hmR0VmxExitVmptrld,
739 /* 22 VMX_EXIT_VMPTRST */ hmR0VmxExitVmptrst,
740 /* 23 VMX_EXIT_VMREAD */ hmR0VmxExitVmread,
741 /* 24 VMX_EXIT_VMRESUME */ hmR0VmxExitVmresume,
742 /* 25 VMX_EXIT_VMWRITE */ hmR0VmxExitVmwrite,
743 /* 26 VMX_EXIT_VMXOFF */ hmR0VmxExitVmxoff,
744 /* 27 VMX_EXIT_VMXON */ hmR0VmxExitVmxon,
745#else
746 /* 19 VMX_EXIT_VMCLEAR */ hmR0VmxExitSetPendingXcptUD,
747 /* 20 VMX_EXIT_VMLAUNCH */ hmR0VmxExitSetPendingXcptUD,
748 /* 21 VMX_EXIT_VMPTRLD */ hmR0VmxExitSetPendingXcptUD,
749 /* 22 VMX_EXIT_VMPTRST */ hmR0VmxExitSetPendingXcptUD,
750 /* 23 VMX_EXIT_VMREAD */ hmR0VmxExitSetPendingXcptUD,
751 /* 24 VMX_EXIT_VMRESUME */ hmR0VmxExitSetPendingXcptUD,
752 /* 25 VMX_EXIT_VMWRITE */ hmR0VmxExitSetPendingXcptUD,
753 /* 26 VMX_EXIT_VMXOFF */ hmR0VmxExitSetPendingXcptUD,
754 /* 27 VMX_EXIT_VMXON */ hmR0VmxExitSetPendingXcptUD,
755#endif
756 /* 28 VMX_EXIT_MOV_CRX */ hmR0VmxExitMovCRx,
757 /* 29 VMX_EXIT_MOV_DRX */ hmR0VmxExitMovDRx,
758 /* 30 VMX_EXIT_IO_INSTR */ hmR0VmxExitIoInstr,
759 /* 31 VMX_EXIT_RDMSR */ hmR0VmxExitRdmsr,
760 /* 32 VMX_EXIT_WRMSR */ hmR0VmxExitWrmsr,
761 /* 33 VMX_EXIT_ERR_INVALID_GUEST_STATE */ hmR0VmxExitErrInvalidGuestState,
762 /* 34 VMX_EXIT_ERR_MSR_LOAD */ hmR0VmxExitErrUnexpected,
763 /* 35 UNDEFINED */ hmR0VmxExitErrUnexpected,
764 /* 36 VMX_EXIT_MWAIT */ hmR0VmxExitMwait,
765 /* 37 VMX_EXIT_MTF */ hmR0VmxExitMtf,
766 /* 38 UNDEFINED */ hmR0VmxExitErrUnexpected,
767 /* 39 VMX_EXIT_MONITOR */ hmR0VmxExitMonitor,
768 /* 40 VMX_EXIT_PAUSE */ hmR0VmxExitPause,
769 /* 41 VMX_EXIT_ERR_MACHINE_CHECK */ hmR0VmxExitErrUnexpected,
770 /* 42 UNDEFINED */ hmR0VmxExitErrUnexpected,
771 /* 43 VMX_EXIT_TPR_BELOW_THRESHOLD */ hmR0VmxExitTprBelowThreshold,
772 /* 44 VMX_EXIT_APIC_ACCESS */ hmR0VmxExitApicAccess,
773 /* 45 VMX_EXIT_VIRTUALIZED_EOI */ hmR0VmxExitErrUnexpected,
774 /* 46 VMX_EXIT_GDTR_IDTR_ACCESS */ hmR0VmxExitErrUnexpected,
775 /* 47 VMX_EXIT_LDTR_TR_ACCESS */ hmR0VmxExitErrUnexpected,
776 /* 48 VMX_EXIT_EPT_VIOLATION */ hmR0VmxExitEptViolation,
777 /* 49 VMX_EXIT_EPT_MISCONFIG */ hmR0VmxExitEptMisconfig,
778 /* 50 VMX_EXIT_INVEPT */ hmR0VmxExitSetPendingXcptUD,
779 /* 51 VMX_EXIT_RDTSCP */ hmR0VmxExitRdtscp,
780 /* 52 VMX_EXIT_PREEMPT_TIMER */ hmR0VmxExitPreemptTimer,
781#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
782 /* 53 VMX_EXIT_INVVPID */ hmR0VmxExitInvvpid,
783#else
784 /* 53 VMX_EXIT_INVVPID */ hmR0VmxExitSetPendingXcptUD,
785#endif
786 /* 54 VMX_EXIT_WBINVD */ hmR0VmxExitWbinvd,
787 /* 55 VMX_EXIT_XSETBV */ hmR0VmxExitXsetbv,
788 /* 56 VMX_EXIT_APIC_WRITE */ hmR0VmxExitErrUnexpected,
789 /* 57 VMX_EXIT_RDRAND */ hmR0VmxExitErrUnexpected,
790 /* 58 VMX_EXIT_INVPCID */ hmR0VmxExitInvpcid,
791 /* 59 VMX_EXIT_VMFUNC */ hmR0VmxExitErrUnexpected,
792 /* 60 VMX_EXIT_ENCLS */ hmR0VmxExitErrUnexpected,
793 /* 61 VMX_EXIT_RDSEED */ hmR0VmxExitErrUnexpected,
794 /* 62 VMX_EXIT_PML_FULL */ hmR0VmxExitErrUnexpected,
795 /* 63 VMX_EXIT_XSAVES */ hmR0VmxExitErrUnexpected,
796 /* 64 VMX_EXIT_XRSTORS */ hmR0VmxExitErrUnexpected,
797 /* 65 UNDEFINED */ hmR0VmxExitErrUnexpected,
798 /* 66 VMX_EXIT_SPP_EVENT */ hmR0VmxExitErrUnexpected,
799 /* 67 VMX_EXIT_UMWAIT */ hmR0VmxExitErrUnexpected,
800 /* 68 VMX_EXIT_TPAUSE */ hmR0VmxExitErrUnexpected,
801};
802#endif /* HMVMX_USE_FUNCTION_TABLE */
803
804#if defined(VBOX_STRICT) && defined(LOG_ENABLED)
805static const char * const g_apszVmxInstrErrors[HMVMX_INSTR_ERROR_MAX + 1] =
806{
807 /* 0 */ "(Not Used)",
808 /* 1 */ "VMCALL executed in VMX root operation.",
809 /* 2 */ "VMCLEAR with invalid physical address.",
810 /* 3 */ "VMCLEAR with VMXON pointer.",
811 /* 4 */ "VMLAUNCH with non-clear VMCS.",
812 /* 5 */ "VMRESUME with non-launched VMCS.",
813 /* 6 */ "VMRESUME after VMXOFF",
814 /* 7 */ "VM-entry with invalid control fields.",
815 /* 8 */ "VM-entry with invalid host state fields.",
816 /* 9 */ "VMPTRLD with invalid physical address.",
817 /* 10 */ "VMPTRLD with VMXON pointer.",
818 /* 11 */ "VMPTRLD with incorrect revision identifier.",
819 /* 12 */ "VMREAD/VMWRITE from/to unsupported VMCS component.",
820 /* 13 */ "VMWRITE to read-only VMCS component.",
821 /* 14 */ "(Not Used)",
822 /* 15 */ "VMXON executed in VMX root operation.",
823 /* 16 */ "VM-entry with invalid executive-VMCS pointer.",
824 /* 17 */ "VM-entry with non-launched executing VMCS.",
825 /* 18 */ "VM-entry with executive-VMCS pointer not VMXON pointer.",
826 /* 19 */ "VMCALL with non-clear VMCS.",
827 /* 20 */ "VMCALL with invalid VM-exit control fields.",
828 /* 21 */ "(Not Used)",
829 /* 22 */ "VMCALL with incorrect MSEG revision identifier.",
830 /* 23 */ "VMXOFF under dual monitor treatment of SMIs and SMM.",
831 /* 24 */ "VMCALL with invalid SMM-monitor features.",
832 /* 25 */ "VM-entry with invalid VM-execution control fields in executive VMCS.",
833 /* 26 */ "VM-entry with events blocked by MOV SS.",
834 /* 27 */ "(Not Used)",
835 /* 28 */ "Invalid operand to INVEPT/INVVPID."
836};
837#endif /* VBOX_STRICT && LOG_ENABLED */
838
839
840/**
841 * Get the CR0 guest/host mask that does not change through the lifetime of a VM.
842 *
843 * Any bit set in this mask is owned by the host/hypervisor and would cause a
844 * VM-exit when modified by the guest.
845 *
846 * @returns The static CR0 guest/host mask.
847 * @param pVCpu The cross context virtual CPU structure.
848 */
849DECL_FORCE_INLINE(uint64_t) hmR0VmxGetFixedCr0Mask(PCVMCPUCC pVCpu)
850{
851 /*
852 * Modifications to CR0 bits that VT-x ignores saving/restoring (CD, ET, NW) and
853 * to CR0 bits that we require for shadow paging (PG) by the guest must cause VM-exits.
854 */
855 /** @todo Avoid intercepting CR0.PE with unrestricted guest execution. Fix PGM
856 * enmGuestMode to be in-sync with the current mode. See @bugref{6398}
857 * and @bugref{6944}. */
858 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
859 return ( X86_CR0_PE
860 | X86_CR0_NE
861 | (pVM->hm.s.fNestedPaging ? 0 : X86_CR0_WP)
862 | X86_CR0_PG
863 | X86_CR0_ET /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.ET */
864 | X86_CR0_CD /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.CD */
865 | X86_CR0_NW); /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.NW */
866}
867
868
869/**
870 * Gets the CR4 guest/host mask that does not change through the lifetime of a VM.
871 *
872 * Any bit set in this mask is owned by the host/hypervisor and would cause a
873 * VM-exit when modified by the guest.
874 *
875 * @returns The static CR4 guest/host mask.
876 * @param pVCpu The cross context virtual CPU structure.
877 */
878DECL_FORCE_INLINE(uint64_t) hmR0VmxGetFixedCr4Mask(PCVMCPUCC pVCpu)
879{
880 /*
881 * We need to look at the host features here (for e.g. OSXSAVE, PCID) because
882 * these bits are reserved on hardware that does not support them. Since the
883 * CPU cannot refer to our virtual CPUID, we need to intercept CR4 changes to
884 * these bits and handle it depending on whether we expose them to the guest.
885 */
886 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
887 bool const fXSaveRstor = pVM->cpum.ro.HostFeatures.fXSaveRstor;
888 bool const fPcid = pVM->cpum.ro.HostFeatures.fPcid;
889 return ( X86_CR4_VMXE
890 | X86_CR4_VME
891 | X86_CR4_PAE
892 | X86_CR4_PGE
893 | X86_CR4_PSE
894 | (fXSaveRstor ? X86_CR4_OSXSAVE : 0)
895 | (fPcid ? X86_CR4_PCIDE : 0));
896}
897
898
899/**
900 * Returns whether the the VM-exit MSR-store area differs from the VM-exit MSR-load
901 * area.
902 *
903 * @returns @c true if it's different, @c false otherwise.
904 * @param pVmcsInfo The VMCS info. object.
905 */
906DECL_FORCE_INLINE(bool) hmR0VmxIsSeparateExitMsrStoreAreaVmcs(PCVMXVMCSINFO pVmcsInfo)
907{
908 return RT_BOOL( pVmcsInfo->pvGuestMsrStore != pVmcsInfo->pvGuestMsrLoad
909 && pVmcsInfo->pvGuestMsrStore);
910}
911
912
913/**
914 * Sets the given Processor-based VM-execution controls.
915 *
916 * @param pVmxTransient The VMX-transient structure.
917 * @param uProcCtls The Processor-based VM-execution controls to set.
918 */
919static void hmR0VmxSetProcCtlsVmcs(PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
920{
921 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
922 if ((pVmcsInfo->u32ProcCtls & uProcCtls) != uProcCtls)
923 {
924 pVmcsInfo->u32ProcCtls |= uProcCtls;
925 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
926 AssertRC(rc);
927 }
928}
929
930
931/**
932 * Removes the given Processor-based VM-execution controls.
933 *
934 * @param pVCpu The cross context virtual CPU structure.
935 * @param pVmxTransient The VMX-transient structure.
936 * @param uProcCtls The Processor-based VM-execution controls to remove.
937 *
938 * @remarks When executing a nested-guest, this will not remove any of the specified
939 * controls if the guest hypervisor has set any one of them.
940 */
941static void hmR0VmxRemoveProcCtlsVmcs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
942{
943 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
944 if (pVmcsInfo->u32ProcCtls & uProcCtls)
945 {
946#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
947 bool const fRemoveCtls = !pVmxTransient->fIsNestedGuest
948 ? true
949 : !CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uProcCtls);
950#else
951 NOREF(pVCpu);
952 bool const fRemoveCtls = true;
953#endif
954 if (fRemoveCtls)
955 {
956 pVmcsInfo->u32ProcCtls &= ~uProcCtls;
957 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
958 AssertRC(rc);
959 }
960 }
961}
962
963
964/**
965 * Sets the TSC offset for the current VMCS.
966 *
967 * @param uTscOffset The TSC offset to set.
968 * @param pVmcsInfo The VMCS info. object.
969 */
970static void hmR0VmxSetTscOffsetVmcs(PVMXVMCSINFO pVmcsInfo, uint64_t uTscOffset)
971{
972 if (pVmcsInfo->u64TscOffset != uTscOffset)
973 {
974 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, uTscOffset);
975 AssertRC(rc);
976 pVmcsInfo->u64TscOffset = uTscOffset;
977 }
978}
979
980
981/**
982 * Adds one or more exceptions to the exception bitmap and commits it to the current
983 * VMCS.
984 *
985 * @param pVmxTransient The VMX-transient structure.
986 * @param uXcptMask The exception(s) to add.
987 */
988static void hmR0VmxAddXcptInterceptMask(PVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
989{
990 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
991 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
992 if ((uXcptBitmap & uXcptMask) != uXcptMask)
993 {
994 uXcptBitmap |= uXcptMask;
995 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
996 AssertRC(rc);
997 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
998 }
999}
1000
1001
1002/**
1003 * Adds an exception to the exception bitmap and commits it to the current VMCS.
1004 *
1005 * @param pVmxTransient The VMX-transient structure.
1006 * @param uXcpt The exception to add.
1007 */
1008static void hmR0VmxAddXcptIntercept(PVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1009{
1010 Assert(uXcpt <= X86_XCPT_LAST);
1011 hmR0VmxAddXcptInterceptMask(pVmxTransient, RT_BIT_32(uXcpt));
1012}
1013
1014
1015/**
1016 * Remove one or more exceptions from the exception bitmap and commits it to the
1017 * current VMCS.
1018 *
1019 * This takes care of not removing the exception intercept if a nested-guest
1020 * requires the exception to be intercepted.
1021 *
1022 * @returns VBox status code.
1023 * @param pVCpu The cross context virtual CPU structure.
1024 * @param pVmxTransient The VMX-transient structure.
1025 * @param uXcptMask The exception(s) to remove.
1026 */
1027static int hmR0VmxRemoveXcptInterceptMask(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1028{
1029 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1030 uint32_t u32XcptBitmap = pVmcsInfo->u32XcptBitmap;
1031 if (u32XcptBitmap & uXcptMask)
1032 {
1033#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1034 if (!pVmxTransient->fIsNestedGuest)
1035 { /* likely */ }
1036 else
1037 {
1038 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
1039 uXcptMask &= ~pVmcsNstGst->u32XcptBitmap;
1040 }
1041#endif
1042#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
1043 uXcptMask &= ~( RT_BIT(X86_XCPT_BP)
1044 | RT_BIT(X86_XCPT_DE)
1045 | RT_BIT(X86_XCPT_NM)
1046 | RT_BIT(X86_XCPT_TS)
1047 | RT_BIT(X86_XCPT_UD)
1048 | RT_BIT(X86_XCPT_NP)
1049 | RT_BIT(X86_XCPT_SS)
1050 | RT_BIT(X86_XCPT_GP)
1051 | RT_BIT(X86_XCPT_PF)
1052 | RT_BIT(X86_XCPT_MF));
1053#elif defined(HMVMX_ALWAYS_TRAP_PF)
1054 uXcptMask &= ~RT_BIT(X86_XCPT_PF);
1055#endif
1056 if (uXcptMask)
1057 {
1058 /* Validate we are not removing any essential exception intercepts. */
1059 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging || !(uXcptMask & RT_BIT(X86_XCPT_PF)));
1060 NOREF(pVCpu);
1061 Assert(!(uXcptMask & RT_BIT(X86_XCPT_DB)));
1062 Assert(!(uXcptMask & RT_BIT(X86_XCPT_AC)));
1063
1064 /* Remove it from the exception bitmap. */
1065 u32XcptBitmap &= ~uXcptMask;
1066
1067 /* Commit and update the cache if necessary. */
1068 if (pVmcsInfo->u32XcptBitmap != u32XcptBitmap)
1069 {
1070 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
1071 AssertRC(rc);
1072 pVmcsInfo->u32XcptBitmap = u32XcptBitmap;
1073 }
1074 }
1075 }
1076 return VINF_SUCCESS;
1077}
1078
1079
1080/**
1081 * Remove an exceptions from the exception bitmap and commits it to the current
1082 * VMCS.
1083 *
1084 * @returns VBox status code.
1085 * @param pVCpu The cross context virtual CPU structure.
1086 * @param pVmxTransient The VMX-transient structure.
1087 * @param uXcpt The exception to remove.
1088 */
1089static int hmR0VmxRemoveXcptIntercept(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1090{
1091 return hmR0VmxRemoveXcptInterceptMask(pVCpu, pVmxTransient, RT_BIT(uXcpt));
1092}
1093
1094
1095/**
1096 * Loads the VMCS specified by the VMCS info. object.
1097 *
1098 * @returns VBox status code.
1099 * @param pVmcsInfo The VMCS info. object.
1100 *
1101 * @remarks Can be called with interrupts disabled.
1102 */
1103static int hmR0VmxLoadVmcs(PVMXVMCSINFO pVmcsInfo)
1104{
1105 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1106 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1107
1108 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysVmcs);
1109 if (RT_SUCCESS(rc))
1110 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1111 return rc;
1112}
1113
1114
1115/**
1116 * Clears the VMCS specified by the VMCS info. object.
1117 *
1118 * @returns VBox status code.
1119 * @param pVmcsInfo The VMCS info. object.
1120 *
1121 * @remarks Can be called with interrupts disabled.
1122 */
1123static int hmR0VmxClearVmcs(PVMXVMCSINFO pVmcsInfo)
1124{
1125 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1126 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1127
1128 int rc = VMXClearVmcs(pVmcsInfo->HCPhysVmcs);
1129 if (RT_SUCCESS(rc))
1130 pVmcsInfo->fVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1131 return rc;
1132}
1133
1134
1135#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1136/**
1137 * Loads the shadow VMCS specified by the VMCS info. object.
1138 *
1139 * @returns VBox status code.
1140 * @param pVmcsInfo The VMCS info. object.
1141 *
1142 * @remarks Can be called with interrupts disabled.
1143 */
1144static int hmR0VmxLoadShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1145{
1146 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1147 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1148
1149 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysShadowVmcs);
1150 if (RT_SUCCESS(rc))
1151 pVmcsInfo->fShadowVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1152 return rc;
1153}
1154
1155
1156/**
1157 * Clears the shadow VMCS specified by the VMCS info. object.
1158 *
1159 * @returns VBox status code.
1160 * @param pVmcsInfo The VMCS info. object.
1161 *
1162 * @remarks Can be called with interrupts disabled.
1163 */
1164static int hmR0VmxClearShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1165{
1166 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1167 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1168
1169 int rc = VMXClearVmcs(pVmcsInfo->HCPhysShadowVmcs);
1170 if (RT_SUCCESS(rc))
1171 pVmcsInfo->fShadowVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1172 return rc;
1173}
1174
1175
1176/**
1177 * Switches from and to the specified VMCSes.
1178 *
1179 * @returns VBox status code.
1180 * @param pVmcsInfoFrom The VMCS info. object we are switching from.
1181 * @param pVmcsInfoTo The VMCS info. object we are switching to.
1182 *
1183 * @remarks Called with interrupts disabled.
1184 */
1185static int hmR0VmxSwitchVmcs(PVMXVMCSINFO pVmcsInfoFrom, PVMXVMCSINFO pVmcsInfoTo)
1186{
1187 /*
1188 * Clear the VMCS we are switching out if it has not already been cleared.
1189 * This will sync any CPU internal data back to the VMCS.
1190 */
1191 if (pVmcsInfoFrom->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1192 {
1193 int rc = hmR0VmxClearVmcs(pVmcsInfoFrom);
1194 if (RT_SUCCESS(rc))
1195 {
1196 /*
1197 * The shadow VMCS, if any, would not be active at this point since we
1198 * would have cleared it while importing the virtual hardware-virtualization
1199 * state as part the VMLAUNCH/VMRESUME VM-exit. Hence, there's no need to
1200 * clear the shadow VMCS here, just assert for safety.
1201 */
1202 Assert(!pVmcsInfoFrom->pvShadowVmcs || pVmcsInfoFrom->fShadowVmcsState == VMX_V_VMCS_LAUNCH_STATE_CLEAR);
1203 }
1204 else
1205 return rc;
1206 }
1207
1208 /*
1209 * Clear the VMCS we are switching to if it has not already been cleared.
1210 * This will initialize the VMCS launch state to "clear" required for loading it.
1211 *
1212 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
1213 */
1214 if (pVmcsInfoTo->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1215 {
1216 int rc = hmR0VmxClearVmcs(pVmcsInfoTo);
1217 if (RT_SUCCESS(rc))
1218 { /* likely */ }
1219 else
1220 return rc;
1221 }
1222
1223 /*
1224 * Finally, load the VMCS we are switching to.
1225 */
1226 return hmR0VmxLoadVmcs(pVmcsInfoTo);
1227}
1228
1229
1230/**
1231 * Switches between the guest VMCS and the nested-guest VMCS as specified by the
1232 * caller.
1233 *
1234 * @returns VBox status code.
1235 * @param pVCpu The cross context virtual CPU structure.
1236 * @param fSwitchToNstGstVmcs Whether to switch to the nested-guest VMCS (pass
1237 * true) or guest VMCS (pass false).
1238 */
1239static int hmR0VmxSwitchToGstOrNstGstVmcs(PVMCPUCC pVCpu, bool fSwitchToNstGstVmcs)
1240{
1241 /* Ensure we have synced everything from the guest-CPU context to the VMCS before switching. */
1242 HMVMX_CPUMCTX_ASSERT(pVCpu, HMVMX_CPUMCTX_EXTRN_ALL);
1243
1244 PVMXVMCSINFO pVmcsInfoFrom;
1245 PVMXVMCSINFO pVmcsInfoTo;
1246 if (fSwitchToNstGstVmcs)
1247 {
1248 pVmcsInfoFrom = &pVCpu->hm.s.vmx.VmcsInfo;
1249 pVmcsInfoTo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
1250 }
1251 else
1252 {
1253 pVmcsInfoFrom = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
1254 pVmcsInfoTo = &pVCpu->hm.s.vmx.VmcsInfo;
1255 }
1256
1257 /*
1258 * Disable interrupts to prevent being preempted while we switch the current VMCS as the
1259 * preemption hook code path acquires the current VMCS.
1260 */
1261 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1262
1263 int rc = hmR0VmxSwitchVmcs(pVmcsInfoFrom, pVmcsInfoTo);
1264 if (RT_SUCCESS(rc))
1265 {
1266 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs = fSwitchToNstGstVmcs;
1267
1268 /*
1269 * If we are switching to a VMCS that was executed on a different host CPU or was
1270 * never executed before, flag that we need to export the host state before executing
1271 * guest/nested-guest code using hardware-assisted VMX.
1272 *
1273 * This could probably be done in a preemptible context since the preemption hook
1274 * will flag the necessary change in host context. However, since preemption is
1275 * already disabled and to avoid making assumptions about host specific code in
1276 * RTMpCpuId when called with preemption enabled, we'll do this while preemption is
1277 * disabled.
1278 */
1279 if (pVmcsInfoTo->idHostCpuState == RTMpCpuId())
1280 { /* likely */ }
1281 else
1282 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE);
1283
1284 ASMSetFlags(fEFlags);
1285
1286 /*
1287 * We use a different VM-exit MSR-store areas for the guest and nested-guest. Hence,
1288 * flag that we need to update the host MSR values there. Even if we decide in the
1289 * future to share the VM-exit MSR-store area page between the guest and nested-guest,
1290 * if its content differs, we would have to update the host MSRs anyway.
1291 */
1292 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
1293 }
1294 else
1295 ASMSetFlags(fEFlags);
1296 return rc;
1297}
1298#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
1299
1300
1301/**
1302 * Updates the VM's last error record.
1303 *
1304 * If there was a VMX instruction error, reads the error data from the VMCS and
1305 * updates VCPU's last error record as well.
1306 *
1307 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1308 * Can be NULL if @a rc is not VERR_VMX_UNABLE_TO_START_VM or
1309 * VERR_VMX_INVALID_VMCS_FIELD.
1310 * @param rc The error code.
1311 */
1312static void hmR0VmxUpdateErrorRecord(PVMCPUCC pVCpu, int rc)
1313{
1314 if ( rc == VERR_VMX_INVALID_VMCS_FIELD
1315 || rc == VERR_VMX_UNABLE_TO_START_VM)
1316 {
1317 AssertPtrReturnVoid(pVCpu);
1318 VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
1319 }
1320 pVCpu->CTX_SUFF(pVM)->hm.s.rcInit = rc;
1321}
1322
1323
1324#ifdef VBOX_STRICT
1325/**
1326 * Reads the VM-entry interruption-information field from the VMCS into the VMX
1327 * transient structure.
1328 *
1329 * @param pVmxTransient The VMX-transient structure.
1330 */
1331DECLINLINE(void) hmR0VmxReadEntryIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1332{
1333 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntInfo);
1334 AssertRC(rc);
1335}
1336
1337
1338/**
1339 * Reads the VM-entry exception error code field from the VMCS into
1340 * the VMX transient structure.
1341 *
1342 * @param pVmxTransient The VMX-transient structure.
1343 */
1344DECLINLINE(void) hmR0VmxReadEntryXcptErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1345{
1346 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
1347 AssertRC(rc);
1348}
1349
1350
1351/**
1352 * Reads the VM-entry exception error code field from the VMCS into
1353 * the VMX transient structure.
1354 *
1355 * @param pVmxTransient The VMX-transient structure.
1356 */
1357DECLINLINE(void) hmR0VmxReadEntryInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1358{
1359 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
1360 AssertRC(rc);
1361}
1362#endif /* VBOX_STRICT */
1363
1364
1365/**
1366 * Reads the VM-exit interruption-information field from the VMCS into the VMX
1367 * transient structure.
1368 *
1369 * @param pVmxTransient The VMX-transient structure.
1370 */
1371DECLINLINE(void) hmR0VmxReadExitIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1372{
1373 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_INFO))
1374 {
1375 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1376 AssertRC(rc);
1377 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_INFO;
1378 }
1379}
1380
1381
1382/**
1383 * Reads the VM-exit interruption error code from the VMCS into the VMX
1384 * transient structure.
1385 *
1386 * @param pVmxTransient The VMX-transient structure.
1387 */
1388DECLINLINE(void) hmR0VmxReadExitIntErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1389{
1390 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE))
1391 {
1392 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1393 AssertRC(rc);
1394 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE;
1395 }
1396}
1397
1398
1399/**
1400 * Reads the VM-exit instruction length field from the VMCS into the VMX
1401 * transient structure.
1402 *
1403 * @param pVmxTransient The VMX-transient structure.
1404 */
1405DECLINLINE(void) hmR0VmxReadExitInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1406{
1407 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_LEN))
1408 {
1409 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1410 AssertRC(rc);
1411 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_LEN;
1412 }
1413}
1414
1415
1416/**
1417 * Reads the VM-exit instruction-information field from the VMCS into
1418 * the VMX transient structure.
1419 *
1420 * @param pVmxTransient The VMX-transient structure.
1421 */
1422DECLINLINE(void) hmR0VmxReadExitInstrInfoVmcs(PVMXTRANSIENT pVmxTransient)
1423{
1424 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_INFO))
1425 {
1426 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1427 AssertRC(rc);
1428 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_INFO;
1429 }
1430}
1431
1432
1433/**
1434 * Reads the Exit Qualification from the VMCS into the VMX transient structure.
1435 *
1436 * @param pVmxTransient The VMX-transient structure.
1437 */
1438DECLINLINE(void) hmR0VmxReadExitQualVmcs(PVMXTRANSIENT pVmxTransient)
1439{
1440 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_QUALIFICATION))
1441 {
1442 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1443 AssertRC(rc);
1444 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION;
1445 }
1446}
1447
1448
1449/**
1450 * Reads the Guest-linear address from the VMCS into the VMX transient structure.
1451 *
1452 * @param pVmxTransient The VMX-transient structure.
1453 */
1454DECLINLINE(void) hmR0VmxReadGuestLinearAddrVmcs(PVMXTRANSIENT pVmxTransient)
1455{
1456 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_LINEAR_ADDR))
1457 {
1458 int rc = VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1459 AssertRC(rc);
1460 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_LINEAR_ADDR;
1461 }
1462}
1463
1464
1465/**
1466 * Reads the Guest-physical address from the VMCS into the VMX transient structure.
1467 *
1468 * @param pVmxTransient The VMX-transient structure.
1469 */
1470DECLINLINE(void) hmR0VmxReadGuestPhysicalAddrVmcs(PVMXTRANSIENT pVmxTransient)
1471{
1472 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PHYSICAL_ADDR))
1473 {
1474 int rc = VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1475 AssertRC(rc);
1476 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PHYSICAL_ADDR;
1477 }
1478}
1479
1480#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1481/**
1482 * Reads the Guest pending-debug exceptions from the VMCS into the VMX transient
1483 * structure.
1484 *
1485 * @param pVmxTransient The VMX-transient structure.
1486 */
1487DECLINLINE(void) hmR0VmxReadGuestPendingDbgXctps(PVMXTRANSIENT pVmxTransient)
1488{
1489 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PENDING_DBG_XCPTS))
1490 {
1491 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &pVmxTransient->uGuestPendingDbgXcpts);
1492 AssertRC(rc);
1493 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PENDING_DBG_XCPTS;
1494 }
1495}
1496#endif
1497
1498/**
1499 * Reads the IDT-vectoring information field from the VMCS into the VMX
1500 * transient structure.
1501 *
1502 * @param pVmxTransient The VMX-transient structure.
1503 *
1504 * @remarks No-long-jump zone!!!
1505 */
1506DECLINLINE(void) hmR0VmxReadIdtVectoringInfoVmcs(PVMXTRANSIENT pVmxTransient)
1507{
1508 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_INFO))
1509 {
1510 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1511 AssertRC(rc);
1512 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_INFO;
1513 }
1514}
1515
1516
1517/**
1518 * Reads the IDT-vectoring error code from the VMCS into the VMX
1519 * transient structure.
1520 *
1521 * @param pVmxTransient The VMX-transient structure.
1522 */
1523DECLINLINE(void) hmR0VmxReadIdtVectoringErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1524{
1525 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_ERROR_CODE))
1526 {
1527 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1528 AssertRC(rc);
1529 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_ERROR_CODE;
1530 }
1531}
1532
1533#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
1534/**
1535 * Reads all relevant read-only VMCS fields into the VMX transient structure.
1536 *
1537 * @param pVmxTransient The VMX-transient structure.
1538 */
1539static void hmR0VmxReadAllRoFieldsVmcs(PVMXTRANSIENT pVmxTransient)
1540{
1541 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1542 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1543 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1544 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1545 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1546 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1547 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1548 rc |= VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1549 rc |= VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1550 AssertRC(rc);
1551 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION
1552 | HMVMX_READ_EXIT_INSTR_LEN
1553 | HMVMX_READ_EXIT_INSTR_INFO
1554 | HMVMX_READ_IDT_VECTORING_INFO
1555 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
1556 | HMVMX_READ_EXIT_INTERRUPTION_INFO
1557 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
1558 | HMVMX_READ_GUEST_LINEAR_ADDR
1559 | HMVMX_READ_GUEST_PHYSICAL_ADDR;
1560}
1561#endif
1562
1563/**
1564 * Enters VMX root mode operation on the current CPU.
1565 *
1566 * @returns VBox status code.
1567 * @param pVM The cross context VM structure. Can be
1568 * NULL, after a resume.
1569 * @param HCPhysCpuPage Physical address of the VMXON region.
1570 * @param pvCpuPage Pointer to the VMXON region.
1571 */
1572static int hmR0VmxEnterRootMode(PVMCC pVM, RTHCPHYS HCPhysCpuPage, void *pvCpuPage)
1573{
1574 Assert(HCPhysCpuPage && HCPhysCpuPage != NIL_RTHCPHYS);
1575 Assert(RT_ALIGN_T(HCPhysCpuPage, _4K, RTHCPHYS) == HCPhysCpuPage);
1576 Assert(pvCpuPage);
1577 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1578
1579 if (pVM)
1580 {
1581 /* Write the VMCS revision identifier to the VMXON region. */
1582 *(uint32_t *)pvCpuPage = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
1583 }
1584
1585 /* Paranoid: Disable interrupts as, in theory, interrupt handlers might mess with CR4. */
1586 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1587
1588 /* Enable the VMX bit in CR4 if necessary. */
1589 RTCCUINTREG const uOldCr4 = SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
1590
1591 /* Enter VMX root mode. */
1592 int rc = VMXEnable(HCPhysCpuPage);
1593 if (RT_FAILURE(rc))
1594 {
1595 if (!(uOldCr4 & X86_CR4_VMXE))
1596 SUPR0ChangeCR4(0 /* fOrMask */, ~X86_CR4_VMXE);
1597
1598 if (pVM)
1599 pVM->hm.s.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
1600 }
1601
1602 /* Restore interrupts. */
1603 ASMSetFlags(fEFlags);
1604 return rc;
1605}
1606
1607
1608/**
1609 * Exits VMX root mode operation on the current CPU.
1610 *
1611 * @returns VBox status code.
1612 */
1613static int hmR0VmxLeaveRootMode(void)
1614{
1615 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1616
1617 /* Paranoid: Disable interrupts as, in theory, interrupts handlers might mess with CR4. */
1618 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1619
1620 /* If we're for some reason not in VMX root mode, then don't leave it. */
1621 RTCCUINTREG const uHostCr4 = ASMGetCR4();
1622
1623 int rc;
1624 if (uHostCr4 & X86_CR4_VMXE)
1625 {
1626 /* Exit VMX root mode and clear the VMX bit in CR4. */
1627 VMXDisable();
1628 SUPR0ChangeCR4(0 /* fOrMask */, ~X86_CR4_VMXE);
1629 rc = VINF_SUCCESS;
1630 }
1631 else
1632 rc = VERR_VMX_NOT_IN_VMX_ROOT_MODE;
1633
1634 /* Restore interrupts. */
1635 ASMSetFlags(fEFlags);
1636 return rc;
1637}
1638
1639
1640/**
1641 * Allocates and maps a physically contiguous page. The allocated page is
1642 * zero'd out (used by various VT-x structures).
1643 *
1644 * @returns IPRT status code.
1645 * @param pMemObj Pointer to the ring-0 memory object.
1646 * @param ppVirt Where to store the virtual address of the allocation.
1647 * @param pHCPhys Where to store the physical address of the allocation.
1648 */
1649static int hmR0VmxPageAllocZ(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
1650{
1651 AssertPtr(pMemObj);
1652 AssertPtr(ppVirt);
1653 AssertPtr(pHCPhys);
1654 int rc = RTR0MemObjAllocCont(pMemObj, X86_PAGE_4K_SIZE, false /* fExecutable */);
1655 if (RT_FAILURE(rc))
1656 return rc;
1657 *ppVirt = RTR0MemObjAddress(*pMemObj);
1658 *pHCPhys = RTR0MemObjGetPagePhysAddr(*pMemObj, 0 /* iPage */);
1659 ASMMemZero32(*ppVirt, X86_PAGE_4K_SIZE);
1660 return VINF_SUCCESS;
1661}
1662
1663
1664/**
1665 * Frees and unmaps an allocated, physical page.
1666 *
1667 * @param pMemObj Pointer to the ring-0 memory object.
1668 * @param ppVirt Where to re-initialize the virtual address of allocation as
1669 * 0.
1670 * @param pHCPhys Where to re-initialize the physical address of the
1671 * allocation as 0.
1672 */
1673static void hmR0VmxPageFree(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
1674{
1675 AssertPtr(pMemObj);
1676 AssertPtr(ppVirt);
1677 AssertPtr(pHCPhys);
1678 /* NULL is valid, accepted and ignored by the free function below. */
1679 RTR0MemObjFree(*pMemObj, true /* fFreeMappings */);
1680 *pMemObj = NIL_RTR0MEMOBJ;
1681 *ppVirt = NULL;
1682 *pHCPhys = NIL_RTHCPHYS;
1683}
1684
1685
1686/**
1687 * Initializes a VMCS info. object.
1688 *
1689 * @param pVmcsInfo The VMCS info. object.
1690 */
1691static void hmR0VmxInitVmcsInfo(PVMXVMCSINFO pVmcsInfo)
1692{
1693 memset(pVmcsInfo, 0, sizeof(*pVmcsInfo));
1694
1695 Assert(pVmcsInfo->hMemObjVmcs == NIL_RTR0MEMOBJ);
1696 Assert(pVmcsInfo->hMemObjShadowVmcs == NIL_RTR0MEMOBJ);
1697 Assert(pVmcsInfo->hMemObjMsrBitmap == NIL_RTR0MEMOBJ);
1698 Assert(pVmcsInfo->hMemObjGuestMsrLoad == NIL_RTR0MEMOBJ);
1699 Assert(pVmcsInfo->hMemObjGuestMsrStore == NIL_RTR0MEMOBJ);
1700 Assert(pVmcsInfo->hMemObjHostMsrLoad == NIL_RTR0MEMOBJ);
1701 pVmcsInfo->HCPhysVmcs = NIL_RTHCPHYS;
1702 pVmcsInfo->HCPhysShadowVmcs = NIL_RTHCPHYS;
1703 pVmcsInfo->HCPhysMsrBitmap = NIL_RTHCPHYS;
1704 pVmcsInfo->HCPhysGuestMsrLoad = NIL_RTHCPHYS;
1705 pVmcsInfo->HCPhysGuestMsrStore = NIL_RTHCPHYS;
1706 pVmcsInfo->HCPhysHostMsrLoad = NIL_RTHCPHYS;
1707 pVmcsInfo->HCPhysVirtApic = NIL_RTHCPHYS;
1708 pVmcsInfo->HCPhysEPTP = NIL_RTHCPHYS;
1709 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
1710 pVmcsInfo->idHostCpuState = NIL_RTCPUID;
1711 pVmcsInfo->idHostCpuExec = NIL_RTCPUID;
1712}
1713
1714
1715/**
1716 * Frees the VT-x structures for a VMCS info. object.
1717 *
1718 * @param pVM The cross context VM structure.
1719 * @param pVmcsInfo The VMCS info. object.
1720 */
1721static void hmR0VmxFreeVmcsInfo(PVMCC pVM, PVMXVMCSINFO pVmcsInfo)
1722{
1723 hmR0VmxPageFree(&pVmcsInfo->hMemObjVmcs, &pVmcsInfo->pvVmcs, &pVmcsInfo->HCPhysVmcs);
1724
1725#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1726 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1727 hmR0VmxPageFree(&pVmcsInfo->hMemObjShadowVmcs, &pVmcsInfo->pvShadowVmcs, &pVmcsInfo->HCPhysShadowVmcs);
1728#endif
1729
1730 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
1731 hmR0VmxPageFree(&pVmcsInfo->hMemObjMsrBitmap, &pVmcsInfo->pvMsrBitmap, &pVmcsInfo->HCPhysMsrBitmap);
1732
1733 hmR0VmxPageFree(&pVmcsInfo->hMemObjHostMsrLoad, &pVmcsInfo->pvHostMsrLoad, &pVmcsInfo->HCPhysHostMsrLoad);
1734 hmR0VmxPageFree(&pVmcsInfo->hMemObjGuestMsrLoad, &pVmcsInfo->pvGuestMsrLoad, &pVmcsInfo->HCPhysGuestMsrLoad);
1735 hmR0VmxPageFree(&pVmcsInfo->hMemObjGuestMsrStore, &pVmcsInfo->pvGuestMsrStore, &pVmcsInfo->HCPhysGuestMsrStore);
1736
1737 hmR0VmxInitVmcsInfo(pVmcsInfo);
1738}
1739
1740
1741/**
1742 * Allocates the VT-x structures for a VMCS info. object.
1743 *
1744 * @returns VBox status code.
1745 * @param pVCpu The cross context virtual CPU structure.
1746 * @param pVmcsInfo The VMCS info. object.
1747 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
1748 */
1749static int hmR0VmxAllocVmcsInfo(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
1750{
1751 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
1752
1753 /* Allocate the guest VM control structure (VMCS). */
1754 int rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjVmcs, &pVmcsInfo->pvVmcs, &pVmcsInfo->HCPhysVmcs);
1755 if (RT_SUCCESS(rc))
1756 {
1757 if (!fIsNstGstVmcs)
1758 {
1759#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1760 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1761 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjShadowVmcs, &pVmcsInfo->pvShadowVmcs, &pVmcsInfo->HCPhysShadowVmcs);
1762#endif
1763 if (RT_SUCCESS(rc))
1764 {
1765 /* Get the allocated virtual-APIC page from the virtual APIC device. */
1766 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
1767 && (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW))
1768 rc = APICGetApicPageForCpu(pVCpu, &pVmcsInfo->HCPhysVirtApic, (PRTR0PTR)&pVmcsInfo->pbVirtApic, NULL /*pR3Ptr*/);
1769 }
1770 }
1771 else
1772 {
1773 /* We don't yet support exposing VMCS shadowing to the guest. */
1774 Assert(pVmcsInfo->HCPhysShadowVmcs == NIL_RTHCPHYS);
1775 Assert(!pVmcsInfo->pvShadowVmcs);
1776
1777 /* Get the allocated virtual-APIC page from CPUM. */
1778 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW)
1779 {
1780 /** @todo NSTVMX: Get rid of this. There is no need to allocate a separate HC
1781 * page for this. Use the one provided by the nested-guest directly. */
1782 pVmcsInfo->pbVirtApic = (uint8_t *)CPUMGetGuestVmxVirtApicPage(pVCpu, &pVCpu->cpum.GstCtx,
1783 &pVmcsInfo->HCPhysVirtApic);
1784 Assert(pVmcsInfo->pbVirtApic);
1785 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1786 }
1787 }
1788
1789 if (RT_SUCCESS(rc))
1790 {
1791 /*
1792 * Allocate the MSR-bitmap if supported by the CPU. The MSR-bitmap is for
1793 * transparent accesses of specific MSRs.
1794 *
1795 * If the condition for enabling MSR bitmaps changes here, don't forget to
1796 * update HMIsMsrBitmapActive().
1797 *
1798 * We don't share MSR bitmaps between the guest and nested-guest as we then
1799 * don't need to care about carefully restoring the guest MSR bitmap.
1800 * The guest visible nested-guest MSR bitmap needs to remain unchanged.
1801 * Hence, allocate a separate MSR bitmap for the guest and nested-guest.
1802 * We also don't need to re-initialize the nested-guest MSR bitmap here as
1803 * we do that later while merging VMCS.
1804 */
1805 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
1806 {
1807 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjMsrBitmap, &pVmcsInfo->pvMsrBitmap, &pVmcsInfo->HCPhysMsrBitmap);
1808 if ( RT_SUCCESS(rc)
1809 && !fIsNstGstVmcs)
1810 ASMMemFill32(pVmcsInfo->pvMsrBitmap, X86_PAGE_4K_SIZE, UINT32_C(0xffffffff));
1811 }
1812
1813 if (RT_SUCCESS(rc))
1814 {
1815 /*
1816 * Allocate the VM-entry MSR-load area for the guest MSRs.
1817 *
1818 * Similar to MSR-bitmaps, we do not share the auto MSR-load/store are between
1819 * the guest and nested-guest.
1820 */
1821 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjGuestMsrLoad, &pVmcsInfo->pvGuestMsrLoad,
1822 &pVmcsInfo->HCPhysGuestMsrLoad);
1823 if (RT_SUCCESS(rc))
1824 {
1825 /*
1826 * We use the same page for VM-entry MSR-load and VM-exit MSR store areas.
1827 * These contain the guest MSRs to load on VM-entry and store on VM-exit.
1828 */
1829 Assert(pVmcsInfo->hMemObjGuestMsrStore == NIL_RTR0MEMOBJ);
1830 pVmcsInfo->pvGuestMsrStore = pVmcsInfo->pvGuestMsrLoad;
1831 pVmcsInfo->HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrLoad;
1832
1833 /* Allocate the VM-exit MSR-load page for the host MSRs. */
1834 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjHostMsrLoad, &pVmcsInfo->pvHostMsrLoad,
1835 &pVmcsInfo->HCPhysHostMsrLoad);
1836 }
1837 }
1838 }
1839 }
1840
1841 return rc;
1842}
1843
1844
1845/**
1846 * Free all VT-x structures for the VM.
1847 *
1848 * @returns IPRT status code.
1849 * @param pVM The cross context VM structure.
1850 */
1851static void hmR0VmxStructsFree(PVMCC pVM)
1852{
1853#ifdef VBOX_WITH_CRASHDUMP_MAGIC
1854 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
1855#endif
1856 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess, &pVM->hm.s.vmx.HCPhysApicAccess);
1857
1858#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1859 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1860 {
1861 RTMemFree(pVM->hm.s.vmx.paShadowVmcsFields);
1862 RTMemFree(pVM->hm.s.vmx.paShadowVmcsRoFields);
1863 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjVmreadBitmap, &pVM->hm.s.vmx.pvVmreadBitmap, &pVM->hm.s.vmx.HCPhysVmreadBitmap);
1864 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjVmwriteBitmap, &pVM->hm.s.vmx.pvVmwriteBitmap, &pVM->hm.s.vmx.HCPhysVmwriteBitmap);
1865 }
1866#endif
1867
1868 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1869 {
1870 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
1871 PVMXVMCSINFO pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfo;
1872 hmR0VmxFreeVmcsInfo(pVM, pVmcsInfo);
1873#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1874 if (pVM->cpum.ro.GuestFeatures.fVmx)
1875 {
1876 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
1877 hmR0VmxFreeVmcsInfo(pVM, pVmcsInfo);
1878 }
1879#endif
1880 }
1881}
1882
1883
1884/**
1885 * Allocate all VT-x structures for the VM.
1886 *
1887 * @returns IPRT status code.
1888 * @param pVM The cross context VM structure.
1889 */
1890static int hmR0VmxStructsAlloc(PVMCC pVM)
1891{
1892 /*
1893 * Sanity check the VMCS size reported by the CPU as we assume 4KB allocations.
1894 * The VMCS size cannot be more than 4096 bytes.
1895 *
1896 * See Intel spec. Appendix A.1 "Basic VMX Information".
1897 */
1898 uint32_t const cbVmcs = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_SIZE);
1899 if (cbVmcs <= X86_PAGE_4K_SIZE)
1900 { /* likely */ }
1901 else
1902 {
1903 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_INVALID_VMCS_SIZE;
1904 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1905 }
1906
1907 /*
1908 * Initialize/check members up-front so we can cleanup en masse on allocation failures.
1909 */
1910#ifdef VBOX_WITH_CRASHDUMP_MAGIC
1911 Assert(pVM->hm.s.vmx.hMemObjScratch == NIL_RTR0MEMOBJ);
1912 Assert(pVM->hm.s.vmx.pbScratch == NULL);
1913 pVM->hm.s.vmx.HCPhysScratch = NIL_RTHCPHYS;
1914#endif
1915
1916 Assert(pVM->hm.s.vmx.hMemObjApicAccess == NIL_RTR0MEMOBJ);
1917 Assert(pVM->hm.s.vmx.pbApicAccess == NULL);
1918 pVM->hm.s.vmx.HCPhysApicAccess = NIL_RTHCPHYS;
1919
1920 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1921 {
1922 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
1923 hmR0VmxInitVmcsInfo(&pVCpu->hm.s.vmx.VmcsInfo);
1924 hmR0VmxInitVmcsInfo(&pVCpu->hm.s.vmx.VmcsInfoNstGst);
1925 }
1926
1927 /*
1928 * Allocate per-VM VT-x structures.
1929 */
1930 int rc = VINF_SUCCESS;
1931#ifdef VBOX_WITH_CRASHDUMP_MAGIC
1932 /* Allocate crash-dump magic scratch page. */
1933 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
1934 if (RT_FAILURE(rc))
1935 {
1936 hmR0VmxStructsFree(pVM);
1937 return rc;
1938 }
1939 strcpy((char *)pVM->hm.s.vmx.pbScratch, "SCRATCH Magic");
1940 *(uint64_t *)(pVM->hm.s.vmx.pbScratch + 16) = UINT64_C(0xdeadbeefdeadbeef);
1941#endif
1942
1943 /* Allocate the APIC-access page for trapping APIC accesses from the guest. */
1944 if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
1945 {
1946 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess,
1947 &pVM->hm.s.vmx.HCPhysApicAccess);
1948 if (RT_FAILURE(rc))
1949 {
1950 hmR0VmxStructsFree(pVM);
1951 return rc;
1952 }
1953 }
1954
1955#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1956 /* Allocate the shadow VMCS fields array, VMREAD, VMWRITE bitmaps.. */
1957 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1958 {
1959 Assert(!pVM->hm.s.vmx.cShadowVmcsFields);
1960 Assert(!pVM->hm.s.vmx.cShadowVmcsRoFields);
1961 pVM->hm.s.vmx.paShadowVmcsFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
1962 pVM->hm.s.vmx.paShadowVmcsRoFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
1963 if (RT_LIKELY( pVM->hm.s.vmx.paShadowVmcsFields
1964 && pVM->hm.s.vmx.paShadowVmcsRoFields))
1965 {
1966 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjVmreadBitmap, &pVM->hm.s.vmx.pvVmreadBitmap,
1967 &pVM->hm.s.vmx.HCPhysVmreadBitmap);
1968 if (RT_SUCCESS(rc))
1969 {
1970 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjVmwriteBitmap, &pVM->hm.s.vmx.pvVmwriteBitmap,
1971 &pVM->hm.s.vmx.HCPhysVmwriteBitmap);
1972 }
1973 }
1974 else
1975 rc = VERR_NO_MEMORY;
1976
1977 if (RT_FAILURE(rc))
1978 {
1979 hmR0VmxStructsFree(pVM);
1980 return rc;
1981 }
1982 }
1983#endif
1984
1985 /*
1986 * Initialize per-VCPU VT-x structures.
1987 */
1988 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1989 {
1990 /* Allocate the guest VMCS structures. */
1991 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
1992 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hm.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
1993 if (RT_SUCCESS(rc))
1994 {
1995#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1996 /* Allocate the nested-guest VMCS structures, when the VMX feature is exposed to the guest. */
1997 if (pVM->cpum.ro.GuestFeatures.fVmx)
1998 {
1999 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hm.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
2000 if (RT_SUCCESS(rc))
2001 { /* likely */ }
2002 else
2003 break;
2004 }
2005#endif
2006 }
2007 else
2008 break;
2009 }
2010
2011 if (RT_FAILURE(rc))
2012 {
2013 hmR0VmxStructsFree(pVM);
2014 return rc;
2015 }
2016
2017 return VINF_SUCCESS;
2018}
2019
2020#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2021/**
2022 * Returns whether an MSR at the given MSR-bitmap offset is intercepted or not.
2023 *
2024 * @returns @c true if the MSR is intercepted, @c false otherwise.
2025 * @param pvMsrBitmap The MSR bitmap.
2026 * @param offMsr The MSR byte offset.
2027 * @param iBit The bit offset from the byte offset.
2028 */
2029DECLINLINE(bool) hmR0VmxIsMsrBitSet(const void *pvMsrBitmap, uint16_t offMsr, int32_t iBit)
2030{
2031 uint8_t const * const pbMsrBitmap = (uint8_t const * const)pvMsrBitmap;
2032 Assert(pbMsrBitmap);
2033 Assert(offMsr + (iBit >> 3) <= X86_PAGE_4K_SIZE);
2034 return ASMBitTest(pbMsrBitmap + offMsr, iBit);
2035}
2036#endif
2037
2038/**
2039 * Sets the permission bits for the specified MSR in the given MSR bitmap.
2040 *
2041 * If the passed VMCS is a nested-guest VMCS, this function ensures that the
2042 * read/write intercept is cleared from the MSR bitmap used for hardware-assisted
2043 * VMX execution of the nested-guest, only if nested-guest is also not intercepting
2044 * the read/write access of this MSR.
2045 *
2046 * @param pVCpu The cross context virtual CPU structure.
2047 * @param pVmcsInfo The VMCS info. object.
2048 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2049 * @param idMsr The MSR value.
2050 * @param fMsrpm The MSR permissions (see VMXMSRPM_XXX). This must
2051 * include both a read -and- a write permission!
2052 *
2053 * @sa CPUMGetVmxMsrPermission.
2054 * @remarks Can be called with interrupts disabled.
2055 */
2056static void hmR0VmxSetMsrPermission(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs, uint32_t idMsr, uint32_t fMsrpm)
2057{
2058 uint8_t *pbMsrBitmap = (uint8_t *)pVmcsInfo->pvMsrBitmap;
2059 Assert(pbMsrBitmap);
2060 Assert(VMXMSRPM_IS_FLAG_VALID(fMsrpm));
2061
2062 /*
2063 * MSR-bitmap Layout:
2064 * Byte index MSR range Interpreted as
2065 * 0x000 - 0x3ff 0x00000000 - 0x00001fff Low MSR read bits.
2066 * 0x400 - 0x7ff 0xc0000000 - 0xc0001fff High MSR read bits.
2067 * 0x800 - 0xbff 0x00000000 - 0x00001fff Low MSR write bits.
2068 * 0xc00 - 0xfff 0xc0000000 - 0xc0001fff High MSR write bits.
2069 *
2070 * A bit corresponding to an MSR within the above range causes a VM-exit
2071 * if the bit is 1 on executions of RDMSR/WRMSR. If an MSR falls out of
2072 * the MSR range, it always cause a VM-exit.
2073 *
2074 * See Intel spec. 24.6.9 "MSR-Bitmap Address".
2075 */
2076 uint16_t const offBitmapRead = 0;
2077 uint16_t const offBitmapWrite = 0x800;
2078 uint16_t offMsr;
2079 int32_t iBit;
2080 if (idMsr <= UINT32_C(0x00001fff))
2081 {
2082 offMsr = 0;
2083 iBit = idMsr;
2084 }
2085 else if (idMsr - UINT32_C(0xc0000000) <= UINT32_C(0x00001fff))
2086 {
2087 offMsr = 0x400;
2088 iBit = idMsr - UINT32_C(0xc0000000);
2089 }
2090 else
2091 AssertMsgFailedReturnVoid(("Invalid MSR %#RX32\n", idMsr));
2092
2093 /*
2094 * Set the MSR read permission.
2095 */
2096 uint16_t const offMsrRead = offBitmapRead + offMsr;
2097 Assert(offMsrRead + (iBit >> 3) < offBitmapWrite);
2098 if (fMsrpm & VMXMSRPM_ALLOW_RD)
2099 {
2100#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2101 bool const fClear = !fIsNstGstVmcs ? true
2102 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrRead, iBit);
2103#else
2104 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2105 bool const fClear = true;
2106#endif
2107 if (fClear)
2108 ASMBitClear(pbMsrBitmap + offMsrRead, iBit);
2109 }
2110 else
2111 ASMBitSet(pbMsrBitmap + offMsrRead, iBit);
2112
2113 /*
2114 * Set the MSR write permission.
2115 */
2116 uint16_t const offMsrWrite = offBitmapWrite + offMsr;
2117 Assert(offMsrWrite + (iBit >> 3) < X86_PAGE_4K_SIZE);
2118 if (fMsrpm & VMXMSRPM_ALLOW_WR)
2119 {
2120#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2121 bool const fClear = !fIsNstGstVmcs ? true
2122 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrWrite, iBit);
2123#else
2124 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2125 bool const fClear = true;
2126#endif
2127 if (fClear)
2128 ASMBitClear(pbMsrBitmap + offMsrWrite, iBit);
2129 }
2130 else
2131 ASMBitSet(pbMsrBitmap + offMsrWrite, iBit);
2132}
2133
2134
2135/**
2136 * Updates the VMCS with the number of effective MSRs in the auto-load/store MSR
2137 * area.
2138 *
2139 * @returns VBox status code.
2140 * @param pVCpu The cross context virtual CPU structure.
2141 * @param pVmcsInfo The VMCS info. object.
2142 * @param cMsrs The number of MSRs.
2143 */
2144static int hmR0VmxSetAutoLoadStoreMsrCount(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t cMsrs)
2145{
2146 /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
2147 uint32_t const cMaxSupportedMsrs = VMX_MISC_MAX_MSRS(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc);
2148 if (RT_LIKELY(cMsrs < cMaxSupportedMsrs))
2149 {
2150 /* Commit the MSR counts to the VMCS and update the cache. */
2151 if (pVmcsInfo->cEntryMsrLoad != cMsrs)
2152 {
2153 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2154 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, cMsrs); AssertRC(rc);
2155 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2156 pVmcsInfo->cEntryMsrLoad = cMsrs;
2157 pVmcsInfo->cExitMsrStore = cMsrs;
2158 pVmcsInfo->cExitMsrLoad = cMsrs;
2159 }
2160 return VINF_SUCCESS;
2161 }
2162
2163 LogRel(("Auto-load/store MSR count exceeded! cMsrs=%u MaxSupported=%u\n", cMsrs, cMaxSupportedMsrs));
2164 pVCpu->hm.s.u32HMError = VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE;
2165 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2166}
2167
2168
2169/**
2170 * Adds a new (or updates the value of an existing) guest/host MSR
2171 * pair to be swapped during the world-switch as part of the
2172 * auto-load/store MSR area in the VMCS.
2173 *
2174 * @returns VBox status code.
2175 * @param pVCpu The cross context virtual CPU structure.
2176 * @param pVmxTransient The VMX-transient structure.
2177 * @param idMsr The MSR.
2178 * @param uGuestMsrValue Value of the guest MSR.
2179 * @param fSetReadWrite Whether to set the guest read/write access of this
2180 * MSR (thus not causing a VM-exit).
2181 * @param fUpdateHostMsr Whether to update the value of the host MSR if
2182 * necessary.
2183 */
2184static int hmR0VmxAddAutoLoadStoreMsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t idMsr, uint64_t uGuestMsrValue,
2185 bool fSetReadWrite, bool fUpdateHostMsr)
2186{
2187 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2188 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2189 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2190 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2191 uint32_t i;
2192
2193 /* Paranoia. */
2194 Assert(pGuestMsrLoad);
2195
2196 LogFlowFunc(("pVCpu=%p idMsr=%#RX32 uGestMsrValue=%#RX64\n", pVCpu, idMsr, uGuestMsrValue));
2197
2198 /* Check if the MSR already exists in the VM-entry MSR-load area. */
2199 for (i = 0; i < cMsrs; i++)
2200 {
2201 if (pGuestMsrLoad[i].u32Msr == idMsr)
2202 break;
2203 }
2204
2205 bool fAdded = false;
2206 if (i == cMsrs)
2207 {
2208 /* The MSR does not exist, bump the MSR count to make room for the new MSR. */
2209 ++cMsrs;
2210 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2211 AssertMsgRCReturn(rc, ("Insufficient space to add MSR to VM-entry MSR-load/store area %u\n", idMsr), rc);
2212
2213 /* Set the guest to read/write this MSR without causing VM-exits. */
2214 if ( fSetReadWrite
2215 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
2216 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_ALLOW_RD_WR);
2217
2218 Log4Func(("Added MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2219 fAdded = true;
2220 }
2221
2222 /* Update the MSR value for the newly added or already existing MSR. */
2223 pGuestMsrLoad[i].u32Msr = idMsr;
2224 pGuestMsrLoad[i].u64Value = uGuestMsrValue;
2225
2226 /* Create the corresponding slot in the VM-exit MSR-store area if we use a different page. */
2227 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2228 {
2229 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2230 pGuestMsrStore[i].u32Msr = idMsr;
2231 pGuestMsrStore[i].u64Value = uGuestMsrValue;
2232 }
2233
2234 /* Update the corresponding slot in the host MSR area. */
2235 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2236 Assert(pHostMsr != pVmcsInfo->pvGuestMsrLoad);
2237 Assert(pHostMsr != pVmcsInfo->pvGuestMsrStore);
2238 pHostMsr[i].u32Msr = idMsr;
2239
2240 /*
2241 * Only if the caller requests to update the host MSR value AND we've newly added the
2242 * MSR to the host MSR area do we actually update the value. Otherwise, it will be
2243 * updated by hmR0VmxUpdateAutoLoadHostMsrs().
2244 *
2245 * We do this for performance reasons since reading MSRs may be quite expensive.
2246 */
2247 if (fAdded)
2248 {
2249 if (fUpdateHostMsr)
2250 {
2251 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2252 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2253 pHostMsr[i].u64Value = ASMRdMsr(idMsr);
2254 }
2255 else
2256 {
2257 /* Someone else can do the work. */
2258 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
2259 }
2260 }
2261 return VINF_SUCCESS;
2262}
2263
2264
2265/**
2266 * Removes a guest/host MSR pair to be swapped during the world-switch from the
2267 * auto-load/store MSR area in the VMCS.
2268 *
2269 * @returns VBox status code.
2270 * @param pVCpu The cross context virtual CPU structure.
2271 * @param pVmxTransient The VMX-transient structure.
2272 * @param idMsr The MSR.
2273 */
2274static int hmR0VmxRemoveAutoLoadStoreMsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t idMsr)
2275{
2276 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2277 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2278 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2279 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2280
2281 LogFlowFunc(("pVCpu=%p idMsr=%#RX32\n", pVCpu, idMsr));
2282
2283 for (uint32_t i = 0; i < cMsrs; i++)
2284 {
2285 /* Find the MSR. */
2286 if (pGuestMsrLoad[i].u32Msr == idMsr)
2287 {
2288 /*
2289 * If it's the last MSR, we only need to reduce the MSR count.
2290 * If it's -not- the last MSR, copy the last MSR in place of it and reduce the MSR count.
2291 */
2292 if (i < cMsrs - 1)
2293 {
2294 /* Remove it from the VM-entry MSR-load area. */
2295 pGuestMsrLoad[i].u32Msr = pGuestMsrLoad[cMsrs - 1].u32Msr;
2296 pGuestMsrLoad[i].u64Value = pGuestMsrLoad[cMsrs - 1].u64Value;
2297
2298 /* Remove it from the VM-exit MSR-store area if it's in a different page. */
2299 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2300 {
2301 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2302 Assert(pGuestMsrStore[i].u32Msr == idMsr);
2303 pGuestMsrStore[i].u32Msr = pGuestMsrStore[cMsrs - 1].u32Msr;
2304 pGuestMsrStore[i].u64Value = pGuestMsrStore[cMsrs - 1].u64Value;
2305 }
2306
2307 /* Remove it from the VM-exit MSR-load area. */
2308 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2309 Assert(pHostMsr[i].u32Msr == idMsr);
2310 pHostMsr[i].u32Msr = pHostMsr[cMsrs - 1].u32Msr;
2311 pHostMsr[i].u64Value = pHostMsr[cMsrs - 1].u64Value;
2312 }
2313
2314 /* Reduce the count to reflect the removed MSR and bail. */
2315 --cMsrs;
2316 break;
2317 }
2318 }
2319
2320 /* Update the VMCS if the count changed (meaning the MSR was found and removed). */
2321 if (cMsrs != pVmcsInfo->cEntryMsrLoad)
2322 {
2323 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2324 AssertRCReturn(rc, rc);
2325
2326 /* We're no longer swapping MSRs during the world-switch, intercept guest read/writes to them. */
2327 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2328 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR);
2329
2330 Log4Func(("Removed MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2331 return VINF_SUCCESS;
2332 }
2333
2334 return VERR_NOT_FOUND;
2335}
2336
2337
2338/**
2339 * Checks if the specified guest MSR is part of the VM-entry MSR-load area.
2340 *
2341 * @returns @c true if found, @c false otherwise.
2342 * @param pVmcsInfo The VMCS info. object.
2343 * @param idMsr The MSR to find.
2344 */
2345static bool hmR0VmxIsAutoLoadGuestMsr(PCVMXVMCSINFO pVmcsInfo, uint32_t idMsr)
2346{
2347 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2348 uint32_t const cMsrs = pVmcsInfo->cEntryMsrLoad;
2349 Assert(pMsrs);
2350 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
2351 for (uint32_t i = 0; i < cMsrs; i++)
2352 {
2353 if (pMsrs[i].u32Msr == idMsr)
2354 return true;
2355 }
2356 return false;
2357}
2358
2359
2360/**
2361 * Updates the value of all host MSRs in the VM-exit MSR-load area.
2362 *
2363 * @param pVCpu The cross context virtual CPU structure.
2364 * @param pVmcsInfo The VMCS info. object.
2365 *
2366 * @remarks No-long-jump zone!!!
2367 */
2368static void hmR0VmxUpdateAutoLoadHostMsrs(PCVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2369{
2370 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2371
2372 PVMXAUTOMSR pHostMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2373 uint32_t const cMsrs = pVmcsInfo->cExitMsrLoad;
2374 Assert(pHostMsrLoad);
2375 Assert(sizeof(*pHostMsrLoad) * cMsrs <= X86_PAGE_4K_SIZE);
2376 LogFlowFunc(("pVCpu=%p cMsrs=%u\n", pVCpu, cMsrs));
2377 for (uint32_t i = 0; i < cMsrs; i++)
2378 {
2379 /*
2380 * Performance hack for the host EFER MSR. We use the cached value rather than re-read it.
2381 * Strict builds will catch mismatches in hmR0VmxCheckAutoLoadStoreMsrs(). See @bugref{7368}.
2382 */
2383 if (pHostMsrLoad[i].u32Msr == MSR_K6_EFER)
2384 pHostMsrLoad[i].u64Value = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer;
2385 else
2386 pHostMsrLoad[i].u64Value = ASMRdMsr(pHostMsrLoad[i].u32Msr);
2387 }
2388}
2389
2390
2391/**
2392 * Saves a set of host MSRs to allow read/write passthru access to the guest and
2393 * perform lazy restoration of the host MSRs while leaving VT-x.
2394 *
2395 * @param pVCpu The cross context virtual CPU structure.
2396 *
2397 * @remarks No-long-jump zone!!!
2398 */
2399static void hmR0VmxLazySaveHostMsrs(PVMCPUCC pVCpu)
2400{
2401 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2402
2403 /*
2404 * Note: If you're adding MSRs here, make sure to update the MSR-bitmap accesses in hmR0VmxSetupVmcsProcCtls().
2405 */
2406 if (!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST))
2407 {
2408 Assert(!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)); /* Guest MSRs better not be loaded now. */
2409 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2410 {
2411 pVCpu->hm.s.vmx.u64HostMsrLStar = ASMRdMsr(MSR_K8_LSTAR);
2412 pVCpu->hm.s.vmx.u64HostMsrStar = ASMRdMsr(MSR_K6_STAR);
2413 pVCpu->hm.s.vmx.u64HostMsrSfMask = ASMRdMsr(MSR_K8_SF_MASK);
2414 pVCpu->hm.s.vmx.u64HostMsrKernelGsBase = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
2415 }
2416 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_SAVED_HOST;
2417 }
2418}
2419
2420
2421/**
2422 * Checks whether the MSR belongs to the set of guest MSRs that we restore
2423 * lazily while leaving VT-x.
2424 *
2425 * @returns true if it does, false otherwise.
2426 * @param pVCpu The cross context virtual CPU structure.
2427 * @param idMsr The MSR to check.
2428 */
2429static bool hmR0VmxIsLazyGuestMsr(PCVMCPUCC pVCpu, uint32_t idMsr)
2430{
2431 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2432 {
2433 switch (idMsr)
2434 {
2435 case MSR_K8_LSTAR:
2436 case MSR_K6_STAR:
2437 case MSR_K8_SF_MASK:
2438 case MSR_K8_KERNEL_GS_BASE:
2439 return true;
2440 }
2441 }
2442 return false;
2443}
2444
2445
2446/**
2447 * Loads a set of guests MSRs to allow read/passthru to the guest.
2448 *
2449 * The name of this function is slightly confusing. This function does NOT
2450 * postpone loading, but loads the MSR right now. "hmR0VmxLazy" is simply a
2451 * common prefix for functions dealing with "lazy restoration" of the shared
2452 * MSRs.
2453 *
2454 * @param pVCpu The cross context virtual CPU structure.
2455 *
2456 * @remarks No-long-jump zone!!!
2457 */
2458static void hmR0VmxLazyLoadGuestMsrs(PVMCPUCC pVCpu)
2459{
2460 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2461 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2462
2463 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2464 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2465 {
2466 /*
2467 * If the guest MSRs are not loaded -and- if all the guest MSRs are identical
2468 * to the MSRs on the CPU (which are the saved host MSRs, see assertion above) then
2469 * we can skip a few MSR writes.
2470 *
2471 * Otherwise, it implies either 1. they're not loaded, or 2. they're loaded but the
2472 * guest MSR values in the guest-CPU context might be different to what's currently
2473 * loaded in the CPU. In either case, we need to write the new guest MSR values to the
2474 * CPU, see @bugref{8728}.
2475 */
2476 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
2477 if ( !(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2478 && pCtx->msrKERNELGSBASE == pVCpu->hm.s.vmx.u64HostMsrKernelGsBase
2479 && pCtx->msrLSTAR == pVCpu->hm.s.vmx.u64HostMsrLStar
2480 && pCtx->msrSTAR == pVCpu->hm.s.vmx.u64HostMsrStar
2481 && pCtx->msrSFMASK == pVCpu->hm.s.vmx.u64HostMsrSfMask)
2482 {
2483#ifdef VBOX_STRICT
2484 Assert(ASMRdMsr(MSR_K8_KERNEL_GS_BASE) == pCtx->msrKERNELGSBASE);
2485 Assert(ASMRdMsr(MSR_K8_LSTAR) == pCtx->msrLSTAR);
2486 Assert(ASMRdMsr(MSR_K6_STAR) == pCtx->msrSTAR);
2487 Assert(ASMRdMsr(MSR_K8_SF_MASK) == pCtx->msrSFMASK);
2488#endif
2489 }
2490 else
2491 {
2492 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pCtx->msrKERNELGSBASE);
2493 ASMWrMsr(MSR_K8_LSTAR, pCtx->msrLSTAR);
2494 ASMWrMsr(MSR_K6_STAR, pCtx->msrSTAR);
2495 ASMWrMsr(MSR_K8_SF_MASK, pCtx->msrSFMASK);
2496 }
2497 }
2498 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_LOADED_GUEST;
2499}
2500
2501
2502/**
2503 * Performs lazy restoration of the set of host MSRs if they were previously
2504 * loaded with guest MSR values.
2505 *
2506 * @param pVCpu The cross context virtual CPU structure.
2507 *
2508 * @remarks No-long-jump zone!!!
2509 * @remarks The guest MSRs should have been saved back into the guest-CPU
2510 * context by hmR0VmxImportGuestState()!!!
2511 */
2512static void hmR0VmxLazyRestoreHostMsrs(PVMCPUCC pVCpu)
2513{
2514 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2515 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2516
2517 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2518 {
2519 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2520 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2521 {
2522 ASMWrMsr(MSR_K8_LSTAR, pVCpu->hm.s.vmx.u64HostMsrLStar);
2523 ASMWrMsr(MSR_K6_STAR, pVCpu->hm.s.vmx.u64HostMsrStar);
2524 ASMWrMsr(MSR_K8_SF_MASK, pVCpu->hm.s.vmx.u64HostMsrSfMask);
2525 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pVCpu->hm.s.vmx.u64HostMsrKernelGsBase);
2526 }
2527 }
2528 pVCpu->hm.s.vmx.fLazyMsrs &= ~(VMX_LAZY_MSRS_LOADED_GUEST | VMX_LAZY_MSRS_SAVED_HOST);
2529}
2530
2531
2532/**
2533 * Verifies that our cached values of the VMCS fields are all consistent with
2534 * what's actually present in the VMCS.
2535 *
2536 * @returns VBox status code.
2537 * @retval VINF_SUCCESS if all our caches match their respective VMCS fields.
2538 * @retval VERR_VMX_VMCS_FIELD_CACHE_INVALID if a cache field doesn't match the
2539 * VMCS content. HMCPU error-field is
2540 * updated, see VMX_VCI_XXX.
2541 * @param pVCpu The cross context virtual CPU structure.
2542 * @param pVmcsInfo The VMCS info. object.
2543 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2544 */
2545static int hmR0VmxCheckVmcsCtls(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2546{
2547 const char * const pcszVmcs = fIsNstGstVmcs ? "Nested-guest VMCS" : "VMCS";
2548
2549 uint32_t u32Val;
2550 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
2551 AssertRC(rc);
2552 AssertMsgReturnStmt(pVmcsInfo->u32EntryCtls == u32Val,
2553 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32EntryCtls, u32Val),
2554 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_ENTRY,
2555 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2556
2557 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val);
2558 AssertRC(rc);
2559 AssertMsgReturnStmt(pVmcsInfo->u32ExitCtls == u32Val,
2560 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ExitCtls, u32Val),
2561 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_EXIT,
2562 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2563
2564 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val);
2565 AssertRC(rc);
2566 AssertMsgReturnStmt(pVmcsInfo->u32PinCtls == u32Val,
2567 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32PinCtls, u32Val),
2568 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PIN_EXEC,
2569 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2570
2571 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val);
2572 AssertRC(rc);
2573 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls == u32Val,
2574 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls, u32Val),
2575 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC,
2576 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2577
2578 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
2579 {
2580 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val);
2581 AssertRC(rc);
2582 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls2 == u32Val,
2583 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls2, u32Val),
2584 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC2,
2585 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2586 }
2587
2588 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val);
2589 AssertRC(rc);
2590 AssertMsgReturnStmt(pVmcsInfo->u32XcptBitmap == u32Val,
2591 ("%s exception bitmap mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32XcptBitmap, u32Val),
2592 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_XCPT_BITMAP,
2593 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2594
2595 uint64_t u64Val;
2596 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, &u64Val);
2597 AssertRC(rc);
2598 AssertMsgReturnStmt(pVmcsInfo->u64TscOffset == u64Val,
2599 ("%s TSC offset mismatch: Cache=%#RX64 VMCS=%#RX64\n", pcszVmcs, pVmcsInfo->u64TscOffset, u64Val),
2600 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_TSC_OFFSET,
2601 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2602
2603 NOREF(pcszVmcs);
2604 return VINF_SUCCESS;
2605}
2606
2607
2608#ifdef VBOX_STRICT
2609/**
2610 * Verifies that our cached host EFER MSR value has not changed since we cached it.
2611 *
2612 * @param pVCpu The cross context virtual CPU structure.
2613 * @param pVmcsInfo The VMCS info. object.
2614 */
2615static void hmR0VmxCheckHostEferMsr(PCVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2616{
2617 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2618
2619 if (pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_LOAD_EFER_MSR)
2620 {
2621 uint64_t const uHostEferMsr = ASMRdMsr(MSR_K6_EFER);
2622 uint64_t const uHostEferMsrCache = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer;
2623 uint64_t uVmcsEferMsrVmcs;
2624 int rc = VMXReadVmcs64(VMX_VMCS64_HOST_EFER_FULL, &uVmcsEferMsrVmcs);
2625 AssertRC(rc);
2626
2627 AssertMsgReturnVoid(uHostEferMsr == uVmcsEferMsrVmcs,
2628 ("EFER Host/VMCS mismatch! host=%#RX64 vmcs=%#RX64\n", uHostEferMsr, uVmcsEferMsrVmcs));
2629 AssertMsgReturnVoid(uHostEferMsr == uHostEferMsrCache,
2630 ("EFER Host/Cache mismatch! host=%#RX64 cache=%#RX64\n", uHostEferMsr, uHostEferMsrCache));
2631 }
2632}
2633
2634
2635/**
2636 * Verifies whether the guest/host MSR pairs in the auto-load/store area in the
2637 * VMCS are correct.
2638 *
2639 * @param pVCpu The cross context virtual CPU structure.
2640 * @param pVmcsInfo The VMCS info. object.
2641 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2642 */
2643static void hmR0VmxCheckAutoLoadStoreMsrs(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2644{
2645 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2646
2647 /* Read the various MSR-area counts from the VMCS. */
2648 uint32_t cEntryLoadMsrs;
2649 uint32_t cExitStoreMsrs;
2650 uint32_t cExitLoadMsrs;
2651 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &cEntryLoadMsrs); AssertRC(rc);
2652 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &cExitStoreMsrs); AssertRC(rc);
2653 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &cExitLoadMsrs); AssertRC(rc);
2654
2655 /* Verify all the MSR counts are the same. */
2656 Assert(cEntryLoadMsrs == cExitStoreMsrs);
2657 Assert(cExitStoreMsrs == cExitLoadMsrs);
2658 uint32_t const cMsrs = cExitLoadMsrs;
2659
2660 /* Verify the MSR counts do not exceed the maximum count supported by the hardware. */
2661 Assert(cMsrs < VMX_MISC_MAX_MSRS(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc));
2662
2663 /* Verify the MSR counts are within the allocated page size. */
2664 Assert(sizeof(VMXAUTOMSR) * cMsrs <= X86_PAGE_4K_SIZE);
2665
2666 /* Verify the relevant contents of the MSR areas match. */
2667 PCVMXAUTOMSR pGuestMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2668 PCVMXAUTOMSR pGuestMsrStore = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2669 PCVMXAUTOMSR pHostMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2670 bool const fSeparateExitMsrStorePage = hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo);
2671 for (uint32_t i = 0; i < cMsrs; i++)
2672 {
2673 /* Verify that the MSRs are paired properly and that the host MSR has the correct value. */
2674 if (fSeparateExitMsrStorePage)
2675 {
2676 AssertMsgReturnVoid(pGuestMsrLoad->u32Msr == pGuestMsrStore->u32Msr,
2677 ("GuestMsrLoad=%#RX32 GuestMsrStore=%#RX32 cMsrs=%u\n",
2678 pGuestMsrLoad->u32Msr, pGuestMsrStore->u32Msr, cMsrs));
2679 }
2680
2681 AssertMsgReturnVoid(pHostMsrLoad->u32Msr == pGuestMsrLoad->u32Msr,
2682 ("HostMsrLoad=%#RX32 GuestMsrLoad=%#RX32 cMsrs=%u\n",
2683 pHostMsrLoad->u32Msr, pGuestMsrLoad->u32Msr, cMsrs));
2684
2685 uint64_t const u64Msr = ASMRdMsr(pHostMsrLoad->u32Msr);
2686 AssertMsgReturnVoid(pHostMsrLoad->u64Value == u64Msr,
2687 ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2688 pHostMsrLoad->u32Msr, pHostMsrLoad->u64Value, u64Msr, cMsrs));
2689
2690 /* Verify that cached host EFER MSR matches what's loaded the CPU. */
2691 bool const fIsEferMsr = RT_BOOL(pHostMsrLoad->u32Msr == MSR_K6_EFER);
2692 if (fIsEferMsr)
2693 {
2694 AssertMsgReturnVoid(u64Msr == pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer,
2695 ("Cached=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2696 pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer, u64Msr, cMsrs));
2697 }
2698
2699 /* Verify that the accesses are as expected in the MSR bitmap for auto-load/store MSRs. */
2700 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2701 {
2702 uint32_t const fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, pGuestMsrLoad->u32Msr);
2703 if (fIsEferMsr)
2704 {
2705 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_RD), ("Passthru read for EFER MSR!?\n"));
2706 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_WR), ("Passthru write for EFER MSR!?\n"));
2707 }
2708 else
2709 {
2710 if (!fIsNstGstVmcs)
2711 {
2712 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_ALLOW_RD_WR) == VMXMSRPM_ALLOW_RD_WR,
2713 ("u32Msr=%#RX32 cMsrs=%u No passthru read/write!\n", pGuestMsrLoad->u32Msr, cMsrs));
2714 }
2715 else
2716 {
2717 /*
2718 * A nested-guest VMCS must -also- allow read/write passthrough for the MSR for us to
2719 * execute a nested-guest with MSR passthrough.
2720 *
2721 * Check if the nested-guest MSR bitmap allows passthrough, and if so, assert that we
2722 * allow passthrough too.
2723 */
2724 void const *pvMsrBitmapNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
2725 Assert(pvMsrBitmapNstGst);
2726 uint32_t const fMsrpmNstGst = CPUMGetVmxMsrPermission(pvMsrBitmapNstGst, pGuestMsrLoad->u32Msr);
2727 AssertMsgReturnVoid(fMsrpm == fMsrpmNstGst,
2728 ("u32Msr=%#RX32 cMsrs=%u Permission mismatch fMsrpm=%#x fMsrpmNstGst=%#x!\n",
2729 pGuestMsrLoad->u32Msr, cMsrs, fMsrpm, fMsrpmNstGst));
2730 }
2731 }
2732 }
2733
2734 /* Move to the next MSR. */
2735 pHostMsrLoad++;
2736 pGuestMsrLoad++;
2737 pGuestMsrStore++;
2738 }
2739}
2740#endif /* VBOX_STRICT */
2741
2742
2743/**
2744 * Flushes the TLB using EPT.
2745 *
2746 * @returns VBox status code.
2747 * @param pVCpu The cross context virtual CPU structure of the calling
2748 * EMT. Can be NULL depending on @a enmTlbFlush.
2749 * @param pVmcsInfo The VMCS info. object. Can be NULL depending on @a
2750 * enmTlbFlush.
2751 * @param enmTlbFlush Type of flush.
2752 *
2753 * @remarks Caller is responsible for making sure this function is called only
2754 * when NestedPaging is supported and providing @a enmTlbFlush that is
2755 * supported by the CPU.
2756 * @remarks Can be called with interrupts disabled.
2757 */
2758static void hmR0VmxFlushEpt(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, VMXTLBFLUSHEPT enmTlbFlush)
2759{
2760 uint64_t au64Descriptor[2];
2761 if (enmTlbFlush == VMXTLBFLUSHEPT_ALL_CONTEXTS)
2762 au64Descriptor[0] = 0;
2763 else
2764 {
2765 Assert(pVCpu);
2766 Assert(pVmcsInfo);
2767 au64Descriptor[0] = pVmcsInfo->HCPhysEPTP;
2768 }
2769 au64Descriptor[1] = 0; /* MBZ. Intel spec. 33.3 "VMX Instructions" */
2770
2771 int rc = VMXR0InvEPT(enmTlbFlush, &au64Descriptor[0]);
2772 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %#RHp failed. rc=%Rrc\n", enmTlbFlush, au64Descriptor[0], rc));
2773
2774 if ( RT_SUCCESS(rc)
2775 && pVCpu)
2776 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushNestedPaging);
2777}
2778
2779
2780/**
2781 * Flushes the TLB using VPID.
2782 *
2783 * @returns VBox status code.
2784 * @param pVCpu The cross context virtual CPU structure of the calling
2785 * EMT. Can be NULL depending on @a enmTlbFlush.
2786 * @param enmTlbFlush Type of flush.
2787 * @param GCPtr Virtual address of the page to flush (can be 0 depending
2788 * on @a enmTlbFlush).
2789 *
2790 * @remarks Can be called with interrupts disabled.
2791 */
2792static void hmR0VmxFlushVpid(PVMCPUCC pVCpu, VMXTLBFLUSHVPID enmTlbFlush, RTGCPTR GCPtr)
2793{
2794 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fVpid);
2795
2796 uint64_t au64Descriptor[2];
2797 if (enmTlbFlush == VMXTLBFLUSHVPID_ALL_CONTEXTS)
2798 {
2799 au64Descriptor[0] = 0;
2800 au64Descriptor[1] = 0;
2801 }
2802 else
2803 {
2804 AssertPtr(pVCpu);
2805 AssertMsg(pVCpu->hm.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
2806 AssertMsg(pVCpu->hm.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
2807 au64Descriptor[0] = pVCpu->hm.s.uCurrentAsid;
2808 au64Descriptor[1] = GCPtr;
2809 }
2810
2811 int rc = VMXR0InvVPID(enmTlbFlush, &au64Descriptor[0]);
2812 AssertMsg(rc == VINF_SUCCESS,
2813 ("VMXR0InvVPID %#x %u %RGv failed with %Rrc\n", enmTlbFlush, pVCpu ? pVCpu->hm.s.uCurrentAsid : 0, GCPtr, rc));
2814
2815 if ( RT_SUCCESS(rc)
2816 && pVCpu)
2817 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
2818 NOREF(rc);
2819}
2820
2821
2822/**
2823 * Invalidates a guest page by guest virtual address. Only relevant for EPT/VPID,
2824 * otherwise there is nothing really to invalidate.
2825 *
2826 * @returns VBox status code.
2827 * @param pVCpu The cross context virtual CPU structure.
2828 * @param GCVirt Guest virtual address of the page to invalidate.
2829 */
2830VMMR0DECL(int) VMXR0InvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt)
2831{
2832 AssertPtr(pVCpu);
2833 LogFlowFunc(("pVCpu=%p GCVirt=%RGv\n", pVCpu, GCVirt));
2834
2835 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_TLB_FLUSH))
2836 {
2837 /*
2838 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for
2839 * the EPT case. See @bugref{6043} and @bugref{6177}.
2840 *
2841 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VM-entry in hmR0VmxFlushTLB*()
2842 * as this function maybe called in a loop with individual addresses.
2843 */
2844 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2845 if (pVM->hm.s.vmx.fVpid)
2846 {
2847 bool fVpidFlush = RT_BOOL(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR);
2848 if (fVpidFlush)
2849 {
2850 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_INDIV_ADDR, GCVirt);
2851 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
2852 }
2853 else
2854 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2855 }
2856 else if (pVM->hm.s.fNestedPaging)
2857 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2858 }
2859
2860 return VINF_SUCCESS;
2861}
2862
2863
2864/**
2865 * Dummy placeholder for tagged-TLB flush handling before VM-entry. Used in the
2866 * case where neither EPT nor VPID is supported by the CPU.
2867 *
2868 * @param pHostCpu The HM physical-CPU structure.
2869 * @param pVCpu The cross context virtual CPU structure.
2870 *
2871 * @remarks Called with interrupts disabled.
2872 */
2873static void hmR0VmxFlushTaggedTlbNone(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
2874{
2875 AssertPtr(pVCpu);
2876 AssertPtr(pHostCpu);
2877
2878 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
2879
2880 Assert(pHostCpu->idCpu != NIL_RTCPUID);
2881 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
2882 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
2883 pVCpu->hm.s.fForceTLBFlush = false;
2884 return;
2885}
2886
2887
2888/**
2889 * Flushes the tagged-TLB entries for EPT+VPID CPUs as necessary.
2890 *
2891 * @param pHostCpu The HM physical-CPU structure.
2892 * @param pVCpu The cross context virtual CPU structure.
2893 * @param pVmcsInfo The VMCS info. object.
2894 *
2895 * @remarks All references to "ASID" in this function pertains to "VPID" in Intel's
2896 * nomenclature. The reason is, to avoid confusion in compare statements
2897 * since the host-CPU copies are named "ASID".
2898 *
2899 * @remarks Called with interrupts disabled.
2900 */
2901static void hmR0VmxFlushTaggedTlbBoth(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2902{
2903#ifdef VBOX_WITH_STATISTICS
2904 bool fTlbFlushed = false;
2905# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { fTlbFlushed = true; } while (0)
2906# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { \
2907 if (!fTlbFlushed) \
2908 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch); \
2909 } while (0)
2910#else
2911# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { } while (0)
2912# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { } while (0)
2913#endif
2914
2915 AssertPtr(pVCpu);
2916 AssertPtr(pHostCpu);
2917 Assert(pHostCpu->idCpu != NIL_RTCPUID);
2918
2919 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2920 AssertMsg(pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid,
2921 ("hmR0VmxFlushTaggedTlbBoth cannot be invoked unless NestedPaging & VPID are enabled."
2922 "fNestedPaging=%RTbool fVpid=%RTbool", pVM->hm.s.fNestedPaging, pVM->hm.s.vmx.fVpid));
2923
2924 /*
2925 * Force a TLB flush for the first world-switch if the current CPU differs from the one we
2926 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
2927 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
2928 * cannot reuse the current ASID anymore.
2929 */
2930 if ( pVCpu->hm.s.idLastCpu != pHostCpu->idCpu
2931 || pVCpu->hm.s.cTlbFlushes != pHostCpu->cTlbFlushes)
2932 {
2933 ++pHostCpu->uCurrentAsid;
2934 if (pHostCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
2935 {
2936 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0. */
2937 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
2938 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
2939 }
2940
2941 pVCpu->hm.s.uCurrentAsid = pHostCpu->uCurrentAsid;
2942 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
2943 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
2944
2945 /*
2946 * Flush by EPT when we get rescheduled to a new host CPU to ensure EPT-only tagged mappings are also
2947 * invalidated. We don't need to flush-by-VPID here as flushing by EPT covers it. See @bugref{6568}.
2948 */
2949 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hm.s.vmx.enmTlbFlushEpt);
2950 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
2951 HMVMX_SET_TAGGED_TLB_FLUSHED();
2952 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
2953 }
2954 else if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH)) /* Check for explicit TLB flushes. */
2955 {
2956 /*
2957 * Changes to the EPT paging structure by VMM requires flushing-by-EPT as the CPU
2958 * creates guest-physical (ie. only EPT-tagged) mappings while traversing the EPT
2959 * tables when EPT is in use. Flushing-by-VPID will only flush linear (only
2960 * VPID-tagged) and combined (EPT+VPID tagged) mappings but not guest-physical
2961 * mappings, see @bugref{6568}.
2962 *
2963 * See Intel spec. 28.3.2 "Creating and Using Cached Translation Information".
2964 */
2965 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hm.s.vmx.enmTlbFlushEpt);
2966 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
2967 HMVMX_SET_TAGGED_TLB_FLUSHED();
2968 }
2969 else if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
2970 {
2971 /*
2972 * The nested-guest specifies its own guest-physical address to use as the APIC-access
2973 * address which requires flushing the TLB of EPT cached structures.
2974 *
2975 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
2976 */
2977 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hm.s.vmx.enmTlbFlushEpt);
2978 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
2979 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
2980 HMVMX_SET_TAGGED_TLB_FLUSHED();
2981 }
2982
2983
2984 pVCpu->hm.s.fForceTLBFlush = false;
2985 HMVMX_UPDATE_FLUSH_SKIPPED_STAT();
2986
2987 Assert(pVCpu->hm.s.idLastCpu == pHostCpu->idCpu);
2988 Assert(pVCpu->hm.s.cTlbFlushes == pHostCpu->cTlbFlushes);
2989 AssertMsg(pVCpu->hm.s.cTlbFlushes == pHostCpu->cTlbFlushes,
2990 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pHostCpu->cTlbFlushes));
2991 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
2992 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
2993 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
2994 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
2995 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
2996
2997 /* Update VMCS with the VPID. */
2998 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
2999 AssertRC(rc);
3000
3001#undef HMVMX_SET_TAGGED_TLB_FLUSHED
3002}
3003
3004
3005/**
3006 * Flushes the tagged-TLB entries for EPT CPUs as necessary.
3007 *
3008 * @param pHostCpu The HM physical-CPU structure.
3009 * @param pVCpu The cross context virtual CPU structure.
3010 * @param pVmcsInfo The VMCS info. object.
3011 *
3012 * @remarks Called with interrupts disabled.
3013 */
3014static void hmR0VmxFlushTaggedTlbEpt(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3015{
3016 AssertPtr(pVCpu);
3017 AssertPtr(pHostCpu);
3018 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3019 AssertMsg(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked without NestedPaging."));
3020 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fVpid, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with VPID."));
3021
3022 /*
3023 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
3024 * A change in the TLB flush count implies the host CPU is online after a suspend/resume.
3025 */
3026 if ( pVCpu->hm.s.idLastCpu != pHostCpu->idCpu
3027 || pVCpu->hm.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3028 {
3029 pVCpu->hm.s.fForceTLBFlush = true;
3030 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3031 }
3032
3033 /* Check for explicit TLB flushes. */
3034 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3035 {
3036 pVCpu->hm.s.fForceTLBFlush = true;
3037 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3038 }
3039
3040 /* Check for TLB flushes while switching to/from a nested-guest. */
3041 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3042 {
3043 pVCpu->hm.s.fForceTLBFlush = true;
3044 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3045 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3046 }
3047
3048 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
3049 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3050
3051 if (pVCpu->hm.s.fForceTLBFlush)
3052 {
3053 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVCpu->CTX_SUFF(pVM)->hm.s.vmx.enmTlbFlushEpt);
3054 pVCpu->hm.s.fForceTLBFlush = false;
3055 }
3056}
3057
3058
3059/**
3060 * Flushes the tagged-TLB entries for VPID CPUs as necessary.
3061 *
3062 * @param pHostCpu The HM physical-CPU structure.
3063 * @param pVCpu The cross context virtual CPU structure.
3064 *
3065 * @remarks Called with interrupts disabled.
3066 */
3067static void hmR0VmxFlushTaggedTlbVpid(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
3068{
3069 AssertPtr(pVCpu);
3070 AssertPtr(pHostCpu);
3071 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3072 AssertMsg(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fVpid, ("hmR0VmxFlushTlbVpid cannot be invoked without VPID."));
3073 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging"));
3074
3075 /*
3076 * Force a TLB flush for the first world switch if the current CPU differs from the one we
3077 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
3078 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
3079 * cannot reuse the current ASID anymore.
3080 */
3081 if ( pVCpu->hm.s.idLastCpu != pHostCpu->idCpu
3082 || pVCpu->hm.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3083 {
3084 pVCpu->hm.s.fForceTLBFlush = true;
3085 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3086 }
3087
3088 /* Check for explicit TLB flushes. */
3089 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3090 {
3091 /*
3092 * If we ever support VPID flush combinations other than ALL or SINGLE-context (see
3093 * hmR0VmxSetupTaggedTlb()) we would need to explicitly flush in this case (add an
3094 * fExplicitFlush = true here and change the pHostCpu->fFlushAsidBeforeUse check below to
3095 * include fExplicitFlush's too) - an obscure corner case.
3096 */
3097 pVCpu->hm.s.fForceTLBFlush = true;
3098 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3099 }
3100
3101 /* Check for TLB flushes while switching to/from a nested-guest. */
3102 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3103 {
3104 pVCpu->hm.s.fForceTLBFlush = true;
3105 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3106 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3107 }
3108
3109 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3110 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
3111 if (pVCpu->hm.s.fForceTLBFlush)
3112 {
3113 ++pHostCpu->uCurrentAsid;
3114 if (pHostCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
3115 {
3116 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0 */
3117 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
3118 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
3119 }
3120
3121 pVCpu->hm.s.fForceTLBFlush = false;
3122 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3123 pVCpu->hm.s.uCurrentAsid = pHostCpu->uCurrentAsid;
3124 if (pHostCpu->fFlushAsidBeforeUse)
3125 {
3126 if (pVM->hm.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_SINGLE_CONTEXT)
3127 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_SINGLE_CONTEXT, 0 /* GCPtr */);
3128 else if (pVM->hm.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_ALL_CONTEXTS)
3129 {
3130 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_ALL_CONTEXTS, 0 /* GCPtr */);
3131 pHostCpu->fFlushAsidBeforeUse = false;
3132 }
3133 else
3134 {
3135 /* hmR0VmxSetupTaggedTlb() ensures we never get here. Paranoia. */
3136 AssertMsgFailed(("Unsupported VPID-flush context type.\n"));
3137 }
3138 }
3139 }
3140
3141 AssertMsg(pVCpu->hm.s.cTlbFlushes == pHostCpu->cTlbFlushes,
3142 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pHostCpu->cTlbFlushes));
3143 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
3144 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3145 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
3146 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
3147 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
3148
3149 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
3150 AssertRC(rc);
3151}
3152
3153
3154/**
3155 * Flushes the guest TLB entry based on CPU capabilities.
3156 *
3157 * @param pHostCpu The HM physical-CPU structure.
3158 * @param pVCpu The cross context virtual CPU structure.
3159 * @param pVmcsInfo The VMCS info. object.
3160 *
3161 * @remarks Called with interrupts disabled.
3162 */
3163static void hmR0VmxFlushTaggedTlb(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3164{
3165#ifdef HMVMX_ALWAYS_FLUSH_TLB
3166 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
3167#endif
3168 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3169 switch (pVM->hm.s.vmx.enmTlbFlushType)
3170 {
3171 case VMXTLBFLUSHTYPE_EPT_VPID: hmR0VmxFlushTaggedTlbBoth(pHostCpu, pVCpu, pVmcsInfo); break;
3172 case VMXTLBFLUSHTYPE_EPT: hmR0VmxFlushTaggedTlbEpt(pHostCpu, pVCpu, pVmcsInfo); break;
3173 case VMXTLBFLUSHTYPE_VPID: hmR0VmxFlushTaggedTlbVpid(pHostCpu, pVCpu); break;
3174 case VMXTLBFLUSHTYPE_NONE: hmR0VmxFlushTaggedTlbNone(pHostCpu, pVCpu); break;
3175 default:
3176 AssertMsgFailed(("Invalid flush-tag function identifier\n"));
3177 break;
3178 }
3179 /* Don't assert that VMCPU_FF_TLB_FLUSH should no longer be pending. It can be set by other EMTs. */
3180}
3181
3182
3183/**
3184 * Sets up the appropriate tagged TLB-flush level and handler for flushing guest
3185 * TLB entries from the host TLB before VM-entry.
3186 *
3187 * @returns VBox status code.
3188 * @param pVM The cross context VM structure.
3189 */
3190static int hmR0VmxSetupTaggedTlb(PVMCC pVM)
3191{
3192 /*
3193 * Determine optimal flush type for nested paging.
3194 * We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup
3195 * unrestricted guest execution (see hmR3InitFinalizeR0()).
3196 */
3197 if (pVM->hm.s.fNestedPaging)
3198 {
3199 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT)
3200 {
3201 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT)
3202 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_SINGLE_CONTEXT;
3203 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
3204 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_ALL_CONTEXTS;
3205 else
3206 {
3207 /* Shouldn't happen. EPT is supported but no suitable flush-types supported. */
3208 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3209 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED;
3210 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3211 }
3212
3213 /* Make sure the write-back cacheable memory type for EPT is supported. */
3214 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EMT_WB)))
3215 {
3216 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3217 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_MEM_TYPE_NOT_WB;
3218 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3219 }
3220
3221 /* EPT requires a page-walk length of 4. */
3222 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4)))
3223 {
3224 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3225 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED;
3226 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3227 }
3228 }
3229 else
3230 {
3231 /* Shouldn't happen. EPT is supported but INVEPT instruction is not supported. */
3232 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3233 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_INVEPT_UNAVAILABLE;
3234 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3235 }
3236 }
3237
3238 /*
3239 * Determine optimal flush type for VPID.
3240 */
3241 if (pVM->hm.s.vmx.fVpid)
3242 {
3243 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID)
3244 {
3245 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT)
3246 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_SINGLE_CONTEXT;
3247 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS)
3248 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_ALL_CONTEXTS;
3249 else
3250 {
3251 /* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
3252 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
3253 LogRelFunc(("Only INDIV_ADDR supported. Ignoring VPID.\n"));
3254 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
3255 LogRelFunc(("Only SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
3256 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3257 pVM->hm.s.vmx.fVpid = false;
3258 }
3259 }
3260 else
3261 {
3262 /* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
3263 Log4Func(("VPID supported without INVEPT support. Ignoring VPID.\n"));
3264 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3265 pVM->hm.s.vmx.fVpid = false;
3266 }
3267 }
3268
3269 /*
3270 * Setup the handler for flushing tagged-TLBs.
3271 */
3272 if (pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid)
3273 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT_VPID;
3274 else if (pVM->hm.s.fNestedPaging)
3275 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT;
3276 else if (pVM->hm.s.vmx.fVpid)
3277 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_VPID;
3278 else
3279 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_NONE;
3280 return VINF_SUCCESS;
3281}
3282
3283
3284#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3285/**
3286 * Sets up the shadow VMCS fields arrays.
3287 *
3288 * This function builds arrays of VMCS fields to sync the shadow VMCS later while
3289 * executing the guest.
3290 *
3291 * @returns VBox status code.
3292 * @param pVM The cross context VM structure.
3293 */
3294static int hmR0VmxSetupShadowVmcsFieldsArrays(PVMCC pVM)
3295{
3296 /*
3297 * Paranoia. Ensure we haven't exposed the VMWRITE-All VMX feature to the guest
3298 * when the host does not support it.
3299 */
3300 bool const fGstVmwriteAll = pVM->cpum.ro.GuestFeatures.fVmxVmwriteAll;
3301 if ( !fGstVmwriteAll
3302 || (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL))
3303 { /* likely. */ }
3304 else
3305 {
3306 LogRelFunc(("VMX VMWRITE-All feature exposed to the guest but host CPU does not support it!\n"));
3307 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_GST_HOST_VMWRITE_ALL;
3308 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3309 }
3310
3311 uint32_t const cVmcsFields = RT_ELEMENTS(g_aVmcsFields);
3312 uint32_t cRwFields = 0;
3313 uint32_t cRoFields = 0;
3314 for (uint32_t i = 0; i < cVmcsFields; i++)
3315 {
3316 VMXVMCSFIELD VmcsField;
3317 VmcsField.u = g_aVmcsFields[i];
3318
3319 /*
3320 * We will be writing "FULL" (64-bit) fields while syncing the shadow VMCS.
3321 * Therefore, "HIGH" (32-bit portion of 64-bit) fields must not be included
3322 * in the shadow VMCS fields array as they would be redundant.
3323 *
3324 * If the VMCS field depends on a CPU feature that is not exposed to the guest,
3325 * we must not include it in the shadow VMCS fields array. Guests attempting to
3326 * VMREAD/VMWRITE such VMCS fields would cause a VM-exit and we shall emulate
3327 * the required behavior.
3328 */
3329 if ( VmcsField.n.fAccessType == VMX_VMCSFIELD_ACCESS_FULL
3330 && CPUMIsGuestVmxVmcsFieldValid(pVM, VmcsField.u))
3331 {
3332 /*
3333 * Read-only fields are placed in a separate array so that while syncing shadow
3334 * VMCS fields later (which is more performance critical) we can avoid branches.
3335 *
3336 * However, if the guest can write to all fields (including read-only fields),
3337 * we treat it a as read/write field. Otherwise, writing to these fields would
3338 * cause a VMWRITE instruction error while syncing the shadow VMCS .
3339 */
3340 if ( fGstVmwriteAll
3341 || !VMXIsVmcsFieldReadOnly(VmcsField.u))
3342 pVM->hm.s.vmx.paShadowVmcsFields[cRwFields++] = VmcsField.u;
3343 else
3344 pVM->hm.s.vmx.paShadowVmcsRoFields[cRoFields++] = VmcsField.u;
3345 }
3346 }
3347
3348 /* Update the counts. */
3349 pVM->hm.s.vmx.cShadowVmcsFields = cRwFields;
3350 pVM->hm.s.vmx.cShadowVmcsRoFields = cRoFields;
3351 return VINF_SUCCESS;
3352}
3353
3354
3355/**
3356 * Sets up the VMREAD and VMWRITE bitmaps.
3357 *
3358 * @param pVM The cross context VM structure.
3359 */
3360static void hmR0VmxSetupVmreadVmwriteBitmaps(PVMCC pVM)
3361{
3362 /*
3363 * By default, ensure guest attempts to acceses to any VMCS fields cause VM-exits.
3364 */
3365 uint32_t const cbBitmap = X86_PAGE_4K_SIZE;
3366 uint8_t *pbVmreadBitmap = (uint8_t *)pVM->hm.s.vmx.pvVmreadBitmap;
3367 uint8_t *pbVmwriteBitmap = (uint8_t *)pVM->hm.s.vmx.pvVmwriteBitmap;
3368 ASMMemFill32(pbVmreadBitmap, cbBitmap, UINT32_C(0xffffffff));
3369 ASMMemFill32(pbVmwriteBitmap, cbBitmap, UINT32_C(0xffffffff));
3370
3371 /*
3372 * Skip intercepting VMREAD/VMWRITE to guest read/write fields in the
3373 * VMREAD and VMWRITE bitmaps.
3374 */
3375 {
3376 uint32_t const *paShadowVmcsFields = pVM->hm.s.vmx.paShadowVmcsFields;
3377 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
3378 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
3379 {
3380 uint32_t const uVmcsField = paShadowVmcsFields[i];
3381 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3382 Assert(uVmcsField >> 3 < cbBitmap);
3383 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3384 ASMBitClear(pbVmwriteBitmap + (uVmcsField >> 3), uVmcsField & 7);
3385 }
3386 }
3387
3388 /*
3389 * Skip intercepting VMREAD for guest read-only fields in the VMREAD bitmap
3390 * if the host supports VMWRITE to all supported VMCS fields.
3391 */
3392 if (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL)
3393 {
3394 uint32_t const *paShadowVmcsRoFields = pVM->hm.s.vmx.paShadowVmcsRoFields;
3395 uint32_t const cShadowVmcsRoFields = pVM->hm.s.vmx.cShadowVmcsRoFields;
3396 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
3397 {
3398 uint32_t const uVmcsField = paShadowVmcsRoFields[i];
3399 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3400 Assert(uVmcsField >> 3 < cbBitmap);
3401 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3402 }
3403 }
3404}
3405#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
3406
3407
3408/**
3409 * Sets up the virtual-APIC page address for the VMCS.
3410 *
3411 * @param pVmcsInfo The VMCS info. object.
3412 */
3413DECLINLINE(void) hmR0VmxSetupVmcsVirtApicAddr(PCVMXVMCSINFO pVmcsInfo)
3414{
3415 RTHCPHYS const HCPhysVirtApic = pVmcsInfo->HCPhysVirtApic;
3416 Assert(HCPhysVirtApic != NIL_RTHCPHYS);
3417 Assert(!(HCPhysVirtApic & 0xfff)); /* Bits 11:0 MBZ. */
3418 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
3419 AssertRC(rc);
3420}
3421
3422
3423/**
3424 * Sets up the MSR-bitmap address for the VMCS.
3425 *
3426 * @param pVmcsInfo The VMCS info. object.
3427 */
3428DECLINLINE(void) hmR0VmxSetupVmcsMsrBitmapAddr(PCVMXVMCSINFO pVmcsInfo)
3429{
3430 RTHCPHYS const HCPhysMsrBitmap = pVmcsInfo->HCPhysMsrBitmap;
3431 Assert(HCPhysMsrBitmap != NIL_RTHCPHYS);
3432 Assert(!(HCPhysMsrBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3433 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_MSR_BITMAP_FULL, HCPhysMsrBitmap);
3434 AssertRC(rc);
3435}
3436
3437
3438/**
3439 * Sets up the APIC-access page address for the VMCS.
3440 *
3441 * @param pVCpu The cross context virtual CPU structure.
3442 */
3443DECLINLINE(void) hmR0VmxSetupVmcsApicAccessAddr(PVMCPUCC pVCpu)
3444{
3445 RTHCPHYS const HCPhysApicAccess = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysApicAccess;
3446 Assert(HCPhysApicAccess != NIL_RTHCPHYS);
3447 Assert(!(HCPhysApicAccess & 0xfff)); /* Bits 11:0 MBZ. */
3448 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
3449 AssertRC(rc);
3450}
3451
3452
3453#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3454/**
3455 * Sets up the VMREAD bitmap address for the VMCS.
3456 *
3457 * @param pVCpu The cross context virtual CPU structure.
3458 */
3459DECLINLINE(void) hmR0VmxSetupVmcsVmreadBitmapAddr(PVMCPUCC pVCpu)
3460{
3461 RTHCPHYS const HCPhysVmreadBitmap = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysVmreadBitmap;
3462 Assert(HCPhysVmreadBitmap != NIL_RTHCPHYS);
3463 Assert(!(HCPhysVmreadBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3464 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL, HCPhysVmreadBitmap);
3465 AssertRC(rc);
3466}
3467
3468
3469/**
3470 * Sets up the VMWRITE bitmap address for the VMCS.
3471 *
3472 * @param pVCpu The cross context virtual CPU structure.
3473 */
3474DECLINLINE(void) hmR0VmxSetupVmcsVmwriteBitmapAddr(PVMCPUCC pVCpu)
3475{
3476 RTHCPHYS const HCPhysVmwriteBitmap = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysVmwriteBitmap;
3477 Assert(HCPhysVmwriteBitmap != NIL_RTHCPHYS);
3478 Assert(!(HCPhysVmwriteBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3479 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL, HCPhysVmwriteBitmap);
3480 AssertRC(rc);
3481}
3482#endif
3483
3484
3485/**
3486 * Sets up the VM-entry MSR load, VM-exit MSR-store and VM-exit MSR-load addresses
3487 * in the VMCS.
3488 *
3489 * @returns VBox status code.
3490 * @param pVmcsInfo The VMCS info. object.
3491 */
3492DECLINLINE(int) hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(PVMXVMCSINFO pVmcsInfo)
3493{
3494 RTHCPHYS const HCPhysGuestMsrLoad = pVmcsInfo->HCPhysGuestMsrLoad;
3495 Assert(HCPhysGuestMsrLoad != NIL_RTHCPHYS);
3496 Assert(!(HCPhysGuestMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3497
3498 RTHCPHYS const HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrStore;
3499 Assert(HCPhysGuestMsrStore != NIL_RTHCPHYS);
3500 Assert(!(HCPhysGuestMsrStore & 0xf)); /* Bits 3:0 MBZ. */
3501
3502 RTHCPHYS const HCPhysHostMsrLoad = pVmcsInfo->HCPhysHostMsrLoad;
3503 Assert(HCPhysHostMsrLoad != NIL_RTHCPHYS);
3504 Assert(!(HCPhysHostMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3505
3506 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL, HCPhysGuestMsrLoad); AssertRC(rc);
3507 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL, HCPhysGuestMsrStore); AssertRC(rc);
3508 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL, HCPhysHostMsrLoad); AssertRC(rc);
3509 return VINF_SUCCESS;
3510}
3511
3512
3513/**
3514 * Sets up MSR permissions in the MSR bitmap of a VMCS info. object.
3515 *
3516 * @param pVCpu The cross context virtual CPU structure.
3517 * @param pVmcsInfo The VMCS info. object.
3518 */
3519static void hmR0VmxSetupVmcsMsrPermissions(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3520{
3521 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS);
3522
3523 /*
3524 * The guest can access the following MSRs (read, write) without causing
3525 * VM-exits; they are loaded/stored automatically using fields in the VMCS.
3526 */
3527 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3528 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_CS, VMXMSRPM_ALLOW_RD_WR);
3529 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_ESP, VMXMSRPM_ALLOW_RD_WR);
3530 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_EIP, VMXMSRPM_ALLOW_RD_WR);
3531 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3532 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_FS_BASE, VMXMSRPM_ALLOW_RD_WR);
3533
3534 /*
3535 * The IA32_PRED_CMD and IA32_FLUSH_CMD MSRs are write-only and has no state
3536 * associated with then. We never need to intercept access (writes need to be
3537 * executed without causing a VM-exit, reads will #GP fault anyway).
3538 *
3539 * The IA32_SPEC_CTRL MSR is read/write and has state. We allow the guest to
3540 * read/write them. We swap the the guest/host MSR value using the
3541 * auto-load/store MSR area.
3542 */
3543 if (pVM->cpum.ro.GuestFeatures.fIbpb)
3544 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_PRED_CMD, VMXMSRPM_ALLOW_RD_WR);
3545 if (pVM->cpum.ro.GuestFeatures.fFlushCmd)
3546 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_FLUSH_CMD, VMXMSRPM_ALLOW_RD_WR);
3547 if (pVM->cpum.ro.GuestFeatures.fIbrs)
3548 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SPEC_CTRL, VMXMSRPM_ALLOW_RD_WR);
3549
3550 /*
3551 * Allow full read/write access for the following MSRs (mandatory for VT-x)
3552 * required for 64-bit guests.
3553 */
3554 if (pVM->hm.s.fAllow64BitGuests)
3555 {
3556 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_LSTAR, VMXMSRPM_ALLOW_RD_WR);
3557 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K6_STAR, VMXMSRPM_ALLOW_RD_WR);
3558 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_SF_MASK, VMXMSRPM_ALLOW_RD_WR);
3559 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_KERNEL_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3560 }
3561
3562 /*
3563 * IA32_EFER MSR is always intercepted, see @bugref{9180#c37}.
3564 */
3565#ifdef VBOX_STRICT
3566 Assert(pVmcsInfo->pvMsrBitmap);
3567 uint32_t const fMsrpmEfer = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, MSR_K6_EFER);
3568 Assert(fMsrpmEfer == VMXMSRPM_EXIT_RD_WR);
3569#endif
3570}
3571
3572
3573/**
3574 * Sets up pin-based VM-execution controls in the VMCS.
3575 *
3576 * @returns VBox status code.
3577 * @param pVCpu The cross context virtual CPU structure.
3578 * @param pVmcsInfo The VMCS info. object.
3579 */
3580static int hmR0VmxSetupVmcsPinCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3581{
3582 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3583 uint32_t fVal = pVM->hm.s.vmx.Msrs.PinCtls.n.allowed0; /* Bits set here must always be set. */
3584 uint32_t const fZap = pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
3585
3586 fVal |= VMX_PIN_CTLS_EXT_INT_EXIT /* External interrupts cause a VM-exit. */
3587 | VMX_PIN_CTLS_NMI_EXIT; /* Non-maskable interrupts (NMIs) cause a VM-exit. */
3588
3589 if (pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1 & VMX_PIN_CTLS_VIRT_NMI)
3590 fVal |= VMX_PIN_CTLS_VIRT_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
3591
3592 /* Enable the VMX-preemption timer. */
3593 if (pVM->hm.s.vmx.fUsePreemptTimer)
3594 {
3595 Assert(pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1 & VMX_PIN_CTLS_PREEMPT_TIMER);
3596 fVal |= VMX_PIN_CTLS_PREEMPT_TIMER;
3597 }
3598
3599#if 0
3600 /* Enable posted-interrupt processing. */
3601 if (pVM->hm.s.fPostedIntrs)
3602 {
3603 Assert(pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1 & VMX_PIN_CTLS_POSTED_INT);
3604 Assert(pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_ACK_EXT_INT);
3605 fVal |= VMX_PIN_CTLS_POSTED_INT;
3606 }
3607#endif
3608
3609 if ((fVal & fZap) != fVal)
3610 {
3611 LogRelFunc(("Invalid pin-based VM-execution controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3612 pVM->hm.s.vmx.Msrs.PinCtls.n.allowed0, fVal, fZap));
3613 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
3614 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3615 }
3616
3617 /* Commit it to the VMCS and update our cache. */
3618 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, fVal);
3619 AssertRC(rc);
3620 pVmcsInfo->u32PinCtls = fVal;
3621
3622 return VINF_SUCCESS;
3623}
3624
3625
3626/**
3627 * Sets up secondary processor-based VM-execution controls in the VMCS.
3628 *
3629 * @returns VBox status code.
3630 * @param pVCpu The cross context virtual CPU structure.
3631 * @param pVmcsInfo The VMCS info. object.
3632 */
3633static int hmR0VmxSetupVmcsProcCtls2(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3634{
3635 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3636 uint32_t fVal = pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed0; /* Bits set here must be set in the VMCS. */
3637 uint32_t const fZap = pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3638
3639 /* WBINVD causes a VM-exit. */
3640 if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_WBINVD_EXIT)
3641 fVal |= VMX_PROC_CTLS2_WBINVD_EXIT;
3642
3643 /* Enable EPT (aka nested-paging). */
3644 if (pVM->hm.s.fNestedPaging)
3645 fVal |= VMX_PROC_CTLS2_EPT;
3646
3647 /* Enable the INVPCID instruction if we expose it to the guest and is supported
3648 by the hardware. Without this, guest executing INVPCID would cause a #UD. */
3649 if ( pVM->cpum.ro.GuestFeatures.fInvpcid
3650 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_INVPCID))
3651 fVal |= VMX_PROC_CTLS2_INVPCID;
3652
3653 /* Enable VPID. */
3654 if (pVM->hm.s.vmx.fVpid)
3655 fVal |= VMX_PROC_CTLS2_VPID;
3656
3657 /* Enable unrestricted guest execution. */
3658 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3659 fVal |= VMX_PROC_CTLS2_UNRESTRICTED_GUEST;
3660
3661#if 0
3662 if (pVM->hm.s.fVirtApicRegs)
3663 {
3664 /* Enable APIC-register virtualization. */
3665 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_APIC_REG_VIRT);
3666 fVal |= VMX_PROC_CTLS2_APIC_REG_VIRT;
3667
3668 /* Enable virtual-interrupt delivery. */
3669 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_INTR_DELIVERY);
3670 fVal |= VMX_PROC_CTLS2_VIRT_INTR_DELIVERY;
3671 }
3672#endif
3673
3674 /* Virtualize-APIC accesses if supported by the CPU. The virtual-APIC page is
3675 where the TPR shadow resides. */
3676 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
3677 * done dynamically. */
3678 if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
3679 {
3680 fVal |= VMX_PROC_CTLS2_VIRT_APIC_ACCESS;
3681 hmR0VmxSetupVmcsApicAccessAddr(pVCpu);
3682 }
3683
3684 /* Enable the RDTSCP instruction if we expose it to the guest and is supported
3685 by the hardware. Without this, guest executing RDTSCP would cause a #UD. */
3686 if ( pVM->cpum.ro.GuestFeatures.fRdTscP
3687 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_RDTSCP))
3688 fVal |= VMX_PROC_CTLS2_RDTSCP;
3689
3690 /* Enable Pause-Loop exiting. */
3691 if ( (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)
3692 && pVM->hm.s.vmx.cPleGapTicks
3693 && pVM->hm.s.vmx.cPleWindowTicks)
3694 {
3695 fVal |= VMX_PROC_CTLS2_PAUSE_LOOP_EXIT;
3696
3697 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, pVM->hm.s.vmx.cPleGapTicks); AssertRC(rc);
3698 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, pVM->hm.s.vmx.cPleWindowTicks); AssertRC(rc);
3699 }
3700
3701 if ((fVal & fZap) != fVal)
3702 {
3703 LogRelFunc(("Invalid secondary processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3704 pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed0, fVal, fZap));
3705 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
3706 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3707 }
3708
3709 /* Commit it to the VMCS and update our cache. */
3710 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, fVal);
3711 AssertRC(rc);
3712 pVmcsInfo->u32ProcCtls2 = fVal;
3713
3714 return VINF_SUCCESS;
3715}
3716
3717
3718/**
3719 * Sets up processor-based VM-execution controls in the VMCS.
3720 *
3721 * @returns VBox status code.
3722 * @param pVCpu The cross context virtual CPU structure.
3723 * @param pVmcsInfo The VMCS info. object.
3724 */
3725static int hmR0VmxSetupVmcsProcCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3726{
3727 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3728
3729 uint32_t fVal = pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
3730 uint32_t const fZap = pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3731
3732 fVal |= VMX_PROC_CTLS_HLT_EXIT /* HLT causes a VM-exit. */
3733 | VMX_PROC_CTLS_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
3734 | VMX_PROC_CTLS_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
3735 | VMX_PROC_CTLS_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
3736 | VMX_PROC_CTLS_RDPMC_EXIT /* RDPMC causes a VM-exit. */
3737 | VMX_PROC_CTLS_MONITOR_EXIT /* MONITOR causes a VM-exit. */
3738 | VMX_PROC_CTLS_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
3739
3740 /* We toggle VMX_PROC_CTLS_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
3741 if ( !(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MOV_DR_EXIT)
3742 || (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0 & VMX_PROC_CTLS_MOV_DR_EXIT))
3743 {
3744 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
3745 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3746 }
3747
3748 /* Without nested paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
3749 if (!pVM->hm.s.fNestedPaging)
3750 {
3751 Assert(!pVM->hm.s.vmx.fUnrestrictedGuest);
3752 fVal |= VMX_PROC_CTLS_INVLPG_EXIT
3753 | VMX_PROC_CTLS_CR3_LOAD_EXIT
3754 | VMX_PROC_CTLS_CR3_STORE_EXIT;
3755 }
3756
3757 /* Use TPR shadowing if supported by the CPU. */
3758 if ( PDMHasApic(pVM)
3759 && pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW)
3760 {
3761 fVal |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
3762 /* CR8 writes cause a VM-exit based on TPR threshold. */
3763 Assert(!(fVal & VMX_PROC_CTLS_CR8_STORE_EXIT));
3764 Assert(!(fVal & VMX_PROC_CTLS_CR8_LOAD_EXIT));
3765 hmR0VmxSetupVmcsVirtApicAddr(pVmcsInfo);
3766 }
3767 else
3768 {
3769 /* Some 32-bit CPUs do not support CR8 load/store exiting as MOV CR8 is
3770 invalid on 32-bit Intel CPUs. Set this control only for 64-bit guests. */
3771 if (pVM->hm.s.fAllow64BitGuests)
3772 {
3773 fVal |= VMX_PROC_CTLS_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
3774 | VMX_PROC_CTLS_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
3775 }
3776 }
3777
3778 /* Use MSR-bitmaps if supported by the CPU. */
3779 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
3780 {
3781 fVal |= VMX_PROC_CTLS_USE_MSR_BITMAPS;
3782 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
3783 }
3784
3785 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
3786 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
3787 fVal |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
3788
3789 if ((fVal & fZap) != fVal)
3790 {
3791 LogRelFunc(("Invalid processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3792 pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0, fVal, fZap));
3793 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
3794 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3795 }
3796
3797 /* Commit it to the VMCS and update our cache. */
3798 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, fVal);
3799 AssertRC(rc);
3800 pVmcsInfo->u32ProcCtls = fVal;
3801
3802 /* Set up MSR permissions that don't change through the lifetime of the VM. */
3803 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
3804 hmR0VmxSetupVmcsMsrPermissions(pVCpu, pVmcsInfo);
3805
3806 /* Set up secondary processor-based VM-execution controls if the CPU supports it. */
3807 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
3808 return hmR0VmxSetupVmcsProcCtls2(pVCpu, pVmcsInfo);
3809
3810 /* Sanity check, should not really happen. */
3811 if (RT_LIKELY(!pVM->hm.s.vmx.fUnrestrictedGuest))
3812 { /* likely */ }
3813 else
3814 {
3815 pVCpu->hm.s.u32HMError = VMX_UFC_INVALID_UX_COMBO;
3816 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3817 }
3818
3819 /* Old CPUs without secondary processor-based VM-execution controls would end up here. */
3820 return VINF_SUCCESS;
3821}
3822
3823
3824/**
3825 * Sets up miscellaneous (everything other than Pin, Processor and secondary
3826 * Processor-based VM-execution) control fields in the VMCS.
3827 *
3828 * @returns VBox status code.
3829 * @param pVCpu The cross context virtual CPU structure.
3830 * @param pVmcsInfo The VMCS info. object.
3831 */
3832static int hmR0VmxSetupVmcsMiscCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3833{
3834#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3835 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
3836 {
3837 hmR0VmxSetupVmcsVmreadBitmapAddr(pVCpu);
3838 hmR0VmxSetupVmcsVmwriteBitmapAddr(pVCpu);
3839 }
3840#endif
3841
3842 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
3843 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
3844 AssertRC(rc);
3845
3846 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
3847 if (RT_SUCCESS(rc))
3848 {
3849 uint64_t const u64Cr0Mask = hmR0VmxGetFixedCr0Mask(pVCpu);
3850 uint64_t const u64Cr4Mask = hmR0VmxGetFixedCr4Mask(pVCpu);
3851
3852 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask); AssertRC(rc);
3853 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask); AssertRC(rc);
3854
3855 pVmcsInfo->u64Cr0Mask = u64Cr0Mask;
3856 pVmcsInfo->u64Cr4Mask = u64Cr4Mask;
3857 return VINF_SUCCESS;
3858 }
3859 else
3860 LogRelFunc(("Failed to initialize VMCS auto-load/store MSR addresses. rc=%Rrc\n", rc));
3861 return rc;
3862}
3863
3864
3865/**
3866 * Sets up the initial exception bitmap in the VMCS based on static conditions.
3867 *
3868 * We shall setup those exception intercepts that don't change during the
3869 * lifetime of the VM here. The rest are done dynamically while loading the
3870 * guest state.
3871 *
3872 * @param pVCpu The cross context virtual CPU structure.
3873 * @param pVmcsInfo The VMCS info. object.
3874 */
3875static void hmR0VmxSetupVmcsXcptBitmap(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3876{
3877 /*
3878 * The following exceptions are always intercepted:
3879 *
3880 * #AC - To prevent the guest from hanging the CPU.
3881 * #DB - To maintain the DR6 state even when intercepting DRx reads/writes and
3882 * recursive #DBs can cause a CPU hang.
3883 * #PF - To sync our shadow page tables when nested-paging is not used.
3884 */
3885 bool const fNestedPaging = pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging;
3886 uint32_t const uXcptBitmap = RT_BIT(X86_XCPT_AC)
3887 | RT_BIT(X86_XCPT_DB)
3888 | (fNestedPaging ? 0 : RT_BIT(X86_XCPT_PF));
3889
3890 /* Commit it to the VMCS. */
3891 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
3892 AssertRC(rc);
3893
3894 /* Update our cache of the exception bitmap. */
3895 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
3896}
3897
3898
3899#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3900/**
3901 * Sets up the VMCS for executing a nested-guest using hardware-assisted VMX.
3902 *
3903 * @returns VBox status code.
3904 * @param pVCpu The cross context virtual CPU structure.
3905 * @param pVmcsInfo The VMCS info. object.
3906 */
3907static int hmR0VmxSetupVmcsCtlsNested(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3908{
3909 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
3910 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
3911 AssertRC(rc);
3912
3913 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
3914 if (RT_SUCCESS(rc))
3915 {
3916 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
3917 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
3918 return VINF_SUCCESS;
3919 }
3920 else
3921 LogRelFunc(("Failed to set up the VMCS link pointer in the nested-guest VMCS. rc=%Rrc\n", rc));
3922 return rc;
3923}
3924#endif
3925
3926
3927/**
3928 * Sets up the VMCS for executing a guest (or nested-guest) using hardware-assisted
3929 * VMX.
3930 *
3931 * @returns VBox status code.
3932 * @param pVCpu The cross context virtual CPU structure.
3933 * @param pVmcsInfo The VMCS info. object.
3934 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
3935 */
3936static int hmR0VmxSetupVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
3937{
3938 Assert(pVmcsInfo->pvVmcs);
3939 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
3940
3941 /* Set the CPU specified revision identifier at the beginning of the VMCS structure. */
3942 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3943 *(uint32_t *)pVmcsInfo->pvVmcs = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
3944 const char * const pszVmcs = fIsNstGstVmcs ? "nested-guest VMCS" : "guest VMCS";
3945
3946 LogFlowFunc(("\n"));
3947
3948 /*
3949 * Initialize the VMCS using VMCLEAR before loading the VMCS.
3950 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
3951 */
3952 int rc = hmR0VmxClearVmcs(pVmcsInfo);
3953 if (RT_SUCCESS(rc))
3954 {
3955 rc = hmR0VmxLoadVmcs(pVmcsInfo);
3956 if (RT_SUCCESS(rc))
3957 {
3958 if (!fIsNstGstVmcs)
3959 {
3960 rc = hmR0VmxSetupVmcsPinCtls(pVCpu, pVmcsInfo);
3961 if (RT_SUCCESS(rc))
3962 {
3963 rc = hmR0VmxSetupVmcsProcCtls(pVCpu, pVmcsInfo);
3964 if (RT_SUCCESS(rc))
3965 {
3966 rc = hmR0VmxSetupVmcsMiscCtls(pVCpu, pVmcsInfo);
3967 if (RT_SUCCESS(rc))
3968 {
3969 hmR0VmxSetupVmcsXcptBitmap(pVCpu, pVmcsInfo);
3970#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3971 /*
3972 * If a shadow VMCS is allocated for the VMCS info. object, initialize the
3973 * VMCS revision ID and shadow VMCS indicator bit. Also, clear the VMCS
3974 * making it fit for use when VMCS shadowing is later enabled.
3975 */
3976 if (pVmcsInfo->pvShadowVmcs)
3977 {
3978 VMXVMCSREVID VmcsRevId;
3979 VmcsRevId.u = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
3980 VmcsRevId.n.fIsShadowVmcs = 1;
3981 *(uint32_t *)pVmcsInfo->pvShadowVmcs = VmcsRevId.u;
3982 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
3983 if (RT_SUCCESS(rc))
3984 { /* likely */ }
3985 else
3986 LogRelFunc(("Failed to initialize shadow VMCS. rc=%Rrc\n", rc));
3987 }
3988#endif
3989 }
3990 else
3991 LogRelFunc(("Failed to setup miscellaneous controls. rc=%Rrc\n", rc));
3992 }
3993 else
3994 LogRelFunc(("Failed to setup processor-based VM-execution controls. rc=%Rrc\n", rc));
3995 }
3996 else
3997 LogRelFunc(("Failed to setup pin-based controls. rc=%Rrc\n", rc));
3998 }
3999 else
4000 {
4001#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4002 rc = hmR0VmxSetupVmcsCtlsNested(pVCpu, pVmcsInfo);
4003 if (RT_SUCCESS(rc))
4004 { /* likely */ }
4005 else
4006 LogRelFunc(("Failed to initialize nested-guest VMCS. rc=%Rrc\n", rc));
4007#else
4008 AssertFailed();
4009#endif
4010 }
4011 }
4012 else
4013 LogRelFunc(("Failed to load the %s. rc=%Rrc\n", rc, pszVmcs));
4014 }
4015 else
4016 LogRelFunc(("Failed to clear the %s. rc=%Rrc\n", rc, pszVmcs));
4017
4018 /* Sync any CPU internal VMCS data back into our VMCS in memory. */
4019 if (RT_SUCCESS(rc))
4020 {
4021 rc = hmR0VmxClearVmcs(pVmcsInfo);
4022 if (RT_SUCCESS(rc))
4023 { /* likely */ }
4024 else
4025 LogRelFunc(("Failed to clear the %s post setup. rc=%Rrc\n", rc, pszVmcs));
4026 }
4027
4028 /*
4029 * Update the last-error record both for failures and success, so we
4030 * can propagate the status code back to ring-3 for diagnostics.
4031 */
4032 hmR0VmxUpdateErrorRecord(pVCpu, rc);
4033 NOREF(pszVmcs);
4034 return rc;
4035}
4036
4037
4038/**
4039 * Does global VT-x initialization (called during module initialization).
4040 *
4041 * @returns VBox status code.
4042 */
4043VMMR0DECL(int) VMXR0GlobalInit(void)
4044{
4045#ifdef HMVMX_USE_FUNCTION_TABLE
4046 AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(g_apfnVMExitHandlers));
4047# ifdef VBOX_STRICT
4048 for (unsigned i = 0; i < RT_ELEMENTS(g_apfnVMExitHandlers); i++)
4049 Assert(g_apfnVMExitHandlers[i]);
4050# endif
4051#endif
4052 return VINF_SUCCESS;
4053}
4054
4055
4056/**
4057 * Does global VT-x termination (called during module termination).
4058 */
4059VMMR0DECL(void) VMXR0GlobalTerm()
4060{
4061 /* Nothing to do currently. */
4062}
4063
4064
4065/**
4066 * Sets up and activates VT-x on the current CPU.
4067 *
4068 * @returns VBox status code.
4069 * @param pHostCpu The HM physical-CPU structure.
4070 * @param pVM The cross context VM structure. Can be
4071 * NULL after a host resume operation.
4072 * @param pvCpuPage Pointer to the VMXON region (can be NULL if @a
4073 * fEnabledByHost is @c true).
4074 * @param HCPhysCpuPage Physical address of the VMXON region (can be 0 if
4075 * @a fEnabledByHost is @c true).
4076 * @param fEnabledByHost Set if SUPR0EnableVTx() or similar was used to
4077 * enable VT-x on the host.
4078 * @param pHwvirtMsrs Pointer to the hardware-virtualization MSRs.
4079 */
4080VMMR0DECL(int) VMXR0EnableCpu(PHMPHYSCPU pHostCpu, PVMCC pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost,
4081 PCSUPHWVIRTMSRS pHwvirtMsrs)
4082{
4083 AssertPtr(pHostCpu);
4084 AssertPtr(pHwvirtMsrs);
4085 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4086
4087 /* Enable VT-x if it's not already enabled by the host. */
4088 if (!fEnabledByHost)
4089 {
4090 int rc = hmR0VmxEnterRootMode(pVM, HCPhysCpuPage, pvCpuPage);
4091 if (RT_FAILURE(rc))
4092 return rc;
4093 }
4094
4095 /*
4096 * Flush all EPT tagged-TLB entries (in case VirtualBox or any other hypervisor have been
4097 * using EPTPs) so we don't retain any stale guest-physical mappings which won't get
4098 * invalidated when flushing by VPID.
4099 */
4100 if (pHwvirtMsrs->u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
4101 {
4102 hmR0VmxFlushEpt(NULL /* pVCpu */, NULL /* pVmcsInfo */, VMXTLBFLUSHEPT_ALL_CONTEXTS);
4103 pHostCpu->fFlushAsidBeforeUse = false;
4104 }
4105 else
4106 pHostCpu->fFlushAsidBeforeUse = true;
4107
4108 /* Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}. */
4109 ++pHostCpu->cTlbFlushes;
4110
4111 return VINF_SUCCESS;
4112}
4113
4114
4115/**
4116 * Deactivates VT-x on the current CPU.
4117 *
4118 * @returns VBox status code.
4119 * @param pvCpuPage Pointer to the VMXON region.
4120 * @param HCPhysCpuPage Physical address of the VMXON region.
4121 *
4122 * @remarks This function should never be called when SUPR0EnableVTx() or
4123 * similar was used to enable VT-x on the host.
4124 */
4125VMMR0DECL(int) VMXR0DisableCpu(void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
4126{
4127 RT_NOREF2(pvCpuPage, HCPhysCpuPage);
4128
4129 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4130 return hmR0VmxLeaveRootMode();
4131}
4132
4133
4134/**
4135 * Does per-VM VT-x initialization.
4136 *
4137 * @returns VBox status code.
4138 * @param pVM The cross context VM structure.
4139 */
4140VMMR0DECL(int) VMXR0InitVM(PVMCC pVM)
4141{
4142 AssertPtr(pVM);
4143 LogFlowFunc(("pVM=%p\n", pVM));
4144
4145 int rc = hmR0VmxStructsAlloc(pVM);
4146 if (RT_FAILURE(rc))
4147 {
4148 LogRelFunc(("Failed to allocated VMX structures. rc=%Rrc\n", rc));
4149 return rc;
4150 }
4151
4152 return VINF_SUCCESS;
4153}
4154
4155
4156/**
4157 * Does per-VM VT-x termination.
4158 *
4159 * @returns VBox status code.
4160 * @param pVM The cross context VM structure.
4161 */
4162VMMR0DECL(int) VMXR0TermVM(PVMCC pVM)
4163{
4164 AssertPtr(pVM);
4165 LogFlowFunc(("pVM=%p\n", pVM));
4166
4167#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4168 if (pVM->hm.s.vmx.hMemObjScratch != NIL_RTR0MEMOBJ)
4169 {
4170 Assert(pVM->hm.s.vmx.pvScratch);
4171 ASMMemZero32(pVM->hm.s.vmx.pvScratch, X86_PAGE_4K_SIZE);
4172 }
4173#endif
4174 hmR0VmxStructsFree(pVM);
4175 return VINF_SUCCESS;
4176}
4177
4178
4179/**
4180 * Sets up the VM for execution using hardware-assisted VMX.
4181 * This function is only called once per-VM during initialization.
4182 *
4183 * @returns VBox status code.
4184 * @param pVM The cross context VM structure.
4185 */
4186VMMR0DECL(int) VMXR0SetupVM(PVMCC pVM)
4187{
4188 AssertPtr(pVM);
4189 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4190
4191 LogFlowFunc(("pVM=%p\n", pVM));
4192
4193 /*
4194 * At least verify if VMX is enabled, since we can't check if we're in
4195 * VMX root mode or not without causing a #GP.
4196 */
4197 RTCCUINTREG const uHostCr4 = ASMGetCR4();
4198 if (RT_LIKELY(uHostCr4 & X86_CR4_VMXE))
4199 { /* likely */ }
4200 else
4201 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
4202
4203 /*
4204 * Without unrestricted guest execution, pRealModeTSS and pNonPagingModeEPTPageTable *must*
4205 * always be allocated. We no longer support the highly unlikely case of unrestricted guest
4206 * without pRealModeTSS, see hmR3InitFinalizeR0Intel().
4207 */
4208 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
4209 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
4210 || !pVM->hm.s.vmx.pRealModeTSS))
4211 {
4212 LogRelFunc(("Invalid real-on-v86 state.\n"));
4213 return VERR_INTERNAL_ERROR;
4214 }
4215
4216 /* Initialize these always, see hmR3InitFinalizeR0().*/
4217 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NONE;
4218 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NONE;
4219
4220 /* Setup the tagged-TLB flush handlers. */
4221 int rc = hmR0VmxSetupTaggedTlb(pVM);
4222 if (RT_FAILURE(rc))
4223 {
4224 LogRelFunc(("Failed to setup tagged TLB. rc=%Rrc\n", rc));
4225 return rc;
4226 }
4227
4228#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4229 /* Setup the shadow VMCS fields array and VMREAD/VMWRITE bitmaps. */
4230 if (pVM->hm.s.vmx.fUseVmcsShadowing)
4231 {
4232 rc = hmR0VmxSetupShadowVmcsFieldsArrays(pVM);
4233 if (RT_SUCCESS(rc))
4234 hmR0VmxSetupVmreadVmwriteBitmaps(pVM);
4235 else
4236 {
4237 LogRelFunc(("Failed to setup shadow VMCS fields arrays. rc=%Rrc\n", rc));
4238 return rc;
4239 }
4240 }
4241#endif
4242
4243 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
4244 {
4245 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
4246 Log4Func(("pVCpu=%p idCpu=%RU32\n", pVCpu, pVCpu->idCpu));
4247
4248 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hm.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
4249 if (RT_SUCCESS(rc))
4250 {
4251#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4252 if (pVM->cpum.ro.GuestFeatures.fVmx)
4253 {
4254 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hm.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
4255 if (RT_SUCCESS(rc))
4256 { /* likely */ }
4257 else
4258 {
4259 LogRelFunc(("Nested-guest VMCS setup failed. rc=%Rrc\n", rc));
4260 return rc;
4261 }
4262 }
4263#endif
4264 }
4265 else
4266 {
4267 LogRelFunc(("VMCS setup failed. rc=%Rrc\n", rc));
4268 return rc;
4269 }
4270 }
4271
4272 return VINF_SUCCESS;
4273}
4274
4275
4276/**
4277 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
4278 * the VMCS.
4279 */
4280static void hmR0VmxExportHostControlRegs(void)
4281{
4282 int rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR0, ASMGetCR0()); AssertRC(rc);
4283 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR3, ASMGetCR3()); AssertRC(rc);
4284 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR4, ASMGetCR4()); AssertRC(rc);
4285}
4286
4287
4288/**
4289 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
4290 * the host-state area in the VMCS.
4291 *
4292 * @returns VBox status code.
4293 * @param pVCpu The cross context virtual CPU structure.
4294 */
4295static int hmR0VmxExportHostSegmentRegs(PVMCPUCC pVCpu)
4296{
4297/**
4298 * Macro for adjusting host segment selectors to satisfy VT-x's VM-entry
4299 * requirements. See hmR0VmxExportHostSegmentRegs().
4300 */
4301#define VMXLOCAL_ADJUST_HOST_SEG(a_Seg, a_selValue) \
4302 if ((a_selValue) & (X86_SEL_RPL | X86_SEL_LDT)) \
4303 { \
4304 bool fValidSelector = true; \
4305 if ((a_selValue) & X86_SEL_LDT) \
4306 { \
4307 uint32_t const uAttr = ASMGetSegAttr(a_selValue); \
4308 fValidSelector = RT_BOOL(uAttr != UINT32_MAX && (uAttr & X86_DESC_P)); \
4309 } \
4310 if (fValidSelector) \
4311 { \
4312 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4313 pVCpu->hm.s.vmx.RestoreHost.uHostSel##a_Seg = (a_selValue); \
4314 } \
4315 (a_selValue) = 0; \
4316 }
4317
4318 /*
4319 * If we've executed guest code using hardware-assisted VMX, the host-state bits
4320 * will be messed up. We should -not- save the messed up state without restoring
4321 * the original host-state, see @bugref{7240}.
4322 *
4323 * This apparently can happen (most likely the FPU changes), deal with it rather than
4324 * asserting. Was observed booting Solaris 10u10 32-bit guest.
4325 */
4326 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
4327 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
4328 {
4329 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags,
4330 pVCpu->idCpu));
4331 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
4332 }
4333 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
4334
4335 /*
4336 * Host segment registers.
4337 */
4338 RTSEL uSelES = ASMGetES();
4339 RTSEL uSelCS = ASMGetCS();
4340 RTSEL uSelSS = ASMGetSS();
4341 RTSEL uSelDS = ASMGetDS();
4342 RTSEL uSelFS = ASMGetFS();
4343 RTSEL uSelGS = ASMGetGS();
4344 RTSEL uSelTR = ASMGetTR();
4345
4346 /*
4347 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to
4348 * gain VM-entry and restore them before we get preempted.
4349 *
4350 * See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
4351 */
4352 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
4353 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
4354 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
4355 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
4356
4357 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
4358 Assert(!(uSelCS & X86_SEL_RPL)); Assert(!(uSelCS & X86_SEL_LDT));
4359 Assert(!(uSelSS & X86_SEL_RPL)); Assert(!(uSelSS & X86_SEL_LDT));
4360 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
4361 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
4362 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
4363 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
4364 Assert(!(uSelTR & X86_SEL_RPL)); Assert(!(uSelTR & X86_SEL_LDT));
4365 Assert(uSelCS);
4366 Assert(uSelTR);
4367
4368 /* Write these host selector fields into the host-state area in the VMCS. */
4369 int rc = VMXWriteVmcs16(VMX_VMCS16_HOST_CS_SEL, uSelCS); AssertRC(rc);
4370 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_SS_SEL, uSelSS); AssertRC(rc);
4371 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_DS_SEL, uSelDS); AssertRC(rc);
4372 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_ES_SEL, uSelES); AssertRC(rc);
4373 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_FS_SEL, uSelFS); AssertRC(rc);
4374 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_GS_SEL, uSelGS); AssertRC(rc);
4375 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_TR_SEL, uSelTR); AssertRC(rc);
4376
4377 /*
4378 * Host GDTR and IDTR.
4379 */
4380 RTGDTR Gdtr;
4381 RTIDTR Idtr;
4382 RT_ZERO(Gdtr);
4383 RT_ZERO(Idtr);
4384 ASMGetGDTR(&Gdtr);
4385 ASMGetIDTR(&Idtr);
4386 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GDTR_BASE, Gdtr.pGdt); AssertRC(rc);
4387 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_IDTR_BASE, Idtr.pIdt); AssertRC(rc);
4388
4389 /*
4390 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps
4391 * them to the maximum limit (0xffff) on every VM-exit.
4392 */
4393 if (Gdtr.cbGdt != 0xffff)
4394 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
4395
4396 /*
4397 * IDT limit is effectively capped at 0xfff. (See Intel spec. 6.14.1 "64-Bit Mode IDT" and
4398 * Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit
4399 * as 0xfff, VT-x bloating the limit to 0xffff shouldn't cause any different CPU behavior.
4400 * However, several hosts either insists on 0xfff being the limit (Windows Patch Guard) or
4401 * uses the limit for other purposes (darwin puts the CPU ID in there but botches sidt
4402 * alignment in at least one consumer). So, we're only allowing the IDTR.LIMIT to be left
4403 * at 0xffff on hosts where we are sure it won't cause trouble.
4404 */
4405#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
4406 if (Idtr.cbIdt < 0x0fff)
4407#else
4408 if (Idtr.cbIdt != 0xffff)
4409#endif
4410 {
4411 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
4412 AssertCompile(sizeof(Idtr) == sizeof(X86XDTR64));
4413 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostIdtr, &Idtr, sizeof(X86XDTR64));
4414 }
4415
4416 /*
4417 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI
4418 * and RPL bits is effectively what the CPU does for "scaling by 8". TI is always 0 and
4419 * RPL should be too in most cases.
4420 */
4421 AssertMsgReturn((uSelTR | X86_SEL_RPL_LDT) <= Gdtr.cbGdt,
4422 ("TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, Gdtr.cbGdt), VERR_VMX_INVALID_HOST_STATE);
4423
4424 PCX86DESCHC pDesc = (PCX86DESCHC)(Gdtr.pGdt + (uSelTR & X86_SEL_MASK));
4425 uintptr_t const uTRBase = X86DESC64_BASE(pDesc);
4426
4427 /*
4428 * VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on
4429 * all VM-exits. The type is the same for 64-bit busy TSS[1]. The limit needs manual
4430 * restoration if the host has something else. Task switching is not supported in 64-bit
4431 * mode[2], but the limit still matters as IOPM is supported in 64-bit mode. Restoring the
4432 * limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
4433 *
4434 * [1] See Intel spec. 3.5 "System Descriptor Types".
4435 * [2] See Intel spec. 7.2.3 "TSS Descriptor in 64-bit mode".
4436 */
4437 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4438 Assert(pDesc->System.u4Type == 11);
4439 if ( pDesc->System.u16LimitLow != 0x67
4440 || pDesc->System.u4LimitHigh)
4441 {
4442 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_TR;
4443 /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */
4444 if (pVM->hm.s.fHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY)
4445 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY;
4446 pVCpu->hm.s.vmx.RestoreHost.uHostSelTR = uSelTR;
4447 }
4448
4449 /*
4450 * Store the GDTR as we need it when restoring the GDT and while restoring the TR.
4451 */
4452 if (pVCpu->hm.s.vmx.fRestoreHostFlags & (VMX_RESTORE_HOST_GDTR | VMX_RESTORE_HOST_SEL_TR))
4453 {
4454 AssertCompile(sizeof(Gdtr) == sizeof(X86XDTR64));
4455 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
4456 if (pVM->hm.s.fHostKernelFeatures & SUPKERNELFEATURES_GDT_NEED_WRITABLE)
4457 {
4458 /* The GDT is read-only but the writable GDT is available. */
4459 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_NEED_WRITABLE;
4460 pVCpu->hm.s.vmx.RestoreHost.HostGdtrRw.cb = Gdtr.cbGdt;
4461 rc = SUPR0GetCurrentGdtRw(&pVCpu->hm.s.vmx.RestoreHost.HostGdtrRw.uAddr);
4462 AssertRCReturn(rc, rc);
4463 }
4464 }
4465
4466 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_TR_BASE, uTRBase);
4467 AssertRC(rc);
4468
4469 /*
4470 * Host FS base and GS base.
4471 */
4472 uint64_t const u64FSBase = ASMRdMsr(MSR_K8_FS_BASE);
4473 uint64_t const u64GSBase = ASMRdMsr(MSR_K8_GS_BASE);
4474 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_FS_BASE, u64FSBase); AssertRC(rc);
4475 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GS_BASE, u64GSBase); AssertRC(rc);
4476
4477 /* Store the base if we have to restore FS or GS manually as we need to restore the base as well. */
4478 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_FS)
4479 pVCpu->hm.s.vmx.RestoreHost.uHostFSBase = u64FSBase;
4480 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_GS)
4481 pVCpu->hm.s.vmx.RestoreHost.uHostGSBase = u64GSBase;
4482
4483 return VINF_SUCCESS;
4484#undef VMXLOCAL_ADJUST_HOST_SEG
4485}
4486
4487
4488/**
4489 * Exports certain host MSRs in the VM-exit MSR-load area and some in the
4490 * host-state area of the VMCS.
4491 *
4492 * These MSRs will be automatically restored on the host after every successful
4493 * VM-exit.
4494 *
4495 * @param pVCpu The cross context virtual CPU structure.
4496 *
4497 * @remarks No-long-jump zone!!!
4498 */
4499static void hmR0VmxExportHostMsrs(PVMCPUCC pVCpu)
4500{
4501 AssertPtr(pVCpu);
4502
4503 /*
4504 * Save MSRs that we restore lazily (due to preemption or transition to ring-3)
4505 * rather than swapping them on every VM-entry.
4506 */
4507 hmR0VmxLazySaveHostMsrs(pVCpu);
4508
4509 /*
4510 * Host Sysenter MSRs.
4511 */
4512 int rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS)); AssertRC(rc);
4513 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP)); AssertRC(rc);
4514 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP)); AssertRC(rc);
4515
4516 /*
4517 * Host EFER MSR.
4518 *
4519 * If the CPU supports the newer VMCS controls for managing EFER, use it. Otherwise it's
4520 * done as part of auto-load/store MSR area in the VMCS, see hmR0VmxExportGuestMsrs().
4521 */
4522 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4523 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
4524 {
4525 rc = VMXWriteVmcs64(VMX_VMCS64_HOST_EFER_FULL, pVM->hm.s.vmx.u64HostMsrEfer);
4526 AssertRC(rc);
4527 }
4528
4529 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT also see
4530 * hmR0VmxExportGuestEntryExitCtls(). */
4531}
4532
4533
4534/**
4535 * Figures out if we need to swap the EFER MSR which is particularly expensive.
4536 *
4537 * We check all relevant bits. For now, that's everything besides LMA/LME, as
4538 * these two bits are handled by VM-entry, see hmR0VMxExportGuestEntryExitCtls().
4539 *
4540 * @returns true if we need to load guest EFER, false otherwise.
4541 * @param pVCpu The cross context virtual CPU structure.
4542 *
4543 * @remarks Requires EFER, CR4.
4544 * @remarks No-long-jump zone!!!
4545 */
4546static bool hmR0VmxShouldSwapEferMsr(PCVMCPUCC pVCpu)
4547{
4548#ifdef HMVMX_ALWAYS_SWAP_EFER
4549 RT_NOREF(pVCpu);
4550 return true;
4551#else
4552 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4553 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4554 uint64_t const u64HostEfer = pVM->hm.s.vmx.u64HostMsrEfer;
4555 uint64_t const u64GuestEfer = pCtx->msrEFER;
4556
4557 /*
4558 * For 64-bit guests, if EFER.SCE bit differs, we need to swap the EFER MSR
4559 * to ensure that the guest's SYSCALL behaviour isn't broken, see @bugref{7386}.
4560 */
4561 if ( CPUMIsGuestInLongModeEx(pCtx)
4562 && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
4563 return true;
4564
4565 /*
4566 * If the guest uses PAE and EFER.NXE bit differs, we need to swap the EFER MSR
4567 * as it affects guest paging. 64-bit paging implies CR4.PAE as well.
4568 *
4569 * See Intel spec. 4.5 "IA-32e Paging".
4570 * See Intel spec. 4.1.1 "Three Paging Modes".
4571 *
4572 * Verify that we always intercept CR4.PAE and CR0.PG bits, so we don't need to
4573 * import CR4 and CR0 from the VMCS here as those bits are always up to date.
4574 */
4575 Assert(hmR0VmxGetFixedCr4Mask(pVCpu) & X86_CR4_PAE);
4576 Assert(hmR0VmxGetFixedCr0Mask(pVCpu) & X86_CR0_PG);
4577 if ( (pCtx->cr4 & X86_CR4_PAE)
4578 && (pCtx->cr0 & X86_CR0_PG)
4579 && (u64GuestEfer & MSR_K6_EFER_NXE) != (u64HostEfer & MSR_K6_EFER_NXE))
4580 {
4581 /* Assert that host is NX capable. */
4582 Assert(pVCpu->CTX_SUFF(pVM)->cpum.ro.HostFeatures.fNoExecute);
4583 return true;
4584 }
4585
4586 return false;
4587#endif
4588}
4589
4590/**
4591 * Exports the guest state with appropriate VM-entry and VM-exit controls in the
4592 * VMCS.
4593 *
4594 * This is typically required when the guest changes paging mode.
4595 *
4596 * @returns VBox status code.
4597 * @param pVCpu The cross context virtual CPU structure.
4598 * @param pVmxTransient The VMX-transient structure.
4599 *
4600 * @remarks Requires EFER.
4601 * @remarks No-long-jump zone!!!
4602 */
4603static int hmR0VmxExportGuestEntryExitCtls(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
4604{
4605 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS)
4606 {
4607 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4608 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4609
4610 /*
4611 * VM-entry controls.
4612 */
4613 {
4614 uint32_t fVal = pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
4615 uint32_t const fZap = pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
4616
4617 /*
4618 * Load the guest debug controls (DR7 and IA32_DEBUGCTL MSR) on VM-entry.
4619 * The first VT-x capable CPUs only supported the 1-setting of this bit.
4620 *
4621 * For nested-guests, this is a mandatory VM-entry control. It's also
4622 * required because we do not want to leak host bits to the nested-guest.
4623 */
4624 fVal |= VMX_ENTRY_CTLS_LOAD_DEBUG;
4625
4626 /*
4627 * Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry.
4628 *
4629 * For nested-guests, the "IA-32e mode guest" control we initialize with what is
4630 * required to get the nested-guest working with hardware-assisted VMX execution.
4631 * It depends on the nested-guest's IA32_EFER.LMA bit. Remember, a guest hypervisor
4632 * can skip intercepting changes to the EFER MSR. This is why it it needs to be done
4633 * here rather than while merging the guest VMCS controls.
4634 */
4635 if (CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
4636 fVal |= VMX_ENTRY_CTLS_IA32E_MODE_GUEST;
4637 else
4638 Assert(!(fVal & VMX_ENTRY_CTLS_IA32E_MODE_GUEST));
4639
4640 /*
4641 * If the CPU supports the newer VMCS controls for managing guest/host EFER, use it.
4642 *
4643 * For nested-guests, we use the "load IA32_EFER" if the hardware supports it,
4644 * regardless of whether the nested-guest VMCS specifies it because we are free to
4645 * load whatever MSRs we require and we do not need to modify the guest visible copy
4646 * of the VM-entry MSR load area.
4647 */
4648 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
4649 && hmR0VmxShouldSwapEferMsr(pVCpu))
4650 fVal |= VMX_ENTRY_CTLS_LOAD_EFER_MSR;
4651 else
4652 Assert(!(fVal & VMX_ENTRY_CTLS_LOAD_EFER_MSR));
4653
4654 /*
4655 * The following should -not- be set (since we're not in SMM mode):
4656 * - VMX_ENTRY_CTLS_ENTRY_TO_SMM
4657 * - VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON
4658 */
4659
4660 /** @todo VMX_ENTRY_CTLS_LOAD_PERF_MSR,
4661 * VMX_ENTRY_CTLS_LOAD_PAT_MSR. */
4662
4663 if ((fVal & fZap) == fVal)
4664 { /* likely */ }
4665 else
4666 {
4667 Log4Func(("Invalid VM-entry controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
4668 pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed0, fVal, fZap));
4669 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_ENTRY;
4670 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4671 }
4672
4673 /* Commit it to the VMCS. */
4674 if (pVmcsInfo->u32EntryCtls != fVal)
4675 {
4676 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, fVal);
4677 AssertRC(rc);
4678 pVmcsInfo->u32EntryCtls = fVal;
4679 }
4680 }
4681
4682 /*
4683 * VM-exit controls.
4684 */
4685 {
4686 uint32_t fVal = pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
4687 uint32_t const fZap = pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
4688
4689 /*
4690 * Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only
4691 * supported the 1-setting of this bit.
4692 *
4693 * For nested-guests, we set the "save debug controls" as the converse
4694 * "load debug controls" is mandatory for nested-guests anyway.
4695 */
4696 fVal |= VMX_EXIT_CTLS_SAVE_DEBUG;
4697
4698 /*
4699 * Set the host long mode active (EFER.LMA) bit (which Intel calls
4700 * "Host address-space size") if necessary. On VM-exit, VT-x sets both the
4701 * host EFER.LMA and EFER.LME bit to this value. See assertion in
4702 * hmR0VmxExportHostMsrs().
4703 *
4704 * For nested-guests, we always set this bit as we do not support 32-bit
4705 * hosts.
4706 */
4707 fVal |= VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE;
4708
4709 /*
4710 * If the VMCS EFER MSR fields are supported by the hardware, we use it.
4711 *
4712 * For nested-guests, we should use the "save IA32_EFER" control if we also
4713 * used the "load IA32_EFER" control while exporting VM-entry controls.
4714 */
4715 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
4716 && hmR0VmxShouldSwapEferMsr(pVCpu))
4717 {
4718 fVal |= VMX_EXIT_CTLS_SAVE_EFER_MSR
4719 | VMX_EXIT_CTLS_LOAD_EFER_MSR;
4720 }
4721
4722 /*
4723 * Enable saving of the VMX-preemption timer value on VM-exit.
4724 * For nested-guests, currently not exposed/used.
4725 */
4726 if ( pVM->hm.s.vmx.fUsePreemptTimer
4727 && (pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER))
4728 fVal |= VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER;
4729
4730 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
4731 Assert(!(fVal & VMX_EXIT_CTLS_ACK_EXT_INT));
4732
4733 /** @todo VMX_EXIT_CTLS_LOAD_PERF_MSR,
4734 * VMX_EXIT_CTLS_SAVE_PAT_MSR,
4735 * VMX_EXIT_CTLS_LOAD_PAT_MSR. */
4736
4737 if ((fVal & fZap) == fVal)
4738 { /* likely */ }
4739 else
4740 {
4741 Log4Func(("Invalid VM-exit controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%R#X32\n",
4742 pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed0, fVal, fZap));
4743 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_EXIT;
4744 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4745 }
4746
4747 /* Commit it to the VMCS. */
4748 if (pVmcsInfo->u32ExitCtls != fVal)
4749 {
4750 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, fVal);
4751 AssertRC(rc);
4752 pVmcsInfo->u32ExitCtls = fVal;
4753 }
4754 }
4755
4756 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
4757 }
4758 return VINF_SUCCESS;
4759}
4760
4761
4762/**
4763 * Sets the TPR threshold in the VMCS.
4764 *
4765 * @param pVmcsInfo The VMCS info. object.
4766 * @param u32TprThreshold The TPR threshold (task-priority class only).
4767 */
4768DECLINLINE(void) hmR0VmxApicSetTprThreshold(PVMXVMCSINFO pVmcsInfo, uint32_t u32TprThreshold)
4769{
4770 Assert(!(u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)); /* Bits 31:4 MBZ. */
4771 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
4772 RT_NOREF(pVmcsInfo);
4773 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
4774 AssertRC(rc);
4775}
4776
4777
4778/**
4779 * Exports the guest APIC TPR state into the VMCS.
4780 *
4781 * @returns VBox status code.
4782 * @param pVCpu The cross context virtual CPU structure.
4783 * @param pVmxTransient The VMX-transient structure.
4784 *
4785 * @remarks No-long-jump zone!!!
4786 */
4787static int hmR0VmxExportGuestApicTpr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
4788{
4789 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_APIC_TPR)
4790 {
4791 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
4792
4793 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4794 if (!pVmxTransient->fIsNestedGuest)
4795 {
4796 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
4797 && APICIsEnabled(pVCpu))
4798 {
4799 /*
4800 * Setup TPR shadowing.
4801 */
4802 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
4803 {
4804 bool fPendingIntr = false;
4805 uint8_t u8Tpr = 0;
4806 uint8_t u8PendingIntr = 0;
4807 int rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
4808 AssertRCReturn(rc, rc);
4809
4810 /*
4811 * If there are interrupts pending but masked by the TPR, instruct VT-x to
4812 * cause a TPR-below-threshold VM-exit when the guest lowers its TPR below the
4813 * priority of the pending interrupt so we can deliver the interrupt. If there
4814 * are no interrupts pending, set threshold to 0 to not cause any
4815 * TPR-below-threshold VM-exits.
4816 */
4817 uint32_t u32TprThreshold = 0;
4818 if (fPendingIntr)
4819 {
4820 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR
4821 (which is the Task-Priority Class). */
4822 const uint8_t u8PendingPriority = u8PendingIntr >> 4;
4823 const uint8_t u8TprPriority = u8Tpr >> 4;
4824 if (u8PendingPriority <= u8TprPriority)
4825 u32TprThreshold = u8PendingPriority;
4826 }
4827
4828 hmR0VmxApicSetTprThreshold(pVmcsInfo, u32TprThreshold);
4829 }
4830 }
4831 }
4832 /* else: the TPR threshold has already been updated while merging the nested-guest VMCS. */
4833 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
4834 }
4835 return VINF_SUCCESS;
4836}
4837
4838
4839/**
4840 * Gets the guest interruptibility-state.
4841 *
4842 * @returns Guest's interruptibility-state.
4843 * @param pVCpu The cross context virtual CPU structure.
4844 * @param pVmxTransient The VMX-transient structure.
4845 *
4846 * @remarks No-long-jump zone!!!
4847 */
4848static uint32_t hmR0VmxGetGuestIntrState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
4849{
4850 /*
4851 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
4852 */
4853 uint32_t fIntrState = 0;
4854 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
4855 {
4856 /* If inhibition is active, RIP and RFLAGS should've been imported from the VMCS already. */
4857 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
4858
4859 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4860 if (pCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
4861 {
4862 if (pCtx->eflags.Bits.u1IF)
4863 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
4864 else
4865 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS;
4866 }
4867 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
4868 {
4869 /*
4870 * We can clear the inhibit force flag as even if we go back to the recompiler
4871 * without executing guest code in VT-x, the flag's condition to be cleared is
4872 * met and thus the cleared state is correct.
4873 */
4874 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
4875 }
4876 }
4877
4878 /*
4879 * NMIs to the guest are blocked after an NMI is injected until the guest executes an IRET. We only
4880 * bother with virtual-NMI blocking when we have support for virtual NMIs in the CPU, otherwise
4881 * setting this would block host-NMIs and IRET will not clear the blocking.
4882 *
4883 * We always set NMI-exiting so when the host receives an NMI we get a VM-exit.
4884 *
4885 * See Intel spec. 26.6.1 "Interruptibility state". See @bugref{7445}.
4886 */
4887 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4888 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
4889 && CPUMIsGuestNmiBlocking(pVCpu))
4890 fIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
4891
4892 return fIntrState;
4893}
4894
4895
4896/**
4897 * Exports the exception intercepts required for guest execution in the VMCS.
4898 *
4899 * @returns VBox status code.
4900 * @param pVCpu The cross context virtual CPU structure.
4901 * @param pVmxTransient The VMX-transient structure.
4902 *
4903 * @remarks No-long-jump zone!!!
4904 */
4905static int hmR0VmxExportGuestXcptIntercepts(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
4906{
4907 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_XCPT_INTERCEPTS)
4908 {
4909 /* When executing a nested-guest, we do not need to trap GIM hypercalls by intercepting #UD. */
4910 if ( !pVmxTransient->fIsNestedGuest
4911 && pVCpu->hm.s.fGIMTrapXcptUD)
4912 hmR0VmxAddXcptIntercept(pVmxTransient, X86_XCPT_UD);
4913 else
4914 hmR0VmxRemoveXcptIntercept(pVCpu, pVmxTransient, X86_XCPT_UD);
4915
4916 /* Other exception intercepts are handled elsewhere, e.g. while exporting guest CR0. */
4917 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_XCPT_INTERCEPTS);
4918 }
4919 return VINF_SUCCESS;
4920}
4921
4922
4923/**
4924 * Exports the guest's RIP into the guest-state area in the VMCS.
4925 *
4926 * @returns VBox status code.
4927 * @param pVCpu The cross context virtual CPU structure.
4928 *
4929 * @remarks No-long-jump zone!!!
4930 */
4931static int hmR0VmxExportGuestRip(PVMCPUCC pVCpu)
4932{
4933 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RIP)
4934 {
4935 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP);
4936
4937 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RIP, pVCpu->cpum.GstCtx.rip);
4938 AssertRC(rc);
4939
4940 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RIP);
4941 Log4Func(("rip=%#RX64\n", pVCpu->cpum.GstCtx.rip));
4942 }
4943 return VINF_SUCCESS;
4944}
4945
4946
4947/**
4948 * Exports the guest's RSP into the guest-state area in the VMCS.
4949 *
4950 * @returns VBox status code.
4951 * @param pVCpu The cross context virtual CPU structure.
4952 *
4953 * @remarks No-long-jump zone!!!
4954 */
4955static int hmR0VmxExportGuestRsp(PVMCPUCC pVCpu)
4956{
4957 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RSP)
4958 {
4959 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RSP);
4960
4961 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RSP, pVCpu->cpum.GstCtx.rsp);
4962 AssertRC(rc);
4963
4964 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RSP);
4965 Log4Func(("rsp=%#RX64\n", pVCpu->cpum.GstCtx.rsp));
4966 }
4967 return VINF_SUCCESS;
4968}
4969
4970
4971/**
4972 * Exports the guest's RFLAGS into the guest-state area in the VMCS.
4973 *
4974 * @returns VBox status code.
4975 * @param pVCpu The cross context virtual CPU structure.
4976 * @param pVmxTransient The VMX-transient structure.
4977 *
4978 * @remarks No-long-jump zone!!!
4979 */
4980static int hmR0VmxExportGuestRflags(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
4981{
4982 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RFLAGS)
4983 {
4984 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
4985
4986 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
4987 Let us assert it as such and use 32-bit VMWRITE. */
4988 Assert(!RT_HI_U32(pVCpu->cpum.GstCtx.rflags.u64));
4989 X86EFLAGS fEFlags = pVCpu->cpum.GstCtx.eflags;
4990 Assert(fEFlags.u32 & X86_EFL_RA1_MASK);
4991 Assert(!(fEFlags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
4992
4993 /*
4994 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so
4995 * we can restore them on VM-exit. Modify the real-mode guest's eflags so that VT-x
4996 * can run the real-mode guest code under Virtual 8086 mode.
4997 */
4998 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4999 if (pVmcsInfo->RealMode.fRealOnV86Active)
5000 {
5001 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
5002 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
5003 Assert(!pVmxTransient->fIsNestedGuest);
5004 pVmcsInfo->RealMode.Eflags.u32 = fEFlags.u32; /* Save the original eflags of the real-mode guest. */
5005 fEFlags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
5006 fEFlags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
5007 }
5008
5009 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RFLAGS, fEFlags.u32);
5010 AssertRC(rc);
5011
5012 /*
5013 * Setup pending debug exceptions if the guest is single-stepping using EFLAGS.TF.
5014 *
5015 * We must avoid setting any automatic debug exceptions delivery when single-stepping
5016 * through the hypervisor debugger using EFLAGS.TF.
5017 */
5018 if ( !pVmxTransient->fIsNestedGuest
5019 && !pVCpu->hm.s.fSingleInstruction
5020 && fEFlags.Bits.u1TF)
5021 {
5022 /** @todo r=ramshankar: Warning!! We ASSUME EFLAGS.TF will not cleared on
5023 * premature trips to ring-3 esp since IEM does not yet handle it. */
5024 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS);
5025 AssertRC(rc);
5026 }
5027 /* else: for nested-guest currently handling while merging controls. */
5028
5029 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RFLAGS);
5030 Log4Func(("eflags=%#RX32\n", fEFlags.u32));
5031 }
5032 return VINF_SUCCESS;
5033}
5034
5035
5036#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5037/**
5038 * Copies the nested-guest VMCS to the shadow VMCS.
5039 *
5040 * @returns VBox status code.
5041 * @param pVCpu The cross context virtual CPU structure.
5042 * @param pVmcsInfo The VMCS info. object.
5043 *
5044 * @remarks No-long-jump zone!!!
5045 */
5046static int hmR0VmxCopyNstGstToShadowVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5047{
5048 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5049 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5050
5051 /*
5052 * Disable interrupts so we don't get preempted while the shadow VMCS is the
5053 * current VMCS, as we may try saving guest lazy MSRs.
5054 *
5055 * Strictly speaking the lazy MSRs are not in the VMCS, but I'd rather not risk
5056 * calling the import VMCS code which is currently performing the guest MSR reads
5057 * (on 64-bit hosts) and accessing the auto-load/store MSR area on 32-bit hosts
5058 * and the rest of the VMX leave session machinery.
5059 */
5060 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
5061
5062 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5063 if (RT_SUCCESS(rc))
5064 {
5065 /*
5066 * Copy all guest read/write VMCS fields.
5067 *
5068 * We don't check for VMWRITE failures here for performance reasons and
5069 * because they are not expected to fail, barring irrecoverable conditions
5070 * like hardware errors.
5071 */
5072 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
5073 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5074 {
5075 uint64_t u64Val;
5076 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
5077 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5078 VMXWriteVmcs64(uVmcsField, u64Val);
5079 }
5080
5081 /*
5082 * If the host CPU supports writing all VMCS fields, copy the guest read-only
5083 * VMCS fields, so the guest can VMREAD them without causing a VM-exit.
5084 */
5085 if (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL)
5086 {
5087 uint32_t const cShadowVmcsRoFields = pVM->hm.s.vmx.cShadowVmcsRoFields;
5088 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
5089 {
5090 uint64_t u64Val;
5091 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsRoFields[i];
5092 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5093 VMXWriteVmcs64(uVmcsField, u64Val);
5094 }
5095 }
5096
5097 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5098 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5099 }
5100
5101 ASMSetFlags(fEFlags);
5102 return rc;
5103}
5104
5105
5106/**
5107 * Copies the shadow VMCS to the nested-guest VMCS.
5108 *
5109 * @returns VBox status code.
5110 * @param pVCpu The cross context virtual CPU structure.
5111 * @param pVmcsInfo The VMCS info. object.
5112 *
5113 * @remarks Called with interrupts disabled.
5114 */
5115static int hmR0VmxCopyShadowToNstGstVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5116{
5117 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5118 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5119 PVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5120
5121 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5122 if (RT_SUCCESS(rc))
5123 {
5124 /*
5125 * Copy guest read/write fields from the shadow VMCS.
5126 * Guest read-only fields cannot be modified, so no need to copy them.
5127 *
5128 * We don't check for VMREAD failures here for performance reasons and
5129 * because they are not expected to fail, barring irrecoverable conditions
5130 * like hardware errors.
5131 */
5132 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
5133 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5134 {
5135 uint64_t u64Val;
5136 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
5137 VMXReadVmcs64(uVmcsField, &u64Val);
5138 IEMWriteVmxVmcsField(pVmcsNstGst, uVmcsField, u64Val);
5139 }
5140
5141 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5142 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5143 }
5144 return rc;
5145}
5146
5147
5148/**
5149 * Enables VMCS shadowing for the given VMCS info. object.
5150 *
5151 * @param pVmcsInfo The VMCS info. object.
5152 *
5153 * @remarks No-long-jump zone!!!
5154 */
5155static void hmR0VmxEnableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5156{
5157 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5158 if (!(uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING))
5159 {
5160 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
5161 uProcCtls2 |= VMX_PROC_CTLS2_VMCS_SHADOWING;
5162 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5163 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, pVmcsInfo->HCPhysShadowVmcs); AssertRC(rc);
5164 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5165 pVmcsInfo->u64VmcsLinkPtr = pVmcsInfo->HCPhysShadowVmcs;
5166 Log4Func(("Enabled\n"));
5167 }
5168}
5169
5170
5171/**
5172 * Disables VMCS shadowing for the given VMCS info. object.
5173 *
5174 * @param pVmcsInfo The VMCS info. object.
5175 *
5176 * @remarks No-long-jump zone!!!
5177 */
5178static void hmR0VmxDisableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5179{
5180 /*
5181 * We want all VMREAD and VMWRITE instructions to cause VM-exits, so we clear the
5182 * VMCS shadowing control. However, VM-entry requires the shadow VMCS indicator bit
5183 * to match the VMCS shadowing control if the VMCS link pointer is not NIL_RTHCPHYS.
5184 * Hence, we must also reset the VMCS link pointer to ensure VM-entry does not fail.
5185 *
5186 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
5187 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5188 */
5189 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5190 if (uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
5191 {
5192 uProcCtls2 &= ~VMX_PROC_CTLS2_VMCS_SHADOWING;
5193 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5194 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS); AssertRC(rc);
5195 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5196 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
5197 Log4Func(("Disabled\n"));
5198 }
5199}
5200#endif
5201
5202
5203/**
5204 * Exports the guest hardware-virtualization state.
5205 *
5206 * @returns VBox status code.
5207 * @param pVCpu The cross context virtual CPU structure.
5208 * @param pVmxTransient The VMX-transient structure.
5209 *
5210 * @remarks No-long-jump zone!!!
5211 */
5212static int hmR0VmxExportGuestHwvirtState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
5213{
5214 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_HWVIRT)
5215 {
5216#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5217 /*
5218 * Check if the VMX feature is exposed to the guest and if the host CPU supports
5219 * VMCS shadowing.
5220 */
5221 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
5222 {
5223 /*
5224 * If the guest hypervisor has loaded a current VMCS and is in VMX root mode,
5225 * copy the guest hypervisor's current VMCS into the shadow VMCS and enable
5226 * VMCS shadowing to skip intercepting some or all VMREAD/VMWRITE VM-exits.
5227 *
5228 * We check for VMX root mode here in case the guest executes VMXOFF without
5229 * clearing the current VMCS pointer and our VMXOFF instruction emulation does
5230 * not clear the current VMCS pointer.
5231 */
5232 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5233 if ( CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx)
5234 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx)
5235 && CPUMIsGuestVmxCurrentVmcsValid(pVCpu, &pVCpu->cpum.GstCtx))
5236 {
5237 /* Paranoia. */
5238 Assert(!pVmxTransient->fIsNestedGuest);
5239
5240 /*
5241 * For performance reasons, also check if the guest hypervisor's current VMCS
5242 * was newly loaded or modified before copying it to the shadow VMCS.
5243 */
5244 if (!pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs)
5245 {
5246 int rc = hmR0VmxCopyNstGstToShadowVmcs(pVCpu, pVmcsInfo);
5247 AssertRCReturn(rc, rc);
5248 pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs = true;
5249 }
5250 hmR0VmxEnableVmcsShadowing(pVmcsInfo);
5251 }
5252 else
5253 hmR0VmxDisableVmcsShadowing(pVmcsInfo);
5254 }
5255#else
5256 NOREF(pVmxTransient);
5257#endif
5258 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_HWVIRT);
5259 }
5260 return VINF_SUCCESS;
5261}
5262
5263
5264/**
5265 * Exports the guest CR0 control register into the guest-state area in the VMCS.
5266 *
5267 * The guest FPU state is always pre-loaded hence we don't need to bother about
5268 * sharing FPU related CR0 bits between the guest and host.
5269 *
5270 * @returns VBox status code.
5271 * @param pVCpu The cross context virtual CPU structure.
5272 * @param pVmxTransient The VMX-transient structure.
5273 *
5274 * @remarks No-long-jump zone!!!
5275 */
5276static int hmR0VmxExportGuestCR0(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
5277{
5278 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR0)
5279 {
5280 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5281 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5282
5283 /*
5284 * Figure out fixed CR0 bits in VMX operation.
5285 */
5286 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
5287 uint64_t fSetCr0 = pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1;
5288 uint64_t const fZapCr0 = pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1;
5289 if (pVM->hm.s.vmx.fUnrestrictedGuest)
5290 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
5291 else
5292 Assert((fSetCr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
5293
5294 if (!pVmxTransient->fIsNestedGuest)
5295 {
5296 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5297 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5298 uint64_t const u64ShadowCr0 = u64GuestCr0;
5299 Assert(!RT_HI_U32(u64GuestCr0));
5300
5301 /*
5302 * Setup VT-x's view of the guest CR0.
5303 */
5304 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5305 if (pVM->hm.s.fNestedPaging)
5306 {
5307 if (CPUMIsGuestPagingEnabled(pVCpu))
5308 {
5309 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
5310 uProcCtls &= ~( VMX_PROC_CTLS_CR3_LOAD_EXIT
5311 | VMX_PROC_CTLS_CR3_STORE_EXIT);
5312 }
5313 else
5314 {
5315 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
5316 uProcCtls |= VMX_PROC_CTLS_CR3_LOAD_EXIT
5317 | VMX_PROC_CTLS_CR3_STORE_EXIT;
5318 }
5319
5320 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
5321 if (pVM->hm.s.vmx.fUnrestrictedGuest)
5322 uProcCtls &= ~VMX_PROC_CTLS_CR3_STORE_EXIT;
5323 }
5324 else
5325 {
5326 /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
5327 u64GuestCr0 |= X86_CR0_WP;
5328 }
5329
5330 /*
5331 * Guest FPU bits.
5332 *
5333 * Since we pre-load the guest FPU always before VM-entry there is no need to track lazy state
5334 * using CR0.TS.
5335 *
5336 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be
5337 * set on the first CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
5338 */
5339 u64GuestCr0 |= X86_CR0_NE;
5340
5341 /* If CR0.NE isn't set, we need to intercept #MF exceptions and report them to the guest differently. */
5342 bool const fInterceptMF = !(u64ShadowCr0 & X86_CR0_NE);
5343
5344 /*
5345 * Update exception intercepts.
5346 */
5347 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
5348 if (pVmcsInfo->RealMode.fRealOnV86Active)
5349 {
5350 Assert(PDMVmmDevHeapIsEnabled(pVM));
5351 Assert(pVM->hm.s.vmx.pRealModeTSS);
5352 uXcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
5353 }
5354 else
5355 {
5356 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
5357 uXcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
5358 if (fInterceptMF)
5359 uXcptBitmap |= RT_BIT(X86_XCPT_MF);
5360 }
5361
5362 /* Additional intercepts for debugging, define these yourself explicitly. */
5363#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
5364 uXcptBitmap |= 0
5365 | RT_BIT(X86_XCPT_BP)
5366 | RT_BIT(X86_XCPT_DE)
5367 | RT_BIT(X86_XCPT_NM)
5368 | RT_BIT(X86_XCPT_TS)
5369 | RT_BIT(X86_XCPT_UD)
5370 | RT_BIT(X86_XCPT_NP)
5371 | RT_BIT(X86_XCPT_SS)
5372 | RT_BIT(X86_XCPT_GP)
5373 | RT_BIT(X86_XCPT_PF)
5374 | RT_BIT(X86_XCPT_MF)
5375 ;
5376#elif defined(HMVMX_ALWAYS_TRAP_PF)
5377 uXcptBitmap |= RT_BIT(X86_XCPT_PF);
5378#endif
5379 if (pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv)
5380 uXcptBitmap |= RT_BIT(X86_XCPT_GP);
5381 Assert(pVM->hm.s.fNestedPaging || (uXcptBitmap & RT_BIT(X86_XCPT_PF)));
5382
5383 /* Apply the hardware specified fixed CR0 bits and enable caching. */
5384 u64GuestCr0 |= fSetCr0;
5385 u64GuestCr0 &= fZapCr0;
5386 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5387
5388 /* Commit the CR0 and related fields to the guest VMCS. */
5389 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5390 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5391 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5392 {
5393 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5394 AssertRC(rc);
5395 }
5396 if (uXcptBitmap != pVmcsInfo->u32XcptBitmap)
5397 {
5398 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
5399 AssertRC(rc);
5400 }
5401
5402 /* Update our caches. */
5403 pVmcsInfo->u32ProcCtls = uProcCtls;
5404 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
5405
5406 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5407 }
5408 else
5409 {
5410 /*
5411 * With nested-guests, we may have extended the guest/host mask here since we
5412 * merged in the outer guest's mask. Thus, the merged mask can include more bits
5413 * (to read from the nested-guest CR0 read-shadow) than the guest hypervisor
5414 * originally supplied. We must copy those bits from the nested-guest CR0 into
5415 * the nested-guest CR0 read-shadow.
5416 */
5417 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5418 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5419 uint64_t const u64ShadowCr0 = CPUMGetGuestVmxMaskedCr0(pVCpu, &pVCpu->cpum.GstCtx, pVmcsInfo->u64Cr0Mask);
5420 Assert(!RT_HI_U32(u64GuestCr0));
5421 Assert(u64GuestCr0 & X86_CR0_NE);
5422
5423 /*
5424 * Apply the hardware specified fixed CR0 bits and enable caching.
5425 * Note! We could be altering our VMX emulation's fixed bits. We thus
5426 * need to re-apply them while importing CR0.
5427 */
5428 u64GuestCr0 |= fSetCr0;
5429 u64GuestCr0 &= fZapCr0;
5430 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5431
5432 /* Commit the CR0 and CR0 read-shadow to the nested-guest VMCS. */
5433 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5434 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5435
5436 Log4Func(("cr0=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5437 }
5438
5439 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR0);
5440 }
5441
5442 return VINF_SUCCESS;
5443}
5444
5445
5446/**
5447 * Exports the guest control registers (CR3, CR4) into the guest-state area
5448 * in the VMCS.
5449 *
5450 * @returns VBox strict status code.
5451 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
5452 * without unrestricted guest access and the VMMDev is not presently
5453 * mapped (e.g. EFI32).
5454 *
5455 * @param pVCpu The cross context virtual CPU structure.
5456 * @param pVmxTransient The VMX-transient structure.
5457 *
5458 * @remarks No-long-jump zone!!!
5459 */
5460static VBOXSTRICTRC hmR0VmxExportGuestCR3AndCR4(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
5461{
5462 int rc = VINF_SUCCESS;
5463 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5464
5465 /*
5466 * Guest CR2.
5467 * It's always loaded in the assembler code. Nothing to do here.
5468 */
5469
5470 /*
5471 * Guest CR3.
5472 */
5473 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR3)
5474 {
5475 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
5476
5477 if (pVM->hm.s.fNestedPaging)
5478 {
5479 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5480 pVmcsInfo->HCPhysEPTP = PGMGetHyperCR3(pVCpu);
5481
5482 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
5483 Assert(pVmcsInfo->HCPhysEPTP != NIL_RTHCPHYS);
5484 Assert(!(pVmcsInfo->HCPhysEPTP & UINT64_C(0xfff0000000000000)));
5485 Assert(!(pVmcsInfo->HCPhysEPTP & 0xfff));
5486
5487 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
5488 pVmcsInfo->HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
5489 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
5490
5491 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
5492 AssertMsg( ((pVmcsInfo->HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
5493 && ((pVmcsInfo->HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
5494 ("EPTP %#RX64\n", pVmcsInfo->HCPhysEPTP));
5495 AssertMsg( !((pVmcsInfo->HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
5496 || (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
5497 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVmcsInfo->HCPhysEPTP));
5498
5499 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVmcsInfo->HCPhysEPTP);
5500 AssertRC(rc);
5501
5502 uint64_t u64GuestCr3;
5503 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5504 if ( pVM->hm.s.vmx.fUnrestrictedGuest
5505 || CPUMIsGuestPagingEnabledEx(pCtx))
5506 {
5507 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
5508 if (CPUMIsGuestInPAEModeEx(pCtx))
5509 {
5510 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
5511 AssertRC(rc);
5512 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
5513 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
5514 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
5515 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
5516 }
5517
5518 /*
5519 * The guest's view of its CR3 is unblemished with nested paging when the
5520 * guest is using paging or we have unrestricted guest execution to handle
5521 * the guest when it's not using paging.
5522 */
5523 u64GuestCr3 = pCtx->cr3;
5524 }
5525 else
5526 {
5527 /*
5528 * The guest is not using paging, but the CPU (VT-x) has to. While the guest
5529 * thinks it accesses physical memory directly, we use our identity-mapped
5530 * page table to map guest-linear to guest-physical addresses. EPT takes care
5531 * of translating it to host-physical addresses.
5532 */
5533 RTGCPHYS GCPhys;
5534 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
5535
5536 /* We obtain it here every time as the guest could have relocated this PCI region. */
5537 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
5538 if (RT_SUCCESS(rc))
5539 { /* likely */ }
5540 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
5541 {
5542 Log4Func(("VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n"));
5543 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
5544 }
5545 else
5546 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
5547
5548 u64GuestCr3 = GCPhys;
5549 }
5550
5551 Log4Func(("guest_cr3=%#RX64 (GstN)\n", u64GuestCr3));
5552 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, u64GuestCr3);
5553 AssertRC(rc);
5554 }
5555 else
5556 {
5557 Assert(!pVmxTransient->fIsNestedGuest);
5558 /* Non-nested paging case, just use the hypervisor's CR3. */
5559 RTHCPHYS const HCPhysGuestCr3 = PGMGetHyperCR3(pVCpu);
5560
5561 Log4Func(("guest_cr3=%#RX64 (HstN)\n", HCPhysGuestCr3));
5562 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, HCPhysGuestCr3);
5563 AssertRC(rc);
5564 }
5565
5566 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR3);
5567 }
5568
5569 /*
5570 * Guest CR4.
5571 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
5572 */
5573 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR4)
5574 {
5575 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5576 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5577
5578 /*
5579 * Figure out fixed CR4 bits in VMX operation.
5580 */
5581 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
5582 uint64_t const fSetCr4 = pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1;
5583 uint64_t const fZapCr4 = pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1;
5584
5585 /*
5586 * With nested-guests, we may have extended the guest/host mask here (since we
5587 * merged in the outer guest's mask, see hmR0VmxMergeVmcsNested). This means, the
5588 * mask can include more bits (to read from the nested-guest CR4 read-shadow) than
5589 * the guest hypervisor originally supplied. Thus, we should, in essence, copy
5590 * those bits from the nested-guest CR4 into the nested-guest CR4 read-shadow.
5591 */
5592 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
5593 uint64_t u64GuestCr4 = pCtx->cr4;
5594 uint64_t const u64ShadowCr4 = !pVmxTransient->fIsNestedGuest
5595 ? pCtx->cr4
5596 : CPUMGetGuestVmxMaskedCr4(pVCpu, pCtx, pVmcsInfo->u64Cr4Mask);
5597 Assert(!RT_HI_U32(u64GuestCr4));
5598
5599 /*
5600 * Setup VT-x's view of the guest CR4.
5601 *
5602 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software
5603 * interrupts to the 8086 program interrupt handler. Clear the VME bit (the interrupt
5604 * redirection bitmap is already all 0, see hmR3InitFinalizeR0())
5605 *
5606 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
5607 */
5608 if (pVmcsInfo->RealMode.fRealOnV86Active)
5609 {
5610 Assert(pVM->hm.s.vmx.pRealModeTSS);
5611 Assert(PDMVmmDevHeapIsEnabled(pVM));
5612 u64GuestCr4 &= ~(uint64_t)X86_CR4_VME;
5613 }
5614
5615 if (pVM->hm.s.fNestedPaging)
5616 {
5617 if ( !CPUMIsGuestPagingEnabledEx(pCtx)
5618 && !pVM->hm.s.vmx.fUnrestrictedGuest)
5619 {
5620 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
5621 u64GuestCr4 |= X86_CR4_PSE;
5622 /* Our identity mapping is a 32-bit page directory. */
5623 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5624 }
5625 /* else use guest CR4.*/
5626 }
5627 else
5628 {
5629 Assert(!pVmxTransient->fIsNestedGuest);
5630
5631 /*
5632 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
5633 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
5634 */
5635 switch (pVCpu->hm.s.enmShadowMode)
5636 {
5637 case PGMMODE_REAL: /* Real-mode. */
5638 case PGMMODE_PROTECTED: /* Protected mode without paging. */
5639 case PGMMODE_32_BIT: /* 32-bit paging. */
5640 {
5641 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5642 break;
5643 }
5644
5645 case PGMMODE_PAE: /* PAE paging. */
5646 case PGMMODE_PAE_NX: /* PAE paging with NX. */
5647 {
5648 u64GuestCr4 |= X86_CR4_PAE;
5649 break;
5650 }
5651
5652 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
5653 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
5654#ifdef VBOX_WITH_64_BITS_GUESTS
5655 break;
5656#endif
5657 default:
5658 AssertFailed();
5659 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
5660 }
5661 }
5662
5663 /*
5664 * Apply the hardware specified fixed CR4 bits (mainly CR4.VMXE).
5665 * Note! For nested-guests, we could be altering our VMX emulation's
5666 * fixed bits. We thus need to re-apply them while importing CR4.
5667 */
5668 u64GuestCr4 |= fSetCr4;
5669 u64GuestCr4 &= fZapCr4;
5670
5671 /* Commit the CR4 and CR4 read-shadow to the guest VMCS. */
5672 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR4, u64GuestCr4); AssertRC(rc);
5673 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, u64ShadowCr4); AssertRC(rc);
5674
5675 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
5676 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
5677
5678 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR4);
5679
5680 Log4Func(("cr4=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr4, u64ShadowCr4, fSetCr4, fZapCr4));
5681 }
5682 return rc;
5683}
5684
5685
5686/**
5687 * Exports the guest debug registers into the guest-state area in the VMCS.
5688 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
5689 *
5690 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
5691 *
5692 * @returns VBox status code.
5693 * @param pVCpu The cross context virtual CPU structure.
5694 * @param pVmxTransient The VMX-transient structure.
5695 *
5696 * @remarks No-long-jump zone!!!
5697 */
5698static int hmR0VmxExportSharedDebugState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
5699{
5700 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5701
5702 /** @todo NSTVMX: Figure out what we want to do with nested-guest instruction
5703 * stepping. */
5704 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5705 if (pVmxTransient->fIsNestedGuest)
5706 {
5707 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, CPUMGetGuestDR7(pVCpu));
5708 AssertRC(rc);
5709
5710 /* Always intercept Mov DRx accesses for the nested-guest for now. */
5711 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
5712 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
5713 AssertRC(rc);
5714 return VINF_SUCCESS;
5715 }
5716
5717#ifdef VBOX_STRICT
5718 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
5719 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
5720 {
5721 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
5722 Assert((pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0);
5723 Assert((pVCpu->cpum.GstCtx.dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK);
5724 }
5725#endif
5726
5727 bool fSteppingDB = false;
5728 bool fInterceptMovDRx = false;
5729 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5730 if (pVCpu->hm.s.fSingleInstruction)
5731 {
5732 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
5733 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5734 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
5735 {
5736 uProcCtls |= VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
5737 Assert(fSteppingDB == false);
5738 }
5739 else
5740 {
5741 pVCpu->cpum.GstCtx.eflags.u32 |= X86_EFL_TF;
5742 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_RFLAGS;
5743 pVCpu->hm.s.fClearTrapFlag = true;
5744 fSteppingDB = true;
5745 }
5746 }
5747
5748 uint64_t u64GuestDr7;
5749 if ( fSteppingDB
5750 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
5751 {
5752 /*
5753 * Use the combined guest and host DRx values found in the hypervisor register set
5754 * because the hypervisor debugger has breakpoints active or someone is single stepping
5755 * on the host side without a monitor trap flag.
5756 *
5757 * Note! DBGF expects a clean DR6 state before executing guest code.
5758 */
5759 if (!CPUMIsHyperDebugStateActive(pVCpu))
5760 {
5761 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
5762 Assert(CPUMIsHyperDebugStateActive(pVCpu));
5763 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
5764 }
5765
5766 /* Update DR7 with the hypervisor value (other DRx registers are handled by CPUM one way or another). */
5767 u64GuestDr7 = CPUMGetHyperDR7(pVCpu);
5768 pVCpu->hm.s.fUsingHyperDR7 = true;
5769 fInterceptMovDRx = true;
5770 }
5771 else
5772 {
5773 /*
5774 * If the guest has enabled debug registers, we need to load them prior to
5775 * executing guest code so they'll trigger at the right time.
5776 */
5777 if (pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
5778 {
5779 if (!CPUMIsGuestDebugStateActive(pVCpu))
5780 {
5781 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
5782 Assert(CPUMIsGuestDebugStateActive(pVCpu));
5783 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
5784 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
5785 }
5786 Assert(!fInterceptMovDRx);
5787 }
5788 else if (!CPUMIsGuestDebugStateActive(pVCpu))
5789 {
5790 /*
5791 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
5792 * must intercept #DB in order to maintain a correct DR6 guest value, and
5793 * because we need to intercept it to prevent nested #DBs from hanging the
5794 * CPU, we end up always having to intercept it. See hmR0VmxSetupVmcsXcptBitmap().
5795 */
5796 fInterceptMovDRx = true;
5797 }
5798
5799 /* Update DR7 with the actual guest value. */
5800 u64GuestDr7 = pVCpu->cpum.GstCtx.dr[7];
5801 pVCpu->hm.s.fUsingHyperDR7 = false;
5802 }
5803
5804 if (fInterceptMovDRx)
5805 uProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
5806 else
5807 uProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
5808
5809 /*
5810 * Update the processor-based VM-execution controls with the MOV-DRx intercepts and the
5811 * monitor-trap flag and update our cache.
5812 */
5813 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5814 {
5815 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5816 AssertRC(rc);
5817 pVmcsInfo->u32ProcCtls = uProcCtls;
5818 }
5819
5820 /*
5821 * Update guest DR7.
5822 */
5823 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, u64GuestDr7);
5824 AssertRC(rc);
5825
5826 /*
5827 * If we have forced EFLAGS.TF to be set because we're single-stepping in the hypervisor debugger,
5828 * we need to clear interrupt inhibition if any as otherwise it causes a VM-entry failure.
5829 *
5830 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5831 */
5832 if (fSteppingDB)
5833 {
5834 Assert(pVCpu->hm.s.fSingleInstruction);
5835 Assert(pVCpu->cpum.GstCtx.eflags.Bits.u1TF);
5836
5837 uint32_t fIntrState = 0;
5838 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
5839 AssertRC(rc);
5840
5841 if (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
5842 {
5843 fIntrState &= ~(VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
5844 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
5845 AssertRC(rc);
5846 }
5847 }
5848
5849 return VINF_SUCCESS;
5850}
5851
5852
5853#ifdef VBOX_STRICT
5854/**
5855 * Strict function to validate segment registers.
5856 *
5857 * @param pVCpu The cross context virtual CPU structure.
5858 * @param pVmcsInfo The VMCS info. object.
5859 *
5860 * @remarks Will import guest CR0 on strict builds during validation of
5861 * segments.
5862 */
5863static void hmR0VmxValidateSegmentRegs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5864{
5865 /*
5866 * Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
5867 *
5868 * The reason we check for attribute value 0 in this function and not just the unusable bit is
5869 * because hmR0VmxExportGuestSegReg() only updates the VMCS' copy of the value with the
5870 * unusable bit and doesn't change the guest-context value.
5871 */
5872 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5873 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5874 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR0);
5875 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
5876 && ( !CPUMIsGuestInRealModeEx(pCtx)
5877 && !CPUMIsGuestInV86ModeEx(pCtx)))
5878 {
5879 /* Protected mode checks */
5880 /* CS */
5881 Assert(pCtx->cs.Attr.n.u1Present);
5882 Assert(!(pCtx->cs.Attr.u & 0xf00));
5883 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
5884 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
5885 || !(pCtx->cs.Attr.n.u1Granularity));
5886 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
5887 || (pCtx->cs.Attr.n.u1Granularity));
5888 /* CS cannot be loaded with NULL in protected mode. */
5889 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
5890 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
5891 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
5892 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
5893 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
5894 else
5895 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
5896 /* SS */
5897 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
5898 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
5899 if ( !(pCtx->cr0 & X86_CR0_PE)
5900 || pCtx->cs.Attr.n.u4Type == 3)
5901 {
5902 Assert(!pCtx->ss.Attr.n.u2Dpl);
5903 }
5904 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
5905 {
5906 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
5907 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
5908 Assert(pCtx->ss.Attr.n.u1Present);
5909 Assert(!(pCtx->ss.Attr.u & 0xf00));
5910 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
5911 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
5912 || !(pCtx->ss.Attr.n.u1Granularity));
5913 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
5914 || (pCtx->ss.Attr.n.u1Granularity));
5915 }
5916 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSegReg(). */
5917 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
5918 {
5919 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5920 Assert(pCtx->ds.Attr.n.u1Present);
5921 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
5922 Assert(!(pCtx->ds.Attr.u & 0xf00));
5923 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
5924 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
5925 || !(pCtx->ds.Attr.n.u1Granularity));
5926 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
5927 || (pCtx->ds.Attr.n.u1Granularity));
5928 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5929 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
5930 }
5931 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
5932 {
5933 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5934 Assert(pCtx->es.Attr.n.u1Present);
5935 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
5936 Assert(!(pCtx->es.Attr.u & 0xf00));
5937 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
5938 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
5939 || !(pCtx->es.Attr.n.u1Granularity));
5940 Assert( !(pCtx->es.u32Limit & 0xfff00000)
5941 || (pCtx->es.Attr.n.u1Granularity));
5942 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5943 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
5944 }
5945 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
5946 {
5947 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5948 Assert(pCtx->fs.Attr.n.u1Present);
5949 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
5950 Assert(!(pCtx->fs.Attr.u & 0xf00));
5951 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
5952 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
5953 || !(pCtx->fs.Attr.n.u1Granularity));
5954 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
5955 || (pCtx->fs.Attr.n.u1Granularity));
5956 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5957 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
5958 }
5959 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
5960 {
5961 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5962 Assert(pCtx->gs.Attr.n.u1Present);
5963 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
5964 Assert(!(pCtx->gs.Attr.u & 0xf00));
5965 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
5966 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
5967 || !(pCtx->gs.Attr.n.u1Granularity));
5968 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
5969 || (pCtx->gs.Attr.n.u1Granularity));
5970 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5971 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
5972 }
5973 /* 64-bit capable CPUs. */
5974 Assert(!RT_HI_U32(pCtx->cs.u64Base));
5975 Assert(!pCtx->ss.Attr.u || !RT_HI_U32(pCtx->ss.u64Base));
5976 Assert(!pCtx->ds.Attr.u || !RT_HI_U32(pCtx->ds.u64Base));
5977 Assert(!pCtx->es.Attr.u || !RT_HI_U32(pCtx->es.u64Base));
5978 }
5979 else if ( CPUMIsGuestInV86ModeEx(pCtx)
5980 || ( CPUMIsGuestInRealModeEx(pCtx)
5981 && !pVM->hm.s.vmx.fUnrestrictedGuest))
5982 {
5983 /* Real and v86 mode checks. */
5984 /* hmR0VmxExportGuestSegReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
5985 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
5986 if (pVmcsInfo->RealMode.fRealOnV86Active)
5987 {
5988 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3;
5989 u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
5990 }
5991 else
5992 {
5993 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
5994 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
5995 }
5996
5997 /* CS */
5998 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
5999 Assert(pCtx->cs.u32Limit == 0xffff);
6000 Assert(u32CSAttr == 0xf3);
6001 /* SS */
6002 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
6003 Assert(pCtx->ss.u32Limit == 0xffff);
6004 Assert(u32SSAttr == 0xf3);
6005 /* DS */
6006 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
6007 Assert(pCtx->ds.u32Limit == 0xffff);
6008 Assert(u32DSAttr == 0xf3);
6009 /* ES */
6010 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
6011 Assert(pCtx->es.u32Limit == 0xffff);
6012 Assert(u32ESAttr == 0xf3);
6013 /* FS */
6014 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
6015 Assert(pCtx->fs.u32Limit == 0xffff);
6016 Assert(u32FSAttr == 0xf3);
6017 /* GS */
6018 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
6019 Assert(pCtx->gs.u32Limit == 0xffff);
6020 Assert(u32GSAttr == 0xf3);
6021 /* 64-bit capable CPUs. */
6022 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6023 Assert(!u32SSAttr || !RT_HI_U32(pCtx->ss.u64Base));
6024 Assert(!u32DSAttr || !RT_HI_U32(pCtx->ds.u64Base));
6025 Assert(!u32ESAttr || !RT_HI_U32(pCtx->es.u64Base));
6026 }
6027}
6028#endif /* VBOX_STRICT */
6029
6030
6031/**
6032 * Exports a guest segment register into the guest-state area in the VMCS.
6033 *
6034 * @returns VBox status code.
6035 * @param pVCpu The cross context virtual CPU structure.
6036 * @param pVmcsInfo The VMCS info. object.
6037 * @param iSegReg The segment register number (X86_SREG_XXX).
6038 * @param pSelReg Pointer to the segment selector.
6039 *
6040 * @remarks No-long-jump zone!!!
6041 */
6042static int hmR0VmxExportGuestSegReg(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t iSegReg, PCCPUMSELREG pSelReg)
6043{
6044 Assert(iSegReg < X86_SREG_COUNT);
6045 uint32_t const idxSel = g_aVmcsSegSel[iSegReg];
6046 uint32_t const idxLimit = g_aVmcsSegLimit[iSegReg];
6047 uint32_t const idxBase = g_aVmcsSegBase[iSegReg];
6048 uint32_t const idxAttr = g_aVmcsSegAttr[iSegReg];
6049
6050 uint32_t u32Access = pSelReg->Attr.u;
6051 if (pVmcsInfo->RealMode.fRealOnV86Active)
6052 {
6053 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
6054 u32Access = 0xf3;
6055 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6056 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
6057 RT_NOREF_PV(pVCpu);
6058 }
6059 else
6060 {
6061 /*
6062 * The way to differentiate between whether this is really a null selector or was just
6063 * a selector loaded with 0 in real-mode is using the segment attributes. A selector
6064 * loaded in real-mode with the value 0 is valid and usable in protected-mode and we
6065 * should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures
6066 * NULL selectors loaded in protected-mode have their attribute as 0.
6067 */
6068 if (!u32Access)
6069 u32Access = X86DESCATTR_UNUSABLE;
6070 }
6071
6072 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
6073 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
6074 ("Access bit not set for usable segment. idx=%#x sel=%#x attr %#x\n", idxBase, pSelReg, pSelReg->Attr.u));
6075
6076 /*
6077 * Commit it to the VMCS.
6078 */
6079 int rc = VMXWriteVmcs32(idxSel, pSelReg->Sel); AssertRC(rc);
6080 rc = VMXWriteVmcs32(idxLimit, pSelReg->u32Limit); AssertRC(rc);
6081 rc = VMXWriteVmcsNw(idxBase, pSelReg->u64Base); AssertRC(rc);
6082 rc = VMXWriteVmcs32(idxAttr, u32Access); AssertRC(rc);
6083 return VINF_SUCCESS;
6084}
6085
6086
6087/**
6088 * Exports the guest segment registers, GDTR, IDTR, LDTR, TR into the guest-state
6089 * area in the VMCS.
6090 *
6091 * @returns VBox status code.
6092 * @param pVCpu The cross context virtual CPU structure.
6093 * @param pVmxTransient The VMX-transient structure.
6094 *
6095 * @remarks Will import guest CR0 on strict builds during validation of
6096 * segments.
6097 * @remarks No-long-jump zone!!!
6098 */
6099static int hmR0VmxExportGuestSegRegsXdtr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6100{
6101 int rc = VERR_INTERNAL_ERROR_5;
6102 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6103 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6104 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6105
6106 /*
6107 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
6108 */
6109 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SREG_MASK)
6110 {
6111#ifdef VBOX_WITH_REM
6112 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
6113 {
6114 Assert(!pVmxTransient->fIsNestedGuest);
6115 Assert(pVM->hm.s.vmx.pRealModeTSS);
6116 AssertCompile(PGMMODE_REAL < PGMMODE_PROTECTED);
6117 if ( pVmcsInfo->fWasInRealMode
6118 && PGMGetGuestMode(pVCpu) >= PGMMODE_PROTECTED)
6119 {
6120 /*
6121 * Notify the recompiler must flush its code-cache as the guest -may-
6122 * rewrite code it in real-mode (e.g. OpenBSD 4.0).
6123 */
6124 REMFlushTBs(pVM);
6125 Log4Func(("Switch to protected mode detected!\n"));
6126 pVmcsInfo->fWasInRealMode = false;
6127 }
6128 }
6129#endif
6130 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CS)
6131 {
6132 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CS);
6133 if (pVmcsInfo->RealMode.fRealOnV86Active)
6134 pVmcsInfo->RealMode.AttrCS.u = pCtx->cs.Attr.u;
6135 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_CS, &pCtx->cs);
6136 AssertRC(rc);
6137 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CS);
6138 }
6139
6140 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SS)
6141 {
6142 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SS);
6143 if (pVmcsInfo->RealMode.fRealOnV86Active)
6144 pVmcsInfo->RealMode.AttrSS.u = pCtx->ss.Attr.u;
6145 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_SS, &pCtx->ss);
6146 AssertRC(rc);
6147 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SS);
6148 }
6149
6150 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_DS)
6151 {
6152 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DS);
6153 if (pVmcsInfo->RealMode.fRealOnV86Active)
6154 pVmcsInfo->RealMode.AttrDS.u = pCtx->ds.Attr.u;
6155 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_DS, &pCtx->ds);
6156 AssertRC(rc);
6157 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_DS);
6158 }
6159
6160 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_ES)
6161 {
6162 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_ES);
6163 if (pVmcsInfo->RealMode.fRealOnV86Active)
6164 pVmcsInfo->RealMode.AttrES.u = pCtx->es.Attr.u;
6165 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_ES, &pCtx->es);
6166 AssertRC(rc);
6167 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_ES);
6168 }
6169
6170 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_FS)
6171 {
6172 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_FS);
6173 if (pVmcsInfo->RealMode.fRealOnV86Active)
6174 pVmcsInfo->RealMode.AttrFS.u = pCtx->fs.Attr.u;
6175 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_FS, &pCtx->fs);
6176 AssertRC(rc);
6177 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_FS);
6178 }
6179
6180 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GS)
6181 {
6182 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GS);
6183 if (pVmcsInfo->RealMode.fRealOnV86Active)
6184 pVmcsInfo->RealMode.AttrGS.u = pCtx->gs.Attr.u;
6185 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_GS, &pCtx->gs);
6186 AssertRC(rc);
6187 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GS);
6188 }
6189
6190#ifdef VBOX_STRICT
6191 hmR0VmxValidateSegmentRegs(pVCpu, pVmcsInfo);
6192#endif
6193 Log4Func(("cs={%#04x base=%#RX64 limit=%#RX32 attr=%#RX32}\n", pCtx->cs.Sel, pCtx->cs.u64Base, pCtx->cs.u32Limit,
6194 pCtx->cs.Attr.u));
6195 }
6196
6197 /*
6198 * Guest TR.
6199 */
6200 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_TR)
6201 {
6202 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_TR);
6203
6204 /*
6205 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is
6206 * achieved using the interrupt redirection bitmap (all bits cleared to let the guest
6207 * handle INT-n's) in the TSS. See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
6208 */
6209 uint16_t u16Sel;
6210 uint32_t u32Limit;
6211 uint64_t u64Base;
6212 uint32_t u32AccessRights;
6213 if (!pVmcsInfo->RealMode.fRealOnV86Active)
6214 {
6215 u16Sel = pCtx->tr.Sel;
6216 u32Limit = pCtx->tr.u32Limit;
6217 u64Base = pCtx->tr.u64Base;
6218 u32AccessRights = pCtx->tr.Attr.u;
6219 }
6220 else
6221 {
6222 Assert(!pVmxTransient->fIsNestedGuest);
6223 Assert(pVM->hm.s.vmx.pRealModeTSS);
6224 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMCanExecuteGuest() -XXX- what about inner loop changes? */
6225
6226 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
6227 RTGCPHYS GCPhys;
6228 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
6229 AssertRCReturn(rc, rc);
6230
6231 X86DESCATTR DescAttr;
6232 DescAttr.u = 0;
6233 DescAttr.n.u1Present = 1;
6234 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
6235
6236 u16Sel = 0;
6237 u32Limit = HM_VTX_TSS_SIZE;
6238 u64Base = GCPhys;
6239 u32AccessRights = DescAttr.u;
6240 }
6241
6242 /* Validate. */
6243 Assert(!(u16Sel & RT_BIT(2)));
6244 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
6245 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
6246 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
6247 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
6248 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
6249 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
6250 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
6251 Assert( (u32Limit & 0xfff) == 0xfff
6252 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
6253 Assert( !(pCtx->tr.u32Limit & 0xfff00000)
6254 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
6255
6256 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_TR_SEL, u16Sel); AssertRC(rc);
6257 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit); AssertRC(rc);
6258 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights); AssertRC(rc);
6259 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_TR_BASE, u64Base); AssertRC(rc);
6260
6261 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_TR);
6262 Log4Func(("tr base=%#RX64 limit=%#RX32\n", pCtx->tr.u64Base, pCtx->tr.u32Limit));
6263 }
6264
6265 /*
6266 * Guest GDTR.
6267 */
6268 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GDTR)
6269 {
6270 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GDTR);
6271
6272 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt); AssertRC(rc);
6273 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, pCtx->gdtr.pGdt); AssertRC(rc);
6274
6275 /* Validate. */
6276 Assert(!(pCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6277
6278 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GDTR);
6279 Log4Func(("gdtr base=%#RX64 limit=%#RX32\n", pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt));
6280 }
6281
6282 /*
6283 * Guest LDTR.
6284 */
6285 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_LDTR)
6286 {
6287 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_LDTR);
6288
6289 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
6290 uint32_t u32Access;
6291 if ( !pVmxTransient->fIsNestedGuest
6292 && !pCtx->ldtr.Attr.u)
6293 u32Access = X86DESCATTR_UNUSABLE;
6294 else
6295 u32Access = pCtx->ldtr.Attr.u;
6296
6297 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, pCtx->ldtr.Sel); AssertRC(rc);
6298 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtr.u32Limit); AssertRC(rc);
6299 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access); AssertRC(rc);
6300 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, pCtx->ldtr.u64Base); AssertRC(rc);
6301
6302 /* Validate. */
6303 if (!(u32Access & X86DESCATTR_UNUSABLE))
6304 {
6305 Assert(!(pCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
6306 Assert(pCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
6307 Assert(!pCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
6308 Assert(pCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
6309 Assert(!pCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
6310 Assert(!(pCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
6311 Assert( (pCtx->ldtr.u32Limit & 0xfff) == 0xfff
6312 || !pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
6313 Assert( !(pCtx->ldtr.u32Limit & 0xfff00000)
6314 || pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
6315 }
6316
6317 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_LDTR);
6318 Log4Func(("ldtr base=%#RX64 limit=%#RX32\n", pCtx->ldtr.u64Base, pCtx->ldtr.u32Limit));
6319 }
6320
6321 /*
6322 * Guest IDTR.
6323 */
6324 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_IDTR)
6325 {
6326 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_IDTR);
6327
6328 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt); AssertRC(rc);
6329 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, pCtx->idtr.pIdt); AssertRC(rc);
6330
6331 /* Validate. */
6332 Assert(!(pCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6333
6334 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_IDTR);
6335 Log4Func(("idtr base=%#RX64 limit=%#RX32\n", pCtx->idtr.pIdt, pCtx->idtr.cbIdt));
6336 }
6337
6338 return VINF_SUCCESS;
6339}
6340
6341
6342/**
6343 * Exports certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
6344 * areas.
6345 *
6346 * These MSRs will automatically be loaded to the host CPU on every successful
6347 * VM-entry and stored from the host CPU on every successful VM-exit.
6348 *
6349 * We creates/updates MSR slots for the host MSRs in the VM-exit MSR-load area. The
6350 * actual host MSR values are not- updated here for performance reasons. See
6351 * hmR0VmxExportHostMsrs().
6352 *
6353 * We also exports the guest sysenter MSRs into the guest-state area in the VMCS.
6354 *
6355 * @returns VBox status code.
6356 * @param pVCpu The cross context virtual CPU structure.
6357 * @param pVmxTransient The VMX-transient structure.
6358 *
6359 * @remarks No-long-jump zone!!!
6360 */
6361static int hmR0VmxExportGuestMsrs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6362{
6363 AssertPtr(pVCpu);
6364 AssertPtr(pVmxTransient);
6365
6366 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6367 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6368
6369 /*
6370 * MSRs that we use the auto-load/store MSR area in the VMCS.
6371 * For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(),
6372 * nothing to do here. The host MSR values are updated when it's safe in
6373 * hmR0VmxLazySaveHostMsrs().
6374 *
6375 * For nested-guests, the guests MSRs from the VM-entry MSR-load area are already
6376 * loaded (into the guest-CPU context) by the VMLAUNCH/VMRESUME instruction
6377 * emulation, nothing to do here.
6378 */
6379 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_GUEST_AUTO_MSRS)
6380 {
6381 /* No auto-load/store MSRs currently. */
6382 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_GUEST_AUTO_MSRS);
6383 }
6384
6385 /*
6386 * Guest Sysenter MSRs.
6387 */
6388 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_MSR_MASK)
6389 {
6390 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SYSENTER_MSRS);
6391
6392 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_CS_MSR)
6393 {
6394 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pCtx->SysEnter.cs);
6395 AssertRC(rc);
6396 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_CS_MSR);
6397 }
6398
6399 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_EIP_MSR)
6400 {
6401 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, pCtx->SysEnter.eip);
6402 AssertRC(rc);
6403 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
6404 }
6405
6406 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_ESP_MSR)
6407 {
6408 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, pCtx->SysEnter.esp);
6409 AssertRC(rc);
6410 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
6411 }
6412 }
6413
6414 /*
6415 * Guest/host EFER MSR.
6416 */
6417 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_EFER_MSR)
6418 {
6419 /* Whether we are using the VMCS to swap the EFER MSR must have been
6420 determined earlier while exporting VM-entry/VM-exit controls. */
6421 Assert(!(ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS));
6422 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
6423
6424 if (hmR0VmxShouldSwapEferMsr(pVCpu))
6425 {
6426 /*
6427 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
6428 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
6429 */
6430 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
6431 {
6432 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, pCtx->msrEFER);
6433 AssertRC(rc);
6434 }
6435 else
6436 {
6437 /*
6438 * We shall use the auto-load/store MSR area only for loading the EFER MSR but we must
6439 * continue to intercept guest read and write accesses to it, see @bugref{7386#c16}.
6440 */
6441 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER, pCtx->msrEFER,
6442 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6443 AssertRCReturn(rc, rc);
6444 }
6445 }
6446 else if (!pVM->hm.s.vmx.fSupportsVmcsEfer)
6447 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER);
6448
6449 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_EFER_MSR);
6450 }
6451
6452 /*
6453 * Other MSRs.
6454 * Speculation Control (R/W).
6455 */
6456 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_OTHER_MSRS)
6457 {
6458 HMVMX_CPUMCTX_ASSERT(pVCpu, HM_CHANGED_GUEST_OTHER_MSRS);
6459 if (pVM->cpum.ro.GuestFeatures.fIbrs)
6460 {
6461 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_IA32_SPEC_CTRL, CPUMGetGuestSpecCtrl(pVCpu),
6462 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6463 AssertRCReturn(rc, rc);
6464 }
6465 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
6466 }
6467
6468 return VINF_SUCCESS;
6469}
6470
6471
6472/**
6473 * Selects up the appropriate function to run guest code.
6474 *
6475 * @returns VBox status code.
6476 * @param pVCpu The cross context virtual CPU structure.
6477 * @param pVmxTransient The VMX-transient structure.
6478 *
6479 * @remarks No-long-jump zone!!!
6480 */
6481static int hmR0VmxSelectVMRunHandler(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6482{
6483 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6484 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6485
6486 if (CPUMIsGuestInLongModeEx(pCtx))
6487 {
6488#ifndef VBOX_WITH_64_BITS_GUESTS
6489 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
6490#else
6491 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
6492 /* Guest is in long mode, use the 64-bit handler (host is 64-bit). */
6493 pVmcsInfo->pfnStartVM = VMXR0StartVM64;
6494#endif
6495 }
6496 else
6497 {
6498 /* Guest is not in long mode, use the 32-bit handler. */
6499 pVmcsInfo->pfnStartVM = VMXR0StartVM32;
6500 }
6501 Assert(pVmcsInfo->pfnStartVM);
6502 return VINF_SUCCESS;
6503}
6504
6505
6506/**
6507 * Wrapper for running the guest code in VT-x.
6508 *
6509 * @returns VBox status code, no informational status codes.
6510 * @param pVCpu The cross context virtual CPU structure.
6511 * @param pVmxTransient The VMX-transient structure.
6512 *
6513 * @remarks No-long-jump zone!!!
6514 */
6515DECLINLINE(int) hmR0VmxRunGuest(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6516{
6517 /* Mark that HM is the keeper of all guest-CPU registers now that we're going to execute guest code. */
6518 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6519 pCtx->fExtrn |= HMVMX_CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_KEEPER_HM;
6520
6521 /** @todo Add stats for VMRESUME vs VMLAUNCH. */
6522
6523 /*
6524 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses
6525 * floating-point operations using SSE instructions. Some XMM registers (XMM6-XMM15) are
6526 * callee-saved and thus the need for this XMM wrapper.
6527 *
6528 * See MSDN "Configuring Programs for 64-bit/x64 Software Conventions / Register Usage".
6529 */
6530 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6531 bool const fResumeVM = RT_BOOL(pVmcsInfo->fVmcsState & VMX_V_VMCS_LAUNCH_STATE_LAUNCHED);
6532 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6533#ifdef VBOX_WITH_KERNEL_USING_XMM
6534 int rc = hmR0VMXStartVMWrapXMM(fResumeVM, pCtx, NULL /*pvUnused*/, pVM, pVCpu, pVmcsInfo->pfnStartVM);
6535#else
6536 int rc = pVmcsInfo->pfnStartVM(fResumeVM, pCtx, NULL /*pvUnused*/, pVM, pVCpu);
6537#endif
6538 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
6539 return rc;
6540}
6541
6542
6543/**
6544 * Reports world-switch error and dumps some useful debug info.
6545 *
6546 * @param pVCpu The cross context virtual CPU structure.
6547 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
6548 * @param pVmxTransient The VMX-transient structure (only
6549 * exitReason updated).
6550 */
6551static void hmR0VmxReportWorldSwitchError(PVMCPUCC pVCpu, int rcVMRun, PVMXTRANSIENT pVmxTransient)
6552{
6553 Assert(pVCpu);
6554 Assert(pVmxTransient);
6555 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
6556
6557 Log4Func(("VM-entry failure: %Rrc\n", rcVMRun));
6558 switch (rcVMRun)
6559 {
6560 case VERR_VMX_INVALID_VMXON_PTR:
6561 AssertFailed();
6562 break;
6563 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
6564 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
6565 {
6566 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
6567 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
6568 AssertRC(rc);
6569 hmR0VmxReadExitQualVmcs(pVmxTransient);
6570
6571 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
6572 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
6573 Cannot do it here as we may have been long preempted. */
6574
6575#ifdef VBOX_STRICT
6576 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6577 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
6578 pVmxTransient->uExitReason));
6579 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQual));
6580 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
6581 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
6582 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
6583 else
6584 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
6585 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
6586 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
6587
6588 static struct
6589 {
6590 /** Name of the field to log. */
6591 const char *pszName;
6592 /** The VMCS field. */
6593 uint32_t uVmcsField;
6594 /** Whether host support of this field needs to be checked. */
6595 bool fCheckSupport;
6596 } const s_aVmcsFields[] =
6597 {
6598 { "VMX_VMCS32_CTRL_PIN_EXEC", VMX_VMCS32_CTRL_PIN_EXEC, false },
6599 { "VMX_VMCS32_CTRL_PROC_EXEC", VMX_VMCS32_CTRL_PROC_EXEC, false },
6600 { "VMX_VMCS32_CTRL_PROC_EXEC2", VMX_VMCS32_CTRL_PROC_EXEC2, true },
6601 { "VMX_VMCS32_CTRL_ENTRY", VMX_VMCS32_CTRL_ENTRY, false },
6602 { "VMX_VMCS32_CTRL_EXIT", VMX_VMCS32_CTRL_EXIT, false },
6603 { "VMX_VMCS32_CTRL_CR3_TARGET_COUNT", VMX_VMCS32_CTRL_CR3_TARGET_COUNT, false },
6604 { "VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO", VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, false },
6605 { "VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE", VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, false },
6606 { "VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH", VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, false },
6607 { "VMX_VMCS32_CTRL_TPR_THRESHOLD", VMX_VMCS32_CTRL_TPR_THRESHOLD, false },
6608 { "VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, false },
6609 { "VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, false },
6610 { "VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, false },
6611 { "VMX_VMCS32_CTRL_EXCEPTION_BITMAP", VMX_VMCS32_CTRL_EXCEPTION_BITMAP, false },
6612 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, false },
6613 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, false },
6614 { "VMX_VMCS_CTRL_CR0_MASK", VMX_VMCS_CTRL_CR0_MASK, false },
6615 { "VMX_VMCS_CTRL_CR0_READ_SHADOW", VMX_VMCS_CTRL_CR0_READ_SHADOW, false },
6616 { "VMX_VMCS_CTRL_CR4_MASK", VMX_VMCS_CTRL_CR4_MASK, false },
6617 { "VMX_VMCS_CTRL_CR4_READ_SHADOW", VMX_VMCS_CTRL_CR4_READ_SHADOW, false },
6618 { "VMX_VMCS64_CTRL_EPTP_FULL", VMX_VMCS64_CTRL_EPTP_FULL, true },
6619 { "VMX_VMCS_GUEST_RIP", VMX_VMCS_GUEST_RIP, false },
6620 { "VMX_VMCS_GUEST_RSP", VMX_VMCS_GUEST_RSP, false },
6621 { "VMX_VMCS_GUEST_RFLAGS", VMX_VMCS_GUEST_RFLAGS, false },
6622 { "VMX_VMCS16_VPID", VMX_VMCS16_VPID, true, },
6623 { "VMX_VMCS_HOST_CR0", VMX_VMCS_HOST_CR0, false },
6624 { "VMX_VMCS_HOST_CR3", VMX_VMCS_HOST_CR3, false },
6625 { "VMX_VMCS_HOST_CR4", VMX_VMCS_HOST_CR4, false },
6626 /* The order of selector fields below are fixed! */
6627 { "VMX_VMCS16_HOST_ES_SEL", VMX_VMCS16_HOST_ES_SEL, false },
6628 { "VMX_VMCS16_HOST_CS_SEL", VMX_VMCS16_HOST_CS_SEL, false },
6629 { "VMX_VMCS16_HOST_SS_SEL", VMX_VMCS16_HOST_SS_SEL, false },
6630 { "VMX_VMCS16_HOST_DS_SEL", VMX_VMCS16_HOST_DS_SEL, false },
6631 { "VMX_VMCS16_HOST_FS_SEL", VMX_VMCS16_HOST_FS_SEL, false },
6632 { "VMX_VMCS16_HOST_GS_SEL", VMX_VMCS16_HOST_GS_SEL, false },
6633 { "VMX_VMCS16_HOST_TR_SEL", VMX_VMCS16_HOST_TR_SEL, false },
6634 /* End of ordered selector fields. */
6635 { "VMX_VMCS_HOST_TR_BASE", VMX_VMCS_HOST_TR_BASE, false },
6636 { "VMX_VMCS_HOST_GDTR_BASE", VMX_VMCS_HOST_GDTR_BASE, false },
6637 { "VMX_VMCS_HOST_IDTR_BASE", VMX_VMCS_HOST_IDTR_BASE, false },
6638 { "VMX_VMCS32_HOST_SYSENTER_CS", VMX_VMCS32_HOST_SYSENTER_CS, false },
6639 { "VMX_VMCS_HOST_SYSENTER_EIP", VMX_VMCS_HOST_SYSENTER_EIP, false },
6640 { "VMX_VMCS_HOST_SYSENTER_ESP", VMX_VMCS_HOST_SYSENTER_ESP, false },
6641 { "VMX_VMCS_HOST_RSP", VMX_VMCS_HOST_RSP, false },
6642 { "VMX_VMCS_HOST_RIP", VMX_VMCS_HOST_RIP, false }
6643 };
6644
6645 RTGDTR HostGdtr;
6646 ASMGetGDTR(&HostGdtr);
6647
6648 uint32_t const cVmcsFields = RT_ELEMENTS(s_aVmcsFields);
6649 for (uint32_t i = 0; i < cVmcsFields; i++)
6650 {
6651 uint32_t const uVmcsField = s_aVmcsFields[i].uVmcsField;
6652
6653 bool fSupported;
6654 if (!s_aVmcsFields[i].fCheckSupport)
6655 fSupported = true;
6656 else
6657 {
6658 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6659 switch (uVmcsField)
6660 {
6661 case VMX_VMCS64_CTRL_EPTP_FULL: fSupported = pVM->hm.s.fNestedPaging; break;
6662 case VMX_VMCS16_VPID: fSupported = pVM->hm.s.vmx.fVpid; break;
6663 case VMX_VMCS32_CTRL_PROC_EXEC2:
6664 fSupported = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
6665 break;
6666 default:
6667 AssertMsgFailedReturnVoid(("Failed to provide VMCS field support for %#RX32\n", uVmcsField));
6668 }
6669 }
6670
6671 if (fSupported)
6672 {
6673 uint8_t const uWidth = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH);
6674 switch (uWidth)
6675 {
6676 case VMX_VMCSFIELD_WIDTH_16BIT:
6677 {
6678 uint16_t u16Val;
6679 rc = VMXReadVmcs16(uVmcsField, &u16Val);
6680 AssertRC(rc);
6681 Log4(("%-40s = %#RX16\n", s_aVmcsFields[i].pszName, u16Val));
6682
6683 if ( uVmcsField >= VMX_VMCS16_HOST_ES_SEL
6684 && uVmcsField <= VMX_VMCS16_HOST_TR_SEL)
6685 {
6686 if (u16Val < HostGdtr.cbGdt)
6687 {
6688 /* Order of selectors in s_apszSel is fixed and matches the order in s_aVmcsFields. */
6689 static const char * const s_apszSel[] = { "Host ES", "Host CS", "Host SS", "Host DS",
6690 "Host FS", "Host GS", "Host TR" };
6691 uint8_t const idxSel = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_INDEX);
6692 Assert(idxSel < RT_ELEMENTS(s_apszSel));
6693 PCX86DESCHC pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u16Val & X86_SEL_MASK));
6694 hmR0DumpDescriptor(pDesc, u16Val, s_apszSel[idxSel]);
6695 }
6696 else
6697 Log4((" Selector value exceeds GDT limit!\n"));
6698 }
6699 break;
6700 }
6701
6702 case VMX_VMCSFIELD_WIDTH_32BIT:
6703 {
6704 uint32_t u32Val;
6705 rc = VMXReadVmcs32(uVmcsField, &u32Val);
6706 AssertRC(rc);
6707 Log4(("%-40s = %#RX32\n", s_aVmcsFields[i].pszName, u32Val));
6708 break;
6709 }
6710
6711 case VMX_VMCSFIELD_WIDTH_64BIT:
6712 case VMX_VMCSFIELD_WIDTH_NATURAL:
6713 {
6714 uint64_t u64Val;
6715 rc = VMXReadVmcs64(uVmcsField, &u64Val);
6716 AssertRC(rc);
6717 Log4(("%-40s = %#RX64\n", s_aVmcsFields[i].pszName, u64Val));
6718 break;
6719 }
6720 }
6721 }
6722 }
6723
6724 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
6725 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
6726 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
6727 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
6728 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
6729 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
6730#endif /* VBOX_STRICT */
6731 break;
6732 }
6733
6734 default:
6735 /* Impossible */
6736 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
6737 break;
6738 }
6739}
6740
6741
6742/**
6743 * Sets up the usage of TSC-offsetting and updates the VMCS.
6744 *
6745 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
6746 * VMX-preemption timer.
6747 *
6748 * @returns VBox status code.
6749 * @param pVCpu The cross context virtual CPU structure.
6750 * @param pVmxTransient The VMX-transient structure.
6751 *
6752 * @remarks No-long-jump zone!!!
6753 */
6754static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6755{
6756 bool fOffsettedTsc;
6757 bool fParavirtTsc;
6758 uint64_t uTscOffset;
6759 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6760 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6761
6762 if (pVM->hm.s.vmx.fUsePreemptTimer)
6763 {
6764 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &uTscOffset, &fOffsettedTsc, &fParavirtTsc);
6765
6766 /* Make sure the returned values have sane upper and lower boundaries. */
6767 uint64_t u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
6768 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second */
6769 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
6770 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
6771
6772 /** @todo r=ramshankar: We need to find a way to integrate nested-guest
6773 * preemption timers here. We probably need to clamp the preemption timer,
6774 * after converting the timer value to the host. */
6775 uint32_t const cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
6776 int rc = VMXWriteVmcs32(VMX_VMCS32_PREEMPT_TIMER_VALUE, cPreemptionTickCount);
6777 AssertRC(rc);
6778 }
6779 else
6780 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
6781
6782 if (fParavirtTsc)
6783 {
6784 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
6785 information before every VM-entry, hence disable it for performance sake. */
6786#if 0
6787 int rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
6788 AssertRC(rc);
6789#endif
6790 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
6791 }
6792
6793 if ( fOffsettedTsc
6794 && RT_LIKELY(!pVCpu->hm.s.fDebugWantRdTscExit))
6795 {
6796 if (pVmxTransient->fIsNestedGuest)
6797 uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
6798 hmR0VmxSetTscOffsetVmcs(pVmcsInfo, uTscOffset);
6799 hmR0VmxRemoveProcCtlsVmcs(pVCpu, pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
6800 }
6801 else
6802 {
6803 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
6804 hmR0VmxSetProcCtlsVmcs(pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
6805 }
6806}
6807
6808
6809/**
6810 * Gets the IEM exception flags for the specified vector and IDT vectoring /
6811 * VM-exit interruption info type.
6812 *
6813 * @returns The IEM exception flags.
6814 * @param uVector The event vector.
6815 * @param uVmxEventType The VMX event type.
6816 *
6817 * @remarks This function currently only constructs flags required for
6818 * IEMEvaluateRecursiveXcpt and not the complete flags (e.g, error-code
6819 * and CR2 aspects of an exception are not included).
6820 */
6821static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxEventType)
6822{
6823 uint32_t fIemXcptFlags;
6824 switch (uVmxEventType)
6825 {
6826 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
6827 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
6828 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
6829 break;
6830
6831 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
6832 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
6833 break;
6834
6835 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
6836 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
6837 break;
6838
6839 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
6840 {
6841 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6842 if (uVector == X86_XCPT_BP)
6843 fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
6844 else if (uVector == X86_XCPT_OF)
6845 fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
6846 else
6847 {
6848 fIemXcptFlags = 0;
6849 AssertMsgFailed(("Unexpected vector for software exception. uVector=%#x", uVector));
6850 }
6851 break;
6852 }
6853
6854 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
6855 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6856 break;
6857
6858 default:
6859 fIemXcptFlags = 0;
6860 AssertMsgFailed(("Unexpected vector type! uVmxEventType=%#x uVector=%#x", uVmxEventType, uVector));
6861 break;
6862 }
6863 return fIemXcptFlags;
6864}
6865
6866
6867/**
6868 * Sets an event as a pending event to be injected into the guest.
6869 *
6870 * @param pVCpu The cross context virtual CPU structure.
6871 * @param u32IntInfo The VM-entry interruption-information field.
6872 * @param cbInstr The VM-entry instruction length in bytes (for
6873 * software interrupts, exceptions and privileged
6874 * software exceptions).
6875 * @param u32ErrCode The VM-entry exception error code.
6876 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
6877 * page-fault.
6878 */
6879DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPUCC pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
6880 RTGCUINTPTR GCPtrFaultAddress)
6881{
6882 Assert(!pVCpu->hm.s.Event.fPending);
6883 pVCpu->hm.s.Event.fPending = true;
6884 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
6885 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
6886 pVCpu->hm.s.Event.cbInstr = cbInstr;
6887 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
6888}
6889
6890
6891/**
6892 * Sets an external interrupt as pending-for-injection into the VM.
6893 *
6894 * @param pVCpu The cross context virtual CPU structure.
6895 * @param u8Interrupt The external interrupt vector.
6896 */
6897DECLINLINE(void) hmR0VmxSetPendingExtInt(PVMCPUCC pVCpu, uint8_t u8Interrupt)
6898{
6899 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, u8Interrupt)
6900 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
6901 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6902 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6903 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6904}
6905
6906
6907/**
6908 * Sets an NMI (\#NMI) exception as pending-for-injection into the VM.
6909 *
6910 * @param pVCpu The cross context virtual CPU structure.
6911 */
6912DECLINLINE(void) hmR0VmxSetPendingXcptNmi(PVMCPUCC pVCpu)
6913{
6914 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI)
6915 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI)
6916 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6917 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6918 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6919}
6920
6921
6922/**
6923 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
6924 *
6925 * @param pVCpu The cross context virtual CPU structure.
6926 */
6927DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPUCC pVCpu)
6928{
6929 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
6930 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6931 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6932 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6933 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6934}
6935
6936
6937/**
6938 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
6939 *
6940 * @param pVCpu The cross context virtual CPU structure.
6941 */
6942DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPUCC pVCpu)
6943{
6944 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_UD)
6945 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6946 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6947 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6948 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6949}
6950
6951
6952/**
6953 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
6954 *
6955 * @param pVCpu The cross context virtual CPU structure.
6956 */
6957DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPUCC pVCpu)
6958{
6959 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
6960 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6961 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6962 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6963 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6964}
6965
6966
6967#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6968/**
6969 * Sets a general-protection (\#GP) exception as pending-for-injection into the VM.
6970 *
6971 * @param pVCpu The cross context virtual CPU structure.
6972 * @param u32ErrCode The error code for the general-protection exception.
6973 */
6974DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPUCC pVCpu, uint32_t u32ErrCode)
6975{
6976 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
6977 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6978 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6979 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6980 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
6981}
6982
6983
6984/**
6985 * Sets a stack (\#SS) exception as pending-for-injection into the VM.
6986 *
6987 * @param pVCpu The cross context virtual CPU structure.
6988 * @param u32ErrCode The error code for the stack exception.
6989 */
6990DECLINLINE(void) hmR0VmxSetPendingXcptSS(PVMCPUCC pVCpu, uint32_t u32ErrCode)
6991{
6992 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_SS)
6993 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6994 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6995 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6996 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
6997}
6998#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
6999
7000
7001/**
7002 * Fixes up attributes for the specified segment register.
7003 *
7004 * @param pVCpu The cross context virtual CPU structure.
7005 * @param pSelReg The segment register that needs fixing.
7006 * @param idxSel The VMCS field for the corresponding segment register.
7007 */
7008static void hmR0VmxFixUnusableSegRegAttr(PVMCPUCC pVCpu, PCPUMSELREG pSelReg, uint32_t idxSel)
7009{
7010 Assert(pSelReg->Attr.u & X86DESCATTR_UNUSABLE);
7011
7012 /*
7013 * If VT-x marks the segment as unusable, most other bits remain undefined:
7014 * - For CS the L, D and G bits have meaning.
7015 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
7016 * - For the remaining data segments no bits are defined.
7017 *
7018 * The present bit and the unusable bit has been observed to be set at the
7019 * same time (the selector was supposed to be invalid as we started executing
7020 * a V8086 interrupt in ring-0).
7021 *
7022 * What should be important for the rest of the VBox code, is that the P bit is
7023 * cleared. Some of the other VBox code recognizes the unusable bit, but
7024 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
7025 * safe side here, we'll strip off P and other bits we don't care about. If
7026 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
7027 *
7028 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
7029 */
7030#ifdef VBOX_STRICT
7031 uint32_t const uAttr = pSelReg->Attr.u;
7032#endif
7033
7034 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
7035 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
7036 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
7037
7038#ifdef VBOX_STRICT
7039 VMMRZCallRing3Disable(pVCpu);
7040 Log4Func(("Unusable %#x: sel=%#x attr=%#x -> %#x\n", idxSel, pSelReg->Sel, uAttr, pSelReg->Attr.u));
7041# ifdef DEBUG_bird
7042 AssertMsg((uAttr & ~X86DESCATTR_P) == pSelReg->Attr.u,
7043 ("%#x: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
7044 idxSel, uAttr, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
7045# endif
7046 VMMRZCallRing3Enable(pVCpu);
7047 NOREF(uAttr);
7048#endif
7049 RT_NOREF2(pVCpu, idxSel);
7050}
7051
7052
7053/**
7054 * Imports a guest segment register from the current VMCS into the guest-CPU
7055 * context.
7056 *
7057 * @param pVCpu The cross context virtual CPU structure.
7058 * @param iSegReg The segment register number (X86_SREG_XXX).
7059 *
7060 * @remarks Called with interrupts and/or preemption disabled.
7061 */
7062static void hmR0VmxImportGuestSegReg(PVMCPUCC pVCpu, uint8_t iSegReg)
7063{
7064 Assert(iSegReg < X86_SREG_COUNT);
7065
7066 uint32_t const idxSel = g_aVmcsSegSel[iSegReg];
7067 uint32_t const idxLimit = g_aVmcsSegLimit[iSegReg];
7068 uint32_t const idxAttr = g_aVmcsSegAttr[iSegReg];
7069 uint32_t const idxBase = g_aVmcsSegBase[iSegReg];
7070
7071 uint16_t u16Sel;
7072 uint64_t u64Base;
7073 uint32_t u32Limit, u32Attr;
7074 int rc = VMXReadVmcs16(idxSel, &u16Sel); AssertRC(rc);
7075 rc = VMXReadVmcs32(idxLimit, &u32Limit); AssertRC(rc);
7076 rc = VMXReadVmcs32(idxAttr, &u32Attr); AssertRC(rc);
7077 rc = VMXReadVmcsNw(idxBase, &u64Base); AssertRC(rc);
7078
7079 PCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
7080 pSelReg->Sel = u16Sel;
7081 pSelReg->ValidSel = u16Sel;
7082 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
7083 pSelReg->u32Limit = u32Limit;
7084 pSelReg->u64Base = u64Base;
7085 pSelReg->Attr.u = u32Attr;
7086 if (u32Attr & X86DESCATTR_UNUSABLE)
7087 hmR0VmxFixUnusableSegRegAttr(pVCpu, pSelReg, idxSel);
7088}
7089
7090
7091/**
7092 * Imports the guest LDTR from the current VMCS into the guest-CPU context.
7093 *
7094 * @param pVCpu The cross context virtual CPU structure.
7095 *
7096 * @remarks Called with interrupts and/or preemption disabled.
7097 */
7098static void hmR0VmxImportGuestLdtr(PVMCPUCC pVCpu)
7099{
7100 uint16_t u16Sel;
7101 uint64_t u64Base;
7102 uint32_t u32Limit, u32Attr;
7103 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, &u16Sel); AssertRC(rc);
7104 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, &u32Limit); AssertRC(rc);
7105 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7106 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, &u64Base); AssertRC(rc);
7107
7108 pVCpu->cpum.GstCtx.ldtr.Sel = u16Sel;
7109 pVCpu->cpum.GstCtx.ldtr.ValidSel = u16Sel;
7110 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
7111 pVCpu->cpum.GstCtx.ldtr.u32Limit = u32Limit;
7112 pVCpu->cpum.GstCtx.ldtr.u64Base = u64Base;
7113 pVCpu->cpum.GstCtx.ldtr.Attr.u = u32Attr;
7114 if (u32Attr & X86DESCATTR_UNUSABLE)
7115 hmR0VmxFixUnusableSegRegAttr(pVCpu, &pVCpu->cpum.GstCtx.ldtr, VMX_VMCS16_GUEST_LDTR_SEL);
7116}
7117
7118
7119/**
7120 * Imports the guest TR from the current VMCS into the guest-CPU context.
7121 *
7122 * @param pVCpu The cross context virtual CPU structure.
7123 *
7124 * @remarks Called with interrupts and/or preemption disabled.
7125 */
7126static void hmR0VmxImportGuestTr(PVMCPUCC pVCpu)
7127{
7128 uint16_t u16Sel;
7129 uint64_t u64Base;
7130 uint32_t u32Limit, u32Attr;
7131 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_TR_SEL, &u16Sel); AssertRC(rc);
7132 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, &u32Limit); AssertRC(rc);
7133 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7134 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_TR_BASE, &u64Base); AssertRC(rc);
7135
7136 pVCpu->cpum.GstCtx.tr.Sel = u16Sel;
7137 pVCpu->cpum.GstCtx.tr.ValidSel = u16Sel;
7138 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
7139 pVCpu->cpum.GstCtx.tr.u32Limit = u32Limit;
7140 pVCpu->cpum.GstCtx.tr.u64Base = u64Base;
7141 pVCpu->cpum.GstCtx.tr.Attr.u = u32Attr;
7142 /* TR is the only selector that can never be unusable. */
7143 Assert(!(u32Attr & X86DESCATTR_UNUSABLE));
7144}
7145
7146
7147/**
7148 * Imports the guest RIP from the VMCS back into the guest-CPU context.
7149 *
7150 * @param pVCpu The cross context virtual CPU structure.
7151 *
7152 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7153 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7154 * instead!!!
7155 */
7156static void hmR0VmxImportGuestRip(PVMCPUCC pVCpu)
7157{
7158 uint64_t u64Val;
7159 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7160 if (pCtx->fExtrn & CPUMCTX_EXTRN_RIP)
7161 {
7162 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
7163 AssertRC(rc);
7164
7165 pCtx->rip = u64Val;
7166 EMR0HistoryUpdatePC(pVCpu, pCtx->rip, false);
7167 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RIP;
7168 }
7169}
7170
7171
7172/**
7173 * Imports the guest RFLAGS from the VMCS back into the guest-CPU context.
7174 *
7175 * @param pVCpu The cross context virtual CPU structure.
7176 * @param pVmcsInfo The VMCS info. object.
7177 *
7178 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7179 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7180 * instead!!!
7181 */
7182static void hmR0VmxImportGuestRFlags(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7183{
7184 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7185 if (pCtx->fExtrn & CPUMCTX_EXTRN_RFLAGS)
7186 {
7187 uint64_t u64Val;
7188 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
7189 AssertRC(rc);
7190
7191 pCtx->rflags.u64 = u64Val;
7192 if (pVmcsInfo->RealMode.fRealOnV86Active)
7193 {
7194 pCtx->eflags.Bits.u1VM = 0;
7195 pCtx->eflags.Bits.u2IOPL = pVmcsInfo->RealMode.Eflags.Bits.u2IOPL;
7196 }
7197 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RFLAGS;
7198 }
7199}
7200
7201
7202/**
7203 * Imports the guest interruptibility-state from the VMCS back into the guest-CPU
7204 * context.
7205 *
7206 * @param pVCpu The cross context virtual CPU structure.
7207 * @param pVmcsInfo The VMCS info. object.
7208 *
7209 * @remarks Called with interrupts and/or preemption disabled, try not to assert and
7210 * do not log!
7211 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7212 * instead!!!
7213 */
7214static void hmR0VmxImportGuestIntrState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7215{
7216 uint32_t u32Val;
7217 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32Val); AssertRC(rc);
7218 if (!u32Val)
7219 {
7220 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7221 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7222 CPUMSetGuestNmiBlocking(pVCpu, false);
7223 }
7224 else
7225 {
7226 /*
7227 * We must import RIP here to set our EM interrupt-inhibited state.
7228 * We also import RFLAGS as our code that evaluates pending interrupts
7229 * before VM-entry requires it.
7230 */
7231 hmR0VmxImportGuestRip(pVCpu);
7232 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7233
7234 if (u32Val & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
7235 EMSetInhibitInterruptsPC(pVCpu, pVCpu->cpum.GstCtx.rip);
7236 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7237 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7238
7239 bool const fNmiBlocking = RT_BOOL(u32Val & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
7240 CPUMSetGuestNmiBlocking(pVCpu, fNmiBlocking);
7241 }
7242}
7243
7244
7245/**
7246 * Worker for VMXR0ImportStateOnDemand.
7247 *
7248 * @returns VBox status code.
7249 * @param pVCpu The cross context virtual CPU structure.
7250 * @param pVmcsInfo The VMCS info. object.
7251 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7252 */
7253static int hmR0VmxImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
7254{
7255 int rc = VINF_SUCCESS;
7256 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7257 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7258 uint32_t u32Val;
7259
7260 /*
7261 * Note! This is hack to workaround a mysterious BSOD observed with release builds
7262 * on Windows 10 64-bit hosts. Profile and debug builds are not affected and
7263 * neither are other host platforms.
7264 *
7265 * Committing this temporarily as it prevents BSOD.
7266 *
7267 * Update: This is very likely a compiler optimization bug, see @bugref{9180}.
7268 */
7269#ifdef RT_OS_WINDOWS
7270 if (pVM == 0 || pVM == (void *)(uintptr_t)-1)
7271 return VERR_HM_IPE_1;
7272#endif
7273
7274 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatImportGuestState, x);
7275
7276 /*
7277 * We disable interrupts to make the updating of the state and in particular
7278 * the fExtrn modification atomic wrt to preemption hooks.
7279 */
7280 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
7281
7282 fWhat &= pCtx->fExtrn;
7283 if (fWhat)
7284 {
7285 do
7286 {
7287 if (fWhat & CPUMCTX_EXTRN_RIP)
7288 hmR0VmxImportGuestRip(pVCpu);
7289
7290 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
7291 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7292
7293 if (fWhat & CPUMCTX_EXTRN_HM_VMX_INT_STATE)
7294 hmR0VmxImportGuestIntrState(pVCpu, pVmcsInfo);
7295
7296 if (fWhat & CPUMCTX_EXTRN_RSP)
7297 {
7298 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RSP, &pCtx->rsp);
7299 AssertRC(rc);
7300 }
7301
7302 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
7303 {
7304 bool const fRealOnV86Active = pVmcsInfo->RealMode.fRealOnV86Active;
7305 if (fWhat & CPUMCTX_EXTRN_CS)
7306 {
7307 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_CS);
7308 hmR0VmxImportGuestRip(pVCpu);
7309 if (fRealOnV86Active)
7310 pCtx->cs.Attr.u = pVmcsInfo->RealMode.AttrCS.u;
7311 EMR0HistoryUpdatePC(pVCpu, pCtx->cs.u64Base + pCtx->rip, true /* fFlattened */);
7312 }
7313 if (fWhat & CPUMCTX_EXTRN_SS)
7314 {
7315 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_SS);
7316 if (fRealOnV86Active)
7317 pCtx->ss.Attr.u = pVmcsInfo->RealMode.AttrSS.u;
7318 }
7319 if (fWhat & CPUMCTX_EXTRN_DS)
7320 {
7321 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_DS);
7322 if (fRealOnV86Active)
7323 pCtx->ds.Attr.u = pVmcsInfo->RealMode.AttrDS.u;
7324 }
7325 if (fWhat & CPUMCTX_EXTRN_ES)
7326 {
7327 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_ES);
7328 if (fRealOnV86Active)
7329 pCtx->es.Attr.u = pVmcsInfo->RealMode.AttrES.u;
7330 }
7331 if (fWhat & CPUMCTX_EXTRN_FS)
7332 {
7333 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_FS);
7334 if (fRealOnV86Active)
7335 pCtx->fs.Attr.u = pVmcsInfo->RealMode.AttrFS.u;
7336 }
7337 if (fWhat & CPUMCTX_EXTRN_GS)
7338 {
7339 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_GS);
7340 if (fRealOnV86Active)
7341 pCtx->gs.Attr.u = pVmcsInfo->RealMode.AttrGS.u;
7342 }
7343 }
7344
7345 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
7346 {
7347 if (fWhat & CPUMCTX_EXTRN_LDTR)
7348 hmR0VmxImportGuestLdtr(pVCpu);
7349
7350 if (fWhat & CPUMCTX_EXTRN_GDTR)
7351 {
7352 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &pCtx->gdtr.pGdt); AssertRC(rc);
7353 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRC(rc);
7354 pCtx->gdtr.cbGdt = u32Val;
7355 }
7356
7357 /* Guest IDTR. */
7358 if (fWhat & CPUMCTX_EXTRN_IDTR)
7359 {
7360 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &pCtx->idtr.pIdt); AssertRC(rc);
7361 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRC(rc);
7362 pCtx->idtr.cbIdt = u32Val;
7363 }
7364
7365 /* Guest TR. */
7366 if (fWhat & CPUMCTX_EXTRN_TR)
7367 {
7368 /* Real-mode emulation using virtual-8086 mode has the fake TSS (pRealModeTSS) in TR,
7369 don't need to import that one. */
7370 if (!pVmcsInfo->RealMode.fRealOnV86Active)
7371 hmR0VmxImportGuestTr(pVCpu);
7372 }
7373 }
7374
7375 if (fWhat & CPUMCTX_EXTRN_DR7)
7376 {
7377 if (!pVCpu->hm.s.fUsingHyperDR7)
7378 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_DR7, &pCtx->dr[7]); AssertRC(rc);
7379 }
7380
7381 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
7382 {
7383 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, &pCtx->SysEnter.eip); AssertRC(rc);
7384 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, &pCtx->SysEnter.esp); AssertRC(rc);
7385 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRC(rc);
7386 pCtx->SysEnter.cs = u32Val;
7387 }
7388
7389 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
7390 {
7391 if ( pVM->hm.s.fAllow64BitGuests
7392 && (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7393 pCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
7394 }
7395
7396 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
7397 {
7398 if ( pVM->hm.s.fAllow64BitGuests
7399 && (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7400 {
7401 pCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
7402 pCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
7403 pCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
7404 }
7405 }
7406
7407 if (fWhat & (CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS))
7408 {
7409 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
7410 uint32_t const cMsrs = pVmcsInfo->cExitMsrStore;
7411 Assert(pMsrs);
7412 Assert(cMsrs <= VMX_MISC_MAX_MSRS(pVM->hm.s.vmx.Msrs.u64Misc));
7413 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
7414 for (uint32_t i = 0; i < cMsrs; i++)
7415 {
7416 uint32_t const idMsr = pMsrs[i].u32Msr;
7417 switch (idMsr)
7418 {
7419 case MSR_K8_TSC_AUX: CPUMSetGuestTscAux(pVCpu, pMsrs[i].u64Value); break;
7420 case MSR_IA32_SPEC_CTRL: CPUMSetGuestSpecCtrl(pVCpu, pMsrs[i].u64Value); break;
7421 case MSR_K6_EFER: /* Can't be changed without causing a VM-exit */ break;
7422 default:
7423 {
7424 pCtx->fExtrn = 0;
7425 pVCpu->hm.s.u32HMError = pMsrs->u32Msr;
7426 ASMSetFlags(fEFlags);
7427 AssertMsgFailed(("Unexpected MSR in auto-load/store area. idMsr=%#RX32 cMsrs=%u\n", idMsr, cMsrs));
7428 return VERR_HM_UNEXPECTED_LD_ST_MSR;
7429 }
7430 }
7431 }
7432 }
7433
7434 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
7435 {
7436 if (fWhat & CPUMCTX_EXTRN_CR0)
7437 {
7438 uint64_t u64Cr0;
7439 uint64_t u64Shadow;
7440 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Cr0); AssertRC(rc);
7441 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Shadow); AssertRC(rc);
7442 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7443 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7444#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7445 /*
7446 * Reapply the nested-guest's CR0 fixed bits that might have been altered while
7447 * exporting the nested-guest CR0 for executing using hardware-assisted VMX.
7448 */
7449 if (CPUMIsGuestInVmxNonRootMode(pCtx))
7450 {
7451 u64Cr0 |= pCtx->hwvirt.vmx.Msrs.u64Cr0Fixed0;
7452 u64Cr0 &= pCtx->hwvirt.vmx.Msrs.u64Cr0Fixed1;
7453 }
7454#endif
7455 VMMRZCallRing3Disable(pVCpu); /* May call into PGM which has Log statements. */
7456 CPUMSetGuestCR0(pVCpu, u64Cr0);
7457 VMMRZCallRing3Enable(pVCpu);
7458 }
7459
7460 if (fWhat & CPUMCTX_EXTRN_CR4)
7461 {
7462 uint64_t u64Cr4;
7463 uint64_t u64Shadow;
7464 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64Cr4); AssertRC(rc);
7465 rc |= VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Shadow); AssertRC(rc);
7466 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7467 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7468#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7469 /*
7470 * Reapply the nested-guest's CR4 fixed bits that might have been altered while
7471 * exporting the nested-guest CR4 for executing using hardware-assisted VMX.
7472 */
7473 if (CPUMIsGuestInVmxNonRootMode(pCtx))
7474 {
7475 u64Cr4 |= pCtx->hwvirt.vmx.Msrs.u64Cr4Fixed0;
7476 u64Cr4 &= pCtx->hwvirt.vmx.Msrs.u64Cr4Fixed1;
7477 }
7478#endif
7479 pCtx->cr4 = u64Cr4;
7480 }
7481
7482 if (fWhat & CPUMCTX_EXTRN_CR3)
7483 {
7484 /* CR0.PG bit changes are always intercepted, so it's up to date. */
7485 if ( pVM->hm.s.vmx.fUnrestrictedGuest
7486 || ( pVM->hm.s.fNestedPaging
7487 && CPUMIsGuestPagingEnabledEx(pCtx)))
7488 {
7489 uint64_t u64Cr3;
7490 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR3, &u64Cr3); AssertRC(rc);
7491 if (pCtx->cr3 != u64Cr3)
7492 {
7493 pCtx->cr3 = u64Cr3;
7494 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
7495 }
7496
7497 /* If the guest is in PAE mode, sync back the PDPE's into the guest state.
7498 Note: CR4.PAE, CR0.PG, EFER MSR changes are always intercepted, so they're up to date. */
7499 if (CPUMIsGuestInPAEModeEx(pCtx))
7500 {
7501 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
7502 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
7503 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
7504 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
7505 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
7506 }
7507 }
7508 }
7509 }
7510
7511#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7512 if (fWhat & CPUMCTX_EXTRN_HWVIRT)
7513 {
7514 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
7515 && !CPUMIsGuestInVmxNonRootMode(pCtx))
7516 {
7517 Assert(CPUMIsGuestInVmxRootMode(pCtx));
7518 rc = hmR0VmxCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
7519 if (RT_SUCCESS(rc))
7520 { /* likely */ }
7521 else
7522 break;
7523 }
7524 }
7525#endif
7526 } while (0);
7527
7528 if (RT_SUCCESS(rc))
7529 {
7530 /* Update fExtrn. */
7531 pCtx->fExtrn &= ~fWhat;
7532
7533 /* If everything has been imported, clear the HM keeper bit. */
7534 if (!(pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL))
7535 {
7536 pCtx->fExtrn &= ~CPUMCTX_EXTRN_KEEPER_HM;
7537 Assert(!pCtx->fExtrn);
7538 }
7539 }
7540 }
7541 else
7542 AssertMsg(!pCtx->fExtrn || (pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL), ("%#RX64\n", pCtx->fExtrn));
7543
7544 /*
7545 * Restore interrupts.
7546 */
7547 ASMSetFlags(fEFlags);
7548
7549 STAM_PROFILE_ADV_STOP(& pVCpu->hm.s.StatImportGuestState, x);
7550
7551 if (RT_SUCCESS(rc))
7552 { /* likely */ }
7553 else
7554 return rc;
7555
7556 /*
7557 * Honor any pending CR3 updates.
7558 *
7559 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> hmR0VmxCallRing3Callback()
7560 * -> VMMRZCallRing3Disable() -> hmR0VmxImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
7561 * -> continue with VM-exit handling -> hmR0VmxImportGuestState() and here we are.
7562 *
7563 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
7564 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
7565 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
7566 * -NOT- check if CPUMCTX_EXTRN_CR3 is set!
7567 *
7568 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
7569 */
7570 if (VMMRZCallRing3IsEnabled(pVCpu))
7571 {
7572 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
7573 {
7574 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & CPUMCTX_EXTRN_CR3));
7575 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
7576 }
7577
7578 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
7579 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
7580
7581 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
7582 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
7583 }
7584
7585 return VINF_SUCCESS;
7586}
7587
7588
7589/**
7590 * Saves the guest state from the VMCS into the guest-CPU context.
7591 *
7592 * @returns VBox status code.
7593 * @param pVCpu The cross context virtual CPU structure.
7594 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7595 */
7596VMMR0DECL(int) VMXR0ImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat)
7597{
7598 AssertPtr(pVCpu);
7599 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7600 return hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fWhat);
7601}
7602
7603
7604/**
7605 * Check per-VM and per-VCPU force flag actions that require us to go back to
7606 * ring-3 for one reason or another.
7607 *
7608 * @returns Strict VBox status code (i.e. informational status codes too)
7609 * @retval VINF_SUCCESS if we don't have any actions that require going back to
7610 * ring-3.
7611 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
7612 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
7613 * interrupts)
7614 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
7615 * all EMTs to be in ring-3.
7616 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
7617 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
7618 * to the EM loop.
7619 *
7620 * @param pVCpu The cross context virtual CPU structure.
7621 * @param fStepping Whether we are single-stepping the guest using the
7622 * hypervisor debugger.
7623 *
7624 * @remarks This might cause nested-guest VM-exits, caller must check if the guest
7625 * is no longer in VMX non-root mode.
7626 */
7627static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVMCPUCC pVCpu, bool fStepping)
7628{
7629 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7630
7631 /*
7632 * Update pending interrupts into the APIC's IRR.
7633 */
7634 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
7635 APICUpdatePendingInterrupts(pVCpu);
7636
7637 /*
7638 * Anything pending? Should be more likely than not if we're doing a good job.
7639 */
7640 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7641 if ( !fStepping
7642 ? !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_MASK)
7643 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
7644 : !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
7645 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
7646 return VINF_SUCCESS;
7647
7648 /* Pending PGM C3 sync. */
7649 if (VMCPU_FF_IS_ANY_SET(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
7650 {
7651 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7652 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & (CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4)));
7653 VBOXSTRICTRC rcStrict = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4,
7654 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
7655 if (rcStrict != VINF_SUCCESS)
7656 {
7657 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
7658 Log4Func(("PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
7659 return rcStrict;
7660 }
7661 }
7662
7663 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
7664 if ( VM_FF_IS_ANY_SET(pVM, VM_FF_HM_TO_R3_MASK)
7665 || VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
7666 {
7667 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
7668 int rc = RT_LIKELY(!VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_RAW_TO_R3 : VINF_EM_NO_MEMORY;
7669 Log4Func(("HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc));
7670 return rc;
7671 }
7672
7673 /* Pending VM request packets, such as hardware interrupts. */
7674 if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
7675 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
7676 {
7677 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchVmReq);
7678 Log4Func(("Pending VM request forcing us back to ring-3\n"));
7679 return VINF_EM_PENDING_REQUEST;
7680 }
7681
7682 /* Pending PGM pool flushes. */
7683 if (VM_FF_IS_SET(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
7684 {
7685 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPgmPoolFlush);
7686 Log4Func(("PGM pool flush pending forcing us back to ring-3\n"));
7687 return VINF_PGM_POOL_FLUSH_PENDING;
7688 }
7689
7690 /* Pending DMA requests. */
7691 if (VM_FF_IS_SET(pVM, VM_FF_PDM_DMA))
7692 {
7693 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchDma);
7694 Log4Func(("Pending DMA request forcing us back to ring-3\n"));
7695 return VINF_EM_RAW_TO_R3;
7696 }
7697
7698#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7699 /* Pending nested-guest APIC-write (has highest priority among nested-guest FFs). */
7700 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
7701 {
7702 Log4Func(("Pending nested-guest APIC-write\n"));
7703 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitApicWrite(pVCpu);
7704 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
7705 return rcStrict;
7706 }
7707 /** @todo VMCPU_FF_VMX_MTF, VMCPU_FF_VMX_PREEMPT_TIMER */
7708#endif
7709
7710 return VINF_SUCCESS;
7711}
7712
7713
7714/**
7715 * Converts any TRPM trap into a pending HM event. This is typically used when
7716 * entering from ring-3 (not longjmp returns).
7717 *
7718 * @param pVCpu The cross context virtual CPU structure.
7719 */
7720static void hmR0VmxTrpmTrapToPendingEvent(PVMCPUCC pVCpu)
7721{
7722 Assert(TRPMHasTrap(pVCpu));
7723 Assert(!pVCpu->hm.s.Event.fPending);
7724
7725 uint8_t uVector;
7726 TRPMEVENT enmTrpmEvent;
7727 RTGCUINT uErrCode;
7728 RTGCUINTPTR GCPtrFaultAddress;
7729 uint8_t cbInstr;
7730
7731 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr);
7732 AssertRC(rc);
7733
7734 uint32_t u32IntInfo;
7735 u32IntInfo = uVector | VMX_IDT_VECTORING_INFO_VALID;
7736 u32IntInfo |= HMTrpmEventTypeToVmxEventType(uVector, enmTrpmEvent);
7737
7738 rc = TRPMResetTrap(pVCpu);
7739 AssertRC(rc);
7740 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
7741 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
7742
7743 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
7744}
7745
7746
7747/**
7748 * Converts the pending HM event into a TRPM trap.
7749 *
7750 * @param pVCpu The cross context virtual CPU structure.
7751 */
7752static void hmR0VmxPendingEventToTrpmTrap(PVMCPUCC pVCpu)
7753{
7754 Assert(pVCpu->hm.s.Event.fPending);
7755
7756 /* If a trap was already pending, we did something wrong! */
7757 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
7758
7759 uint32_t const u32IntInfo = pVCpu->hm.s.Event.u64IntInfo;
7760 uint32_t const uVector = VMX_IDT_VECTORING_INFO_VECTOR(u32IntInfo);
7761 TRPMEVENT const enmTrapType = HMVmxEventTypeToTrpmEventType(u32IntInfo);
7762
7763 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
7764
7765 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
7766 AssertRC(rc);
7767
7768 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
7769 TRPMSetErrorCode(pVCpu, pVCpu->hm.s.Event.u32ErrCode);
7770
7771 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(u32IntInfo))
7772 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
7773 else if (VMX_IDT_VECTORING_INFO_TYPE(u32IntInfo) == VMX_IDT_VECTORING_INFO_TYPE_SW_INT)
7774 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
7775
7776 /* We're now done converting the pending event. */
7777 pVCpu->hm.s.Event.fPending = false;
7778}
7779
7780
7781/**
7782 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
7783 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
7784 *
7785 * @param pVCpu The cross context virtual CPU structure.
7786 * @param pVmcsInfo The VMCS info. object.
7787 */
7788static void hmR0VmxSetIntWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
7789{
7790 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7791 {
7792 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
7793 {
7794 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_INT_WINDOW_EXIT;
7795 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7796 AssertRC(rc);
7797 }
7798 } /* else we will deliver interrupts whenever the guest Vm-exits next and is in a state to receive the interrupt. */
7799}
7800
7801
7802/**
7803 * Clears the interrupt-window exiting control in the VMCS.
7804 *
7805 * @param pVmcsInfo The VMCS info. object.
7806 */
7807DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
7808{
7809 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7810 {
7811 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_INT_WINDOW_EXIT;
7812 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7813 AssertRC(rc);
7814 }
7815}
7816
7817
7818/**
7819 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
7820 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
7821 *
7822 * @param pVCpu The cross context virtual CPU structure.
7823 * @param pVmcsInfo The VMCS info. object.
7824 */
7825static void hmR0VmxSetNmiWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
7826{
7827 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7828 {
7829 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
7830 {
7831 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_NMI_WINDOW_EXIT;
7832 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7833 AssertRC(rc);
7834 Log4Func(("Setup NMI-window exiting\n"));
7835 }
7836 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
7837}
7838
7839
7840/**
7841 * Clears the NMI-window exiting control in the VMCS.
7842 *
7843 * @param pVmcsInfo The VMCS info. object.
7844 */
7845DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
7846{
7847 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7848 {
7849 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_NMI_WINDOW_EXIT;
7850 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7851 AssertRC(rc);
7852 }
7853}
7854
7855
7856/**
7857 * Does the necessary state syncing before returning to ring-3 for any reason
7858 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
7859 *
7860 * @returns VBox status code.
7861 * @param pVCpu The cross context virtual CPU structure.
7862 * @param fImportState Whether to import the guest state from the VMCS back
7863 * to the guest-CPU context.
7864 *
7865 * @remarks No-long-jmp zone!!!
7866 */
7867static int hmR0VmxLeave(PVMCPUCC pVCpu, bool fImportState)
7868{
7869 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7870 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7871
7872 RTCPUID const idCpu = RTMpCpuId();
7873 Log4Func(("HostCpuId=%u\n", idCpu));
7874
7875 /*
7876 * !!! IMPORTANT !!!
7877 * If you modify code here, check whether hmR0VmxCallRing3Callback() needs to be updated too.
7878 */
7879
7880 /* Save the guest state if necessary. */
7881 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7882 if (fImportState)
7883 {
7884 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
7885 AssertRCReturn(rc, rc);
7886 }
7887
7888 /* Restore host FPU state if necessary. We will resync on next R0 reentry. */
7889 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
7890 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
7891
7892 /* Restore host debug registers if necessary. We will resync on next R0 reentry. */
7893#ifdef VBOX_STRICT
7894 if (CPUMIsHyperDebugStateActive(pVCpu))
7895 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT);
7896#endif
7897 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
7898 Assert(!CPUMIsGuestDebugStateActive(pVCpu) && !CPUMIsGuestDebugStateActivePending(pVCpu));
7899 Assert(!CPUMIsHyperDebugStateActive(pVCpu) && !CPUMIsHyperDebugStateActivePending(pVCpu));
7900
7901 /* Restore host-state bits that VT-x only restores partially. */
7902 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7903 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7904 {
7905 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags, idCpu));
7906 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7907 }
7908 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7909
7910 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7911 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
7912 {
7913 /* We shouldn't restore the host MSRs without saving the guest MSRs first. */
7914 if (!fImportState)
7915 {
7916 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS);
7917 AssertRCReturn(rc, rc);
7918 }
7919 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7920 Assert(!pVCpu->hm.s.vmx.fLazyMsrs);
7921 }
7922 else
7923 pVCpu->hm.s.vmx.fLazyMsrs = 0;
7924
7925 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7926 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
7927
7928 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
7929 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatImportGuestState);
7930 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExportGuestState);
7931 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatPreExit);
7932 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitHandling);
7933 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
7934 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
7935 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
7936 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitVmentry);
7937 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7938
7939 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7940
7941 /** @todo This partially defeats the purpose of having preemption hooks.
7942 * The problem is, deregistering the hooks should be moved to a place that
7943 * lasts until the EMT is about to be destroyed not everytime while leaving HM
7944 * context.
7945 */
7946 int rc = hmR0VmxClearVmcs(pVmcsInfo);
7947 AssertRCReturn(rc, rc);
7948
7949#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7950 /*
7951 * A valid shadow VMCS is made active as part of VM-entry. It is necessary to
7952 * clear a shadow VMCS before allowing that VMCS to become active on another
7953 * logical processor. We may or may not be importing guest state which clears
7954 * it, so cover for it here.
7955 *
7956 * See Intel spec. 24.11.1 "Software Use of Virtual-Machine Control Structures".
7957 */
7958 if ( pVmcsInfo->pvShadowVmcs
7959 && pVmcsInfo->fShadowVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
7960 {
7961 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
7962 AssertRCReturn(rc, rc);
7963 }
7964
7965 /*
7966 * Flag that we need to re-export the host state if we switch to this VMCS before
7967 * executing guest or nested-guest code.
7968 */
7969 pVmcsInfo->idHostCpuState = NIL_RTCPUID;
7970#endif
7971
7972 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
7973 NOREF(idCpu);
7974 return VINF_SUCCESS;
7975}
7976
7977
7978/**
7979 * Leaves the VT-x session.
7980 *
7981 * @returns VBox status code.
7982 * @param pVCpu The cross context virtual CPU structure.
7983 *
7984 * @remarks No-long-jmp zone!!!
7985 */
7986static int hmR0VmxLeaveSession(PVMCPUCC pVCpu)
7987{
7988 HM_DISABLE_PREEMPT(pVCpu);
7989 HMVMX_ASSERT_CPU_SAFE(pVCpu);
7990 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7991 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7992
7993 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
7994 and done this from the VMXR0ThreadCtxCallback(). */
7995 if (!pVCpu->hm.s.fLeaveDone)
7996 {
7997 int rc2 = hmR0VmxLeave(pVCpu, true /* fImportState */);
7998 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
7999 pVCpu->hm.s.fLeaveDone = true;
8000 }
8001 Assert(!pVCpu->cpum.GstCtx.fExtrn);
8002
8003 /*
8004 * !!! IMPORTANT !!!
8005 * If you modify code here, make sure to check whether hmR0VmxCallRing3Callback() needs to be updated too.
8006 */
8007
8008 /* Deregister hook now that we've left HM context before re-enabling preemption. */
8009 /** @todo Deregistering here means we need to VMCLEAR always
8010 * (longjmp/exit-to-r3) in VT-x which is not efficient, eliminate need
8011 * for calling VMMR0ThreadCtxHookDisable here! */
8012 VMMR0ThreadCtxHookDisable(pVCpu);
8013
8014 /* Leave HM context. This takes care of local init (term). */
8015 int rc = HMR0LeaveCpu(pVCpu);
8016
8017 HM_RESTORE_PREEMPT();
8018 return rc;
8019}
8020
8021
8022/**
8023 * Does the necessary state syncing before doing a longjmp to ring-3.
8024 *
8025 * @returns VBox status code.
8026 * @param pVCpu The cross context virtual CPU structure.
8027 *
8028 * @remarks No-long-jmp zone!!!
8029 */
8030DECLINLINE(int) hmR0VmxLongJmpToRing3(PVMCPUCC pVCpu)
8031{
8032 return hmR0VmxLeaveSession(pVCpu);
8033}
8034
8035
8036/**
8037 * Take necessary actions before going back to ring-3.
8038 *
8039 * An action requires us to go back to ring-3. This function does the necessary
8040 * steps before we can safely return to ring-3. This is not the same as longjmps
8041 * to ring-3, this is voluntary and prepares the guest so it may continue
8042 * executing outside HM (recompiler/IEM).
8043 *
8044 * @returns VBox status code.
8045 * @param pVCpu The cross context virtual CPU structure.
8046 * @param rcExit The reason for exiting to ring-3. Can be
8047 * VINF_VMM_UNKNOWN_RING3_CALL.
8048 */
8049static int hmR0VmxExitToRing3(PVMCPUCC pVCpu, VBOXSTRICTRC rcExit)
8050{
8051 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8052
8053 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8054 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
8055 {
8056 VMXGetCurrentVmcs(&pVCpu->hm.s.vmx.LastError.HCPhysCurrentVmcs);
8057 pVCpu->hm.s.vmx.LastError.u32VmcsRev = *(uint32_t *)pVmcsInfo->pvVmcs;
8058 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
8059 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
8060 }
8061
8062 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
8063 VMMRZCallRing3Disable(pVCpu);
8064 Log4Func(("rcExit=%d\n", VBOXSTRICTRC_VAL(rcExit)));
8065
8066 /*
8067 * Convert any pending HM events back to TRPM due to premature exits to ring-3.
8068 * We need to do this only on returns to ring-3 and not for longjmps to ring3.
8069 *
8070 * This is because execution may continue from ring-3 and we would need to inject
8071 * the event from there (hence place it back in TRPM).
8072 */
8073 if (pVCpu->hm.s.Event.fPending)
8074 {
8075 hmR0VmxPendingEventToTrpmTrap(pVCpu);
8076 Assert(!pVCpu->hm.s.Event.fPending);
8077
8078 /* Clear the events from the VMCS. */
8079 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0);
8080 AssertRC(rc);
8081 }
8082#ifdef VBOX_STRICT
8083 else
8084 {
8085 /*
8086 * Ensure we don't accidentally clear a pending HM event without clearing the VMCS.
8087 * This can be pretty hard to debug otherwise, interrupts might get injected twice
8088 * occasionally, see @bugref{9180#c42}.
8089 *
8090 * However, if the VM-entry failed, any VM entry-interruption info. field would
8091 * be left unmodified as the event would not have been injected to the guest. In
8092 * such cases, don't assert, we're not going to continue guest execution anyway.
8093 */
8094 uint32_t uExitReason;
8095 uint32_t uEntryIntInfo;
8096 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8097 rc |= VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &uEntryIntInfo);
8098 AssertRC(rc);
8099 Assert(VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason) || !VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo));
8100 }
8101#endif
8102
8103 /*
8104 * Clear the interrupt-window and NMI-window VMCS controls as we could have got
8105 * a VM-exit with higher priority than interrupt-window or NMI-window VM-exits
8106 * (e.g. TPR below threshold).
8107 */
8108 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8109 {
8110 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
8111 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
8112 }
8113
8114 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
8115 and if we're injecting an event we should have a TRPM trap pending. */
8116 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8117#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a triple fault in progress. */
8118 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8119#endif
8120
8121 /* Save guest state and restore host state bits. */
8122 int rc = hmR0VmxLeaveSession(pVCpu);
8123 AssertRCReturn(rc, rc);
8124 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8125
8126 /* Thread-context hooks are unregistered at this point!!! */
8127
8128 /* Sync recompiler state. */
8129 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
8130 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
8131 | CPUM_CHANGED_LDTR
8132 | CPUM_CHANGED_GDTR
8133 | CPUM_CHANGED_IDTR
8134 | CPUM_CHANGED_TR
8135 | CPUM_CHANGED_HIDDEN_SEL_REGS);
8136 if ( pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging
8137 && CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx))
8138 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
8139
8140 Assert(!pVCpu->hm.s.fClearTrapFlag);
8141
8142 /* Update the exit-to-ring 3 reason. */
8143 pVCpu->hm.s.rcLastExitToR3 = VBOXSTRICTRC_VAL(rcExit);
8144
8145 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
8146 if ( rcExit != VINF_EM_RAW_INTERRUPT
8147 || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8148 {
8149 Assert(!(pVCpu->cpum.GstCtx.fExtrn & HMVMX_CPUMCTX_EXTRN_ALL));
8150 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
8151 }
8152
8153 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
8154
8155 /* We do -not- want any longjmp notifications after this! We must return to ring-3 ASAP. */
8156 VMMRZCallRing3RemoveNotification(pVCpu);
8157 VMMRZCallRing3Enable(pVCpu);
8158
8159 return rc;
8160}
8161
8162
8163/**
8164 * VMMRZCallRing3() callback wrapper which saves the guest state before we
8165 * longjump to ring-3 and possibly get preempted.
8166 *
8167 * @returns VBox status code.
8168 * @param pVCpu The cross context virtual CPU structure.
8169 * @param enmOperation The operation causing the ring-3 longjump.
8170 * @param pvUser User argument, currently unused, NULL.
8171 */
8172static DECLCALLBACK(int) hmR0VmxCallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
8173{
8174 RT_NOREF(pvUser);
8175 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
8176 {
8177 /*
8178 * !!! IMPORTANT !!!
8179 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
8180 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
8181 */
8182 VMMRZCallRing3RemoveNotification(pVCpu);
8183 VMMRZCallRing3Disable(pVCpu);
8184 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
8185 RTThreadPreemptDisable(&PreemptState);
8186
8187 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8188 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8189 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8190 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8191
8192 /* Restore host-state bits that VT-x only restores partially. */
8193 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
8194 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
8195 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
8196 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
8197
8198 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8199 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8200 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8201
8202 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8203 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
8204 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8205
8206 /* Clear the current VMCS data back to memory (shadow VMCS if any would have been
8207 cleared as part of importing the guest state above. */
8208 hmR0VmxClearVmcs(pVmcsInfo);
8209
8210 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
8211 VMMR0ThreadCtxHookDisable(pVCpu);
8212 HMR0LeaveCpu(pVCpu);
8213 RTThreadPreemptRestore(&PreemptState);
8214 return VINF_SUCCESS;
8215 }
8216
8217 Assert(pVCpu);
8218 Assert(pvUser);
8219 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8220 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8221
8222 VMMRZCallRing3Disable(pVCpu);
8223 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8224
8225 Log4Func(("-> hmR0VmxLongJmpToRing3 enmOperation=%d\n", enmOperation));
8226
8227 int rc = hmR0VmxLongJmpToRing3(pVCpu);
8228 AssertRCReturn(rc, rc);
8229
8230 VMMRZCallRing3Enable(pVCpu);
8231 return VINF_SUCCESS;
8232}
8233
8234
8235/**
8236 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
8237 * stack.
8238 *
8239 * @returns Strict VBox status code (i.e. informational status codes too).
8240 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
8241 * @param pVCpu The cross context virtual CPU structure.
8242 * @param uValue The value to push to the guest stack.
8243 */
8244static VBOXSTRICTRC hmR0VmxRealModeGuestStackPush(PVMCPUCC pVCpu, uint16_t uValue)
8245{
8246 /*
8247 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
8248 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
8249 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
8250 */
8251 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8252 if (pCtx->sp == 1)
8253 return VINF_EM_RESET;
8254 pCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
8255 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), pCtx->ss.u64Base + pCtx->sp, &uValue, sizeof(uint16_t));
8256 AssertRC(rc);
8257 return rc;
8258}
8259
8260
8261/**
8262 * Injects an event into the guest upon VM-entry by updating the relevant fields
8263 * in the VM-entry area in the VMCS.
8264 *
8265 * @returns Strict VBox status code (i.e. informational status codes too).
8266 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
8267 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
8268 *
8269 * @param pVCpu The cross context virtual CPU structure.
8270 * @param pVmxTransient The VMX-transient structure.
8271 * @param pEvent The event being injected.
8272 * @param pfIntrState Pointer to the VT-x guest-interruptibility-state. This
8273 * will be updated if necessary. This cannot not be NULL.
8274 * @param fStepping Whether we're single-stepping guest execution and should
8275 * return VINF_EM_DBG_STEPPED if the event is injected
8276 * directly (registers modified by us, not by hardware on
8277 * VM-entry).
8278 */
8279static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCHMEVENT pEvent, bool fStepping,
8280 uint32_t *pfIntrState)
8281{
8282 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
8283 AssertMsg(!RT_HI_U32(pEvent->u64IntInfo), ("%#RX64\n", pEvent->u64IntInfo));
8284 Assert(pfIntrState);
8285
8286 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8287 uint32_t u32IntInfo = pEvent->u64IntInfo;
8288 uint32_t const u32ErrCode = pEvent->u32ErrCode;
8289 uint32_t const cbInstr = pEvent->cbInstr;
8290 RTGCUINTPTR const GCPtrFault = pEvent->GCPtrFaultAddress;
8291 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(u32IntInfo);
8292 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(u32IntInfo);
8293
8294#ifdef VBOX_STRICT
8295 /*
8296 * Validate the error-code-valid bit for hardware exceptions.
8297 * No error codes for exceptions in real-mode.
8298 *
8299 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8300 */
8301 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8302 && !CPUMIsGuestInRealModeEx(pCtx))
8303 {
8304 switch (uVector)
8305 {
8306 case X86_XCPT_PF:
8307 case X86_XCPT_DF:
8308 case X86_XCPT_TS:
8309 case X86_XCPT_NP:
8310 case X86_XCPT_SS:
8311 case X86_XCPT_GP:
8312 case X86_XCPT_AC:
8313 AssertMsg(VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo),
8314 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
8315 RT_FALL_THRU();
8316 default:
8317 break;
8318 }
8319 }
8320
8321 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
8322 Assert( uIntType != VMX_EXIT_INT_INFO_TYPE_NMI
8323 || !(*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
8324#endif
8325
8326 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
8327
8328 /*
8329 * Hardware interrupts & exceptions cannot be delivered through the software interrupt
8330 * redirection bitmap to the real mode task in virtual-8086 mode. We must jump to the
8331 * interrupt handler in the (real-mode) guest.
8332 *
8333 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode".
8334 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
8335 */
8336 if (CPUMIsGuestInRealModeEx(pCtx)) /* CR0.PE bit changes are always intercepted, so it's up to date. */
8337 {
8338 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest)
8339 {
8340 /*
8341 * For CPUs with unrestricted guest execution enabled and with the guest
8342 * in real-mode, we must not set the deliver-error-code bit.
8343 *
8344 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8345 */
8346 u32IntInfo &= ~VMX_ENTRY_INT_INFO_ERROR_CODE_VALID;
8347 }
8348 else
8349 {
8350 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8351 Assert(PDMVmmDevHeapIsEnabled(pVM));
8352 Assert(pVM->hm.s.vmx.pRealModeTSS);
8353 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
8354
8355 /* We require RIP, RSP, RFLAGS, CS, IDTR, import them. */
8356 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8357 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TABLE_MASK
8358 | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS);
8359 AssertRCReturn(rc2, rc2);
8360
8361 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8362 size_t const cbIdtEntry = sizeof(X86IDTR16);
8363 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pCtx->idtr.cbIdt)
8364 {
8365 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8366 if (uVector == X86_XCPT_DF)
8367 return VINF_EM_RESET;
8368
8369 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault.
8370 No error codes for exceptions in real-mode. */
8371 if (uVector == X86_XCPT_GP)
8372 {
8373 uint32_t const uXcptDfInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
8374 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8375 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8376 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8377 HMEVENT EventXcptDf;
8378 RT_ZERO(EventXcptDf);
8379 EventXcptDf.u64IntInfo = uXcptDfInfo;
8380 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptDf, fStepping, pfIntrState);
8381 }
8382
8383 /*
8384 * If we're injecting an event with no valid IDT entry, inject a #GP.
8385 * No error codes for exceptions in real-mode.
8386 *
8387 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8388 */
8389 uint32_t const uXcptGpInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
8390 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8391 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8392 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8393 HMEVENT EventXcptGp;
8394 RT_ZERO(EventXcptGp);
8395 EventXcptGp.u64IntInfo = uXcptGpInfo;
8396 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptGp, fStepping, pfIntrState);
8397 }
8398
8399 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8400 uint16_t uGuestIp = pCtx->ip;
8401 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT)
8402 {
8403 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8404 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8405 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8406 }
8407 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_INT)
8408 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8409
8410 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8411 X86IDTR16 IdtEntry;
8412 RTGCPHYS const GCPhysIdtEntry = (RTGCPHYS)pCtx->idtr.pIdt + uVector * cbIdtEntry;
8413 rc2 = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8414 AssertRCReturn(rc2, rc2);
8415
8416 /* Construct the stack frame for the interrupt/exception handler. */
8417 VBOXSTRICTRC rcStrict;
8418 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->eflags.u32);
8419 if (rcStrict == VINF_SUCCESS)
8420 {
8421 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->cs.Sel);
8422 if (rcStrict == VINF_SUCCESS)
8423 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, uGuestIp);
8424 }
8425
8426 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8427 if (rcStrict == VINF_SUCCESS)
8428 {
8429 pCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8430 pCtx->rip = IdtEntry.offSel;
8431 pCtx->cs.Sel = IdtEntry.uSel;
8432 pCtx->cs.ValidSel = IdtEntry.uSel;
8433 pCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8434 if ( uIntType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
8435 && uVector == X86_XCPT_PF)
8436 pCtx->cr2 = GCPtrFault;
8437
8438 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CS | HM_CHANGED_GUEST_CR2
8439 | HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
8440 | HM_CHANGED_GUEST_RSP);
8441
8442 /*
8443 * If we delivered a hardware exception (other than an NMI) and if there was
8444 * block-by-STI in effect, we should clear it.
8445 */
8446 if (*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
8447 {
8448 Assert( uIntType != VMX_ENTRY_INT_INFO_TYPE_NMI
8449 && uIntType != VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
8450 Log4Func(("Clearing inhibition due to STI\n"));
8451 *pfIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
8452 }
8453
8454 Log4(("Injected real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8455 u32IntInfo, u32ErrCode, cbInstr, pCtx->eflags.u, pCtx->cs.Sel, pCtx->eip));
8456
8457 /*
8458 * The event has been truly dispatched to the guest. Mark it as no longer pending so
8459 * we don't attempt to undo it if we are returning to ring-3 before executing guest code.
8460 */
8461 pVCpu->hm.s.Event.fPending = false;
8462
8463 /*
8464 * If we eventually support nested-guest execution without unrestricted guest execution,
8465 * we should set fInterceptEvents here.
8466 */
8467 Assert(!pVmxTransient->fIsNestedGuest);
8468
8469 /* If we're stepping and we've changed cs:rip above, bail out of the VMX R0 execution loop. */
8470 if (fStepping)
8471 rcStrict = VINF_EM_DBG_STEPPED;
8472 }
8473 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8474 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8475 return rcStrict;
8476 }
8477 }
8478
8479 /*
8480 * Validate.
8481 */
8482 Assert(VMX_ENTRY_INT_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
8483 Assert(!(u32IntInfo & VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK)); /* Bits 30:12 MBZ. */
8484
8485 /*
8486 * Inject the event into the VMCS.
8487 */
8488 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8489 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8490 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8491 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8492 AssertRC(rc);
8493
8494 /*
8495 * Update guest CR2 if this is a page-fault.
8496 */
8497 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
8498 pCtx->cr2 = GCPtrFault;
8499
8500 Log4(("Injecting u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x CR2=%#RX64\n", u32IntInfo, u32ErrCode, cbInstr, pCtx->cr2));
8501 return VINF_SUCCESS;
8502}
8503
8504
8505/**
8506 * Evaluates the event to be delivered to the guest and sets it as the pending
8507 * event.
8508 *
8509 * @returns Strict VBox status code (i.e. informational status codes too).
8510 * @param pVCpu The cross context virtual CPU structure.
8511 * @param pVmxTransient The VMX-transient structure.
8512 * @param pfIntrState Where to store the VT-x guest-interruptibility state.
8513 */
8514static VBOXSTRICTRC hmR0VmxEvaluatePendingEvent(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t *pfIntrState)
8515{
8516 Assert(pfIntrState);
8517 Assert(!TRPMHasTrap(pVCpu));
8518
8519 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8520 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8521 bool const fIsNestedGuest = pVmxTransient->fIsNestedGuest;
8522
8523 /*
8524 * Get the current interruptibility-state of the guest or nested-guest and
8525 * then figure out what needs to be injected.
8526 */
8527 uint32_t const fIntrState = hmR0VmxGetGuestIntrState(pVCpu, pVmxTransient);
8528 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
8529 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
8530 bool const fBlockNmi = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
8531
8532 /* We don't support block-by-SMI yet.*/
8533 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI));
8534
8535 /* Block-by-STI must not be set when interrupts are disabled. */
8536 if (fBlockSti)
8537 {
8538 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
8539 Assert(pCtx->eflags.Bits.u1IF);
8540 }
8541
8542 /* Update interruptibility state to the caller. */
8543 *pfIntrState = fIntrState;
8544
8545 /*
8546 * Toggling of interrupt force-flags here is safe since we update TRPM on
8547 * premature exits to ring-3 before executing guest code, see hmR0VmxExitToRing3().
8548 * We must NOT restore these force-flags.
8549 */
8550
8551 /** @todo SMI. SMIs take priority over NMIs. */
8552
8553 /*
8554 * Check if an NMI is pending and if the guest or nested-guest can receive them.
8555 * NMIs take priority over external interrupts.
8556 */
8557 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
8558 {
8559 /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
8560 if ( !pVCpu->hm.s.Event.fPending
8561 && !fBlockNmi
8562 && !fBlockSti
8563 && !fBlockMovSS)
8564 {
8565#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8566 if ( fIsNestedGuest
8567 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_NMI_EXIT))
8568 return IEMExecVmxVmexitXcptNmi(pVCpu);
8569#endif
8570 hmR0VmxSetPendingXcptNmi(pVCpu);
8571 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
8572 Log4Func(("Pending NMI\n"));
8573 }
8574 else if (!fIsNestedGuest)
8575 hmR0VmxSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
8576 /* else: for nested-guests, NMI-window exiting will be picked up when merging VMCS controls. */
8577 }
8578 /*
8579 * Check if an external interrupt (PIC/APIC) is pending and if the guest or nested-guest
8580 * can receive them. Once PDMGetInterrupt() returns a valid interrupt we -must- deliver
8581 * the interrupt. We can no longer re-request it from the APIC.
8582 */
8583 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
8584 && !pVCpu->hm.s.fSingleInstruction)
8585 {
8586 Assert(!DBGFIsStepping(pVCpu));
8587 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
8588 AssertRCReturn(rc, rc);
8589
8590 bool const fBlockInt = !(pCtx->eflags.u32 & X86_EFL_IF);
8591 if ( !pVCpu->hm.s.Event.fPending
8592 && !fBlockInt
8593 && !fBlockSti
8594 && !fBlockMovSS)
8595 {
8596#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8597 if ( fIsNestedGuest
8598 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
8599 && !CPUMIsGuestVmxExitCtlsSet(pVCpu, pCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
8600 {
8601 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
8602 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8603 return rcStrict;
8604 }
8605#endif
8606 uint8_t u8Interrupt;
8607 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
8608 if (RT_SUCCESS(rc))
8609 {
8610#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8611 if ( fIsNestedGuest
8612 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
8613 && CPUMIsGuestVmxExitCtlsSet(pVCpu, pCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
8614 {
8615 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, u8Interrupt, false /* fIntPending */);
8616 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8617 return rcStrict;
8618 }
8619#endif
8620 hmR0VmxSetPendingExtInt(pVCpu, u8Interrupt);
8621 Log4Func(("Pending external interrupt vector %#x\n", u8Interrupt));
8622 }
8623 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
8624 {
8625 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
8626
8627 if ( !fIsNestedGuest
8628 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
8629 hmR0VmxApicSetTprThreshold(pVmcsInfo, u8Interrupt >> 4);
8630 /* else: for nested-guests, TPR threshold is picked up while merging VMCS controls. */
8631
8632 /*
8633 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
8634 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
8635 * need to re-set this force-flag here.
8636 */
8637 }
8638 else
8639 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
8640 }
8641 else if (!fIsNestedGuest)
8642 hmR0VmxSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
8643 /* else: for nested-guests, interrupt-window exiting will be picked up when merging VMCS controls. */
8644 }
8645
8646 return VINF_SUCCESS;
8647}
8648
8649
8650/**
8651 * Injects any pending events into the guest if the guest is in a state to
8652 * receive them.
8653 *
8654 * @returns Strict VBox status code (i.e. informational status codes too).
8655 * @param pVCpu The cross context virtual CPU structure.
8656 * @param pVmxTransient The VMX-transient structure.
8657 * @param fIntrState The VT-x guest-interruptibility state.
8658 * @param fStepping Whether we are single-stepping the guest using the
8659 * hypervisor debugger and should return
8660 * VINF_EM_DBG_STEPPED if the event was dispatched
8661 * directly.
8662 */
8663static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t fIntrState, bool fStepping)
8664{
8665 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8666 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8667
8668 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
8669 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
8670
8671 Assert(!fBlockSti || !(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_RFLAGS));
8672 Assert(!fBlockSti || pVCpu->cpum.GstCtx.eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
8673 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
8674 Assert(!TRPMHasTrap(pVCpu));
8675
8676 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
8677 if (pVCpu->hm.s.Event.fPending)
8678 {
8679 /*
8680 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
8681 * pending even while injecting an event and in this case, we want a VM-exit as soon as
8682 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
8683 *
8684 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
8685 */
8686 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
8687#ifdef VBOX_STRICT
8688 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
8689 {
8690 bool const fBlockInt = !(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_IF);
8691 Assert(!fBlockInt);
8692 Assert(!fBlockSti);
8693 Assert(!fBlockMovSS);
8694 }
8695 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_NMI)
8696 {
8697 bool const fBlockNmi = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
8698 Assert(!fBlockSti);
8699 Assert(!fBlockMovSS);
8700 Assert(!fBlockNmi);
8701 }
8702#endif
8703 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
8704 uIntType));
8705
8706 /*
8707 * Inject the event and get any changes to the guest-interruptibility state.
8708 *
8709 * The guest-interruptibility state may need to be updated if we inject the event
8710 * into the guest IDT ourselves (for real-on-v86 guest injecting software interrupts).
8711 */
8712 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &pVCpu->hm.s.Event, fStepping, &fIntrState);
8713 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
8714
8715 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
8716 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
8717 else
8718 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
8719 }
8720
8721 /*
8722 * Update the guest-interruptibility state.
8723 *
8724 * This is required for the real-on-v86 software interrupt injection case above, as well as
8725 * updates to the guest state from ring-3 or IEM/REM.
8726 */
8727 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
8728 AssertRC(rc);
8729
8730 /*
8731 * There's no need to clear the VM-entry interruption-information field here if we're not
8732 * injecting anything. VT-x clears the valid bit on every VM-exit.
8733 *
8734 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
8735 */
8736
8737 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
8738 NOREF(fBlockMovSS); NOREF(fBlockSti);
8739 return rcStrict;
8740}
8741
8742
8743/**
8744 * Enters the VT-x session.
8745 *
8746 * @returns VBox status code.
8747 * @param pVCpu The cross context virtual CPU structure.
8748 */
8749VMMR0DECL(int) VMXR0Enter(PVMCPUCC pVCpu)
8750{
8751 AssertPtr(pVCpu);
8752 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported);
8753 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8754
8755 LogFlowFunc(("pVCpu=%p\n", pVCpu));
8756 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
8757 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
8758
8759#ifdef VBOX_STRICT
8760 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
8761 RTCCUINTREG uHostCr4 = ASMGetCR4();
8762 if (!(uHostCr4 & X86_CR4_VMXE))
8763 {
8764 LogRelFunc(("X86_CR4_VMXE bit in CR4 is not set!\n"));
8765 return VERR_VMX_X86_CR4_VMXE_CLEARED;
8766 }
8767#endif
8768
8769 /*
8770 * Load the appropriate VMCS as the current and active one.
8771 */
8772 PVMXVMCSINFO pVmcsInfo;
8773 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx);
8774 if (!fInNestedGuestMode)
8775 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfo;
8776 else
8777 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
8778 int rc = hmR0VmxLoadVmcs(pVmcsInfo);
8779 if (RT_SUCCESS(rc))
8780 {
8781 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs = fInNestedGuestMode;
8782 pVCpu->hm.s.fLeaveDone = false;
8783 Log4Func(("Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8784
8785 /*
8786 * Do the EMT scheduled L1D flush here if needed.
8787 */
8788 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
8789 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
8790 else if (pVCpu->CTX_SUFF(pVM)->hm.s.fMdsClearOnSched)
8791 hmR0MdsClear();
8792 }
8793 return rc;
8794}
8795
8796
8797/**
8798 * The thread-context callback (only on platforms which support it).
8799 *
8800 * @param enmEvent The thread-context event.
8801 * @param pVCpu The cross context virtual CPU structure.
8802 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
8803 * @thread EMT(pVCpu)
8804 */
8805VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPUCC pVCpu, bool fGlobalInit)
8806{
8807 AssertPtr(pVCpu);
8808 RT_NOREF1(fGlobalInit);
8809
8810 switch (enmEvent)
8811 {
8812 case RTTHREADCTXEVENT_OUT:
8813 {
8814 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8815 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8816 VMCPU_ASSERT_EMT(pVCpu);
8817
8818 /* No longjmps (logger flushes, locks) in this fragile context. */
8819 VMMRZCallRing3Disable(pVCpu);
8820 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
8821
8822 /* Restore host-state (FPU, debug etc.) */
8823 if (!pVCpu->hm.s.fLeaveDone)
8824 {
8825 /*
8826 * Do -not- import the guest-state here as we might already be in the middle of importing
8827 * it, esp. bad if we're holding the PGM lock, see comment in hmR0VmxImportGuestState().
8828 */
8829 hmR0VmxLeave(pVCpu, false /* fImportState */);
8830 pVCpu->hm.s.fLeaveDone = true;
8831 }
8832
8833 /* Leave HM context, takes care of local init (term). */
8834 int rc = HMR0LeaveCpu(pVCpu);
8835 AssertRC(rc);
8836
8837 /* Restore longjmp state. */
8838 VMMRZCallRing3Enable(pVCpu);
8839 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
8840 break;
8841 }
8842
8843 case RTTHREADCTXEVENT_IN:
8844 {
8845 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8846 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8847 VMCPU_ASSERT_EMT(pVCpu);
8848
8849 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
8850 VMMRZCallRing3Disable(pVCpu);
8851 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
8852
8853 /* Initialize the bare minimum state required for HM. This takes care of
8854 initializing VT-x if necessary (onlined CPUs, local init etc.) */
8855 int rc = hmR0EnterCpu(pVCpu);
8856 AssertRC(rc);
8857 Assert( (pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
8858 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
8859
8860 /* Load the active VMCS as the current one. */
8861 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8862 rc = hmR0VmxLoadVmcs(pVmcsInfo);
8863 AssertRC(rc);
8864 Log4Func(("Resumed: Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8865 pVCpu->hm.s.fLeaveDone = false;
8866
8867 /* Do the EMT scheduled L1D flush if needed. */
8868 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
8869 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
8870
8871 /* Restore longjmp state. */
8872 VMMRZCallRing3Enable(pVCpu);
8873 break;
8874 }
8875
8876 default:
8877 break;
8878 }
8879}
8880
8881
8882/**
8883 * Exports the host state into the VMCS host-state area.
8884 * Sets up the VM-exit MSR-load area.
8885 *
8886 * The CPU state will be loaded from these fields on every successful VM-exit.
8887 *
8888 * @returns VBox status code.
8889 * @param pVCpu The cross context virtual CPU structure.
8890 *
8891 * @remarks No-long-jump zone!!!
8892 */
8893static int hmR0VmxExportHostState(PVMCPUCC pVCpu)
8894{
8895 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8896
8897 int rc = VINF_SUCCESS;
8898 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
8899 {
8900 hmR0VmxExportHostControlRegs();
8901
8902 rc = hmR0VmxExportHostSegmentRegs(pVCpu);
8903 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8904
8905 hmR0VmxExportHostMsrs(pVCpu);
8906
8907 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_HOST_CONTEXT;
8908 }
8909 return rc;
8910}
8911
8912
8913/**
8914 * Saves the host state in the VMCS host-state.
8915 *
8916 * @returns VBox status code.
8917 * @param pVCpu The cross context virtual CPU structure.
8918 *
8919 * @remarks No-long-jump zone!!!
8920 */
8921VMMR0DECL(int) VMXR0ExportHostState(PVMCPUCC pVCpu)
8922{
8923 AssertPtr(pVCpu);
8924 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8925
8926 /*
8927 * Export the host state here while entering HM context.
8928 * When thread-context hooks are used, we might get preempted and have to re-save the host
8929 * state but most of the time we won't be, so do it here before we disable interrupts.
8930 */
8931 return hmR0VmxExportHostState(pVCpu);
8932}
8933
8934
8935/**
8936 * Exports the guest state into the VMCS guest-state area.
8937 *
8938 * The will typically be done before VM-entry when the guest-CPU state and the
8939 * VMCS state may potentially be out of sync.
8940 *
8941 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
8942 * VM-entry controls.
8943 * Sets up the appropriate VMX non-root function to execute guest code based on
8944 * the guest CPU mode.
8945 *
8946 * @returns VBox strict status code.
8947 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8948 * without unrestricted guest execution and the VMMDev is not presently
8949 * mapped (e.g. EFI32).
8950 *
8951 * @param pVCpu The cross context virtual CPU structure.
8952 * @param pVmxTransient The VMX-transient structure.
8953 *
8954 * @remarks No-long-jump zone!!!
8955 */
8956static VBOXSTRICTRC hmR0VmxExportGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8957{
8958 AssertPtr(pVCpu);
8959 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8960 LogFlowFunc(("pVCpu=%p\n", pVCpu));
8961
8962 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExportGuestState, x);
8963
8964 /*
8965 * Determine real-on-v86 mode.
8966 * Used when the guest is in real-mode and unrestricted guest execution is not used.
8967 */
8968 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8969 if ( pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest
8970 || !CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx))
8971 pVmcsInfo->RealMode. fRealOnV86Active = false;
8972 else
8973 {
8974 Assert(!pVmxTransient->fIsNestedGuest);
8975 pVmcsInfo->RealMode.fRealOnV86Active = true;
8976 }
8977
8978 /*
8979 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
8980 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
8981 */
8982 /** @todo r=ramshankar: Move hmR0VmxSelectVMRunHandler inside
8983 * hmR0VmxExportGuestEntryExitCtls and do it conditionally. There shouldn't
8984 * be a need to evaluate this everytime since I'm pretty sure we intercept
8985 * all guest paging mode changes. */
8986 int rc = hmR0VmxSelectVMRunHandler(pVCpu, pVmxTransient);
8987 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8988
8989 rc = hmR0VmxExportGuestEntryExitCtls(pVCpu, pVmxTransient);
8990 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8991
8992 rc = hmR0VmxExportGuestCR0(pVCpu, pVmxTransient);
8993 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8994
8995 VBOXSTRICTRC rcStrict = hmR0VmxExportGuestCR3AndCR4(pVCpu, pVmxTransient);
8996 if (rcStrict == VINF_SUCCESS)
8997 { /* likely */ }
8998 else
8999 {
9000 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
9001 return rcStrict;
9002 }
9003
9004 rc = hmR0VmxExportGuestSegRegsXdtr(pVCpu, pVmxTransient);
9005 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9006
9007 rc = hmR0VmxExportGuestMsrs(pVCpu, pVmxTransient);
9008 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9009
9010 rc = hmR0VmxExportGuestApicTpr(pVCpu, pVmxTransient);
9011 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9012
9013 rc = hmR0VmxExportGuestXcptIntercepts(pVCpu, pVmxTransient);
9014 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9015
9016 rc = hmR0VmxExportGuestRip(pVCpu);
9017 rc |= hmR0VmxExportGuestRsp(pVCpu);
9018 rc |= hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9019 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9020
9021 rc = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9022 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9023
9024 /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
9025 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~( (HM_CHANGED_GUEST_GPRS_MASK & ~HM_CHANGED_GUEST_RSP)
9026 | HM_CHANGED_GUEST_CR2
9027 | (HM_CHANGED_GUEST_DR_MASK & ~HM_CHANGED_GUEST_DR7)
9028 | HM_CHANGED_GUEST_X87
9029 | HM_CHANGED_GUEST_SSE_AVX
9030 | HM_CHANGED_GUEST_OTHER_XSAVE
9031 | HM_CHANGED_GUEST_XCRx
9032 | HM_CHANGED_GUEST_KERNEL_GS_BASE /* Part of lazy or auto load-store MSRs. */
9033 | HM_CHANGED_GUEST_SYSCALL_MSRS /* Part of lazy or auto load-store MSRs. */
9034 | HM_CHANGED_GUEST_TSC_AUX
9035 | HM_CHANGED_GUEST_OTHER_MSRS
9036 | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
9037
9038 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExportGuestState, x);
9039 return rc;
9040}
9041
9042
9043/**
9044 * Exports the state shared between the host and guest into the VMCS.
9045 *
9046 * @param pVCpu The cross context virtual CPU structure.
9047 * @param pVmxTransient The VMX-transient structure.
9048 *
9049 * @remarks No-long-jump zone!!!
9050 */
9051static void hmR0VmxExportSharedState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9052{
9053 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9054 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9055
9056 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_DR_MASK)
9057 {
9058 int rc = hmR0VmxExportSharedDebugState(pVCpu, pVmxTransient);
9059 AssertRC(rc);
9060 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_GUEST_DR_MASK;
9061
9062 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
9063 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_RFLAGS)
9064 {
9065 rc = hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9066 AssertRC(rc);
9067 }
9068 }
9069
9070 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_GUEST_LAZY_MSRS)
9071 {
9072 hmR0VmxLazyLoadGuestMsrs(pVCpu);
9073 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_VMX_GUEST_LAZY_MSRS;
9074 }
9075
9076 AssertMsg(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE),
9077 ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
9078}
9079
9080
9081/**
9082 * Worker for loading the guest-state bits in the inner VT-x execution loop.
9083 *
9084 * @returns Strict VBox status code (i.e. informational status codes too).
9085 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9086 * without unrestricted guest execution and the VMMDev is not presently
9087 * mapped (e.g. EFI32).
9088 *
9089 * @param pVCpu The cross context virtual CPU structure.
9090 * @param pVmxTransient The VMX-transient structure.
9091 *
9092 * @remarks No-long-jump zone!!!
9093 */
9094static VBOXSTRICTRC hmR0VmxExportGuestStateOptimal(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9095{
9096 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9097 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9098 Assert(VMMR0IsLogFlushDisabled(pVCpu));
9099
9100#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
9101 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
9102#endif
9103
9104 /*
9105 * For many exits it's only RIP that changes and hence try to export it first
9106 * without going through a lot of change flag checks.
9107 */
9108 VBOXSTRICTRC rcStrict;
9109 uint64_t fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9110 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
9111 if ((fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)) == HM_CHANGED_GUEST_RIP)
9112 {
9113 rcStrict = hmR0VmxExportGuestRip(pVCpu);
9114 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9115 { /* likely */}
9116 else
9117 AssertMsgFailedReturn(("Failed to export guest RIP! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)), rcStrict);
9118 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportMinimal);
9119 }
9120 else if (fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9121 {
9122 rcStrict = hmR0VmxExportGuestState(pVCpu, pVmxTransient);
9123 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9124 { /* likely */}
9125 else
9126 {
9127 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM, ("Failed to export guest state! rc=%Rrc\n",
9128 VBOXSTRICTRC_VAL(rcStrict)));
9129 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9130 return rcStrict;
9131 }
9132 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportFull);
9133 }
9134 else
9135 rcStrict = VINF_SUCCESS;
9136
9137#ifdef VBOX_STRICT
9138 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
9139 fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9140 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
9141 AssertMsg(!(fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)),
9142 ("fCtxChanged=%#RX64\n", fCtxChanged));
9143#endif
9144 return rcStrict;
9145}
9146
9147
9148/**
9149 * Tries to determine what part of the guest-state VT-x has deemed as invalid
9150 * and update error record fields accordingly.
9151 *
9152 * @returns VMX_IGS_* error codes.
9153 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
9154 * wrong with the guest state.
9155 *
9156 * @param pVCpu The cross context virtual CPU structure.
9157 * @param pVmcsInfo The VMCS info. object.
9158 *
9159 * @remarks This function assumes our cache of the VMCS controls
9160 * are valid, i.e. hmR0VmxCheckVmcsCtls() succeeded.
9161 */
9162static uint32_t hmR0VmxCheckGuestState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
9163{
9164#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
9165#define HMVMX_CHECK_BREAK(expr, err) do { \
9166 if (!(expr)) { uError = (err); break; } \
9167 } while (0)
9168
9169 int rc;
9170 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9171 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9172 uint32_t uError = VMX_IGS_ERROR;
9173 uint32_t u32Val;
9174 bool const fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuest;
9175
9176 do
9177 {
9178 /*
9179 * CR0.
9180 */
9181 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9182 uint64_t fSetCr0 = (pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
9183 uint64_t const fZapCr0 = (pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
9184 /* Exceptions for unrestricted guest execution for fixed CR0 bits (PE, PG).
9185 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
9186 if (fUnrestrictedGuest)
9187 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
9188
9189 uint64_t u64GuestCr0;
9190 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64GuestCr0);
9191 AssertRC(rc);
9192 HMVMX_CHECK_BREAK((u64GuestCr0 & fSetCr0) == fSetCr0, VMX_IGS_CR0_FIXED1);
9193 HMVMX_CHECK_BREAK(!(u64GuestCr0 & ~fZapCr0), VMX_IGS_CR0_FIXED0);
9194 if ( !fUnrestrictedGuest
9195 && (u64GuestCr0 & X86_CR0_PG)
9196 && !(u64GuestCr0 & X86_CR0_PE))
9197 {
9198 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
9199 }
9200
9201 /*
9202 * CR4.
9203 */
9204 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9205 uint64_t const fSetCr4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
9206 uint64_t const fZapCr4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
9207
9208 uint64_t u64GuestCr4;
9209 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64GuestCr4);
9210 AssertRC(rc);
9211 HMVMX_CHECK_BREAK((u64GuestCr4 & fSetCr4) == fSetCr4, VMX_IGS_CR4_FIXED1);
9212 HMVMX_CHECK_BREAK(!(u64GuestCr4 & ~fZapCr4), VMX_IGS_CR4_FIXED0);
9213
9214 /*
9215 * IA32_DEBUGCTL MSR.
9216 */
9217 uint64_t u64Val;
9218 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
9219 AssertRC(rc);
9220 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9221 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
9222 {
9223 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
9224 }
9225 uint64_t u64DebugCtlMsr = u64Val;
9226
9227#ifdef VBOX_STRICT
9228 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
9229 AssertRC(rc);
9230 Assert(u32Val == pVmcsInfo->u32EntryCtls);
9231#endif
9232 bool const fLongModeGuest = RT_BOOL(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
9233
9234 /*
9235 * RIP and RFLAGS.
9236 */
9237 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
9238 AssertRC(rc);
9239 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
9240 if ( !fLongModeGuest
9241 || !pCtx->cs.Attr.n.u1Long)
9242 {
9243 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
9244 }
9245 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
9246 * must be identical if the "IA-32e mode guest" VM-entry
9247 * control is 1 and CS.L is 1. No check applies if the
9248 * CPU supports 64 linear-address bits. */
9249
9250 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
9251 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
9252 AssertRC(rc);
9253 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
9254 VMX_IGS_RFLAGS_RESERVED);
9255 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
9256 uint32_t const u32Eflags = u64Val;
9257
9258 if ( fLongModeGuest
9259 || ( fUnrestrictedGuest
9260 && !(u64GuestCr0 & X86_CR0_PE)))
9261 {
9262 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
9263 }
9264
9265 uint32_t u32EntryInfo;
9266 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
9267 AssertRC(rc);
9268 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9269 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
9270
9271 /*
9272 * 64-bit checks.
9273 */
9274 if (fLongModeGuest)
9275 {
9276 HMVMX_CHECK_BREAK(u64GuestCr0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
9277 HMVMX_CHECK_BREAK(u64GuestCr4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
9278 }
9279
9280 if ( !fLongModeGuest
9281 && (u64GuestCr4 & X86_CR4_PCIDE))
9282 {
9283 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
9284 }
9285
9286 /** @todo CR3 field must be such that bits 63:52 and bits in the range
9287 * 51:32 beyond the processor's physical-address width are 0. */
9288
9289 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9290 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
9291 {
9292 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
9293 }
9294
9295 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
9296 AssertRC(rc);
9297 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
9298
9299 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
9300 AssertRC(rc);
9301 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
9302
9303 /*
9304 * PERF_GLOBAL MSR.
9305 */
9306 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR)
9307 {
9308 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
9309 AssertRC(rc);
9310 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
9311 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
9312 }
9313
9314 /*
9315 * PAT MSR.
9316 */
9317 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
9318 {
9319 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
9320 AssertRC(rc);
9321 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
9322 for (unsigned i = 0; i < 8; i++)
9323 {
9324 uint8_t u8Val = (u64Val & 0xff);
9325 if ( u8Val != 0 /* UC */
9326 && u8Val != 1 /* WC */
9327 && u8Val != 4 /* WT */
9328 && u8Val != 5 /* WP */
9329 && u8Val != 6 /* WB */
9330 && u8Val != 7 /* UC- */)
9331 {
9332 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
9333 }
9334 u64Val >>= 8;
9335 }
9336 }
9337
9338 /*
9339 * EFER MSR.
9340 */
9341 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
9342 {
9343 Assert(pVM->hm.s.vmx.fSupportsVmcsEfer);
9344 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
9345 AssertRC(rc);
9346 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
9347 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
9348 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVmcsInfo->u32EntryCtls
9349 & VMX_ENTRY_CTLS_IA32E_MODE_GUEST),
9350 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
9351 /** @todo r=ramshankar: Unrestricted check here is probably wrong, see
9352 * iemVmxVmentryCheckGuestState(). */
9353 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9354 || !(u64GuestCr0 & X86_CR0_PG)
9355 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
9356 VMX_IGS_EFER_LMA_LME_MISMATCH);
9357 }
9358
9359 /*
9360 * Segment registers.
9361 */
9362 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9363 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
9364 if (!(u32Eflags & X86_EFL_VM))
9365 {
9366 /* CS */
9367 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
9368 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
9369 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
9370 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
9371 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9372 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
9373 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9374 /* CS cannot be loaded with NULL in protected mode. */
9375 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
9376 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
9377 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
9378 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
9379 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
9380 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
9381 else if (pVM->hm.s.vmx.fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
9382 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
9383 else
9384 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
9385
9386 /* SS */
9387 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9388 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
9389 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
9390 if ( !(pCtx->cr0 & X86_CR0_PE)
9391 || pCtx->cs.Attr.n.u4Type == 3)
9392 {
9393 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
9394 }
9395 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
9396 {
9397 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
9398 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
9399 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
9400 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
9401 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
9402 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9403 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
9404 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9405 }
9406
9407 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSReg(). */
9408 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
9409 {
9410 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
9411 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
9412 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9413 || pCtx->ds.Attr.n.u4Type > 11
9414 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9415 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
9416 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
9417 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
9418 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9419 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
9420 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9421 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9422 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
9423 }
9424 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
9425 {
9426 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
9427 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
9428 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9429 || pCtx->es.Attr.n.u4Type > 11
9430 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9431 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
9432 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
9433 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
9434 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9435 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
9436 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9437 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9438 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
9439 }
9440 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
9441 {
9442 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
9443 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
9444 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9445 || pCtx->fs.Attr.n.u4Type > 11
9446 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
9447 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
9448 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
9449 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
9450 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9451 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
9452 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9453 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9454 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
9455 }
9456 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
9457 {
9458 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
9459 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
9460 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9461 || pCtx->gs.Attr.n.u4Type > 11
9462 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
9463 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
9464 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
9465 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
9466 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9467 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
9468 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9469 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9470 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
9471 }
9472 /* 64-bit capable CPUs. */
9473 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9474 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9475 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9476 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9477 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9478 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9479 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9480 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9481 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9482 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9483 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9484 }
9485 else
9486 {
9487 /* V86 mode checks. */
9488 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
9489 if (pVmcsInfo->RealMode.fRealOnV86Active)
9490 {
9491 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
9492 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
9493 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
9494 }
9495 else
9496 {
9497 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
9498 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
9499 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
9500 }
9501
9502 /* CS */
9503 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
9504 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
9505 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
9506 /* SS */
9507 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
9508 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
9509 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
9510 /* DS */
9511 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
9512 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
9513 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
9514 /* ES */
9515 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
9516 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
9517 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
9518 /* FS */
9519 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
9520 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
9521 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
9522 /* GS */
9523 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
9524 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
9525 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
9526 /* 64-bit capable CPUs. */
9527 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9528 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9529 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9530 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9531 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9532 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9533 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9534 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9535 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9536 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9537 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9538 }
9539
9540 /*
9541 * TR.
9542 */
9543 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
9544 /* 64-bit capable CPUs. */
9545 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
9546 if (fLongModeGuest)
9547 {
9548 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
9549 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
9550 }
9551 else
9552 {
9553 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
9554 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
9555 VMX_IGS_TR_ATTR_TYPE_INVALID);
9556 }
9557 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
9558 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
9559 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
9560 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
9561 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
9562 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
9563 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
9564 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
9565
9566 /*
9567 * GDTR and IDTR (64-bit capable checks).
9568 */
9569 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
9570 AssertRC(rc);
9571 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
9572
9573 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
9574 AssertRC(rc);
9575 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
9576
9577 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
9578 AssertRC(rc);
9579 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
9580
9581 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
9582 AssertRC(rc);
9583 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
9584
9585 /*
9586 * Guest Non-Register State.
9587 */
9588 /* Activity State. */
9589 uint32_t u32ActivityState;
9590 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
9591 AssertRC(rc);
9592 HMVMX_CHECK_BREAK( !u32ActivityState
9593 || (u32ActivityState & RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Misc, VMX_BF_MISC_ACTIVITY_STATES)),
9594 VMX_IGS_ACTIVITY_STATE_INVALID);
9595 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
9596 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
9597 uint32_t u32IntrState;
9598 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32IntrState);
9599 AssertRC(rc);
9600 if ( u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS
9601 || u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9602 {
9603 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
9604 }
9605
9606 /** @todo Activity state and injecting interrupts. Left as a todo since we
9607 * currently don't use activity states but ACTIVE. */
9608
9609 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
9610 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
9611
9612 /* Guest interruptibility-state. */
9613 HMVMX_CHECK_BREAK(!(u32IntrState & 0xffffffe0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
9614 HMVMX_CHECK_BREAK((u32IntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
9615 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9616 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
9617 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
9618 || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
9619 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
9620 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9621 {
9622 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9623 && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9624 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
9625 }
9626 else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
9627 {
9628 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9629 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
9630 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
9631 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
9632 }
9633 /** @todo Assumes the processor is not in SMM. */
9634 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
9635 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
9636 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
9637 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
9638 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
9639 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
9640 && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
9641 {
9642 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI),
9643 VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
9644 }
9645
9646 /* Pending debug exceptions. */
9647 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &u64Val);
9648 AssertRC(rc);
9649 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
9650 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
9651 u32Val = u64Val; /* For pending debug exceptions checks below. */
9652
9653 if ( (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9654 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
9655 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
9656 {
9657 if ( (u32Eflags & X86_EFL_TF)
9658 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
9659 {
9660 /* Bit 14 is PendingDebug.BS. */
9661 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
9662 }
9663 if ( !(u32Eflags & X86_EFL_TF)
9664 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
9665 {
9666 /* Bit 14 is PendingDebug.BS. */
9667 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
9668 }
9669 }
9670
9671 /* VMCS link pointer. */
9672 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
9673 AssertRC(rc);
9674 if (u64Val != UINT64_C(0xffffffffffffffff))
9675 {
9676 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
9677 /** @todo Bits beyond the processor's physical-address width MBZ. */
9678 /** @todo SMM checks. */
9679 Assert(pVmcsInfo->HCPhysShadowVmcs == u64Val);
9680 Assert(pVmcsInfo->pvShadowVmcs);
9681 VMXVMCSREVID VmcsRevId;
9682 VmcsRevId.u = *(uint32_t *)pVmcsInfo->pvShadowVmcs;
9683 HMVMX_CHECK_BREAK(VmcsRevId.n.u31RevisionId == RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID),
9684 VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID);
9685 HMVMX_CHECK_BREAK(VmcsRevId.n.fIsShadowVmcs == (uint32_t)!!(pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING),
9686 VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW);
9687 }
9688
9689 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
9690 * not using nested paging? */
9691 if ( pVM->hm.s.fNestedPaging
9692 && !fLongModeGuest
9693 && CPUMIsGuestInPAEModeEx(pCtx))
9694 {
9695 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
9696 AssertRC(rc);
9697 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9698
9699 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
9700 AssertRC(rc);
9701 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9702
9703 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
9704 AssertRC(rc);
9705 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9706
9707 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
9708 AssertRC(rc);
9709 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9710 }
9711
9712 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
9713 if (uError == VMX_IGS_ERROR)
9714 uError = VMX_IGS_REASON_NOT_FOUND;
9715 } while (0);
9716
9717 pVCpu->hm.s.u32HMError = uError;
9718 return uError;
9719
9720#undef HMVMX_ERROR_BREAK
9721#undef HMVMX_CHECK_BREAK
9722}
9723
9724
9725/**
9726 * Map the APIC-access page for virtualizing APIC accesses.
9727 *
9728 * This can cause a longjumps to R3 due to the acquisition of the PGM lock. Hence,
9729 * this not done as part of exporting guest state, see @bugref{8721}.
9730 *
9731 * @returns VBox status code.
9732 * @param pVCpu The cross context virtual CPU structure.
9733 */
9734static int hmR0VmxMapHCApicAccessPage(PVMCPUCC pVCpu)
9735{
9736 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9737 uint64_t const u64MsrApicBase = APICGetBaseMsrNoCheck(pVCpu);
9738
9739 Assert(PDMHasApic(pVM));
9740 Assert(u64MsrApicBase);
9741
9742 RTGCPHYS const GCPhysApicBase = u64MsrApicBase & PAGE_BASE_GC_MASK;
9743 Log4Func(("Mappping HC APIC-access page at %#RGp\n", GCPhysApicBase));
9744
9745 /* Unalias the existing mapping. */
9746 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
9747 AssertRCReturn(rc, rc);
9748
9749 /* Map the HC APIC-access page in place of the MMIO page, also updates the shadow page tables if necessary. */
9750 Assert(pVM->hm.s.vmx.HCPhysApicAccess != NIL_RTHCPHYS);
9751 rc = IOMMMIOMapMMIOHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hm.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
9752 AssertRCReturn(rc, rc);
9753
9754 /* Update the per-VCPU cache of the APIC base MSR. */
9755 pVCpu->hm.s.vmx.u64GstMsrApicBase = u64MsrApicBase;
9756 return VINF_SUCCESS;
9757}
9758
9759
9760/**
9761 * Worker function passed to RTMpOnSpecific() that is to be called on the target
9762 * CPU.
9763 *
9764 * @param idCpu The ID for the CPU the function is called on.
9765 * @param pvUser1 Null, not used.
9766 * @param pvUser2 Null, not used.
9767 */
9768static DECLCALLBACK(void) hmR0DispatchHostNmi(RTCPUID idCpu, void *pvUser1, void *pvUser2)
9769{
9770 RT_NOREF3(idCpu, pvUser1, pvUser2);
9771 VMXDispatchHostNmi();
9772}
9773
9774
9775/**
9776 * Dispatching an NMI on the host CPU that received it.
9777 *
9778 * @returns VBox status code.
9779 * @param pVCpu The cross context virtual CPU structure.
9780 * @param pVmcsInfo The VMCS info. object corresponding to the VMCS that was
9781 * executing when receiving the host NMI in VMX non-root
9782 * operation.
9783 */
9784static int hmR0VmxExitHostNmi(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
9785{
9786 RTCPUID const idCpu = pVmcsInfo->idHostCpuExec;
9787 Assert(idCpu != NIL_RTCPUID);
9788
9789 /*
9790 * We don't want to delay dispatching the NMI any more than we have to. However,
9791 * we have already chosen -not- to dispatch NMIs when interrupts were still disabled
9792 * after executing guest or nested-guest code for the following reasons:
9793 *
9794 * - We would need to perform VMREADs with interrupts disabled and is orders of
9795 * magnitude worse when we run as a guest hypervisor without VMCS shadowing
9796 * supported by the host hypervisor.
9797 *
9798 * - It affects the common VM-exit scenario and keeps interrupts disabled for a
9799 * longer period of time just for handling an edge case like host NMIs which do
9800 * not occur nearly as frequently as other VM-exits.
9801 *
9802 * Let's cover the most likely scenario first. Check if we are on the target CPU
9803 * and dispatch the NMI right away. This should be much faster than calling into
9804 * RTMpOnSpecific() machinery.
9805 */
9806 bool fDispatched = false;
9807 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
9808 if (idCpu == RTMpCpuId())
9809 {
9810 VMXDispatchHostNmi();
9811 fDispatched = true;
9812 }
9813 ASMSetFlags(fEFlags);
9814 if (fDispatched)
9815 {
9816 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
9817 return VINF_SUCCESS;
9818 }
9819
9820 /*
9821 * RTMpOnSpecific() waits until the worker function has run on the target CPU. So
9822 * there should be no race or recursion even if we are unlucky enough to be preempted
9823 * (to the target CPU) without dispatching the host NMI above.
9824 */
9825 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGCIpi);
9826 return RTMpOnSpecific(idCpu, &hmR0DispatchHostNmi, NULL /* pvUser1 */, NULL /* pvUser2 */);
9827}
9828
9829
9830#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9831/**
9832 * Merges the guest with the nested-guest MSR bitmap in preparation of executing the
9833 * nested-guest using hardware-assisted VMX.
9834 *
9835 * @param pVCpu The cross context virtual CPU structure.
9836 * @param pVmcsInfoNstGst The nested-guest VMCS info. object.
9837 * @param pVmcsInfoGst The guest VMCS info. object.
9838 */
9839static void hmR0VmxMergeMsrBitmapNested(PCVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfoNstGst, PCVMXVMCSINFO pVmcsInfoGst)
9840{
9841 uint32_t const cbMsrBitmap = X86_PAGE_4K_SIZE;
9842 uint64_t *pu64MsrBitmap = (uint64_t *)pVmcsInfoNstGst->pvMsrBitmap;
9843 Assert(pu64MsrBitmap);
9844
9845 /*
9846 * We merge the guest MSR bitmap with the nested-guest MSR bitmap such that any
9847 * MSR that is intercepted by the guest is also intercepted while executing the
9848 * nested-guest using hardware-assisted VMX.
9849 *
9850 * Note! If the nested-guest is not using an MSR bitmap, ever MSR must cause a
9851 * nested-guest VM-exit even if the outer guest is not intercepting some
9852 * MSRs. We cannot assume the caller has initialized the nested-guest
9853 * MSR bitmap in this case.
9854 *
9855 * The guest hypervisor may also switch whether it uses MSR bitmaps for
9856 * each VM-entry, hence initializing it once per-VM while setting up the
9857 * nested-guest VMCS is not sufficient.
9858 */
9859 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
9860 if (pVmcsNstGst->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
9861 {
9862 uint64_t const *pu64MsrBitmapNstGst = (uint64_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
9863 uint64_t const *pu64MsrBitmapGst = (uint64_t const *)pVmcsInfoGst->pvMsrBitmap;
9864 Assert(pu64MsrBitmapNstGst);
9865 Assert(pu64MsrBitmapGst);
9866
9867 uint32_t const cFrags = cbMsrBitmap / sizeof(uint64_t);
9868 for (uint32_t i = 0; i < cFrags; i++)
9869 pu64MsrBitmap[i] = pu64MsrBitmapNstGst[i] | pu64MsrBitmapGst[i];
9870 }
9871 else
9872 ASMMemFill32(pu64MsrBitmap, cbMsrBitmap, UINT32_C(0xffffffff));
9873}
9874
9875
9876/**
9877 * Merges the guest VMCS in to the nested-guest VMCS controls in preparation of
9878 * hardware-assisted VMX execution of the nested-guest.
9879 *
9880 * For a guest, we don't modify these controls once we set up the VMCS and hence
9881 * this function is never called.
9882 *
9883 * For nested-guests since the guest hypervisor provides these controls on every
9884 * nested-guest VM-entry and could potentially change them everytime we need to
9885 * merge them before every nested-guest VM-entry.
9886 *
9887 * @returns VBox status code.
9888 * @param pVCpu The cross context virtual CPU structure.
9889 */
9890static int hmR0VmxMergeVmcsNested(PVMCPUCC pVCpu)
9891{
9892 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9893 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hm.s.vmx.VmcsInfo;
9894 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
9895 Assert(pVmcsNstGst);
9896
9897 /*
9898 * Merge the controls with the requirements of the guest VMCS.
9899 *
9900 * We do not need to validate the nested-guest VMX features specified in the nested-guest
9901 * VMCS with the features supported by the physical CPU as it's already done by the
9902 * VMLAUNCH/VMRESUME instruction emulation.
9903 *
9904 * This is because the VMX features exposed by CPUM (through CPUID/MSRs) to the guest are
9905 * derived from the VMX features supported by the physical CPU.
9906 */
9907
9908 /* Pin-based VM-execution controls. */
9909 uint32_t const u32PinCtls = pVmcsNstGst->u32PinCtls | pVmcsInfoGst->u32PinCtls;
9910
9911 /* Processor-based VM-execution controls. */
9912 uint32_t u32ProcCtls = (pVmcsNstGst->u32ProcCtls & ~VMX_PROC_CTLS_USE_IO_BITMAPS)
9913 | (pVmcsInfoGst->u32ProcCtls & ~( VMX_PROC_CTLS_INT_WINDOW_EXIT
9914 | VMX_PROC_CTLS_NMI_WINDOW_EXIT
9915 | VMX_PROC_CTLS_USE_TPR_SHADOW
9916 | VMX_PROC_CTLS_MONITOR_TRAP_FLAG));
9917
9918 /* Secondary processor-based VM-execution controls. */
9919 uint32_t const u32ProcCtls2 = (pVmcsNstGst->u32ProcCtls2 & ~VMX_PROC_CTLS2_VPID)
9920 | (pVmcsInfoGst->u32ProcCtls2 & ~( VMX_PROC_CTLS2_VIRT_APIC_ACCESS
9921 | VMX_PROC_CTLS2_INVPCID
9922 | VMX_PROC_CTLS2_VMCS_SHADOWING
9923 | VMX_PROC_CTLS2_RDTSCP
9924 | VMX_PROC_CTLS2_XSAVES_XRSTORS
9925 | VMX_PROC_CTLS2_APIC_REG_VIRT
9926 | VMX_PROC_CTLS2_VIRT_INT_DELIVERY
9927 | VMX_PROC_CTLS2_VMFUNC));
9928
9929 /*
9930 * VM-entry controls:
9931 * These controls contains state that depends on the nested-guest state (primarily
9932 * EFER MSR) and is thus not constant between VMLAUNCH/VMRESUME and the nested-guest
9933 * VM-exit. Although the guest hypervisor cannot change it, we need to in order to
9934 * properly continue executing the nested-guest if the EFER MSR changes but does not
9935 * cause a nested-guest VM-exits.
9936 *
9937 * VM-exit controls:
9938 * These controls specify the host state on return. We cannot use the controls from
9939 * the guest hypervisor state as is as it would contain the guest state rather than
9940 * the host state. Since the host state is subject to change (e.g. preemption, trips
9941 * to ring-3, longjmp and rescheduling to a different host CPU) they are not constant
9942 * through VMLAUNCH/VMRESUME and the nested-guest VM-exit.
9943 *
9944 * VM-entry MSR-load:
9945 * The guest MSRs from the VM-entry MSR-load area are already loaded into the guest-CPU
9946 * context by the VMLAUNCH/VMRESUME instruction emulation.
9947 *
9948 * VM-exit MSR-store:
9949 * The VM-exit emulation will take care of populating the MSRs from the guest-CPU context
9950 * back into the VM-exit MSR-store area.
9951 *
9952 * VM-exit MSR-load areas:
9953 * This must contain the real host MSRs with hardware-assisted VMX execution. Hence, we
9954 * can entirely ignore what the guest hypervisor wants to load here.
9955 */
9956
9957 /*
9958 * Exception bitmap.
9959 *
9960 * We could remove #UD from the guest bitmap and merge it with the nested-guest bitmap
9961 * here (and avoid doing anything while exporting nested-guest state), but to keep the
9962 * code more flexible if intercepting exceptions become more dynamic in the future we do
9963 * it as part of exporting the nested-guest state.
9964 */
9965 uint32_t const u32XcptBitmap = pVmcsNstGst->u32XcptBitmap | pVmcsInfoGst->u32XcptBitmap;
9966
9967 /*
9968 * CR0/CR4 guest/host mask.
9969 *
9970 * Modifications by the nested-guest to CR0/CR4 bits owned by the host and the guest must
9971 * cause VM-exits, so we need to merge them here.
9972 */
9973 uint64_t const u64Cr0Mask = pVmcsNstGst->u64Cr0Mask.u | pVmcsInfoGst->u64Cr0Mask;
9974 uint64_t const u64Cr4Mask = pVmcsNstGst->u64Cr4Mask.u | pVmcsInfoGst->u64Cr4Mask;
9975
9976 /*
9977 * Page-fault error-code mask and match.
9978 *
9979 * Although we require unrestricted guest execution (and thereby nested-paging) for
9980 * hardware-assisted VMX execution of nested-guests and thus the outer guest doesn't
9981 * normally intercept #PFs, it might intercept them for debugging purposes.
9982 *
9983 * If the outer guest is not intercepting #PFs, we can use the nested-guest #PF filters.
9984 * If the outer guest is intercepting #PFs, we must intercept all #PFs.
9985 */
9986 uint32_t u32XcptPFMask;
9987 uint32_t u32XcptPFMatch;
9988 if (!(pVmcsInfoGst->u32XcptBitmap & RT_BIT(X86_XCPT_PF)))
9989 {
9990 u32XcptPFMask = pVmcsNstGst->u32XcptPFMask;
9991 u32XcptPFMatch = pVmcsNstGst->u32XcptPFMatch;
9992 }
9993 else
9994 {
9995 u32XcptPFMask = 0;
9996 u32XcptPFMatch = 0;
9997 }
9998
9999 /*
10000 * Pause-Loop exiting.
10001 */
10002 uint32_t const cPleGapTicks = RT_MIN(pVM->hm.s.vmx.cPleGapTicks, pVmcsNstGst->u32PleGap);
10003 uint32_t const cPleWindowTicks = RT_MIN(pVM->hm.s.vmx.cPleWindowTicks, pVmcsNstGst->u32PleWindow);
10004
10005 /*
10006 * Pending debug exceptions.
10007 * Currently just copy whatever the nested-guest provides us.
10008 */
10009 uint64_t const uPendingDbgXcpts = pVmcsNstGst->u64GuestPendingDbgXcpts.u;
10010
10011 /*
10012 * I/O Bitmap.
10013 *
10014 * We do not use the I/O bitmap that may be provided by the guest hypervisor as we always
10015 * intercept all I/O port accesses.
10016 */
10017 Assert(u32ProcCtls & VMX_PROC_CTLS_UNCOND_IO_EXIT);
10018 Assert(!(u32ProcCtls & VMX_PROC_CTLS_USE_IO_BITMAPS));
10019
10020 /*
10021 * VMCS shadowing.
10022 *
10023 * We do not yet expose VMCS shadowing to the guest and thus VMCS shadowing should not be
10024 * enabled while executing the nested-guest.
10025 */
10026 Assert(!(u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING));
10027
10028 /*
10029 * APIC-access page.
10030 */
10031 RTHCPHYS HCPhysApicAccess;
10032 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10033 {
10034 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
10035 RTGCPHYS const GCPhysApicAccess = pVmcsNstGst->u64AddrApicAccess.u;
10036
10037 /** @todo NSTVMX: This is not really correct but currently is required to make
10038 * things work. We need to re-enable the page handler when we fallback to
10039 * IEM execution of the nested-guest! */
10040 PGMHandlerPhysicalPageTempOff(pVM, GCPhysApicAccess, GCPhysApicAccess);
10041
10042 void *pvPage;
10043 PGMPAGEMAPLOCK PgLockApicAccess;
10044 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysApicAccess, &pvPage, &PgLockApicAccess);
10045 if (RT_SUCCESS(rc))
10046 {
10047 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysApicAccess, &HCPhysApicAccess);
10048 AssertMsgRCReturn(rc, ("Failed to get host-physical address for APIC-access page at %#RGp\n", GCPhysApicAccess), rc);
10049
10050 /** @todo Handle proper releasing of page-mapping lock later. */
10051 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockApicAccess);
10052 }
10053 else
10054 return rc;
10055 }
10056 else
10057 HCPhysApicAccess = 0;
10058
10059 /*
10060 * Virtual-APIC page and TPR threshold.
10061 */
10062 PVMXVMCSINFO pVmcsInfoNstGst = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
10063 RTHCPHYS HCPhysVirtApic;
10064 uint32_t u32TprThreshold;
10065 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10066 {
10067 Assert(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW);
10068 RTGCPHYS const GCPhysVirtApic = pVmcsNstGst->u64AddrVirtApic.u;
10069
10070 void *pvPage;
10071 PGMPAGEMAPLOCK PgLockVirtApic;
10072 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysVirtApic, &pvPage, &PgLockVirtApic);
10073 if (RT_SUCCESS(rc))
10074 {
10075 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysVirtApic, &HCPhysVirtApic);
10076 AssertMsgRCReturn(rc, ("Failed to get host-physical address for virtual-APIC page at %#RGp\n", GCPhysVirtApic), rc);
10077
10078 /** @todo Handle proper releasing of page-mapping lock later. */
10079 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockVirtApic);
10080 }
10081 else
10082 return rc;
10083
10084 u32TprThreshold = pVmcsNstGst->u32TprThreshold;
10085 }
10086 else
10087 {
10088 HCPhysVirtApic = 0;
10089 u32TprThreshold = 0;
10090
10091 /*
10092 * We must make sure CR8 reads/write must cause VM-exits when TPR shadowing is not
10093 * used by the guest hypervisor. Preventing MMIO accesses to the physical APIC will
10094 * be taken care of by EPT/shadow paging.
10095 */
10096 if (pVM->hm.s.fAllow64BitGuests)
10097 {
10098 u32ProcCtls |= VMX_PROC_CTLS_CR8_STORE_EXIT
10099 | VMX_PROC_CTLS_CR8_LOAD_EXIT;
10100 }
10101 }
10102
10103 /*
10104 * Validate basic assumptions.
10105 */
10106 Assert(pVM->hm.s.vmx.fAllowUnrestricted);
10107 Assert(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
10108 Assert(hmGetVmxActiveVmcsInfo(pVCpu) == pVmcsInfoNstGst);
10109
10110 /*
10111 * Commit it to the nested-guest VMCS.
10112 */
10113 int rc = VINF_SUCCESS;
10114 if (pVmcsInfoNstGst->u32PinCtls != u32PinCtls)
10115 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, u32PinCtls);
10116 if (pVmcsInfoNstGst->u32ProcCtls != u32ProcCtls)
10117 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, u32ProcCtls);
10118 if (pVmcsInfoNstGst->u32ProcCtls2 != u32ProcCtls2)
10119 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, u32ProcCtls2);
10120 if (pVmcsInfoNstGst->u32XcptBitmap != u32XcptBitmap)
10121 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
10122 if (pVmcsInfoNstGst->u64Cr0Mask != u64Cr0Mask)
10123 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask);
10124 if (pVmcsInfoNstGst->u64Cr4Mask != u64Cr4Mask)
10125 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask);
10126 if (pVmcsInfoNstGst->u32XcptPFMask != u32XcptPFMask)
10127 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, u32XcptPFMask);
10128 if (pVmcsInfoNstGst->u32XcptPFMatch != u32XcptPFMatch)
10129 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, u32XcptPFMatch);
10130 if ( !(u32ProcCtls & VMX_PROC_CTLS_PAUSE_EXIT)
10131 && (u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
10132 {
10133 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT);
10134 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, cPleGapTicks);
10135 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, cPleWindowTicks);
10136 }
10137 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10138 {
10139 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
10140 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
10141 }
10142 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10143 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
10144 rc |= VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, uPendingDbgXcpts);
10145 AssertRC(rc);
10146
10147 /*
10148 * Update the nested-guest VMCS cache.
10149 */
10150 pVmcsInfoNstGst->u32PinCtls = u32PinCtls;
10151 pVmcsInfoNstGst->u32ProcCtls = u32ProcCtls;
10152 pVmcsInfoNstGst->u32ProcCtls2 = u32ProcCtls2;
10153 pVmcsInfoNstGst->u32XcptBitmap = u32XcptBitmap;
10154 pVmcsInfoNstGst->u64Cr0Mask = u64Cr0Mask;
10155 pVmcsInfoNstGst->u64Cr4Mask = u64Cr4Mask;
10156 pVmcsInfoNstGst->u32XcptPFMask = u32XcptPFMask;
10157 pVmcsInfoNstGst->u32XcptPFMatch = u32XcptPFMatch;
10158 pVmcsInfoNstGst->HCPhysVirtApic = HCPhysVirtApic;
10159
10160 /*
10161 * We need to flush the TLB if we are switching the APIC-access page address.
10162 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
10163 */
10164 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10165 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = true;
10166
10167 /*
10168 * MSR bitmap.
10169 *
10170 * The MSR bitmap address has already been initialized while setting up the nested-guest
10171 * VMCS, here we need to merge the MSR bitmaps.
10172 */
10173 if (u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10174 hmR0VmxMergeMsrBitmapNested(pVCpu, pVmcsInfoNstGst, pVmcsInfoGst);
10175
10176 return VINF_SUCCESS;
10177}
10178#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10179
10180
10181/**
10182 * Does the preparations before executing guest code in VT-x.
10183 *
10184 * This may cause longjmps to ring-3 and may even result in rescheduling to the
10185 * recompiler/IEM. We must be cautious what we do here regarding committing
10186 * guest-state information into the VMCS assuming we assuredly execute the
10187 * guest in VT-x mode.
10188 *
10189 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
10190 * the common-state (TRPM/forceflags), we must undo those changes so that the
10191 * recompiler/IEM can (and should) use them when it resumes guest execution.
10192 * Otherwise such operations must be done when we can no longer exit to ring-3.
10193 *
10194 * @returns Strict VBox status code (i.e. informational status codes too).
10195 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
10196 * have been disabled.
10197 * @retval VINF_VMX_VMEXIT if a nested-guest VM-exit occurs (e.g., while evaluating
10198 * pending events).
10199 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
10200 * double-fault into the guest.
10201 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
10202 * dispatched directly.
10203 * @retval VINF_* scheduling changes, we have to go back to ring-3.
10204 *
10205 * @param pVCpu The cross context virtual CPU structure.
10206 * @param pVmxTransient The VMX-transient structure.
10207 * @param fStepping Whether we are single-stepping the guest in the
10208 * hypervisor debugger. Makes us ignore some of the reasons
10209 * for returning to ring-3, and return VINF_EM_DBG_STEPPED
10210 * if event dispatching took place.
10211 */
10212static VBOXSTRICTRC hmR0VmxPreRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, bool fStepping)
10213{
10214 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10215
10216 Log4Func(("fIsNested=%RTbool fStepping=%RTbool\n", pVmxTransient->fIsNestedGuest, fStepping));
10217
10218#ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
10219 if (pVmxTransient->fIsNestedGuest)
10220 {
10221 RT_NOREF2(pVCpu, fStepping);
10222 Log2Func(("Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
10223 return VINF_EM_RESCHEDULE_REM;
10224 }
10225#endif
10226
10227#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
10228 PGMRZDynMapFlushAutoSet(pVCpu);
10229#endif
10230
10231 /*
10232 * Check and process force flag actions, some of which might require us to go back to ring-3.
10233 */
10234 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVCpu, fStepping);
10235 if (rcStrict == VINF_SUCCESS)
10236 {
10237 /* FFs don't get set all the time. */
10238#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10239 if ( pVmxTransient->fIsNestedGuest
10240 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10241 {
10242 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10243 return VINF_VMX_VMEXIT;
10244 }
10245#endif
10246 }
10247 else
10248 return rcStrict;
10249
10250 /*
10251 * Virtualize memory-mapped accesses to the physical APIC (may take locks).
10252 */
10253 /** @todo Doing this from ring-3 after VM setup phase causes a
10254 * VERR_IOM_MMIO_RANGE_NOT_FOUND guru while booting Visa 64 SMP VM. No
10255 * idea why atm. */
10256 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10257 if ( !pVCpu->hm.s.vmx.u64GstMsrApicBase
10258 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10259 && PDMHasApic(pVM))
10260 {
10261 int rc = hmR0VmxMapHCApicAccessPage(pVCpu);
10262 AssertRCReturn(rc, rc);
10263 }
10264
10265#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10266 /*
10267 * Merge guest VMCS controls with the nested-guest VMCS controls.
10268 *
10269 * Even if we have not executed the guest prior to this (e.g. when resuming from a
10270 * saved state), we should be okay with merging controls as we initialize the
10271 * guest VMCS controls as part of VM setup phase.
10272 */
10273 if ( pVmxTransient->fIsNestedGuest
10274 && !pVCpu->hm.s.vmx.fMergedNstGstCtls)
10275 {
10276 int rc = hmR0VmxMergeVmcsNested(pVCpu);
10277 AssertRCReturn(rc, rc);
10278 pVCpu->hm.s.vmx.fMergedNstGstCtls = true;
10279 }
10280#endif
10281
10282 /*
10283 * Evaluate events to be injected into the guest.
10284 *
10285 * Events in TRPM can be injected without inspecting the guest state.
10286 * If any new events (interrupts/NMI) are pending currently, we try to set up the
10287 * guest to cause a VM-exit the next time they are ready to receive the event.
10288 *
10289 * With nested-guests, evaluating pending events may cause VM-exits.
10290 */
10291 if (TRPMHasTrap(pVCpu))
10292 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
10293
10294 uint32_t fIntrState;
10295 rcStrict = hmR0VmxEvaluatePendingEvent(pVCpu, pVmxTransient, &fIntrState);
10296
10297#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10298 /*
10299 * While evaluating pending events if something failed (unlikely) or if we were
10300 * preparing to run a nested-guest but performed a nested-guest VM-exit, we should bail.
10301 */
10302 if (rcStrict != VINF_SUCCESS)
10303 return rcStrict;
10304 if ( pVmxTransient->fIsNestedGuest
10305 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10306 {
10307 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10308 return VINF_VMX_VMEXIT;
10309 }
10310#else
10311 Assert(rcStrict == VINF_SUCCESS);
10312#endif
10313
10314 /*
10315 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus
10316 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might
10317 * also result in triple-faulting the VM.
10318 *
10319 * With nested-guests, the above does not apply since unrestricted guest execution is a
10320 * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
10321 */
10322 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pVmxTransient, fIntrState, fStepping);
10323 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10324 { /* likely */ }
10325 else
10326 {
10327 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
10328 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
10329 return rcStrict;
10330 }
10331
10332 /*
10333 * A longjump might result in importing CR3 even for VM-exits that don't necessarily
10334 * import CR3 themselves. We will need to update them here, as even as late as the above
10335 * hmR0VmxInjectPendingEvent() call may lazily import guest-CPU state on demand causing
10336 * the below force flags to be set.
10337 */
10338 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
10339 {
10340 Assert(!(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_CR3));
10341 int rc2 = PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
10342 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
10343 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
10344 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10345 }
10346 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
10347 {
10348 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
10349 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10350 }
10351
10352#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10353 /* Paranoia. */
10354 Assert(!pVmxTransient->fIsNestedGuest || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10355#endif
10356
10357 /*
10358 * No longjmps to ring-3 from this point on!!!
10359 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
10360 * This also disables flushing of the R0-logger instance (if any).
10361 */
10362 VMMRZCallRing3Disable(pVCpu);
10363
10364 /*
10365 * Export the guest state bits.
10366 *
10367 * We cannot perform longjmps while loading the guest state because we do not preserve the
10368 * host/guest state (although the VMCS will be preserved) across longjmps which can cause
10369 * CPU migration.
10370 *
10371 * If we are injecting events to a real-on-v86 mode guest, we would have updated RIP and some segment
10372 * registers. Hence, exporting of the guest state needs to be done -after- injection of events.
10373 */
10374 rcStrict = hmR0VmxExportGuestStateOptimal(pVCpu, pVmxTransient);
10375 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10376 { /* likely */ }
10377 else
10378 {
10379 VMMRZCallRing3Enable(pVCpu);
10380 return rcStrict;
10381 }
10382
10383 /*
10384 * We disable interrupts so that we don't miss any interrupts that would flag preemption
10385 * (IPI/timers etc.) when thread-context hooks aren't used and we've been running with
10386 * preemption disabled for a while. Since this is purely to aid the
10387 * RTThreadPreemptIsPending() code, it doesn't matter that it may temporarily reenable and
10388 * disable interrupt on NT.
10389 *
10390 * We need to check for force-flags that could've possible been altered since we last
10391 * checked them (e.g. by PDMGetInterrupt() leaving the PDM critical section,
10392 * see @bugref{6398}).
10393 *
10394 * We also check a couple of other force-flags as a last opportunity to get the EMT back
10395 * to ring-3 before executing guest code.
10396 */
10397 pVmxTransient->fEFlags = ASMIntDisableFlags();
10398
10399 if ( ( !VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
10400 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
10401 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
10402 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
10403 {
10404 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
10405 {
10406#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10407 /*
10408 * If we are executing a nested-guest make sure that we should intercept subsequent
10409 * events. The one we are injecting might be part of VM-entry. This is mainly to keep
10410 * the VM-exit instruction emulation happy.
10411 */
10412 if (pVmxTransient->fIsNestedGuest)
10413 pVCpu->cpum.GstCtx.hwvirt.vmx.fInterceptEvents = true;
10414#endif
10415
10416 /*
10417 * We've injected any pending events. This is really the point of no return (to ring-3).
10418 *
10419 * Note! The caller expects to continue with interrupts & longjmps disabled on successful
10420 * returns from this function, so do -not- enable them here.
10421 */
10422 pVCpu->hm.s.Event.fPending = false;
10423 return VINF_SUCCESS;
10424 }
10425
10426 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPendingHostIrq);
10427 rcStrict = VINF_EM_RAW_INTERRUPT;
10428 }
10429 else
10430 {
10431 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
10432 rcStrict = VINF_EM_RAW_TO_R3;
10433 }
10434
10435 ASMSetFlags(pVmxTransient->fEFlags);
10436 VMMRZCallRing3Enable(pVCpu);
10437
10438 return rcStrict;
10439}
10440
10441
10442/**
10443 * Final preparations before executing guest code using hardware-assisted VMX.
10444 *
10445 * We can no longer get preempted to a different host CPU and there are no returns
10446 * to ring-3. We ignore any errors that may happen from this point (e.g. VMWRITE
10447 * failures), this function is not intended to fail sans unrecoverable hardware
10448 * errors.
10449 *
10450 * @param pVCpu The cross context virtual CPU structure.
10451 * @param pVmxTransient The VMX-transient structure.
10452 *
10453 * @remarks Called with preemption disabled.
10454 * @remarks No-long-jump zone!!!
10455 */
10456static void hmR0VmxPreRunGuestCommitted(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10457{
10458 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10459 Assert(VMMR0IsLogFlushDisabled(pVCpu));
10460 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
10461 Assert(!pVCpu->hm.s.Event.fPending);
10462
10463 /*
10464 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
10465 */
10466 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10467 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
10468
10469 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10470 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10471 PHMPHYSCPU pHostCpu = hmR0GetCurrentCpu();
10472 RTCPUID const idCurrentCpu = pHostCpu->idCpu;
10473
10474 if (!CPUMIsGuestFPUStateActive(pVCpu))
10475 {
10476 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10477 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
10478 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_HOST_CONTEXT;
10479 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10480 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadGuestFpu);
10481 }
10482
10483 /*
10484 * Re-export the host state bits as we may've been preempted (only happens when
10485 * thread-context hooks are used or when the VM start function changes) or if
10486 * the host CR0 is modified while loading the guest FPU state above.
10487 *
10488 * The 64-on-32 switcher saves the (64-bit) host state into the VMCS and if we
10489 * changed the switcher back to 32-bit, we *must* save the 32-bit host state here,
10490 * see @bugref{8432}.
10491 *
10492 * This may also happen when switching to/from a nested-guest VMCS without leaving
10493 * ring-0.
10494 */
10495 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
10496 {
10497 hmR0VmxExportHostState(pVCpu);
10498 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportHostState);
10499 }
10500 Assert(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT));
10501
10502 /*
10503 * Export the state shared between host and guest (FPU, debug, lazy MSRs).
10504 */
10505 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)
10506 hmR0VmxExportSharedState(pVCpu, pVmxTransient);
10507 AssertMsg(!pVCpu->hm.s.fCtxChanged, ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
10508
10509 /*
10510 * Store status of the shared guest/host debug state at the time of VM-entry.
10511 */
10512 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
10513 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
10514
10515 /*
10516 * Always cache the TPR-shadow if the virtual-APIC page exists, thereby skipping
10517 * more than one conditional check. The post-run side of our code shall determine
10518 * if it needs to sync. the virtual APIC TPR with the TPR-shadow.
10519 */
10520 if (pVmcsInfo->pbVirtApic)
10521 pVmxTransient->u8GuestTpr = pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR];
10522
10523 /*
10524 * Update the host MSRs values in the VM-exit MSR-load area.
10525 */
10526 if (!pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs)
10527 {
10528 if (pVmcsInfo->cExitMsrLoad > 0)
10529 hmR0VmxUpdateAutoLoadHostMsrs(pVCpu, pVmcsInfo);
10530 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = true;
10531 }
10532
10533 /*
10534 * Evaluate if we need to intercept guest RDTSC/P accesses. Set up the
10535 * VMX-preemption timer based on the next virtual sync clock deadline.
10536 */
10537 if ( !pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer
10538 || idCurrentCpu != pVCpu->hm.s.idLastCpu)
10539 {
10540 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVCpu, pVmxTransient);
10541 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = true;
10542 }
10543
10544 /* Record statistics of how often we use TSC offsetting as opposed to intercepting RDTSC/P. */
10545 bool const fIsRdtscIntercepted = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT);
10546 if (!fIsRdtscIntercepted)
10547 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
10548 else
10549 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
10550
10551 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
10552 hmR0VmxFlushTaggedTlb(pHostCpu, pVCpu, pVmcsInfo); /* Invalidate the appropriate guest entries from the TLB. */
10553 Assert(idCurrentCpu == pVCpu->hm.s.idLastCpu);
10554 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Update the error reporting info. with the current host CPU. */
10555 pVmcsInfo->idHostCpuState = idCurrentCpu; /* Record the CPU for which the host-state has been exported. */
10556 pVmcsInfo->idHostCpuExec = idCurrentCpu; /* Record the CPU on which we shall execute. */
10557
10558 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
10559
10560 TMNotifyStartOfExecution(pVM, pVCpu); /* Notify TM to resume its clocks when TSC is tied to execution,
10561 as we're about to start executing the guest . */
10562
10563 /*
10564 * Load the guest TSC_AUX MSR when we are not intercepting RDTSCP.
10565 *
10566 * This is done this late as updating the TSC offsetting/preemption timer above
10567 * figures out if we can skip intercepting RDTSCP by calculating the number of
10568 * host CPU ticks till the next virtual sync deadline (for the dynamic case).
10569 */
10570 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_RDTSCP)
10571 && !fIsRdtscIntercepted)
10572 {
10573 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_TSC_AUX);
10574
10575 /* NB: Because we call hmR0VmxAddAutoLoadStoreMsr with fUpdateHostMsr=true,
10576 it's safe even after hmR0VmxUpdateAutoLoadHostMsrs has already been done. */
10577 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX, CPUMGetGuestTscAux(pVCpu),
10578 true /* fSetReadWrite */, true /* fUpdateHostMsr */);
10579 AssertRC(rc);
10580 Assert(!pVmxTransient->fRemoveTscAuxMsr);
10581 pVmxTransient->fRemoveTscAuxMsr = true;
10582 }
10583
10584#ifdef VBOX_STRICT
10585 Assert(pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs);
10586 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
10587 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo);
10588 AssertRC(hmR0VmxCheckVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest));
10589#endif
10590
10591#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
10592 /** @todo r=ramshankar: We can now probably use iemVmxVmentryCheckGuestState here.
10593 * Add a PVMXMSRS parameter to it, so that IEM can look at the host MSRs,
10594 * see @bugref{9180#c54}. */
10595 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
10596 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
10597 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
10598#endif
10599}
10600
10601
10602/**
10603 * First C routine invoked after running guest code using hardware-assisted VMX.
10604 *
10605 * @param pVCpu The cross context virtual CPU structure.
10606 * @param pVmxTransient The VMX-transient structure.
10607 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
10608 *
10609 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
10610 *
10611 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
10612 * unconditionally when it is safe to do so.
10613 */
10614static void hmR0VmxPostRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, int rcVMRun)
10615{
10616 uint64_t const uHostTsc = ASMReadTSC(); /** @todo We can do a lot better here, see @bugref{9180#c38}. */
10617
10618 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
10619 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
10620 pVCpu->hm.s.fCtxChanged = 0; /* Exits/longjmps to ring-3 requires saving the guest state. */
10621 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
10622 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
10623 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
10624
10625 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10626 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
10627 {
10628 uint64_t uGstTsc;
10629 if (!pVmxTransient->fIsNestedGuest)
10630 uGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
10631 else
10632 {
10633 uint64_t const uNstGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
10634 uGstTsc = CPUMRemoveNestedGuestTscOffset(pVCpu, uNstGstTsc);
10635 }
10636 TMCpuTickSetLastSeen(pVCpu, uGstTsc); /* Update TM with the guest TSC. */
10637 }
10638
10639 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatPreExit, x);
10640 TMNotifyEndOfExecution(pVCpu->CTX_SUFF(pVM), pVCpu); /* Notify TM that the guest is no longer running. */
10641 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10642
10643 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Some host state messed up by VMX needs restoring. */
10644 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
10645#ifdef VBOX_STRICT
10646 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo); /* Verify that the host EFER MSR wasn't modified. */
10647#endif
10648 Assert(!ASMIntAreEnabled());
10649 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
10650 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10651
10652#ifdef HMVMX_ALWAYS_CLEAN_TRANSIENT
10653 /*
10654 * Clean all the VMCS fields in the transient structure before reading
10655 * anything from the VMCS.
10656 */
10657 pVmxTransient->uExitReason = 0;
10658 pVmxTransient->uExitIntErrorCode = 0;
10659 pVmxTransient->uExitQual = 0;
10660 pVmxTransient->uGuestLinearAddr = 0;
10661 pVmxTransient->uExitIntInfo = 0;
10662 pVmxTransient->cbExitInstr = 0;
10663 pVmxTransient->ExitInstrInfo.u = 0;
10664 pVmxTransient->uEntryIntInfo = 0;
10665 pVmxTransient->uEntryXcptErrorCode = 0;
10666 pVmxTransient->cbEntryInstr = 0;
10667 pVmxTransient->uIdtVectoringInfo = 0;
10668 pVmxTransient->uIdtVectoringErrorCode = 0;
10669#endif
10670
10671 /*
10672 * Save the basic VM-exit reason and check if the VM-entry failed.
10673 * See Intel spec. 24.9.1 "Basic VM-exit Information".
10674 */
10675 uint32_t uExitReason;
10676 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
10677 AssertRC(rc);
10678 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason);
10679 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
10680
10681 /*
10682 * Log the VM-exit before logging anything else as otherwise it might be a
10683 * tad confusing what happens before and after the world-switch.
10684 */
10685 HMVMX_LOG_EXIT(pVCpu, uExitReason);
10686
10687 /*
10688 * Remove the TSC_AUX MSR from the auto-load/store MSR area and reset any MSR
10689 * bitmap permissions, if it was added before VM-entry.
10690 */
10691 if (pVmxTransient->fRemoveTscAuxMsr)
10692 {
10693 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX);
10694 pVmxTransient->fRemoveTscAuxMsr = false;
10695 }
10696
10697 /*
10698 * Check if VMLAUNCH/VMRESUME succeeded.
10699 * If this failed, we cause a guru meditation and cease further execution.
10700 *
10701 * However, if we are executing a nested-guest we might fail if we use the
10702 * fast path rather than fully emulating VMLAUNCH/VMRESUME instruction in IEM.
10703 */
10704 if (RT_LIKELY(rcVMRun == VINF_SUCCESS))
10705 {
10706 /*
10707 * Update the VM-exit history array here even if the VM-entry failed due to:
10708 * - Invalid guest state.
10709 * - MSR loading.
10710 * - Machine-check event.
10711 *
10712 * In any of the above cases we will still have a "valid" VM-exit reason
10713 * despite @a fVMEntryFailed being false.
10714 *
10715 * See Intel spec. 26.7 "VM-Entry failures during or after loading guest state".
10716 *
10717 * Note! We don't have CS or RIP at this point. Will probably address that later
10718 * by amending the history entry added here.
10719 */
10720 EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_VMX, pVmxTransient->uExitReason & EMEXIT_F_TYPE_MASK),
10721 UINT64_MAX, uHostTsc);
10722
10723 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
10724 {
10725 VMMRZCallRing3Enable(pVCpu);
10726
10727 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10728 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10729
10730#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
10731 hmR0VmxReadAllRoFieldsVmcs(pVmxTransient);
10732#endif
10733#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
10734 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
10735 AssertRC(rc);
10736#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
10737 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_RFLAGS);
10738 AssertRC(rc);
10739#else
10740 /*
10741 * Import the guest-interruptibility state always as we need it while evaluating
10742 * injecting events on re-entry.
10743 *
10744 * We don't import CR0 (when unrestricted guest execution is unavailable) despite
10745 * checking for real-mode while exporting the state because all bits that cause
10746 * mode changes wrt CR0 are intercepted.
10747 */
10748 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_HM_VMX_INT_STATE);
10749 AssertRC(rc);
10750#endif
10751
10752 /*
10753 * Sync the TPR shadow with our APIC state.
10754 */
10755 if ( !pVmxTransient->fIsNestedGuest
10756 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
10757 {
10758 Assert(pVmcsInfo->pbVirtApic);
10759 if (pVmxTransient->u8GuestTpr != pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR])
10760 {
10761 rc = APICSetTpr(pVCpu, pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR]);
10762 AssertRC(rc);
10763 ASMAtomicOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
10764 }
10765 }
10766
10767 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10768 return;
10769 }
10770 }
10771#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10772 else if (pVmxTransient->fIsNestedGuest)
10773 AssertMsgFailed(("VMLAUNCH/VMRESUME failed but shouldn't happen when VMLAUNCH/VMRESUME was emulated in IEM!\n"));
10774#endif
10775 else
10776 Log4Func(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
10777
10778 VMMRZCallRing3Enable(pVCpu);
10779}
10780
10781
10782/**
10783 * Runs the guest code using hardware-assisted VMX the normal way.
10784 *
10785 * @returns VBox status code.
10786 * @param pVCpu The cross context virtual CPU structure.
10787 * @param pcLoops Pointer to the number of executed loops.
10788 */
10789static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVMCPUCC pVCpu, uint32_t *pcLoops)
10790{
10791 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
10792 Assert(pcLoops);
10793 Assert(*pcLoops <= cMaxResumeLoops);
10794 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10795
10796#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10797 /*
10798 * Switch to the guest VMCS as we may have transitioned from executing the nested-guest
10799 * without leaving ring-0. Otherwise, if we came from ring-3 we would have loaded the
10800 * guest VMCS while entering the VMX ring-0 session.
10801 */
10802 if (pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs)
10803 {
10804 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, false /* fSwitchToNstGstVmcs */);
10805 if (RT_SUCCESS(rc))
10806 { /* likely */ }
10807 else
10808 {
10809 LogRelFunc(("Failed to switch to the guest VMCS. rc=%Rrc\n", rc));
10810 return rc;
10811 }
10812 }
10813#endif
10814
10815 VMXTRANSIENT VmxTransient;
10816 RT_ZERO(VmxTransient);
10817 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
10818
10819 /* Paranoia. */
10820 Assert(VmxTransient.pVmcsInfo == &pVCpu->hm.s.vmx.VmcsInfo);
10821
10822 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10823 for (;;)
10824 {
10825 Assert(!HMR0SuspendPending());
10826 HMVMX_ASSERT_CPU_SAFE(pVCpu);
10827 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10828
10829 /*
10830 * Preparatory work for running nested-guest code, this may force us to
10831 * return to ring-3.
10832 *
10833 * Warning! This bugger disables interrupts on VINF_SUCCESS!
10834 */
10835 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
10836 if (rcStrict != VINF_SUCCESS)
10837 break;
10838
10839 /* Interrupts are disabled at this point! */
10840 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
10841 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
10842 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
10843 /* Interrupts are re-enabled at this point! */
10844
10845 /*
10846 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
10847 */
10848 if (RT_SUCCESS(rcRun))
10849 { /* very likely */ }
10850 else
10851 {
10852 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
10853 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
10854 return rcRun;
10855 }
10856
10857 /*
10858 * Profile the VM-exit.
10859 */
10860 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10861 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10862 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10863 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
10864 HMVMX_START_EXIT_DISPATCH_PROF();
10865
10866 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
10867
10868 /*
10869 * Handle the VM-exit.
10870 */
10871#ifdef HMVMX_USE_FUNCTION_TABLE
10872 rcStrict = g_apfnVMExitHandlers[VmxTransient.uExitReason](pVCpu, &VmxTransient);
10873#else
10874 rcStrict = hmR0VmxHandleExit(pVCpu, &VmxTransient);
10875#endif
10876 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
10877 if (rcStrict == VINF_SUCCESS)
10878 {
10879 if (++(*pcLoops) <= cMaxResumeLoops)
10880 continue;
10881 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10882 rcStrict = VINF_EM_RAW_INTERRUPT;
10883 }
10884 break;
10885 }
10886
10887 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10888 return rcStrict;
10889}
10890
10891
10892#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10893/**
10894 * Runs the nested-guest code using hardware-assisted VMX.
10895 *
10896 * @returns VBox status code.
10897 * @param pVCpu The cross context virtual CPU structure.
10898 * @param pcLoops Pointer to the number of executed loops.
10899 *
10900 * @sa hmR0VmxRunGuestCodeNormal.
10901 */
10902static VBOXSTRICTRC hmR0VmxRunGuestCodeNested(PVMCPUCC pVCpu, uint32_t *pcLoops)
10903{
10904 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
10905 Assert(pcLoops);
10906 Assert(*pcLoops <= cMaxResumeLoops);
10907 Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10908
10909 /*
10910 * Switch to the nested-guest VMCS as we may have transitioned from executing the
10911 * guest without leaving ring-0. Otherwise, if we came from ring-3 we would have
10912 * loaded the nested-guest VMCS while entering the VMX ring-0 session.
10913 */
10914 if (!pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs)
10915 {
10916 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, true /* fSwitchToNstGstVmcs */);
10917 if (RT_SUCCESS(rc))
10918 { /* likely */ }
10919 else
10920 {
10921 LogRelFunc(("Failed to switch to the nested-guest VMCS. rc=%Rrc\n", rc));
10922 return rc;
10923 }
10924 }
10925
10926 VMXTRANSIENT VmxTransient;
10927 RT_ZERO(VmxTransient);
10928 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
10929 VmxTransient.fIsNestedGuest = true;
10930
10931 /* Paranoia. */
10932 Assert(VmxTransient.pVmcsInfo == &pVCpu->hm.s.vmx.VmcsInfoNstGst);
10933
10934 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10935 for (;;)
10936 {
10937 Assert(!HMR0SuspendPending());
10938 HMVMX_ASSERT_CPU_SAFE(pVCpu);
10939 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10940
10941 /*
10942 * Preparatory work for running guest code, this may force us to
10943 * return to ring-3.
10944 *
10945 * Warning! This bugger disables interrupts on VINF_SUCCESS!
10946 */
10947 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
10948 if (rcStrict != VINF_SUCCESS)
10949 break;
10950
10951 /* Interrupts are disabled at this point! */
10952 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
10953 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
10954 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
10955 /* Interrupts are re-enabled at this point! */
10956
10957 /*
10958 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
10959 */
10960 if (RT_SUCCESS(rcRun))
10961 { /* very likely */ }
10962 else
10963 {
10964 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
10965 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
10966 return rcRun;
10967 }
10968
10969 /*
10970 * Profile the VM-exit.
10971 */
10972 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10973 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10974 STAM_COUNTER_INC(&pVCpu->hm.s.StatNestedExitAll);
10975 STAM_COUNTER_INC(&pVCpu->hm.s.paStatNestedExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10976 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
10977 HMVMX_START_EXIT_DISPATCH_PROF();
10978
10979 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
10980
10981 /*
10982 * Handle the VM-exit.
10983 */
10984 rcStrict = hmR0VmxHandleExitNested(pVCpu, &VmxTransient);
10985 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
10986 if (rcStrict == VINF_SUCCESS)
10987 {
10988 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10989 {
10990 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10991 rcStrict = VINF_VMX_VMEXIT;
10992 }
10993 else
10994 {
10995 if (++(*pcLoops) <= cMaxResumeLoops)
10996 continue;
10997 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10998 rcStrict = VINF_EM_RAW_INTERRUPT;
10999 }
11000 }
11001 else
11002 Assert(rcStrict != VINF_VMX_VMEXIT);
11003 break;
11004 }
11005
11006 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
11007 return rcStrict;
11008}
11009#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
11010
11011
11012/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
11013 * probes.
11014 *
11015 * The following few functions and associated structure contains the bloat
11016 * necessary for providing detailed debug events and dtrace probes as well as
11017 * reliable host side single stepping. This works on the principle of
11018 * "subclassing" the normal execution loop and workers. We replace the loop
11019 * method completely and override selected helpers to add necessary adjustments
11020 * to their core operation.
11021 *
11022 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
11023 * any performance for debug and analysis features.
11024 *
11025 * @{
11026 */
11027
11028/**
11029 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
11030 * the debug run loop.
11031 */
11032typedef struct VMXRUNDBGSTATE
11033{
11034 /** The RIP we started executing at. This is for detecting that we stepped. */
11035 uint64_t uRipStart;
11036 /** The CS we started executing with. */
11037 uint16_t uCsStart;
11038
11039 /** Whether we've actually modified the 1st execution control field. */
11040 bool fModifiedProcCtls : 1;
11041 /** Whether we've actually modified the 2nd execution control field. */
11042 bool fModifiedProcCtls2 : 1;
11043 /** Whether we've actually modified the exception bitmap. */
11044 bool fModifiedXcptBitmap : 1;
11045
11046 /** We desire the modified the CR0 mask to be cleared. */
11047 bool fClearCr0Mask : 1;
11048 /** We desire the modified the CR4 mask to be cleared. */
11049 bool fClearCr4Mask : 1;
11050 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
11051 uint32_t fCpe1Extra;
11052 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
11053 uint32_t fCpe1Unwanted;
11054 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
11055 uint32_t fCpe2Extra;
11056 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
11057 uint32_t bmXcptExtra;
11058 /** The sequence number of the Dtrace provider settings the state was
11059 * configured against. */
11060 uint32_t uDtraceSettingsSeqNo;
11061 /** VM-exits to check (one bit per VM-exit). */
11062 uint32_t bmExitsToCheck[3];
11063
11064 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
11065 uint32_t fProcCtlsInitial;
11066 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
11067 uint32_t fProcCtls2Initial;
11068 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
11069 uint32_t bmXcptInitial;
11070} VMXRUNDBGSTATE;
11071AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
11072typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
11073
11074
11075/**
11076 * Initializes the VMXRUNDBGSTATE structure.
11077 *
11078 * @param pVCpu The cross context virtual CPU structure of the
11079 * calling EMT.
11080 * @param pVmxTransient The VMX-transient structure.
11081 * @param pDbgState The debug state to initialize.
11082 */
11083static void hmR0VmxRunDebugStateInit(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11084{
11085 pDbgState->uRipStart = pVCpu->cpum.GstCtx.rip;
11086 pDbgState->uCsStart = pVCpu->cpum.GstCtx.cs.Sel;
11087
11088 pDbgState->fModifiedProcCtls = false;
11089 pDbgState->fModifiedProcCtls2 = false;
11090 pDbgState->fModifiedXcptBitmap = false;
11091 pDbgState->fClearCr0Mask = false;
11092 pDbgState->fClearCr4Mask = false;
11093 pDbgState->fCpe1Extra = 0;
11094 pDbgState->fCpe1Unwanted = 0;
11095 pDbgState->fCpe2Extra = 0;
11096 pDbgState->bmXcptExtra = 0;
11097 pDbgState->fProcCtlsInitial = pVmxTransient->pVmcsInfo->u32ProcCtls;
11098 pDbgState->fProcCtls2Initial = pVmxTransient->pVmcsInfo->u32ProcCtls2;
11099 pDbgState->bmXcptInitial = pVmxTransient->pVmcsInfo->u32XcptBitmap;
11100}
11101
11102
11103/**
11104 * Updates the VMSC fields with changes requested by @a pDbgState.
11105 *
11106 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
11107 * immediately before executing guest code, i.e. when interrupts are disabled.
11108 * We don't check status codes here as we cannot easily assert or return in the
11109 * latter case.
11110 *
11111 * @param pVCpu The cross context virtual CPU structure.
11112 * @param pVmxTransient The VMX-transient structure.
11113 * @param pDbgState The debug state.
11114 */
11115static void hmR0VmxPreRunGuestDebugStateApply(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11116{
11117 /*
11118 * Ensure desired flags in VMCS control fields are set.
11119 * (Ignoring write failure here, as we're committed and it's just debug extras.)
11120 *
11121 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
11122 * there should be no stale data in pCtx at this point.
11123 */
11124 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11125 if ( (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
11126 || (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Unwanted))
11127 {
11128 pVmcsInfo->u32ProcCtls |= pDbgState->fCpe1Extra;
11129 pVmcsInfo->u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
11130 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
11131 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVmcsInfo->u32ProcCtls));
11132 pDbgState->fModifiedProcCtls = true;
11133 }
11134
11135 if ((pVmcsInfo->u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
11136 {
11137 pVmcsInfo->u32ProcCtls2 |= pDbgState->fCpe2Extra;
11138 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVmcsInfo->u32ProcCtls2);
11139 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVmcsInfo->u32ProcCtls2));
11140 pDbgState->fModifiedProcCtls2 = true;
11141 }
11142
11143 if ((pVmcsInfo->u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
11144 {
11145 pVmcsInfo->u32XcptBitmap |= pDbgState->bmXcptExtra;
11146 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVmcsInfo->u32XcptBitmap);
11147 Log6Func(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVmcsInfo->u32XcptBitmap));
11148 pDbgState->fModifiedXcptBitmap = true;
11149 }
11150
11151 if (pDbgState->fClearCr0Mask && pVmcsInfo->u64Cr0Mask != 0)
11152 {
11153 pVmcsInfo->u64Cr0Mask = 0;
11154 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, 0);
11155 Log6Func(("VMX_VMCS_CTRL_CR0_MASK: 0\n"));
11156 }
11157
11158 if (pDbgState->fClearCr4Mask && pVmcsInfo->u64Cr4Mask != 0)
11159 {
11160 pVmcsInfo->u64Cr4Mask = 0;
11161 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, 0);
11162 Log6Func(("VMX_VMCS_CTRL_CR4_MASK: 0\n"));
11163 }
11164
11165 NOREF(pVCpu);
11166}
11167
11168
11169/**
11170 * Restores VMCS fields that were changed by hmR0VmxPreRunGuestDebugStateApply for
11171 * re-entry next time around.
11172 *
11173 * @returns Strict VBox status code (i.e. informational status codes too).
11174 * @param pVCpu The cross context virtual CPU structure.
11175 * @param pVmxTransient The VMX-transient structure.
11176 * @param pDbgState The debug state.
11177 * @param rcStrict The return code from executing the guest using single
11178 * stepping.
11179 */
11180static VBOXSTRICTRC hmR0VmxRunDebugStateRevert(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState,
11181 VBOXSTRICTRC rcStrict)
11182{
11183 /*
11184 * Restore VM-exit control settings as we may not reenter this function the
11185 * next time around.
11186 */
11187 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11188
11189 /* We reload the initial value, trigger what we can of recalculations the
11190 next time around. From the looks of things, that's all that's required atm. */
11191 if (pDbgState->fModifiedProcCtls)
11192 {
11193 if (!(pDbgState->fProcCtlsInitial & VMX_PROC_CTLS_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
11194 pDbgState->fProcCtlsInitial |= VMX_PROC_CTLS_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
11195 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
11196 AssertRC(rc2);
11197 pVmcsInfo->u32ProcCtls = pDbgState->fProcCtlsInitial;
11198 }
11199
11200 /* We're currently the only ones messing with this one, so just restore the
11201 cached value and reload the field. */
11202 if ( pDbgState->fModifiedProcCtls2
11203 && pVmcsInfo->u32ProcCtls2 != pDbgState->fProcCtls2Initial)
11204 {
11205 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
11206 AssertRC(rc2);
11207 pVmcsInfo->u32ProcCtls2 = pDbgState->fProcCtls2Initial;
11208 }
11209
11210 /* If we've modified the exception bitmap, we restore it and trigger
11211 reloading and partial recalculation the next time around. */
11212 if (pDbgState->fModifiedXcptBitmap)
11213 pVmcsInfo->u32XcptBitmap = pDbgState->bmXcptInitial;
11214
11215 return rcStrict;
11216}
11217
11218
11219/**
11220 * Configures VM-exit controls for current DBGF and DTrace settings.
11221 *
11222 * This updates @a pDbgState and the VMCS execution control fields to reflect
11223 * the necessary VM-exits demanded by DBGF and DTrace.
11224 *
11225 * @param pVCpu The cross context virtual CPU structure.
11226 * @param pVmxTransient The VMX-transient structure. May update
11227 * fUpdatedTscOffsettingAndPreemptTimer.
11228 * @param pDbgState The debug state.
11229 */
11230static void hmR0VmxPreRunGuestDebugStateUpdate(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11231{
11232 /*
11233 * Take down the dtrace serial number so we can spot changes.
11234 */
11235 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
11236 ASMCompilerBarrier();
11237
11238 /*
11239 * We'll rebuild most of the middle block of data members (holding the
11240 * current settings) as we go along here, so start by clearing it all.
11241 */
11242 pDbgState->bmXcptExtra = 0;
11243 pDbgState->fCpe1Extra = 0;
11244 pDbgState->fCpe1Unwanted = 0;
11245 pDbgState->fCpe2Extra = 0;
11246 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
11247 pDbgState->bmExitsToCheck[i] = 0;
11248
11249 /*
11250 * Software interrupts (INT XXh) - no idea how to trigger these...
11251 */
11252 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11253 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
11254 || VBOXVMM_INT_SOFTWARE_ENABLED())
11255 {
11256 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11257 }
11258
11259 /*
11260 * INT3 breakpoints - triggered by #BP exceptions.
11261 */
11262 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
11263 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11264
11265 /*
11266 * Exception bitmap and XCPT events+probes.
11267 */
11268 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
11269 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
11270 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
11271
11272 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
11273 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
11274 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11275 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
11276 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
11277 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
11278 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
11279 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
11280 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
11281 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
11282 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
11283 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
11284 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
11285 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
11286 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
11287 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
11288 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
11289 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
11290
11291 if (pDbgState->bmXcptExtra)
11292 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11293
11294 /*
11295 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
11296 *
11297 * Note! This is the reverse of what hmR0VmxHandleExitDtraceEvents does.
11298 * So, when adding/changing/removing please don't forget to update it.
11299 *
11300 * Some of the macros are picking up local variables to save horizontal space,
11301 * (being able to see it in a table is the lesser evil here).
11302 */
11303#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
11304 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
11305 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
11306#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
11307 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11308 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11309 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11310 } else do { } while (0)
11311#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
11312 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11313 { \
11314 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
11315 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11316 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11317 } else do { } while (0)
11318#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
11319 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11320 { \
11321 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
11322 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11323 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11324 } else do { } while (0)
11325#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
11326 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11327 { \
11328 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
11329 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11330 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11331 } else do { } while (0)
11332
11333 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
11334 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
11335 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
11336 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
11337 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
11338
11339 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
11340 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
11341 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
11342 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
11343 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_PROC_CTLS_HLT_EXIT); /* paranoia */
11344 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
11345 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
11346 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
11347 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_PROC_CTLS_INVLPG_EXIT);
11348 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
11349 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_PROC_CTLS_RDPMC_EXIT);
11350 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
11351 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_PROC_CTLS_RDTSC_EXIT);
11352 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
11353 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
11354 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
11355 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
11356 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
11357 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
11358 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
11359 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
11360 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
11361 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
11362 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
11363 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
11364 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
11365 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
11366 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
11367 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
11368 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
11369 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
11370 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
11371 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
11372 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
11373 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
11374 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
11375
11376 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
11377 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11378 {
11379 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4
11380 | CPUMCTX_EXTRN_APIC_TPR);
11381 AssertRC(rc);
11382
11383#if 0 /** @todo fix me */
11384 pDbgState->fClearCr0Mask = true;
11385 pDbgState->fClearCr4Mask = true;
11386#endif
11387 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
11388 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_STORE_EXIT | VMX_PROC_CTLS_CR8_STORE_EXIT;
11389 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11390 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_LOAD_EXIT | VMX_PROC_CTLS_CR8_LOAD_EXIT;
11391 pDbgState->fCpe1Unwanted |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* risky? */
11392 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
11393 require clearing here and in the loop if we start using it. */
11394 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
11395 }
11396 else
11397 {
11398 if (pDbgState->fClearCr0Mask)
11399 {
11400 pDbgState->fClearCr0Mask = false;
11401 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR0);
11402 }
11403 if (pDbgState->fClearCr4Mask)
11404 {
11405 pDbgState->fClearCr4Mask = false;
11406 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR4);
11407 }
11408 }
11409 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
11410 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
11411
11412 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
11413 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
11414 {
11415 /** @todo later, need to fix handler as it assumes this won't usually happen. */
11416 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
11417 }
11418 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
11419 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
11420
11421 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS); /* risky clearing this? */
11422 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
11423 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS);
11424 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
11425 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_PROC_CTLS_MWAIT_EXIT); /* paranoia */
11426 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
11427 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_PROC_CTLS_MONITOR_EXIT); /* paranoia */
11428 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
11429#if 0 /** @todo too slow, fix handler. */
11430 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_PROC_CTLS_PAUSE_EXIT);
11431#endif
11432 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
11433
11434 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
11435 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
11436 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
11437 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
11438 {
11439 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11440 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_GDTR_IDTR_ACCESS);
11441 }
11442 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11443 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11444 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11445 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11446
11447 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
11448 || IS_EITHER_ENABLED(pVM, INSTR_STR)
11449 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
11450 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
11451 {
11452 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11453 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_LDTR_TR_ACCESS);
11454 }
11455 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_LDTR_TR_ACCESS);
11456 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_LDTR_TR_ACCESS);
11457 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_LDTR_TR_ACCESS);
11458 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_LDTR_TR_ACCESS);
11459
11460 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
11461 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
11462 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_PROC_CTLS_RDTSC_EXIT);
11463 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
11464 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
11465 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
11466 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_PROC_CTLS2_WBINVD_EXIT);
11467 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
11468 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
11469 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
11470 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_PROC_CTLS2_RDRAND_EXIT);
11471 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
11472 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_PROC_CTLS_INVLPG_EXIT);
11473 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
11474 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
11475 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
11476 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_PROC_CTLS2_RDSEED_EXIT);
11477 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
11478 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
11479 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
11480 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
11481 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
11482
11483#undef IS_EITHER_ENABLED
11484#undef SET_ONLY_XBM_IF_EITHER_EN
11485#undef SET_CPE1_XBM_IF_EITHER_EN
11486#undef SET_CPEU_XBM_IF_EITHER_EN
11487#undef SET_CPE2_XBM_IF_EITHER_EN
11488
11489 /*
11490 * Sanitize the control stuff.
11491 */
11492 pDbgState->fCpe2Extra &= pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1;
11493 if (pDbgState->fCpe2Extra)
11494 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
11495 pDbgState->fCpe1Extra &= pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1;
11496 pDbgState->fCpe1Unwanted &= ~pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0;
11497 if (pVCpu->hm.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_PROC_CTLS_RDTSC_EXIT))
11498 {
11499 pVCpu->hm.s.fDebugWantRdTscExit ^= true;
11500 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
11501 }
11502
11503 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
11504 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
11505 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
11506 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
11507}
11508
11509
11510/**
11511 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
11512 * appropriate.
11513 *
11514 * The caller has checked the VM-exit against the
11515 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
11516 * already, so we don't have to do that either.
11517 *
11518 * @returns Strict VBox status code (i.e. informational status codes too).
11519 * @param pVCpu The cross context virtual CPU structure.
11520 * @param pVmxTransient The VMX-transient structure.
11521 * @param uExitReason The VM-exit reason.
11522 *
11523 * @remarks The name of this function is displayed by dtrace, so keep it short
11524 * and to the point. No longer than 33 chars long, please.
11525 */
11526static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
11527{
11528 /*
11529 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
11530 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
11531 *
11532 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
11533 * does. Must add/change/remove both places. Same ordering, please.
11534 *
11535 * Added/removed events must also be reflected in the next section
11536 * where we dispatch dtrace events.
11537 */
11538 bool fDtrace1 = false;
11539 bool fDtrace2 = false;
11540 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
11541 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
11542 uint32_t uEventArg = 0;
11543#define SET_EXIT(a_EventSubName) \
11544 do { \
11545 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11546 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11547 } while (0)
11548#define SET_BOTH(a_EventSubName) \
11549 do { \
11550 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
11551 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11552 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
11553 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11554 } while (0)
11555 switch (uExitReason)
11556 {
11557 case VMX_EXIT_MTF:
11558 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
11559
11560 case VMX_EXIT_XCPT_OR_NMI:
11561 {
11562 uint8_t const idxVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
11563 switch (VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo))
11564 {
11565 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
11566 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
11567 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
11568 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
11569 {
11570 if (VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uExitIntInfo))
11571 {
11572 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
11573 uEventArg = pVmxTransient->uExitIntErrorCode;
11574 }
11575 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
11576 switch (enmEvent1)
11577 {
11578 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
11579 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
11580 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
11581 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
11582 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
11583 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
11584 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
11585 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
11586 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
11587 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
11588 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
11589 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
11590 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
11591 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
11592 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
11593 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
11594 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
11595 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
11596 default: break;
11597 }
11598 }
11599 else
11600 AssertFailed();
11601 break;
11602
11603 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
11604 uEventArg = idxVector;
11605 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
11606 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
11607 break;
11608 }
11609 break;
11610 }
11611
11612 case VMX_EXIT_TRIPLE_FAULT:
11613 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
11614 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
11615 break;
11616 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
11617 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
11618 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
11619 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
11620 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
11621
11622 /* Instruction specific VM-exits: */
11623 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
11624 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
11625 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
11626 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
11627 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
11628 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
11629 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
11630 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
11631 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
11632 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
11633 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
11634 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
11635 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
11636 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
11637 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
11638 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
11639 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
11640 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
11641 case VMX_EXIT_MOV_CRX:
11642 hmR0VmxReadExitQualVmcs(pVmxTransient);
11643 if (VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_CRX_ACCESS_READ)
11644 SET_BOTH(CRX_READ);
11645 else
11646 SET_BOTH(CRX_WRITE);
11647 uEventArg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
11648 break;
11649 case VMX_EXIT_MOV_DRX:
11650 hmR0VmxReadExitQualVmcs(pVmxTransient);
11651 if ( VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual)
11652 == VMX_EXIT_QUAL_DRX_DIRECTION_READ)
11653 SET_BOTH(DRX_READ);
11654 else
11655 SET_BOTH(DRX_WRITE);
11656 uEventArg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
11657 break;
11658 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
11659 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
11660 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
11661 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
11662 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
11663 case VMX_EXIT_GDTR_IDTR_ACCESS:
11664 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
11665 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_XDTR_INSINFO_INSTR_ID))
11666 {
11667 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
11668 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
11669 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
11670 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
11671 }
11672 break;
11673
11674 case VMX_EXIT_LDTR_TR_ACCESS:
11675 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
11676 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_YYTR_INSINFO_INSTR_ID))
11677 {
11678 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
11679 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
11680 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
11681 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
11682 }
11683 break;
11684
11685 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
11686 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
11687 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
11688 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
11689 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
11690 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
11691 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
11692 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
11693 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
11694 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
11695 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
11696
11697 /* Events that aren't relevant at this point. */
11698 case VMX_EXIT_EXT_INT:
11699 case VMX_EXIT_INT_WINDOW:
11700 case VMX_EXIT_NMI_WINDOW:
11701 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11702 case VMX_EXIT_PREEMPT_TIMER:
11703 case VMX_EXIT_IO_INSTR:
11704 break;
11705
11706 /* Errors and unexpected events. */
11707 case VMX_EXIT_INIT_SIGNAL:
11708 case VMX_EXIT_SIPI:
11709 case VMX_EXIT_IO_SMI:
11710 case VMX_EXIT_SMI:
11711 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
11712 case VMX_EXIT_ERR_MSR_LOAD:
11713 case VMX_EXIT_ERR_MACHINE_CHECK:
11714 case VMX_EXIT_PML_FULL:
11715 case VMX_EXIT_VIRTUALIZED_EOI:
11716 break;
11717
11718 default:
11719 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
11720 break;
11721 }
11722#undef SET_BOTH
11723#undef SET_EXIT
11724
11725 /*
11726 * Dtrace tracepoints go first. We do them here at once so we don't
11727 * have to copy the guest state saving and stuff a few dozen times.
11728 * Down side is that we've got to repeat the switch, though this time
11729 * we use enmEvent since the probes are a subset of what DBGF does.
11730 */
11731 if (fDtrace1 || fDtrace2)
11732 {
11733 hmR0VmxReadExitQualVmcs(pVmxTransient);
11734 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
11735 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
11736 switch (enmEvent1)
11737 {
11738 /** @todo consider which extra parameters would be helpful for each probe. */
11739 case DBGFEVENT_END: break;
11740 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pCtx); break;
11741 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pCtx, pCtx->dr[6]); break;
11742 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pCtx); break;
11743 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pCtx); break;
11744 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pCtx); break;
11745 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pCtx); break;
11746 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pCtx); break;
11747 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pCtx); break;
11748 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pCtx, uEventArg); break;
11749 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pCtx, uEventArg); break;
11750 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pCtx, uEventArg); break;
11751 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pCtx, uEventArg); break;
11752 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pCtx, uEventArg, pCtx->cr2); break;
11753 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pCtx); break;
11754 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pCtx); break;
11755 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pCtx); break;
11756 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pCtx); break;
11757 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pCtx, uEventArg); break;
11758 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11759 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11760 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pCtx); break;
11761 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pCtx); break;
11762 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pCtx); break;
11763 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pCtx); break;
11764 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pCtx); break;
11765 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pCtx); break;
11766 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pCtx); break;
11767 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11768 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11769 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11770 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11771 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11772 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pCtx, pCtx->ecx,
11773 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11774 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pCtx); break;
11775 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pCtx); break;
11776 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pCtx); break;
11777 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pCtx); break;
11778 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pCtx); break;
11779 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pCtx); break;
11780 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pCtx); break;
11781 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pCtx); break;
11782 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pCtx); break;
11783 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pCtx); break;
11784 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pCtx); break;
11785 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pCtx); break;
11786 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pCtx); break;
11787 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pCtx); break;
11788 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pCtx); break;
11789 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pCtx); break;
11790 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pCtx); break;
11791 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pCtx); break;
11792 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pCtx); break;
11793 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pCtx); break;
11794 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pCtx); break;
11795 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pCtx); break;
11796 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pCtx); break;
11797 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pCtx); break;
11798 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pCtx); break;
11799 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pCtx); break;
11800 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pCtx); break;
11801 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pCtx); break;
11802 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pCtx); break;
11803 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pCtx); break;
11804 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pCtx); break;
11805 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pCtx); break;
11806 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
11807 }
11808 switch (enmEvent2)
11809 {
11810 /** @todo consider which extra parameters would be helpful for each probe. */
11811 case DBGFEVENT_END: break;
11812 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pCtx); break;
11813 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11814 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pCtx); break;
11815 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pCtx); break;
11816 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pCtx); break;
11817 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pCtx); break;
11818 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pCtx); break;
11819 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pCtx); break;
11820 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pCtx); break;
11821 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11822 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11823 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11824 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11825 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11826 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pCtx, pCtx->ecx,
11827 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11828 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pCtx); break;
11829 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pCtx); break;
11830 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pCtx); break;
11831 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pCtx); break;
11832 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pCtx); break;
11833 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pCtx); break;
11834 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pCtx); break;
11835 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pCtx); break;
11836 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pCtx); break;
11837 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pCtx); break;
11838 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pCtx); break;
11839 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pCtx); break;
11840 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pCtx); break;
11841 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pCtx); break;
11842 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pCtx); break;
11843 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pCtx); break;
11844 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pCtx); break;
11845 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pCtx); break;
11846 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pCtx); break;
11847 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pCtx); break;
11848 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pCtx); break;
11849 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pCtx); break;
11850 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pCtx); break;
11851 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pCtx); break;
11852 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pCtx); break;
11853 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pCtx); break;
11854 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pCtx); break;
11855 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pCtx); break;
11856 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pCtx); break;
11857 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pCtx); break;
11858 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pCtx); break;
11859 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pCtx); break;
11860 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pCtx); break;
11861 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pCtx); break;
11862 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pCtx); break;
11863 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pCtx); break;
11864 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
11865 }
11866 }
11867
11868 /*
11869 * Fire of the DBGF event, if enabled (our check here is just a quick one,
11870 * the DBGF call will do a full check).
11871 *
11872 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
11873 * Note! If we have to events, we prioritize the first, i.e. the instruction
11874 * one, in order to avoid event nesting.
11875 */
11876 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11877 if ( enmEvent1 != DBGFEVENT_END
11878 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
11879 {
11880 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11881 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent1, DBGFEVENTCTX_HM, 1, uEventArg);
11882 if (rcStrict != VINF_SUCCESS)
11883 return rcStrict;
11884 }
11885 else if ( enmEvent2 != DBGFEVENT_END
11886 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
11887 {
11888 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11889 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent2, DBGFEVENTCTX_HM, 1, uEventArg);
11890 if (rcStrict != VINF_SUCCESS)
11891 return rcStrict;
11892 }
11893
11894 return VINF_SUCCESS;
11895}
11896
11897
11898/**
11899 * Single-stepping VM-exit filtering.
11900 *
11901 * This is preprocessing the VM-exits and deciding whether we've gotten far
11902 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
11903 * handling is performed.
11904 *
11905 * @returns Strict VBox status code (i.e. informational status codes too).
11906 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
11907 * @param pVmxTransient The VMX-transient structure.
11908 * @param pDbgState The debug state.
11909 */
11910DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11911{
11912 /*
11913 * Expensive (saves context) generic dtrace VM-exit probe.
11914 */
11915 uint32_t const uExitReason = pVmxTransient->uExitReason;
11916 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
11917 { /* more likely */ }
11918 else
11919 {
11920 hmR0VmxReadExitQualVmcs(pVmxTransient);
11921 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
11922 AssertRC(rc);
11923 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, &pVCpu->cpum.GstCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
11924 }
11925
11926 /*
11927 * Check for host NMI, just to get that out of the way.
11928 */
11929 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
11930 { /* normally likely */ }
11931 else
11932 {
11933 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
11934 uint32_t const uIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
11935 if (uIntType == VMX_EXIT_INT_INFO_TYPE_NMI)
11936 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
11937 }
11938
11939 /*
11940 * Check for single stepping event if we're stepping.
11941 */
11942 if (pVCpu->hm.s.fSingleInstruction)
11943 {
11944 switch (uExitReason)
11945 {
11946 case VMX_EXIT_MTF:
11947 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
11948
11949 /* Various events: */
11950 case VMX_EXIT_XCPT_OR_NMI:
11951 case VMX_EXIT_EXT_INT:
11952 case VMX_EXIT_TRIPLE_FAULT:
11953 case VMX_EXIT_INT_WINDOW:
11954 case VMX_EXIT_NMI_WINDOW:
11955 case VMX_EXIT_TASK_SWITCH:
11956 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11957 case VMX_EXIT_APIC_ACCESS:
11958 case VMX_EXIT_EPT_VIOLATION:
11959 case VMX_EXIT_EPT_MISCONFIG:
11960 case VMX_EXIT_PREEMPT_TIMER:
11961
11962 /* Instruction specific VM-exits: */
11963 case VMX_EXIT_CPUID:
11964 case VMX_EXIT_GETSEC:
11965 case VMX_EXIT_HLT:
11966 case VMX_EXIT_INVD:
11967 case VMX_EXIT_INVLPG:
11968 case VMX_EXIT_RDPMC:
11969 case VMX_EXIT_RDTSC:
11970 case VMX_EXIT_RSM:
11971 case VMX_EXIT_VMCALL:
11972 case VMX_EXIT_VMCLEAR:
11973 case VMX_EXIT_VMLAUNCH:
11974 case VMX_EXIT_VMPTRLD:
11975 case VMX_EXIT_VMPTRST:
11976 case VMX_EXIT_VMREAD:
11977 case VMX_EXIT_VMRESUME:
11978 case VMX_EXIT_VMWRITE:
11979 case VMX_EXIT_VMXOFF:
11980 case VMX_EXIT_VMXON:
11981 case VMX_EXIT_MOV_CRX:
11982 case VMX_EXIT_MOV_DRX:
11983 case VMX_EXIT_IO_INSTR:
11984 case VMX_EXIT_RDMSR:
11985 case VMX_EXIT_WRMSR:
11986 case VMX_EXIT_MWAIT:
11987 case VMX_EXIT_MONITOR:
11988 case VMX_EXIT_PAUSE:
11989 case VMX_EXIT_GDTR_IDTR_ACCESS:
11990 case VMX_EXIT_LDTR_TR_ACCESS:
11991 case VMX_EXIT_INVEPT:
11992 case VMX_EXIT_RDTSCP:
11993 case VMX_EXIT_INVVPID:
11994 case VMX_EXIT_WBINVD:
11995 case VMX_EXIT_XSETBV:
11996 case VMX_EXIT_RDRAND:
11997 case VMX_EXIT_INVPCID:
11998 case VMX_EXIT_VMFUNC:
11999 case VMX_EXIT_RDSEED:
12000 case VMX_EXIT_XSAVES:
12001 case VMX_EXIT_XRSTORS:
12002 {
12003 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12004 AssertRCReturn(rc, rc);
12005 if ( pVCpu->cpum.GstCtx.rip != pDbgState->uRipStart
12006 || pVCpu->cpum.GstCtx.cs.Sel != pDbgState->uCsStart)
12007 return VINF_EM_DBG_STEPPED;
12008 break;
12009 }
12010
12011 /* Errors and unexpected events: */
12012 case VMX_EXIT_INIT_SIGNAL:
12013 case VMX_EXIT_SIPI:
12014 case VMX_EXIT_IO_SMI:
12015 case VMX_EXIT_SMI:
12016 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
12017 case VMX_EXIT_ERR_MSR_LOAD:
12018 case VMX_EXIT_ERR_MACHINE_CHECK:
12019 case VMX_EXIT_PML_FULL:
12020 case VMX_EXIT_VIRTUALIZED_EOI:
12021 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
12022 break;
12023
12024 default:
12025 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12026 break;
12027 }
12028 }
12029
12030 /*
12031 * Check for debugger event breakpoints and dtrace probes.
12032 */
12033 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
12034 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
12035 {
12036 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVCpu, pVmxTransient, uExitReason);
12037 if (rcStrict != VINF_SUCCESS)
12038 return rcStrict;
12039 }
12040
12041 /*
12042 * Normal processing.
12043 */
12044#ifdef HMVMX_USE_FUNCTION_TABLE
12045 return g_apfnVMExitHandlers[uExitReason](pVCpu, pVmxTransient);
12046#else
12047 return hmR0VmxHandleExit(pVCpu, pVmxTransient, uExitReason);
12048#endif
12049}
12050
12051
12052/**
12053 * Single steps guest code using hardware-assisted VMX.
12054 *
12055 * This is -not- the same as the guest single-stepping itself (say using EFLAGS.TF)
12056 * but single-stepping through the hypervisor debugger.
12057 *
12058 * @returns Strict VBox status code (i.e. informational status codes too).
12059 * @param pVCpu The cross context virtual CPU structure.
12060 * @param pcLoops Pointer to the number of executed loops.
12061 *
12062 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
12063 */
12064static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVMCPUCC pVCpu, uint32_t *pcLoops)
12065{
12066 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
12067 Assert(pcLoops);
12068 Assert(*pcLoops <= cMaxResumeLoops);
12069
12070 VMXTRANSIENT VmxTransient;
12071 RT_ZERO(VmxTransient);
12072 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
12073
12074 /* Set HMCPU indicators. */
12075 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
12076 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
12077 pVCpu->hm.s.fDebugWantRdTscExit = false;
12078 pVCpu->hm.s.fUsingDebugLoop = true;
12079
12080 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
12081 VMXRUNDBGSTATE DbgState;
12082 hmR0VmxRunDebugStateInit(pVCpu, &VmxTransient, &DbgState);
12083 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12084
12085 /*
12086 * The loop.
12087 */
12088 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
12089 for (;;)
12090 {
12091 Assert(!HMR0SuspendPending());
12092 HMVMX_ASSERT_CPU_SAFE(pVCpu);
12093 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
12094 bool fStepping = pVCpu->hm.s.fSingleInstruction;
12095
12096 /* Set up VM-execution controls the next two can respond to. */
12097 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12098
12099 /*
12100 * Preparatory work for running guest code, this may force us to
12101 * return to ring-3.
12102 *
12103 * Warning! This bugger disables interrupts on VINF_SUCCESS!
12104 */
12105 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, fStepping);
12106 if (rcStrict != VINF_SUCCESS)
12107 break;
12108
12109 /* Interrupts are disabled at this point! */
12110 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
12111
12112 /* Override any obnoxious code in the above two calls. */
12113 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12114
12115 /*
12116 * Finally execute the guest.
12117 */
12118 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
12119
12120 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
12121 /* Interrupts are re-enabled at this point! */
12122
12123 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
12124 if (RT_SUCCESS(rcRun))
12125 { /* very likely */ }
12126 else
12127 {
12128 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
12129 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
12130 return rcRun;
12131 }
12132
12133 /* Profile the VM-exit. */
12134 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
12135 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
12136 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
12137 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
12138 HMVMX_START_EXIT_DISPATCH_PROF();
12139
12140 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
12141
12142 /*
12143 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
12144 */
12145 rcStrict = hmR0VmxRunDebugHandleExit(pVCpu, &VmxTransient, &DbgState);
12146 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
12147 if (rcStrict != VINF_SUCCESS)
12148 break;
12149 if (++(*pcLoops) > cMaxResumeLoops)
12150 {
12151 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
12152 rcStrict = VINF_EM_RAW_INTERRUPT;
12153 break;
12154 }
12155
12156 /*
12157 * Stepping: Did the RIP change, if so, consider it a single step.
12158 * Otherwise, make sure one of the TFs gets set.
12159 */
12160 if (fStepping)
12161 {
12162 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12163 AssertRC(rc);
12164 if ( pVCpu->cpum.GstCtx.rip != DbgState.uRipStart
12165 || pVCpu->cpum.GstCtx.cs.Sel != DbgState.uCsStart)
12166 {
12167 rcStrict = VINF_EM_DBG_STEPPED;
12168 break;
12169 }
12170 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
12171 }
12172
12173 /*
12174 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
12175 */
12176 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
12177 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12178 }
12179
12180 /*
12181 * Clear the X86_EFL_TF if necessary.
12182 */
12183 if (pVCpu->hm.s.fClearTrapFlag)
12184 {
12185 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
12186 AssertRC(rc);
12187 pVCpu->hm.s.fClearTrapFlag = false;
12188 pVCpu->cpum.GstCtx.eflags.Bits.u1TF = 0;
12189 }
12190 /** @todo there seems to be issues with the resume flag when the monitor trap
12191 * flag is pending without being used. Seen early in bios init when
12192 * accessing APIC page in protected mode. */
12193
12194 /*
12195 * Restore VM-exit control settings as we may not re-enter this function the
12196 * next time around.
12197 */
12198 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &VmxTransient, &DbgState, rcStrict);
12199
12200 /* Restore HMCPU indicators. */
12201 pVCpu->hm.s.fUsingDebugLoop = false;
12202 pVCpu->hm.s.fDebugWantRdTscExit = false;
12203 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
12204
12205 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
12206 return rcStrict;
12207}
12208
12209
12210/** @} */
12211
12212
12213/**
12214 * Checks if any expensive dtrace probes are enabled and we should go to the
12215 * debug loop.
12216 *
12217 * @returns true if we should use debug loop, false if not.
12218 */
12219static bool hmR0VmxAnyExpensiveProbesEnabled(void)
12220{
12221 /* It's probably faster to OR the raw 32-bit counter variables together.
12222 Since the variables are in an array and the probes are next to one
12223 another (more or less), we have good locality. So, better read
12224 eight-nine cache lines ever time and only have one conditional, than
12225 128+ conditionals, right? */
12226 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
12227 | VBOXVMM_XCPT_DE_ENABLED_RAW()
12228 | VBOXVMM_XCPT_DB_ENABLED_RAW()
12229 | VBOXVMM_XCPT_BP_ENABLED_RAW()
12230 | VBOXVMM_XCPT_OF_ENABLED_RAW()
12231 | VBOXVMM_XCPT_BR_ENABLED_RAW()
12232 | VBOXVMM_XCPT_UD_ENABLED_RAW()
12233 | VBOXVMM_XCPT_NM_ENABLED_RAW()
12234 | VBOXVMM_XCPT_DF_ENABLED_RAW()
12235 | VBOXVMM_XCPT_TS_ENABLED_RAW()
12236 | VBOXVMM_XCPT_NP_ENABLED_RAW()
12237 | VBOXVMM_XCPT_SS_ENABLED_RAW()
12238 | VBOXVMM_XCPT_GP_ENABLED_RAW()
12239 | VBOXVMM_XCPT_PF_ENABLED_RAW()
12240 | VBOXVMM_XCPT_MF_ENABLED_RAW()
12241 | VBOXVMM_XCPT_AC_ENABLED_RAW()
12242 | VBOXVMM_XCPT_XF_ENABLED_RAW()
12243 | VBOXVMM_XCPT_VE_ENABLED_RAW()
12244 | VBOXVMM_XCPT_SX_ENABLED_RAW()
12245 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
12246 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
12247 ) != 0
12248 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
12249 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
12250 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
12251 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
12252 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
12253 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
12254 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
12255 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
12256 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
12257 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
12258 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
12259 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
12260 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
12261 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
12262 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
12263 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
12264 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
12265 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
12266 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
12267 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
12268 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
12269 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
12270 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
12271 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
12272 | VBOXVMM_INSTR_STR_ENABLED_RAW()
12273 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
12274 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
12275 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
12276 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
12277 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
12278 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
12279 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
12280 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
12281 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
12282 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
12283 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
12284 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
12285 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
12286 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
12287 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
12288 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
12289 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
12290 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
12291 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
12292 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
12293 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
12294 ) != 0
12295 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
12296 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
12297 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
12298 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
12299 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
12300 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
12301 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
12302 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
12303 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
12304 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
12305 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
12306 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
12307 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
12308 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
12309 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
12310 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
12311 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
12312 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
12313 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
12314 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
12315 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
12316 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
12317 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
12318 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
12319 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
12320 | VBOXVMM_EXIT_STR_ENABLED_RAW()
12321 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
12322 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
12323 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
12324 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
12325 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
12326 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
12327 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
12328 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
12329 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
12330 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
12331 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
12332 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
12333 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
12334 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
12335 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
12336 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
12337 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
12338 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
12339 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
12340 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
12341 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
12342 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
12343 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
12344 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
12345 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
12346 ) != 0;
12347}
12348
12349
12350/**
12351 * Runs the guest using hardware-assisted VMX.
12352 *
12353 * @returns Strict VBox status code (i.e. informational status codes too).
12354 * @param pVCpu The cross context virtual CPU structure.
12355 */
12356VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVMCPUCC pVCpu)
12357{
12358 AssertPtr(pVCpu);
12359 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12360 Assert(VMMRZCallRing3IsEnabled(pVCpu));
12361 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12362 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
12363
12364 VMMRZCallRing3SetNotification(pVCpu, hmR0VmxCallRing3Callback, pCtx);
12365
12366 VBOXSTRICTRC rcStrict;
12367 uint32_t cLoops = 0;
12368 for (;;)
12369 {
12370#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12371 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(pCtx);
12372#else
12373 bool const fInNestedGuestMode = false;
12374#endif
12375 if (!fInNestedGuestMode)
12376 {
12377 if ( !pVCpu->hm.s.fUseDebugLoop
12378 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
12379 && !DBGFIsStepping(pVCpu)
12380 && !pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
12381 rcStrict = hmR0VmxRunGuestCodeNormal(pVCpu, &cLoops);
12382 else
12383 rcStrict = hmR0VmxRunGuestCodeDebug(pVCpu, &cLoops);
12384 }
12385#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12386 else
12387 rcStrict = hmR0VmxRunGuestCodeNested(pVCpu, &cLoops);
12388
12389 if (rcStrict == VINF_VMX_VMLAUNCH_VMRESUME)
12390 {
12391 Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
12392 continue;
12393 }
12394 if (rcStrict == VINF_VMX_VMEXIT)
12395 {
12396 Assert(!CPUMIsGuestInVmxNonRootMode(pCtx));
12397 continue;
12398 }
12399#endif
12400 break;
12401 }
12402
12403 int const rcLoop = VBOXSTRICTRC_VAL(rcStrict);
12404 switch (rcLoop)
12405 {
12406 case VERR_EM_INTERPRETER: rcStrict = VINF_EM_RAW_EMULATE_INSTR; break;
12407 case VINF_EM_RESET: rcStrict = VINF_EM_TRIPLE_FAULT; break;
12408 }
12409
12410 int rc2 = hmR0VmxExitToRing3(pVCpu, rcStrict);
12411 if (RT_FAILURE(rc2))
12412 {
12413 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
12414 rcStrict = rc2;
12415 }
12416 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12417 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
12418 return rcStrict;
12419}
12420
12421
12422#ifndef HMVMX_USE_FUNCTION_TABLE
12423/**
12424 * Handles a guest VM-exit from hardware-assisted VMX execution.
12425 *
12426 * @returns Strict VBox status code (i.e. informational status codes too).
12427 * @param pVCpu The cross context virtual CPU structure.
12428 * @param pVmxTransient The VMX-transient structure.
12429 */
12430DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12431{
12432#ifdef DEBUG_ramshankar
12433# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) \
12434 do { \
12435 if (a_fSave != 0) \
12436 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL); \
12437 VBOXSTRICTRC rcStrict = a_CallExpr; \
12438 if (a_fSave != 0) \
12439 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST); \
12440 return rcStrict; \
12441 } while (0)
12442#else
12443# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) return a_CallExpr
12444#endif
12445 uint32_t const uExitReason = pVmxTransient->uExitReason;
12446 switch (uExitReason)
12447 {
12448 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient));
12449 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, hmR0VmxExitEptViolation(pVCpu, pVmxTransient));
12450 case VMX_EXIT_IO_INSTR: VMEXIT_CALL_RET(0, hmR0VmxExitIoInstr(pVCpu, pVmxTransient));
12451 case VMX_EXIT_CPUID: VMEXIT_CALL_RET(0, hmR0VmxExitCpuid(pVCpu, pVmxTransient));
12452 case VMX_EXIT_RDTSC: VMEXIT_CALL_RET(0, hmR0VmxExitRdtsc(pVCpu, pVmxTransient));
12453 case VMX_EXIT_RDTSCP: VMEXIT_CALL_RET(0, hmR0VmxExitRdtscp(pVCpu, pVmxTransient));
12454 case VMX_EXIT_APIC_ACCESS: VMEXIT_CALL_RET(0, hmR0VmxExitApicAccess(pVCpu, pVmxTransient));
12455 case VMX_EXIT_XCPT_OR_NMI: VMEXIT_CALL_RET(0, hmR0VmxExitXcptOrNmi(pVCpu, pVmxTransient));
12456 case VMX_EXIT_MOV_CRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovCRx(pVCpu, pVmxTransient));
12457 case VMX_EXIT_EXT_INT: VMEXIT_CALL_RET(0, hmR0VmxExitExtInt(pVCpu, pVmxTransient));
12458 case VMX_EXIT_INT_WINDOW: VMEXIT_CALL_RET(0, hmR0VmxExitIntWindow(pVCpu, pVmxTransient));
12459 case VMX_EXIT_TPR_BELOW_THRESHOLD: VMEXIT_CALL_RET(0, hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient));
12460 case VMX_EXIT_MWAIT: VMEXIT_CALL_RET(0, hmR0VmxExitMwait(pVCpu, pVmxTransient));
12461 case VMX_EXIT_MONITOR: VMEXIT_CALL_RET(0, hmR0VmxExitMonitor(pVCpu, pVmxTransient));
12462 case VMX_EXIT_TASK_SWITCH: VMEXIT_CALL_RET(0, hmR0VmxExitTaskSwitch(pVCpu, pVmxTransient));
12463 case VMX_EXIT_PREEMPT_TIMER: VMEXIT_CALL_RET(0, hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient));
12464 case VMX_EXIT_RDMSR: VMEXIT_CALL_RET(0, hmR0VmxExitRdmsr(pVCpu, pVmxTransient));
12465 case VMX_EXIT_WRMSR: VMEXIT_CALL_RET(0, hmR0VmxExitWrmsr(pVCpu, pVmxTransient));
12466 case VMX_EXIT_VMCALL: VMEXIT_CALL_RET(0, hmR0VmxExitVmcall(pVCpu, pVmxTransient));
12467 case VMX_EXIT_MOV_DRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovDRx(pVCpu, pVmxTransient));
12468 case VMX_EXIT_HLT: VMEXIT_CALL_RET(0, hmR0VmxExitHlt(pVCpu, pVmxTransient));
12469 case VMX_EXIT_INVD: VMEXIT_CALL_RET(0, hmR0VmxExitInvd(pVCpu, pVmxTransient));
12470 case VMX_EXIT_INVLPG: VMEXIT_CALL_RET(0, hmR0VmxExitInvlpg(pVCpu, pVmxTransient));
12471 case VMX_EXIT_MTF: VMEXIT_CALL_RET(0, hmR0VmxExitMtf(pVCpu, pVmxTransient));
12472 case VMX_EXIT_PAUSE: VMEXIT_CALL_RET(0, hmR0VmxExitPause(pVCpu, pVmxTransient));
12473 case VMX_EXIT_WBINVD: VMEXIT_CALL_RET(0, hmR0VmxExitWbinvd(pVCpu, pVmxTransient));
12474 case VMX_EXIT_XSETBV: VMEXIT_CALL_RET(0, hmR0VmxExitXsetbv(pVCpu, pVmxTransient));
12475 case VMX_EXIT_INVPCID: VMEXIT_CALL_RET(0, hmR0VmxExitInvpcid(pVCpu, pVmxTransient));
12476 case VMX_EXIT_GETSEC: VMEXIT_CALL_RET(0, hmR0VmxExitGetsec(pVCpu, pVmxTransient));
12477 case VMX_EXIT_RDPMC: VMEXIT_CALL_RET(0, hmR0VmxExitRdpmc(pVCpu, pVmxTransient));
12478#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12479 case VMX_EXIT_VMCLEAR: VMEXIT_CALL_RET(0, hmR0VmxExitVmclear(pVCpu, pVmxTransient));
12480 case VMX_EXIT_VMLAUNCH: VMEXIT_CALL_RET(0, hmR0VmxExitVmlaunch(pVCpu, pVmxTransient));
12481 case VMX_EXIT_VMPTRLD: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrld(pVCpu, pVmxTransient));
12482 case VMX_EXIT_VMPTRST: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrst(pVCpu, pVmxTransient));
12483 case VMX_EXIT_VMREAD: VMEXIT_CALL_RET(0, hmR0VmxExitVmread(pVCpu, pVmxTransient));
12484 case VMX_EXIT_VMRESUME: VMEXIT_CALL_RET(0, hmR0VmxExitVmwrite(pVCpu, pVmxTransient));
12485 case VMX_EXIT_VMWRITE: VMEXIT_CALL_RET(0, hmR0VmxExitVmresume(pVCpu, pVmxTransient));
12486 case VMX_EXIT_VMXOFF: VMEXIT_CALL_RET(0, hmR0VmxExitVmxoff(pVCpu, pVmxTransient));
12487 case VMX_EXIT_VMXON: VMEXIT_CALL_RET(0, hmR0VmxExitVmxon(pVCpu, pVmxTransient));
12488 case VMX_EXIT_INVVPID: VMEXIT_CALL_RET(0, hmR0VmxExitInvvpid(pVCpu, pVmxTransient));
12489 case VMX_EXIT_INVEPT: VMEXIT_CALL_RET(0, hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient));
12490#else
12491 case VMX_EXIT_VMCLEAR:
12492 case VMX_EXIT_VMLAUNCH:
12493 case VMX_EXIT_VMPTRLD:
12494 case VMX_EXIT_VMPTRST:
12495 case VMX_EXIT_VMREAD:
12496 case VMX_EXIT_VMRESUME:
12497 case VMX_EXIT_VMWRITE:
12498 case VMX_EXIT_VMXOFF:
12499 case VMX_EXIT_VMXON:
12500 case VMX_EXIT_INVVPID:
12501 case VMX_EXIT_INVEPT:
12502 return hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient);
12503#endif
12504
12505 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pVmxTransient);
12506 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pVmxTransient);
12507 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
12508
12509 case VMX_EXIT_INIT_SIGNAL:
12510 case VMX_EXIT_SIPI:
12511 case VMX_EXIT_IO_SMI:
12512 case VMX_EXIT_SMI:
12513 case VMX_EXIT_ERR_MSR_LOAD:
12514 case VMX_EXIT_ERR_MACHINE_CHECK:
12515 case VMX_EXIT_PML_FULL:
12516 case VMX_EXIT_VIRTUALIZED_EOI:
12517 case VMX_EXIT_GDTR_IDTR_ACCESS:
12518 case VMX_EXIT_LDTR_TR_ACCESS:
12519 case VMX_EXIT_APIC_WRITE:
12520 case VMX_EXIT_RDRAND:
12521 case VMX_EXIT_RSM:
12522 case VMX_EXIT_VMFUNC:
12523 case VMX_EXIT_ENCLS:
12524 case VMX_EXIT_RDSEED:
12525 case VMX_EXIT_XSAVES:
12526 case VMX_EXIT_XRSTORS:
12527 case VMX_EXIT_UMWAIT:
12528 case VMX_EXIT_TPAUSE:
12529 default:
12530 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
12531 }
12532#undef VMEXIT_CALL_RET
12533}
12534#endif /* !HMVMX_USE_FUNCTION_TABLE */
12535
12536
12537#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12538/**
12539 * Handles a nested-guest VM-exit from hardware-assisted VMX execution.
12540 *
12541 * @returns Strict VBox status code (i.e. informational status codes too).
12542 * @param pVCpu The cross context virtual CPU structure.
12543 * @param pVmxTransient The VMX-transient structure.
12544 */
12545DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12546{
12547 /** @todo NSTVMX: Remove after debugging page-fault issue. */
12548#ifdef DEBUG_ramshankar
12549 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
12550 Log4Func(("cs:rip=%#04x:%#RX64 rsp=%#RX64 eflags=%#RX32 cr3=%#RX64\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
12551 pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u32, pVCpu->cpum.GstCtx.cr3));
12552#endif
12553
12554 uint32_t const uExitReason = pVmxTransient->uExitReason;
12555 switch (uExitReason)
12556 {
12557 case VMX_EXIT_EPT_MISCONFIG: return hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient);
12558 case VMX_EXIT_EPT_VIOLATION: return hmR0VmxExitEptViolation(pVCpu, pVmxTransient);
12559 case VMX_EXIT_XCPT_OR_NMI: return hmR0VmxExitXcptOrNmiNested(pVCpu, pVmxTransient);
12560 case VMX_EXIT_IO_INSTR: return hmR0VmxExitIoInstrNested(pVCpu, pVmxTransient);
12561 case VMX_EXIT_HLT: return hmR0VmxExitHltNested(pVCpu, pVmxTransient);
12562
12563 /*
12564 * We shouldn't direct host physical interrupts to the nested-guest.
12565 */
12566 case VMX_EXIT_EXT_INT:
12567 return hmR0VmxExitExtInt(pVCpu, pVmxTransient);
12568
12569 /*
12570 * Instructions that cause VM-exits unconditionally or the condition is
12571 * always is taken solely from the guest hypervisor (meaning if the VM-exit
12572 * happens, it's guaranteed to be a nested-guest VM-exit).
12573 *
12574 * - Provides VM-exit instruction length ONLY.
12575 */
12576 case VMX_EXIT_CPUID: /* Unconditional. */
12577 case VMX_EXIT_VMCALL:
12578 case VMX_EXIT_GETSEC:
12579 case VMX_EXIT_INVD:
12580 case VMX_EXIT_XSETBV:
12581 case VMX_EXIT_VMLAUNCH:
12582 case VMX_EXIT_VMRESUME:
12583 case VMX_EXIT_VMXOFF:
12584 case VMX_EXIT_ENCLS: /* Condition specified solely by guest hypervisor. */
12585 case VMX_EXIT_VMFUNC:
12586 return hmR0VmxExitInstrNested(pVCpu, pVmxTransient);
12587
12588 /*
12589 * Instructions that cause VM-exits unconditionally or the condition is
12590 * always is taken solely from the guest hypervisor (meaning if the VM-exit
12591 * happens, it's guaranteed to be a nested-guest VM-exit).
12592 *
12593 * - Provides VM-exit instruction length.
12594 * - Provides VM-exit information.
12595 * - Optionally provides Exit qualification.
12596 *
12597 * Since Exit qualification is 0 for all VM-exits where it is not
12598 * applicable, reading and passing it to the guest should produce
12599 * defined behavior.
12600 *
12601 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
12602 */
12603 case VMX_EXIT_INVEPT: /* Unconditional. */
12604 case VMX_EXIT_INVVPID:
12605 case VMX_EXIT_VMCLEAR:
12606 case VMX_EXIT_VMPTRLD:
12607 case VMX_EXIT_VMPTRST:
12608 case VMX_EXIT_VMXON:
12609 case VMX_EXIT_GDTR_IDTR_ACCESS: /* Condition specified solely by guest hypervisor. */
12610 case VMX_EXIT_LDTR_TR_ACCESS:
12611 case VMX_EXIT_RDRAND:
12612 case VMX_EXIT_RDSEED:
12613 case VMX_EXIT_XSAVES:
12614 case VMX_EXIT_XRSTORS:
12615 case VMX_EXIT_UMWAIT:
12616 case VMX_EXIT_TPAUSE:
12617 return hmR0VmxExitInstrWithInfoNested(pVCpu, pVmxTransient);
12618
12619 case VMX_EXIT_RDTSC: return hmR0VmxExitRdtscNested(pVCpu, pVmxTransient);
12620 case VMX_EXIT_RDTSCP: return hmR0VmxExitRdtscpNested(pVCpu, pVmxTransient);
12621 case VMX_EXIT_RDMSR: return hmR0VmxExitRdmsrNested(pVCpu, pVmxTransient);
12622 case VMX_EXIT_WRMSR: return hmR0VmxExitWrmsrNested(pVCpu, pVmxTransient);
12623 case VMX_EXIT_INVLPG: return hmR0VmxExitInvlpgNested(pVCpu, pVmxTransient);
12624 case VMX_EXIT_INVPCID: return hmR0VmxExitInvpcidNested(pVCpu, pVmxTransient);
12625 case VMX_EXIT_TASK_SWITCH: return hmR0VmxExitTaskSwitchNested(pVCpu, pVmxTransient);
12626 case VMX_EXIT_WBINVD: return hmR0VmxExitWbinvdNested(pVCpu, pVmxTransient);
12627 case VMX_EXIT_MTF: return hmR0VmxExitMtfNested(pVCpu, pVmxTransient);
12628 case VMX_EXIT_APIC_ACCESS: return hmR0VmxExitApicAccessNested(pVCpu, pVmxTransient);
12629 case VMX_EXIT_APIC_WRITE: return hmR0VmxExitApicWriteNested(pVCpu, pVmxTransient);
12630 case VMX_EXIT_VIRTUALIZED_EOI: return hmR0VmxExitVirtEoiNested(pVCpu, pVmxTransient);
12631 case VMX_EXIT_MOV_CRX: return hmR0VmxExitMovCRxNested(pVCpu, pVmxTransient);
12632 case VMX_EXIT_INT_WINDOW: return hmR0VmxExitIntWindowNested(pVCpu, pVmxTransient);
12633 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindowNested(pVCpu, pVmxTransient);
12634 case VMX_EXIT_TPR_BELOW_THRESHOLD: return hmR0VmxExitTprBelowThresholdNested(pVCpu, pVmxTransient);
12635 case VMX_EXIT_MWAIT: return hmR0VmxExitMwaitNested(pVCpu, pVmxTransient);
12636 case VMX_EXIT_MONITOR: return hmR0VmxExitMonitorNested(pVCpu, pVmxTransient);
12637 case VMX_EXIT_PAUSE: return hmR0VmxExitPauseNested(pVCpu, pVmxTransient);
12638
12639 case VMX_EXIT_PREEMPT_TIMER:
12640 {
12641 /** @todo NSTVMX: Preempt timer. */
12642 return hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient);
12643 }
12644
12645 case VMX_EXIT_MOV_DRX: return hmR0VmxExitMovDRxNested(pVCpu, pVmxTransient);
12646 case VMX_EXIT_RDPMC: return hmR0VmxExitRdpmcNested(pVCpu, pVmxTransient);
12647
12648 case VMX_EXIT_VMREAD:
12649 case VMX_EXIT_VMWRITE: return hmR0VmxExitVmreadVmwriteNested(pVCpu, pVmxTransient);
12650
12651 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFaultNested(pVCpu, pVmxTransient);
12652 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestStateNested(pVCpu, pVmxTransient);
12653
12654 case VMX_EXIT_INIT_SIGNAL:
12655 case VMX_EXIT_SIPI:
12656 case VMX_EXIT_IO_SMI:
12657 case VMX_EXIT_SMI:
12658 case VMX_EXIT_ERR_MSR_LOAD:
12659 case VMX_EXIT_ERR_MACHINE_CHECK:
12660 case VMX_EXIT_PML_FULL:
12661 case VMX_EXIT_RSM:
12662 default:
12663 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
12664 }
12665}
12666#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
12667
12668
12669/** @name VM-exit helpers.
12670 * @{
12671 */
12672/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12673/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= VM-exit helpers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
12674/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12675
12676/** Macro for VM-exits called unexpectedly. */
12677#define HMVMX_UNEXPECTED_EXIT_RET(a_pVCpu, a_HmError) \
12678 do { \
12679 (a_pVCpu)->hm.s.u32HMError = (a_HmError); \
12680 return VERR_VMX_UNEXPECTED_EXIT; \
12681 } while (0)
12682
12683#ifdef VBOX_STRICT
12684/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
12685# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
12686 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
12687
12688# define HMVMX_ASSERT_PREEMPT_CPUID() \
12689 do { \
12690 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
12691 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
12692 } while (0)
12693
12694# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12695 do { \
12696 AssertPtr((a_pVCpu)); \
12697 AssertPtr((a_pVmxTransient)); \
12698 Assert((a_pVmxTransient)->fVMEntryFailed == false); \
12699 Assert((a_pVmxTransient)->pVmcsInfo); \
12700 Assert(ASMIntAreEnabled()); \
12701 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
12702 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
12703 Log4Func(("vcpu[%RU32]\n", (a_pVCpu)->idCpu)); \
12704 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
12705 if (VMMR0IsLogFlushDisabled((a_pVCpu))) \
12706 HMVMX_ASSERT_PREEMPT_CPUID(); \
12707 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
12708 } while (0)
12709
12710# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12711 do { \
12712 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); \
12713 Assert((a_pVmxTransient)->fIsNestedGuest); \
12714 } while (0)
12715
12716# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12717 do { \
12718 Log4Func(("\n")); \
12719 } while (0)
12720#else
12721# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12722 do { \
12723 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
12724 NOREF((a_pVCpu)); NOREF((a_pVmxTransient)); \
12725 } while (0)
12726
12727# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12728 do { HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); } while (0)
12729
12730# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) do { } while (0)
12731#endif
12732
12733#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12734/** Macro that does the necessary privilege checks and intercepted VM-exits for
12735 * guests that attempted to execute a VMX instruction. */
12736# define HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(a_pVCpu, a_uExitReason) \
12737 do \
12738 { \
12739 VBOXSTRICTRC rcStrictTmp = hmR0VmxCheckExitDueToVmxInstr((a_pVCpu), (a_uExitReason)); \
12740 if (rcStrictTmp == VINF_SUCCESS) \
12741 { /* likely */ } \
12742 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
12743 { \
12744 Assert((a_pVCpu)->hm.s.Event.fPending); \
12745 Log4Func(("Privilege checks failed -> %#x\n", VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo))); \
12746 return VINF_SUCCESS; \
12747 } \
12748 else \
12749 { \
12750 int rcTmp = VBOXSTRICTRC_VAL(rcStrictTmp); \
12751 AssertMsgFailedReturn(("Unexpected failure. rc=%Rrc", rcTmp), rcTmp); \
12752 } \
12753 } while (0)
12754
12755/** Macro that decodes a memory operand for an VM-exit caused by an instruction. */
12756# define HMVMX_DECODE_MEM_OPERAND(a_pVCpu, a_uExitInstrInfo, a_uExitQual, a_enmMemAccess, a_pGCPtrEffAddr) \
12757 do \
12758 { \
12759 VBOXSTRICTRC rcStrictTmp = hmR0VmxDecodeMemOperand((a_pVCpu), (a_uExitInstrInfo), (a_uExitQual), (a_enmMemAccess), \
12760 (a_pGCPtrEffAddr)); \
12761 if (rcStrictTmp == VINF_SUCCESS) \
12762 { /* likely */ } \
12763 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
12764 { \
12765 uint8_t const uXcptTmp = VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo); \
12766 Log4Func(("Memory operand decoding failed, raising xcpt %#x\n", uXcptTmp)); \
12767 NOREF(uXcptTmp); \
12768 return VINF_SUCCESS; \
12769 } \
12770 else \
12771 { \
12772 Log4Func(("hmR0VmxDecodeMemOperand failed. rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrictTmp))); \
12773 return rcStrictTmp; \
12774 } \
12775 } while (0)
12776#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
12777
12778
12779/**
12780 * Advances the guest RIP by the specified number of bytes.
12781 *
12782 * @param pVCpu The cross context virtual CPU structure.
12783 * @param cbInstr Number of bytes to advance the RIP by.
12784 *
12785 * @remarks No-long-jump zone!!!
12786 */
12787DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPUCC pVCpu, uint32_t cbInstr)
12788{
12789 /* Advance the RIP. */
12790 pVCpu->cpum.GstCtx.rip += cbInstr;
12791 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
12792
12793 /* Update interrupt inhibition. */
12794 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
12795 && pVCpu->cpum.GstCtx.rip != EMGetInhibitInterruptsPC(pVCpu))
12796 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
12797}
12798
12799
12800/**
12801 * Advances the guest RIP after reading it from the VMCS.
12802 *
12803 * @returns VBox status code, no informational status codes.
12804 * @param pVCpu The cross context virtual CPU structure.
12805 * @param pVmxTransient The VMX-transient structure.
12806 *
12807 * @remarks No-long-jump zone!!!
12808 */
12809static int hmR0VmxAdvanceGuestRip(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12810{
12811 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12812 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
12813 AssertRCReturn(rc, rc);
12814
12815 hmR0VmxAdvanceGuestRipBy(pVCpu, pVmxTransient->cbExitInstr);
12816 return VINF_SUCCESS;
12817}
12818
12819
12820/**
12821 * Handle a condition that occurred while delivering an event through the guest or
12822 * nested-guest IDT.
12823 *
12824 * @returns Strict VBox status code (i.e. informational status codes too).
12825 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
12826 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
12827 * to continue execution of the guest which will delivery the \#DF.
12828 * @retval VINF_EM_RESET if we detected a triple-fault condition.
12829 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
12830 *
12831 * @param pVCpu The cross context virtual CPU structure.
12832 * @param pVmxTransient The VMX-transient structure.
12833 *
12834 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
12835 * Additionally, HMVMX_READ_EXIT_QUALIFICATION is required if the VM-exit
12836 * is due to an EPT violation, PML full or SPP-related event.
12837 *
12838 * @remarks No-long-jump zone!!!
12839 */
12840static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12841{
12842 Assert(!pVCpu->hm.s.Event.fPending);
12843 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
12844 if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
12845 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
12846 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
12847 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_EXIT_QUALIFICATION);
12848
12849 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
12850 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
12851 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo;
12852 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
12853 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo))
12854 {
12855 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo);
12856 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo);
12857
12858 /*
12859 * If the event was a software interrupt (generated with INT n) or a software exception
12860 * (generated by INT3/INTO) or a privileged software exception (generated by INT1), we
12861 * can handle the VM-exit and continue guest execution which will re-execute the
12862 * instruction rather than re-injecting the exception, as that can cause premature
12863 * trips to ring-3 before injection and involve TRPM which currently has no way of
12864 * storing that these exceptions were caused by these instructions (ICEBP's #DB poses
12865 * the problem).
12866 */
12867 IEMXCPTRAISE enmRaise;
12868 IEMXCPTRAISEINFO fRaiseInfo;
12869 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
12870 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
12871 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
12872 {
12873 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
12874 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
12875 }
12876 else if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo))
12877 {
12878 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
12879 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo);
12880 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT);
12881
12882 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
12883 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
12884
12885 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo);
12886
12887 /* Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF(). */
12888 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
12889 {
12890 pVmxTransient->fVectoringPF = true;
12891 enmRaise = IEMXCPTRAISE_PREV_EVENT;
12892 }
12893 }
12894 else
12895 {
12896 /*
12897 * If an exception or hardware interrupt delivery caused an EPT violation/misconfig or APIC access
12898 * VM-exit, then the VM-exit interruption-information will not be valid and we end up here.
12899 * It is sufficient to reflect the original event to the guest after handling the VM-exit.
12900 */
12901 Assert( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
12902 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
12903 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
12904 enmRaise = IEMXCPTRAISE_PREV_EVENT;
12905 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
12906 }
12907
12908 /*
12909 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
12910 * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
12911 * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
12912 * subsequent VM-entry would fail, see @bugref{7445}.
12913 *
12914 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception".
12915 */
12916 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
12917 && enmRaise == IEMXCPTRAISE_PREV_EVENT
12918 && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
12919 && CPUMIsGuestNmiBlocking(pVCpu))
12920 {
12921 CPUMSetGuestNmiBlocking(pVCpu, false);
12922 }
12923
12924 switch (enmRaise)
12925 {
12926 case IEMXCPTRAISE_CURRENT_XCPT:
12927 {
12928 Log4Func(("IDT: Pending secondary Xcpt: idtinfo=%#RX64 exitinfo=%#RX64\n", uIdtVectorInfo, uExitIntInfo));
12929 Assert(rcStrict == VINF_SUCCESS);
12930 break;
12931 }
12932
12933 case IEMXCPTRAISE_PREV_EVENT:
12934 {
12935 uint32_t u32ErrCode;
12936 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo))
12937 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
12938 else
12939 u32ErrCode = 0;
12940
12941 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
12942 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflect);
12943 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(uIdtVectorInfo), 0 /* cbInstr */,
12944 u32ErrCode, pVCpu->cpum.GstCtx.cr2);
12945
12946 Log4Func(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntInfo,
12947 pVCpu->hm.s.Event.u32ErrCode));
12948 Assert(rcStrict == VINF_SUCCESS);
12949 break;
12950 }
12951
12952 case IEMXCPTRAISE_REEXEC_INSTR:
12953 Assert(rcStrict == VINF_SUCCESS);
12954 break;
12955
12956 case IEMXCPTRAISE_DOUBLE_FAULT:
12957 {
12958 /*
12959 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
12960 * second #PF as a guest #PF (and not a shadow #PF) and needs to be converted into a #DF.
12961 */
12962 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
12963 {
12964 pVmxTransient->fVectoringDoublePF = true;
12965 Log4Func(("IDT: Vectoring double #PF %#RX64 cr2=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo,
12966 pVCpu->cpum.GstCtx.cr2));
12967 rcStrict = VINF_SUCCESS;
12968 }
12969 else
12970 {
12971 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectConvertDF);
12972 hmR0VmxSetPendingXcptDF(pVCpu);
12973 Log4Func(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntInfo,
12974 uIdtVector, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
12975 rcStrict = VINF_HM_DOUBLE_FAULT;
12976 }
12977 break;
12978 }
12979
12980 case IEMXCPTRAISE_TRIPLE_FAULT:
12981 {
12982 Log4Func(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector,
12983 VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
12984 rcStrict = VINF_EM_RESET;
12985 break;
12986 }
12987
12988 case IEMXCPTRAISE_CPU_HANG:
12989 {
12990 Log4Func(("IDT: Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", fRaiseInfo));
12991 rcStrict = VERR_EM_GUEST_CPU_HANG;
12992 break;
12993 }
12994
12995 default:
12996 {
12997 AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
12998 rcStrict = VERR_VMX_IPE_2;
12999 break;
13000 }
13001 }
13002 }
13003 else if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
13004 && !CPUMIsGuestNmiBlocking(pVCpu))
13005 {
13006 if ( VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)
13007 && VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo) != X86_XCPT_DF
13008 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(uExitIntInfo))
13009 {
13010 /*
13011 * Execution of IRET caused a fault when NMI blocking was in effect (i.e we're in
13012 * the guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13013 * that NMIs remain blocked until the IRET execution is completed.
13014 *
13015 * See Intel spec. 31.7.1.2 "Resuming Guest Software After Handling An Exception".
13016 */
13017 CPUMSetGuestNmiBlocking(pVCpu, true);
13018 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13019 }
13020 else if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
13021 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
13022 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
13023 {
13024 /*
13025 * Execution of IRET caused an EPT violation, page-modification log-full event or
13026 * SPP-related event VM-exit when NMI blocking was in effect (i.e. we're in the
13027 * guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13028 * that NMIs remain blocked until the IRET execution is completed.
13029 *
13030 * See Intel spec. 27.2.3 "Information about NMI unblocking due to IRET"
13031 */
13032 if (VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(pVmxTransient->uExitQual))
13033 {
13034 CPUMSetGuestNmiBlocking(pVCpu, true);
13035 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13036 }
13037 }
13038 }
13039
13040 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
13041 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
13042 return rcStrict;
13043}
13044
13045
13046#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13047/**
13048 * Perform the relevant VMX instruction checks for VM-exits that occurred due to the
13049 * guest attempting to execute a VMX instruction.
13050 *
13051 * @returns Strict VBox status code (i.e. informational status codes too).
13052 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13053 * @retval VINF_HM_PENDING_XCPT if an exception was raised.
13054 *
13055 * @param pVCpu The cross context virtual CPU structure.
13056 * @param uExitReason The VM-exit reason.
13057 *
13058 * @todo NSTVMX: Document other error codes when VM-exit is implemented.
13059 * @remarks No-long-jump zone!!!
13060 */
13061static VBOXSTRICTRC hmR0VmxCheckExitDueToVmxInstr(PVMCPUCC pVCpu, uint32_t uExitReason)
13062{
13063 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS
13064 | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
13065
13066 /*
13067 * The physical CPU would have already checked the CPU mode/code segment.
13068 * We shall just assert here for paranoia.
13069 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
13070 */
13071 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13072 Assert( !CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx)
13073 || CPUMIsGuestIn64BitCodeEx(&pVCpu->cpum.GstCtx));
13074
13075 if (uExitReason == VMX_EXIT_VMXON)
13076 {
13077 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
13078
13079 /*
13080 * We check CR4.VMXE because it is required to be always set while in VMX operation
13081 * by physical CPUs and our CR4 read-shadow is only consulted when executing specific
13082 * instructions (CLTS, LMSW, MOV CR, and SMSW) and thus doesn't affect CPU operation
13083 * otherwise (i.e. physical CPU won't automatically #UD if Cr4Shadow.VMXE is 0).
13084 */
13085 if (!CPUMIsGuestVmxEnabled(&pVCpu->cpum.GstCtx))
13086 {
13087 Log4Func(("CR4.VMXE is not set -> #UD\n"));
13088 hmR0VmxSetPendingXcptUD(pVCpu);
13089 return VINF_HM_PENDING_XCPT;
13090 }
13091 }
13092 else if (!CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx))
13093 {
13094 /*
13095 * The guest has not entered VMX operation but attempted to execute a VMX instruction
13096 * (other than VMXON), we need to raise a #UD.
13097 */
13098 Log4Func(("Not in VMX root mode -> #UD\n"));
13099 hmR0VmxSetPendingXcptUD(pVCpu);
13100 return VINF_HM_PENDING_XCPT;
13101 }
13102
13103 /* All other checks (including VM-exit intercepts) are handled by IEM instruction emulation. */
13104 return VINF_SUCCESS;
13105}
13106
13107
13108/**
13109 * Decodes the memory operand of an instruction that caused a VM-exit.
13110 *
13111 * The Exit qualification field provides the displacement field for memory
13112 * operand instructions, if any.
13113 *
13114 * @returns Strict VBox status code (i.e. informational status codes too).
13115 * @retval VINF_SUCCESS if the operand was successfully decoded.
13116 * @retval VINF_HM_PENDING_XCPT if an exception was raised while decoding the
13117 * operand.
13118 * @param pVCpu The cross context virtual CPU structure.
13119 * @param uExitInstrInfo The VM-exit instruction information field.
13120 * @param enmMemAccess The memory operand's access type (read or write).
13121 * @param GCPtrDisp The instruction displacement field, if any. For
13122 * RIP-relative addressing pass RIP + displacement here.
13123 * @param pGCPtrMem Where to store the effective destination memory address.
13124 *
13125 * @remarks Warning! This function ASSUMES the instruction cannot be used in real or
13126 * virtual-8086 mode hence skips those checks while verifying if the
13127 * segment is valid.
13128 */
13129static VBOXSTRICTRC hmR0VmxDecodeMemOperand(PVMCPUCC pVCpu, uint32_t uExitInstrInfo, RTGCPTR GCPtrDisp, VMXMEMACCESS enmMemAccess,
13130 PRTGCPTR pGCPtrMem)
13131{
13132 Assert(pGCPtrMem);
13133 Assert(!CPUMIsGuestInRealOrV86Mode(pVCpu));
13134 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_EFER
13135 | CPUMCTX_EXTRN_CR0);
13136
13137 static uint64_t const s_auAddrSizeMasks[] = { UINT64_C(0xffff), UINT64_C(0xffffffff), UINT64_C(0xffffffffffffffff) };
13138 static uint64_t const s_auAccessSizeMasks[] = { sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t) };
13139 AssertCompile(RT_ELEMENTS(s_auAccessSizeMasks) == RT_ELEMENTS(s_auAddrSizeMasks));
13140
13141 VMXEXITINSTRINFO ExitInstrInfo;
13142 ExitInstrInfo.u = uExitInstrInfo;
13143 uint8_t const uAddrSize = ExitInstrInfo.All.u3AddrSize;
13144 uint8_t const iSegReg = ExitInstrInfo.All.iSegReg;
13145 bool const fIdxRegValid = !ExitInstrInfo.All.fIdxRegInvalid;
13146 uint8_t const iIdxReg = ExitInstrInfo.All.iIdxReg;
13147 uint8_t const uScale = ExitInstrInfo.All.u2Scaling;
13148 bool const fBaseRegValid = !ExitInstrInfo.All.fBaseRegInvalid;
13149 uint8_t const iBaseReg = ExitInstrInfo.All.iBaseReg;
13150 bool const fIsMemOperand = !ExitInstrInfo.All.fIsRegOperand;
13151 bool const fIsLongMode = CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx);
13152
13153 /*
13154 * Validate instruction information.
13155 * This shouldn't happen on real hardware but useful while testing our nested hardware-virtualization code.
13156 */
13157 AssertLogRelMsgReturn(uAddrSize < RT_ELEMENTS(s_auAddrSizeMasks),
13158 ("Invalid address size. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_1);
13159 AssertLogRelMsgReturn(iSegReg < X86_SREG_COUNT,
13160 ("Invalid segment register. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_2);
13161 AssertLogRelMsgReturn(fIsMemOperand,
13162 ("Expected memory operand. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_3);
13163
13164 /*
13165 * Compute the complete effective address.
13166 *
13167 * See AMD instruction spec. 1.4.2 "SIB Byte Format"
13168 * See AMD spec. 4.5.2 "Segment Registers".
13169 */
13170 RTGCPTR GCPtrMem = GCPtrDisp;
13171 if (fBaseRegValid)
13172 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iBaseReg].u64;
13173 if (fIdxRegValid)
13174 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iIdxReg].u64 << uScale;
13175
13176 RTGCPTR const GCPtrOff = GCPtrMem;
13177 if ( !fIsLongMode
13178 || iSegReg >= X86_SREG_FS)
13179 GCPtrMem += pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
13180 GCPtrMem &= s_auAddrSizeMasks[uAddrSize];
13181
13182 /*
13183 * Validate effective address.
13184 * See AMD spec. 4.5.3 "Segment Registers in 64-Bit Mode".
13185 */
13186 uint8_t const cbAccess = s_auAccessSizeMasks[uAddrSize];
13187 Assert(cbAccess > 0);
13188 if (fIsLongMode)
13189 {
13190 if (X86_IS_CANONICAL(GCPtrMem))
13191 {
13192 *pGCPtrMem = GCPtrMem;
13193 return VINF_SUCCESS;
13194 }
13195
13196 /** @todo r=ramshankar: We should probably raise \#SS or \#GP. See AMD spec. 4.12.2
13197 * "Data Limit Checks in 64-bit Mode". */
13198 Log4Func(("Long mode effective address is not canonical GCPtrMem=%#RX64\n", GCPtrMem));
13199 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13200 return VINF_HM_PENDING_XCPT;
13201 }
13202
13203 /*
13204 * This is a watered down version of iemMemApplySegment().
13205 * Parts that are not applicable for VMX instructions like real-or-v8086 mode
13206 * and segment CPL/DPL checks are skipped.
13207 */
13208 RTGCPTR32 const GCPtrFirst32 = (RTGCPTR32)GCPtrOff;
13209 RTGCPTR32 const GCPtrLast32 = GCPtrFirst32 + cbAccess - 1;
13210 PCCPUMSELREG pSel = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
13211
13212 /* Check if the segment is present and usable. */
13213 if ( pSel->Attr.n.u1Present
13214 && !pSel->Attr.n.u1Unusable)
13215 {
13216 Assert(pSel->Attr.n.u1DescType);
13217 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
13218 {
13219 /* Check permissions for the data segment. */
13220 if ( enmMemAccess == VMXMEMACCESS_WRITE
13221 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE))
13222 {
13223 Log4Func(("Data segment access invalid. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13224 hmR0VmxSetPendingXcptGP(pVCpu, iSegReg);
13225 return VINF_HM_PENDING_XCPT;
13226 }
13227
13228 /* Check limits if it's a normal data segment. */
13229 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
13230 {
13231 if ( GCPtrFirst32 > pSel->u32Limit
13232 || GCPtrLast32 > pSel->u32Limit)
13233 {
13234 Log4Func(("Data segment limit exceeded. "
13235 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13236 GCPtrLast32, pSel->u32Limit));
13237 if (iSegReg == X86_SREG_SS)
13238 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13239 else
13240 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13241 return VINF_HM_PENDING_XCPT;
13242 }
13243 }
13244 else
13245 {
13246 /* Check limits if it's an expand-down data segment.
13247 Note! The upper boundary is defined by the B bit, not the G bit! */
13248 if ( GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
13249 || GCPtrLast32 > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
13250 {
13251 Log4Func(("Expand-down data segment limit exceeded. "
13252 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13253 GCPtrLast32, pSel->u32Limit));
13254 if (iSegReg == X86_SREG_SS)
13255 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13256 else
13257 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13258 return VINF_HM_PENDING_XCPT;
13259 }
13260 }
13261 }
13262 else
13263 {
13264 /* Check permissions for the code segment. */
13265 if ( enmMemAccess == VMXMEMACCESS_WRITE
13266 || ( enmMemAccess == VMXMEMACCESS_READ
13267 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)))
13268 {
13269 Log4Func(("Code segment access invalid. Attr=%#RX32\n", pSel->Attr.u));
13270 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13271 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13272 return VINF_HM_PENDING_XCPT;
13273 }
13274
13275 /* Check limits for the code segment (normal/expand-down not applicable for code segments). */
13276 if ( GCPtrFirst32 > pSel->u32Limit
13277 || GCPtrLast32 > pSel->u32Limit)
13278 {
13279 Log4Func(("Code segment limit exceeded. GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n",
13280 GCPtrFirst32, GCPtrLast32, pSel->u32Limit));
13281 if (iSegReg == X86_SREG_SS)
13282 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13283 else
13284 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13285 return VINF_HM_PENDING_XCPT;
13286 }
13287 }
13288 }
13289 else
13290 {
13291 Log4Func(("Not present or unusable segment. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13292 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13293 return VINF_HM_PENDING_XCPT;
13294 }
13295
13296 *pGCPtrMem = GCPtrMem;
13297 return VINF_SUCCESS;
13298}
13299#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13300
13301
13302/**
13303 * VM-exit helper for LMSW.
13304 */
13305static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst)
13306{
13307 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13308 AssertRCReturn(rc, rc);
13309
13310 VBOXSTRICTRC rcStrict = IEMExecDecodedLmsw(pVCpu, cbInstr, uMsw, GCPtrEffDst);
13311 AssertMsg( rcStrict == VINF_SUCCESS
13312 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13313
13314 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13315 if (rcStrict == VINF_IEM_RAISED_XCPT)
13316 {
13317 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13318 rcStrict = VINF_SUCCESS;
13319 }
13320
13321 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
13322 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13323 return rcStrict;
13324}
13325
13326
13327/**
13328 * VM-exit helper for CLTS.
13329 */
13330static VBOXSTRICTRC hmR0VmxExitClts(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
13331{
13332 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13333 AssertRCReturn(rc, rc);
13334
13335 VBOXSTRICTRC rcStrict = IEMExecDecodedClts(pVCpu, cbInstr);
13336 AssertMsg( rcStrict == VINF_SUCCESS
13337 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13338
13339 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13340 if (rcStrict == VINF_IEM_RAISED_XCPT)
13341 {
13342 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13343 rcStrict = VINF_SUCCESS;
13344 }
13345
13346 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
13347 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13348 return rcStrict;
13349}
13350
13351
13352/**
13353 * VM-exit helper for MOV from CRx (CRx read).
13354 */
13355static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13356{
13357 Assert(iCrReg < 16);
13358 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
13359
13360 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13361 AssertRCReturn(rc, rc);
13362
13363 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxRead(pVCpu, cbInstr, iGReg, iCrReg);
13364 AssertMsg( rcStrict == VINF_SUCCESS
13365 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13366
13367 if (iGReg == X86_GREG_xSP)
13368 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_RSP);
13369 else
13370 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13371#ifdef VBOX_WITH_STATISTICS
13372 switch (iCrReg)
13373 {
13374 case 0: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Read); break;
13375 case 2: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Read); break;
13376 case 3: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Read); break;
13377 case 4: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Read); break;
13378 case 8: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Read); break;
13379 }
13380#endif
13381 Log4Func(("CR%d Read access rcStrict=%Rrc\n", iCrReg, VBOXSTRICTRC_VAL(rcStrict)));
13382 return rcStrict;
13383}
13384
13385
13386/**
13387 * VM-exit helper for MOV to CRx (CRx write).
13388 */
13389static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13390{
13391 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13392 AssertRCReturn(rc, rc);
13393
13394 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, cbInstr, iCrReg, iGReg);
13395 AssertMsg( rcStrict == VINF_SUCCESS
13396 || rcStrict == VINF_IEM_RAISED_XCPT
13397 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13398
13399 switch (iCrReg)
13400 {
13401 case 0:
13402 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13403 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Write);
13404 Log4Func(("CR0 write. rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr0));
13405 break;
13406
13407 case 2:
13408 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Write);
13409 /* Nothing to do here, CR2 it's not part of the VMCS. */
13410 break;
13411
13412 case 3:
13413 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR3);
13414 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Write);
13415 Log4Func(("CR3 write. rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr3));
13416 break;
13417
13418 case 4:
13419 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR4);
13420 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Write);
13421 Log4Func(("CR4 write. rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n", VBOXSTRICTRC_VAL(rcStrict),
13422 pVCpu->cpum.GstCtx.cr4, pVCpu->hm.s.fLoadSaveGuestXcr0));
13423 break;
13424
13425 case 8:
13426 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged,
13427 HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_APIC_TPR);
13428 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Write);
13429 break;
13430
13431 default:
13432 AssertMsgFailed(("Invalid CRx register %#x\n", iCrReg));
13433 break;
13434 }
13435
13436 if (rcStrict == VINF_IEM_RAISED_XCPT)
13437 {
13438 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13439 rcStrict = VINF_SUCCESS;
13440 }
13441 return rcStrict;
13442}
13443
13444
13445/**
13446 * VM-exit exception handler for \#PF (Page-fault exception).
13447 *
13448 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13449 */
13450static VBOXSTRICTRC hmR0VmxExitXcptPF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13451{
13452 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13453 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
13454 hmR0VmxReadExitQualVmcs(pVmxTransient);
13455
13456 if (!pVM->hm.s.fNestedPaging)
13457 { /* likely */ }
13458 else
13459 {
13460#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13461 Assert(pVmxTransient->fIsNestedGuest || pVCpu->hm.s.fUsingDebugLoop);
13462#endif
13463 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13464 if (!pVmxTransient->fVectoringDoublePF)
13465 {
13466 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13467 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual);
13468 }
13469 else
13470 {
13471 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13472 Assert(!pVmxTransient->fIsNestedGuest);
13473 hmR0VmxSetPendingXcptDF(pVCpu);
13474 Log4Func(("Pending #DF due to vectoring #PF w/ NestedPaging\n"));
13475 }
13476 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13477 return VINF_SUCCESS;
13478 }
13479
13480 Assert(!pVmxTransient->fIsNestedGuest);
13481
13482 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
13483 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
13484 if (pVmxTransient->fVectoringPF)
13485 {
13486 Assert(pVCpu->hm.s.Event.fPending);
13487 return VINF_EM_RAW_INJECT_TRPM_EVENT;
13488 }
13489
13490 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13491 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13492 AssertRCReturn(rc, rc);
13493
13494 Log4Func(("#PF: cr2=%#RX64 cs:rip=%#04x:%#RX64 uErrCode %#RX32 cr3=%#RX64\n", pVmxTransient->uExitQual, pCtx->cs.Sel,
13495 pCtx->rip, pVmxTransient->uExitIntErrorCode, pCtx->cr3));
13496
13497 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQual, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
13498 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pCtx), (RTGCPTR)pVmxTransient->uExitQual);
13499
13500 Log4Func(("#PF: rc=%Rrc\n", rc));
13501 if (rc == VINF_SUCCESS)
13502 {
13503 /*
13504 * This is typically a shadow page table sync or a MMIO instruction. But we may have
13505 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
13506 */
13507 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13508 TRPMResetTrap(pVCpu);
13509 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
13510 return rc;
13511 }
13512
13513 if (rc == VINF_EM_RAW_GUEST_TRAP)
13514 {
13515 if (!pVmxTransient->fVectoringDoublePF)
13516 {
13517 /* It's a guest page fault and needs to be reflected to the guest. */
13518 uint32_t uGstErrorCode = TRPMGetErrorCode(pVCpu);
13519 TRPMResetTrap(pVCpu);
13520 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
13521 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13522 uGstErrorCode, pVmxTransient->uExitQual);
13523 }
13524 else
13525 {
13526 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13527 TRPMResetTrap(pVCpu);
13528 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
13529 hmR0VmxSetPendingXcptDF(pVCpu);
13530 Log4Func(("#PF: Pending #DF due to vectoring #PF\n"));
13531 }
13532
13533 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13534 return VINF_SUCCESS;
13535 }
13536
13537 TRPMResetTrap(pVCpu);
13538 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
13539 return rc;
13540}
13541
13542
13543/**
13544 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
13545 *
13546 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13547 */
13548static VBOXSTRICTRC hmR0VmxExitXcptMF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13549{
13550 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13551 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
13552
13553 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0);
13554 AssertRCReturn(rc, rc);
13555
13556 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_NE))
13557 {
13558 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
13559 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
13560
13561 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
13562 * provides VM-exit instruction length. If this causes problem later,
13563 * disassemble the instruction like it's done on AMD-V. */
13564 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
13565 AssertRCReturn(rc2, rc2);
13566 return rc;
13567 }
13568
13569 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbExitInstr,
13570 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13571 return VINF_SUCCESS;
13572}
13573
13574
13575/**
13576 * VM-exit exception handler for \#BP (Breakpoint exception).
13577 *
13578 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13579 */
13580static VBOXSTRICTRC hmR0VmxExitXcptBP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13581{
13582 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13583 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
13584
13585 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13586 AssertRCReturn(rc, rc);
13587
13588 if (!pVmxTransient->fIsNestedGuest)
13589 rc = DBGFRZTrap03Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(&pVCpu->cpum.GstCtx));
13590 else
13591 rc = VINF_EM_RAW_GUEST_TRAP;
13592
13593 if (rc == VINF_EM_RAW_GUEST_TRAP)
13594 {
13595 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13596 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13597 rc = VINF_SUCCESS;
13598 }
13599
13600 Assert(rc == VINF_SUCCESS || rc == VINF_EM_DBG_BREAKPOINT);
13601 return rc;
13602}
13603
13604
13605/**
13606 * VM-exit exception handler for \#AC (Alignment-check exception).
13607 *
13608 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13609 */
13610static VBOXSTRICTRC hmR0VmxExitXcptAC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13611{
13612 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13613 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC);
13614
13615 /* Re-inject it. We'll detect any nesting before getting here. */
13616 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13617 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13618 return VINF_SUCCESS;
13619}
13620
13621
13622/**
13623 * VM-exit exception handler for \#DB (Debug exception).
13624 *
13625 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13626 */
13627static VBOXSTRICTRC hmR0VmxExitXcptDB(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13628{
13629 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13630 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
13631
13632 /*
13633 * Get the DR6-like values from the Exit qualification and pass it to DBGF for processing.
13634 */
13635 hmR0VmxReadExitQualVmcs(pVmxTransient);
13636
13637 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
13638 uint64_t const uDR6 = X86_DR6_INIT_VAL
13639 | (pVmxTransient->uExitQual & ( X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3
13640 | X86_DR6_BD | X86_DR6_BS));
13641
13642 int rc;
13643 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13644 if (!pVmxTransient->fIsNestedGuest)
13645 rc = DBGFRZTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
13646 else
13647 rc = VINF_EM_RAW_GUEST_TRAP;
13648 Log6Func(("rc=%Rrc\n", rc));
13649 if (rc == VINF_EM_RAW_GUEST_TRAP)
13650 {
13651 /*
13652 * The exception was for the guest. Update DR6, DR7.GD and
13653 * IA32_DEBUGCTL.LBR before forwarding it.
13654 * See Intel spec. 27.1 "Architectural State before a VM-Exit".
13655 */
13656 VMMRZCallRing3Disable(pVCpu);
13657 HM_DISABLE_PREEMPT(pVCpu);
13658
13659 pCtx->dr[6] &= ~X86_DR6_B_MASK;
13660 pCtx->dr[6] |= uDR6;
13661 if (CPUMIsGuestDebugStateActive(pVCpu))
13662 ASMSetDR6(pCtx->dr[6]);
13663
13664 HM_RESTORE_PREEMPT();
13665 VMMRZCallRing3Enable(pVCpu);
13666
13667 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_DR7);
13668 AssertRCReturn(rc, rc);
13669
13670 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
13671 pCtx->dr[7] &= ~(uint64_t)X86_DR7_GD;
13672
13673 /* Paranoia. */
13674 pCtx->dr[7] &= ~(uint64_t)X86_DR7_RAZ_MASK;
13675 pCtx->dr[7] |= X86_DR7_RA1_MASK;
13676
13677 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, pCtx->dr[7]);
13678 AssertRC(rc);
13679
13680 /*
13681 * Raise #DB in the guest.
13682 *
13683 * It is important to reflect exactly what the VM-exit gave us (preserving the
13684 * interruption-type) rather than use hmR0VmxSetPendingXcptDB() as the #DB could've
13685 * been raised while executing ICEBP (INT1) and not the regular #DB. Thus it may
13686 * trigger different handling in the CPU (like skipping DPL checks), see @bugref{6398}.
13687 *
13688 * Intel re-documented ICEBP/INT1 on May 2018 previously documented as part of
13689 * Intel 386, see Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
13690 */
13691 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13692 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13693 return VINF_SUCCESS;
13694 }
13695
13696 /*
13697 * Not a guest trap, must be a hypervisor related debug event then.
13698 * Update DR6 in case someone is interested in it.
13699 */
13700 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
13701 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
13702 CPUMSetHyperDR6(pVCpu, uDR6);
13703
13704 return rc;
13705}
13706
13707
13708/**
13709 * Hacks its way around the lovely mesa driver's backdoor accesses.
13710 *
13711 * @sa hmR0SvmHandleMesaDrvGp.
13712 */
13713static int hmR0VmxHandleMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
13714{
13715 LogFunc(("cs:rip=%#04x:%#RX64 rcx=%#RX64 rbx=%#RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->rcx, pCtx->rbx));
13716 RT_NOREF(pCtx);
13717
13718 /* For now we'll just skip the instruction. */
13719 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
13720}
13721
13722
13723/**
13724 * Checks if the \#GP'ing instruction is the mesa driver doing it's lovely
13725 * backdoor logging w/o checking what it is running inside.
13726 *
13727 * This recognizes an "IN EAX,DX" instruction executed in flat ring-3, with the
13728 * backdoor port and magic numbers loaded in registers.
13729 *
13730 * @returns true if it is, false if it isn't.
13731 * @sa hmR0SvmIsMesaDrvGp.
13732 */
13733DECLINLINE(bool) hmR0VmxIsMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
13734{
13735 /* 0xed: IN eAX,dx */
13736 uint8_t abInstr[1];
13737 if (pVmxTransient->cbExitInstr != sizeof(abInstr))
13738 return false;
13739
13740 /* Check that it is #GP(0). */
13741 if (pVmxTransient->uExitIntErrorCode != 0)
13742 return false;
13743
13744 /* Check magic and port. */
13745 Assert(!(pCtx->fExtrn & (CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX)));
13746 /*Log(("hmR0VmxIsMesaDrvGp: rax=%RX64 rdx=%RX64\n", pCtx->rax, pCtx->rdx));*/
13747 if (pCtx->rax != UINT32_C(0x564d5868))
13748 return false;
13749 if (pCtx->dx != UINT32_C(0x5658))
13750 return false;
13751
13752 /* Flat ring-3 CS. */
13753 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_CS);
13754 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_CS));
13755 /*Log(("hmR0VmxIsMesaDrvGp: cs.Attr.n.u2Dpl=%d base=%Rx64\n", pCtx->cs.Attr.n.u2Dpl, pCtx->cs.u64Base));*/
13756 if (pCtx->cs.Attr.n.u2Dpl != 3)
13757 return false;
13758 if (pCtx->cs.u64Base != 0)
13759 return false;
13760
13761 /* Check opcode. */
13762 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_RIP);
13763 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_RIP));
13764 int rc = PGMPhysSimpleReadGCPtr(pVCpu, abInstr, pCtx->rip, sizeof(abInstr));
13765 /*Log(("hmR0VmxIsMesaDrvGp: PGMPhysSimpleReadGCPtr -> %Rrc %#x\n", rc, abInstr[0]));*/
13766 if (RT_FAILURE(rc))
13767 return false;
13768 if (abInstr[0] != 0xed)
13769 return false;
13770
13771 return true;
13772}
13773
13774
13775/**
13776 * VM-exit exception handler for \#GP (General-protection exception).
13777 *
13778 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13779 */
13780static VBOXSTRICTRC hmR0VmxExitXcptGP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13781{
13782 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13783 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
13784
13785 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13786 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13787 if (pVmcsInfo->RealMode.fRealOnV86Active)
13788 { /* likely */ }
13789 else
13790 {
13791#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13792 Assert(pVCpu->hm.s.fUsingDebugLoop || pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
13793#endif
13794 /*
13795 * If the guest is not in real-mode or we have unrestricted guest execution support, or if we are
13796 * executing a nested-guest, reflect #GP to the guest or nested-guest.
13797 */
13798 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13799 AssertRCReturn(rc, rc);
13800 Log4Func(("Gst: cs:rip=%#04x:%#RX64 ErrorCode=%#x cr0=%#RX64 cpl=%u tr=%#04x\n", pCtx->cs.Sel, pCtx->rip,
13801 pVmxTransient->uExitIntErrorCode, pCtx->cr0, CPUMGetGuestCPL(pVCpu), pCtx->tr.Sel));
13802
13803 if ( pVmxTransient->fIsNestedGuest
13804 || !pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv
13805 || !hmR0VmxIsMesaDrvGp(pVCpu, pVmxTransient, pCtx))
13806 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13807 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13808 else
13809 rc = hmR0VmxHandleMesaDrvGp(pVCpu, pVmxTransient, pCtx);
13810 return rc;
13811 }
13812
13813 Assert(CPUMIsGuestInRealModeEx(pCtx));
13814 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest);
13815 Assert(!pVmxTransient->fIsNestedGuest);
13816
13817 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13818 AssertRCReturn(rc, rc);
13819
13820 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
13821 if (rcStrict == VINF_SUCCESS)
13822 {
13823 if (!CPUMIsGuestInRealModeEx(pCtx))
13824 {
13825 /*
13826 * The guest is no longer in real-mode, check if we can continue executing the
13827 * guest using hardware-assisted VMX. Otherwise, fall back to emulation.
13828 */
13829 pVmcsInfo->RealMode.fRealOnV86Active = false;
13830 if (HMCanExecuteVmxGuest(pVCpu->pVMR0, pVCpu, pCtx))
13831 {
13832 Log4Func(("Mode changed but guest still suitable for executing using hardware-assisted VMX\n"));
13833 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13834 }
13835 else
13836 {
13837 Log4Func(("Mode changed -> VINF_EM_RESCHEDULE\n"));
13838 rcStrict = VINF_EM_RESCHEDULE;
13839 }
13840 }
13841 else
13842 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13843 }
13844 else if (rcStrict == VINF_IEM_RAISED_XCPT)
13845 {
13846 rcStrict = VINF_SUCCESS;
13847 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13848 }
13849 return VBOXSTRICTRC_VAL(rcStrict);
13850}
13851
13852
13853/**
13854 * VM-exit exception handler wrapper for all other exceptions that are not handled
13855 * by a specific handler.
13856 *
13857 * This simply re-injects the exception back into the VM without any special
13858 * processing.
13859 *
13860 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13861 */
13862static VBOXSTRICTRC hmR0VmxExitXcptOthers(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13863{
13864 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13865
13866#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13867 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13868 AssertMsg(pVCpu->hm.s.fUsingDebugLoop || pVmcsInfo->RealMode.fRealOnV86Active || pVmxTransient->fIsNestedGuest,
13869 ("uVector=%#x u32XcptBitmap=%#X32\n",
13870 VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVmcsInfo->u32XcptBitmap));
13871 NOREF(pVmcsInfo);
13872#endif
13873
13874 /*
13875 * Re-inject the exception into the guest. This cannot be a double-fault condition which
13876 * would have been handled while checking exits due to event delivery.
13877 */
13878 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13879
13880#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13881 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
13882 AssertRCReturn(rc, rc);
13883 Log4Func(("Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
13884#endif
13885
13886#ifdef VBOX_WITH_STATISTICS
13887 switch (uVector)
13888 {
13889 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE); break;
13890 case X86_XCPT_DB: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB); break;
13891 case X86_XCPT_BP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP); break;
13892 case X86_XCPT_OF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
13893 case X86_XCPT_BR: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBR); break;
13894 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD); break;
13895 case X86_XCPT_NM: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
13896 case X86_XCPT_DF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDF); break;
13897 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS); break;
13898 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP); break;
13899 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS); break;
13900 case X86_XCPT_GP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP); break;
13901 case X86_XCPT_PF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF); break;
13902 case X86_XCPT_MF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF); break;
13903 case X86_XCPT_AC: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC); break;
13904 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF); break;
13905 default:
13906 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
13907 break;
13908 }
13909#endif
13910
13911 /* We should never call this function for a page-fault, we'd need to pass on the fault address below otherwise. */
13912 Assert(!VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo));
13913 NOREF(uVector);
13914
13915 /* Re-inject the original exception into the guest. */
13916 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13917 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13918 return VINF_SUCCESS;
13919}
13920
13921
13922/**
13923 * VM-exit exception handler for all exceptions (except NMIs!).
13924 *
13925 * @remarks This may be called for both guests and nested-guests. Take care to not
13926 * make assumptions and avoid doing anything that is not relevant when
13927 * executing a nested-guest (e.g., Mesa driver hacks).
13928 */
13929static VBOXSTRICTRC hmR0VmxExitXcpt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13930{
13931 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
13932
13933 /*
13934 * If this VM-exit occurred while delivering an event through the guest IDT, take
13935 * action based on the return code and additional hints (e.g. for page-faults)
13936 * that will be updated in the VMX transient structure.
13937 */
13938 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
13939 if (rcStrict == VINF_SUCCESS)
13940 {
13941 /*
13942 * If an exception caused a VM-exit due to delivery of an event, the original
13943 * event may have to be re-injected into the guest. We shall reinject it and
13944 * continue guest execution. However, page-fault is a complicated case and
13945 * needs additional processing done in hmR0VmxExitXcptPF().
13946 */
13947 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
13948 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13949 if ( !pVCpu->hm.s.Event.fPending
13950 || uVector == X86_XCPT_PF)
13951 {
13952 switch (uVector)
13953 {
13954 case X86_XCPT_PF: return hmR0VmxExitXcptPF(pVCpu, pVmxTransient);
13955 case X86_XCPT_GP: return hmR0VmxExitXcptGP(pVCpu, pVmxTransient);
13956 case X86_XCPT_MF: return hmR0VmxExitXcptMF(pVCpu, pVmxTransient);
13957 case X86_XCPT_DB: return hmR0VmxExitXcptDB(pVCpu, pVmxTransient);
13958 case X86_XCPT_BP: return hmR0VmxExitXcptBP(pVCpu, pVmxTransient);
13959 case X86_XCPT_AC: return hmR0VmxExitXcptAC(pVCpu, pVmxTransient);
13960 default:
13961 return hmR0VmxExitXcptOthers(pVCpu, pVmxTransient);
13962 }
13963 }
13964 /* else: inject pending event before resuming guest execution. */
13965 }
13966 else if (rcStrict == VINF_HM_DOUBLE_FAULT)
13967 {
13968 Assert(pVCpu->hm.s.Event.fPending);
13969 rcStrict = VINF_SUCCESS;
13970 }
13971
13972 return rcStrict;
13973}
13974/** @} */
13975
13976
13977/** @name VM-exit handlers.
13978 * @{
13979 */
13980/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13981/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
13982/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13983
13984/**
13985 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
13986 */
13987HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13988{
13989 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13990 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
13991 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
13992 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
13993 return VINF_SUCCESS;
13994 return VINF_EM_RAW_INTERRUPT;
13995}
13996
13997
13998/**
13999 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI). Conditional
14000 * VM-exit.
14001 */
14002HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14003{
14004 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14005 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
14006
14007 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
14008
14009 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
14010 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14011 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
14012
14013 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14014 Assert( !(pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT)
14015 && uExitIntType != VMX_EXIT_INT_INFO_TYPE_EXT_INT);
14016 NOREF(pVmcsInfo);
14017
14018 VBOXSTRICTRC rcStrict;
14019 switch (uExitIntType)
14020 {
14021 /*
14022 * Host physical NMIs:
14023 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we
14024 * injected it ourselves and anything we inject is not going to cause a VM-exit directly
14025 * for the event being injected[1]. Go ahead and dispatch the NMI to the host[2].
14026 *
14027 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
14028 * See Intel spec. 27.5.5 "Updating Non-Register State".
14029 */
14030 case VMX_EXIT_INT_INFO_TYPE_NMI:
14031 {
14032 rcStrict = hmR0VmxExitHostNmi(pVCpu, pVmcsInfo);
14033 break;
14034 }
14035
14036 /*
14037 * Privileged software exceptions (#DB from ICEBP),
14038 * Software exceptions (#BP and #OF),
14039 * Hardware exceptions:
14040 * Process the required exceptions and resume guest execution if possible.
14041 */
14042 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
14043 Assert(uVector == X86_XCPT_DB);
14044 RT_FALL_THRU();
14045 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
14046 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uExitIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT);
14047 RT_FALL_THRU();
14048 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
14049 {
14050 NOREF(uVector);
14051 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
14052 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14053 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
14054 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
14055
14056 rcStrict = hmR0VmxExitXcpt(pVCpu, pVmxTransient);
14057 break;
14058 }
14059
14060 default:
14061 {
14062 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
14063 rcStrict = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
14064 AssertMsgFailed(("Invalid/unexpected VM-exit interruption info %#x\n", pVmxTransient->uExitIntInfo));
14065 break;
14066 }
14067 }
14068
14069 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
14070 return rcStrict;
14071}
14072
14073
14074/**
14075 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
14076 */
14077HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14078{
14079 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14080
14081 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
14082 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14083 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
14084
14085 /* Evaluate and deliver pending events and resume guest execution. */
14086 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
14087 return VINF_SUCCESS;
14088}
14089
14090
14091/**
14092 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
14093 */
14094HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14095{
14096 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14097
14098 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14099 if (RT_UNLIKELY(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))) /** @todo NSTVMX: Turn this into an assertion. */
14100 {
14101 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
14102 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14103 }
14104
14105 Assert(!CPUMIsGuestNmiBlocking(pVCpu));
14106
14107 /*
14108 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
14109 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
14110 */
14111 uint32_t fIntrState;
14112 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
14113 AssertRC(rc);
14114 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
14115 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
14116 {
14117 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
14118 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
14119
14120 fIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
14121 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
14122 AssertRC(rc);
14123 }
14124
14125 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
14126 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
14127
14128 /* Evaluate and deliver pending events and resume guest execution. */
14129 return VINF_SUCCESS;
14130}
14131
14132
14133/**
14134 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
14135 */
14136HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14137{
14138 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14139 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14140}
14141
14142
14143/**
14144 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
14145 */
14146HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14147{
14148 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14149 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14150}
14151
14152
14153/**
14154 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
14155 */
14156HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14157{
14158 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14159
14160 /*
14161 * Get the state we need and update the exit history entry.
14162 */
14163 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14164 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14165
14166 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14167 AssertRCReturn(rc, rc);
14168
14169 VBOXSTRICTRC rcStrict;
14170 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
14171 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_CPUID),
14172 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
14173 if (!pExitRec)
14174 {
14175 /*
14176 * Regular CPUID instruction execution.
14177 */
14178 rcStrict = IEMExecDecodedCpuid(pVCpu, pVmxTransient->cbExitInstr);
14179 if (rcStrict == VINF_SUCCESS)
14180 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14181 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14182 {
14183 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14184 rcStrict = VINF_SUCCESS;
14185 }
14186 }
14187 else
14188 {
14189 /*
14190 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
14191 */
14192 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14193 AssertRCReturn(rc2, rc2);
14194
14195 Log4(("CpuIdExit/%u: %04x:%08RX64: %#x/%#x -> EMHistoryExec\n",
14196 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx));
14197
14198 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
14199 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14200
14201 Log4(("CpuIdExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
14202 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
14203 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
14204 }
14205 return rcStrict;
14206}
14207
14208
14209/**
14210 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
14211 */
14212HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14213{
14214 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14215
14216 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14217 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4);
14218 AssertRCReturn(rc, rc);
14219
14220 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_SMXE)
14221 return VINF_EM_RAW_EMULATE_INSTR;
14222
14223 AssertMsgFailed(("hmR0VmxExitGetsec: Unexpected VM-exit when CR4.SMXE is 0.\n"));
14224 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14225}
14226
14227
14228/**
14229 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
14230 */
14231HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14232{
14233 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14234
14235 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14236 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14237 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14238 AssertRCReturn(rc, rc);
14239
14240 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtsc(pVCpu, pVmxTransient->cbExitInstr);
14241 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14242 {
14243 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14244 we must reset offsetting on VM-entry. See @bugref{6634}. */
14245 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14246 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14247 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14248 }
14249 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14250 {
14251 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14252 rcStrict = VINF_SUCCESS;
14253 }
14254 return rcStrict;
14255}
14256
14257
14258/**
14259 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
14260 */
14261HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14262{
14263 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14264
14265 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14266 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14267 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_TSC_AUX);
14268 AssertRCReturn(rc, rc);
14269
14270 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtscp(pVCpu, pVmxTransient->cbExitInstr);
14271 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14272 {
14273 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14274 we must reset offsetting on VM-reentry. See @bugref{6634}. */
14275 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14276 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14277 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14278 }
14279 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14280 {
14281 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14282 rcStrict = VINF_SUCCESS;
14283 }
14284 return rcStrict;
14285}
14286
14287
14288/**
14289 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
14290 */
14291HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14292{
14293 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14294
14295 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14296 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_CR0
14297 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS);
14298 AssertRCReturn(rc, rc);
14299
14300 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14301 rc = EMInterpretRdpmc(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
14302 if (RT_LIKELY(rc == VINF_SUCCESS))
14303 {
14304 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14305 Assert(pVmxTransient->cbExitInstr == 2);
14306 }
14307 else
14308 {
14309 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
14310 rc = VERR_EM_INTERPRETER;
14311 }
14312 return rc;
14313}
14314
14315
14316/**
14317 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
14318 */
14319HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14320{
14321 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14322
14323 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
14324 if (EMAreHypercallInstructionsEnabled(pVCpu))
14325 {
14326 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14327 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CR0
14328 | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
14329 AssertRCReturn(rc, rc);
14330
14331 /* Perform the hypercall. */
14332 rcStrict = GIMHypercall(pVCpu, &pVCpu->cpum.GstCtx);
14333 if (rcStrict == VINF_SUCCESS)
14334 {
14335 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14336 AssertRCReturn(rc, rc);
14337 }
14338 else
14339 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
14340 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
14341 || RT_FAILURE(rcStrict));
14342
14343 /* If the hypercall changes anything other than guest's general-purpose registers,
14344 we would need to reload the guest changed bits here before VM-entry. */
14345 }
14346 else
14347 Log4Func(("Hypercalls not enabled\n"));
14348
14349 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
14350 if (RT_FAILURE(rcStrict))
14351 {
14352 hmR0VmxSetPendingXcptUD(pVCpu);
14353 rcStrict = VINF_SUCCESS;
14354 }
14355
14356 return rcStrict;
14357}
14358
14359
14360/**
14361 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
14362 */
14363HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14364{
14365 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14366 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging || pVCpu->hm.s.fUsingDebugLoop);
14367
14368 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14369 hmR0VmxReadExitQualVmcs(pVmxTransient);
14370 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14371 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
14372 AssertRCReturn(rc, rc);
14373
14374 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpg(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->uExitQual);
14375
14376 if (rcStrict == VINF_SUCCESS || rcStrict == VINF_PGM_SYNC_CR3)
14377 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14378 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14379 {
14380 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14381 rcStrict = VINF_SUCCESS;
14382 }
14383 else
14384 AssertMsgFailed(("Unexpected IEMExecDecodedInvlpg(%#RX64) status: %Rrc\n", pVmxTransient->uExitQual,
14385 VBOXSTRICTRC_VAL(rcStrict)));
14386 return rcStrict;
14387}
14388
14389
14390/**
14391 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
14392 */
14393HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14394{
14395 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14396
14397 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14398 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14399 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_DS);
14400 AssertRCReturn(rc, rc);
14401
14402 VBOXSTRICTRC rcStrict = IEMExecDecodedMonitor(pVCpu, pVmxTransient->cbExitInstr);
14403 if (rcStrict == VINF_SUCCESS)
14404 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14405 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14406 {
14407 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14408 rcStrict = VINF_SUCCESS;
14409 }
14410
14411 return rcStrict;
14412}
14413
14414
14415/**
14416 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
14417 */
14418HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14419{
14420 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14421
14422 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14423 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14424 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14425 AssertRCReturn(rc, rc);
14426
14427 VBOXSTRICTRC rcStrict = IEMExecDecodedMwait(pVCpu, pVmxTransient->cbExitInstr);
14428 if (RT_SUCCESS(rcStrict))
14429 {
14430 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14431 if (EMMonitorWaitShouldContinue(pVCpu, &pVCpu->cpum.GstCtx))
14432 rcStrict = VINF_SUCCESS;
14433 }
14434
14435 return rcStrict;
14436}
14437
14438
14439/**
14440 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
14441 * VM-exit.
14442 */
14443HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14444{
14445 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14446 return VINF_EM_RESET;
14447}
14448
14449
14450/**
14451 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
14452 */
14453HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14454{
14455 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14456
14457 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14458 AssertRCReturn(rc, rc);
14459
14460 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS); /* Advancing the RIP above should've imported eflags. */
14461 if (EMShouldContinueAfterHalt(pVCpu, &pVCpu->cpum.GstCtx)) /* Requires eflags. */
14462 rc = VINF_SUCCESS;
14463 else
14464 rc = VINF_EM_HALT;
14465
14466 if (rc != VINF_SUCCESS)
14467 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
14468 return rc;
14469}
14470
14471
14472/**
14473 * VM-exit handler for instructions that result in a \#UD exception delivered to
14474 * the guest.
14475 */
14476HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14477{
14478 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14479 hmR0VmxSetPendingXcptUD(pVCpu);
14480 return VINF_SUCCESS;
14481}
14482
14483
14484/**
14485 * VM-exit handler for expiry of the VMX-preemption timer.
14486 */
14487HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14488{
14489 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14490
14491 /* If the VMX-preemption timer has expired, reinitialize the preemption timer on next VM-entry. */
14492 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14493
14494 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
14495 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
14496 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
14497 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
14498 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
14499}
14500
14501
14502/**
14503 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
14504 */
14505HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14506{
14507 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14508
14509 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14510 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14511 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_CR4);
14512 AssertRCReturn(rc, rc);
14513
14514 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbExitInstr);
14515 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
14516 : HM_CHANGED_RAISED_XCPT_MASK);
14517
14518 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14519 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
14520
14521 return rcStrict;
14522}
14523
14524
14525/**
14526 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
14527 */
14528HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14529{
14530 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14531 /** @todo Use VM-exit instruction information. */
14532 return VERR_EM_INTERPRETER;
14533}
14534
14535
14536/**
14537 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error
14538 * VM-exit.
14539 */
14540HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14541{
14542 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14543 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14544 AssertRCReturn(rc, rc);
14545
14546 rc = hmR0VmxCheckVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
14547 if (RT_FAILURE(rc))
14548 return rc;
14549
14550 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
14551 NOREF(uInvalidReason);
14552
14553#ifdef VBOX_STRICT
14554 uint32_t fIntrState;
14555 uint64_t u64Val;
14556 hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
14557 hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
14558 hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
14559
14560 Log4(("uInvalidReason %u\n", uInvalidReason));
14561 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
14562 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
14563 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
14564
14565 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState); AssertRC(rc);
14566 Log4(("VMX_VMCS32_GUEST_INT_STATE %#RX32\n", fIntrState));
14567 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Val); AssertRC(rc);
14568 Log4(("VMX_VMCS_GUEST_CR0 %#RX64\n", u64Val));
14569 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_MASK, &u64Val); AssertRC(rc);
14570 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RX64\n", u64Val));
14571 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Val); AssertRC(rc);
14572 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
14573 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_MASK, &u64Val); AssertRC(rc);
14574 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RX64\n", u64Val));
14575 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Val); AssertRC(rc);
14576 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
14577 if (pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging)
14578 {
14579 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
14580 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
14581 }
14582 hmR0DumpRegs(pVCpu, HM_DUMP_REG_FLAGS_ALL);
14583#endif
14584
14585 return VERR_VMX_INVALID_GUEST_STATE;
14586}
14587
14588/**
14589 * VM-exit handler for all undefined/unexpected reasons. Should never happen.
14590 */
14591HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUnexpected(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14592{
14593 /*
14594 * Cummulative notes of all recognized but unexpected VM-exits.
14595 *
14596 * 1. This does -not- cover scenarios like like a page-fault VM-exit occurring when
14597 * nested-paging is used.
14598 *
14599 * 2. Any instruction that causes a VM-exit unconditionally (for e.g. VMXON) must be
14600 * emulated or a #UD must be raised in the guest. Therefore, we should -not- be using
14601 * this function (and thereby stop VM execution) for handling such instructions.
14602 *
14603 *
14604 * VMX_EXIT_INIT_SIGNAL:
14605 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
14606 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these
14607 * VM-exits. However, we should not receive INIT signals VM-exit while executing a VM.
14608 *
14609 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery"
14610 * See Intel spec. 29.3 "VMX Instructions" for "VMXON".
14611 * See Intel spec. "23.8 Restrictions on VMX operation".
14612 *
14613 * VMX_EXIT_SIPI:
14614 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest
14615 * activity state is used. We don't make use of it as our guests don't have direct
14616 * access to the host local APIC.
14617 *
14618 * See Intel spec. 25.3 "Other Causes of VM-exits".
14619 *
14620 * VMX_EXIT_IO_SMI:
14621 * VMX_EXIT_SMI:
14622 * This can only happen if we support dual-monitor treatment of SMI, which can be
14623 * activated by executing VMCALL in VMX root operation. Only an STM (SMM transfer
14624 * monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL in
14625 * VMX root mode or receive an SMI. If we get here, something funny is going on.
14626 *
14627 * See Intel spec. 33.15.6 "Activating the Dual-Monitor Treatment"
14628 * See Intel spec. 25.3 "Other Causes of VM-Exits"
14629 *
14630 * VMX_EXIT_ERR_MSR_LOAD:
14631 * Failures while loading MSRs are part of the VM-entry MSR-load area are unexpected
14632 * and typically indicates a bug in the hypervisor code. We thus cannot not resume
14633 * execution.
14634 *
14635 * See Intel spec. 26.7 "VM-Entry Failures During Or After Loading Guest State".
14636 *
14637 * VMX_EXIT_ERR_MACHINE_CHECK:
14638 * Machine check exceptions indicates a fatal/unrecoverable hardware condition
14639 * including but not limited to system bus, ECC, parity, cache and TLB errors. A
14640 * #MC exception abort class exception is raised. We thus cannot assume a
14641 * reasonable chance of continuing any sort of execution and we bail.
14642 *
14643 * See Intel spec. 15.1 "Machine-check Architecture".
14644 * See Intel spec. 27.1 "Architectural State Before A VM Exit".
14645 *
14646 * VMX_EXIT_PML_FULL:
14647 * VMX_EXIT_VIRTUALIZED_EOI:
14648 * VMX_EXIT_APIC_WRITE:
14649 * We do not currently support any of these features and thus they are all unexpected
14650 * VM-exits.
14651 *
14652 * VMX_EXIT_GDTR_IDTR_ACCESS:
14653 * VMX_EXIT_LDTR_TR_ACCESS:
14654 * VMX_EXIT_RDRAND:
14655 * VMX_EXIT_RSM:
14656 * VMX_EXIT_VMFUNC:
14657 * VMX_EXIT_ENCLS:
14658 * VMX_EXIT_RDSEED:
14659 * VMX_EXIT_XSAVES:
14660 * VMX_EXIT_XRSTORS:
14661 * VMX_EXIT_UMWAIT:
14662 * VMX_EXIT_TPAUSE:
14663 * These VM-exits are -not- caused unconditionally by execution of the corresponding
14664 * instruction. Any VM-exit for these instructions indicate a hardware problem,
14665 * unsupported CPU modes (like SMM) or potentially corrupt VMCS controls.
14666 *
14667 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
14668 */
14669 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14670 AssertMsgFailed(("Unexpected VM-exit %u\n", pVmxTransient->uExitReason));
14671 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14672}
14673
14674
14675/**
14676 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
14677 */
14678HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14679{
14680 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14681
14682 /** @todo Optimize this: We currently drag in in the whole MSR state
14683 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
14684 * MSRs required. That would require changes to IEM and possibly CPUM too.
14685 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
14686 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14687 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
14688 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
14689 switch (idMsr)
14690 {
14691 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
14692 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
14693 }
14694
14695 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14696 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
14697 AssertRCReturn(rc, rc);
14698
14699 Log4Func(("ecx=%#RX32\n", idMsr));
14700
14701#ifdef VBOX_STRICT
14702 Assert(!pVmxTransient->fIsNestedGuest);
14703 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
14704 {
14705 if ( hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr)
14706 && idMsr != MSR_K6_EFER)
14707 {
14708 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", idMsr));
14709 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14710 }
14711 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14712 {
14713 Assert(pVmcsInfo->pvMsrBitmap);
14714 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
14715 if (fMsrpm & VMXMSRPM_ALLOW_RD)
14716 {
14717 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", idMsr));
14718 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14719 }
14720 }
14721 }
14722#endif
14723
14724 VBOXSTRICTRC rcStrict = IEMExecDecodedRdmsr(pVCpu, pVmxTransient->cbExitInstr);
14725 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
14726 if (rcStrict == VINF_SUCCESS)
14727 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
14728 | HM_CHANGED_GUEST_RAX | HM_CHANGED_GUEST_RDX);
14729 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14730 {
14731 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14732 rcStrict = VINF_SUCCESS;
14733 }
14734 else
14735 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_READ, ("Unexpected IEMExecDecodedRdmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
14736
14737 return rcStrict;
14738}
14739
14740
14741/**
14742 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
14743 */
14744HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14745{
14746 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14747
14748 /** @todo Optimize this: We currently drag in in the whole MSR state
14749 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
14750 * MSRs required. That would require changes to IEM and possibly CPUM too.
14751 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
14752 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
14753 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
14754
14755 /*
14756 * The FS and GS base MSRs are not part of the above all-MSRs mask.
14757 * Although we don't need to fetch the base as it will be overwritten shortly, while
14758 * loading guest-state we would also load the entire segment register including limit
14759 * and attributes and thus we need to load them here.
14760 */
14761 switch (idMsr)
14762 {
14763 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
14764 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
14765 }
14766
14767 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14768 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14769 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
14770 AssertRCReturn(rc, rc);
14771
14772 Log4Func(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", idMsr, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.eax));
14773
14774 VBOXSTRICTRC rcStrict = IEMExecDecodedWrmsr(pVCpu, pVmxTransient->cbExitInstr);
14775 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
14776
14777 if (rcStrict == VINF_SUCCESS)
14778 {
14779 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14780
14781 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
14782 if ( idMsr == MSR_IA32_APICBASE
14783 || ( idMsr >= MSR_IA32_X2APIC_START
14784 && idMsr <= MSR_IA32_X2APIC_END))
14785 {
14786 /*
14787 * We've already saved the APIC related guest-state (TPR) in post-run phase.
14788 * When full APIC register virtualization is implemented we'll have to make
14789 * sure APIC state is saved from the VMCS before IEM changes it.
14790 */
14791 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
14792 }
14793 else if (idMsr == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
14794 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14795 else if (idMsr == MSR_K6_EFER)
14796 {
14797 /*
14798 * If the guest touches the EFER MSR we need to update the VM-Entry and VM-Exit controls
14799 * as well, even if it is -not- touching bits that cause paging mode changes (LMA/LME).
14800 * We care about the other bits as well, SCE and NXE. See @bugref{7368}.
14801 */
14802 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
14803 }
14804
14805 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not used. */
14806 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
14807 {
14808 switch (idMsr)
14809 {
14810 case MSR_IA32_SYSENTER_CS: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
14811 case MSR_IA32_SYSENTER_EIP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
14812 case MSR_IA32_SYSENTER_ESP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
14813 case MSR_K8_FS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_FS); break;
14814 case MSR_K8_GS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_GS); break;
14815 case MSR_K6_EFER: /* Nothing to do, already handled above. */ break;
14816 default:
14817 {
14818 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14819 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_LAZY_MSRS);
14820 else if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
14821 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
14822 break;
14823 }
14824 }
14825 }
14826#ifdef VBOX_STRICT
14827 else
14828 {
14829 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
14830 switch (idMsr)
14831 {
14832 case MSR_IA32_SYSENTER_CS:
14833 case MSR_IA32_SYSENTER_EIP:
14834 case MSR_IA32_SYSENTER_ESP:
14835 case MSR_K8_FS_BASE:
14836 case MSR_K8_GS_BASE:
14837 {
14838 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", idMsr));
14839 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14840 }
14841
14842 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
14843 default:
14844 {
14845 if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
14846 {
14847 /* EFER MSR writes are always intercepted. */
14848 if (idMsr != MSR_K6_EFER)
14849 {
14850 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
14851 idMsr));
14852 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14853 }
14854 }
14855
14856 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14857 {
14858 Assert(pVmcsInfo->pvMsrBitmap);
14859 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
14860 if (fMsrpm & VMXMSRPM_ALLOW_WR)
14861 {
14862 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", idMsr));
14863 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14864 }
14865 }
14866 break;
14867 }
14868 }
14869 }
14870#endif /* VBOX_STRICT */
14871 }
14872 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14873 {
14874 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14875 rcStrict = VINF_SUCCESS;
14876 }
14877 else
14878 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_WRITE, ("Unexpected IEMExecDecodedWrmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
14879
14880 return rcStrict;
14881}
14882
14883
14884/**
14885 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
14886 */
14887HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14888{
14889 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14890
14891 /** @todo The guest has likely hit a contended spinlock. We might want to
14892 * poke a schedule different guest VCPU. */
14893 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14894 if (RT_SUCCESS(rc))
14895 return VINF_EM_RAW_INTERRUPT;
14896
14897 AssertMsgFailed(("hmR0VmxExitPause: Failed to increment RIP. rc=%Rrc\n", rc));
14898 return rc;
14899}
14900
14901
14902/**
14903 * VM-exit handler for when the TPR value is lowered below the specified
14904 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
14905 */
14906HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14907{
14908 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14909 Assert(pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
14910
14911 /*
14912 * The TPR shadow would've been synced with the APIC TPR in the post-run phase.
14913 * We'll re-evaluate pending interrupts and inject them before the next VM
14914 * entry so we can just continue execution here.
14915 */
14916 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
14917 return VINF_SUCCESS;
14918}
14919
14920
14921/**
14922 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
14923 * VM-exit.
14924 *
14925 * @retval VINF_SUCCESS when guest execution can continue.
14926 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
14927 * @retval VERR_EM_RESCHEDULE_REM when we need to return to ring-3 due to
14928 * incompatible guest state for VMX execution (real-on-v86 case).
14929 */
14930HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14931{
14932 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14933 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
14934
14935 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14936 hmR0VmxReadExitQualVmcs(pVmxTransient);
14937 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14938
14939 VBOXSTRICTRC rcStrict;
14940 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
14941 uint64_t const uExitQual = pVmxTransient->uExitQual;
14942 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(uExitQual);
14943 switch (uAccessType)
14944 {
14945 /*
14946 * MOV to CRx.
14947 */
14948 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
14949 {
14950 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14951 AssertRCReturn(rc, rc);
14952
14953 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
14954 uint32_t const uOldCr0 = pVCpu->cpum.GstCtx.cr0;
14955 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
14956 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
14957
14958 /*
14959 * MOV to CR3 only cause a VM-exit when one or more of the following are true:
14960 * - When nested paging isn't used.
14961 * - If the guest doesn't have paging enabled (intercept CR3 to update shadow page tables).
14962 * - We are executing in the VM debug loop.
14963 */
14964 Assert( iCrReg != 3
14965 || !pVM->hm.s.fNestedPaging
14966 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
14967 || pVCpu->hm.s.fUsingDebugLoop);
14968
14969 /* MOV to CR8 writes only cause VM-exits when TPR shadow is not used. */
14970 Assert( iCrReg != 8
14971 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
14972
14973 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
14974 AssertMsg( rcStrict == VINF_SUCCESS
14975 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
14976
14977 /*
14978 * This is a kludge for handling switches back to real mode when we try to use
14979 * V86 mode to run real mode code directly. Problem is that V86 mode cannot
14980 * deal with special selector values, so we have to return to ring-3 and run
14981 * there till the selector values are V86 mode compatible.
14982 *
14983 * Note! Using VINF_EM_RESCHEDULE_REM here rather than VINF_EM_RESCHEDULE since the
14984 * latter is an alias for VINF_IEM_RAISED_XCPT which is asserted at the end of
14985 * this function.
14986 */
14987 if ( iCrReg == 0
14988 && rcStrict == VINF_SUCCESS
14989 && !pVM->hm.s.vmx.fUnrestrictedGuest
14990 && CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx)
14991 && (uOldCr0 & X86_CR0_PE)
14992 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
14993 {
14994 /** @todo Check selectors rather than returning all the time. */
14995 Assert(!pVmxTransient->fIsNestedGuest);
14996 Log4Func(("CR0 write, back to real mode -> VINF_EM_RESCHEDULE_REM\n"));
14997 rcStrict = VINF_EM_RESCHEDULE_REM;
14998 }
14999 break;
15000 }
15001
15002 /*
15003 * MOV from CRx.
15004 */
15005 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
15006 {
15007 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
15008 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
15009
15010 /*
15011 * MOV from CR3 only cause a VM-exit when one or more of the following are true:
15012 * - When nested paging isn't used.
15013 * - If the guest doesn't have paging enabled (pass guest's CR3 rather than our identity mapped CR3).
15014 * - We are executing in the VM debug loop.
15015 */
15016 Assert( iCrReg != 3
15017 || !pVM->hm.s.fNestedPaging
15018 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
15019 || pVCpu->hm.s.fUsingDebugLoop);
15020
15021 /* MOV from CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
15022 Assert( iCrReg != 8
15023 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
15024
15025 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
15026 break;
15027 }
15028
15029 /*
15030 * CLTS (Clear Task-Switch Flag in CR0).
15031 */
15032 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
15033 {
15034 rcStrict = hmR0VmxExitClts(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr);
15035 break;
15036 }
15037
15038 /*
15039 * LMSW (Load Machine-Status Word into CR0).
15040 * LMSW cannot clear CR0.PE, so no fRealOnV86Active kludge needed here.
15041 */
15042 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW:
15043 {
15044 RTGCPTR GCPtrEffDst;
15045 uint8_t const cbInstr = pVmxTransient->cbExitInstr;
15046 uint16_t const uMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(uExitQual);
15047 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(uExitQual);
15048 if (fMemOperand)
15049 {
15050 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
15051 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
15052 }
15053 else
15054 GCPtrEffDst = NIL_RTGCPTR;
15055 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmcsInfo, cbInstr, uMsw, GCPtrEffDst);
15056 break;
15057 }
15058
15059 default:
15060 {
15061 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
15062 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
15063 }
15064 }
15065
15066 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS))
15067 == (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS));
15068 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15069
15070 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
15071 NOREF(pVM);
15072 return rcStrict;
15073}
15074
15075
15076/**
15077 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
15078 * VM-exit.
15079 */
15080HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15081{
15082 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15083 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
15084
15085 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15086 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15087 hmR0VmxReadExitQualVmcs(pVmxTransient);
15088 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15089 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_SREG_MASK
15090 | CPUMCTX_EXTRN_EFER);
15091 /* EFER MSR also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
15092 AssertRCReturn(rc, rc);
15093
15094 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
15095 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
15096 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
15097 bool const fIOWrite = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
15098 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
15099 bool const fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
15100 bool const fDbgStepping = pVCpu->hm.s.fSingleInstruction;
15101 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
15102
15103 /*
15104 * Update exit history to see if this exit can be optimized.
15105 */
15106 VBOXSTRICTRC rcStrict;
15107 PCEMEXITREC pExitRec = NULL;
15108 if ( !fGstStepping
15109 && !fDbgStepping)
15110 pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15111 !fIOString
15112 ? !fIOWrite
15113 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_READ)
15114 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_WRITE)
15115 : !fIOWrite
15116 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_READ)
15117 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_WRITE),
15118 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15119 if (!pExitRec)
15120 {
15121 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
15122 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving result in AL/AX/EAX. */
15123
15124 uint32_t const cbValue = s_aIOSizes[uIOSize];
15125 uint32_t const cbInstr = pVmxTransient->cbExitInstr;
15126 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
15127 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15128 if (fIOString)
15129 {
15130 /*
15131 * INS/OUTS - I/O String instruction.
15132 *
15133 * Use instruction-information if available, otherwise fall back on
15134 * interpreting the instruction.
15135 */
15136 Log4Func(("cs:rip=%#04x:%#RX64 %#06x/%u %c str\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15137 AssertReturn(pCtx->dx == uIOPort, VERR_VMX_IPE_2);
15138 bool const fInsOutsInfo = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS);
15139 if (fInsOutsInfo)
15140 {
15141 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15142 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
15143 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
15144 IEMMODE const enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
15145 bool const fRep = VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual);
15146 if (fIOWrite)
15147 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
15148 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
15149 else
15150 {
15151 /*
15152 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
15153 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
15154 * See Intel Instruction spec. for "INS".
15155 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
15156 */
15157 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
15158 }
15159 }
15160 else
15161 rcStrict = IEMExecOne(pVCpu);
15162
15163 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15164 fUpdateRipAlready = true;
15165 }
15166 else
15167 {
15168 /*
15169 * IN/OUT - I/O instruction.
15170 */
15171 Log4Func(("cs:rip=%04x:%08RX64 %#06x/%u %c\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15172 uint32_t const uAndVal = s_aIOOpAnd[uIOSize];
15173 Assert(!VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual));
15174 if (fIOWrite)
15175 {
15176 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pCtx->eax & uAndVal, cbValue);
15177 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
15178 if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15179 && !pCtx->eflags.Bits.u1TF)
15180 rcStrict = EMRZSetPendingIoPortWrite(pVCpu, uIOPort, cbInstr, cbValue, pCtx->eax & uAndVal);
15181 }
15182 else
15183 {
15184 uint32_t u32Result = 0;
15185 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
15186 if (IOM_SUCCESS(rcStrict))
15187 {
15188 /* Save result of I/O IN instr. in AL/AX/EAX. */
15189 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Result & uAndVal);
15190 }
15191 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15192 && !pCtx->eflags.Bits.u1TF)
15193 rcStrict = EMRZSetPendingIoPortRead(pVCpu, uIOPort, cbInstr, cbValue);
15194 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
15195 }
15196 }
15197
15198 if (IOM_SUCCESS(rcStrict))
15199 {
15200 if (!fUpdateRipAlready)
15201 {
15202 hmR0VmxAdvanceGuestRipBy(pVCpu, cbInstr);
15203 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15204 }
15205
15206 /*
15207 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru
15208 * while booting Fedora 17 64-bit guest.
15209 *
15210 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
15211 */
15212 if (fIOString)
15213 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RFLAGS);
15214
15215 /*
15216 * If any I/O breakpoints are armed, we need to check if one triggered
15217 * and take appropriate action.
15218 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
15219 */
15220 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_DR7);
15221 AssertRCReturn(rc, rc);
15222
15223 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
15224 * execution engines about whether hyper BPs and such are pending. */
15225 uint32_t const uDr7 = pCtx->dr[7];
15226 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
15227 && X86_DR7_ANY_RW_IO(uDr7)
15228 && (pCtx->cr4 & X86_CR4_DE))
15229 || DBGFBpIsHwIoArmed(pVM)))
15230 {
15231 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
15232
15233 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
15234 VMMRZCallRing3Disable(pVCpu);
15235 HM_DISABLE_PREEMPT(pVCpu);
15236
15237 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
15238
15239 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, uIOPort, cbValue);
15240 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
15241 {
15242 /* Raise #DB. */
15243 if (fIsGuestDbgActive)
15244 ASMSetDR6(pCtx->dr[6]);
15245 if (pCtx->dr[7] != uDr7)
15246 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_DR7;
15247
15248 hmR0VmxSetPendingXcptDB(pVCpu);
15249 }
15250 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
15251 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
15252 else if ( rcStrict2 != VINF_SUCCESS
15253 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
15254 rcStrict = rcStrict2;
15255 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
15256
15257 HM_RESTORE_PREEMPT();
15258 VMMRZCallRing3Enable(pVCpu);
15259 }
15260 }
15261
15262#ifdef VBOX_STRICT
15263 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15264 || rcStrict == VINF_EM_PENDING_R3_IOPORT_READ)
15265 Assert(!fIOWrite);
15266 else if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15267 || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
15268 || rcStrict == VINF_EM_PENDING_R3_IOPORT_WRITE)
15269 Assert(fIOWrite);
15270 else
15271 {
15272# if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
15273 * statuses, that the VMM device and some others may return. See
15274 * IOM_SUCCESS() for guidance. */
15275 AssertMsg( RT_FAILURE(rcStrict)
15276 || rcStrict == VINF_SUCCESS
15277 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
15278 || rcStrict == VINF_EM_DBG_BREAKPOINT
15279 || rcStrict == VINF_EM_RAW_GUEST_TRAP
15280 || rcStrict == VINF_EM_RAW_TO_R3
15281 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15282# endif
15283 }
15284#endif
15285 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
15286 }
15287 else
15288 {
15289 /*
15290 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
15291 */
15292 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15293 AssertRCReturn(rc2, rc2);
15294 STAM_COUNTER_INC(!fIOString ? fIOWrite ? &pVCpu->hm.s.StatExitIOWrite : &pVCpu->hm.s.StatExitIORead
15295 : fIOWrite ? &pVCpu->hm.s.StatExitIOStringWrite : &pVCpu->hm.s.StatExitIOStringRead);
15296 Log4(("IOExit/%u: %04x:%08RX64: %s%s%s %#x LB %u -> EMHistoryExec\n",
15297 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15298 VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual) ? "REP " : "",
15299 fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOSize));
15300
15301 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15302 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15303
15304 Log4(("IOExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15305 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15306 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15307 }
15308 return rcStrict;
15309}
15310
15311
15312/**
15313 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
15314 * VM-exit.
15315 */
15316HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15317{
15318 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15319
15320 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
15321 hmR0VmxReadExitQualVmcs(pVmxTransient);
15322 if (VMX_EXIT_QUAL_TASK_SWITCH_TYPE(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT)
15323 {
15324 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15325 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
15326 {
15327 uint32_t uErrCode;
15328 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uIdtVectoringInfo))
15329 {
15330 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15331 uErrCode = pVmxTransient->uIdtVectoringErrorCode;
15332 }
15333 else
15334 uErrCode = 0;
15335
15336 RTGCUINTPTR GCPtrFaultAddress;
15337 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(pVmxTransient->uIdtVectoringInfo))
15338 GCPtrFaultAddress = pVCpu->cpum.GstCtx.cr2;
15339 else
15340 GCPtrFaultAddress = 0;
15341
15342 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15343
15344 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
15345 pVmxTransient->cbExitInstr, uErrCode, GCPtrFaultAddress);
15346
15347 Log4Func(("Pending event. uIntType=%#x uVector=%#x\n", VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo),
15348 VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo)));
15349 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15350 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15351 }
15352 }
15353
15354 /* Fall back to the interpreter to emulate the task-switch. */
15355 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15356 return VERR_EM_INTERPRETER;
15357}
15358
15359
15360/**
15361 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
15362 */
15363HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15364{
15365 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15366
15367 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15368 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
15369 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15370 AssertRC(rc);
15371 return VINF_EM_DBG_STEPPED;
15372}
15373
15374
15375/**
15376 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
15377 */
15378HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15379{
15380 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15381 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
15382
15383 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15384 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15385 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15386 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15387 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15388
15389 /*
15390 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15391 */
15392 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15393 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15394 {
15395 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
15396 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
15397 {
15398 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15399 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15400 }
15401 }
15402 else
15403 {
15404 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15405 return rcStrict;
15406 }
15407
15408 /* IOMMIOPhysHandler() below may call into IEM, save the necessary state. */
15409 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15410 hmR0VmxReadExitQualVmcs(pVmxTransient);
15411 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15412 AssertRCReturn(rc, rc);
15413
15414 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
15415 uint32_t const uAccessType = VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual);
15416 switch (uAccessType)
15417 {
15418 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
15419 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
15420 {
15421 AssertMsg( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
15422 || VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual) != XAPIC_OFF_TPR,
15423 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
15424
15425 RTGCPHYS GCPhys = pVCpu->hm.s.vmx.u64GstMsrApicBase; /* Always up-to-date, as it is not part of the VMCS. */
15426 GCPhys &= PAGE_BASE_GC_MASK;
15427 GCPhys += VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual);
15428 Log4Func(("Linear access uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
15429 VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual)));
15430
15431 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15432 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15433 rcStrict = IOMMMIOPhysHandler(pVM, pVCpu,
15434 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW,
15435 CPUMCTX2CORE(pCtx), GCPhys);
15436 Log4Func(("IOMMMIOPhysHandler returned %Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15437 if ( rcStrict == VINF_SUCCESS
15438 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15439 || rcStrict == VERR_PAGE_NOT_PRESENT)
15440 {
15441 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15442 | HM_CHANGED_GUEST_APIC_TPR);
15443 rcStrict = VINF_SUCCESS;
15444 }
15445 break;
15446 }
15447
15448 default:
15449 {
15450 Log4Func(("uAccessType=%#x\n", uAccessType));
15451 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
15452 break;
15453 }
15454 }
15455
15456 if (rcStrict != VINF_SUCCESS)
15457 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
15458 return rcStrict;
15459}
15460
15461
15462/**
15463 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
15464 * VM-exit.
15465 */
15466HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15467{
15468 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15469 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15470
15471 /* We might get this VM-exit if the nested-guest is not intercepting MOV DRx accesses. */
15472 if (!pVmxTransient->fIsNestedGuest)
15473 {
15474 /* We should -not- get this VM-exit if the guest's debug registers were active. */
15475 if (pVmxTransient->fWasGuestDebugStateActive)
15476 {
15477 AssertMsgFailed(("Unexpected MOV DRx exit\n"));
15478 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
15479 }
15480
15481 if ( !pVCpu->hm.s.fSingleInstruction
15482 && !pVmxTransient->fWasHyperDebugStateActive)
15483 {
15484 Assert(!DBGFIsStepping(pVCpu));
15485 Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB));
15486
15487 /* Don't intercept MOV DRx any more. */
15488 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
15489 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15490 AssertRC(rc);
15491
15492 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
15493 VMMRZCallRing3Disable(pVCpu);
15494 HM_DISABLE_PREEMPT(pVCpu);
15495
15496 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
15497 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
15498 Assert(CPUMIsGuestDebugStateActive(pVCpu));
15499
15500 HM_RESTORE_PREEMPT();
15501 VMMRZCallRing3Enable(pVCpu);
15502
15503#ifdef VBOX_WITH_STATISTICS
15504 hmR0VmxReadExitQualVmcs(pVmxTransient);
15505 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
15506 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
15507 else
15508 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
15509#endif
15510 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
15511 return VINF_SUCCESS;
15512 }
15513 }
15514
15515 /*
15516 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER MSR, CS.
15517 * The EFER MSR is always up-to-date.
15518 * Update the segment registers and DR7 from the CPU.
15519 */
15520 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15521 hmR0VmxReadExitQualVmcs(pVmxTransient);
15522 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_DR7);
15523 AssertRCReturn(rc, rc);
15524 Log4Func(("cs:rip=%#04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
15525
15526 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15527 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
15528 {
15529 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pCtx),
15530 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual),
15531 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual));
15532 if (RT_SUCCESS(rc))
15533 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
15534 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
15535 }
15536 else
15537 {
15538 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pCtx),
15539 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual),
15540 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual));
15541 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
15542 }
15543
15544 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
15545 if (RT_SUCCESS(rc))
15546 {
15547 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15548 AssertRCReturn(rc2, rc2);
15549 return VINF_SUCCESS;
15550 }
15551 return rc;
15552}
15553
15554
15555/**
15556 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
15557 * Conditional VM-exit.
15558 */
15559HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15560{
15561 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15562 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
15563
15564 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15565 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15566 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15567 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15568 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15569
15570 /*
15571 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15572 */
15573 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15574 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15575 {
15576 /*
15577 * In the unlikely case where delivering an event causes an EPT misconfig (MMIO), go back to
15578 * instruction emulation to inject the original event. Otherwise, injecting the original event
15579 * using hardware-assisted VMX would would trigger the same EPT misconfig VM-exit again.
15580 */
15581 if (!pVCpu->hm.s.Event.fPending)
15582 { /* likely */ }
15583 else
15584 {
15585 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15586#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
15587 /** @todo NSTVMX: Think about how this should be handled. */
15588 if (pVmxTransient->fIsNestedGuest)
15589 return VERR_VMX_IPE_3;
15590#endif
15591 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15592 }
15593 }
15594 else
15595 {
15596 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15597 return rcStrict;
15598 }
15599
15600 /*
15601 * Get sufficent state and update the exit history entry.
15602 */
15603 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15604 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
15605 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15606 AssertRCReturn(rc, rc);
15607
15608 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
15609 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15610 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_MMIO),
15611 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15612 if (!pExitRec)
15613 {
15614 /*
15615 * If we succeed, resume guest execution.
15616 * If we fail in interpreting the instruction because we couldn't get the guest physical address
15617 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
15618 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
15619 * weird case. See @bugref{6043}.
15620 */
15621 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15622 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15623 rcStrict = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pCtx), GCPhys, UINT32_MAX);
15624 Log4Func(("At %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pCtx->rip, VBOXSTRICTRC_VAL(rcStrict)));
15625 if ( rcStrict == VINF_SUCCESS
15626 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15627 || rcStrict == VERR_PAGE_NOT_PRESENT)
15628 {
15629 /* Successfully handled MMIO operation. */
15630 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15631 | HM_CHANGED_GUEST_APIC_TPR);
15632 rcStrict = VINF_SUCCESS;
15633 }
15634 }
15635 else
15636 {
15637 /*
15638 * Frequent exit or something needing probing. Call EMHistoryExec.
15639 */
15640 Log4(("EptMisscfgExit/%u: %04x:%08RX64: %RGp -> EMHistoryExec\n",
15641 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPhys));
15642
15643 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15644 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15645
15646 Log4(("EptMisscfgExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15647 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15648 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15649 }
15650 return rcStrict;
15651}
15652
15653
15654/**
15655 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
15656 * VM-exit.
15657 */
15658HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15659{
15660 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15661 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
15662
15663 hmR0VmxReadExitQualVmcs(pVmxTransient);
15664 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15665 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15666 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15667 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15668 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15669
15670 /*
15671 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15672 */
15673 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15674 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15675 {
15676 /*
15677 * If delivery of an event causes an EPT violation (true nested #PF and not MMIO),
15678 * we shall resolve the nested #PF and re-inject the original event.
15679 */
15680 if (pVCpu->hm.s.Event.fPending)
15681 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflectNPF);
15682 }
15683 else
15684 {
15685 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15686 return rcStrict;
15687 }
15688
15689 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15690 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
15691 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15692 AssertRCReturn(rc, rc);
15693
15694 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
15695 uint64_t const uExitQual = pVmxTransient->uExitQual;
15696 AssertMsg(((pVmxTransient->uExitQual >> 7) & 3) != 2, ("%#RX64", uExitQual));
15697
15698 RTGCUINT uErrorCode = 0;
15699 if (uExitQual & VMX_EXIT_QUAL_EPT_INSTR_FETCH)
15700 uErrorCode |= X86_TRAP_PF_ID;
15701 if (uExitQual & VMX_EXIT_QUAL_EPT_DATA_WRITE)
15702 uErrorCode |= X86_TRAP_PF_RW;
15703 if (uExitQual & VMX_EXIT_QUAL_EPT_ENTRY_PRESENT)
15704 uErrorCode |= X86_TRAP_PF_P;
15705
15706 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15707 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15708 Log4Func(("at %#RX64 (%#RX64 errcode=%#x) cs:rip=%#04x:%#RX64\n", GCPhys, uExitQual, uErrorCode, pCtx->cs.Sel, pCtx->rip));
15709
15710 /*
15711 * Handle the pagefault trap for the nested shadow table.
15712 */
15713 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
15714 rcStrict = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pCtx), GCPhys);
15715 TRPMResetTrap(pVCpu);
15716
15717 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
15718 if ( rcStrict == VINF_SUCCESS
15719 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15720 || rcStrict == VERR_PAGE_NOT_PRESENT)
15721 {
15722 /* Successfully synced our nested page tables. */
15723 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
15724 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS);
15725 return VINF_SUCCESS;
15726 }
15727
15728 Log4Func(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15729 return rcStrict;
15730}
15731
15732
15733#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
15734/**
15735 * VM-exit handler for VMCLEAR (VMX_EXIT_VMCLEAR). Unconditional VM-exit.
15736 */
15737HMVMX_EXIT_DECL hmR0VmxExitVmclear(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15738{
15739 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15740
15741 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15742 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15743 hmR0VmxReadExitQualVmcs(pVmxTransient);
15744 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15745 | CPUMCTX_EXTRN_HWVIRT
15746 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15747 AssertRCReturn(rc, rc);
15748
15749 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15750
15751 VMXVEXITINFO ExitInfo;
15752 RT_ZERO(ExitInfo);
15753 ExitInfo.uReason = pVmxTransient->uExitReason;
15754 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15755 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15756 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
15757 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15758
15759 VBOXSTRICTRC rcStrict = IEMExecDecodedVmclear(pVCpu, &ExitInfo);
15760 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15761 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15762 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15763 {
15764 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15765 rcStrict = VINF_SUCCESS;
15766 }
15767 return rcStrict;
15768}
15769
15770
15771/**
15772 * VM-exit handler for VMLAUNCH (VMX_EXIT_VMLAUNCH). Unconditional VM-exit.
15773 */
15774HMVMX_EXIT_DECL hmR0VmxExitVmlaunch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15775{
15776 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15777
15778 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMLAUNCH,
15779 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
15780 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15781 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15782 AssertRCReturn(rc, rc);
15783
15784 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15785
15786 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
15787 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMLAUNCH);
15788 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
15789 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15790 {
15791 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15792 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
15793 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
15794 }
15795 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15796 return rcStrict;
15797}
15798
15799
15800/**
15801 * VM-exit handler for VMPTRLD (VMX_EXIT_VMPTRLD). Unconditional VM-exit.
15802 */
15803HMVMX_EXIT_DECL hmR0VmxExitVmptrld(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15804{
15805 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15806
15807 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15808 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15809 hmR0VmxReadExitQualVmcs(pVmxTransient);
15810 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15811 | CPUMCTX_EXTRN_HWVIRT
15812 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15813 AssertRCReturn(rc, rc);
15814
15815 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15816
15817 VMXVEXITINFO ExitInfo;
15818 RT_ZERO(ExitInfo);
15819 ExitInfo.uReason = pVmxTransient->uExitReason;
15820 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15821 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15822 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
15823 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15824
15825 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrld(pVCpu, &ExitInfo);
15826 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15827 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15828 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15829 {
15830 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15831 rcStrict = VINF_SUCCESS;
15832 }
15833 return rcStrict;
15834}
15835
15836
15837/**
15838 * VM-exit handler for VMPTRST (VMX_EXIT_VMPTRST). Unconditional VM-exit.
15839 */
15840HMVMX_EXIT_DECL hmR0VmxExitVmptrst(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15841{
15842 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15843
15844 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15845 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15846 hmR0VmxReadExitQualVmcs(pVmxTransient);
15847 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15848 | CPUMCTX_EXTRN_HWVIRT
15849 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15850 AssertRCReturn(rc, rc);
15851
15852 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15853
15854 VMXVEXITINFO ExitInfo;
15855 RT_ZERO(ExitInfo);
15856 ExitInfo.uReason = pVmxTransient->uExitReason;
15857 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15858 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15859 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
15860 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
15861
15862 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrst(pVCpu, &ExitInfo);
15863 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15864 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15865 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15866 {
15867 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15868 rcStrict = VINF_SUCCESS;
15869 }
15870 return rcStrict;
15871}
15872
15873
15874/**
15875 * VM-exit handler for VMREAD (VMX_EXIT_VMREAD). Conditional VM-exit.
15876 */
15877HMVMX_EXIT_DECL hmR0VmxExitVmread(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15878{
15879 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15880
15881 /*
15882 * Strictly speaking we should not get VMREAD VM-exits for shadow VMCS fields and
15883 * thus might not need to import the shadow VMCS state, it's safer just in case
15884 * code elsewhere dares look at unsynced VMCS fields.
15885 */
15886 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15887 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15888 hmR0VmxReadExitQualVmcs(pVmxTransient);
15889 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15890 | CPUMCTX_EXTRN_HWVIRT
15891 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15892 AssertRCReturn(rc, rc);
15893
15894 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15895
15896 VMXVEXITINFO ExitInfo;
15897 RT_ZERO(ExitInfo);
15898 ExitInfo.uReason = pVmxTransient->uExitReason;
15899 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15900 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15901 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
15902 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
15903 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
15904
15905 VBOXSTRICTRC rcStrict = IEMExecDecodedVmread(pVCpu, &ExitInfo);
15906 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15907 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15908 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15909 {
15910 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15911 rcStrict = VINF_SUCCESS;
15912 }
15913 return rcStrict;
15914}
15915
15916
15917/**
15918 * VM-exit handler for VMRESUME (VMX_EXIT_VMRESUME). Unconditional VM-exit.
15919 */
15920HMVMX_EXIT_DECL hmR0VmxExitVmresume(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15921{
15922 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15923
15924 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMRESUME,
15925 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
15926 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15927 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15928 AssertRCReturn(rc, rc);
15929
15930 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15931
15932 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
15933 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMRESUME);
15934 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
15935 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15936 {
15937 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15938 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
15939 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
15940 }
15941 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15942 return rcStrict;
15943}
15944
15945
15946/**
15947 * VM-exit handler for VMWRITE (VMX_EXIT_VMWRITE). Conditional VM-exit.
15948 */
15949HMVMX_EXIT_DECL hmR0VmxExitVmwrite(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15950{
15951 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15952
15953 /*
15954 * Although we should not get VMWRITE VM-exits for shadow VMCS fields, since our HM hook
15955 * gets invoked when IEM's VMWRITE instruction emulation modifies the current VMCS and it
15956 * flags re-loading the entire shadow VMCS, we should save the entire shadow VMCS here.
15957 */
15958 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15959 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15960 hmR0VmxReadExitQualVmcs(pVmxTransient);
15961 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15962 | CPUMCTX_EXTRN_HWVIRT
15963 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15964 AssertRCReturn(rc, rc);
15965
15966 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15967
15968 VMXVEXITINFO ExitInfo;
15969 RT_ZERO(ExitInfo);
15970 ExitInfo.uReason = pVmxTransient->uExitReason;
15971 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15972 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15973 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
15974 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
15975 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15976
15977 VBOXSTRICTRC rcStrict = IEMExecDecodedVmwrite(pVCpu, &ExitInfo);
15978 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15979 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15980 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15981 {
15982 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15983 rcStrict = VINF_SUCCESS;
15984 }
15985 return rcStrict;
15986}
15987
15988
15989/**
15990 * VM-exit handler for VMXOFF (VMX_EXIT_VMXOFF). Unconditional VM-exit.
15991 */
15992HMVMX_EXIT_DECL hmR0VmxExitVmxoff(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15993{
15994 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15995
15996 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15997 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR4
15998 | CPUMCTX_EXTRN_HWVIRT
15999 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
16000 AssertRCReturn(rc, rc);
16001
16002 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16003
16004 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxoff(pVCpu, pVmxTransient->cbExitInstr);
16005 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16006 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_HWVIRT);
16007 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16008 {
16009 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16010 rcStrict = VINF_SUCCESS;
16011 }
16012 return rcStrict;
16013}
16014
16015
16016/**
16017 * VM-exit handler for VMXON (VMX_EXIT_VMXON). Unconditional VM-exit.
16018 */
16019HMVMX_EXIT_DECL hmR0VmxExitVmxon(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16020{
16021 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16022
16023 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16024 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16025 hmR0VmxReadExitQualVmcs(pVmxTransient);
16026 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16027 | CPUMCTX_EXTRN_HWVIRT
16028 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16029 AssertRCReturn(rc, rc);
16030
16031 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16032
16033 VMXVEXITINFO ExitInfo;
16034 RT_ZERO(ExitInfo);
16035 ExitInfo.uReason = pVmxTransient->uExitReason;
16036 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16037 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16038 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16039 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16040
16041 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxon(pVCpu, &ExitInfo);
16042 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16043 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16044 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16045 {
16046 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16047 rcStrict = VINF_SUCCESS;
16048 }
16049 return rcStrict;
16050}
16051
16052
16053/**
16054 * VM-exit handler for INVVPID (VMX_EXIT_INVVPID). Unconditional VM-exit.
16055 */
16056HMVMX_EXIT_DECL hmR0VmxExitInvvpid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16057{
16058 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16059
16060 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16061 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16062 hmR0VmxReadExitQualVmcs(pVmxTransient);
16063 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16064 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16065 AssertRCReturn(rc, rc);
16066
16067 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16068
16069 VMXVEXITINFO ExitInfo;
16070 RT_ZERO(ExitInfo);
16071 ExitInfo.uReason = pVmxTransient->uExitReason;
16072 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16073 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16074 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16075 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16076
16077 VBOXSTRICTRC rcStrict = IEMExecDecodedInvvpid(pVCpu, &ExitInfo);
16078 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16079 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16080 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16081 {
16082 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16083 rcStrict = VINF_SUCCESS;
16084 }
16085 return rcStrict;
16086}
16087#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16088/** @} */
16089
16090
16091#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16092/** @name Nested-guest VM-exit handlers.
16093 * @{
16094 */
16095/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16096/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Nested-guest VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16097/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16098
16099/**
16100 * Nested-guest VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
16101 * Conditional VM-exit.
16102 */
16103HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16104{
16105 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16106
16107 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16108
16109 uint64_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
16110 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
16111 Assert(VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo));
16112
16113 switch (uExitIntType)
16114 {
16115 /*
16116 * Physical NMIs:
16117 * We shouldn't direct host physical NMIs to the nested-guest. Dispatch it to the host.
16118 */
16119 case VMX_EXIT_INT_INFO_TYPE_NMI:
16120 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
16121
16122 /*
16123 * Hardware exceptions,
16124 * Software exceptions,
16125 * Privileged software exceptions:
16126 * Figure out if the exception must be delivered to the guest or the nested-guest.
16127 */
16128 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
16129 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
16130 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
16131 {
16132 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16133 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16134 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16135 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16136
16137 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16138 bool const fIntercept = CPUMIsGuestVmxXcptInterceptSet(pVCpu, pCtx, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo),
16139 pVmxTransient->uExitIntErrorCode);
16140 if (fIntercept)
16141 {
16142 /* Exit qualification is required for debug and page-fault exceptions. */
16143 hmR0VmxReadExitQualVmcs(pVmxTransient);
16144
16145 /*
16146 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged
16147 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
16148 * length. However, if delivery of a software interrupt, software exception or privileged
16149 * software exception causes a VM-exit, that too provides the VM-exit instruction length.
16150 */
16151 VMXVEXITINFO ExitInfo;
16152 RT_ZERO(ExitInfo);
16153 ExitInfo.uReason = pVmxTransient->uExitReason;
16154 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16155 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16156
16157 VMXVEXITEVENTINFO ExitEventInfo;
16158 RT_ZERO(ExitEventInfo);
16159 ExitEventInfo.uExitIntInfo = pVmxTransient->uExitIntInfo;
16160 ExitEventInfo.uExitIntErrCode = pVmxTransient->uExitIntErrorCode;
16161 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16162 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16163
16164#ifdef DEBUG_ramshankar
16165 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16166 Log4Func(("exit_int_info=%#x err_code=%#x exit_qual=%#RX64\n", pVmxTransient->uExitIntInfo,
16167 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual));
16168 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
16169 {
16170 Log4Func(("idt_info=%#RX32 idt_errcode=%#RX32 cr2=%#RX64\n", pVmxTransient->uIdtVectoringInfo,
16171 pVmxTransient->uIdtVectoringErrorCode, pCtx->cr2));
16172 }
16173#endif
16174 return IEMExecVmxVmexitXcpt(pVCpu, &ExitInfo, &ExitEventInfo);
16175 }
16176
16177 /* Nested paging is currently a requirement, otherwise we would need to handle shadow #PFs in hmR0VmxExitXcptPF. */
16178 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
16179 return hmR0VmxExitXcpt(pVCpu, pVmxTransient);
16180 }
16181
16182 /*
16183 * Software interrupts:
16184 * VM-exits cannot be caused by software interrupts.
16185 *
16186 * External interrupts:
16187 * This should only happen when "acknowledge external interrupts on VM-exit"
16188 * control is set. However, we never set this when executing a guest or
16189 * nested-guest. For nested-guests it is emulated while injecting interrupts into
16190 * the guest.
16191 */
16192 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
16193 case VMX_EXIT_INT_INFO_TYPE_EXT_INT:
16194 default:
16195 {
16196 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
16197 return VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
16198 }
16199 }
16200}
16201
16202
16203/**
16204 * Nested-guest VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT).
16205 * Unconditional VM-exit.
16206 */
16207HMVMX_EXIT_DECL hmR0VmxExitTripleFaultNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16208{
16209 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16210 return IEMExecVmxVmexitTripleFault(pVCpu);
16211}
16212
16213
16214/**
16215 * Nested-guest VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
16216 */
16217HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16218{
16219 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16220
16221 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
16222 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16223 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16224}
16225
16226
16227/**
16228 * Nested-guest VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
16229 */
16230HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16231{
16232 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16233
16234 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT))
16235 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16236 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16237}
16238
16239
16240/**
16241 * Nested-guest VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH).
16242 * Unconditional VM-exit.
16243 */
16244HMVMX_EXIT_DECL hmR0VmxExitTaskSwitchNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16245{
16246 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16247
16248 hmR0VmxReadExitQualVmcs(pVmxTransient);
16249 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16250 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16251 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16252
16253 VMXVEXITINFO ExitInfo;
16254 RT_ZERO(ExitInfo);
16255 ExitInfo.uReason = pVmxTransient->uExitReason;
16256 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16257 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16258
16259 VMXVEXITEVENTINFO ExitEventInfo;
16260 RT_ZERO(ExitEventInfo);
16261 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16262 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16263 return IEMExecVmxVmexitTaskSwitch(pVCpu, &ExitInfo, &ExitEventInfo);
16264}
16265
16266
16267/**
16268 * Nested-guest VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
16269 */
16270HMVMX_EXIT_DECL hmR0VmxExitHltNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16271{
16272 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16273
16274 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_HLT_EXIT))
16275 {
16276 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16277 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16278 }
16279 return hmR0VmxExitHlt(pVCpu, pVmxTransient);
16280}
16281
16282
16283/**
16284 * Nested-guest VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
16285 */
16286HMVMX_EXIT_DECL hmR0VmxExitInvlpgNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16287{
16288 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16289
16290 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16291 {
16292 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16293 hmR0VmxReadExitQualVmcs(pVmxTransient);
16294
16295 VMXVEXITINFO ExitInfo;
16296 RT_ZERO(ExitInfo);
16297 ExitInfo.uReason = pVmxTransient->uExitReason;
16298 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16299 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16300 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16301 }
16302 return hmR0VmxExitInvlpg(pVCpu, pVmxTransient);
16303}
16304
16305
16306/**
16307 * Nested-guest VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
16308 */
16309HMVMX_EXIT_DECL hmR0VmxExitRdpmcNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16310{
16311 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16312
16313 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDPMC_EXIT))
16314 {
16315 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16316 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16317 }
16318 return hmR0VmxExitRdpmc(pVCpu, pVmxTransient);
16319}
16320
16321
16322/**
16323 * Nested-guest VM-exit handler for VMREAD (VMX_EXIT_VMREAD) and VMWRITE
16324 * (VMX_EXIT_VMWRITE). Conditional VM-exit.
16325 */
16326HMVMX_EXIT_DECL hmR0VmxExitVmreadVmwriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16327{
16328 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16329
16330 Assert( pVmxTransient->uExitReason == VMX_EXIT_VMREAD
16331 || pVmxTransient->uExitReason == VMX_EXIT_VMWRITE);
16332
16333 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16334
16335 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
16336 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16337 uint64_t u64VmcsField = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16338
16339 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
16340 if (!CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
16341 u64VmcsField &= UINT64_C(0xffffffff);
16342
16343 if (CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, pVmxTransient->uExitReason, u64VmcsField))
16344 {
16345 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16346 hmR0VmxReadExitQualVmcs(pVmxTransient);
16347
16348 VMXVEXITINFO ExitInfo;
16349 RT_ZERO(ExitInfo);
16350 ExitInfo.uReason = pVmxTransient->uExitReason;
16351 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16352 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16353 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16354 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16355 }
16356
16357 if (pVmxTransient->uExitReason == VMX_EXIT_VMREAD)
16358 return hmR0VmxExitVmread(pVCpu, pVmxTransient);
16359 return hmR0VmxExitVmwrite(pVCpu, pVmxTransient);
16360}
16361
16362
16363/**
16364 * Nested-guest VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
16365 */
16366HMVMX_EXIT_DECL hmR0VmxExitRdtscNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16367{
16368 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16369
16370 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16371 {
16372 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16373 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16374 }
16375
16376 return hmR0VmxExitRdtsc(pVCpu, pVmxTransient);
16377}
16378
16379
16380/**
16381 * Nested-guest VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX).
16382 * Conditional VM-exit.
16383 */
16384HMVMX_EXIT_DECL hmR0VmxExitMovCRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16385{
16386 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16387
16388 hmR0VmxReadExitQualVmcs(pVmxTransient);
16389 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16390
16391 VBOXSTRICTRC rcStrict;
16392 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual);
16393 switch (uAccessType)
16394 {
16395 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
16396 {
16397 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16398 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
16399 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16400 uint64_t const uNewCrX = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16401
16402 bool fIntercept;
16403 switch (iCrReg)
16404 {
16405 case 0:
16406 case 4:
16407 fIntercept = CPUMIsGuestVmxMovToCr0Cr4InterceptSet(pVCpu, &pVCpu->cpum.GstCtx, iCrReg, uNewCrX);
16408 break;
16409
16410 case 3:
16411 fIntercept = CPUMIsGuestVmxMovToCr3InterceptSet(pVCpu, uNewCrX);
16412 break;
16413
16414 case 8:
16415 fIntercept = CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_CR8_LOAD_EXIT);
16416 break;
16417
16418 default:
16419 fIntercept = false;
16420 break;
16421 }
16422 if (fIntercept)
16423 {
16424 VMXVEXITINFO ExitInfo;
16425 RT_ZERO(ExitInfo);
16426 ExitInfo.uReason = pVmxTransient->uExitReason;
16427 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16428 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16429 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16430 }
16431 else
16432 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
16433 break;
16434 }
16435
16436 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
16437 {
16438 /*
16439 * CR0/CR4 reads do not cause VM-exits, the read-shadow is used (subject to masking).
16440 * CR2 reads do not cause a VM-exit.
16441 * CR3 reads cause a VM-exit depending on the "CR3 store exiting" control.
16442 * CR8 reads cause a VM-exit depending on the "CR8 store exiting" control.
16443 */
16444 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16445 if ( iCrReg == 3
16446 || iCrReg == 8)
16447 {
16448 static const uint32_t s_auCrXReadIntercepts[] = { 0, 0, 0, VMX_PROC_CTLS_CR3_STORE_EXIT, 0,
16449 0, 0, 0, VMX_PROC_CTLS_CR8_STORE_EXIT };
16450 uint32_t const uIntercept = s_auCrXReadIntercepts[iCrReg];
16451 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uIntercept))
16452 {
16453 VMXVEXITINFO ExitInfo;
16454 RT_ZERO(ExitInfo);
16455 ExitInfo.uReason = pVmxTransient->uExitReason;
16456 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16457 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16458 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16459 }
16460 else
16461 {
16462 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
16463 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
16464 }
16465 }
16466 else
16467 {
16468 AssertMsgFailed(("MOV from CR%d VM-exit must not happen\n", iCrReg));
16469 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, iCrReg);
16470 }
16471 break;
16472 }
16473
16474 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
16475 {
16476 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
16477 Assert(pVmcsNstGst);
16478 uint64_t const uGstHostMask = pVmcsNstGst->u64Cr0Mask.u;
16479 uint64_t const uReadShadow = pVmcsNstGst->u64Cr0ReadShadow.u;
16480 if ( (uGstHostMask & X86_CR0_TS)
16481 && (uReadShadow & X86_CR0_TS))
16482 {
16483 VMXVEXITINFO ExitInfo;
16484 RT_ZERO(ExitInfo);
16485 ExitInfo.uReason = pVmxTransient->uExitReason;
16486 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16487 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16488 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16489 }
16490 else
16491 rcStrict = hmR0VmxExitClts(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr);
16492 break;
16493 }
16494
16495 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
16496 {
16497 RTGCPTR GCPtrEffDst;
16498 uint16_t const uNewMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(pVmxTransient->uExitQual);
16499 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(pVmxTransient->uExitQual);
16500 if (fMemOperand)
16501 {
16502 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
16503 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
16504 }
16505 else
16506 GCPtrEffDst = NIL_RTGCPTR;
16507
16508 if (CPUMIsGuestVmxLmswInterceptSet(pVCpu, &pVCpu->cpum.GstCtx, uNewMsw))
16509 {
16510 VMXVEXITINFO ExitInfo;
16511 RT_ZERO(ExitInfo);
16512 ExitInfo.uReason = pVmxTransient->uExitReason;
16513 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16514 ExitInfo.u64GuestLinearAddr = GCPtrEffDst;
16515 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16516 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16517 }
16518 else
16519 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, uNewMsw, GCPtrEffDst);
16520 break;
16521 }
16522
16523 default:
16524 {
16525 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
16526 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
16527 }
16528 }
16529
16530 if (rcStrict == VINF_IEM_RAISED_XCPT)
16531 {
16532 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16533 rcStrict = VINF_SUCCESS;
16534 }
16535 return rcStrict;
16536}
16537
16538
16539/**
16540 * Nested-guest VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX).
16541 * Conditional VM-exit.
16542 */
16543HMVMX_EXIT_DECL hmR0VmxExitMovDRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16544{
16545 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16546
16547 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MOV_DR_EXIT))
16548 {
16549 hmR0VmxReadExitQualVmcs(pVmxTransient);
16550 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16551
16552 VMXVEXITINFO ExitInfo;
16553 RT_ZERO(ExitInfo);
16554 ExitInfo.uReason = pVmxTransient->uExitReason;
16555 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16556 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16557 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16558 }
16559 return hmR0VmxExitMovDRx(pVCpu, pVmxTransient);
16560}
16561
16562
16563/**
16564 * Nested-guest VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR).
16565 * Conditional VM-exit.
16566 */
16567HMVMX_EXIT_DECL hmR0VmxExitIoInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16568{
16569 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16570
16571 hmR0VmxReadExitQualVmcs(pVmxTransient);
16572
16573 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
16574 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
16575 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
16576
16577 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
16578 uint8_t const cbAccess = s_aIOSizes[uIOSize];
16579 if (CPUMIsGuestVmxIoInterceptSet(pVCpu, uIOPort, cbAccess))
16580 {
16581 /*
16582 * IN/OUT instruction:
16583 * - Provides VM-exit instruction length.
16584 *
16585 * INS/OUTS instruction:
16586 * - Provides VM-exit instruction length.
16587 * - Provides Guest-linear address.
16588 * - Optionally provides VM-exit instruction info (depends on CPU feature).
16589 */
16590 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16591 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16592
16593 /* Make sure we don't use stale/uninitialized VMX-transient info. below. */
16594 pVmxTransient->ExitInstrInfo.u = 0;
16595 pVmxTransient->uGuestLinearAddr = 0;
16596
16597 bool const fVmxInsOutsInfo = pVM->cpum.ro.GuestFeatures.fVmxInsOutInfo;
16598 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
16599 if (fIOString)
16600 {
16601 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
16602 if (fVmxInsOutsInfo)
16603 {
16604 Assert(RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS)); /* Paranoia. */
16605 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16606 }
16607 }
16608
16609 VMXVEXITINFO ExitInfo;
16610 RT_ZERO(ExitInfo);
16611 ExitInfo.uReason = pVmxTransient->uExitReason;
16612 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16613 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16614 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16615 ExitInfo.u64GuestLinearAddr = pVmxTransient->uGuestLinearAddr;
16616 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16617 }
16618 return hmR0VmxExitIoInstr(pVCpu, pVmxTransient);
16619}
16620
16621
16622/**
16623 * Nested-guest VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
16624 */
16625HMVMX_EXIT_DECL hmR0VmxExitRdmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16626{
16627 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16628
16629 uint32_t fMsrpm;
16630 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
16631 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
16632 else
16633 fMsrpm = VMXMSRPM_EXIT_RD;
16634
16635 if (fMsrpm & VMXMSRPM_EXIT_RD)
16636 {
16637 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16638 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16639 }
16640 return hmR0VmxExitRdmsr(pVCpu, pVmxTransient);
16641}
16642
16643
16644/**
16645 * Nested-guest VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
16646 */
16647HMVMX_EXIT_DECL hmR0VmxExitWrmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16648{
16649 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16650
16651 uint32_t fMsrpm;
16652 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
16653 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
16654 else
16655 fMsrpm = VMXMSRPM_EXIT_WR;
16656
16657 if (fMsrpm & VMXMSRPM_EXIT_WR)
16658 {
16659 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16660 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16661 }
16662 return hmR0VmxExitWrmsr(pVCpu, pVmxTransient);
16663}
16664
16665
16666/**
16667 * Nested-guest VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
16668 */
16669HMVMX_EXIT_DECL hmR0VmxExitMwaitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16670{
16671 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16672
16673 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MWAIT_EXIT))
16674 {
16675 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16676 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16677 }
16678 return hmR0VmxExitMwait(pVCpu, pVmxTransient);
16679}
16680
16681
16682/**
16683 * Nested-guest VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional
16684 * VM-exit.
16685 */
16686HMVMX_EXIT_DECL hmR0VmxExitMtfNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16687{
16688 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16689
16690 /** @todo NSTVMX: Should consider debugging nested-guests using VM debugger. */
16691 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
16692 VMXVEXITINFO ExitInfo;
16693 RT_ZERO(ExitInfo);
16694 ExitInfo.uReason = pVmxTransient->uExitReason;
16695 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
16696 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
16697}
16698
16699
16700/**
16701 * Nested-guest VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
16702 */
16703HMVMX_EXIT_DECL hmR0VmxExitMonitorNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16704{
16705 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16706
16707 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MONITOR_EXIT))
16708 {
16709 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16710 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16711 }
16712 return hmR0VmxExitMonitor(pVCpu, pVmxTransient);
16713}
16714
16715
16716/**
16717 * Nested-guest VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
16718 */
16719HMVMX_EXIT_DECL hmR0VmxExitPauseNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16720{
16721 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16722
16723 /** @todo NSTVMX: Think about this more. Does the outer guest need to intercept
16724 * PAUSE when executing a nested-guest? If it does not, we would not need
16725 * to check for the intercepts here. Just call VM-exit... */
16726
16727 /* The CPU would have already performed the necessary CPL checks for PAUSE-loop exiting. */
16728 if ( CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_PAUSE_EXIT)
16729 || CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
16730 {
16731 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16732 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16733 }
16734 return hmR0VmxExitPause(pVCpu, pVmxTransient);
16735}
16736
16737
16738/**
16739 * Nested-guest VM-exit handler for when the TPR value is lowered below the
16740 * specified threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
16741 */
16742HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThresholdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16743{
16744 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16745
16746 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_TPR_SHADOW))
16747 {
16748 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
16749 VMXVEXITINFO ExitInfo;
16750 RT_ZERO(ExitInfo);
16751 ExitInfo.uReason = pVmxTransient->uExitReason;
16752 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
16753 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
16754 }
16755 return hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient);
16756}
16757
16758
16759/**
16760 * Nested-guest VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional
16761 * VM-exit.
16762 */
16763HMVMX_EXIT_DECL hmR0VmxExitApicAccessNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16764{
16765 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16766
16767 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16768 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16769 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16770 hmR0VmxReadExitQualVmcs(pVmxTransient);
16771
16772 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
16773
16774 Log4Func(("at offset %#x type=%u\n", VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual),
16775 VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual)));
16776
16777 VMXVEXITINFO ExitInfo;
16778 RT_ZERO(ExitInfo);
16779 ExitInfo.uReason = pVmxTransient->uExitReason;
16780 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16781 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16782
16783 VMXVEXITEVENTINFO ExitEventInfo;
16784 RT_ZERO(ExitEventInfo);
16785 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16786 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16787 return IEMExecVmxVmexitApicAccess(pVCpu, &ExitInfo, &ExitEventInfo);
16788}
16789
16790
16791/**
16792 * Nested-guest VM-exit handler for APIC write emulation (VMX_EXIT_APIC_WRITE).
16793 * Conditional VM-exit.
16794 */
16795HMVMX_EXIT_DECL hmR0VmxExitApicWriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16796{
16797 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16798
16799 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_APIC_REG_VIRT));
16800 hmR0VmxReadExitQualVmcs(pVmxTransient);
16801 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
16802}
16803
16804
16805/**
16806 * Nested-guest VM-exit handler for virtualized EOI (VMX_EXIT_VIRTUALIZED_EOI).
16807 * Conditional VM-exit.
16808 */
16809HMVMX_EXIT_DECL hmR0VmxExitVirtEoiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16810{
16811 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16812
16813 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_INT_DELIVERY));
16814 hmR0VmxReadExitQualVmcs(pVmxTransient);
16815 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
16816}
16817
16818
16819/**
16820 * Nested-guest VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
16821 */
16822HMVMX_EXIT_DECL hmR0VmxExitRdtscpNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16823{
16824 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16825
16826 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16827 {
16828 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_RDTSCP));
16829 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16830 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16831 }
16832 return hmR0VmxExitRdtscp(pVCpu, pVmxTransient);
16833}
16834
16835
16836/**
16837 * Nested-guest VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
16838 */
16839HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16840{
16841 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16842
16843 if (CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_WBINVD_EXIT))
16844 {
16845 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16846 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16847 }
16848 return hmR0VmxExitWbinvd(pVCpu, pVmxTransient);
16849}
16850
16851
16852/**
16853 * Nested-guest VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
16854 */
16855HMVMX_EXIT_DECL hmR0VmxExitInvpcidNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16856{
16857 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16858
16859 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16860 {
16861 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_INVPCID));
16862 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16863 hmR0VmxReadExitQualVmcs(pVmxTransient);
16864 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16865
16866 VMXVEXITINFO ExitInfo;
16867 RT_ZERO(ExitInfo);
16868 ExitInfo.uReason = pVmxTransient->uExitReason;
16869 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16870 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16871 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16872 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16873 }
16874 return hmR0VmxExitInvpcid(pVCpu, pVmxTransient);
16875}
16876
16877
16878/**
16879 * Nested-guest VM-exit handler for invalid-guest state
16880 * (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error VM-exit.
16881 */
16882HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestStateNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16883{
16884 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16885
16886 /*
16887 * Currently this should never happen because we fully emulate VMLAUNCH/VMRESUME in IEM.
16888 * So if it does happen, it indicates a bug possibly in the hardware-assisted VMX code.
16889 * Handle it like it's in an invalid guest state of the outer guest.
16890 *
16891 * When the fast path is implemented, this should be changed to cause the corresponding
16892 * nested-guest VM-exit.
16893 */
16894 return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
16895}
16896
16897
16898/**
16899 * Nested-guest VM-exit handler for instructions that cause VM-exits uncondtionally
16900 * and only provide the instruction length.
16901 *
16902 * Unconditional VM-exit.
16903 */
16904HMVMX_EXIT_DECL hmR0VmxExitInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16905{
16906 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16907
16908#ifdef VBOX_STRICT
16909 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16910 switch (pVmxTransient->uExitReason)
16911 {
16912 case VMX_EXIT_ENCLS:
16913 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_ENCLS_EXIT));
16914 break;
16915
16916 case VMX_EXIT_VMFUNC:
16917 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_VMFUNC));
16918 break;
16919 }
16920#endif
16921
16922 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16923 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16924}
16925
16926
16927/**
16928 * Nested-guest VM-exit handler for instructions that provide instruction length as
16929 * well as more information.
16930 *
16931 * Unconditional VM-exit.
16932 */
16933HMVMX_EXIT_DECL hmR0VmxExitInstrWithInfoNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16934{
16935 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16936
16937#ifdef VBOX_STRICT
16938 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16939 switch (pVmxTransient->uExitReason)
16940 {
16941 case VMX_EXIT_GDTR_IDTR_ACCESS:
16942 case VMX_EXIT_LDTR_TR_ACCESS:
16943 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_DESC_TABLE_EXIT));
16944 break;
16945
16946 case VMX_EXIT_RDRAND:
16947 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_RDRAND_EXIT));
16948 break;
16949
16950 case VMX_EXIT_RDSEED:
16951 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_RDSEED_EXIT));
16952 break;
16953
16954 case VMX_EXIT_XSAVES:
16955 case VMX_EXIT_XRSTORS:
16956 /** @todo NSTVMX: Verify XSS-bitmap. */
16957 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_XSAVES_XRSTORS));
16958 break;
16959
16960 case VMX_EXIT_UMWAIT:
16961 case VMX_EXIT_TPAUSE:
16962 Assert(CPUMIsGuestVmxProcCtlsSet(pVCpu, pCtx, VMX_PROC_CTLS_RDTSC_EXIT));
16963 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_USER_WAIT_PAUSE));
16964 break;
16965 }
16966#endif
16967
16968 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16969 hmR0VmxReadExitQualVmcs(pVmxTransient);
16970 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16971
16972 VMXVEXITINFO ExitInfo;
16973 RT_ZERO(ExitInfo);
16974 ExitInfo.uReason = pVmxTransient->uExitReason;
16975 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16976 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16977 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16978 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16979}
16980
16981/** @} */
16982#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16983
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