VirtualBox

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

Last change on this file since 80150 was 80150, checked in by vboxsync, 6 years ago

VMM: Kicking out 32-bit host support - VMX [drop VMCSCACHE]. bugref:9511

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 700.3 KB
Line 
1/* $Id: HMVMXR0.cpp 80150 2019-08-06 07:44:20Z 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/vm.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
87/** All the VMCS fields required for processing of exception/NMI VM-exits. */
88#define HMVMX_READ_XCPT_INFO ( HMVMX_READ_EXIT_INTERRUPTION_INFO \
89 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE \
90 | HMVMX_READ_EXIT_INSTR_LEN \
91 | HMVMX_READ_IDT_VECTORING_INFO \
92 | HMVMX_READ_IDT_VECTORING_ERROR_CODE)
93
94/** Assert that all the given fields have been read from the VMCS. */
95#ifdef VBOX_STRICT
96# define HMVMX_ASSERT_READ(a_pVmxTransient, a_fReadFields) \
97 do { \
98 uint32_t const fVmcsFieldRead = ASMAtomicUoReadU32(&pVmxTransient->fVmcsFieldsRead); \
99 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE(); \
100 Assert((fVmcsFieldRead & (a_fReadFields)) == (a_fReadFields)); \
101 } while (0)
102#else
103# define HMVMX_ASSERT_READ(a_pVmxTransient, a_fReadFields) do { } while (0)
104#endif
105
106/**
107 * Subset of the guest-CPU state that is kept by VMX R0 code while executing the
108 * guest using hardware-assisted VMX.
109 *
110 * This excludes state like GPRs (other than RSP) which are always are
111 * swapped and restored across the world-switch and also registers like EFER,
112 * MSR which cannot be modified by the guest without causing a VM-exit.
113 */
114#define HMVMX_CPUMCTX_EXTRN_ALL ( CPUMCTX_EXTRN_RIP \
115 | CPUMCTX_EXTRN_RFLAGS \
116 | CPUMCTX_EXTRN_RSP \
117 | CPUMCTX_EXTRN_SREG_MASK \
118 | CPUMCTX_EXTRN_TABLE_MASK \
119 | CPUMCTX_EXTRN_KERNEL_GS_BASE \
120 | CPUMCTX_EXTRN_SYSCALL_MSRS \
121 | CPUMCTX_EXTRN_SYSENTER_MSRS \
122 | CPUMCTX_EXTRN_TSC_AUX \
123 | CPUMCTX_EXTRN_OTHER_MSRS \
124 | CPUMCTX_EXTRN_CR0 \
125 | CPUMCTX_EXTRN_CR3 \
126 | CPUMCTX_EXTRN_CR4 \
127 | CPUMCTX_EXTRN_DR7 \
128 | CPUMCTX_EXTRN_HWVIRT \
129 | CPUMCTX_EXTRN_HM_VMX_MASK)
130
131/**
132 * Exception bitmap mask for real-mode guests (real-on-v86).
133 *
134 * We need to intercept all exceptions manually except:
135 * - \#AC and \#DB are always intercepted to prevent the CPU from deadlocking
136 * due to bugs in Intel CPUs.
137 * - \#PF need not be intercepted even in real-mode if we have nested paging
138 * support.
139 */
140#define HMVMX_REAL_MODE_XCPT_MASK ( RT_BIT(X86_XCPT_DE) /* always: | RT_BIT(X86_XCPT_DB) */ | RT_BIT(X86_XCPT_NMI) \
141 | RT_BIT(X86_XCPT_BP) | RT_BIT(X86_XCPT_OF) | RT_BIT(X86_XCPT_BR) \
142 | RT_BIT(X86_XCPT_UD) | RT_BIT(X86_XCPT_NM) | RT_BIT(X86_XCPT_DF) \
143 | RT_BIT(X86_XCPT_CO_SEG_OVERRUN) | RT_BIT(X86_XCPT_TS) | RT_BIT(X86_XCPT_NP) \
144 | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_GP) /* RT_BIT(X86_XCPT_PF) */ \
145 | RT_BIT(X86_XCPT_MF) /* always: | RT_BIT(X86_XCPT_AC) */ | RT_BIT(X86_XCPT_MC) \
146 | RT_BIT(X86_XCPT_XF))
147
148/** Maximum VM-instruction error number. */
149#define HMVMX_INSTR_ERROR_MAX 28
150
151/** Profiling macro. */
152#ifdef HM_PROFILE_EXIT_DISPATCH
153# define HMVMX_START_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitDispatch, ed)
154# define HMVMX_STOP_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitDispatch, ed)
155#else
156# define HMVMX_START_EXIT_DISPATCH_PROF() do { } while (0)
157# define HMVMX_STOP_EXIT_DISPATCH_PROF() do { } while (0)
158#endif
159
160/** Assert that preemption is disabled or covered by thread-context hooks. */
161#define HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu) Assert( VMMR0ThreadCtxHookIsEnabled((a_pVCpu)) \
162 || !RTThreadPreemptIsEnabled(NIL_RTTHREAD))
163
164/** Assert that we haven't migrated CPUs when thread-context hooks are not
165 * used. */
166#define HMVMX_ASSERT_CPU_SAFE(a_pVCpu) AssertMsg( VMMR0ThreadCtxHookIsEnabled((a_pVCpu)) \
167 || (a_pVCpu)->hm.s.idEnteredCpu == RTMpCpuId(), \
168 ("Illegal migration! Entered on CPU %u Current %u\n", \
169 (a_pVCpu)->hm.s.idEnteredCpu, RTMpCpuId()))
170
171/** Asserts that the given CPUMCTX_EXTRN_XXX bits are present in the guest-CPU
172 * context. */
173#define HMVMX_CPUMCTX_ASSERT(a_pVCpu, a_fExtrnMbz) AssertMsg(!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fExtrnMbz)), \
174 ("fExtrn=%#RX64 fExtrnMbz=%#RX64\n", \
175 (a_pVCpu)->cpum.GstCtx.fExtrn, (a_fExtrnMbz)))
176
177/** Log the VM-exit reason with an easily visible marker to identify it in a
178 * potential sea of logging data. */
179#define HMVMX_LOG_EXIT(a_pVCpu, a_uExitReason) \
180 do { \
181 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, \
182 HMGetVmxExitName(a_uExitReason))); \
183 } while (0) \
184
185
186/*********************************************************************************************************************************
187* Structures and Typedefs *
188*********************************************************************************************************************************/
189/**
190 * VMX per-VCPU transient state.
191 *
192 * A state structure for holding miscellaneous information across
193 * VMX non-root operation and restored after the transition.
194 */
195typedef struct VMXTRANSIENT
196{
197 /** The host's rflags/eflags. */
198 RTCCUINTREG fEFlags;
199
200 /** The guest's TPR value used for TPR shadowing. */
201 uint8_t u8GuestTpr;
202 /** Alignment. */
203 uint8_t abAlignment0[7];
204
205 /** The basic VM-exit reason. */
206 uint16_t uExitReason;
207 /** Alignment. */
208 uint16_t u16Alignment0;
209 /** The VM-exit interruption error code. */
210 uint32_t uExitIntErrorCode;
211 /** The VM-exit exit code qualification. */
212 uint64_t uExitQual;
213 /** The Guest-linear address. */
214 uint64_t uGuestLinearAddr;
215 /** The Guest-physical address. */
216 uint64_t uGuestPhysicalAddr;
217
218 /** The VM-exit interruption-information field. */
219 uint32_t uExitIntInfo;
220 /** The VM-exit instruction-length field. */
221 uint32_t cbInstr;
222 /** The VM-exit instruction-information field. */
223 VMXEXITINSTRINFO ExitInstrInfo;
224 /** Whether the VM-entry failed or not. */
225 bool fVMEntryFailed;
226 /** Whether we are currently executing a nested-guest. */
227 bool fIsNestedGuest;
228 /** Alignment. */
229 uint8_t abAlignment1[2];
230
231 /** The VM-entry interruption-information field. */
232 uint32_t uEntryIntInfo;
233 /** The VM-entry exception error code field. */
234 uint32_t uEntryXcptErrorCode;
235 /** The VM-entry instruction length field. */
236 uint32_t cbEntryInstr;
237
238 /** IDT-vectoring information field. */
239 uint32_t uIdtVectoringInfo;
240 /** IDT-vectoring error code. */
241 uint32_t uIdtVectoringErrorCode;
242
243 /** Mask of currently read VMCS fields; HMVMX_READ_XXX. */
244 uint32_t fVmcsFieldsRead;
245
246 /** Whether the guest debug state was active at the time of VM-exit. */
247 bool fWasGuestDebugStateActive;
248 /** Whether the hyper debug state was active at the time of VM-exit. */
249 bool fWasHyperDebugStateActive;
250 /** Whether TSC-offsetting and VMX-preemption timer was updated before VM-entry. */
251 bool fUpdatedTscOffsettingAndPreemptTimer;
252 /** Whether the VM-exit was caused by a page-fault during delivery of a
253 * contributory exception or a page-fault. */
254 bool fVectoringDoublePF;
255 /** Whether the VM-exit was caused by a page-fault during delivery of an
256 * external interrupt or NMI. */
257 bool fVectoringPF;
258 /** Whether the TSC_AUX MSR needs to be removed from the auto-load/store MSR
259 * area after VM-exit. */
260 bool fRemoveTscAuxMsr;
261 bool afAlignment0[2];
262
263 /** The VMCS info. object. */
264 PVMXVMCSINFO pVmcsInfo;
265} VMXTRANSIENT;
266AssertCompileMemberAlignment(VMXTRANSIENT, uExitReason, sizeof(uint64_t));
267AssertCompileMemberAlignment(VMXTRANSIENT, uExitIntInfo, sizeof(uint64_t));
268AssertCompileMemberAlignment(VMXTRANSIENT, uEntryIntInfo, sizeof(uint64_t));
269AssertCompileMemberAlignment(VMXTRANSIENT, fWasGuestDebugStateActive, sizeof(uint64_t));
270AssertCompileMemberAlignment(VMXTRANSIENT, pVmcsInfo, sizeof(uint64_t));
271AssertCompileMemberSize(VMXTRANSIENT, ExitInstrInfo, sizeof(uint32_t));
272/** Pointer to VMX transient state. */
273typedef VMXTRANSIENT *PVMXTRANSIENT;
274/** Pointer to a const VMX transient state. */
275typedef const VMXTRANSIENT *PCVMXTRANSIENT;
276
277/**
278 * Memory operand read or write access.
279 */
280typedef enum VMXMEMACCESS
281{
282 VMXMEMACCESS_READ = 0,
283 VMXMEMACCESS_WRITE = 1
284} VMXMEMACCESS;
285
286/**
287 * VMX VM-exit handler.
288 *
289 * @returns Strict VBox status code (i.e. informational status codes too).
290 * @param pVCpu The cross context virtual CPU structure.
291 * @param pVmxTransient The VMX-transient structure.
292 */
293#ifndef HMVMX_USE_FUNCTION_TABLE
294typedef VBOXSTRICTRC FNVMXEXITHANDLER(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient);
295#else
296typedef DECLCALLBACK(VBOXSTRICTRC) FNVMXEXITHANDLER(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient);
297/** Pointer to VM-exit handler. */
298typedef FNVMXEXITHANDLER *PFNVMXEXITHANDLER;
299#endif
300
301/**
302 * VMX VM-exit handler, non-strict status code.
303 *
304 * This is generally the same as FNVMXEXITHANDLER, the NSRC bit is just FYI.
305 *
306 * @returns VBox status code, no informational status code returned.
307 * @param pVCpu The cross context virtual CPU structure.
308 * @param pVmxTransient The VMX-transient structure.
309 *
310 * @remarks This is not used on anything returning VERR_EM_INTERPRETER as the
311 * use of that status code will be replaced with VINF_EM_SOMETHING
312 * later when switching over to IEM.
313 */
314#ifndef HMVMX_USE_FUNCTION_TABLE
315typedef int FNVMXEXITHANDLERNSRC(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient);
316#else
317typedef FNVMXEXITHANDLER FNVMXEXITHANDLERNSRC;
318#endif
319
320
321/*********************************************************************************************************************************
322* Internal Functions *
323*********************************************************************************************************************************/
324#ifndef HMVMX_USE_FUNCTION_TABLE
325DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient);
326# define HMVMX_EXIT_DECL DECLINLINE(VBOXSTRICTRC)
327# define HMVMX_EXIT_NSRC_DECL DECLINLINE(int)
328#else
329# define HMVMX_EXIT_DECL static DECLCALLBACK(VBOXSTRICTRC)
330# define HMVMX_EXIT_NSRC_DECL HMVMX_EXIT_DECL
331#endif
332#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
333DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient);
334#endif
335
336static int hmR0VmxImportGuestState(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat);
337
338/** @name VM-exit handler prototypes.
339 * @{
340 */
341static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmi;
342static FNVMXEXITHANDLER hmR0VmxExitExtInt;
343static FNVMXEXITHANDLER hmR0VmxExitTripleFault;
344static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindow;
345static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindow;
346static FNVMXEXITHANDLER hmR0VmxExitTaskSwitch;
347static FNVMXEXITHANDLER hmR0VmxExitCpuid;
348static FNVMXEXITHANDLER hmR0VmxExitGetsec;
349static FNVMXEXITHANDLER hmR0VmxExitHlt;
350static FNVMXEXITHANDLERNSRC hmR0VmxExitInvd;
351static FNVMXEXITHANDLER hmR0VmxExitInvlpg;
352static FNVMXEXITHANDLER hmR0VmxExitRdpmc;
353static FNVMXEXITHANDLER hmR0VmxExitVmcall;
354#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
355static FNVMXEXITHANDLER hmR0VmxExitVmclear;
356static FNVMXEXITHANDLER hmR0VmxExitVmlaunch;
357static FNVMXEXITHANDLER hmR0VmxExitVmptrld;
358static FNVMXEXITHANDLER hmR0VmxExitVmptrst;
359static FNVMXEXITHANDLER hmR0VmxExitVmread;
360static FNVMXEXITHANDLER hmR0VmxExitVmresume;
361static FNVMXEXITHANDLER hmR0VmxExitVmwrite;
362static FNVMXEXITHANDLER hmR0VmxExitVmxoff;
363static FNVMXEXITHANDLER hmR0VmxExitVmxon;
364static FNVMXEXITHANDLER hmR0VmxExitInvvpid;
365#endif
366static FNVMXEXITHANDLER hmR0VmxExitRdtsc;
367static FNVMXEXITHANDLER hmR0VmxExitMovCRx;
368static FNVMXEXITHANDLER hmR0VmxExitMovDRx;
369static FNVMXEXITHANDLER hmR0VmxExitIoInstr;
370static FNVMXEXITHANDLER hmR0VmxExitRdmsr;
371static FNVMXEXITHANDLER hmR0VmxExitWrmsr;
372static FNVMXEXITHANDLER hmR0VmxExitMwait;
373static FNVMXEXITHANDLER hmR0VmxExitMtf;
374static FNVMXEXITHANDLER hmR0VmxExitMonitor;
375static FNVMXEXITHANDLER hmR0VmxExitPause;
376static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThreshold;
377static FNVMXEXITHANDLER hmR0VmxExitApicAccess;
378static FNVMXEXITHANDLER hmR0VmxExitEptViolation;
379static FNVMXEXITHANDLER hmR0VmxExitEptMisconfig;
380static FNVMXEXITHANDLER hmR0VmxExitRdtscp;
381static FNVMXEXITHANDLER hmR0VmxExitPreemptTimer;
382static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvd;
383static FNVMXEXITHANDLER hmR0VmxExitXsetbv;
384static FNVMXEXITHANDLER hmR0VmxExitInvpcid;
385static FNVMXEXITHANDLERNSRC hmR0VmxExitSetPendingXcptUD;
386static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestState;
387static FNVMXEXITHANDLERNSRC hmR0VmxExitErrUnexpected;
388/** @} */
389
390#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
391/** @name Nested-guest VM-exit handler prototypes.
392 * @{
393 */
394static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmiNested;
395static FNVMXEXITHANDLER hmR0VmxExitTripleFaultNested;
396static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindowNested;
397static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindowNested;
398static FNVMXEXITHANDLER hmR0VmxExitTaskSwitchNested;
399static FNVMXEXITHANDLER hmR0VmxExitHltNested;
400static FNVMXEXITHANDLER hmR0VmxExitInvlpgNested;
401static FNVMXEXITHANDLER hmR0VmxExitRdpmcNested;
402static FNVMXEXITHANDLER hmR0VmxExitVmreadVmwriteNested;
403static FNVMXEXITHANDLER hmR0VmxExitRdtscNested;
404static FNVMXEXITHANDLER hmR0VmxExitMovCRxNested;
405static FNVMXEXITHANDLER hmR0VmxExitMovDRxNested;
406static FNVMXEXITHANDLER hmR0VmxExitIoInstrNested;
407static FNVMXEXITHANDLER hmR0VmxExitRdmsrNested;
408static FNVMXEXITHANDLER hmR0VmxExitWrmsrNested;
409static FNVMXEXITHANDLER hmR0VmxExitMwaitNested;
410static FNVMXEXITHANDLER hmR0VmxExitMtfNested;
411static FNVMXEXITHANDLER hmR0VmxExitMonitorNested;
412static FNVMXEXITHANDLER hmR0VmxExitPauseNested;
413static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThresholdNested;
414static FNVMXEXITHANDLER hmR0VmxExitApicAccessNested;
415static FNVMXEXITHANDLER hmR0VmxExitApicWriteNested;
416static FNVMXEXITHANDLER hmR0VmxExitVirtEoiNested;
417static FNVMXEXITHANDLER hmR0VmxExitRdtscpNested;
418static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvdNested;
419static FNVMXEXITHANDLER hmR0VmxExitInvpcidNested;
420static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestStateNested;
421static FNVMXEXITHANDLER hmR0VmxExitInstrNested;
422static FNVMXEXITHANDLER hmR0VmxExitInstrWithInfoNested;
423/** @} */
424#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
425
426
427/*********************************************************************************************************************************
428* Global Variables *
429*********************************************************************************************************************************/
430#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
431/**
432 * Array of all VMCS fields.
433 * Any fields added to the VT-x spec. should be added here.
434 *
435 * Currently only used to derive shadow VMCS fields for hardware-assisted execution
436 * of nested-guests.
437 */
438static const uint32_t g_aVmcsFields[] =
439{
440 /* 16-bit control fields. */
441 VMX_VMCS16_VPID,
442 VMX_VMCS16_POSTED_INT_NOTIFY_VECTOR,
443 VMX_VMCS16_EPTP_INDEX,
444
445 /* 16-bit guest-state fields. */
446 VMX_VMCS16_GUEST_ES_SEL,
447 VMX_VMCS16_GUEST_CS_SEL,
448 VMX_VMCS16_GUEST_SS_SEL,
449 VMX_VMCS16_GUEST_DS_SEL,
450 VMX_VMCS16_GUEST_FS_SEL,
451 VMX_VMCS16_GUEST_GS_SEL,
452 VMX_VMCS16_GUEST_LDTR_SEL,
453 VMX_VMCS16_GUEST_TR_SEL,
454 VMX_VMCS16_GUEST_INTR_STATUS,
455 VMX_VMCS16_GUEST_PML_INDEX,
456
457 /* 16-bits host-state fields. */
458 VMX_VMCS16_HOST_ES_SEL,
459 VMX_VMCS16_HOST_CS_SEL,
460 VMX_VMCS16_HOST_SS_SEL,
461 VMX_VMCS16_HOST_DS_SEL,
462 VMX_VMCS16_HOST_FS_SEL,
463 VMX_VMCS16_HOST_GS_SEL,
464 VMX_VMCS16_HOST_TR_SEL,
465
466 /* 64-bit control fields. */
467 VMX_VMCS64_CTRL_IO_BITMAP_A_FULL,
468 VMX_VMCS64_CTRL_IO_BITMAP_A_HIGH,
469 VMX_VMCS64_CTRL_IO_BITMAP_B_FULL,
470 VMX_VMCS64_CTRL_IO_BITMAP_B_HIGH,
471 VMX_VMCS64_CTRL_MSR_BITMAP_FULL,
472 VMX_VMCS64_CTRL_MSR_BITMAP_HIGH,
473 VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL,
474 VMX_VMCS64_CTRL_EXIT_MSR_STORE_HIGH,
475 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL,
476 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_HIGH,
477 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL,
478 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_HIGH,
479 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL,
480 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_HIGH,
481 VMX_VMCS64_CTRL_EXEC_PML_ADDR_FULL,
482 VMX_VMCS64_CTRL_EXEC_PML_ADDR_HIGH,
483 VMX_VMCS64_CTRL_TSC_OFFSET_FULL,
484 VMX_VMCS64_CTRL_TSC_OFFSET_HIGH,
485 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL,
486 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_HIGH,
487 VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL,
488 VMX_VMCS64_CTRL_APIC_ACCESSADDR_HIGH,
489 VMX_VMCS64_CTRL_POSTED_INTR_DESC_FULL,
490 VMX_VMCS64_CTRL_POSTED_INTR_DESC_HIGH,
491 VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL,
492 VMX_VMCS64_CTRL_VMFUNC_CTRLS_HIGH,
493 VMX_VMCS64_CTRL_EPTP_FULL,
494 VMX_VMCS64_CTRL_EPTP_HIGH,
495 VMX_VMCS64_CTRL_EOI_BITMAP_0_FULL,
496 VMX_VMCS64_CTRL_EOI_BITMAP_0_HIGH,
497 VMX_VMCS64_CTRL_EOI_BITMAP_1_FULL,
498 VMX_VMCS64_CTRL_EOI_BITMAP_1_HIGH,
499 VMX_VMCS64_CTRL_EOI_BITMAP_2_FULL,
500 VMX_VMCS64_CTRL_EOI_BITMAP_2_HIGH,
501 VMX_VMCS64_CTRL_EOI_BITMAP_3_FULL,
502 VMX_VMCS64_CTRL_EOI_BITMAP_3_HIGH,
503 VMX_VMCS64_CTRL_EPTP_LIST_FULL,
504 VMX_VMCS64_CTRL_EPTP_LIST_HIGH,
505 VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL,
506 VMX_VMCS64_CTRL_VMREAD_BITMAP_HIGH,
507 VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL,
508 VMX_VMCS64_CTRL_VMWRITE_BITMAP_HIGH,
509 VMX_VMCS64_CTRL_VIRTXCPT_INFO_ADDR_FULL,
510 VMX_VMCS64_CTRL_VIRTXCPT_INFO_ADDR_HIGH,
511 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_FULL,
512 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_HIGH,
513 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_FULL,
514 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_HIGH,
515 VMX_VMCS64_CTRL_TSC_MULTIPLIER_FULL,
516 VMX_VMCS64_CTRL_TSC_MULTIPLIER_HIGH,
517
518 /* 64-bit read-only data fields. */
519 VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL,
520 VMX_VMCS64_RO_GUEST_PHYS_ADDR_HIGH,
521
522 /* 64-bit guest-state fields. */
523 VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL,
524 VMX_VMCS64_GUEST_VMCS_LINK_PTR_HIGH,
525 VMX_VMCS64_GUEST_DEBUGCTL_FULL,
526 VMX_VMCS64_GUEST_DEBUGCTL_HIGH,
527 VMX_VMCS64_GUEST_PAT_FULL,
528 VMX_VMCS64_GUEST_PAT_HIGH,
529 VMX_VMCS64_GUEST_EFER_FULL,
530 VMX_VMCS64_GUEST_EFER_HIGH,
531 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL,
532 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_HIGH,
533 VMX_VMCS64_GUEST_PDPTE0_FULL,
534 VMX_VMCS64_GUEST_PDPTE0_HIGH,
535 VMX_VMCS64_GUEST_PDPTE1_FULL,
536 VMX_VMCS64_GUEST_PDPTE1_HIGH,
537 VMX_VMCS64_GUEST_PDPTE2_FULL,
538 VMX_VMCS64_GUEST_PDPTE2_HIGH,
539 VMX_VMCS64_GUEST_PDPTE3_FULL,
540 VMX_VMCS64_GUEST_PDPTE3_HIGH,
541 VMX_VMCS64_GUEST_BNDCFGS_FULL,
542 VMX_VMCS64_GUEST_BNDCFGS_HIGH,
543
544 /* 64-bit host-state fields. */
545 VMX_VMCS64_HOST_PAT_FULL,
546 VMX_VMCS64_HOST_PAT_HIGH,
547 VMX_VMCS64_HOST_EFER_FULL,
548 VMX_VMCS64_HOST_EFER_HIGH,
549 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL,
550 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_HIGH,
551
552 /* 32-bit control fields. */
553 VMX_VMCS32_CTRL_PIN_EXEC,
554 VMX_VMCS32_CTRL_PROC_EXEC,
555 VMX_VMCS32_CTRL_EXCEPTION_BITMAP,
556 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK,
557 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH,
558 VMX_VMCS32_CTRL_CR3_TARGET_COUNT,
559 VMX_VMCS32_CTRL_EXIT,
560 VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT,
561 VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT,
562 VMX_VMCS32_CTRL_ENTRY,
563 VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT,
564 VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO,
565 VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE,
566 VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH,
567 VMX_VMCS32_CTRL_TPR_THRESHOLD,
568 VMX_VMCS32_CTRL_PROC_EXEC2,
569 VMX_VMCS32_CTRL_PLE_GAP,
570 VMX_VMCS32_CTRL_PLE_WINDOW,
571
572 /* 32-bits read-only fields. */
573 VMX_VMCS32_RO_VM_INSTR_ERROR,
574 VMX_VMCS32_RO_EXIT_REASON,
575 VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO,
576 VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE,
577 VMX_VMCS32_RO_IDT_VECTORING_INFO,
578 VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE,
579 VMX_VMCS32_RO_EXIT_INSTR_LENGTH,
580 VMX_VMCS32_RO_EXIT_INSTR_INFO,
581
582 /* 32-bit guest-state fields. */
583 VMX_VMCS32_GUEST_ES_LIMIT,
584 VMX_VMCS32_GUEST_CS_LIMIT,
585 VMX_VMCS32_GUEST_SS_LIMIT,
586 VMX_VMCS32_GUEST_DS_LIMIT,
587 VMX_VMCS32_GUEST_FS_LIMIT,
588 VMX_VMCS32_GUEST_GS_LIMIT,
589 VMX_VMCS32_GUEST_LDTR_LIMIT,
590 VMX_VMCS32_GUEST_TR_LIMIT,
591 VMX_VMCS32_GUEST_GDTR_LIMIT,
592 VMX_VMCS32_GUEST_IDTR_LIMIT,
593 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
594 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
595 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
596 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
597 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
598 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS,
599 VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS,
600 VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS,
601 VMX_VMCS32_GUEST_INT_STATE,
602 VMX_VMCS32_GUEST_ACTIVITY_STATE,
603 VMX_VMCS32_GUEST_SMBASE,
604 VMX_VMCS32_GUEST_SYSENTER_CS,
605 VMX_VMCS32_PREEMPT_TIMER_VALUE,
606
607 /* 32-bit host-state fields. */
608 VMX_VMCS32_HOST_SYSENTER_CS,
609
610 /* Natural-width control fields. */
611 VMX_VMCS_CTRL_CR0_MASK,
612 VMX_VMCS_CTRL_CR4_MASK,
613 VMX_VMCS_CTRL_CR0_READ_SHADOW,
614 VMX_VMCS_CTRL_CR4_READ_SHADOW,
615 VMX_VMCS_CTRL_CR3_TARGET_VAL0,
616 VMX_VMCS_CTRL_CR3_TARGET_VAL1,
617 VMX_VMCS_CTRL_CR3_TARGET_VAL2,
618 VMX_VMCS_CTRL_CR3_TARGET_VAL3,
619
620 /* Natural-width read-only data fields. */
621 VMX_VMCS_RO_EXIT_QUALIFICATION,
622 VMX_VMCS_RO_IO_RCX,
623 VMX_VMCS_RO_IO_RSI,
624 VMX_VMCS_RO_IO_RDI,
625 VMX_VMCS_RO_IO_RIP,
626 VMX_VMCS_RO_GUEST_LINEAR_ADDR,
627
628 /* Natural-width guest-state field */
629 VMX_VMCS_GUEST_CR0,
630 VMX_VMCS_GUEST_CR3,
631 VMX_VMCS_GUEST_CR4,
632 VMX_VMCS_GUEST_ES_BASE,
633 VMX_VMCS_GUEST_CS_BASE,
634 VMX_VMCS_GUEST_SS_BASE,
635 VMX_VMCS_GUEST_DS_BASE,
636 VMX_VMCS_GUEST_FS_BASE,
637 VMX_VMCS_GUEST_GS_BASE,
638 VMX_VMCS_GUEST_LDTR_BASE,
639 VMX_VMCS_GUEST_TR_BASE,
640 VMX_VMCS_GUEST_GDTR_BASE,
641 VMX_VMCS_GUEST_IDTR_BASE,
642 VMX_VMCS_GUEST_DR7,
643 VMX_VMCS_GUEST_RSP,
644 VMX_VMCS_GUEST_RIP,
645 VMX_VMCS_GUEST_RFLAGS,
646 VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS,
647 VMX_VMCS_GUEST_SYSENTER_ESP,
648 VMX_VMCS_GUEST_SYSENTER_EIP,
649
650 /* Natural-width host-state fields */
651 VMX_VMCS_HOST_CR0,
652 VMX_VMCS_HOST_CR3,
653 VMX_VMCS_HOST_CR4,
654 VMX_VMCS_HOST_FS_BASE,
655 VMX_VMCS_HOST_GS_BASE,
656 VMX_VMCS_HOST_TR_BASE,
657 VMX_VMCS_HOST_GDTR_BASE,
658 VMX_VMCS_HOST_IDTR_BASE,
659 VMX_VMCS_HOST_SYSENTER_ESP,
660 VMX_VMCS_HOST_SYSENTER_EIP,
661 VMX_VMCS_HOST_RSP,
662 VMX_VMCS_HOST_RIP
663};
664#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
665
666static const uint32_t g_aVmcsSegBase[] =
667{
668 VMX_VMCS_GUEST_ES_BASE,
669 VMX_VMCS_GUEST_CS_BASE,
670 VMX_VMCS_GUEST_SS_BASE,
671 VMX_VMCS_GUEST_DS_BASE,
672 VMX_VMCS_GUEST_FS_BASE,
673 VMX_VMCS_GUEST_GS_BASE
674};
675static const uint32_t g_aVmcsSegSel[] =
676{
677 VMX_VMCS16_GUEST_ES_SEL,
678 VMX_VMCS16_GUEST_CS_SEL,
679 VMX_VMCS16_GUEST_SS_SEL,
680 VMX_VMCS16_GUEST_DS_SEL,
681 VMX_VMCS16_GUEST_FS_SEL,
682 VMX_VMCS16_GUEST_GS_SEL
683};
684static const uint32_t g_aVmcsSegLimit[] =
685{
686 VMX_VMCS32_GUEST_ES_LIMIT,
687 VMX_VMCS32_GUEST_CS_LIMIT,
688 VMX_VMCS32_GUEST_SS_LIMIT,
689 VMX_VMCS32_GUEST_DS_LIMIT,
690 VMX_VMCS32_GUEST_FS_LIMIT,
691 VMX_VMCS32_GUEST_GS_LIMIT
692};
693static const uint32_t g_aVmcsSegAttr[] =
694{
695 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
696 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
697 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
698 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
699 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
700 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS
701};
702AssertCompile(RT_ELEMENTS(g_aVmcsSegSel) == X86_SREG_COUNT);
703AssertCompile(RT_ELEMENTS(g_aVmcsSegLimit) == X86_SREG_COUNT);
704AssertCompile(RT_ELEMENTS(g_aVmcsSegBase) == X86_SREG_COUNT);
705AssertCompile(RT_ELEMENTS(g_aVmcsSegAttr) == X86_SREG_COUNT);
706
707#ifdef HMVMX_USE_FUNCTION_TABLE
708/**
709 * VMX_EXIT dispatch table.
710 */
711static const PFNVMXEXITHANDLER g_apfnVMExitHandlers[VMX_EXIT_MAX + 1] =
712{
713 /* 0 VMX_EXIT_XCPT_OR_NMI */ hmR0VmxExitXcptOrNmi,
714 /* 1 VMX_EXIT_EXT_INT */ hmR0VmxExitExtInt,
715 /* 2 VMX_EXIT_TRIPLE_FAULT */ hmR0VmxExitTripleFault,
716 /* 3 VMX_EXIT_INIT_SIGNAL */ hmR0VmxExitErrUnexpected,
717 /* 4 VMX_EXIT_SIPI */ hmR0VmxExitErrUnexpected,
718 /* 5 VMX_EXIT_IO_SMI */ hmR0VmxExitErrUnexpected,
719 /* 6 VMX_EXIT_SMI */ hmR0VmxExitErrUnexpected,
720 /* 7 VMX_EXIT_INT_WINDOW */ hmR0VmxExitIntWindow,
721 /* 8 VMX_EXIT_NMI_WINDOW */ hmR0VmxExitNmiWindow,
722 /* 9 VMX_EXIT_TASK_SWITCH */ hmR0VmxExitTaskSwitch,
723 /* 10 VMX_EXIT_CPUID */ hmR0VmxExitCpuid,
724 /* 11 VMX_EXIT_GETSEC */ hmR0VmxExitGetsec,
725 /* 12 VMX_EXIT_HLT */ hmR0VmxExitHlt,
726 /* 13 VMX_EXIT_INVD */ hmR0VmxExitInvd,
727 /* 14 VMX_EXIT_INVLPG */ hmR0VmxExitInvlpg,
728 /* 15 VMX_EXIT_RDPMC */ hmR0VmxExitRdpmc,
729 /* 16 VMX_EXIT_RDTSC */ hmR0VmxExitRdtsc,
730 /* 17 VMX_EXIT_RSM */ hmR0VmxExitErrUnexpected,
731 /* 18 VMX_EXIT_VMCALL */ hmR0VmxExitVmcall,
732#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
733 /* 19 VMX_EXIT_VMCLEAR */ hmR0VmxExitVmclear,
734 /* 20 VMX_EXIT_VMLAUNCH */ hmR0VmxExitVmlaunch,
735 /* 21 VMX_EXIT_VMPTRLD */ hmR0VmxExitVmptrld,
736 /* 22 VMX_EXIT_VMPTRST */ hmR0VmxExitVmptrst,
737 /* 23 VMX_EXIT_VMREAD */ hmR0VmxExitVmread,
738 /* 24 VMX_EXIT_VMRESUME */ hmR0VmxExitVmresume,
739 /* 25 VMX_EXIT_VMWRITE */ hmR0VmxExitVmwrite,
740 /* 26 VMX_EXIT_VMXOFF */ hmR0VmxExitVmxoff,
741 /* 27 VMX_EXIT_VMXON */ hmR0VmxExitVmxon,
742#else
743 /* 19 VMX_EXIT_VMCLEAR */ hmR0VmxExitSetPendingXcptUD,
744 /* 20 VMX_EXIT_VMLAUNCH */ hmR0VmxExitSetPendingXcptUD,
745 /* 21 VMX_EXIT_VMPTRLD */ hmR0VmxExitSetPendingXcptUD,
746 /* 22 VMX_EXIT_VMPTRST */ hmR0VmxExitSetPendingXcptUD,
747 /* 23 VMX_EXIT_VMREAD */ hmR0VmxExitSetPendingXcptUD,
748 /* 24 VMX_EXIT_VMRESUME */ hmR0VmxExitSetPendingXcptUD,
749 /* 25 VMX_EXIT_VMWRITE */ hmR0VmxExitSetPendingXcptUD,
750 /* 26 VMX_EXIT_VMXOFF */ hmR0VmxExitSetPendingXcptUD,
751 /* 27 VMX_EXIT_VMXON */ hmR0VmxExitSetPendingXcptUD,
752#endif
753 /* 28 VMX_EXIT_MOV_CRX */ hmR0VmxExitMovCRx,
754 /* 29 VMX_EXIT_MOV_DRX */ hmR0VmxExitMovDRx,
755 /* 30 VMX_EXIT_IO_INSTR */ hmR0VmxExitIoInstr,
756 /* 31 VMX_EXIT_RDMSR */ hmR0VmxExitRdmsr,
757 /* 32 VMX_EXIT_WRMSR */ hmR0VmxExitWrmsr,
758 /* 33 VMX_EXIT_ERR_INVALID_GUEST_STATE */ hmR0VmxExitErrInvalidGuestState,
759 /* 34 VMX_EXIT_ERR_MSR_LOAD */ hmR0VmxExitErrUnexpected,
760 /* 35 UNDEFINED */ hmR0VmxExitErrUnexpected,
761 /* 36 VMX_EXIT_MWAIT */ hmR0VmxExitMwait,
762 /* 37 VMX_EXIT_MTF */ hmR0VmxExitMtf,
763 /* 38 UNDEFINED */ hmR0VmxExitErrUnexpected,
764 /* 39 VMX_EXIT_MONITOR */ hmR0VmxExitMonitor,
765 /* 40 VMX_EXIT_PAUSE */ hmR0VmxExitPause,
766 /* 41 VMX_EXIT_ERR_MACHINE_CHECK */ hmR0VmxExitErrUnexpected,
767 /* 42 UNDEFINED */ hmR0VmxExitErrUnexpected,
768 /* 43 VMX_EXIT_TPR_BELOW_THRESHOLD */ hmR0VmxExitTprBelowThreshold,
769 /* 44 VMX_EXIT_APIC_ACCESS */ hmR0VmxExitApicAccess,
770 /* 45 VMX_EXIT_VIRTUALIZED_EOI */ hmR0VmxExitErrUnexpected,
771 /* 46 VMX_EXIT_GDTR_IDTR_ACCESS */ hmR0VmxExitErrUnexpected,
772 /* 47 VMX_EXIT_LDTR_TR_ACCESS */ hmR0VmxExitErrUnexpected,
773 /* 48 VMX_EXIT_EPT_VIOLATION */ hmR0VmxExitEptViolation,
774 /* 49 VMX_EXIT_EPT_MISCONFIG */ hmR0VmxExitEptMisconfig,
775 /* 50 VMX_EXIT_INVEPT */ hmR0VmxExitSetPendingXcptUD,
776 /* 51 VMX_EXIT_RDTSCP */ hmR0VmxExitRdtscp,
777 /* 52 VMX_EXIT_PREEMPT_TIMER */ hmR0VmxExitPreemptTimer,
778#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
779 /* 53 VMX_EXIT_INVVPID */ hmR0VmxExitInvvpid,
780#else
781 /* 53 VMX_EXIT_INVVPID */ hmR0VmxExitSetPendingXcptUD,
782#endif
783 /* 54 VMX_EXIT_WBINVD */ hmR0VmxExitWbinvd,
784 /* 55 VMX_EXIT_XSETBV */ hmR0VmxExitXsetbv,
785 /* 56 VMX_EXIT_APIC_WRITE */ hmR0VmxExitErrUnexpected,
786 /* 57 VMX_EXIT_RDRAND */ hmR0VmxExitErrUnexpected,
787 /* 58 VMX_EXIT_INVPCID */ hmR0VmxExitInvpcid,
788 /* 59 VMX_EXIT_VMFUNC */ hmR0VmxExitErrUnexpected,
789 /* 60 VMX_EXIT_ENCLS */ hmR0VmxExitErrUnexpected,
790 /* 61 VMX_EXIT_RDSEED */ hmR0VmxExitErrUnexpected,
791 /* 62 VMX_EXIT_PML_FULL */ hmR0VmxExitErrUnexpected,
792 /* 63 VMX_EXIT_XSAVES */ hmR0VmxExitErrUnexpected,
793 /* 64 VMX_EXIT_XRSTORS */ hmR0VmxExitErrUnexpected,
794 /* 65 UNDEFINED */ hmR0VmxExitErrUnexpected,
795 /* 66 VMX_EXIT_SPP_EVENT */ hmR0VmxExitErrUnexpected,
796 /* 67 VMX_EXIT_UMWAIT */ hmR0VmxExitErrUnexpected,
797 /* 68 VMX_EXIT_TPAUSE */ hmR0VmxExitErrUnexpected,
798};
799#endif /* HMVMX_USE_FUNCTION_TABLE */
800
801#if defined(VBOX_STRICT) && defined(LOG_ENABLED)
802static const char * const g_apszVmxInstrErrors[HMVMX_INSTR_ERROR_MAX + 1] =
803{
804 /* 0 */ "(Not Used)",
805 /* 1 */ "VMCALL executed in VMX root operation.",
806 /* 2 */ "VMCLEAR with invalid physical address.",
807 /* 3 */ "VMCLEAR with VMXON pointer.",
808 /* 4 */ "VMLAUNCH with non-clear VMCS.",
809 /* 5 */ "VMRESUME with non-launched VMCS.",
810 /* 6 */ "VMRESUME after VMXOFF",
811 /* 7 */ "VM-entry with invalid control fields.",
812 /* 8 */ "VM-entry with invalid host state fields.",
813 /* 9 */ "VMPTRLD with invalid physical address.",
814 /* 10 */ "VMPTRLD with VMXON pointer.",
815 /* 11 */ "VMPTRLD with incorrect revision identifier.",
816 /* 12 */ "VMREAD/VMWRITE from/to unsupported VMCS component.",
817 /* 13 */ "VMWRITE to read-only VMCS component.",
818 /* 14 */ "(Not Used)",
819 /* 15 */ "VMXON executed in VMX root operation.",
820 /* 16 */ "VM-entry with invalid executive-VMCS pointer.",
821 /* 17 */ "VM-entry with non-launched executing VMCS.",
822 /* 18 */ "VM-entry with executive-VMCS pointer not VMXON pointer.",
823 /* 19 */ "VMCALL with non-clear VMCS.",
824 /* 20 */ "VMCALL with invalid VM-exit control fields.",
825 /* 21 */ "(Not Used)",
826 /* 22 */ "VMCALL with incorrect MSEG revision identifier.",
827 /* 23 */ "VMXOFF under dual monitor treatment of SMIs and SMM.",
828 /* 24 */ "VMCALL with invalid SMM-monitor features.",
829 /* 25 */ "VM-entry with invalid VM-execution control fields in executive VMCS.",
830 /* 26 */ "VM-entry with events blocked by MOV SS.",
831 /* 27 */ "(Not Used)",
832 /* 28 */ "Invalid operand to INVEPT/INVVPID."
833};
834#endif /* VBOX_STRICT && LOG_ENABLED */
835
836
837/**
838 * Get the CR0 guest/host mask that does not change through the lifetime of a VM.
839 *
840 * Any bit set in this mask is owned by the host/hypervisor and would cause a
841 * VM-exit when modified by the guest.
842 *
843 * @returns The static CR0 guest/host mask.
844 * @param pVCpu The cross context virtual CPU structure.
845 */
846DECL_FORCE_INLINE(uint64_t) hmR0VmxGetFixedCr0Mask(PCVMCPU pVCpu)
847{
848 /*
849 * Modifications to CR0 bits that VT-x ignores saving/restoring (CD, ET, NW) and
850 * to CR0 bits that we require for shadow paging (PG) by the guest must cause VM-exits.
851 */
852 /** @todo Avoid intercepting CR0.PE with unrestricted guest execution. Fix PGM
853 * enmGuestMode to be in-sync with the current mode. See @bugref{6398}
854 * and @bugref{6944}. */
855 PVM pVM = pVCpu->CTX_SUFF(pVM);
856 return ( X86_CR0_PE
857 | X86_CR0_NE
858 | (pVM->hm.s.fNestedPaging ? 0 : X86_CR0_WP)
859 | X86_CR0_PG
860 | X86_CR0_ET /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.ET */
861 | X86_CR0_CD /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.CD */
862 | X86_CR0_NW); /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.NW */
863}
864
865
866/**
867 * Gets the CR4 guest/host mask that does not change through the lifetime of a VM.
868 *
869 * Any bit set in this mask is owned by the host/hypervisor and would cause a
870 * VM-exit when modified by the guest.
871 *
872 * @returns The static CR4 guest/host mask.
873 * @param pVCpu The cross context virtual CPU structure.
874 */
875DECL_FORCE_INLINE(uint64_t) hmR0VmxGetFixedCr4Mask(PCVMCPU pVCpu)
876{
877 /*
878 * We need to look at the host features here (for e.g. OSXSAVE, PCID) because
879 * these bits are reserved on hardware that does not support them. Since the
880 * CPU cannot refer to our virtual CPUID, we need to intercept CR4 changes to
881 * these bits and handle it depending on whether we expose them to the guest.
882 */
883 PVM pVM = pVCpu->CTX_SUFF(pVM);
884 bool const fXSaveRstor = pVM->cpum.ro.HostFeatures.fXSaveRstor;
885 bool const fPcid = pVM->cpum.ro.HostFeatures.fPcid;
886 return ( X86_CR4_VMXE
887 | X86_CR4_VME
888 | X86_CR4_PAE
889 | X86_CR4_PGE
890 | X86_CR4_PSE
891 | (fXSaveRstor ? X86_CR4_OSXSAVE : 0)
892 | (fPcid ? X86_CR4_PCIDE : 0));
893}
894
895
896/**
897 * Returns whether the the VM-exit MSR-store area differs from the VM-exit MSR-load
898 * area.
899 *
900 * @returns @c true if it's different, @c false otherwise.
901 * @param pVmcsInfo The VMCS info. object.
902 */
903DECL_FORCE_INLINE(bool) hmR0VmxIsSeparateExitMsrStoreAreaVmcs(PCVMXVMCSINFO pVmcsInfo)
904{
905 return RT_BOOL( pVmcsInfo->pvGuestMsrStore != pVmcsInfo->pvGuestMsrLoad
906 && pVmcsInfo->pvGuestMsrStore);
907}
908
909
910/**
911 * Sets the given Processor-based VM-execution controls.
912 *
913 * @param pVmxTransient The VMX-transient structure.
914 * @param uProcCtls The Processor-based VM-execution controls to set.
915 */
916static void hmR0VmxSetProcCtlsVmcs(PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
917{
918 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
919 if ((pVmcsInfo->u32ProcCtls & uProcCtls) != uProcCtls)
920 {
921 pVmcsInfo->u32ProcCtls |= uProcCtls;
922 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
923 AssertRC(rc);
924 }
925}
926
927
928/**
929 * Removes the given Processor-based VM-execution controls.
930 *
931 * @param pVCpu The cross context virtual CPU structure.
932 * @param pVmxTransient The VMX-transient structure.
933 * @param uProcCtls The Processor-based VM-execution controls to remove.
934 *
935 * @remarks When executing a nested-guest, this will not remove any of the specified
936 * controls if the guest hypervisor has set any one of them.
937 */
938static void hmR0VmxRemoveProcCtlsVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
939{
940 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
941 if (pVmcsInfo->u32ProcCtls & uProcCtls)
942 {
943#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
944 bool const fRemoveCtls = !pVmxTransient->fIsNestedGuest
945 ? true
946 : !CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uProcCtls);
947#else
948 NOREF(pVCpu);
949 bool const fRemoveCtls = true;
950#endif
951 if (fRemoveCtls)
952 {
953 pVmcsInfo->u32ProcCtls &= ~uProcCtls;
954 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
955 AssertRC(rc);
956 }
957 }
958}
959
960
961/**
962 * Sets the TSC offset for the current VMCS.
963 *
964 * @param uTscOffset The TSC offset to set.
965 * @param pVmcsInfo The VMCS info. object.
966 */
967static void hmR0VmxSetTscOffsetVmcs(PVMXVMCSINFO pVmcsInfo, uint64_t uTscOffset)
968{
969 if (pVmcsInfo->u64TscOffset != uTscOffset)
970 {
971 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, uTscOffset);
972 AssertRC(rc);
973 pVmcsInfo->u64TscOffset = uTscOffset;
974 }
975}
976
977
978/**
979 * Adds one or more exceptions to the exception bitmap and commits it to the current
980 * VMCS.
981 *
982 * @param pVmxTransient The VMX-transient structure.
983 * @param uXcptMask The exception(s) to add.
984 */
985static void hmR0VmxAddXcptInterceptMask(PVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
986{
987 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
988 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
989 if ((uXcptBitmap & uXcptMask) != uXcptMask)
990 {
991 uXcptBitmap |= uXcptMask;
992 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
993 AssertRC(rc);
994 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
995 }
996}
997
998
999/**
1000 * Adds an exception to the exception bitmap and commits it to the current VMCS.
1001 *
1002 * @param pVmxTransient The VMX-transient structure.
1003 * @param uXcpt The exception to add.
1004 */
1005static void hmR0VmxAddXcptIntercept(PVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1006{
1007 Assert(uXcpt <= X86_XCPT_LAST);
1008 hmR0VmxAddXcptInterceptMask(pVmxTransient, RT_BIT_32(uXcpt));
1009}
1010
1011
1012/**
1013 * Remove one or more exceptions from the exception bitmap and commits it to the
1014 * current VMCS.
1015 *
1016 * This takes care of not removing the exception intercept if a nested-guest
1017 * requires the exception to be intercepted.
1018 *
1019 * @returns VBox status code.
1020 * @param pVCpu The cross context virtual CPU structure.
1021 * @param pVmxTransient The VMX-transient structure.
1022 * @param uXcptMask The exception(s) to remove.
1023 */
1024static int hmR0VmxRemoveXcptInterceptMask(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1025{
1026 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1027 uint32_t u32XcptBitmap = pVmcsInfo->u32XcptBitmap;
1028 if (u32XcptBitmap & uXcptMask)
1029 {
1030#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1031 if (!pVmxTransient->fIsNestedGuest)
1032 { /* likely */ }
1033 else
1034 {
1035 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
1036 uXcptMask &= ~pVmcsNstGst->u32XcptBitmap;
1037 }
1038#endif
1039#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
1040 uXcptMask &= ~( RT_BIT(X86_XCPT_BP)
1041 | RT_BIT(X86_XCPT_DE)
1042 | RT_BIT(X86_XCPT_NM)
1043 | RT_BIT(X86_XCPT_TS)
1044 | RT_BIT(X86_XCPT_UD)
1045 | RT_BIT(X86_XCPT_NP)
1046 | RT_BIT(X86_XCPT_SS)
1047 | RT_BIT(X86_XCPT_GP)
1048 | RT_BIT(X86_XCPT_PF)
1049 | RT_BIT(X86_XCPT_MF));
1050#elif defined(HMVMX_ALWAYS_TRAP_PF)
1051 uXcptMask &= ~RT_BIT(X86_XCPT_PF);
1052#endif
1053 if (uXcptMask)
1054 {
1055 /* Validate we are not removing any essential exception intercepts. */
1056 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging || !(uXcptMask & RT_BIT(X86_XCPT_PF)));
1057 NOREF(pVCpu);
1058 Assert(!(uXcptMask & RT_BIT(X86_XCPT_DB)));
1059 Assert(!(uXcptMask & RT_BIT(X86_XCPT_AC)));
1060
1061 /* Remove it from the exception bitmap. */
1062 u32XcptBitmap &= ~uXcptMask;
1063
1064 /* Commit and update the cache if necessary. */
1065 if (pVmcsInfo->u32XcptBitmap != u32XcptBitmap)
1066 {
1067 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
1068 AssertRC(rc);
1069 pVmcsInfo->u32XcptBitmap = u32XcptBitmap;
1070 }
1071 }
1072 }
1073 return VINF_SUCCESS;
1074}
1075
1076
1077/**
1078 * Remove an exceptions from the exception bitmap and commits it to the current
1079 * VMCS.
1080 *
1081 * @returns VBox status code.
1082 * @param pVCpu The cross context virtual CPU structure.
1083 * @param pVmxTransient The VMX-transient structure.
1084 * @param uXcpt The exception to remove.
1085 */
1086static int hmR0VmxRemoveXcptIntercept(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1087{
1088 return hmR0VmxRemoveXcptInterceptMask(pVCpu, pVmxTransient, RT_BIT(uXcpt));
1089}
1090
1091
1092/**
1093 * Loads the VMCS specified by the VMCS info. object.
1094 *
1095 * @returns VBox status code.
1096 * @param pVmcsInfo The VMCS info. object.
1097 *
1098 * @remarks Can be called with interrupts disabled.
1099 */
1100static int hmR0VmxLoadVmcs(PVMXVMCSINFO pVmcsInfo)
1101{
1102 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1103 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1104
1105 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysVmcs);
1106 if (RT_SUCCESS(rc))
1107 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1108 return rc;
1109}
1110
1111
1112/**
1113 * Clears the VMCS specified by the VMCS info. object.
1114 *
1115 * @returns VBox status code.
1116 * @param pVmcsInfo The VMCS info. object.
1117 *
1118 * @remarks Can be called with interrupts disabled.
1119 */
1120static int hmR0VmxClearVmcs(PVMXVMCSINFO pVmcsInfo)
1121{
1122 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1123 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1124
1125 int rc = VMXClearVmcs(pVmcsInfo->HCPhysVmcs);
1126 if (RT_SUCCESS(rc))
1127 pVmcsInfo->fVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1128 return rc;
1129}
1130
1131
1132#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1133/**
1134 * Loads the shadow VMCS specified by the VMCS info. object.
1135 *
1136 * @returns VBox status code.
1137 * @param pVmcsInfo The VMCS info. object.
1138 *
1139 * @remarks Can be called with interrupts disabled.
1140 */
1141static int hmR0VmxLoadShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1142{
1143 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1144 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1145
1146 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysShadowVmcs);
1147 if (RT_SUCCESS(rc))
1148 pVmcsInfo->fShadowVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1149 return rc;
1150}
1151
1152
1153/**
1154 * Clears the shadow VMCS specified by the VMCS info. object.
1155 *
1156 * @returns VBox status code.
1157 * @param pVmcsInfo The VMCS info. object.
1158 *
1159 * @remarks Can be called with interrupts disabled.
1160 */
1161static int hmR0VmxClearShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1162{
1163 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1164 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1165
1166 int rc = VMXClearVmcs(pVmcsInfo->HCPhysShadowVmcs);
1167 if (RT_SUCCESS(rc))
1168 pVmcsInfo->fShadowVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1169 return rc;
1170}
1171
1172
1173/**
1174 * Switches from and to the specified VMCSes.
1175 *
1176 * @returns VBox status code.
1177 * @param pVmcsInfoFrom The VMCS info. object we are switching from.
1178 * @param pVmcsInfoTo The VMCS info. object we are switching to.
1179 *
1180 * @remarks Called with interrupts disabled.
1181 */
1182static int hmR0VmxSwitchVmcs(PVMXVMCSINFO pVmcsInfoFrom, PVMXVMCSINFO pVmcsInfoTo)
1183{
1184 /*
1185 * Clear the VMCS we are switching out if it has not already been cleared.
1186 * This will sync any CPU internal data back to the VMCS.
1187 */
1188 if (pVmcsInfoFrom->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1189 {
1190 int rc = hmR0VmxClearVmcs(pVmcsInfoFrom);
1191 if (RT_SUCCESS(rc))
1192 {
1193 /*
1194 * The shadow VMCS, if any, would not be active at this point since we
1195 * would have cleared it while importing the virtual hardware-virtualization
1196 * state as part the VMLAUNCH/VMRESUME VM-exit. Hence, there's no need to
1197 * clear the shadow VMCS here, just assert for safety.
1198 */
1199 Assert(!pVmcsInfoFrom->pvShadowVmcs || pVmcsInfoFrom->fShadowVmcsState == VMX_V_VMCS_LAUNCH_STATE_CLEAR);
1200 }
1201 else
1202 return rc;
1203 }
1204
1205 /*
1206 * Clear the VMCS we are switching to if it has not already been cleared.
1207 * This will initialize the VMCS launch state to "clear" required for loading it.
1208 *
1209 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
1210 */
1211 if (pVmcsInfoTo->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1212 {
1213 int rc = hmR0VmxClearVmcs(pVmcsInfoTo);
1214 if (RT_SUCCESS(rc))
1215 { /* likely */ }
1216 else
1217 return rc;
1218 }
1219
1220 /*
1221 * Finally, load the VMCS we are switching to.
1222 */
1223 return hmR0VmxLoadVmcs(pVmcsInfoTo);
1224}
1225
1226
1227/**
1228 * Switches between the guest VMCS and the nested-guest VMCS as specified by the
1229 * caller.
1230 *
1231 * @returns VBox status code.
1232 * @param pVCpu The cross context virtual CPU structure.
1233 * @param fSwitchToNstGstVmcs Whether to switch to the nested-guest VMCS (pass
1234 * true) or guest VMCS (pass false).
1235 */
1236static int hmR0VmxSwitchToGstOrNstGstVmcs(PVMCPU pVCpu, bool fSwitchToNstGstVmcs)
1237{
1238 /* Ensure we have synced everything from the guest-CPU context to the VMCS before switching. */
1239 HMVMX_CPUMCTX_ASSERT(pVCpu, HMVMX_CPUMCTX_EXTRN_ALL);
1240
1241 PVMXVMCSINFO pVmcsInfoFrom;
1242 PVMXVMCSINFO pVmcsInfoTo;
1243 if (fSwitchToNstGstVmcs)
1244 {
1245 pVmcsInfoFrom = &pVCpu->hm.s.vmx.VmcsInfo;
1246 pVmcsInfoTo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
1247 }
1248 else
1249 {
1250 pVmcsInfoFrom = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
1251 pVmcsInfoTo = &pVCpu->hm.s.vmx.VmcsInfo;
1252 }
1253
1254 /*
1255 * Disable interrupts to prevent being preempted while we switch the current VMCS as the
1256 * preemption hook code path acquires the current VMCS.
1257 */
1258 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1259
1260 int rc = hmR0VmxSwitchVmcs(pVmcsInfoFrom, pVmcsInfoTo);
1261 if (RT_SUCCESS(rc))
1262 {
1263 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs = fSwitchToNstGstVmcs;
1264
1265 /*
1266 * If we are switching to a VMCS that was executed on a different host CPU or was
1267 * never executed before, flag that we need to export the host state before executing
1268 * guest/nested-guest code using hardware-assisted VMX.
1269 *
1270 * This could probably be done in a preemptible context since the preemption hook
1271 * will flag the necessary change in host context. However, since preemption is
1272 * already disabled and to avoid making assumptions about host specific code in
1273 * RTMpCpuId when called with preemption enabled, we'll do this while preemption is
1274 * disabled.
1275 */
1276 if (pVmcsInfoTo->idHostCpu == RTMpCpuId())
1277 { /* likely */ }
1278 else
1279 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE);
1280
1281 ASMSetFlags(fEFlags);
1282
1283 /*
1284 * We use a different VM-exit MSR-store areas for the guest and nested-guest. Hence,
1285 * flag that we need to update the host MSR values there. Even if we decide in the
1286 * future to share the VM-exit MSR-store area page between the guest and nested-guest,
1287 * if its content differs, we would have to update the host MSRs anyway.
1288 */
1289 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
1290 }
1291 else
1292 ASMSetFlags(fEFlags);
1293 return rc;
1294}
1295#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
1296
1297
1298/**
1299 * Updates the VM's last error record.
1300 *
1301 * If there was a VMX instruction error, reads the error data from the VMCS and
1302 * updates VCPU's last error record as well.
1303 *
1304 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1305 * Can be NULL if @a rc is not VERR_VMX_UNABLE_TO_START_VM or
1306 * VERR_VMX_INVALID_VMCS_FIELD.
1307 * @param rc The error code.
1308 */
1309static void hmR0VmxUpdateErrorRecord(PVMCPU pVCpu, int rc)
1310{
1311 if ( rc == VERR_VMX_INVALID_VMCS_FIELD
1312 || rc == VERR_VMX_UNABLE_TO_START_VM)
1313 {
1314 AssertPtrReturnVoid(pVCpu);
1315 VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
1316 }
1317 pVCpu->CTX_SUFF(pVM)->hm.s.rcInit = rc;
1318}
1319
1320
1321#ifdef VBOX_STRICT
1322/**
1323 * Reads the VM-entry interruption-information field from the VMCS into the VMX
1324 * transient structure.
1325 *
1326 * @param pVmxTransient The VMX-transient structure.
1327 */
1328DECLINLINE(void) hmR0VmxReadEntryIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1329{
1330 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntInfo);
1331 AssertRC(rc);
1332}
1333
1334
1335/**
1336 * Reads the VM-entry exception error code field from the VMCS into
1337 * the VMX transient structure.
1338 *
1339 * @param pVmxTransient The VMX-transient structure.
1340 */
1341DECLINLINE(void) hmR0VmxReadEntryXcptErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1342{
1343 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
1344 AssertRC(rc);
1345}
1346
1347
1348/**
1349 * Reads the VM-entry exception error code field from the VMCS into
1350 * the VMX transient structure.
1351 *
1352 * @param pVmxTransient The VMX-transient structure.
1353 */
1354DECLINLINE(void) hmR0VmxReadEntryInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1355{
1356 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
1357 AssertRC(rc);
1358}
1359#endif /* VBOX_STRICT */
1360
1361
1362/**
1363 * Reads the VM-exit interruption-information field from the VMCS into the VMX
1364 * transient structure.
1365 *
1366 * @param pVmxTransient The VMX-transient structure.
1367 */
1368DECLINLINE(void) hmR0VmxReadExitIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1369{
1370 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_INFO))
1371 {
1372 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1373 AssertRC(rc);
1374 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_INFO;
1375 }
1376}
1377
1378
1379/**
1380 * Reads the VM-exit interruption error code from the VMCS into the VMX
1381 * transient structure.
1382 *
1383 * @param pVmxTransient The VMX-transient structure.
1384 */
1385DECLINLINE(void) hmR0VmxReadExitIntErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1386{
1387 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE))
1388 {
1389 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1390 AssertRC(rc);
1391 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE;
1392 }
1393}
1394
1395
1396/**
1397 * Reads the VM-exit instruction length field from the VMCS into the VMX
1398 * transient structure.
1399 *
1400 * @param pVmxTransient The VMX-transient structure.
1401 */
1402DECLINLINE(void) hmR0VmxReadExitInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1403{
1404 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_LEN))
1405 {
1406 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbInstr);
1407 AssertRC(rc);
1408 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_LEN;
1409 }
1410}
1411
1412
1413/**
1414 * Reads the VM-exit instruction-information field from the VMCS into
1415 * the VMX transient structure.
1416 *
1417 * @param pVmxTransient The VMX-transient structure.
1418 */
1419DECLINLINE(void) hmR0VmxReadExitInstrInfoVmcs(PVMXTRANSIENT pVmxTransient)
1420{
1421 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_INFO))
1422 {
1423 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1424 AssertRC(rc);
1425 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_INFO;
1426 }
1427}
1428
1429
1430/**
1431 * Reads the Exit Qualification from the VMCS into the VMX transient structure.
1432 *
1433 * @param pVmxTransient The VMX-transient structure.
1434 */
1435DECLINLINE(void) hmR0VmxReadExitQualVmcs(PVMXTRANSIENT pVmxTransient)
1436{
1437 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_QUALIFICATION))
1438 {
1439 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1440 AssertRC(rc);
1441 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION;
1442 }
1443}
1444
1445
1446/**
1447 * Reads the Guest-linear address from the VMCS into the VMX transient structure.
1448 *
1449 * @param pVmxTransient The VMX-transient structure.
1450 */
1451DECLINLINE(void) hmR0VmxReadGuestLinearAddrVmcs(PVMXTRANSIENT pVmxTransient)
1452{
1453 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_LINEAR_ADDR))
1454 {
1455 int rc = VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1456 AssertRC(rc);
1457 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_LINEAR_ADDR;
1458 }
1459}
1460
1461
1462/**
1463 * Reads the Guest-physical address from the VMCS into the VMX transient structure.
1464 *
1465 * @param pVmxTransient The VMX-transient structure.
1466 */
1467DECLINLINE(void) hmR0VmxReadGuestPhysicalAddrVmcs(PVMXTRANSIENT pVmxTransient)
1468{
1469 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PHYSICAL_ADDR))
1470 {
1471 int rc = VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1472 AssertRC(rc);
1473 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PHYSICAL_ADDR;
1474 }
1475}
1476
1477
1478/**
1479 * Reads the IDT-vectoring information field from the VMCS into the VMX
1480 * transient structure.
1481 *
1482 * @param pVmxTransient The VMX-transient structure.
1483 *
1484 * @remarks No-long-jump zone!!!
1485 */
1486DECLINLINE(void) hmR0VmxReadIdtVectoringInfoVmcs(PVMXTRANSIENT pVmxTransient)
1487{
1488 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_INFO))
1489 {
1490 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1491 AssertRC(rc);
1492 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_INFO;
1493 }
1494}
1495
1496
1497/**
1498 * Reads the IDT-vectoring error code from the VMCS into the VMX
1499 * transient structure.
1500 *
1501 * @param pVmxTransient The VMX-transient structure.
1502 */
1503DECLINLINE(void) hmR0VmxReadIdtVectoringErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1504{
1505 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_ERROR_CODE))
1506 {
1507 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1508 AssertRC(rc);
1509 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_ERROR_CODE;
1510 }
1511}
1512
1513#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
1514/**
1515 * Reads all relevant read-only VMCS fields into the VMX transient structure.
1516 *
1517 * @param pVmxTransient The VMX-transient structure.
1518 */
1519static void hmR0VmxReadAllRoFieldsVmcs(PVMXTRANSIENT pVmxTransient)
1520{
1521 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1522 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbInstr);
1523 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1524 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1525 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1526 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1527 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1528 rc |= VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1529 rc |= VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1530 AssertRC(rc);
1531 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION
1532 | HMVMX_READ_EXIT_INSTR_LEN
1533 | HMVMX_READ_EXIT_INSTR_INFO
1534 | HMVMX_READ_IDT_VECTORING_INFO
1535 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
1536 | HMVMX_READ_EXIT_INTERRUPTION_INFO
1537 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
1538 | HMVMX_READ_GUEST_LINEAR_ADDR
1539 | HMVMX_READ_GUEST_PHYSICAL_ADDR;
1540}
1541#endif
1542
1543/**
1544 * Enters VMX root mode operation on the current CPU.
1545 *
1546 * @returns VBox status code.
1547 * @param pVM The cross context VM structure. Can be
1548 * NULL, after a resume.
1549 * @param HCPhysCpuPage Physical address of the VMXON region.
1550 * @param pvCpuPage Pointer to the VMXON region.
1551 */
1552static int hmR0VmxEnterRootMode(PVM pVM, RTHCPHYS HCPhysCpuPage, void *pvCpuPage)
1553{
1554 Assert(HCPhysCpuPage && HCPhysCpuPage != NIL_RTHCPHYS);
1555 Assert(RT_ALIGN_T(HCPhysCpuPage, _4K, RTHCPHYS) == HCPhysCpuPage);
1556 Assert(pvCpuPage);
1557 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1558
1559 if (pVM)
1560 {
1561 /* Write the VMCS revision identifier to the VMXON region. */
1562 *(uint32_t *)pvCpuPage = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
1563 }
1564
1565 /* Paranoid: Disable interrupts as, in theory, interrupt handlers might mess with CR4. */
1566 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1567
1568 /* Enable the VMX bit in CR4 if necessary. */
1569 RTCCUINTREG const uOldCr4 = SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
1570
1571 /* Enter VMX root mode. */
1572 int rc = VMXEnable(HCPhysCpuPage);
1573 if (RT_FAILURE(rc))
1574 {
1575 if (!(uOldCr4 & X86_CR4_VMXE))
1576 SUPR0ChangeCR4(0 /* fOrMask */, ~X86_CR4_VMXE);
1577
1578 if (pVM)
1579 pVM->hm.s.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
1580 }
1581
1582 /* Restore interrupts. */
1583 ASMSetFlags(fEFlags);
1584 return rc;
1585}
1586
1587
1588/**
1589 * Exits VMX root mode operation on the current CPU.
1590 *
1591 * @returns VBox status code.
1592 */
1593static int hmR0VmxLeaveRootMode(void)
1594{
1595 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1596
1597 /* Paranoid: Disable interrupts as, in theory, interrupts handlers might mess with CR4. */
1598 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1599
1600 /* If we're for some reason not in VMX root mode, then don't leave it. */
1601 RTCCUINTREG const uHostCr4 = ASMGetCR4();
1602
1603 int rc;
1604 if (uHostCr4 & X86_CR4_VMXE)
1605 {
1606 /* Exit VMX root mode and clear the VMX bit in CR4. */
1607 VMXDisable();
1608 SUPR0ChangeCR4(0 /* fOrMask */, ~X86_CR4_VMXE);
1609 rc = VINF_SUCCESS;
1610 }
1611 else
1612 rc = VERR_VMX_NOT_IN_VMX_ROOT_MODE;
1613
1614 /* Restore interrupts. */
1615 ASMSetFlags(fEFlags);
1616 return rc;
1617}
1618
1619
1620/**
1621 * Allocates and maps a physically contiguous page. The allocated page is
1622 * zero'd out (used by various VT-x structures).
1623 *
1624 * @returns IPRT status code.
1625 * @param pMemObj Pointer to the ring-0 memory object.
1626 * @param ppVirt Where to store the virtual address of the allocation.
1627 * @param pHCPhys Where to store the physical address of the allocation.
1628 */
1629static int hmR0VmxPageAllocZ(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
1630{
1631 AssertPtr(pMemObj);
1632 AssertPtr(ppVirt);
1633 AssertPtr(pHCPhys);
1634 int rc = RTR0MemObjAllocCont(pMemObj, X86_PAGE_4K_SIZE, false /* fExecutable */);
1635 if (RT_FAILURE(rc))
1636 return rc;
1637 *ppVirt = RTR0MemObjAddress(*pMemObj);
1638 *pHCPhys = RTR0MemObjGetPagePhysAddr(*pMemObj, 0 /* iPage */);
1639 ASMMemZero32(*ppVirt, X86_PAGE_4K_SIZE);
1640 return VINF_SUCCESS;
1641}
1642
1643
1644/**
1645 * Frees and unmaps an allocated, physical page.
1646 *
1647 * @param pMemObj Pointer to the ring-0 memory object.
1648 * @param ppVirt Where to re-initialize the virtual address of allocation as
1649 * 0.
1650 * @param pHCPhys Where to re-initialize the physical address of the
1651 * allocation as 0.
1652 */
1653static void hmR0VmxPageFree(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
1654{
1655 AssertPtr(pMemObj);
1656 AssertPtr(ppVirt);
1657 AssertPtr(pHCPhys);
1658 /* NULL is valid, accepted and ignored by the free function below. */
1659 RTR0MemObjFree(*pMemObj, true /* fFreeMappings */);
1660 *pMemObj = NIL_RTR0MEMOBJ;
1661 *ppVirt = NULL;
1662 *pHCPhys = NIL_RTHCPHYS;
1663}
1664
1665
1666/**
1667 * Initializes a VMCS info. object.
1668 *
1669 * @param pVmcsInfo The VMCS info. object.
1670 */
1671static void hmR0VmxInitVmcsInfo(PVMXVMCSINFO pVmcsInfo)
1672{
1673 memset(pVmcsInfo, 0, sizeof(*pVmcsInfo));
1674
1675 Assert(pVmcsInfo->hMemObjVmcs == NIL_RTR0MEMOBJ);
1676 Assert(pVmcsInfo->hMemObjShadowVmcs == NIL_RTR0MEMOBJ);
1677 Assert(pVmcsInfo->hMemObjMsrBitmap == NIL_RTR0MEMOBJ);
1678 Assert(pVmcsInfo->hMemObjGuestMsrLoad == NIL_RTR0MEMOBJ);
1679 Assert(pVmcsInfo->hMemObjGuestMsrStore == NIL_RTR0MEMOBJ);
1680 Assert(pVmcsInfo->hMemObjHostMsrLoad == NIL_RTR0MEMOBJ);
1681 pVmcsInfo->HCPhysVmcs = NIL_RTHCPHYS;
1682 pVmcsInfo->HCPhysShadowVmcs = NIL_RTHCPHYS;
1683 pVmcsInfo->HCPhysMsrBitmap = NIL_RTHCPHYS;
1684 pVmcsInfo->HCPhysGuestMsrLoad = NIL_RTHCPHYS;
1685 pVmcsInfo->HCPhysGuestMsrStore = NIL_RTHCPHYS;
1686 pVmcsInfo->HCPhysHostMsrLoad = NIL_RTHCPHYS;
1687 pVmcsInfo->HCPhysVirtApic = NIL_RTHCPHYS;
1688 pVmcsInfo->HCPhysEPTP = NIL_RTHCPHYS;
1689 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
1690 pVmcsInfo->idHostCpu = NIL_RTCPUID;
1691}
1692
1693
1694/**
1695 * Frees the VT-x structures for a VMCS info. object.
1696 *
1697 * @param pVM The cross context VM structure.
1698 * @param pVmcsInfo The VMCS info. object.
1699 */
1700static void hmR0VmxFreeVmcsInfo(PVM pVM, PVMXVMCSINFO pVmcsInfo)
1701{
1702 hmR0VmxPageFree(&pVmcsInfo->hMemObjVmcs, &pVmcsInfo->pvVmcs, &pVmcsInfo->HCPhysVmcs);
1703
1704#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1705 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1706 hmR0VmxPageFree(&pVmcsInfo->hMemObjShadowVmcs, &pVmcsInfo->pvShadowVmcs, &pVmcsInfo->HCPhysShadowVmcs);
1707#endif
1708
1709 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
1710 hmR0VmxPageFree(&pVmcsInfo->hMemObjMsrBitmap, &pVmcsInfo->pvMsrBitmap, &pVmcsInfo->HCPhysMsrBitmap);
1711
1712 hmR0VmxPageFree(&pVmcsInfo->hMemObjHostMsrLoad, &pVmcsInfo->pvHostMsrLoad, &pVmcsInfo->HCPhysHostMsrLoad);
1713 hmR0VmxPageFree(&pVmcsInfo->hMemObjGuestMsrLoad, &pVmcsInfo->pvGuestMsrLoad, &pVmcsInfo->HCPhysGuestMsrLoad);
1714 hmR0VmxPageFree(&pVmcsInfo->hMemObjGuestMsrStore, &pVmcsInfo->pvGuestMsrStore, &pVmcsInfo->HCPhysGuestMsrStore);
1715
1716 hmR0VmxInitVmcsInfo(pVmcsInfo);
1717}
1718
1719
1720/**
1721 * Allocates the VT-x structures for a VMCS info. object.
1722 *
1723 * @returns VBox status code.
1724 * @param pVCpu The cross context virtual CPU structure.
1725 * @param pVmcsInfo The VMCS info. object.
1726 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
1727 */
1728static int hmR0VmxAllocVmcsInfo(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
1729{
1730 PVM pVM = pVCpu->CTX_SUFF(pVM);
1731
1732 /* Allocate the guest VM control structure (VMCS). */
1733 int rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjVmcs, &pVmcsInfo->pvVmcs, &pVmcsInfo->HCPhysVmcs);
1734 if (RT_SUCCESS(rc))
1735 {
1736 if (!fIsNstGstVmcs)
1737 {
1738#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1739 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1740 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjShadowVmcs, &pVmcsInfo->pvShadowVmcs, &pVmcsInfo->HCPhysShadowVmcs);
1741#endif
1742 if (RT_SUCCESS(rc))
1743 {
1744 /* Get the allocated virtual-APIC page from the virtual APIC device. */
1745 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
1746 && (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW))
1747 rc = APICGetApicPageForCpu(pVCpu, &pVmcsInfo->HCPhysVirtApic, (PRTR0PTR)&pVmcsInfo->pbVirtApic, NULL /*pR3Ptr*/);
1748 }
1749 }
1750 else
1751 {
1752 /* We don't yet support exposing VMCS shadowing to the guest. */
1753 Assert(pVmcsInfo->HCPhysShadowVmcs == NIL_RTHCPHYS);
1754 Assert(!pVmcsInfo->pvShadowVmcs);
1755
1756 /* Get the allocated virtual-APIC page from CPUM. */
1757 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW)
1758 {
1759 /** @todo NSTVMX: Get rid of this. There is no need to allocate a separate HC
1760 * page for this. Use the one provided by the nested-guest directly. */
1761 pVmcsInfo->pbVirtApic = (uint8_t *)CPUMGetGuestVmxVirtApicPage(pVCpu, &pVCpu->cpum.GstCtx,
1762 &pVmcsInfo->HCPhysVirtApic);
1763 Assert(pVmcsInfo->pbVirtApic);
1764 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1765 }
1766 }
1767
1768 if (RT_SUCCESS(rc))
1769 {
1770 /*
1771 * Allocate the MSR-bitmap if supported by the CPU. The MSR-bitmap is for
1772 * transparent accesses of specific MSRs.
1773 *
1774 * If the condition for enabling MSR bitmaps changes here, don't forget to
1775 * update HMIsMsrBitmapActive().
1776 *
1777 * We don't share MSR bitmaps between the guest and nested-guest as we then
1778 * don't need to care about carefully restoring the guest MSR bitmap.
1779 * The guest visible nested-guest MSR bitmap needs to remain unchanged.
1780 * Hence, allocate a separate MSR bitmap for the guest and nested-guest.
1781 * We also don't need to re-initialize the nested-guest MSR bitmap here as
1782 * we do that later while merging VMCS.
1783 */
1784 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
1785 {
1786 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjMsrBitmap, &pVmcsInfo->pvMsrBitmap, &pVmcsInfo->HCPhysMsrBitmap);
1787 if ( RT_SUCCESS(rc)
1788 && !fIsNstGstVmcs)
1789 ASMMemFill32(pVmcsInfo->pvMsrBitmap, X86_PAGE_4K_SIZE, UINT32_C(0xffffffff));
1790 }
1791
1792 if (RT_SUCCESS(rc))
1793 {
1794 /*
1795 * Allocate the VM-entry MSR-load area for the guest MSRs.
1796 *
1797 * Similar to MSR-bitmaps, we do not share the auto MSR-load/store are between
1798 * the guest and nested-guest.
1799 */
1800 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjGuestMsrLoad, &pVmcsInfo->pvGuestMsrLoad,
1801 &pVmcsInfo->HCPhysGuestMsrLoad);
1802 if (RT_SUCCESS(rc))
1803 {
1804 /*
1805 * We use the same page for VM-entry MSR-load and VM-exit MSR store areas.
1806 * These contain the guest MSRs to load on VM-entry and store on VM-exit.
1807 */
1808 Assert(pVmcsInfo->hMemObjGuestMsrStore == NIL_RTR0MEMOBJ);
1809 pVmcsInfo->pvGuestMsrStore = pVmcsInfo->pvGuestMsrLoad;
1810 pVmcsInfo->HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrLoad;
1811
1812 /* Allocate the VM-exit MSR-load page for the host MSRs. */
1813 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjHostMsrLoad, &pVmcsInfo->pvHostMsrLoad,
1814 &pVmcsInfo->HCPhysHostMsrLoad);
1815 }
1816 }
1817 }
1818 }
1819
1820 return rc;
1821}
1822
1823
1824/**
1825 * Free all VT-x structures for the VM.
1826 *
1827 * @returns IPRT status code.
1828 * @param pVM The cross context VM structure.
1829 */
1830static void hmR0VmxStructsFree(PVM pVM)
1831{
1832#ifdef VBOX_WITH_CRASHDUMP_MAGIC
1833 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
1834#endif
1835 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess, &pVM->hm.s.vmx.HCPhysApicAccess);
1836
1837#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1838 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1839 {
1840 RTMemFree(pVM->hm.s.vmx.paShadowVmcsFields);
1841 RTMemFree(pVM->hm.s.vmx.paShadowVmcsRoFields);
1842 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjVmreadBitmap, &pVM->hm.s.vmx.pvVmreadBitmap, &pVM->hm.s.vmx.HCPhysVmreadBitmap);
1843 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjVmwriteBitmap, &pVM->hm.s.vmx.pvVmwriteBitmap, &pVM->hm.s.vmx.HCPhysVmwriteBitmap);
1844 }
1845#endif
1846
1847 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1848 {
1849 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1850 PVMXVMCSINFO pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfo;
1851 hmR0VmxFreeVmcsInfo(pVM, pVmcsInfo);
1852#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1853 if (pVM->cpum.ro.GuestFeatures.fVmx)
1854 {
1855 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
1856 hmR0VmxFreeVmcsInfo(pVM, pVmcsInfo);
1857 }
1858#endif
1859 }
1860}
1861
1862
1863/**
1864 * Allocate all VT-x structures for the VM.
1865 *
1866 * @returns IPRT status code.
1867 * @param pVM The cross context VM structure.
1868 */
1869static int hmR0VmxStructsAlloc(PVM pVM)
1870{
1871 /*
1872 * Sanity check the VMCS size reported by the CPU as we assume 4KB allocations.
1873 * The VMCS size cannot be more than 4096 bytes.
1874 *
1875 * See Intel spec. Appendix A.1 "Basic VMX Information".
1876 */
1877 uint32_t const cbVmcs = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_SIZE);
1878 if (cbVmcs <= X86_PAGE_4K_SIZE)
1879 { /* likely */ }
1880 else
1881 {
1882 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_INVALID_VMCS_SIZE;
1883 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1884 }
1885
1886 /*
1887 * Initialize/check members up-front so we can cleanup en masse on allocation failures.
1888 */
1889#ifdef VBOX_WITH_CRASHDUMP_MAGIC
1890 Assert(pVM->hm.s.vmx.hMemObjScratch == NIL_RTR0MEMOBJ);
1891 Assert(pVM->hm.s.vmx.pbScratch == NULL);
1892 pVM->hm.s.vmx.HCPhysScratch = NIL_RTHCPHYS;
1893#endif
1894
1895 Assert(pVM->hm.s.vmx.hMemObjApicAccess == NIL_RTR0MEMOBJ);
1896 Assert(pVM->hm.s.vmx.pbApicAccess == NULL);
1897 pVM->hm.s.vmx.HCPhysApicAccess = NIL_RTHCPHYS;
1898
1899 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1900 {
1901 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1902 hmR0VmxInitVmcsInfo(&pVCpu->hm.s.vmx.VmcsInfo);
1903 hmR0VmxInitVmcsInfo(&pVCpu->hm.s.vmx.VmcsInfoNstGst);
1904 }
1905
1906 /*
1907 * Allocate per-VM VT-x structures.
1908 */
1909 int rc = VINF_SUCCESS;
1910#ifdef VBOX_WITH_CRASHDUMP_MAGIC
1911 /* Allocate crash-dump magic scratch page. */
1912 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
1913 if (RT_FAILURE(rc))
1914 {
1915 hmR0VmxStructsFree(pVM);
1916 return rc;
1917 }
1918 strcpy((char *)pVM->hm.s.vmx.pbScratch, "SCRATCH Magic");
1919 *(uint64_t *)(pVM->hm.s.vmx.pbScratch + 16) = UINT64_C(0xdeadbeefdeadbeef);
1920#endif
1921
1922 /* Allocate the APIC-access page for trapping APIC accesses from the guest. */
1923 if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
1924 {
1925 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess,
1926 &pVM->hm.s.vmx.HCPhysApicAccess);
1927 if (RT_FAILURE(rc))
1928 {
1929 hmR0VmxStructsFree(pVM);
1930 return rc;
1931 }
1932 }
1933
1934#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1935 /* Allocate the shadow VMCS fields array, VMREAD, VMWRITE bitmaps.. */
1936 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1937 {
1938 Assert(!pVM->hm.s.vmx.cShadowVmcsFields);
1939 Assert(!pVM->hm.s.vmx.cShadowVmcsRoFields);
1940 pVM->hm.s.vmx.paShadowVmcsFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
1941 pVM->hm.s.vmx.paShadowVmcsRoFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
1942 if (RT_LIKELY( pVM->hm.s.vmx.paShadowVmcsFields
1943 && pVM->hm.s.vmx.paShadowVmcsRoFields))
1944 {
1945 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjVmreadBitmap, &pVM->hm.s.vmx.pvVmreadBitmap,
1946 &pVM->hm.s.vmx.HCPhysVmreadBitmap);
1947 if (RT_SUCCESS(rc))
1948 {
1949 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjVmwriteBitmap, &pVM->hm.s.vmx.pvVmwriteBitmap,
1950 &pVM->hm.s.vmx.HCPhysVmwriteBitmap);
1951 }
1952 }
1953 else
1954 rc = VERR_NO_MEMORY;
1955
1956 if (RT_FAILURE(rc))
1957 {
1958 hmR0VmxStructsFree(pVM);
1959 return rc;
1960 }
1961 }
1962#endif
1963
1964 /*
1965 * Initialize per-VCPU VT-x structures.
1966 */
1967 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1968 {
1969 /* Allocate the guest VMCS structures. */
1970 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1971 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hm.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
1972 if (RT_SUCCESS(rc))
1973 {
1974#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1975 /* Allocate the nested-guest VMCS structures, when the VMX feature is exposed to the guest. */
1976 if (pVM->cpum.ro.GuestFeatures.fVmx)
1977 {
1978 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hm.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
1979 if (RT_SUCCESS(rc))
1980 { /* likely */ }
1981 else
1982 break;
1983 }
1984#endif
1985 }
1986 else
1987 break;
1988 }
1989
1990 if (RT_FAILURE(rc))
1991 {
1992 hmR0VmxStructsFree(pVM);
1993 return rc;
1994 }
1995
1996 return VINF_SUCCESS;
1997}
1998
1999#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2000/**
2001 * Returns whether an MSR at the given MSR-bitmap offset is intercepted or not.
2002 *
2003 * @returns @c true if the MSR is intercepted, @c false otherwise.
2004 * @param pvMsrBitmap The MSR bitmap.
2005 * @param offMsr The MSR byte offset.
2006 * @param iBit The bit offset from the byte offset.
2007 */
2008DECLINLINE(bool) hmR0VmxIsMsrBitSet(const void *pvMsrBitmap, uint16_t offMsr, int32_t iBit)
2009{
2010 uint8_t const * const pbMsrBitmap = (uint8_t const * const)pvMsrBitmap;
2011 Assert(pbMsrBitmap);
2012 Assert(offMsr + (iBit >> 3) <= X86_PAGE_4K_SIZE);
2013 return ASMBitTest(pbMsrBitmap + offMsr, iBit);
2014}
2015#endif
2016
2017/**
2018 * Sets the permission bits for the specified MSR in the given MSR bitmap.
2019 *
2020 * If the passed VMCS is a nested-guest VMCS, this function ensures that the
2021 * read/write intercept is cleared from the MSR bitmap used for hardware-assisted
2022 * VMX execution of the nested-guest, only if nested-guest is also not intercepting
2023 * the read/write access of this MSR.
2024 *
2025 * @param pVCpu The cross context virtual CPU structure.
2026 * @param pVmcsInfo The VMCS info. object.
2027 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2028 * @param idMsr The MSR value.
2029 * @param fMsrpm The MSR permissions (see VMXMSRPM_XXX). This must
2030 * include both a read -and- a write permission!
2031 *
2032 * @sa CPUMGetVmxMsrPermission.
2033 * @remarks Can be called with interrupts disabled.
2034 */
2035static void hmR0VmxSetMsrPermission(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs, uint32_t idMsr, uint32_t fMsrpm)
2036{
2037 uint8_t *pbMsrBitmap = (uint8_t *)pVmcsInfo->pvMsrBitmap;
2038 Assert(pbMsrBitmap);
2039 Assert(VMXMSRPM_IS_FLAG_VALID(fMsrpm));
2040
2041 /*
2042 * MSR-bitmap Layout:
2043 * Byte index MSR range Interpreted as
2044 * 0x000 - 0x3ff 0x00000000 - 0x00001fff Low MSR read bits.
2045 * 0x400 - 0x7ff 0xc0000000 - 0xc0001fff High MSR read bits.
2046 * 0x800 - 0xbff 0x00000000 - 0x00001fff Low MSR write bits.
2047 * 0xc00 - 0xfff 0xc0000000 - 0xc0001fff High MSR write bits.
2048 *
2049 * A bit corresponding to an MSR within the above range causes a VM-exit
2050 * if the bit is 1 on executions of RDMSR/WRMSR. If an MSR falls out of
2051 * the MSR range, it always cause a VM-exit.
2052 *
2053 * See Intel spec. 24.6.9 "MSR-Bitmap Address".
2054 */
2055 uint16_t const offBitmapRead = 0;
2056 uint16_t const offBitmapWrite = 0x800;
2057 uint16_t offMsr;
2058 int32_t iBit;
2059 if (idMsr <= UINT32_C(0x00001fff))
2060 {
2061 offMsr = 0;
2062 iBit = idMsr;
2063 }
2064 else if (idMsr - UINT32_C(0xc0000000) <= UINT32_C(0x00001fff))
2065 {
2066 offMsr = 0x400;
2067 iBit = idMsr - UINT32_C(0xc0000000);
2068 }
2069 else
2070 AssertMsgFailedReturnVoid(("Invalid MSR %#RX32\n", idMsr));
2071
2072 /*
2073 * Set the MSR read permission.
2074 */
2075 uint16_t const offMsrRead = offBitmapRead + offMsr;
2076 Assert(offMsrRead + (iBit >> 3) < offBitmapWrite);
2077 if (fMsrpm & VMXMSRPM_ALLOW_RD)
2078 {
2079#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2080 bool const fClear = !fIsNstGstVmcs ? true
2081 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrRead, iBit);
2082#else
2083 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2084 bool const fClear = true;
2085#endif
2086 if (fClear)
2087 ASMBitClear(pbMsrBitmap + offMsrRead, iBit);
2088 }
2089 else
2090 ASMBitSet(pbMsrBitmap + offMsrRead, iBit);
2091
2092 /*
2093 * Set the MSR write permission.
2094 */
2095 uint16_t const offMsrWrite = offBitmapWrite + offMsr;
2096 Assert(offMsrWrite + (iBit >> 3) < X86_PAGE_4K_SIZE);
2097 if (fMsrpm & VMXMSRPM_ALLOW_WR)
2098 {
2099#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2100 bool const fClear = !fIsNstGstVmcs ? true
2101 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrWrite, iBit);
2102#else
2103 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2104 bool const fClear = true;
2105#endif
2106 if (fClear)
2107 ASMBitClear(pbMsrBitmap + offMsrWrite, iBit);
2108 }
2109 else
2110 ASMBitSet(pbMsrBitmap + offMsrWrite, iBit);
2111}
2112
2113
2114/**
2115 * Updates the VMCS with the number of effective MSRs in the auto-load/store MSR
2116 * area.
2117 *
2118 * @returns VBox status code.
2119 * @param pVCpu The cross context virtual CPU structure.
2120 * @param pVmcsInfo The VMCS info. object.
2121 * @param cMsrs The number of MSRs.
2122 */
2123static int hmR0VmxSetAutoLoadStoreMsrCount(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t cMsrs)
2124{
2125 /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
2126 uint32_t const cMaxSupportedMsrs = VMX_MISC_MAX_MSRS(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc);
2127 if (RT_LIKELY(cMsrs < cMaxSupportedMsrs))
2128 {
2129 /* Commit the MSR counts to the VMCS and update the cache. */
2130 if (pVmcsInfo->cEntryMsrLoad != cMsrs)
2131 {
2132 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2133 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, cMsrs); AssertRC(rc);
2134 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2135 pVmcsInfo->cEntryMsrLoad = cMsrs;
2136 pVmcsInfo->cExitMsrStore = cMsrs;
2137 pVmcsInfo->cExitMsrLoad = cMsrs;
2138 }
2139 return VINF_SUCCESS;
2140 }
2141
2142 LogRel(("Auto-load/store MSR count exceeded! cMsrs=%u MaxSupported=%u\n", cMsrs, cMaxSupportedMsrs));
2143 pVCpu->hm.s.u32HMError = VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE;
2144 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2145}
2146
2147
2148/**
2149 * Adds a new (or updates the value of an existing) guest/host MSR
2150 * pair to be swapped during the world-switch as part of the
2151 * auto-load/store MSR area in the VMCS.
2152 *
2153 * @returns VBox status code.
2154 * @param pVCpu The cross context virtual CPU structure.
2155 * @param pVmxTransient The VMX-transient structure.
2156 * @param idMsr The MSR.
2157 * @param uGuestMsrValue Value of the guest MSR.
2158 * @param fSetReadWrite Whether to set the guest read/write access of this
2159 * MSR (thus not causing a VM-exit).
2160 * @param fUpdateHostMsr Whether to update the value of the host MSR if
2161 * necessary.
2162 */
2163static int hmR0VmxAddAutoLoadStoreMsr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t idMsr, uint64_t uGuestMsrValue,
2164 bool fSetReadWrite, bool fUpdateHostMsr)
2165{
2166 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2167 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2168 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2169 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2170 uint32_t i;
2171
2172 /* Paranoia. */
2173 Assert(pGuestMsrLoad);
2174
2175 LogFlowFunc(("pVCpu=%p idMsr=%#RX32 uGestMsrValue=%#RX64\n", pVCpu, idMsr, uGuestMsrValue));
2176
2177 /* Check if the MSR already exists in the VM-entry MSR-load area. */
2178 for (i = 0; i < cMsrs; i++)
2179 {
2180 if (pGuestMsrLoad[i].u32Msr == idMsr)
2181 break;
2182 }
2183
2184 bool fAdded = false;
2185 if (i == cMsrs)
2186 {
2187 /* The MSR does not exist, bump the MSR count to make room for the new MSR. */
2188 ++cMsrs;
2189 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2190 AssertMsgRCReturn(rc, ("Insufficient space to add MSR to VM-entry MSR-load/store area %u\n", idMsr), rc);
2191
2192 /* Set the guest to read/write this MSR without causing VM-exits. */
2193 if ( fSetReadWrite
2194 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
2195 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_ALLOW_RD_WR);
2196
2197 Log4Func(("Added MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2198 fAdded = true;
2199 }
2200
2201 /* Update the MSR value for the newly added or already existing MSR. */
2202 pGuestMsrLoad[i].u32Msr = idMsr;
2203 pGuestMsrLoad[i].u64Value = uGuestMsrValue;
2204
2205 /* Create the corresponding slot in the VM-exit MSR-store area if we use a different page. */
2206 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2207 {
2208 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2209 pGuestMsrStore[i].u32Msr = idMsr;
2210 pGuestMsrStore[i].u64Value = uGuestMsrValue;
2211 }
2212
2213 /* Update the corresponding slot in the host MSR area. */
2214 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2215 Assert(pHostMsr != pVmcsInfo->pvGuestMsrLoad);
2216 Assert(pHostMsr != pVmcsInfo->pvGuestMsrStore);
2217 pHostMsr[i].u32Msr = idMsr;
2218
2219 /*
2220 * Only if the caller requests to update the host MSR value AND we've newly added the
2221 * MSR to the host MSR area do we actually update the value. Otherwise, it will be
2222 * updated by hmR0VmxUpdateAutoLoadHostMsrs().
2223 *
2224 * We do this for performance reasons since reading MSRs may be quite expensive.
2225 */
2226 if (fAdded)
2227 {
2228 if (fUpdateHostMsr)
2229 {
2230 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2231 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2232 pHostMsr[i].u64Value = ASMRdMsr(idMsr);
2233 }
2234 else
2235 {
2236 /* Someone else can do the work. */
2237 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
2238 }
2239 }
2240 return VINF_SUCCESS;
2241}
2242
2243
2244/**
2245 * Removes a guest/host MSR pair to be swapped during the world-switch from the
2246 * auto-load/store MSR area in the VMCS.
2247 *
2248 * @returns VBox status code.
2249 * @param pVCpu The cross context virtual CPU structure.
2250 * @param pVmxTransient The VMX-transient structure.
2251 * @param idMsr The MSR.
2252 */
2253static int hmR0VmxRemoveAutoLoadStoreMsr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t idMsr)
2254{
2255 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2256 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2257 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2258 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2259
2260 LogFlowFunc(("pVCpu=%p idMsr=%#RX32\n", pVCpu, idMsr));
2261
2262 for (uint32_t i = 0; i < cMsrs; i++)
2263 {
2264 /* Find the MSR. */
2265 if (pGuestMsrLoad[i].u32Msr == idMsr)
2266 {
2267 /*
2268 * If it's the last MSR, we only need to reduce the MSR count.
2269 * If it's -not- the last MSR, copy the last MSR in place of it and reduce the MSR count.
2270 */
2271 if (i < cMsrs - 1)
2272 {
2273 /* Remove it from the VM-entry MSR-load area. */
2274 pGuestMsrLoad[i].u32Msr = pGuestMsrLoad[cMsrs - 1].u32Msr;
2275 pGuestMsrLoad[i].u64Value = pGuestMsrLoad[cMsrs - 1].u64Value;
2276
2277 /* Remove it from the VM-exit MSR-store area if it's in a different page. */
2278 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2279 {
2280 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2281 Assert(pGuestMsrStore[i].u32Msr == idMsr);
2282 pGuestMsrStore[i].u32Msr = pGuestMsrStore[cMsrs - 1].u32Msr;
2283 pGuestMsrStore[i].u64Value = pGuestMsrStore[cMsrs - 1].u64Value;
2284 }
2285
2286 /* Remove it from the VM-exit MSR-load area. */
2287 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2288 Assert(pHostMsr[i].u32Msr == idMsr);
2289 pHostMsr[i].u32Msr = pHostMsr[cMsrs - 1].u32Msr;
2290 pHostMsr[i].u64Value = pHostMsr[cMsrs - 1].u64Value;
2291 }
2292
2293 /* Reduce the count to reflect the removed MSR and bail. */
2294 --cMsrs;
2295 break;
2296 }
2297 }
2298
2299 /* Update the VMCS if the count changed (meaning the MSR was found and removed). */
2300 if (cMsrs != pVmcsInfo->cEntryMsrLoad)
2301 {
2302 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2303 AssertRCReturn(rc, rc);
2304
2305 /* We're no longer swapping MSRs during the world-switch, intercept guest read/writes to them. */
2306 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2307 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR);
2308
2309 Log4Func(("Removed MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2310 return VINF_SUCCESS;
2311 }
2312
2313 return VERR_NOT_FOUND;
2314}
2315
2316
2317/**
2318 * Checks if the specified guest MSR is part of the VM-entry MSR-load area.
2319 *
2320 * @returns @c true if found, @c false otherwise.
2321 * @param pVmcsInfo The VMCS info. object.
2322 * @param idMsr The MSR to find.
2323 */
2324static bool hmR0VmxIsAutoLoadGuestMsr(PCVMXVMCSINFO pVmcsInfo, uint32_t idMsr)
2325{
2326 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2327 uint32_t const cMsrs = pVmcsInfo->cEntryMsrLoad;
2328 Assert(pMsrs);
2329 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
2330 for (uint32_t i = 0; i < cMsrs; i++)
2331 {
2332 if (pMsrs[i].u32Msr == idMsr)
2333 return true;
2334 }
2335 return false;
2336}
2337
2338
2339/**
2340 * Updates the value of all host MSRs in the VM-exit MSR-load area.
2341 *
2342 * @param pVCpu The cross context virtual CPU structure.
2343 * @param pVmcsInfo The VMCS info. object.
2344 *
2345 * @remarks No-long-jump zone!!!
2346 */
2347static void hmR0VmxUpdateAutoLoadHostMsrs(PCVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
2348{
2349 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2350
2351 PVMXAUTOMSR pHostMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2352 uint32_t const cMsrs = pVmcsInfo->cExitMsrLoad;
2353 Assert(pHostMsrLoad);
2354 Assert(sizeof(*pHostMsrLoad) * cMsrs <= X86_PAGE_4K_SIZE);
2355 LogFlowFunc(("pVCpu=%p cMsrs=%u\n", pVCpu, cMsrs));
2356 for (uint32_t i = 0; i < cMsrs; i++)
2357 {
2358 /*
2359 * Performance hack for the host EFER MSR. We use the cached value rather than re-read it.
2360 * Strict builds will catch mismatches in hmR0VmxCheckAutoLoadStoreMsrs(). See @bugref{7368}.
2361 */
2362 if (pHostMsrLoad[i].u32Msr == MSR_K6_EFER)
2363 pHostMsrLoad[i].u64Value = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer;
2364 else
2365 pHostMsrLoad[i].u64Value = ASMRdMsr(pHostMsrLoad[i].u32Msr);
2366 }
2367}
2368
2369
2370/**
2371 * Saves a set of host MSRs to allow read/write passthru access to the guest and
2372 * perform lazy restoration of the host MSRs while leaving VT-x.
2373 *
2374 * @param pVCpu The cross context virtual CPU structure.
2375 *
2376 * @remarks No-long-jump zone!!!
2377 */
2378static void hmR0VmxLazySaveHostMsrs(PVMCPU pVCpu)
2379{
2380 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2381
2382 /*
2383 * Note: If you're adding MSRs here, make sure to update the MSR-bitmap accesses in hmR0VmxSetupVmcsProcCtls().
2384 */
2385 if (!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST))
2386 {
2387 Assert(!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)); /* Guest MSRs better not be loaded now. */
2388 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2389 {
2390 pVCpu->hm.s.vmx.u64HostMsrLStar = ASMRdMsr(MSR_K8_LSTAR);
2391 pVCpu->hm.s.vmx.u64HostMsrStar = ASMRdMsr(MSR_K6_STAR);
2392 pVCpu->hm.s.vmx.u64HostMsrSfMask = ASMRdMsr(MSR_K8_SF_MASK);
2393 pVCpu->hm.s.vmx.u64HostMsrKernelGsBase = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
2394 }
2395 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_SAVED_HOST;
2396 }
2397}
2398
2399
2400/**
2401 * Checks whether the MSR belongs to the set of guest MSRs that we restore
2402 * lazily while leaving VT-x.
2403 *
2404 * @returns true if it does, false otherwise.
2405 * @param pVCpu The cross context virtual CPU structure.
2406 * @param idMsr The MSR to check.
2407 */
2408static bool hmR0VmxIsLazyGuestMsr(PCVMCPU pVCpu, uint32_t idMsr)
2409{
2410 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2411 {
2412 switch (idMsr)
2413 {
2414 case MSR_K8_LSTAR:
2415 case MSR_K6_STAR:
2416 case MSR_K8_SF_MASK:
2417 case MSR_K8_KERNEL_GS_BASE:
2418 return true;
2419 }
2420 }
2421 return false;
2422}
2423
2424
2425/**
2426 * Loads a set of guests MSRs to allow read/passthru to the guest.
2427 *
2428 * The name of this function is slightly confusing. This function does NOT
2429 * postpone loading, but loads the MSR right now. "hmR0VmxLazy" is simply a
2430 * common prefix for functions dealing with "lazy restoration" of the shared
2431 * MSRs.
2432 *
2433 * @param pVCpu The cross context virtual CPU structure.
2434 *
2435 * @remarks No-long-jump zone!!!
2436 */
2437static void hmR0VmxLazyLoadGuestMsrs(PVMCPU pVCpu)
2438{
2439 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2440 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2441
2442 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2443 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2444 {
2445 /*
2446 * If the guest MSRs are not loaded -and- if all the guest MSRs are identical
2447 * to the MSRs on the CPU (which are the saved host MSRs, see assertion above) then
2448 * we can skip a few MSR writes.
2449 *
2450 * Otherwise, it implies either 1. they're not loaded, or 2. they're loaded but the
2451 * guest MSR values in the guest-CPU context might be different to what's currently
2452 * loaded in the CPU. In either case, we need to write the new guest MSR values to the
2453 * CPU, see @bugref{8728}.
2454 */
2455 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
2456 if ( !(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2457 && pCtx->msrKERNELGSBASE == pVCpu->hm.s.vmx.u64HostMsrKernelGsBase
2458 && pCtx->msrLSTAR == pVCpu->hm.s.vmx.u64HostMsrLStar
2459 && pCtx->msrSTAR == pVCpu->hm.s.vmx.u64HostMsrStar
2460 && pCtx->msrSFMASK == pVCpu->hm.s.vmx.u64HostMsrSfMask)
2461 {
2462#ifdef VBOX_STRICT
2463 Assert(ASMRdMsr(MSR_K8_KERNEL_GS_BASE) == pCtx->msrKERNELGSBASE);
2464 Assert(ASMRdMsr(MSR_K8_LSTAR) == pCtx->msrLSTAR);
2465 Assert(ASMRdMsr(MSR_K6_STAR) == pCtx->msrSTAR);
2466 Assert(ASMRdMsr(MSR_K8_SF_MASK) == pCtx->msrSFMASK);
2467#endif
2468 }
2469 else
2470 {
2471 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pCtx->msrKERNELGSBASE);
2472 ASMWrMsr(MSR_K8_LSTAR, pCtx->msrLSTAR);
2473 ASMWrMsr(MSR_K6_STAR, pCtx->msrSTAR);
2474 ASMWrMsr(MSR_K8_SF_MASK, pCtx->msrSFMASK);
2475 }
2476 }
2477 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_LOADED_GUEST;
2478}
2479
2480
2481/**
2482 * Performs lazy restoration of the set of host MSRs if they were previously
2483 * loaded with guest MSR values.
2484 *
2485 * @param pVCpu The cross context virtual CPU structure.
2486 *
2487 * @remarks No-long-jump zone!!!
2488 * @remarks The guest MSRs should have been saved back into the guest-CPU
2489 * context by hmR0VmxImportGuestState()!!!
2490 */
2491static void hmR0VmxLazyRestoreHostMsrs(PVMCPU pVCpu)
2492{
2493 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2494 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2495
2496 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2497 {
2498 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2499 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2500 {
2501 ASMWrMsr(MSR_K8_LSTAR, pVCpu->hm.s.vmx.u64HostMsrLStar);
2502 ASMWrMsr(MSR_K6_STAR, pVCpu->hm.s.vmx.u64HostMsrStar);
2503 ASMWrMsr(MSR_K8_SF_MASK, pVCpu->hm.s.vmx.u64HostMsrSfMask);
2504 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pVCpu->hm.s.vmx.u64HostMsrKernelGsBase);
2505 }
2506 }
2507 pVCpu->hm.s.vmx.fLazyMsrs &= ~(VMX_LAZY_MSRS_LOADED_GUEST | VMX_LAZY_MSRS_SAVED_HOST);
2508}
2509
2510
2511/**
2512 * Verifies that our cached values of the VMCS fields are all consistent with
2513 * what's actually present in the VMCS.
2514 *
2515 * @returns VBox status code.
2516 * @retval VINF_SUCCESS if all our caches match their respective VMCS fields.
2517 * @retval VERR_VMX_VMCS_FIELD_CACHE_INVALID if a cache field doesn't match the
2518 * VMCS content. HMCPU error-field is
2519 * updated, see VMX_VCI_XXX.
2520 * @param pVCpu The cross context virtual CPU structure.
2521 * @param pVmcsInfo The VMCS info. object.
2522 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2523 */
2524static int hmR0VmxCheckVmcsCtls(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2525{
2526 const char * const pcszVmcs = fIsNstGstVmcs ? "Nested-guest VMCS" : "VMCS";
2527
2528 uint32_t u32Val;
2529 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
2530 AssertRC(rc);
2531 AssertMsgReturnStmt(pVmcsInfo->u32EntryCtls == u32Val,
2532 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32EntryCtls, u32Val),
2533 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_ENTRY,
2534 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2535
2536 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val);
2537 AssertRC(rc);
2538 AssertMsgReturnStmt(pVmcsInfo->u32ExitCtls == u32Val,
2539 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ExitCtls, u32Val),
2540 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_EXIT,
2541 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2542
2543 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val);
2544 AssertRC(rc);
2545 AssertMsgReturnStmt(pVmcsInfo->u32PinCtls == u32Val,
2546 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32PinCtls, u32Val),
2547 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PIN_EXEC,
2548 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2549
2550 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val);
2551 AssertRC(rc);
2552 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls == u32Val,
2553 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls, u32Val),
2554 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC,
2555 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2556
2557 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
2558 {
2559 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val);
2560 AssertRC(rc);
2561 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls2 == u32Val,
2562 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls2, u32Val),
2563 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC2,
2564 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2565 }
2566
2567 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val);
2568 AssertRC(rc);
2569 AssertMsgReturnStmt(pVmcsInfo->u32XcptBitmap == u32Val,
2570 ("%s exception bitmap mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32XcptBitmap, u32Val),
2571 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_XCPT_BITMAP,
2572 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2573
2574 uint64_t u64Val;
2575 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, &u64Val);
2576 AssertRC(rc);
2577 AssertMsgReturnStmt(pVmcsInfo->u64TscOffset == u64Val,
2578 ("%s TSC offset mismatch: Cache=%#RX64 VMCS=%#RX64\n", pcszVmcs, pVmcsInfo->u64TscOffset, u64Val),
2579 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_TSC_OFFSET,
2580 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2581
2582 NOREF(pcszVmcs);
2583 return VINF_SUCCESS;
2584}
2585
2586
2587#ifdef VBOX_STRICT
2588/**
2589 * Verifies that our cached host EFER MSR value has not changed since we cached it.
2590 *
2591 * @param pVCpu The cross context virtual CPU structure.
2592 * @param pVmcsInfo The VMCS info. object.
2593 */
2594static void hmR0VmxCheckHostEferMsr(PCVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
2595{
2596 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2597
2598 if (pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_LOAD_EFER_MSR)
2599 {
2600 uint64_t const uHostEferMsr = ASMRdMsr(MSR_K6_EFER);
2601 uint64_t const uHostEferMsrCache = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer;
2602 uint64_t uVmcsEferMsrVmcs;
2603 int rc = VMXReadVmcs64(VMX_VMCS64_HOST_EFER_FULL, &uVmcsEferMsrVmcs);
2604 AssertRC(rc);
2605
2606 AssertMsgReturnVoid(uHostEferMsr == uVmcsEferMsrVmcs,
2607 ("EFER Host/VMCS mismatch! host=%#RX64 vmcs=%#RX64\n", uHostEferMsr, uVmcsEferMsrVmcs));
2608 AssertMsgReturnVoid(uHostEferMsr == uHostEferMsrCache,
2609 ("EFER Host/Cache mismatch! host=%#RX64 cache=%#RX64\n", uHostEferMsr, uHostEferMsrCache));
2610 }
2611}
2612
2613
2614/**
2615 * Verifies whether the guest/host MSR pairs in the auto-load/store area in the
2616 * VMCS are correct.
2617 *
2618 * @param pVCpu The cross context virtual CPU structure.
2619 * @param pVmcsInfo The VMCS info. object.
2620 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2621 */
2622static void hmR0VmxCheckAutoLoadStoreMsrs(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2623{
2624 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2625
2626 /* Read the various MSR-area counts from the VMCS. */
2627 uint32_t cEntryLoadMsrs;
2628 uint32_t cExitStoreMsrs;
2629 uint32_t cExitLoadMsrs;
2630 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &cEntryLoadMsrs); AssertRC(rc);
2631 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &cExitStoreMsrs); AssertRC(rc);
2632 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &cExitLoadMsrs); AssertRC(rc);
2633
2634 /* Verify all the MSR counts are the same. */
2635 Assert(cEntryLoadMsrs == cExitStoreMsrs);
2636 Assert(cExitStoreMsrs == cExitLoadMsrs);
2637 uint32_t const cMsrs = cExitLoadMsrs;
2638
2639 /* Verify the MSR counts do not exceed the maximum count supported by the hardware. */
2640 Assert(cMsrs < VMX_MISC_MAX_MSRS(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc));
2641
2642 /* Verify the MSR counts are within the allocated page size. */
2643 Assert(sizeof(VMXAUTOMSR) * cMsrs <= X86_PAGE_4K_SIZE);
2644
2645 /* Verify the relevant contents of the MSR areas match. */
2646 PCVMXAUTOMSR pGuestMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2647 PCVMXAUTOMSR pGuestMsrStore = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2648 PCVMXAUTOMSR pHostMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2649 bool const fSeparateExitMsrStorePage = hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo);
2650 for (uint32_t i = 0; i < cMsrs; i++)
2651 {
2652 /* Verify that the MSRs are paired properly and that the host MSR has the correct value. */
2653 if (fSeparateExitMsrStorePage)
2654 {
2655 AssertMsgReturnVoid(pGuestMsrLoad->u32Msr == pGuestMsrStore->u32Msr,
2656 ("GuestMsrLoad=%#RX32 GuestMsrStore=%#RX32 cMsrs=%u\n",
2657 pGuestMsrLoad->u32Msr, pGuestMsrStore->u32Msr, cMsrs));
2658 }
2659
2660 AssertMsgReturnVoid(pHostMsrLoad->u32Msr == pGuestMsrLoad->u32Msr,
2661 ("HostMsrLoad=%#RX32 GuestMsrLoad=%#RX32 cMsrs=%u\n",
2662 pHostMsrLoad->u32Msr, pGuestMsrLoad->u32Msr, cMsrs));
2663
2664 uint64_t const u64Msr = ASMRdMsr(pHostMsrLoad->u32Msr);
2665 AssertMsgReturnVoid(pHostMsrLoad->u64Value == u64Msr,
2666 ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2667 pHostMsrLoad->u32Msr, pHostMsrLoad->u64Value, u64Msr, cMsrs));
2668
2669 /* Verify that cached host EFER MSR matches what's loaded the CPU. */
2670 bool const fIsEferMsr = RT_BOOL(pHostMsrLoad->u32Msr == MSR_K6_EFER);
2671 if (fIsEferMsr)
2672 {
2673 AssertMsgReturnVoid(u64Msr == pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer,
2674 ("Cached=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2675 pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer, u64Msr, cMsrs));
2676 }
2677
2678 /* Verify that the accesses are as expected in the MSR bitmap for auto-load/store MSRs. */
2679 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2680 {
2681 uint32_t const fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, pGuestMsrLoad->u32Msr);
2682 if (fIsEferMsr)
2683 {
2684 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_RD), ("Passthru read for EFER MSR!?\n"));
2685 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_WR), ("Passthru write for EFER MSR!?\n"));
2686 }
2687 else
2688 {
2689 if (!fIsNstGstVmcs)
2690 {
2691 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_ALLOW_RD_WR) == VMXMSRPM_ALLOW_RD_WR,
2692 ("u32Msr=%#RX32 cMsrs=%u No passthru read/write!\n", pGuestMsrLoad->u32Msr, cMsrs));
2693 }
2694 else
2695 {
2696 /*
2697 * A nested-guest VMCS must -also- allow read/write passthrough for the MSR for us to
2698 * execute a nested-guest with MSR passthrough.
2699 *
2700 * Check if the nested-guest MSR bitmap allows passthrough, and if so, assert that we
2701 * allow passthrough too.
2702 */
2703 void const *pvMsrBitmapNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
2704 Assert(pvMsrBitmapNstGst);
2705 uint32_t const fMsrpmNstGst = CPUMGetVmxMsrPermission(pvMsrBitmapNstGst, pGuestMsrLoad->u32Msr);
2706 AssertMsgReturnVoid(fMsrpm == fMsrpmNstGst,
2707 ("u32Msr=%#RX32 cMsrs=%u Permission mismatch fMsrpm=%#x fMsrpmNstGst=%#x!\n",
2708 pGuestMsrLoad->u32Msr, cMsrs, fMsrpm, fMsrpmNstGst));
2709 }
2710 }
2711 }
2712
2713 /* Move to the next MSR. */
2714 pHostMsrLoad++;
2715 pGuestMsrLoad++;
2716 pGuestMsrStore++;
2717 }
2718}
2719#endif /* VBOX_STRICT */
2720
2721
2722/**
2723 * Flushes the TLB using EPT.
2724 *
2725 * @returns VBox status code.
2726 * @param pVCpu The cross context virtual CPU structure of the calling
2727 * EMT. Can be NULL depending on @a enmTlbFlush.
2728 * @param pVmcsInfo The VMCS info. object. Can be NULL depending on @a
2729 * enmTlbFlush.
2730 * @param enmTlbFlush Type of flush.
2731 *
2732 * @remarks Caller is responsible for making sure this function is called only
2733 * when NestedPaging is supported and providing @a enmTlbFlush that is
2734 * supported by the CPU.
2735 * @remarks Can be called with interrupts disabled.
2736 */
2737static void hmR0VmxFlushEpt(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, VMXTLBFLUSHEPT enmTlbFlush)
2738{
2739 uint64_t au64Descriptor[2];
2740 if (enmTlbFlush == VMXTLBFLUSHEPT_ALL_CONTEXTS)
2741 au64Descriptor[0] = 0;
2742 else
2743 {
2744 Assert(pVCpu);
2745 Assert(pVmcsInfo);
2746 au64Descriptor[0] = pVmcsInfo->HCPhysEPTP;
2747 }
2748 au64Descriptor[1] = 0; /* MBZ. Intel spec. 33.3 "VMX Instructions" */
2749
2750 int rc = VMXR0InvEPT(enmTlbFlush, &au64Descriptor[0]);
2751 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %#RHp failed. rc=%Rrc\n", enmTlbFlush, au64Descriptor[0], rc));
2752
2753 if ( RT_SUCCESS(rc)
2754 && pVCpu)
2755 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushNestedPaging);
2756}
2757
2758
2759/**
2760 * Flushes the TLB using VPID.
2761 *
2762 * @returns VBox status code.
2763 * @param pVCpu The cross context virtual CPU structure of the calling
2764 * EMT. Can be NULL depending on @a enmTlbFlush.
2765 * @param enmTlbFlush Type of flush.
2766 * @param GCPtr Virtual address of the page to flush (can be 0 depending
2767 * on @a enmTlbFlush).
2768 *
2769 * @remarks Can be called with interrupts disabled.
2770 */
2771static void hmR0VmxFlushVpid(PVMCPU pVCpu, VMXTLBFLUSHVPID enmTlbFlush, RTGCPTR GCPtr)
2772{
2773 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fVpid);
2774
2775 uint64_t au64Descriptor[2];
2776 if (enmTlbFlush == VMXTLBFLUSHVPID_ALL_CONTEXTS)
2777 {
2778 au64Descriptor[0] = 0;
2779 au64Descriptor[1] = 0;
2780 }
2781 else
2782 {
2783 AssertPtr(pVCpu);
2784 AssertMsg(pVCpu->hm.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
2785 AssertMsg(pVCpu->hm.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
2786 au64Descriptor[0] = pVCpu->hm.s.uCurrentAsid;
2787 au64Descriptor[1] = GCPtr;
2788 }
2789
2790 int rc = VMXR0InvVPID(enmTlbFlush, &au64Descriptor[0]);
2791 AssertMsg(rc == VINF_SUCCESS,
2792 ("VMXR0InvVPID %#x %u %RGv failed with %Rrc\n", enmTlbFlush, pVCpu ? pVCpu->hm.s.uCurrentAsid : 0, GCPtr, rc));
2793
2794 if ( RT_SUCCESS(rc)
2795 && pVCpu)
2796 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
2797 NOREF(rc);
2798}
2799
2800
2801/**
2802 * Invalidates a guest page by guest virtual address. Only relevant for EPT/VPID,
2803 * otherwise there is nothing really to invalidate.
2804 *
2805 * @returns VBox status code.
2806 * @param pVCpu The cross context virtual CPU structure.
2807 * @param GCVirt Guest virtual address of the page to invalidate.
2808 */
2809VMMR0DECL(int) VMXR0InvalidatePage(PVMCPU pVCpu, RTGCPTR GCVirt)
2810{
2811 AssertPtr(pVCpu);
2812 LogFlowFunc(("pVCpu=%p GCVirt=%RGv\n", pVCpu, GCVirt));
2813
2814 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_TLB_FLUSH))
2815 {
2816 /*
2817 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for
2818 * the EPT case. See @bugref{6043} and @bugref{6177}.
2819 *
2820 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VM-entry in hmR0VmxFlushTLB*()
2821 * as this function maybe called in a loop with individual addresses.
2822 */
2823 PVM pVM = pVCpu->CTX_SUFF(pVM);
2824 if (pVM->hm.s.vmx.fVpid)
2825 {
2826 bool fVpidFlush = RT_BOOL(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR);
2827 if (fVpidFlush)
2828 {
2829 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_INDIV_ADDR, GCVirt);
2830 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
2831 }
2832 else
2833 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2834 }
2835 else if (pVM->hm.s.fNestedPaging)
2836 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2837 }
2838
2839 return VINF_SUCCESS;
2840}
2841
2842
2843/**
2844 * Dummy placeholder for tagged-TLB flush handling before VM-entry. Used in the
2845 * case where neither EPT nor VPID is supported by the CPU.
2846 *
2847 * @param pHostCpu The HM physical-CPU structure.
2848 * @param pVCpu The cross context virtual CPU structure.
2849 *
2850 * @remarks Called with interrupts disabled.
2851 */
2852static void hmR0VmxFlushTaggedTlbNone(PHMPHYSCPU pHostCpu, PVMCPU pVCpu)
2853{
2854 AssertPtr(pVCpu);
2855 AssertPtr(pHostCpu);
2856
2857 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
2858
2859 Assert(pHostCpu->idCpu != NIL_RTCPUID);
2860 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
2861 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
2862 pVCpu->hm.s.fForceTLBFlush = false;
2863 return;
2864}
2865
2866
2867/**
2868 * Flushes the tagged-TLB entries for EPT+VPID CPUs as necessary.
2869 *
2870 * @param pHostCpu The HM physical-CPU structure.
2871 * @param pVCpu The cross context virtual CPU structure.
2872 * @param pVmcsInfo The VMCS info. object.
2873 *
2874 * @remarks All references to "ASID" in this function pertains to "VPID" in Intel's
2875 * nomenclature. The reason is, to avoid confusion in compare statements
2876 * since the host-CPU copies are named "ASID".
2877 *
2878 * @remarks Called with interrupts disabled.
2879 */
2880static void hmR0VmxFlushTaggedTlbBoth(PHMPHYSCPU pHostCpu, PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
2881{
2882#ifdef VBOX_WITH_STATISTICS
2883 bool fTlbFlushed = false;
2884# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { fTlbFlushed = true; } while (0)
2885# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { \
2886 if (!fTlbFlushed) \
2887 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch); \
2888 } while (0)
2889#else
2890# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { } while (0)
2891# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { } while (0)
2892#endif
2893
2894 AssertPtr(pVCpu);
2895 AssertPtr(pHostCpu);
2896 Assert(pHostCpu->idCpu != NIL_RTCPUID);
2897
2898 PVM pVM = pVCpu->CTX_SUFF(pVM);
2899 AssertMsg(pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid,
2900 ("hmR0VmxFlushTaggedTlbBoth cannot be invoked unless NestedPaging & VPID are enabled."
2901 "fNestedPaging=%RTbool fVpid=%RTbool", pVM->hm.s.fNestedPaging, pVM->hm.s.vmx.fVpid));
2902
2903 /*
2904 * Force a TLB flush for the first world-switch if the current CPU differs from the one we
2905 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
2906 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
2907 * cannot reuse the current ASID anymore.
2908 */
2909 if ( pVCpu->hm.s.idLastCpu != pHostCpu->idCpu
2910 || pVCpu->hm.s.cTlbFlushes != pHostCpu->cTlbFlushes)
2911 {
2912 ++pHostCpu->uCurrentAsid;
2913 if (pHostCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
2914 {
2915 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0. */
2916 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
2917 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
2918 }
2919
2920 pVCpu->hm.s.uCurrentAsid = pHostCpu->uCurrentAsid;
2921 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
2922 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
2923
2924 /*
2925 * Flush by EPT when we get rescheduled to a new host CPU to ensure EPT-only tagged mappings are also
2926 * invalidated. We don't need to flush-by-VPID here as flushing by EPT covers it. See @bugref{6568}.
2927 */
2928 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hm.s.vmx.enmTlbFlushEpt);
2929 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
2930 HMVMX_SET_TAGGED_TLB_FLUSHED();
2931 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
2932 }
2933 else if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH)) /* Check for explicit TLB flushes. */
2934 {
2935 /*
2936 * Changes to the EPT paging structure by VMM requires flushing-by-EPT as the CPU
2937 * creates guest-physical (ie. only EPT-tagged) mappings while traversing the EPT
2938 * tables when EPT is in use. Flushing-by-VPID will only flush linear (only
2939 * VPID-tagged) and combined (EPT+VPID tagged) mappings but not guest-physical
2940 * mappings, see @bugref{6568}.
2941 *
2942 * See Intel spec. 28.3.2 "Creating and Using Cached Translation Information".
2943 */
2944 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hm.s.vmx.enmTlbFlushEpt);
2945 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
2946 HMVMX_SET_TAGGED_TLB_FLUSHED();
2947 }
2948 else if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
2949 {
2950 /*
2951 * The nested-guest specifies its own guest-physical address to use as the APIC-access
2952 * address which requires flushing the TLB of EPT cached structures.
2953 *
2954 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
2955 */
2956 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hm.s.vmx.enmTlbFlushEpt);
2957 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
2958 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
2959 HMVMX_SET_TAGGED_TLB_FLUSHED();
2960 }
2961
2962
2963 pVCpu->hm.s.fForceTLBFlush = false;
2964 HMVMX_UPDATE_FLUSH_SKIPPED_STAT();
2965
2966 Assert(pVCpu->hm.s.idLastCpu == pHostCpu->idCpu);
2967 Assert(pVCpu->hm.s.cTlbFlushes == pHostCpu->cTlbFlushes);
2968 AssertMsg(pVCpu->hm.s.cTlbFlushes == pHostCpu->cTlbFlushes,
2969 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pHostCpu->cTlbFlushes));
2970 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
2971 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
2972 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
2973 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
2974 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
2975
2976 /* Update VMCS with the VPID. */
2977 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
2978 AssertRC(rc);
2979
2980#undef HMVMX_SET_TAGGED_TLB_FLUSHED
2981}
2982
2983
2984/**
2985 * Flushes the tagged-TLB entries for EPT CPUs as necessary.
2986 *
2987 * @param pHostCpu The HM physical-CPU structure.
2988 * @param pVCpu The cross context virtual CPU structure.
2989 * @param pVmcsInfo The VMCS info. object.
2990 *
2991 * @remarks Called with interrupts disabled.
2992 */
2993static void hmR0VmxFlushTaggedTlbEpt(PHMPHYSCPU pHostCpu, PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
2994{
2995 AssertPtr(pVCpu);
2996 AssertPtr(pHostCpu);
2997 Assert(pHostCpu->idCpu != NIL_RTCPUID);
2998 AssertMsg(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked without NestedPaging."));
2999 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fVpid, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with VPID."));
3000
3001 /*
3002 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
3003 * A change in the TLB flush count implies the host CPU is online after a suspend/resume.
3004 */
3005 if ( pVCpu->hm.s.idLastCpu != pHostCpu->idCpu
3006 || pVCpu->hm.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3007 {
3008 pVCpu->hm.s.fForceTLBFlush = true;
3009 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3010 }
3011
3012 /* Check for explicit TLB flushes. */
3013 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3014 {
3015 pVCpu->hm.s.fForceTLBFlush = true;
3016 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3017 }
3018
3019 /* Check for TLB flushes while switching to/from a nested-guest. */
3020 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3021 {
3022 pVCpu->hm.s.fForceTLBFlush = true;
3023 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3024 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3025 }
3026
3027 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
3028 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3029
3030 if (pVCpu->hm.s.fForceTLBFlush)
3031 {
3032 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVCpu->CTX_SUFF(pVM)->hm.s.vmx.enmTlbFlushEpt);
3033 pVCpu->hm.s.fForceTLBFlush = false;
3034 }
3035}
3036
3037
3038/**
3039 * Flushes the tagged-TLB entries for VPID CPUs as necessary.
3040 *
3041 * @param pHostCpu The HM physical-CPU structure.
3042 * @param pVCpu The cross context virtual CPU structure.
3043 *
3044 * @remarks Called with interrupts disabled.
3045 */
3046static void hmR0VmxFlushTaggedTlbVpid(PHMPHYSCPU pHostCpu, PVMCPU pVCpu)
3047{
3048 AssertPtr(pVCpu);
3049 AssertPtr(pHostCpu);
3050 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3051 AssertMsg(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fVpid, ("hmR0VmxFlushTlbVpid cannot be invoked without VPID."));
3052 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging"));
3053
3054 /*
3055 * Force a TLB flush for the first world switch if the current CPU differs from the one we
3056 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
3057 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
3058 * cannot reuse the current ASID anymore.
3059 */
3060 if ( pVCpu->hm.s.idLastCpu != pHostCpu->idCpu
3061 || pVCpu->hm.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3062 {
3063 pVCpu->hm.s.fForceTLBFlush = true;
3064 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3065 }
3066
3067 /* Check for explicit TLB flushes. */
3068 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3069 {
3070 /*
3071 * If we ever support VPID flush combinations other than ALL or SINGLE-context (see
3072 * hmR0VmxSetupTaggedTlb()) we would need to explicitly flush in this case (add an
3073 * fExplicitFlush = true here and change the pHostCpu->fFlushAsidBeforeUse check below to
3074 * include fExplicitFlush's too) - an obscure corner case.
3075 */
3076 pVCpu->hm.s.fForceTLBFlush = true;
3077 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3078 }
3079
3080 /* Check for TLB flushes while switching to/from a nested-guest. */
3081 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3082 {
3083 pVCpu->hm.s.fForceTLBFlush = true;
3084 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3085 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3086 }
3087
3088 PVM pVM = pVCpu->CTX_SUFF(pVM);
3089 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
3090 if (pVCpu->hm.s.fForceTLBFlush)
3091 {
3092 ++pHostCpu->uCurrentAsid;
3093 if (pHostCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
3094 {
3095 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0 */
3096 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
3097 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
3098 }
3099
3100 pVCpu->hm.s.fForceTLBFlush = false;
3101 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3102 pVCpu->hm.s.uCurrentAsid = pHostCpu->uCurrentAsid;
3103 if (pHostCpu->fFlushAsidBeforeUse)
3104 {
3105 if (pVM->hm.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_SINGLE_CONTEXT)
3106 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_SINGLE_CONTEXT, 0 /* GCPtr */);
3107 else if (pVM->hm.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_ALL_CONTEXTS)
3108 {
3109 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_ALL_CONTEXTS, 0 /* GCPtr */);
3110 pHostCpu->fFlushAsidBeforeUse = false;
3111 }
3112 else
3113 {
3114 /* hmR0VmxSetupTaggedTlb() ensures we never get here. Paranoia. */
3115 AssertMsgFailed(("Unsupported VPID-flush context type.\n"));
3116 }
3117 }
3118 }
3119
3120 AssertMsg(pVCpu->hm.s.cTlbFlushes == pHostCpu->cTlbFlushes,
3121 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pHostCpu->cTlbFlushes));
3122 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
3123 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3124 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
3125 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
3126 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
3127
3128 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
3129 AssertRC(rc);
3130}
3131
3132
3133/**
3134 * Flushes the guest TLB entry based on CPU capabilities.
3135 *
3136 * @param pHostCpu The HM physical-CPU structure.
3137 * @param pVCpu The cross context virtual CPU structure.
3138 * @param pVmcsInfo The VMCS info. object.
3139 *
3140 * @remarks Called with interrupts disabled.
3141 */
3142static void hmR0VmxFlushTaggedTlb(PHMPHYSCPU pHostCpu, PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
3143{
3144#ifdef HMVMX_ALWAYS_FLUSH_TLB
3145 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
3146#endif
3147 PVM pVM = pVCpu->CTX_SUFF(pVM);
3148 switch (pVM->hm.s.vmx.enmTlbFlushType)
3149 {
3150 case VMXTLBFLUSHTYPE_EPT_VPID: hmR0VmxFlushTaggedTlbBoth(pHostCpu, pVCpu, pVmcsInfo); break;
3151 case VMXTLBFLUSHTYPE_EPT: hmR0VmxFlushTaggedTlbEpt(pHostCpu, pVCpu, pVmcsInfo); break;
3152 case VMXTLBFLUSHTYPE_VPID: hmR0VmxFlushTaggedTlbVpid(pHostCpu, pVCpu); break;
3153 case VMXTLBFLUSHTYPE_NONE: hmR0VmxFlushTaggedTlbNone(pHostCpu, pVCpu); break;
3154 default:
3155 AssertMsgFailed(("Invalid flush-tag function identifier\n"));
3156 break;
3157 }
3158 /* Don't assert that VMCPU_FF_TLB_FLUSH should no longer be pending. It can be set by other EMTs. */
3159}
3160
3161
3162/**
3163 * Sets up the appropriate tagged TLB-flush level and handler for flushing guest
3164 * TLB entries from the host TLB before VM-entry.
3165 *
3166 * @returns VBox status code.
3167 * @param pVM The cross context VM structure.
3168 */
3169static int hmR0VmxSetupTaggedTlb(PVM pVM)
3170{
3171 /*
3172 * Determine optimal flush type for nested paging.
3173 * We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup
3174 * unrestricted guest execution (see hmR3InitFinalizeR0()).
3175 */
3176 if (pVM->hm.s.fNestedPaging)
3177 {
3178 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT)
3179 {
3180 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT)
3181 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_SINGLE_CONTEXT;
3182 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
3183 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_ALL_CONTEXTS;
3184 else
3185 {
3186 /* Shouldn't happen. EPT is supported but no suitable flush-types supported. */
3187 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3188 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED;
3189 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3190 }
3191
3192 /* Make sure the write-back cacheable memory type for EPT is supported. */
3193 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EMT_WB)))
3194 {
3195 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3196 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_MEM_TYPE_NOT_WB;
3197 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3198 }
3199
3200 /* EPT requires a page-walk length of 4. */
3201 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4)))
3202 {
3203 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3204 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED;
3205 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3206 }
3207 }
3208 else
3209 {
3210 /* Shouldn't happen. EPT is supported but INVEPT instruction is not supported. */
3211 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3212 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_INVEPT_UNAVAILABLE;
3213 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3214 }
3215 }
3216
3217 /*
3218 * Determine optimal flush type for VPID.
3219 */
3220 if (pVM->hm.s.vmx.fVpid)
3221 {
3222 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID)
3223 {
3224 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT)
3225 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_SINGLE_CONTEXT;
3226 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS)
3227 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_ALL_CONTEXTS;
3228 else
3229 {
3230 /* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
3231 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
3232 LogRelFunc(("Only INDIV_ADDR supported. Ignoring VPID.\n"));
3233 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
3234 LogRelFunc(("Only SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
3235 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3236 pVM->hm.s.vmx.fVpid = false;
3237 }
3238 }
3239 else
3240 {
3241 /* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
3242 Log4Func(("VPID supported without INVEPT support. Ignoring VPID.\n"));
3243 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3244 pVM->hm.s.vmx.fVpid = false;
3245 }
3246 }
3247
3248 /*
3249 * Setup the handler for flushing tagged-TLBs.
3250 */
3251 if (pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid)
3252 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT_VPID;
3253 else if (pVM->hm.s.fNestedPaging)
3254 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT;
3255 else if (pVM->hm.s.vmx.fVpid)
3256 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_VPID;
3257 else
3258 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_NONE;
3259 return VINF_SUCCESS;
3260}
3261
3262
3263#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3264/**
3265 * Sets up the shadow VMCS fields arrays.
3266 *
3267 * This function builds arrays of VMCS fields to sync the shadow VMCS later while
3268 * executing the guest.
3269 *
3270 * @returns VBox status code.
3271 * @param pVM The cross context VM structure.
3272 */
3273static int hmR0VmxSetupShadowVmcsFieldsArrays(PVM pVM)
3274{
3275 /*
3276 * Paranoia. Ensure we haven't exposed the VMWRITE-All VMX feature to the guest
3277 * when the host does not support it.
3278 */
3279 bool const fGstVmwriteAll = pVM->cpum.ro.GuestFeatures.fVmxVmwriteAll;
3280 if ( !fGstVmwriteAll
3281 || (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL))
3282 { /* likely. */ }
3283 else
3284 {
3285 LogRelFunc(("VMX VMWRITE-All feature exposed to the guest but host CPU does not support it!\n"));
3286 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_GST_HOST_VMWRITE_ALL;
3287 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3288 }
3289
3290 uint32_t const cVmcsFields = RT_ELEMENTS(g_aVmcsFields);
3291 uint32_t cRwFields = 0;
3292 uint32_t cRoFields = 0;
3293 for (uint32_t i = 0; i < cVmcsFields; i++)
3294 {
3295 VMXVMCSFIELD VmcsField;
3296 VmcsField.u = g_aVmcsFields[i];
3297
3298 /*
3299 * We will be writing "FULL" (64-bit) fields while syncing the shadow VMCS.
3300 * Therefore, "HIGH" (32-bit portion of 64-bit) fields must not be included
3301 * in the shadow VMCS fields array as they would be redundant.
3302 *
3303 * If the VMCS field depends on a CPU feature that is not exposed to the guest,
3304 * we must not include it in the shadow VMCS fields array. Guests attempting to
3305 * VMREAD/VMWRITE such VMCS fields would cause a VM-exit and we shall emulate
3306 * the required behavior.
3307 */
3308 if ( VmcsField.n.fAccessType == VMX_VMCSFIELD_ACCESS_FULL
3309 && CPUMIsGuestVmxVmcsFieldValid(pVM, VmcsField.u))
3310 {
3311 /*
3312 * Read-only fields are placed in a separate array so that while syncing shadow
3313 * VMCS fields later (which is more performance critical) we can avoid branches.
3314 *
3315 * However, if the guest can write to all fields (including read-only fields),
3316 * we treat it a as read/write field. Otherwise, writing to these fields would
3317 * cause a VMWRITE instruction error while syncing the shadow VMCS .
3318 */
3319 if ( fGstVmwriteAll
3320 || !VMXIsVmcsFieldReadOnly(VmcsField.u))
3321 pVM->hm.s.vmx.paShadowVmcsFields[cRwFields++] = VmcsField.u;
3322 else
3323 pVM->hm.s.vmx.paShadowVmcsRoFields[cRoFields++] = VmcsField.u;
3324 }
3325 }
3326
3327 /* Update the counts. */
3328 pVM->hm.s.vmx.cShadowVmcsFields = cRwFields;
3329 pVM->hm.s.vmx.cShadowVmcsRoFields = cRoFields;
3330 return VINF_SUCCESS;
3331}
3332
3333
3334/**
3335 * Sets up the VMREAD and VMWRITE bitmaps.
3336 *
3337 * @param pVM The cross context VM structure.
3338 */
3339static void hmR0VmxSetupVmreadVmwriteBitmaps(PVM pVM)
3340{
3341 /*
3342 * By default, ensure guest attempts to acceses to any VMCS fields cause VM-exits.
3343 */
3344 uint32_t const cbBitmap = X86_PAGE_4K_SIZE;
3345 uint8_t *pbVmreadBitmap = (uint8_t *)pVM->hm.s.vmx.pvVmreadBitmap;
3346 uint8_t *pbVmwriteBitmap = (uint8_t *)pVM->hm.s.vmx.pvVmwriteBitmap;
3347 ASMMemFill32(pbVmreadBitmap, cbBitmap, UINT32_C(0xffffffff));
3348 ASMMemFill32(pbVmwriteBitmap, cbBitmap, UINT32_C(0xffffffff));
3349
3350 /*
3351 * Skip intercepting VMREAD/VMWRITE to guest read/write fields in the
3352 * VMREAD and VMWRITE bitmaps.
3353 */
3354 {
3355 uint32_t const *paShadowVmcsFields = pVM->hm.s.vmx.paShadowVmcsFields;
3356 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
3357 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
3358 {
3359 uint32_t const uVmcsField = paShadowVmcsFields[i];
3360 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3361 Assert(uVmcsField >> 3 < cbBitmap);
3362 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3363 ASMBitClear(pbVmwriteBitmap + (uVmcsField >> 3), uVmcsField & 7);
3364 }
3365 }
3366
3367 /*
3368 * Skip intercepting VMREAD for guest read-only fields in the VMREAD bitmap
3369 * if the host supports VMWRITE to all supported VMCS fields.
3370 */
3371 if (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL)
3372 {
3373 uint32_t const *paShadowVmcsRoFields = pVM->hm.s.vmx.paShadowVmcsRoFields;
3374 uint32_t const cShadowVmcsRoFields = pVM->hm.s.vmx.cShadowVmcsRoFields;
3375 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
3376 {
3377 uint32_t const uVmcsField = paShadowVmcsRoFields[i];
3378 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3379 Assert(uVmcsField >> 3 < cbBitmap);
3380 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3381 }
3382 }
3383}
3384#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
3385
3386
3387/**
3388 * Sets up the virtual-APIC page address for the VMCS.
3389 *
3390 * @param pVmcsInfo The VMCS info. object.
3391 */
3392DECLINLINE(void) hmR0VmxSetupVmcsVirtApicAddr(PCVMXVMCSINFO pVmcsInfo)
3393{
3394 RTHCPHYS const HCPhysVirtApic = pVmcsInfo->HCPhysVirtApic;
3395 Assert(HCPhysVirtApic != NIL_RTHCPHYS);
3396 Assert(!(HCPhysVirtApic & 0xfff)); /* Bits 11:0 MBZ. */
3397 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
3398 AssertRC(rc);
3399}
3400
3401
3402/**
3403 * Sets up the MSR-bitmap address for the VMCS.
3404 *
3405 * @param pVmcsInfo The VMCS info. object.
3406 */
3407DECLINLINE(void) hmR0VmxSetupVmcsMsrBitmapAddr(PCVMXVMCSINFO pVmcsInfo)
3408{
3409 RTHCPHYS const HCPhysMsrBitmap = pVmcsInfo->HCPhysMsrBitmap;
3410 Assert(HCPhysMsrBitmap != NIL_RTHCPHYS);
3411 Assert(!(HCPhysMsrBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3412 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_MSR_BITMAP_FULL, HCPhysMsrBitmap);
3413 AssertRC(rc);
3414}
3415
3416
3417/**
3418 * Sets up the APIC-access page address for the VMCS.
3419 *
3420 * @param pVCpu The cross context virtual CPU structure.
3421 */
3422DECLINLINE(void) hmR0VmxSetupVmcsApicAccessAddr(PVMCPU pVCpu)
3423{
3424 RTHCPHYS const HCPhysApicAccess = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysApicAccess;
3425 Assert(HCPhysApicAccess != NIL_RTHCPHYS);
3426 Assert(!(HCPhysApicAccess & 0xfff)); /* Bits 11:0 MBZ. */
3427 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
3428 AssertRC(rc);
3429}
3430
3431
3432#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3433/**
3434 * Sets up the VMREAD bitmap address for the VMCS.
3435 *
3436 * @param pVCpu The cross context virtual CPU structure.
3437 */
3438DECLINLINE(void) hmR0VmxSetupVmcsVmreadBitmapAddr(PVMCPU pVCpu)
3439{
3440 RTHCPHYS const HCPhysVmreadBitmap = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysVmreadBitmap;
3441 Assert(HCPhysVmreadBitmap != NIL_RTHCPHYS);
3442 Assert(!(HCPhysVmreadBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3443 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL, HCPhysVmreadBitmap);
3444 AssertRC(rc);
3445}
3446
3447
3448/**
3449 * Sets up the VMWRITE bitmap address for the VMCS.
3450 *
3451 * @param pVCpu The cross context virtual CPU structure.
3452 */
3453DECLINLINE(void) hmR0VmxSetupVmcsVmwriteBitmapAddr(PVMCPU pVCpu)
3454{
3455 RTHCPHYS const HCPhysVmwriteBitmap = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysVmwriteBitmap;
3456 Assert(HCPhysVmwriteBitmap != NIL_RTHCPHYS);
3457 Assert(!(HCPhysVmwriteBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3458 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL, HCPhysVmwriteBitmap);
3459 AssertRC(rc);
3460}
3461#endif
3462
3463
3464/**
3465 * Sets up the VM-entry MSR load, VM-exit MSR-store and VM-exit MSR-load addresses
3466 * in the VMCS.
3467 *
3468 * @returns VBox status code.
3469 * @param pVmcsInfo The VMCS info. object.
3470 */
3471DECLINLINE(int) hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(PVMXVMCSINFO pVmcsInfo)
3472{
3473 RTHCPHYS const HCPhysGuestMsrLoad = pVmcsInfo->HCPhysGuestMsrLoad;
3474 Assert(HCPhysGuestMsrLoad != NIL_RTHCPHYS);
3475 Assert(!(HCPhysGuestMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3476
3477 RTHCPHYS const HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrStore;
3478 Assert(HCPhysGuestMsrStore != NIL_RTHCPHYS);
3479 Assert(!(HCPhysGuestMsrStore & 0xf)); /* Bits 3:0 MBZ. */
3480
3481 RTHCPHYS const HCPhysHostMsrLoad = pVmcsInfo->HCPhysHostMsrLoad;
3482 Assert(HCPhysHostMsrLoad != NIL_RTHCPHYS);
3483 Assert(!(HCPhysHostMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3484
3485 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL, HCPhysGuestMsrLoad); AssertRC(rc);
3486 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL, HCPhysGuestMsrStore); AssertRC(rc);
3487 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL, HCPhysHostMsrLoad); AssertRC(rc);
3488 return VINF_SUCCESS;
3489}
3490
3491
3492/**
3493 * Sets up MSR permissions in the MSR bitmap of a VMCS info. object.
3494 *
3495 * @param pVCpu The cross context virtual CPU structure.
3496 * @param pVmcsInfo The VMCS info. object.
3497 */
3498static void hmR0VmxSetupVmcsMsrPermissions(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
3499{
3500 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS);
3501
3502 /*
3503 * The guest can access the following MSRs (read, write) without causing
3504 * VM-exits; they are loaded/stored automatically using fields in the VMCS.
3505 */
3506 PVM pVM = pVCpu->CTX_SUFF(pVM);
3507 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_CS, VMXMSRPM_ALLOW_RD_WR);
3508 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_ESP, VMXMSRPM_ALLOW_RD_WR);
3509 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_EIP, VMXMSRPM_ALLOW_RD_WR);
3510 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3511 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_FS_BASE, VMXMSRPM_ALLOW_RD_WR);
3512
3513 /*
3514 * The IA32_PRED_CMD and IA32_FLUSH_CMD MSRs are write-only and has no state
3515 * associated with then. We never need to intercept access (writes need to be
3516 * executed without causing a VM-exit, reads will #GP fault anyway).
3517 *
3518 * The IA32_SPEC_CTRL MSR is read/write and has state. We allow the guest to
3519 * read/write them. We swap the the guest/host MSR value using the
3520 * auto-load/store MSR area.
3521 */
3522 if (pVM->cpum.ro.GuestFeatures.fIbpb)
3523 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_PRED_CMD, VMXMSRPM_ALLOW_RD_WR);
3524 if (pVM->cpum.ro.GuestFeatures.fFlushCmd)
3525 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_FLUSH_CMD, VMXMSRPM_ALLOW_RD_WR);
3526 if (pVM->cpum.ro.GuestFeatures.fIbrs)
3527 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SPEC_CTRL, VMXMSRPM_ALLOW_RD_WR);
3528
3529 /*
3530 * Allow full read/write access for the following MSRs (mandatory for VT-x)
3531 * required for 64-bit guests.
3532 */
3533 if (pVM->hm.s.fAllow64BitGuests)
3534 {
3535 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_LSTAR, VMXMSRPM_ALLOW_RD_WR);
3536 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K6_STAR, VMXMSRPM_ALLOW_RD_WR);
3537 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_SF_MASK, VMXMSRPM_ALLOW_RD_WR);
3538 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_KERNEL_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3539 }
3540
3541 /*
3542 * IA32_EFER MSR is always intercepted, see @bugref{9180#c37}.
3543 */
3544#ifdef VBOX_STRICT
3545 Assert(pVmcsInfo->pvMsrBitmap);
3546 uint32_t const fMsrpmEfer = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, MSR_K6_EFER);
3547 Assert(fMsrpmEfer == VMXMSRPM_EXIT_RD_WR);
3548#endif
3549}
3550
3551
3552/**
3553 * Sets up pin-based VM-execution controls in the VMCS.
3554 *
3555 * @returns VBox status code.
3556 * @param pVCpu The cross context virtual CPU structure.
3557 * @param pVmcsInfo The VMCS info. object.
3558 */
3559static int hmR0VmxSetupVmcsPinCtls(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
3560{
3561 PVM pVM = pVCpu->CTX_SUFF(pVM);
3562 uint32_t fVal = pVM->hm.s.vmx.Msrs.PinCtls.n.allowed0; /* Bits set here must always be set. */
3563 uint32_t const fZap = pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
3564
3565 fVal |= VMX_PIN_CTLS_EXT_INT_EXIT /* External interrupts cause a VM-exit. */
3566 | VMX_PIN_CTLS_NMI_EXIT; /* Non-maskable interrupts (NMIs) cause a VM-exit. */
3567
3568 if (pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1 & VMX_PIN_CTLS_VIRT_NMI)
3569 fVal |= VMX_PIN_CTLS_VIRT_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
3570
3571 /* Enable the VMX-preemption timer. */
3572 if (pVM->hm.s.vmx.fUsePreemptTimer)
3573 {
3574 Assert(pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1 & VMX_PIN_CTLS_PREEMPT_TIMER);
3575 fVal |= VMX_PIN_CTLS_PREEMPT_TIMER;
3576 }
3577
3578#if 0
3579 /* Enable posted-interrupt processing. */
3580 if (pVM->hm.s.fPostedIntrs)
3581 {
3582 Assert(pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1 & VMX_PIN_CTLS_POSTED_INT);
3583 Assert(pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_ACK_EXT_INT);
3584 fVal |= VMX_PIN_CTLS_POSTED_INT;
3585 }
3586#endif
3587
3588 if ((fVal & fZap) != fVal)
3589 {
3590 LogRelFunc(("Invalid pin-based VM-execution controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3591 pVM->hm.s.vmx.Msrs.PinCtls.n.allowed0, fVal, fZap));
3592 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
3593 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3594 }
3595
3596 /* Commit it to the VMCS and update our cache. */
3597 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, fVal);
3598 AssertRC(rc);
3599 pVmcsInfo->u32PinCtls = fVal;
3600
3601 return VINF_SUCCESS;
3602}
3603
3604
3605/**
3606 * Sets up secondary processor-based VM-execution controls in the VMCS.
3607 *
3608 * @returns VBox status code.
3609 * @param pVCpu The cross context virtual CPU structure.
3610 * @param pVmcsInfo The VMCS info. object.
3611 */
3612static int hmR0VmxSetupVmcsProcCtls2(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
3613{
3614 PVM pVM = pVCpu->CTX_SUFF(pVM);
3615 uint32_t fVal = pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed0; /* Bits set here must be set in the VMCS. */
3616 uint32_t const fZap = pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3617
3618 /* WBINVD causes a VM-exit. */
3619 if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_WBINVD_EXIT)
3620 fVal |= VMX_PROC_CTLS2_WBINVD_EXIT;
3621
3622 /* Enable EPT (aka nested-paging). */
3623 if (pVM->hm.s.fNestedPaging)
3624 fVal |= VMX_PROC_CTLS2_EPT;
3625
3626 /* Enable the INVPCID instruction if we expose it to the guest and is supported
3627 by the hardware. Without this, guest executing INVPCID would cause a #UD. */
3628 if ( pVM->cpum.ro.GuestFeatures.fInvpcid
3629 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_INVPCID))
3630 fVal |= VMX_PROC_CTLS2_INVPCID;
3631
3632 /* Enable VPID. */
3633 if (pVM->hm.s.vmx.fVpid)
3634 fVal |= VMX_PROC_CTLS2_VPID;
3635
3636 /* Enable unrestricted guest execution. */
3637 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3638 fVal |= VMX_PROC_CTLS2_UNRESTRICTED_GUEST;
3639
3640#if 0
3641 if (pVM->hm.s.fVirtApicRegs)
3642 {
3643 /* Enable APIC-register virtualization. */
3644 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_APIC_REG_VIRT);
3645 fVal |= VMX_PROC_CTLS2_APIC_REG_VIRT;
3646
3647 /* Enable virtual-interrupt delivery. */
3648 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_INTR_DELIVERY);
3649 fVal |= VMX_PROC_CTLS2_VIRT_INTR_DELIVERY;
3650 }
3651#endif
3652
3653 /* Virtualize-APIC accesses if supported by the CPU. The virtual-APIC page is
3654 where the TPR shadow resides. */
3655 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
3656 * done dynamically. */
3657 if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
3658 {
3659 fVal |= VMX_PROC_CTLS2_VIRT_APIC_ACCESS;
3660 hmR0VmxSetupVmcsApicAccessAddr(pVCpu);
3661 }
3662
3663 /* Enable the RDTSCP instruction if we expose it to the guest and is supported
3664 by the hardware. Without this, guest executing RDTSCP would cause a #UD. */
3665 if ( pVM->cpum.ro.GuestFeatures.fRdTscP
3666 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_RDTSCP))
3667 fVal |= VMX_PROC_CTLS2_RDTSCP;
3668
3669 /* Enable Pause-Loop exiting. */
3670 if ( (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)
3671 && pVM->hm.s.vmx.cPleGapTicks
3672 && pVM->hm.s.vmx.cPleWindowTicks)
3673 {
3674 fVal |= VMX_PROC_CTLS2_PAUSE_LOOP_EXIT;
3675
3676 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, pVM->hm.s.vmx.cPleGapTicks); AssertRC(rc);
3677 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, pVM->hm.s.vmx.cPleWindowTicks); AssertRC(rc);
3678 }
3679
3680 if ((fVal & fZap) != fVal)
3681 {
3682 LogRelFunc(("Invalid secondary processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3683 pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed0, fVal, fZap));
3684 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
3685 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3686 }
3687
3688 /* Commit it to the VMCS and update our cache. */
3689 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, fVal);
3690 AssertRC(rc);
3691 pVmcsInfo->u32ProcCtls2 = fVal;
3692
3693 return VINF_SUCCESS;
3694}
3695
3696
3697/**
3698 * Sets up processor-based VM-execution controls in the VMCS.
3699 *
3700 * @returns VBox status code.
3701 * @param pVCpu The cross context virtual CPU structure.
3702 * @param pVmcsInfo The VMCS info. object.
3703 */
3704static int hmR0VmxSetupVmcsProcCtls(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
3705{
3706 PVM pVM = pVCpu->CTX_SUFF(pVM);
3707
3708 uint32_t fVal = pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
3709 uint32_t const fZap = pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3710
3711 fVal |= VMX_PROC_CTLS_HLT_EXIT /* HLT causes a VM-exit. */
3712 | VMX_PROC_CTLS_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
3713 | VMX_PROC_CTLS_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
3714 | VMX_PROC_CTLS_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
3715 | VMX_PROC_CTLS_RDPMC_EXIT /* RDPMC causes a VM-exit. */
3716 | VMX_PROC_CTLS_MONITOR_EXIT /* MONITOR causes a VM-exit. */
3717 | VMX_PROC_CTLS_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
3718
3719 /* We toggle VMX_PROC_CTLS_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
3720 if ( !(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MOV_DR_EXIT)
3721 || (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0 & VMX_PROC_CTLS_MOV_DR_EXIT))
3722 {
3723 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
3724 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3725 }
3726
3727 /* Without nested paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
3728 if (!pVM->hm.s.fNestedPaging)
3729 {
3730 Assert(!pVM->hm.s.vmx.fUnrestrictedGuest);
3731 fVal |= VMX_PROC_CTLS_INVLPG_EXIT
3732 | VMX_PROC_CTLS_CR3_LOAD_EXIT
3733 | VMX_PROC_CTLS_CR3_STORE_EXIT;
3734 }
3735
3736 /* Use TPR shadowing if supported by the CPU. */
3737 if ( PDMHasApic(pVM)
3738 && pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW)
3739 {
3740 fVal |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
3741 /* CR8 writes cause a VM-exit based on TPR threshold. */
3742 Assert(!(fVal & VMX_PROC_CTLS_CR8_STORE_EXIT));
3743 Assert(!(fVal & VMX_PROC_CTLS_CR8_LOAD_EXIT));
3744 hmR0VmxSetupVmcsVirtApicAddr(pVmcsInfo);
3745 }
3746 else
3747 {
3748 /* Some 32-bit CPUs do not support CR8 load/store exiting as MOV CR8 is
3749 invalid on 32-bit Intel CPUs. Set this control only for 64-bit guests. */
3750 if (pVM->hm.s.fAllow64BitGuests)
3751 {
3752 fVal |= VMX_PROC_CTLS_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
3753 | VMX_PROC_CTLS_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
3754 }
3755 }
3756
3757 /* Use MSR-bitmaps if supported by the CPU. */
3758 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
3759 {
3760 fVal |= VMX_PROC_CTLS_USE_MSR_BITMAPS;
3761 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
3762 }
3763
3764 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
3765 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
3766 fVal |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
3767
3768 if ((fVal & fZap) != fVal)
3769 {
3770 LogRelFunc(("Invalid processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3771 pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0, fVal, fZap));
3772 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
3773 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3774 }
3775
3776 /* Commit it to the VMCS and update our cache. */
3777 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, fVal);
3778 AssertRC(rc);
3779 pVmcsInfo->u32ProcCtls = fVal;
3780
3781 /* Set up MSR permissions that don't change through the lifetime of the VM. */
3782 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
3783 hmR0VmxSetupVmcsMsrPermissions(pVCpu, pVmcsInfo);
3784
3785 /* Set up secondary processor-based VM-execution controls if the CPU supports it. */
3786 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
3787 return hmR0VmxSetupVmcsProcCtls2(pVCpu, pVmcsInfo);
3788
3789 /* Sanity check, should not really happen. */
3790 if (RT_LIKELY(!pVM->hm.s.vmx.fUnrestrictedGuest))
3791 { /* likely */ }
3792 else
3793 {
3794 pVCpu->hm.s.u32HMError = VMX_UFC_INVALID_UX_COMBO;
3795 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3796 }
3797
3798 /* Old CPUs without secondary processor-based VM-execution controls would end up here. */
3799 return VINF_SUCCESS;
3800}
3801
3802
3803/**
3804 * Sets up miscellaneous (everything other than Pin, Processor and secondary
3805 * Processor-based VM-execution) control fields in the VMCS.
3806 *
3807 * @returns VBox status code.
3808 * @param pVCpu The cross context virtual CPU structure.
3809 * @param pVmcsInfo The VMCS info. object.
3810 */
3811static int hmR0VmxSetupVmcsMiscCtls(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
3812{
3813#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3814 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
3815 {
3816 hmR0VmxSetupVmcsVmreadBitmapAddr(pVCpu);
3817 hmR0VmxSetupVmcsVmwriteBitmapAddr(pVCpu);
3818 }
3819#endif
3820
3821 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
3822 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
3823 AssertRC(rc);
3824
3825 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
3826 if (RT_SUCCESS(rc))
3827 {
3828 uint64_t const u64Cr0Mask = hmR0VmxGetFixedCr0Mask(pVCpu);
3829 uint64_t const u64Cr4Mask = hmR0VmxGetFixedCr4Mask(pVCpu);
3830
3831 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask); AssertRC(rc);
3832 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask); AssertRC(rc);
3833
3834 pVmcsInfo->u64Cr0Mask = u64Cr0Mask;
3835 pVmcsInfo->u64Cr4Mask = u64Cr4Mask;
3836 return VINF_SUCCESS;
3837 }
3838 else
3839 LogRelFunc(("Failed to initialize VMCS auto-load/store MSR addresses. rc=%Rrc\n", rc));
3840 return rc;
3841}
3842
3843
3844/**
3845 * Sets up the initial exception bitmap in the VMCS based on static conditions.
3846 *
3847 * We shall setup those exception intercepts that don't change during the
3848 * lifetime of the VM here. The rest are done dynamically while loading the
3849 * guest state.
3850 *
3851 * @param pVCpu The cross context virtual CPU structure.
3852 * @param pVmcsInfo The VMCS info. object.
3853 */
3854static void hmR0VmxSetupVmcsXcptBitmap(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
3855{
3856 /*
3857 * The following exceptions are always intercepted:
3858 *
3859 * #AC - To prevent the guest from hanging the CPU.
3860 * #DB - To maintain the DR6 state even when intercepting DRx reads/writes and
3861 * recursive #DBs can cause a CPU hang.
3862 * #PF - To sync our shadow page tables when nested-paging is not used.
3863 */
3864 bool const fNestedPaging = pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging;
3865 uint32_t const uXcptBitmap = RT_BIT(X86_XCPT_AC)
3866 | RT_BIT(X86_XCPT_DB)
3867 | (fNestedPaging ? 0 : RT_BIT(X86_XCPT_PF));
3868
3869 /* Commit it to the VMCS. */
3870 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
3871 AssertRC(rc);
3872
3873 /* Update our cache of the exception bitmap. */
3874 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
3875}
3876
3877
3878#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3879/**
3880 * Sets up the VMCS for executing a nested-guest using hardware-assisted VMX.
3881 *
3882 * @returns VBox status code.
3883 * @param pVCpu The cross context virtual CPU structure.
3884 * @param pVmcsInfo The VMCS info. object.
3885 */
3886static int hmR0VmxSetupVmcsCtlsNested(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
3887{
3888 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
3889 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
3890 AssertRC(rc);
3891
3892 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
3893 if (RT_SUCCESS(rc))
3894 {
3895 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
3896 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
3897 return VINF_SUCCESS;
3898 }
3899 else
3900 LogRelFunc(("Failed to set up the VMCS link pointer in the nested-guest VMCS. rc=%Rrc\n", rc));
3901 return rc;
3902}
3903#endif
3904
3905
3906/**
3907 * Sets up the VMCS for executing a guest (or nested-guest) using hardware-assisted
3908 * VMX.
3909 *
3910 * @returns VBox status code.
3911 * @param pVCpu The cross context virtual CPU structure.
3912 * @param pVmcsInfo The VMCS info. object.
3913 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
3914 */
3915static int hmR0VmxSetupVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
3916{
3917 Assert(pVmcsInfo->pvVmcs);
3918 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
3919
3920 /* Set the CPU specified revision identifier at the beginning of the VMCS structure. */
3921 PVM pVM = pVCpu->CTX_SUFF(pVM);
3922 *(uint32_t *)pVmcsInfo->pvVmcs = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
3923 const char * const pszVmcs = fIsNstGstVmcs ? "nested-guest VMCS" : "guest VMCS";
3924
3925 LogFlowFunc(("\n"));
3926
3927 /*
3928 * Initialize the VMCS using VMCLEAR before loading the VMCS.
3929 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
3930 */
3931 int rc = hmR0VmxClearVmcs(pVmcsInfo);
3932 if (RT_SUCCESS(rc))
3933 {
3934 rc = hmR0VmxLoadVmcs(pVmcsInfo);
3935 if (RT_SUCCESS(rc))
3936 {
3937 if (!fIsNstGstVmcs)
3938 {
3939 rc = hmR0VmxSetupVmcsPinCtls(pVCpu, pVmcsInfo);
3940 if (RT_SUCCESS(rc))
3941 {
3942 rc = hmR0VmxSetupVmcsProcCtls(pVCpu, pVmcsInfo);
3943 if (RT_SUCCESS(rc))
3944 {
3945 rc = hmR0VmxSetupVmcsMiscCtls(pVCpu, pVmcsInfo);
3946 if (RT_SUCCESS(rc))
3947 {
3948 hmR0VmxSetupVmcsXcptBitmap(pVCpu, pVmcsInfo);
3949#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3950 /*
3951 * If a shadow VMCS is allocated for the VMCS info. object, initialize the
3952 * VMCS revision ID and shadow VMCS indicator bit. Also, clear the VMCS
3953 * making it fit for use when VMCS shadowing is later enabled.
3954 */
3955 if (pVmcsInfo->pvShadowVmcs)
3956 {
3957 VMXVMCSREVID VmcsRevId;
3958 VmcsRevId.u = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
3959 VmcsRevId.n.fIsShadowVmcs = 1;
3960 *(uint32_t *)pVmcsInfo->pvShadowVmcs = VmcsRevId.u;
3961 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
3962 if (RT_SUCCESS(rc))
3963 { /* likely */ }
3964 else
3965 LogRelFunc(("Failed to initialize shadow VMCS. rc=%Rrc\n", rc));
3966 }
3967#endif
3968 }
3969 else
3970 LogRelFunc(("Failed to setup miscellaneous controls. rc=%Rrc\n", rc));
3971 }
3972 else
3973 LogRelFunc(("Failed to setup processor-based VM-execution controls. rc=%Rrc\n", rc));
3974 }
3975 else
3976 LogRelFunc(("Failed to setup pin-based controls. rc=%Rrc\n", rc));
3977 }
3978 else
3979 {
3980#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3981 rc = hmR0VmxSetupVmcsCtlsNested(pVCpu, pVmcsInfo);
3982 if (RT_SUCCESS(rc))
3983 { /* likely */ }
3984 else
3985 LogRelFunc(("Failed to initialize nested-guest VMCS. rc=%Rrc\n", rc));
3986#else
3987 AssertFailed();
3988#endif
3989 }
3990 }
3991 else
3992 LogRelFunc(("Failed to load the %s. rc=%Rrc\n", rc, pszVmcs));
3993 }
3994 else
3995 LogRelFunc(("Failed to clear the %s. rc=%Rrc\n", rc, pszVmcs));
3996
3997 /* Sync any CPU internal VMCS data back into our VMCS in memory. */
3998 if (RT_SUCCESS(rc))
3999 {
4000 rc = hmR0VmxClearVmcs(pVmcsInfo);
4001 if (RT_SUCCESS(rc))
4002 { /* likely */ }
4003 else
4004 LogRelFunc(("Failed to clear the %s post setup. rc=%Rrc\n", rc, pszVmcs));
4005 }
4006
4007 /*
4008 * Update the last-error record both for failures and success, so we
4009 * can propagate the status code back to ring-3 for diagnostics.
4010 */
4011 hmR0VmxUpdateErrorRecord(pVCpu, rc);
4012 NOREF(pszVmcs);
4013 return rc;
4014}
4015
4016
4017/**
4018 * Does global VT-x initialization (called during module initialization).
4019 *
4020 * @returns VBox status code.
4021 */
4022VMMR0DECL(int) VMXR0GlobalInit(void)
4023{
4024#ifdef HMVMX_USE_FUNCTION_TABLE
4025 AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(g_apfnVMExitHandlers));
4026# ifdef VBOX_STRICT
4027 for (unsigned i = 0; i < RT_ELEMENTS(g_apfnVMExitHandlers); i++)
4028 Assert(g_apfnVMExitHandlers[i]);
4029# endif
4030#endif
4031 return VINF_SUCCESS;
4032}
4033
4034
4035/**
4036 * Does global VT-x termination (called during module termination).
4037 */
4038VMMR0DECL(void) VMXR0GlobalTerm()
4039{
4040 /* Nothing to do currently. */
4041}
4042
4043
4044/**
4045 * Sets up and activates VT-x on the current CPU.
4046 *
4047 * @returns VBox status code.
4048 * @param pHostCpu The HM physical-CPU structure.
4049 * @param pVM The cross context VM structure. Can be
4050 * NULL after a host resume operation.
4051 * @param pvCpuPage Pointer to the VMXON region (can be NULL if @a
4052 * fEnabledByHost is @c true).
4053 * @param HCPhysCpuPage Physical address of the VMXON region (can be 0 if
4054 * @a fEnabledByHost is @c true).
4055 * @param fEnabledByHost Set if SUPR0EnableVTx() or similar was used to
4056 * enable VT-x on the host.
4057 * @param pHwvirtMsrs Pointer to the hardware-virtualization MSRs.
4058 */
4059VMMR0DECL(int) VMXR0EnableCpu(PHMPHYSCPU pHostCpu, PVM pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost,
4060 PCSUPHWVIRTMSRS pHwvirtMsrs)
4061{
4062 AssertPtr(pHostCpu);
4063 AssertPtr(pHwvirtMsrs);
4064 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4065
4066 /* Enable VT-x if it's not already enabled by the host. */
4067 if (!fEnabledByHost)
4068 {
4069 int rc = hmR0VmxEnterRootMode(pVM, HCPhysCpuPage, pvCpuPage);
4070 if (RT_FAILURE(rc))
4071 return rc;
4072 }
4073
4074 /*
4075 * Flush all EPT tagged-TLB entries (in case VirtualBox or any other hypervisor have been
4076 * using EPTPs) so we don't retain any stale guest-physical mappings which won't get
4077 * invalidated when flushing by VPID.
4078 */
4079 if (pHwvirtMsrs->u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
4080 {
4081 hmR0VmxFlushEpt(NULL /* pVCpu */, NULL /* pVmcsInfo */, VMXTLBFLUSHEPT_ALL_CONTEXTS);
4082 pHostCpu->fFlushAsidBeforeUse = false;
4083 }
4084 else
4085 pHostCpu->fFlushAsidBeforeUse = true;
4086
4087 /* Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}. */
4088 ++pHostCpu->cTlbFlushes;
4089
4090 return VINF_SUCCESS;
4091}
4092
4093
4094/**
4095 * Deactivates VT-x on the current CPU.
4096 *
4097 * @returns VBox status code.
4098 * @param pvCpuPage Pointer to the VMXON region.
4099 * @param HCPhysCpuPage Physical address of the VMXON region.
4100 *
4101 * @remarks This function should never be called when SUPR0EnableVTx() or
4102 * similar was used to enable VT-x on the host.
4103 */
4104VMMR0DECL(int) VMXR0DisableCpu(void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
4105{
4106 RT_NOREF2(pvCpuPage, HCPhysCpuPage);
4107
4108 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4109 return hmR0VmxLeaveRootMode();
4110}
4111
4112
4113/**
4114 * Does per-VM VT-x initialization.
4115 *
4116 * @returns VBox status code.
4117 * @param pVM The cross context VM structure.
4118 */
4119VMMR0DECL(int) VMXR0InitVM(PVM pVM)
4120{
4121 AssertPtr(pVM);
4122 LogFlowFunc(("pVM=%p\n", pVM));
4123
4124 int rc = hmR0VmxStructsAlloc(pVM);
4125 if (RT_FAILURE(rc))
4126 {
4127 LogRelFunc(("Failed to allocated VMX structures. rc=%Rrc\n", rc));
4128 return rc;
4129 }
4130
4131 return VINF_SUCCESS;
4132}
4133
4134
4135/**
4136 * Does per-VM VT-x termination.
4137 *
4138 * @returns VBox status code.
4139 * @param pVM The cross context VM structure.
4140 */
4141VMMR0DECL(int) VMXR0TermVM(PVM pVM)
4142{
4143 AssertPtr(pVM);
4144 LogFlowFunc(("pVM=%p\n", pVM));
4145
4146#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4147 if (pVM->hm.s.vmx.hMemObjScratch != NIL_RTR0MEMOBJ)
4148 {
4149 Assert(pVM->hm.s.vmx.pvScratch);
4150 ASMMemZero32(pVM->hm.s.vmx.pvScratch, X86_PAGE_4K_SIZE);
4151 }
4152#endif
4153 hmR0VmxStructsFree(pVM);
4154 return VINF_SUCCESS;
4155}
4156
4157
4158/**
4159 * Sets up the VM for execution using hardware-assisted VMX.
4160 * This function is only called once per-VM during initialization.
4161 *
4162 * @returns VBox status code.
4163 * @param pVM The cross context VM structure.
4164 */
4165VMMR0DECL(int) VMXR0SetupVM(PVM pVM)
4166{
4167 AssertPtr(pVM);
4168 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4169
4170 LogFlowFunc(("pVM=%p\n", pVM));
4171
4172 /*
4173 * At least verify if VMX is enabled, since we can't check if we're in
4174 * VMX root mode or not without causing a #GP.
4175 */
4176 RTCCUINTREG const uHostCr4 = ASMGetCR4();
4177 if (RT_LIKELY(uHostCr4 & X86_CR4_VMXE))
4178 { /* likely */ }
4179 else
4180 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
4181
4182 /*
4183 * Without unrestricted guest execution, pRealModeTSS and pNonPagingModeEPTPageTable *must*
4184 * always be allocated. We no longer support the highly unlikely case of unrestricted guest
4185 * without pRealModeTSS, see hmR3InitFinalizeR0Intel().
4186 */
4187 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
4188 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
4189 || !pVM->hm.s.vmx.pRealModeTSS))
4190 {
4191 LogRelFunc(("Invalid real-on-v86 state.\n"));
4192 return VERR_INTERNAL_ERROR;
4193 }
4194
4195 /* Initialize these always, see hmR3InitFinalizeR0().*/
4196 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NONE;
4197 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NONE;
4198
4199 /* Setup the tagged-TLB flush handlers. */
4200 int rc = hmR0VmxSetupTaggedTlb(pVM);
4201 if (RT_FAILURE(rc))
4202 {
4203 LogRelFunc(("Failed to setup tagged TLB. rc=%Rrc\n", rc));
4204 return rc;
4205 }
4206
4207#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4208 /* Setup the shadow VMCS fields array and VMREAD/VMWRITE bitmaps. */
4209 if (pVM->hm.s.vmx.fUseVmcsShadowing)
4210 {
4211 rc = hmR0VmxSetupShadowVmcsFieldsArrays(pVM);
4212 if (RT_SUCCESS(rc))
4213 hmR0VmxSetupVmreadVmwriteBitmaps(pVM);
4214 else
4215 {
4216 LogRelFunc(("Failed to setup shadow VMCS fields arrays. rc=%Rrc\n", rc));
4217 return rc;
4218 }
4219 }
4220#endif
4221
4222 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
4223 {
4224 PVMCPU pVCpu = &pVM->aCpus[idCpu];
4225 Log4Func(("pVCpu=%p idCpu=%RU32\n", pVCpu, pVCpu->idCpu));
4226
4227 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hm.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
4228 if (RT_SUCCESS(rc))
4229 {
4230#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4231 if (pVM->cpum.ro.GuestFeatures.fVmx)
4232 {
4233 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hm.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
4234 if (RT_SUCCESS(rc))
4235 { /* likely */ }
4236 else
4237 {
4238 LogRelFunc(("Nested-guest VMCS setup failed. rc=%Rrc\n", rc));
4239 return rc;
4240 }
4241 }
4242#endif
4243 }
4244 else
4245 {
4246 LogRelFunc(("VMCS setup failed. rc=%Rrc\n", rc));
4247 return rc;
4248 }
4249 }
4250
4251 return VINF_SUCCESS;
4252}
4253
4254
4255/**
4256 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
4257 * the VMCS.
4258 */
4259static void hmR0VmxExportHostControlRegs(void)
4260{
4261 int rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR0, ASMGetCR0()); AssertRC(rc);
4262 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR3, ASMGetCR3()); AssertRC(rc);
4263 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR4, ASMGetCR4()); AssertRC(rc);
4264}
4265
4266
4267/**
4268 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
4269 * the host-state area in the VMCS.
4270 *
4271 * @returns VBox status code.
4272 * @param pVCpu The cross context virtual CPU structure.
4273 */
4274static int hmR0VmxExportHostSegmentRegs(PVMCPU pVCpu)
4275{
4276/**
4277 * Macro for adjusting host segment selectors to satisfy VT-x's VM-entry
4278 * requirements. See hmR0VmxExportHostSegmentRegs().
4279 */
4280#define VMXLOCAL_ADJUST_HOST_SEG(a_Seg, a_selValue) \
4281 if ((a_selValue) & (X86_SEL_RPL | X86_SEL_LDT)) \
4282 { \
4283 bool fValidSelector = true; \
4284 if ((a_selValue) & X86_SEL_LDT) \
4285 { \
4286 uint32_t const uAttr = ASMGetSegAttr(a_selValue); \
4287 fValidSelector = RT_BOOL(uAttr != UINT32_MAX && (uAttr & X86_DESC_P)); \
4288 } \
4289 if (fValidSelector) \
4290 { \
4291 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4292 pVCpu->hm.s.vmx.RestoreHost.uHostSel##a_Seg = (a_selValue); \
4293 } \
4294 (a_selValue) = 0; \
4295 }
4296
4297 /*
4298 * If we've executed guest code using hardware-assisted VMX, the host-state bits
4299 * will be messed up. We should -not- save the messed up state without restoring
4300 * the original host-state, see @bugref{7240}.
4301 *
4302 * This apparently can happen (most likely the FPU changes), deal with it rather than
4303 * asserting. Was observed booting Solaris 10u10 32-bit guest.
4304 */
4305 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
4306 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
4307 {
4308 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags,
4309 pVCpu->idCpu));
4310 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
4311 }
4312 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
4313
4314 /*
4315 * Host segment registers.
4316 */
4317 RTSEL uSelES = ASMGetES();
4318 RTSEL uSelCS = ASMGetCS();
4319 RTSEL uSelSS = ASMGetSS();
4320 RTSEL uSelDS = ASMGetDS();
4321 RTSEL uSelFS = ASMGetFS();
4322 RTSEL uSelGS = ASMGetGS();
4323 RTSEL uSelTR = ASMGetTR();
4324
4325 /*
4326 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to
4327 * gain VM-entry and restore them before we get preempted.
4328 *
4329 * See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
4330 */
4331 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
4332 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
4333 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
4334 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
4335
4336 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
4337 Assert(!(uSelCS & X86_SEL_RPL)); Assert(!(uSelCS & X86_SEL_LDT));
4338 Assert(!(uSelSS & X86_SEL_RPL)); Assert(!(uSelSS & X86_SEL_LDT));
4339 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
4340 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
4341 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
4342 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
4343 Assert(!(uSelTR & X86_SEL_RPL)); Assert(!(uSelTR & X86_SEL_LDT));
4344 Assert(uSelCS);
4345 Assert(uSelTR);
4346
4347 /* Write these host selector fields into the host-state area in the VMCS. */
4348 int rc = VMXWriteVmcs16(VMX_VMCS16_HOST_CS_SEL, uSelCS); AssertRC(rc);
4349 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_SS_SEL, uSelSS); AssertRC(rc);
4350 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_DS_SEL, uSelDS); AssertRC(rc);
4351 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_ES_SEL, uSelES); AssertRC(rc);
4352 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_FS_SEL, uSelFS); AssertRC(rc);
4353 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_GS_SEL, uSelGS); AssertRC(rc);
4354 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_TR_SEL, uSelTR); AssertRC(rc);
4355
4356 /*
4357 * Host GDTR and IDTR.
4358 */
4359 RTGDTR Gdtr;
4360 RTIDTR Idtr;
4361 RT_ZERO(Gdtr);
4362 RT_ZERO(Idtr);
4363 ASMGetGDTR(&Gdtr);
4364 ASMGetIDTR(&Idtr);
4365 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GDTR_BASE, Gdtr.pGdt); AssertRC(rc);
4366 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_IDTR_BASE, Idtr.pIdt); AssertRC(rc);
4367
4368 /*
4369 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps
4370 * them to the maximum limit (0xffff) on every VM-exit.
4371 */
4372 if (Gdtr.cbGdt != 0xffff)
4373 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
4374
4375 /*
4376 * IDT limit is effectively capped at 0xfff. (See Intel spec. 6.14.1 "64-Bit Mode IDT" and
4377 * Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit
4378 * as 0xfff, VT-x bloating the limit to 0xffff shouldn't cause any different CPU behavior.
4379 * However, several hosts either insists on 0xfff being the limit (Windows Patch Guard) or
4380 * uses the limit for other purposes (darwin puts the CPU ID in there but botches sidt
4381 * alignment in at least one consumer). So, we're only allowing the IDTR.LIMIT to be left
4382 * at 0xffff on hosts where we are sure it won't cause trouble.
4383 */
4384#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
4385 if (Idtr.cbIdt < 0x0fff)
4386#else
4387 if (Idtr.cbIdt != 0xffff)
4388#endif
4389 {
4390 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
4391 AssertCompile(sizeof(Idtr) == sizeof(X86XDTR64));
4392 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostIdtr, &Idtr, sizeof(X86XDTR64));
4393 }
4394
4395 /*
4396 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI
4397 * and RPL bits is effectively what the CPU does for "scaling by 8". TI is always 0 and
4398 * RPL should be too in most cases.
4399 */
4400 AssertMsgReturn((uSelTR | X86_SEL_RPL_LDT) <= Gdtr.cbGdt,
4401 ("TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, Gdtr.cbGdt), VERR_VMX_INVALID_HOST_STATE);
4402
4403 PCX86DESCHC pDesc = (PCX86DESCHC)(Gdtr.pGdt + (uSelTR & X86_SEL_MASK));
4404 uintptr_t const uTRBase = X86DESC64_BASE(pDesc);
4405
4406 /*
4407 * VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on
4408 * all VM-exits. The type is the same for 64-bit busy TSS[1]. The limit needs manual
4409 * restoration if the host has something else. Task switching is not supported in 64-bit
4410 * mode[2], but the limit still matters as IOPM is supported in 64-bit mode. Restoring the
4411 * limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
4412 *
4413 * [1] See Intel spec. 3.5 "System Descriptor Types".
4414 * [2] See Intel spec. 7.2.3 "TSS Descriptor in 64-bit mode".
4415 */
4416 PVM pVM = pVCpu->CTX_SUFF(pVM);
4417 Assert(pDesc->System.u4Type == 11);
4418 if ( pDesc->System.u16LimitLow != 0x67
4419 || pDesc->System.u4LimitHigh)
4420 {
4421 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_TR;
4422 /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */
4423 if (pVM->hm.s.fHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY)
4424 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY;
4425 pVCpu->hm.s.vmx.RestoreHost.uHostSelTR = uSelTR;
4426 }
4427
4428 /*
4429 * Store the GDTR as we need it when restoring the GDT and while restoring the TR.
4430 */
4431 if (pVCpu->hm.s.vmx.fRestoreHostFlags & (VMX_RESTORE_HOST_GDTR | VMX_RESTORE_HOST_SEL_TR))
4432 {
4433 AssertCompile(sizeof(Gdtr) == sizeof(X86XDTR64));
4434 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
4435 if (pVM->hm.s.fHostKernelFeatures & SUPKERNELFEATURES_GDT_NEED_WRITABLE)
4436 {
4437 /* The GDT is read-only but the writable GDT is available. */
4438 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_NEED_WRITABLE;
4439 pVCpu->hm.s.vmx.RestoreHost.HostGdtrRw.cb = Gdtr.cbGdt;
4440 rc = SUPR0GetCurrentGdtRw(&pVCpu->hm.s.vmx.RestoreHost.HostGdtrRw.uAddr);
4441 AssertRCReturn(rc, rc);
4442 }
4443 }
4444
4445 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_TR_BASE, uTRBase);
4446 AssertRC(rc);
4447
4448 /*
4449 * Host FS base and GS base.
4450 */
4451 uint64_t const u64FSBase = ASMRdMsr(MSR_K8_FS_BASE);
4452 uint64_t const u64GSBase = ASMRdMsr(MSR_K8_GS_BASE);
4453 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_FS_BASE, u64FSBase); AssertRC(rc);
4454 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GS_BASE, u64GSBase); AssertRC(rc);
4455
4456 /* Store the base if we have to restore FS or GS manually as we need to restore the base as well. */
4457 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_FS)
4458 pVCpu->hm.s.vmx.RestoreHost.uHostFSBase = u64FSBase;
4459 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_GS)
4460 pVCpu->hm.s.vmx.RestoreHost.uHostGSBase = u64GSBase;
4461
4462 return VINF_SUCCESS;
4463#undef VMXLOCAL_ADJUST_HOST_SEG
4464}
4465
4466
4467/**
4468 * Exports certain host MSRs in the VM-exit MSR-load area and some in the
4469 * host-state area of the VMCS.
4470 *
4471 * These MSRs will be automatically restored on the host after every successful
4472 * VM-exit.
4473 *
4474 * @param pVCpu The cross context virtual CPU structure.
4475 *
4476 * @remarks No-long-jump zone!!!
4477 */
4478static void hmR0VmxExportHostMsrs(PVMCPU pVCpu)
4479{
4480 AssertPtr(pVCpu);
4481
4482 /*
4483 * Save MSRs that we restore lazily (due to preemption or transition to ring-3)
4484 * rather than swapping them on every VM-entry.
4485 */
4486 hmR0VmxLazySaveHostMsrs(pVCpu);
4487
4488 /*
4489 * Host Sysenter MSRs.
4490 */
4491 int rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS)); AssertRC(rc);
4492 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP)); AssertRC(rc);
4493 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP)); AssertRC(rc);
4494
4495 /*
4496 * Host EFER MSR.
4497 *
4498 * If the CPU supports the newer VMCS controls for managing EFER, use it. Otherwise it's
4499 * done as part of auto-load/store MSR area in the VMCS, see hmR0VmxExportGuestMsrs().
4500 */
4501 PVM pVM = pVCpu->CTX_SUFF(pVM);
4502 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
4503 {
4504 rc = VMXWriteVmcs64(VMX_VMCS64_HOST_EFER_FULL, pVM->hm.s.vmx.u64HostMsrEfer);
4505 AssertRC(rc);
4506 }
4507
4508 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT also see
4509 * hmR0VmxExportGuestEntryExitCtls(). */
4510}
4511
4512
4513/**
4514 * Figures out if we need to swap the EFER MSR which is particularly expensive.
4515 *
4516 * We check all relevant bits. For now, that's everything besides LMA/LME, as
4517 * these two bits are handled by VM-entry, see hmR0VMxExportGuestEntryExitCtls().
4518 *
4519 * @returns true if we need to load guest EFER, false otherwise.
4520 * @param pVCpu The cross context virtual CPU structure.
4521 *
4522 * @remarks Requires EFER, CR4.
4523 * @remarks No-long-jump zone!!!
4524 */
4525static bool hmR0VmxShouldSwapEferMsr(PCVMCPU pVCpu)
4526{
4527#ifdef HMVMX_ALWAYS_SWAP_EFER
4528 RT_NOREF(pVCpu);
4529 return true;
4530#else
4531 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4532 PVM pVM = pVCpu->CTX_SUFF(pVM);
4533 uint64_t const u64HostEfer = pVM->hm.s.vmx.u64HostMsrEfer;
4534 uint64_t const u64GuestEfer = pCtx->msrEFER;
4535
4536 /*
4537 * For 64-bit guests, if EFER.SCE bit differs, we need to swap the EFER MSR
4538 * to ensure that the guest's SYSCALL behaviour isn't broken, see @bugref{7386}.
4539 */
4540 if ( CPUMIsGuestInLongModeEx(pCtx)
4541 && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
4542 return true;
4543
4544 /*
4545 * If the guest uses PAE and EFER.NXE bit differs, we need to swap the EFER MSR
4546 * as it affects guest paging. 64-bit paging implies CR4.PAE as well.
4547 *
4548 * See Intel spec. 4.5 "IA-32e Paging".
4549 * See Intel spec. 4.1.1 "Three Paging Modes".
4550 *
4551 * Verify that we always intercept CR4.PAE and CR0.PG bits, so we don't need to
4552 * import CR4 and CR0 from the VMCS here as those bits are always up to date.
4553 */
4554 Assert(hmR0VmxGetFixedCr4Mask(pVCpu) & X86_CR4_PAE);
4555 Assert(hmR0VmxGetFixedCr0Mask(pVCpu) & X86_CR0_PG);
4556 if ( (pCtx->cr4 & X86_CR4_PAE)
4557 && (pCtx->cr0 & X86_CR0_PG)
4558 && (u64GuestEfer & MSR_K6_EFER_NXE) != (u64HostEfer & MSR_K6_EFER_NXE))
4559 {
4560 /* Assert that host is NX capable. */
4561 Assert(pVCpu->CTX_SUFF(pVM)->cpum.ro.HostFeatures.fNoExecute);
4562 return true;
4563 }
4564
4565 return false;
4566#endif
4567}
4568
4569/**
4570 * Exports the guest state with appropriate VM-entry and VM-exit controls in the
4571 * VMCS.
4572 *
4573 * This is typically required when the guest changes paging mode.
4574 *
4575 * @returns VBox status code.
4576 * @param pVCpu The cross context virtual CPU structure.
4577 * @param pVmxTransient The VMX-transient structure.
4578 *
4579 * @remarks Requires EFER.
4580 * @remarks No-long-jump zone!!!
4581 */
4582static int hmR0VmxExportGuestEntryExitCtls(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
4583{
4584 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS)
4585 {
4586 PVM pVM = pVCpu->CTX_SUFF(pVM);
4587 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4588
4589 /*
4590 * VM-entry controls.
4591 */
4592 {
4593 uint32_t fVal = pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
4594 uint32_t const fZap = pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
4595
4596 /*
4597 * Load the guest debug controls (DR7 and IA32_DEBUGCTL MSR) on VM-entry.
4598 * The first VT-x capable CPUs only supported the 1-setting of this bit.
4599 *
4600 * For nested-guests, this is a mandatory VM-entry control. It's also
4601 * required because we do not want to leak host bits to the nested-guest.
4602 */
4603 fVal |= VMX_ENTRY_CTLS_LOAD_DEBUG;
4604
4605 /*
4606 * Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry.
4607 *
4608 * For nested-guests, the "IA-32e mode guest" control we initialize with what is
4609 * required to get the nested-guest working with hardware-assisted VMX execution.
4610 * It depends on the nested-guest's IA32_EFER.LMA bit. Remember, a guest hypervisor
4611 * can skip intercepting changes to the EFER MSR. This is why it it needs to be done
4612 * here rather than while merging the guest VMCS controls.
4613 */
4614 if (CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
4615 fVal |= VMX_ENTRY_CTLS_IA32E_MODE_GUEST;
4616 else
4617 Assert(!(fVal & VMX_ENTRY_CTLS_IA32E_MODE_GUEST));
4618
4619 /*
4620 * If the CPU supports the newer VMCS controls for managing guest/host EFER, use it.
4621 *
4622 * For nested-guests, we use the "load IA32_EFER" if the hardware supports it,
4623 * regardless of whether the nested-guest VMCS specifies it because we are free to
4624 * load whatever MSRs we require and we do not need to modify the guest visible copy
4625 * of the VM-entry MSR load area.
4626 */
4627 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
4628 && hmR0VmxShouldSwapEferMsr(pVCpu))
4629 fVal |= VMX_ENTRY_CTLS_LOAD_EFER_MSR;
4630 else
4631 Assert(!(fVal & VMX_ENTRY_CTLS_LOAD_EFER_MSR));
4632
4633 /*
4634 * The following should -not- be set (since we're not in SMM mode):
4635 * - VMX_ENTRY_CTLS_ENTRY_TO_SMM
4636 * - VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON
4637 */
4638
4639 /** @todo VMX_ENTRY_CTLS_LOAD_PERF_MSR,
4640 * VMX_ENTRY_CTLS_LOAD_PAT_MSR. */
4641
4642 if ((fVal & fZap) == fVal)
4643 { /* likely */ }
4644 else
4645 {
4646 Log4Func(("Invalid VM-entry controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
4647 pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed0, fVal, fZap));
4648 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_ENTRY;
4649 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4650 }
4651
4652 /* Commit it to the VMCS. */
4653 if (pVmcsInfo->u32EntryCtls != fVal)
4654 {
4655 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, fVal);
4656 AssertRC(rc);
4657 pVmcsInfo->u32EntryCtls = fVal;
4658 }
4659 }
4660
4661 /*
4662 * VM-exit controls.
4663 */
4664 {
4665 uint32_t fVal = pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
4666 uint32_t const fZap = pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
4667
4668 /*
4669 * Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only
4670 * supported the 1-setting of this bit.
4671 *
4672 * For nested-guests, we set the "save debug controls" as the converse
4673 * "load debug controls" is mandatory for nested-guests anyway.
4674 */
4675 fVal |= VMX_EXIT_CTLS_SAVE_DEBUG;
4676
4677 /*
4678 * Set the host long mode active (EFER.LMA) bit (which Intel calls
4679 * "Host address-space size") if necessary. On VM-exit, VT-x sets both the
4680 * host EFER.LMA and EFER.LME bit to this value. See assertion in
4681 * hmR0VmxExportHostMsrs().
4682 *
4683 * For nested-guests, we always set this bit as we do not support 32-bit
4684 * hosts.
4685 */
4686 fVal |= VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE;
4687
4688 /*
4689 * If the VMCS EFER MSR fields are supported by the hardware, we use it.
4690 *
4691 * For nested-guests, we should use the "save IA32_EFER" control if we also
4692 * used the "load IA32_EFER" control while exporting VM-entry controls.
4693 */
4694 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
4695 && hmR0VmxShouldSwapEferMsr(pVCpu))
4696 {
4697 fVal |= VMX_EXIT_CTLS_SAVE_EFER_MSR
4698 | VMX_EXIT_CTLS_LOAD_EFER_MSR;
4699 }
4700
4701 /*
4702 * Enable saving of the VMX-preemption timer value on VM-exit.
4703 * For nested-guests, currently not exposed/used.
4704 */
4705 if ( pVM->hm.s.vmx.fUsePreemptTimer
4706 && (pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER))
4707 fVal |= VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER;
4708
4709 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
4710 Assert(!(fVal & VMX_EXIT_CTLS_ACK_EXT_INT));
4711
4712 /** @todo VMX_EXIT_CTLS_LOAD_PERF_MSR,
4713 * VMX_EXIT_CTLS_SAVE_PAT_MSR,
4714 * VMX_EXIT_CTLS_LOAD_PAT_MSR. */
4715
4716 if ((fVal & fZap) == fVal)
4717 { /* likely */ }
4718 else
4719 {
4720 Log4Func(("Invalid VM-exit controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%R#X32\n",
4721 pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed0, fVal, fZap));
4722 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_EXIT;
4723 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4724 }
4725
4726 /* Commit it to the VMCS. */
4727 if (pVmcsInfo->u32ExitCtls != fVal)
4728 {
4729 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, fVal);
4730 AssertRC(rc);
4731 pVmcsInfo->u32ExitCtls = fVal;
4732 }
4733 }
4734
4735 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
4736 }
4737 return VINF_SUCCESS;
4738}
4739
4740
4741/**
4742 * Sets the TPR threshold in the VMCS.
4743 *
4744 * @param pVCpu The cross context virtual CPU structure.
4745 * @param pVmcsInfo The VMCS info. object.
4746 * @param u32TprThreshold The TPR threshold (task-priority class only).
4747 */
4748DECLINLINE(void) hmR0VmxApicSetTprThreshold(PVMXVMCSINFO pVmcsInfo, uint32_t u32TprThreshold)
4749{
4750 Assert(!(u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)); /* Bits 31:4 MBZ. */
4751 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
4752 RT_NOREF(pVmcsInfo);
4753 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
4754 AssertRC(rc);
4755}
4756
4757
4758/**
4759 * Exports the guest APIC TPR state into the VMCS.
4760 *
4761 * @returns VBox status code.
4762 * @param pVCpu The cross context virtual CPU structure.
4763 * @param pVmxTransient The VMX-transient structure.
4764 *
4765 * @remarks No-long-jump zone!!!
4766 */
4767static int hmR0VmxExportGuestApicTpr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
4768{
4769 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_APIC_TPR)
4770 {
4771 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
4772
4773 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4774 if (!pVmxTransient->fIsNestedGuest)
4775 {
4776 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
4777 && APICIsEnabled(pVCpu))
4778 {
4779 /*
4780 * Setup TPR shadowing.
4781 */
4782 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
4783 {
4784 bool fPendingIntr = false;
4785 uint8_t u8Tpr = 0;
4786 uint8_t u8PendingIntr = 0;
4787 int rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
4788 AssertRCReturn(rc, rc);
4789
4790 /*
4791 * If there are interrupts pending but masked by the TPR, instruct VT-x to
4792 * cause a TPR-below-threshold VM-exit when the guest lowers its TPR below the
4793 * priority of the pending interrupt so we can deliver the interrupt. If there
4794 * are no interrupts pending, set threshold to 0 to not cause any
4795 * TPR-below-threshold VM-exits.
4796 */
4797 uint32_t u32TprThreshold = 0;
4798 if (fPendingIntr)
4799 {
4800 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR
4801 (which is the Task-Priority Class). */
4802 const uint8_t u8PendingPriority = u8PendingIntr >> 4;
4803 const uint8_t u8TprPriority = u8Tpr >> 4;
4804 if (u8PendingPriority <= u8TprPriority)
4805 u32TprThreshold = u8PendingPriority;
4806 }
4807
4808 hmR0VmxApicSetTprThreshold(pVmcsInfo, u32TprThreshold);
4809 }
4810 }
4811 }
4812 /* else: the TPR threshold has already been updated while merging the nested-guest VMCS. */
4813 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
4814 }
4815 return VINF_SUCCESS;
4816}
4817
4818
4819/**
4820 * Gets the guest interruptibility-state.
4821 *
4822 * @returns Guest's interruptibility-state.
4823 * @param pVCpu The cross context virtual CPU structure.
4824 * @param pVmxTransient The VMX-transient structure.
4825 *
4826 * @remarks No-long-jump zone!!!
4827 */
4828static uint32_t hmR0VmxGetGuestIntrState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
4829{
4830 /*
4831 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
4832 */
4833 uint32_t fIntrState = 0;
4834 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
4835 {
4836 /* If inhibition is active, RIP and RFLAGS should've been imported from the VMCS already. */
4837 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
4838
4839 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4840 if (pCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
4841 {
4842 if (pCtx->eflags.Bits.u1IF)
4843 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
4844 else
4845 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS;
4846 }
4847 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
4848 {
4849 /*
4850 * We can clear the inhibit force flag as even if we go back to the recompiler
4851 * without executing guest code in VT-x, the flag's condition to be cleared is
4852 * met and thus the cleared state is correct.
4853 */
4854 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
4855 }
4856 }
4857
4858 /*
4859 * NMIs to the guest are blocked after an NMI is injected until the guest executes an IRET. We only
4860 * bother with virtual-NMI blocking when we have support for virtual NMIs in the CPU, otherwise
4861 * setting this would block host-NMIs and IRET will not clear the blocking.
4862 *
4863 * We always set NMI-exiting so when the host receives an NMI we get a VM-exit.
4864 *
4865 * See Intel spec. 26.6.1 "Interruptibility state". See @bugref{7445}.
4866 */
4867 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4868 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
4869 && CPUMIsGuestNmiBlocking(pVCpu))
4870 fIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
4871
4872 return fIntrState;
4873}
4874
4875
4876/**
4877 * Exports the exception intercepts required for guest execution in the VMCS.
4878 *
4879 * @returns VBox status code.
4880 * @param pVCpu The cross context virtual CPU structure.
4881 * @param pVmxTransient The VMX-transient structure.
4882 *
4883 * @remarks No-long-jump zone!!!
4884 */
4885static int hmR0VmxExportGuestXcptIntercepts(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
4886{
4887 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_XCPT_INTERCEPTS)
4888 {
4889 /* When executing a nested-guest, we do not need to trap GIM hypercalls by intercepting #UD. */
4890 if ( !pVmxTransient->fIsNestedGuest
4891 && pVCpu->hm.s.fGIMTrapXcptUD)
4892 hmR0VmxAddXcptIntercept(pVmxTransient, X86_XCPT_UD);
4893 else
4894 hmR0VmxRemoveXcptIntercept(pVCpu, pVmxTransient, X86_XCPT_UD);
4895
4896 /* Other exception intercepts are handled elsewhere, e.g. while exporting guest CR0. */
4897 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_XCPT_INTERCEPTS);
4898 }
4899 return VINF_SUCCESS;
4900}
4901
4902
4903/**
4904 * Exports the guest's RIP into the guest-state area in the VMCS.
4905 *
4906 * @returns VBox status code.
4907 * @param pVCpu The cross context virtual CPU structure.
4908 *
4909 * @remarks No-long-jump zone!!!
4910 */
4911static int hmR0VmxExportGuestRip(PVMCPU pVCpu)
4912{
4913 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RIP)
4914 {
4915 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP);
4916
4917 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RIP, pVCpu->cpum.GstCtx.rip);
4918 AssertRC(rc);
4919
4920 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RIP);
4921 Log4Func(("rip=%#RX64\n", pVCpu->cpum.GstCtx.rip));
4922 }
4923 return VINF_SUCCESS;
4924}
4925
4926
4927/**
4928 * Exports the guest's RSP into the guest-state area in the VMCS.
4929 *
4930 * @returns VBox status code.
4931 * @param pVCpu The cross context virtual CPU structure.
4932 *
4933 * @remarks No-long-jump zone!!!
4934 */
4935static int hmR0VmxExportGuestRsp(PVMCPU pVCpu)
4936{
4937 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RSP)
4938 {
4939 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RSP);
4940
4941 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RSP, pVCpu->cpum.GstCtx.rsp);
4942 AssertRC(rc);
4943
4944 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RSP);
4945 }
4946 return VINF_SUCCESS;
4947}
4948
4949
4950/**
4951 * Exports the guest's RFLAGS into the guest-state area in the VMCS.
4952 *
4953 * @returns VBox status code.
4954 * @param pVCpu The cross context virtual CPU structure.
4955 * @param pVmxTransient The VMX-transient structure.
4956 *
4957 * @remarks No-long-jump zone!!!
4958 */
4959static int hmR0VmxExportGuestRflags(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
4960{
4961 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RFLAGS)
4962 {
4963 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
4964
4965 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
4966 Let us assert it as such and use 32-bit VMWRITE. */
4967 Assert(!RT_HI_U32(pVCpu->cpum.GstCtx.rflags.u64));
4968 X86EFLAGS fEFlags = pVCpu->cpum.GstCtx.eflags;
4969 Assert(fEFlags.u32 & X86_EFL_RA1_MASK);
4970 Assert(!(fEFlags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
4971
4972 /*
4973 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so
4974 * we can restore them on VM-exit. Modify the real-mode guest's eflags so that VT-x
4975 * can run the real-mode guest code under Virtual 8086 mode.
4976 */
4977 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4978 if (pVmcsInfo->RealMode.fRealOnV86Active)
4979 {
4980 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
4981 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
4982 Assert(!pVmxTransient->fIsNestedGuest);
4983 pVmcsInfo->RealMode.Eflags.u32 = fEFlags.u32; /* Save the original eflags of the real-mode guest. */
4984 fEFlags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
4985 fEFlags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
4986 }
4987
4988 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RFLAGS, fEFlags.u32);
4989 AssertRC(rc);
4990
4991 /*
4992 * Setup pending debug exceptions if the guest is single-stepping using EFLAGS.TF.
4993 *
4994 * We must avoid setting any automatic debug exceptions delivery when single-stepping
4995 * through the hypervisor debugger using EFLAGS.TF.
4996 */
4997 if ( !pVmxTransient->fIsNestedGuest
4998 && !pVCpu->hm.s.fSingleInstruction
4999 && fEFlags.Bits.u1TF)
5000 {
5001 /** @todo r=ramshankar: Warning!! We ASSUME EFLAGS.TF will not cleared on
5002 * premature trips to ring-3 esp since IEM does not yet handle it. */
5003 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS);
5004 AssertRC(rc);
5005 }
5006 /** @todo NSTVMX: Handling copying of VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS from
5007 * nested-guest VMCS. */
5008
5009 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RFLAGS);
5010 Log4Func(("eflags=%#RX32\n", fEFlags.u32));
5011 }
5012 return VINF_SUCCESS;
5013}
5014
5015
5016#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5017/**
5018 * Copies the nested-guest VMCS to the shadow VMCS.
5019 *
5020 * @returns VBox status code.
5021 * @param pVCpu The cross context virtual CPU structure.
5022 * @param pVmcsInfo The VMCS info. object.
5023 *
5024 * @remarks No-long-jump zone!!!
5025 */
5026static int hmR0VmxCopyNstGstToShadowVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
5027{
5028 PVM pVM = pVCpu->CTX_SUFF(pVM);
5029 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5030
5031 /*
5032 * Disable interrupts so we don't get preempted while the shadow VMCS is the
5033 * current VMCS, as we may try saving guest lazy MSRs.
5034 *
5035 * Strictly speaking the lazy MSRs are not in the VMCS, but I'd rather not risk
5036 * calling the import VMCS code which is currently performing the guest MSR reads
5037 * (on 64-bit hosts) and accessing the auto-load/store MSR area on 32-bit hosts
5038 * and the rest of the VMX leave session machinery.
5039 */
5040 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
5041
5042 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5043 if (RT_SUCCESS(rc))
5044 {
5045 /*
5046 * Copy all guest read/write VMCS fields.
5047 *
5048 * We don't check for VMWRITE failures here for performance reasons and
5049 * because they are not expected to fail, barring irrecoverable conditions
5050 * like hardware errors.
5051 */
5052 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
5053 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5054 {
5055 uint64_t u64Val;
5056 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
5057 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5058 VMXWriteVmcs64(uVmcsField, u64Val);
5059 }
5060
5061 /*
5062 * If the host CPU supports writing all VMCS fields, copy the guest read-only
5063 * VMCS fields, so the guest can VMREAD them without causing a VM-exit.
5064 */
5065 if (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL)
5066 {
5067 uint32_t const cShadowVmcsRoFields = pVM->hm.s.vmx.cShadowVmcsRoFields;
5068 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
5069 {
5070 uint64_t u64Val;
5071 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsRoFields[i];
5072 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5073 VMXWriteVmcs64(uVmcsField, u64Val);
5074 }
5075 }
5076
5077 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5078 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5079 }
5080
5081 ASMSetFlags(fEFlags);
5082 return rc;
5083}
5084
5085
5086/**
5087 * Copies the shadow VMCS to the nested-guest VMCS.
5088 *
5089 * @returns VBox status code.
5090 * @param pVCpu The cross context virtual CPU structure.
5091 * @param pVmcsInfo The VMCS info. object.
5092 *
5093 * @remarks Called with interrupts disabled.
5094 */
5095static int hmR0VmxCopyShadowToNstGstVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
5096{
5097 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5098 PVM pVM = pVCpu->CTX_SUFF(pVM);
5099 PVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5100
5101 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5102 if (RT_SUCCESS(rc))
5103 {
5104 /*
5105 * Copy guest read/write fields from the shadow VMCS.
5106 * Guest read-only fields cannot be modified, so no need to copy them.
5107 *
5108 * We don't check for VMREAD failures here for performance reasons and
5109 * because they are not expected to fail, barring irrecoverable conditions
5110 * like hardware errors.
5111 */
5112 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
5113 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5114 {
5115 uint64_t u64Val;
5116 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
5117 VMXReadVmcs64(uVmcsField, &u64Val);
5118 IEMWriteVmxVmcsField(pVmcsNstGst, uVmcsField, u64Val);
5119 }
5120
5121 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5122 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5123 }
5124 return rc;
5125}
5126
5127
5128/**
5129 * Enables VMCS shadowing for the given VMCS info. object.
5130 *
5131 * @param pVmcsInfo The VMCS info. object.
5132 *
5133 * @remarks No-long-jump zone!!!
5134 */
5135static void hmR0VmxEnableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5136{
5137 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5138 if (!(uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING))
5139 {
5140 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
5141 uProcCtls2 |= VMX_PROC_CTLS2_VMCS_SHADOWING;
5142 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5143 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, pVmcsInfo->HCPhysShadowVmcs); AssertRC(rc);
5144 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5145 pVmcsInfo->u64VmcsLinkPtr = pVmcsInfo->HCPhysShadowVmcs;
5146 Log4Func(("Enabled\n"));
5147 }
5148}
5149
5150
5151/**
5152 * Disables VMCS shadowing for the given VMCS info. object.
5153 *
5154 * @param pVmcsInfo The VMCS info. object.
5155 *
5156 * @remarks No-long-jump zone!!!
5157 */
5158static void hmR0VmxDisableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5159{
5160 /*
5161 * We want all VMREAD and VMWRITE instructions to cause VM-exits, so we clear the
5162 * VMCS shadowing control. However, VM-entry requires the shadow VMCS indicator bit
5163 * to match the VMCS shadowing control if the VMCS link pointer is not NIL_RTHCPHYS.
5164 * Hence, we must also reset the VMCS link pointer to ensure VM-entry does not fail.
5165 *
5166 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
5167 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5168 */
5169 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5170 if (uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
5171 {
5172 uProcCtls2 &= ~VMX_PROC_CTLS2_VMCS_SHADOWING;
5173 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5174 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS); AssertRC(rc);
5175 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5176 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
5177 Log4Func(("Disabled\n"));
5178 }
5179}
5180#endif
5181
5182
5183/**
5184 * Exports the guest hardware-virtualization state.
5185 *
5186 * @returns VBox status code.
5187 * @param pVCpu The cross context virtual CPU structure.
5188 * @param pVmxTransient The VMX-transient structure.
5189 *
5190 * @remarks No-long-jump zone!!!
5191 */
5192static int hmR0VmxExportGuestHwvirtState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
5193{
5194 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_HWVIRT)
5195 {
5196#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5197 /*
5198 * Check if the VMX feature is exposed to the guest and if the host CPU supports
5199 * VMCS shadowing.
5200 */
5201 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
5202 {
5203 /*
5204 * If the guest hypervisor has loaded a current VMCS and is in VMX root mode,
5205 * copy the guest hypervisor's current VMCS into the shadow VMCS and enable
5206 * VMCS shadowing to skip intercepting some or all VMREAD/VMWRITE VM-exits.
5207 *
5208 * We check for VMX root mode here in case the guest executes VMXOFF without
5209 * clearing the current VMCS pointer and our VMXOFF instruction emulation does
5210 * not clear the current VMCS pointer.
5211 */
5212 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5213 if ( CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx)
5214 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx)
5215 && CPUMIsGuestVmxCurrentVmcsValid(pVCpu, &pVCpu->cpum.GstCtx))
5216 {
5217 /* Paranoia. */
5218 Assert(!pVmxTransient->fIsNestedGuest);
5219
5220 /*
5221 * For performance reasons, also check if the guest hypervisor's current VMCS
5222 * was newly loaded or modified before copying it to the shadow VMCS.
5223 */
5224 if (!pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs)
5225 {
5226 int rc = hmR0VmxCopyNstGstToShadowVmcs(pVCpu, pVmcsInfo);
5227 AssertRCReturn(rc, rc);
5228 pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs = true;
5229 }
5230 hmR0VmxEnableVmcsShadowing(pVmcsInfo);
5231 }
5232 else
5233 hmR0VmxDisableVmcsShadowing(pVmcsInfo);
5234 }
5235#else
5236 NOREF(pVmxTransient);
5237#endif
5238 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_HWVIRT);
5239 }
5240 return VINF_SUCCESS;
5241}
5242
5243
5244/**
5245 * Exports the guest CR0 control register into the guest-state area in the VMCS.
5246 *
5247 * The guest FPU state is always pre-loaded hence we don't need to bother about
5248 * sharing FPU related CR0 bits between the guest and host.
5249 *
5250 * @returns VBox status code.
5251 * @param pVCpu The cross context virtual CPU structure.
5252 * @param pVmxTransient The VMX-transient structure.
5253 *
5254 * @remarks No-long-jump zone!!!
5255 */
5256static int hmR0VmxExportGuestCR0(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
5257{
5258 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR0)
5259 {
5260 PVM pVM = pVCpu->CTX_SUFF(pVM);
5261 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5262
5263 /*
5264 * Figure out fixed CR0 bits in VMX operation.
5265 */
5266 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
5267 uint64_t fSetCr0 = pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1;
5268 uint64_t const fZapCr0 = pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1;
5269 if (pVM->hm.s.vmx.fUnrestrictedGuest)
5270 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
5271 else
5272 Assert((fSetCr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
5273
5274 if (!pVmxTransient->fIsNestedGuest)
5275 {
5276 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5277 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5278 uint64_t const u64ShadowCr0 = u64GuestCr0;
5279 Assert(!RT_HI_U32(u64GuestCr0));
5280
5281 /*
5282 * Setup VT-x's view of the guest CR0.
5283 */
5284 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5285 if (pVM->hm.s.fNestedPaging)
5286 {
5287 if (CPUMIsGuestPagingEnabled(pVCpu))
5288 {
5289 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
5290 uProcCtls &= ~( VMX_PROC_CTLS_CR3_LOAD_EXIT
5291 | VMX_PROC_CTLS_CR3_STORE_EXIT);
5292 }
5293 else
5294 {
5295 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
5296 uProcCtls |= VMX_PROC_CTLS_CR3_LOAD_EXIT
5297 | VMX_PROC_CTLS_CR3_STORE_EXIT;
5298 }
5299
5300 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
5301 if (pVM->hm.s.vmx.fUnrestrictedGuest)
5302 uProcCtls &= ~VMX_PROC_CTLS_CR3_STORE_EXIT;
5303 }
5304 else
5305 {
5306 /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
5307 u64GuestCr0 |= X86_CR0_WP;
5308 }
5309
5310 /*
5311 * Guest FPU bits.
5312 *
5313 * Since we pre-load the guest FPU always before VM-entry there is no need to track lazy state
5314 * using CR0.TS.
5315 *
5316 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be
5317 * set on the first CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
5318 */
5319 u64GuestCr0 |= X86_CR0_NE;
5320
5321 /* If CR0.NE isn't set, we need to intercept #MF exceptions and report them to the guest differently. */
5322 bool const fInterceptMF = !(u64ShadowCr0 & X86_CR0_NE);
5323
5324 /*
5325 * Update exception intercepts.
5326 */
5327 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
5328 if (pVmcsInfo->RealMode.fRealOnV86Active)
5329 {
5330 Assert(PDMVmmDevHeapIsEnabled(pVM));
5331 Assert(pVM->hm.s.vmx.pRealModeTSS);
5332 uXcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
5333 }
5334 else
5335 {
5336 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
5337 uXcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
5338 if (fInterceptMF)
5339 uXcptBitmap |= RT_BIT(X86_XCPT_MF);
5340 }
5341
5342 /* Additional intercepts for debugging, define these yourself explicitly. */
5343#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
5344 uXcptBitmap |= 0
5345 | RT_BIT(X86_XCPT_BP)
5346 | RT_BIT(X86_XCPT_DE)
5347 | RT_BIT(X86_XCPT_NM)
5348 | RT_BIT(X86_XCPT_TS)
5349 | RT_BIT(X86_XCPT_UD)
5350 | RT_BIT(X86_XCPT_NP)
5351 | RT_BIT(X86_XCPT_SS)
5352 | RT_BIT(X86_XCPT_GP)
5353 | RT_BIT(X86_XCPT_PF)
5354 | RT_BIT(X86_XCPT_MF)
5355 ;
5356#elif defined(HMVMX_ALWAYS_TRAP_PF)
5357 uXcptBitmap |= RT_BIT(X86_XCPT_PF);
5358#endif
5359 if (pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv)
5360 uXcptBitmap |= RT_BIT(X86_XCPT_GP);
5361 Assert(pVM->hm.s.fNestedPaging || (uXcptBitmap & RT_BIT(X86_XCPT_PF)));
5362
5363 /* Apply the hardware specified fixed CR0 bits and enable caching. */
5364 u64GuestCr0 |= fSetCr0;
5365 u64GuestCr0 &= fZapCr0;
5366 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5367
5368 /* Commit the CR0 and related fields to the guest VMCS. */
5369 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5370 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5371 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5372 {
5373 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5374 AssertRC(rc);
5375 }
5376 if (uXcptBitmap != pVmcsInfo->u32XcptBitmap)
5377 {
5378 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
5379 AssertRC(rc);
5380 }
5381
5382 /* Update our caches. */
5383 pVmcsInfo->u32ProcCtls = uProcCtls;
5384 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
5385
5386 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5387 }
5388 else
5389 {
5390 /*
5391 * With nested-guests, we may have extended the guest/host mask here since we
5392 * merged in the outer guest's mask. Thus, the merged mask can include more bits
5393 * (to read from the nested-guest CR0 read-shadow) than the guest hypervisor
5394 * originally supplied. We must copy those bits from the nested-guest CR0 into
5395 * the nested-guest CR0 read-shadow.
5396 */
5397 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5398 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5399 uint64_t const u64ShadowCr0 = CPUMGetGuestVmxMaskedCr0(pVCpu, &pVCpu->cpum.GstCtx, pVmcsInfo->u64Cr0Mask);
5400 Assert(!RT_HI_U32(u64GuestCr0));
5401 Assert(u64GuestCr0 & X86_CR0_NE);
5402
5403 /*
5404 * Apply the hardware specified fixed CR0 bits and enable caching.
5405 * Note! We could be altering our VMX emulation's fixed bits. We thus
5406 * need to re-apply them while importing CR0.
5407 */
5408 u64GuestCr0 |= fSetCr0;
5409 u64GuestCr0 &= fZapCr0;
5410 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5411
5412 /* Commit the CR0 and CR0 read-shadow to the nested-guest VMCS. */
5413 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5414 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5415
5416 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5417 }
5418
5419 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR0);
5420 }
5421
5422 return VINF_SUCCESS;
5423}
5424
5425
5426/**
5427 * Exports the guest control registers (CR3, CR4) into the guest-state area
5428 * in the VMCS.
5429 *
5430 * @returns VBox strict status code.
5431 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
5432 * without unrestricted guest access and the VMMDev is not presently
5433 * mapped (e.g. EFI32).
5434 *
5435 * @param pVCpu The cross context virtual CPU structure.
5436 * @param pVmxTransient The VMX-transient structure.
5437 *
5438 * @remarks No-long-jump zone!!!
5439 */
5440static VBOXSTRICTRC hmR0VmxExportGuestCR3AndCR4(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
5441{
5442 int rc = VINF_SUCCESS;
5443 PVM pVM = pVCpu->CTX_SUFF(pVM);
5444
5445 /*
5446 * Guest CR2.
5447 * It's always loaded in the assembler code. Nothing to do here.
5448 */
5449
5450 /*
5451 * Guest CR3.
5452 */
5453 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR3)
5454 {
5455 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
5456
5457 RTGCPHYS GCPhysGuestCr3 = NIL_RTGCPHYS;
5458 if (pVM->hm.s.fNestedPaging)
5459 {
5460 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5461 pVmcsInfo->HCPhysEPTP = PGMGetHyperCR3(pVCpu);
5462
5463 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
5464 Assert(pVmcsInfo->HCPhysEPTP != NIL_RTHCPHYS);
5465 Assert(!(pVmcsInfo->HCPhysEPTP & UINT64_C(0xfff0000000000000)));
5466 Assert(!(pVmcsInfo->HCPhysEPTP & 0xfff));
5467
5468 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
5469 pVmcsInfo->HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
5470 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
5471
5472 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
5473 AssertMsg( ((pVmcsInfo->HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
5474 && ((pVmcsInfo->HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
5475 ("EPTP %#RX64\n", pVmcsInfo->HCPhysEPTP));
5476 AssertMsg( !((pVmcsInfo->HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
5477 || (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
5478 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVmcsInfo->HCPhysEPTP));
5479
5480 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVmcsInfo->HCPhysEPTP);
5481 AssertRC(rc);
5482
5483 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5484 if ( pVM->hm.s.vmx.fUnrestrictedGuest
5485 || CPUMIsGuestPagingEnabledEx(pCtx))
5486 {
5487 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
5488 if (CPUMIsGuestInPAEModeEx(pCtx))
5489 {
5490 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
5491 AssertRC(rc);
5492 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
5493 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
5494 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
5495 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
5496 }
5497
5498 /*
5499 * The guest's view of its CR3 is unblemished with nested paging when the
5500 * guest is using paging or we have unrestricted guest execution to handle
5501 * the guest when it's not using paging.
5502 */
5503 GCPhysGuestCr3 = pCtx->cr3;
5504 }
5505 else
5506 {
5507 /*
5508 * The guest is not using paging, but the CPU (VT-x) has to. While the guest
5509 * thinks it accesses physical memory directly, we use our identity-mapped
5510 * page table to map guest-linear to guest-physical addresses. EPT takes care
5511 * of translating it to host-physical addresses.
5512 */
5513 RTGCPHYS GCPhys;
5514 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
5515
5516 /* We obtain it here every time as the guest could have relocated this PCI region. */
5517 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
5518 if (RT_SUCCESS(rc))
5519 { /* likely */ }
5520 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
5521 {
5522 Log4Func(("VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n"));
5523 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
5524 }
5525 else
5526 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
5527
5528 GCPhysGuestCr3 = GCPhys;
5529 }
5530
5531 Log4Func(("u32GuestCr3=%#RGp (GstN)\n", GCPhysGuestCr3));
5532 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, GCPhysGuestCr3);
5533 AssertRC(rc);
5534 }
5535 else
5536 {
5537 /* Non-nested paging case, just use the hypervisor's CR3. */
5538 RTHCPHYS const HCPhysGuestCr3 = PGMGetHyperCR3(pVCpu);
5539
5540 Log4Func(("u32GuestCr3=%#RHv (HstN)\n", HCPhysGuestCr3));
5541 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, HCPhysGuestCr3);
5542 AssertRC(rc);
5543 }
5544
5545 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR3);
5546 }
5547
5548 /*
5549 * Guest CR4.
5550 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
5551 */
5552 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR4)
5553 {
5554 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5555 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5556
5557 /*
5558 * Figure out fixed CR4 bits in VMX operation.
5559 */
5560 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
5561 uint64_t const fSetCr4 = pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1;
5562 uint64_t const fZapCr4 = pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1;
5563
5564 /*
5565 * With nested-guests, we may have extended the guest/host mask here (since we
5566 * merged in the outer guest's mask, see hmR0VmxMergeVmcsNested). This means, the
5567 * mask can include more bits (to read from the nested-guest CR4 read-shadow) than
5568 * the guest hypervisor originally supplied. Thus, we should, in essence, copy
5569 * those bits from the nested-guest CR4 into the nested-guest CR4 read-shadow.
5570 */
5571 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
5572 uint64_t u64GuestCr4 = pCtx->cr4;
5573 uint64_t const u64ShadowCr4 = !pVmxTransient->fIsNestedGuest
5574 ? pCtx->cr4
5575 : CPUMGetGuestVmxMaskedCr4(pVCpu, pCtx, pVmcsInfo->u64Cr4Mask);
5576 Assert(!RT_HI_U32(u64GuestCr4));
5577
5578 /*
5579 * Setup VT-x's view of the guest CR4.
5580 *
5581 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software
5582 * interrupts to the 8086 program interrupt handler. Clear the VME bit (the interrupt
5583 * redirection bitmap is already all 0, see hmR3InitFinalizeR0())
5584 *
5585 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
5586 */
5587 if (pVmcsInfo->RealMode.fRealOnV86Active)
5588 {
5589 Assert(pVM->hm.s.vmx.pRealModeTSS);
5590 Assert(PDMVmmDevHeapIsEnabled(pVM));
5591 u64GuestCr4 &= ~(uint64_t)X86_CR4_VME;
5592 }
5593
5594 if (pVM->hm.s.fNestedPaging)
5595 {
5596 if ( !CPUMIsGuestPagingEnabledEx(pCtx)
5597 && !pVM->hm.s.vmx.fUnrestrictedGuest)
5598 {
5599 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
5600 u64GuestCr4 |= X86_CR4_PSE;
5601 /* Our identity mapping is a 32-bit page directory. */
5602 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5603 }
5604 /* else use guest CR4.*/
5605 }
5606 else
5607 {
5608 Assert(!pVmxTransient->fIsNestedGuest);
5609
5610 /*
5611 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
5612 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
5613 */
5614 switch (pVCpu->hm.s.enmShadowMode)
5615 {
5616 case PGMMODE_REAL: /* Real-mode. */
5617 case PGMMODE_PROTECTED: /* Protected mode without paging. */
5618 case PGMMODE_32_BIT: /* 32-bit paging. */
5619 {
5620 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5621 break;
5622 }
5623
5624 case PGMMODE_PAE: /* PAE paging. */
5625 case PGMMODE_PAE_NX: /* PAE paging with NX. */
5626 {
5627 u64GuestCr4 |= X86_CR4_PAE;
5628 break;
5629 }
5630
5631 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
5632 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
5633#ifdef VBOX_WITH_64_BITS_GUESTS
5634 break;
5635#endif
5636 default:
5637 AssertFailed();
5638 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
5639 }
5640 }
5641
5642 /*
5643 * Apply the hardware specified fixed CR4 bits (mainly CR4.VMXE).
5644 * Note! For nested-guests, we could be altering our VMX emulation's
5645 * fixed bits. We thus need to re-apply them while importing CR4.
5646 */
5647 u64GuestCr4 |= fSetCr4;
5648 u64GuestCr4 &= fZapCr4;
5649
5650 /* Commit the CR4 and CR4 read-shadow to the guest VMCS. */
5651 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR4, u64GuestCr4); AssertRC(rc);
5652 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, u64ShadowCr4); AssertRC(rc);
5653
5654 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
5655 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
5656
5657 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR4);
5658
5659 Log4Func(("cr4=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64)\n", u64GuestCr4, u64ShadowCr4, fSetCr4, fZapCr4));
5660 }
5661 return rc;
5662}
5663
5664
5665/**
5666 * Exports the guest debug registers into the guest-state area in the VMCS.
5667 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
5668 *
5669 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
5670 *
5671 * @returns VBox status code.
5672 * @param pVCpu The cross context virtual CPU structure.
5673 * @param pVmxTransient The VMX-transient structure.
5674 *
5675 * @remarks No-long-jump zone!!!
5676 */
5677static int hmR0VmxExportSharedDebugState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
5678{
5679 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5680
5681 /** @todo NSTVMX: Figure out what we want to do with nested-guest instruction
5682 * stepping. */
5683 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5684 if (pVmxTransient->fIsNestedGuest)
5685 {
5686 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, CPUMGetGuestDR7(pVCpu));
5687 AssertRC(rc);
5688
5689 /* Always intercept Mov DRx accesses for the nested-guest for now. */
5690 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
5691 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
5692 AssertRC(rc);
5693 return VINF_SUCCESS;
5694 }
5695
5696#ifdef VBOX_STRICT
5697 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
5698 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
5699 {
5700 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
5701 Assert((pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0);
5702 Assert((pVCpu->cpum.GstCtx.dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK);
5703 }
5704#endif
5705
5706 bool fSteppingDB = false;
5707 bool fInterceptMovDRx = false;
5708 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5709 if (pVCpu->hm.s.fSingleInstruction)
5710 {
5711 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
5712 PVM pVM = pVCpu->CTX_SUFF(pVM);
5713 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
5714 {
5715 uProcCtls |= VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
5716 Assert(fSteppingDB == false);
5717 }
5718 else
5719 {
5720 pVCpu->cpum.GstCtx.eflags.u32 |= X86_EFL_TF;
5721 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_RFLAGS;
5722 pVCpu->hm.s.fClearTrapFlag = true;
5723 fSteppingDB = true;
5724 }
5725 }
5726
5727 uint64_t u64GuestDr7;
5728 if ( fSteppingDB
5729 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
5730 {
5731 /*
5732 * Use the combined guest and host DRx values found in the hypervisor register set
5733 * because the hypervisor debugger has breakpoints active or someone is single stepping
5734 * on the host side without a monitor trap flag.
5735 *
5736 * Note! DBGF expects a clean DR6 state before executing guest code.
5737 */
5738 if (!CPUMIsHyperDebugStateActive(pVCpu))
5739 {
5740 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
5741 Assert(CPUMIsHyperDebugStateActive(pVCpu));
5742 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
5743 }
5744
5745 /* Update DR7 with the hypervisor value (other DRx registers are handled by CPUM one way or another). */
5746 u64GuestDr7 = CPUMGetHyperDR7(pVCpu);
5747 pVCpu->hm.s.fUsingHyperDR7 = true;
5748 fInterceptMovDRx = true;
5749 }
5750 else
5751 {
5752 /*
5753 * If the guest has enabled debug registers, we need to load them prior to
5754 * executing guest code so they'll trigger at the right time.
5755 */
5756 if (pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
5757 {
5758 if (!CPUMIsGuestDebugStateActive(pVCpu))
5759 {
5760 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
5761 Assert(CPUMIsGuestDebugStateActive(pVCpu));
5762 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
5763 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
5764 }
5765 Assert(!fInterceptMovDRx);
5766 }
5767 else if (!CPUMIsGuestDebugStateActive(pVCpu))
5768 {
5769 /*
5770 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
5771 * must intercept #DB in order to maintain a correct DR6 guest value, and
5772 * because we need to intercept it to prevent nested #DBs from hanging the
5773 * CPU, we end up always having to intercept it. See hmR0VmxSetupVmcsXcptBitmap().
5774 */
5775 fInterceptMovDRx = true;
5776 }
5777
5778 /* Update DR7 with the actual guest value. */
5779 u64GuestDr7 = pVCpu->cpum.GstCtx.dr[7];
5780 pVCpu->hm.s.fUsingHyperDR7 = false;
5781 }
5782
5783 if (fInterceptMovDRx)
5784 uProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
5785 else
5786 uProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
5787
5788 /*
5789 * Update the processor-based VM-execution controls with the MOV-DRx intercepts and the
5790 * monitor-trap flag and update our cache.
5791 */
5792 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5793 {
5794 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5795 AssertRC(rc);
5796 pVmcsInfo->u32ProcCtls = uProcCtls;
5797 }
5798
5799 /*
5800 * Update guest DR7.
5801 */
5802 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, u64GuestDr7);
5803 AssertRC(rc);
5804
5805 /*
5806 * If we have forced EFLAGS.TF to be set because we're single-stepping in the hypervisor debugger,
5807 * we need to clear interrupt inhibition if any as otherwise it causes a VM-entry failure.
5808 *
5809 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5810 */
5811 if (fSteppingDB)
5812 {
5813 Assert(pVCpu->hm.s.fSingleInstruction);
5814 Assert(pVCpu->cpum.GstCtx.eflags.Bits.u1TF);
5815
5816 uint32_t fIntrState = 0;
5817 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
5818 AssertRC(rc);
5819
5820 if (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
5821 {
5822 fIntrState &= ~(VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
5823 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
5824 AssertRC(rc);
5825 }
5826 }
5827
5828 return VINF_SUCCESS;
5829}
5830
5831
5832#ifdef VBOX_STRICT
5833/**
5834 * Strict function to validate segment registers.
5835 *
5836 * @param pVCpu The cross context virtual CPU structure.
5837 * @param pVmcsInfo The VMCS info. object.
5838 *
5839 * @remarks Will import guest CR0 on strict builds during validation of
5840 * segments.
5841 */
5842static void hmR0VmxValidateSegmentRegs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
5843{
5844 /*
5845 * Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
5846 *
5847 * The reason we check for attribute value 0 in this function and not just the unusable bit is
5848 * because hmR0VmxExportGuestSegReg() only updates the VMCS' copy of the value with the
5849 * unusable bit and doesn't change the guest-context value.
5850 */
5851 PVM pVM = pVCpu->CTX_SUFF(pVM);
5852 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5853 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR0);
5854 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
5855 && ( !CPUMIsGuestInRealModeEx(pCtx)
5856 && !CPUMIsGuestInV86ModeEx(pCtx)))
5857 {
5858 /* Protected mode checks */
5859 /* CS */
5860 Assert(pCtx->cs.Attr.n.u1Present);
5861 Assert(!(pCtx->cs.Attr.u & 0xf00));
5862 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
5863 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
5864 || !(pCtx->cs.Attr.n.u1Granularity));
5865 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
5866 || (pCtx->cs.Attr.n.u1Granularity));
5867 /* CS cannot be loaded with NULL in protected mode. */
5868 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
5869 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
5870 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
5871 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
5872 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
5873 else
5874 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
5875 /* SS */
5876 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
5877 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
5878 if ( !(pCtx->cr0 & X86_CR0_PE)
5879 || pCtx->cs.Attr.n.u4Type == 3)
5880 {
5881 Assert(!pCtx->ss.Attr.n.u2Dpl);
5882 }
5883 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
5884 {
5885 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
5886 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
5887 Assert(pCtx->ss.Attr.n.u1Present);
5888 Assert(!(pCtx->ss.Attr.u & 0xf00));
5889 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
5890 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
5891 || !(pCtx->ss.Attr.n.u1Granularity));
5892 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
5893 || (pCtx->ss.Attr.n.u1Granularity));
5894 }
5895 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSegReg(). */
5896 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
5897 {
5898 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5899 Assert(pCtx->ds.Attr.n.u1Present);
5900 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
5901 Assert(!(pCtx->ds.Attr.u & 0xf00));
5902 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
5903 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
5904 || !(pCtx->ds.Attr.n.u1Granularity));
5905 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
5906 || (pCtx->ds.Attr.n.u1Granularity));
5907 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5908 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
5909 }
5910 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
5911 {
5912 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5913 Assert(pCtx->es.Attr.n.u1Present);
5914 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
5915 Assert(!(pCtx->es.Attr.u & 0xf00));
5916 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
5917 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
5918 || !(pCtx->es.Attr.n.u1Granularity));
5919 Assert( !(pCtx->es.u32Limit & 0xfff00000)
5920 || (pCtx->es.Attr.n.u1Granularity));
5921 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5922 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
5923 }
5924 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
5925 {
5926 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5927 Assert(pCtx->fs.Attr.n.u1Present);
5928 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
5929 Assert(!(pCtx->fs.Attr.u & 0xf00));
5930 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
5931 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
5932 || !(pCtx->fs.Attr.n.u1Granularity));
5933 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
5934 || (pCtx->fs.Attr.n.u1Granularity));
5935 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5936 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
5937 }
5938 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
5939 {
5940 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5941 Assert(pCtx->gs.Attr.n.u1Present);
5942 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
5943 Assert(!(pCtx->gs.Attr.u & 0xf00));
5944 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
5945 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
5946 || !(pCtx->gs.Attr.n.u1Granularity));
5947 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
5948 || (pCtx->gs.Attr.n.u1Granularity));
5949 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5950 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
5951 }
5952 /* 64-bit capable CPUs. */
5953 Assert(!RT_HI_U32(pCtx->cs.u64Base));
5954 Assert(!pCtx->ss.Attr.u || !RT_HI_U32(pCtx->ss.u64Base));
5955 Assert(!pCtx->ds.Attr.u || !RT_HI_U32(pCtx->ds.u64Base));
5956 Assert(!pCtx->es.Attr.u || !RT_HI_U32(pCtx->es.u64Base));
5957 }
5958 else if ( CPUMIsGuestInV86ModeEx(pCtx)
5959 || ( CPUMIsGuestInRealModeEx(pCtx)
5960 && !pVM->hm.s.vmx.fUnrestrictedGuest))
5961 {
5962 /* Real and v86 mode checks. */
5963 /* hmR0VmxExportGuestSegReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
5964 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
5965 if (pVmcsInfo->RealMode.fRealOnV86Active)
5966 {
5967 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3;
5968 u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
5969 }
5970 else
5971 {
5972 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
5973 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
5974 }
5975
5976 /* CS */
5977 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
5978 Assert(pCtx->cs.u32Limit == 0xffff);
5979 Assert(u32CSAttr == 0xf3);
5980 /* SS */
5981 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
5982 Assert(pCtx->ss.u32Limit == 0xffff);
5983 Assert(u32SSAttr == 0xf3);
5984 /* DS */
5985 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
5986 Assert(pCtx->ds.u32Limit == 0xffff);
5987 Assert(u32DSAttr == 0xf3);
5988 /* ES */
5989 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
5990 Assert(pCtx->es.u32Limit == 0xffff);
5991 Assert(u32ESAttr == 0xf3);
5992 /* FS */
5993 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
5994 Assert(pCtx->fs.u32Limit == 0xffff);
5995 Assert(u32FSAttr == 0xf3);
5996 /* GS */
5997 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
5998 Assert(pCtx->gs.u32Limit == 0xffff);
5999 Assert(u32GSAttr == 0xf3);
6000 /* 64-bit capable CPUs. */
6001 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6002 Assert(!u32SSAttr || !RT_HI_U32(pCtx->ss.u64Base));
6003 Assert(!u32DSAttr || !RT_HI_U32(pCtx->ds.u64Base));
6004 Assert(!u32ESAttr || !RT_HI_U32(pCtx->es.u64Base));
6005 }
6006}
6007#endif /* VBOX_STRICT */
6008
6009
6010/**
6011 * Exports a guest segment register into the guest-state area in the VMCS.
6012 *
6013 * @returns VBox status code.
6014 * @param pVCpu The cross context virtual CPU structure.
6015 * @param pVmcsInfo The VMCS info. object.
6016 * @param iSegReg The segment register number (X86_SREG_XXX).
6017 * @param pSelReg Pointer to the segment selector.
6018 *
6019 * @remarks No-long-jump zone!!!
6020 */
6021static int hmR0VmxExportGuestSegReg(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t iSegReg, PCCPUMSELREG pSelReg)
6022{
6023 Assert(iSegReg < X86_SREG_COUNT);
6024 uint32_t const idxSel = g_aVmcsSegSel[iSegReg];
6025 uint32_t const idxLimit = g_aVmcsSegLimit[iSegReg];
6026 uint32_t const idxBase = g_aVmcsSegBase[iSegReg];
6027 uint32_t const idxAttr = g_aVmcsSegAttr[iSegReg];
6028
6029 uint32_t u32Access = pSelReg->Attr.u;
6030 if (pVmcsInfo->RealMode.fRealOnV86Active)
6031 {
6032 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
6033 u32Access = 0xf3;
6034 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6035 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
6036 RT_NOREF_PV(pVCpu);
6037 }
6038 else
6039 {
6040 /*
6041 * The way to differentiate between whether this is really a null selector or was just
6042 * a selector loaded with 0 in real-mode is using the segment attributes. A selector
6043 * loaded in real-mode with the value 0 is valid and usable in protected-mode and we
6044 * should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures
6045 * NULL selectors loaded in protected-mode have their attribute as 0.
6046 */
6047 if (!u32Access)
6048 u32Access = X86DESCATTR_UNUSABLE;
6049 }
6050
6051 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
6052 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
6053 ("Access bit not set for usable segment. idx=%#x sel=%#x attr %#x\n", idxBase, pSelReg, pSelReg->Attr.u));
6054
6055 /*
6056 * Commit it to the VMCS.
6057 */
6058 int rc = VMXWriteVmcs32(idxSel, pSelReg->Sel); AssertRC(rc);
6059 rc = VMXWriteVmcs32(idxLimit, pSelReg->u32Limit); AssertRC(rc);
6060 rc = VMXWriteVmcsNw(idxBase, pSelReg->u64Base); AssertRC(rc);
6061 rc = VMXWriteVmcs32(idxAttr, u32Access); AssertRC(rc);
6062 return VINF_SUCCESS;
6063}
6064
6065
6066/**
6067 * Exports the guest segment registers, GDTR, IDTR, LDTR, TR into the guest-state
6068 * area in the VMCS.
6069 *
6070 * @returns VBox status code.
6071 * @param pVCpu The cross context virtual CPU structure.
6072 * @param pVmxTransient The VMX-transient structure.
6073 *
6074 * @remarks Will import guest CR0 on strict builds during validation of
6075 * segments.
6076 * @remarks No-long-jump zone!!!
6077 */
6078static int hmR0VmxExportGuestSegRegsXdtr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
6079{
6080 int rc = VERR_INTERNAL_ERROR_5;
6081 PVM pVM = pVCpu->CTX_SUFF(pVM);
6082 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6083 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6084
6085 /*
6086 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
6087 */
6088 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SREG_MASK)
6089 {
6090#ifdef VBOX_WITH_REM
6091 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
6092 {
6093 Assert(!pVmxTransient->fIsNestedGuest);
6094 Assert(pVM->hm.s.vmx.pRealModeTSS);
6095 AssertCompile(PGMMODE_REAL < PGMMODE_PROTECTED);
6096 if ( pVmcsInfo->fWasInRealMode
6097 && PGMGetGuestMode(pVCpu) >= PGMMODE_PROTECTED)
6098 {
6099 /*
6100 * Notify the recompiler must flush its code-cache as the guest -may-
6101 * rewrite code it in real-mode (e.g. OpenBSD 4.0).
6102 */
6103 REMFlushTBs(pVM);
6104 Log4Func(("Switch to protected mode detected!\n"));
6105 pVmcsInfo->fWasInRealMode = false;
6106 }
6107 }
6108#endif
6109 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CS)
6110 {
6111 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CS);
6112 if (pVmcsInfo->RealMode.fRealOnV86Active)
6113 pVmcsInfo->RealMode.AttrCS.u = pCtx->cs.Attr.u;
6114 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_CS, &pCtx->cs);
6115 AssertRC(rc);
6116 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CS);
6117 }
6118
6119 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SS)
6120 {
6121 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SS);
6122 if (pVmcsInfo->RealMode.fRealOnV86Active)
6123 pVmcsInfo->RealMode.AttrSS.u = pCtx->ss.Attr.u;
6124 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_SS, &pCtx->ss);
6125 AssertRC(rc);
6126 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SS);
6127 }
6128
6129 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_DS)
6130 {
6131 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DS);
6132 if (pVmcsInfo->RealMode.fRealOnV86Active)
6133 pVmcsInfo->RealMode.AttrDS.u = pCtx->ds.Attr.u;
6134 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_DS, &pCtx->ds);
6135 AssertRC(rc);
6136 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_DS);
6137 }
6138
6139 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_ES)
6140 {
6141 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_ES);
6142 if (pVmcsInfo->RealMode.fRealOnV86Active)
6143 pVmcsInfo->RealMode.AttrES.u = pCtx->es.Attr.u;
6144 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_ES, &pCtx->es);
6145 AssertRC(rc);
6146 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_ES);
6147 }
6148
6149 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_FS)
6150 {
6151 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_FS);
6152 if (pVmcsInfo->RealMode.fRealOnV86Active)
6153 pVmcsInfo->RealMode.AttrFS.u = pCtx->fs.Attr.u;
6154 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_FS, &pCtx->fs);
6155 AssertRC(rc);
6156 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_FS);
6157 }
6158
6159 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GS)
6160 {
6161 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GS);
6162 if (pVmcsInfo->RealMode.fRealOnV86Active)
6163 pVmcsInfo->RealMode.AttrGS.u = pCtx->gs.Attr.u;
6164 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_GS, &pCtx->gs);
6165 AssertRC(rc);
6166 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GS);
6167 }
6168
6169#ifdef VBOX_STRICT
6170 hmR0VmxValidateSegmentRegs(pVCpu, pVmcsInfo);
6171#endif
6172 Log4Func(("cs={%#04x base=%#RX64 limit=%#RX32 attr=%#RX32}\n", pCtx->cs.Sel, pCtx->cs.u64Base, pCtx->cs.u32Limit,
6173 pCtx->cs.Attr.u));
6174 }
6175
6176 /*
6177 * Guest TR.
6178 */
6179 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_TR)
6180 {
6181 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_TR);
6182
6183 /*
6184 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is
6185 * achieved using the interrupt redirection bitmap (all bits cleared to let the guest
6186 * handle INT-n's) in the TSS. See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
6187 */
6188 uint16_t u16Sel;
6189 uint32_t u32Limit;
6190 uint64_t u64Base;
6191 uint32_t u32AccessRights;
6192 if (!pVmcsInfo->RealMode.fRealOnV86Active)
6193 {
6194 u16Sel = pCtx->tr.Sel;
6195 u32Limit = pCtx->tr.u32Limit;
6196 u64Base = pCtx->tr.u64Base;
6197 u32AccessRights = pCtx->tr.Attr.u;
6198 }
6199 else
6200 {
6201 Assert(!pVmxTransient->fIsNestedGuest);
6202 Assert(pVM->hm.s.vmx.pRealModeTSS);
6203 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMCanExecuteGuest() -XXX- what about inner loop changes? */
6204
6205 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
6206 RTGCPHYS GCPhys;
6207 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
6208 AssertRCReturn(rc, rc);
6209
6210 X86DESCATTR DescAttr;
6211 DescAttr.u = 0;
6212 DescAttr.n.u1Present = 1;
6213 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
6214
6215 u16Sel = 0;
6216 u32Limit = HM_VTX_TSS_SIZE;
6217 u64Base = GCPhys;
6218 u32AccessRights = DescAttr.u;
6219 }
6220
6221 /* Validate. */
6222 Assert(!(u16Sel & RT_BIT(2)));
6223 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
6224 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
6225 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
6226 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
6227 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
6228 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
6229 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
6230 Assert( (u32Limit & 0xfff) == 0xfff
6231 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
6232 Assert( !(pCtx->tr.u32Limit & 0xfff00000)
6233 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
6234
6235 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_TR_SEL, u16Sel); AssertRC(rc);
6236 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit); AssertRC(rc);
6237 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights); AssertRC(rc);
6238 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_TR_BASE, u64Base); AssertRC(rc);
6239
6240 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_TR);
6241 Log4Func(("tr base=%#RX64 limit=%#RX32\n", pCtx->tr.u64Base, pCtx->tr.u32Limit));
6242 }
6243
6244 /*
6245 * Guest GDTR.
6246 */
6247 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GDTR)
6248 {
6249 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GDTR);
6250
6251 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt); AssertRC(rc);
6252 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, pCtx->gdtr.pGdt); AssertRC(rc);
6253
6254 /* Validate. */
6255 Assert(!(pCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6256
6257 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GDTR);
6258 Log4Func(("gdtr base=%#RX64 limit=%#RX32\n", pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt));
6259 }
6260
6261 /*
6262 * Guest LDTR.
6263 */
6264 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_LDTR)
6265 {
6266 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_LDTR);
6267
6268 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
6269 uint32_t u32Access;
6270 if ( !pVmxTransient->fIsNestedGuest
6271 && !pCtx->ldtr.Attr.u)
6272 u32Access = X86DESCATTR_UNUSABLE;
6273 else
6274 u32Access = pCtx->ldtr.Attr.u;
6275
6276 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, pCtx->ldtr.Sel); AssertRC(rc);
6277 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtr.u32Limit); AssertRC(rc);
6278 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access); AssertRC(rc);
6279 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, pCtx->ldtr.u64Base); AssertRC(rc);
6280
6281 /* Validate. */
6282 if (!(u32Access & X86DESCATTR_UNUSABLE))
6283 {
6284 Assert(!(pCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
6285 Assert(pCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
6286 Assert(!pCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
6287 Assert(pCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
6288 Assert(!pCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
6289 Assert(!(pCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
6290 Assert( (pCtx->ldtr.u32Limit & 0xfff) == 0xfff
6291 || !pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
6292 Assert( !(pCtx->ldtr.u32Limit & 0xfff00000)
6293 || pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
6294 }
6295
6296 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_LDTR);
6297 Log4Func(("ldtr base=%#RX64 limit=%#RX32\n", pCtx->ldtr.u64Base, pCtx->ldtr.u32Limit));
6298 }
6299
6300 /*
6301 * Guest IDTR.
6302 */
6303 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_IDTR)
6304 {
6305 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_IDTR);
6306
6307 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt); AssertRC(rc);
6308 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, pCtx->idtr.pIdt); AssertRC(rc);
6309
6310 /* Validate. */
6311 Assert(!(pCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6312
6313 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_IDTR);
6314 Log4Func(("idtr base=%#RX64 limit=%#RX32\n", pCtx->idtr.pIdt, pCtx->idtr.cbIdt));
6315 }
6316
6317 return VINF_SUCCESS;
6318}
6319
6320
6321/**
6322 * Exports certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
6323 * areas.
6324 *
6325 * These MSRs will automatically be loaded to the host CPU on every successful
6326 * VM-entry and stored from the host CPU on every successful VM-exit.
6327 *
6328 * We creates/updates MSR slots for the host MSRs in the VM-exit MSR-load area. The
6329 * actual host MSR values are not- updated here for performance reasons. See
6330 * hmR0VmxExportHostMsrs().
6331 *
6332 * We also exports the guest sysenter MSRs into the guest-state area in the VMCS.
6333 *
6334 * @returns VBox status code.
6335 * @param pVCpu The cross context virtual CPU structure.
6336 * @param pVmxTransient The VMX-transient structure.
6337 *
6338 * @remarks No-long-jump zone!!!
6339 */
6340static int hmR0VmxExportGuestMsrs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
6341{
6342 AssertPtr(pVCpu);
6343 AssertPtr(pVmxTransient);
6344
6345 PVM pVM = pVCpu->CTX_SUFF(pVM);
6346 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6347
6348 /*
6349 * MSRs that we use the auto-load/store MSR area in the VMCS.
6350 * For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(),
6351 * nothing to do here. The host MSR values are updated when it's safe in
6352 * hmR0VmxLazySaveHostMsrs().
6353 *
6354 * For nested-guests, the guests MSRs from the VM-entry MSR-load area are already
6355 * loaded (into the guest-CPU context) by the VMLAUNCH/VMRESUME instruction
6356 * emulation, nothing to do here.
6357 */
6358 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_GUEST_AUTO_MSRS)
6359 {
6360 /* No auto-load/store MSRs currently. */
6361 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_GUEST_AUTO_MSRS);
6362 }
6363
6364 /*
6365 * Guest Sysenter MSRs.
6366 */
6367 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_MSR_MASK)
6368 {
6369 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SYSENTER_MSRS);
6370
6371 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_CS_MSR)
6372 {
6373 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pCtx->SysEnter.cs);
6374 AssertRC(rc);
6375 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_CS_MSR);
6376 }
6377
6378 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_EIP_MSR)
6379 {
6380 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, pCtx->SysEnter.eip);
6381 AssertRC(rc);
6382 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
6383 }
6384
6385 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_ESP_MSR)
6386 {
6387 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, pCtx->SysEnter.esp);
6388 AssertRC(rc);
6389 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
6390 }
6391 }
6392
6393 /*
6394 * Guest/host EFER MSR.
6395 */
6396 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_EFER_MSR)
6397 {
6398 /* Whether we are using the VMCS to swap the EFER MSR must have been
6399 determined earlier while exporting VM-entry/VM-exit controls. */
6400 Assert(!(ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS));
6401 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
6402
6403 if (hmR0VmxShouldSwapEferMsr(pVCpu))
6404 {
6405 /*
6406 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
6407 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
6408 */
6409 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
6410 {
6411 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, pCtx->msrEFER);
6412 AssertRC(rc);
6413 }
6414 else
6415 {
6416 /*
6417 * We shall use the auto-load/store MSR area only for loading the EFER MSR but we must
6418 * continue to intercept guest read and write accesses to it, see @bugref{7386#c16}.
6419 */
6420 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER, pCtx->msrEFER,
6421 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6422 AssertRCReturn(rc, rc);
6423 }
6424 }
6425 else if (!pVM->hm.s.vmx.fSupportsVmcsEfer)
6426 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER);
6427
6428 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_EFER_MSR);
6429 }
6430
6431 /*
6432 * Other MSRs.
6433 * Speculation Control (R/W).
6434 */
6435 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_OTHER_MSRS)
6436 {
6437 HMVMX_CPUMCTX_ASSERT(pVCpu, HM_CHANGED_GUEST_OTHER_MSRS);
6438 if (pVM->cpum.ro.GuestFeatures.fIbrs)
6439 {
6440 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_IA32_SPEC_CTRL, CPUMGetGuestSpecCtrl(pVCpu),
6441 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6442 AssertRCReturn(rc, rc);
6443 }
6444 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
6445 }
6446
6447 return VINF_SUCCESS;
6448}
6449
6450
6451/**
6452 * Selects up the appropriate function to run guest code.
6453 *
6454 * @returns VBox status code.
6455 * @param pVCpu The cross context virtual CPU structure.
6456 * @param pVmxTransient The VMX-transient structure.
6457 *
6458 * @remarks No-long-jump zone!!!
6459 */
6460static int hmR0VmxSelectVMRunHandler(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
6461{
6462 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6463 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6464
6465 if (CPUMIsGuestInLongModeEx(pCtx))
6466 {
6467#ifndef VBOX_WITH_64_BITS_GUESTS
6468 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
6469#else
6470 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
6471 /* Guest is in long mode, use the 64-bit handler (host is 64-bit). */
6472 pVmcsInfo->pfnStartVM = VMXR0StartVM64;
6473#endif
6474 }
6475 else
6476 {
6477 /* Guest is not in long mode, use the 32-bit handler. */
6478 pVmcsInfo->pfnStartVM = VMXR0StartVM32;
6479 }
6480 Assert(pVmcsInfo->pfnStartVM);
6481 return VINF_SUCCESS;
6482}
6483
6484
6485/**
6486 * Wrapper for running the guest code in VT-x.
6487 *
6488 * @returns VBox status code, no informational status codes.
6489 * @param pVCpu The cross context virtual CPU structure.
6490 * @param pVmxTransient The VMX-transient structure.
6491 *
6492 * @remarks No-long-jump zone!!!
6493 */
6494DECLINLINE(int) hmR0VmxRunGuest(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient)
6495{
6496 /* Mark that HM is the keeper of all guest-CPU registers now that we're going to execute guest code. */
6497 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6498 pCtx->fExtrn |= HMVMX_CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_KEEPER_HM;
6499
6500 /** @todo Add stats for VMRESUME vs VMLAUNCH. */
6501
6502 /*
6503 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses
6504 * floating-point operations using SSE instructions. Some XMM registers (XMM6-XMM15) are
6505 * callee-saved and thus the need for this XMM wrapper.
6506 *
6507 * See MSDN "Configuring Programs for 64-bit/x64 Software Conventions / Register Usage".
6508 */
6509 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6510 bool const fResumeVM = RT_BOOL(pVmcsInfo->fVmcsState & VMX_V_VMCS_LAUNCH_STATE_LAUNCHED);
6511 PVM pVM = pVCpu->CTX_SUFF(pVM);
6512#ifdef VBOX_WITH_KERNEL_USING_XMM
6513 int rc = hmR0VMXStartVMWrapXMM(fResumeVM, pCtx, NULL /*pvUnused*/, pVM, pVCpu, pVmcsInfo->pfnStartVM);
6514#else
6515 int rc = pVmcsInfo->pfnStartVM(fResumeVM, pCtx, NULL /*pvUnused*/, pVM, pVCpu);
6516#endif
6517 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
6518 return rc;
6519}
6520
6521
6522/**
6523 * Reports world-switch error and dumps some useful debug info.
6524 *
6525 * @param pVCpu The cross context virtual CPU structure.
6526 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
6527 * @param pVmxTransient The VMX-transient structure (only
6528 * exitReason updated).
6529 */
6530static void hmR0VmxReportWorldSwitchError(PVMCPU pVCpu, int rcVMRun, PVMXTRANSIENT pVmxTransient)
6531{
6532 Assert(pVCpu);
6533 Assert(pVmxTransient);
6534 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
6535
6536 Log4Func(("VM-entry failure: %Rrc\n", rcVMRun));
6537 switch (rcVMRun)
6538 {
6539 case VERR_VMX_INVALID_VMXON_PTR:
6540 AssertFailed();
6541 break;
6542 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
6543 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
6544 {
6545 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
6546 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
6547 AssertRC(rc);
6548 hmR0VmxReadExitQualVmcs(pVmxTransient);
6549
6550 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
6551 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
6552 Cannot do it here as we may have been long preempted. */
6553
6554#ifdef VBOX_STRICT
6555 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6556 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
6557 pVmxTransient->uExitReason));
6558 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQual));
6559 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
6560 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
6561 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
6562 else
6563 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
6564 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
6565 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
6566
6567 static struct
6568 {
6569 /** Name of the field to log. */
6570 const char *pszName;
6571 /** The VMCS field. */
6572 uint32_t uVmcsField;
6573 /** Whether host support of this field needs to be checked. */
6574 bool fCheckSupport;
6575 } const s_aVmcsFields[] =
6576 {
6577 { "VMX_VMCS32_CTRL_PIN_EXEC", VMX_VMCS32_CTRL_PIN_EXEC, false },
6578 { "VMX_VMCS32_CTRL_PROC_EXEC", VMX_VMCS32_CTRL_PROC_EXEC, false },
6579 { "VMX_VMCS32_CTRL_PROC_EXEC2", VMX_VMCS32_CTRL_PROC_EXEC2, true },
6580 { "VMX_VMCS32_CTRL_ENTRY", VMX_VMCS32_CTRL_ENTRY, false },
6581 { "VMX_VMCS32_CTRL_EXIT", VMX_VMCS32_CTRL_EXIT, false },
6582 { "VMX_VMCS32_CTRL_CR3_TARGET_COUNT", VMX_VMCS32_CTRL_CR3_TARGET_COUNT, false },
6583 { "VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO", VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, false },
6584 { "VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE", VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, false },
6585 { "VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH", VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, false },
6586 { "VMX_VMCS32_CTRL_TPR_THRESHOLD", VMX_VMCS32_CTRL_TPR_THRESHOLD, false },
6587 { "VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, false },
6588 { "VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, false },
6589 { "VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, false },
6590 { "VMX_VMCS32_CTRL_EXCEPTION_BITMAP", VMX_VMCS32_CTRL_EXCEPTION_BITMAP, false },
6591 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, false },
6592 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, false },
6593 { "VMX_VMCS_CTRL_CR0_MASK", VMX_VMCS_CTRL_CR0_MASK, false },
6594 { "VMX_VMCS_CTRL_CR0_READ_SHADOW", VMX_VMCS_CTRL_CR0_READ_SHADOW, false },
6595 { "VMX_VMCS_CTRL_CR4_MASK", VMX_VMCS_CTRL_CR4_MASK, false },
6596 { "VMX_VMCS_CTRL_CR4_READ_SHADOW", VMX_VMCS_CTRL_CR4_READ_SHADOW, false },
6597 { "VMX_VMCS64_CTRL_EPTP_FULL", VMX_VMCS64_CTRL_EPTP_FULL, true },
6598 { "VMX_VMCS_GUEST_RIP", VMX_VMCS_GUEST_RIP, false },
6599 { "VMX_VMCS_GUEST_RSP", VMX_VMCS_GUEST_RSP, false },
6600 { "VMX_VMCS_GUEST_RFLAGS", VMX_VMCS_GUEST_RFLAGS, false },
6601 { "VMX_VMCS16_VPID", VMX_VMCS16_VPID, true, },
6602 { "VMX_VMCS_HOST_CR0", VMX_VMCS_HOST_CR0, false },
6603 { "VMX_VMCS_HOST_CR3", VMX_VMCS_HOST_CR3, false },
6604 { "VMX_VMCS_HOST_CR4", VMX_VMCS_HOST_CR4, false },
6605 /* The order of selector fields below are fixed! */
6606 { "VMX_VMCS16_HOST_ES_SEL", VMX_VMCS16_HOST_ES_SEL, false },
6607 { "VMX_VMCS16_HOST_CS_SEL", VMX_VMCS16_HOST_CS_SEL, false },
6608 { "VMX_VMCS16_HOST_SS_SEL", VMX_VMCS16_HOST_SS_SEL, false },
6609 { "VMX_VMCS16_HOST_DS_SEL", VMX_VMCS16_HOST_DS_SEL, false },
6610 { "VMX_VMCS16_HOST_FS_SEL", VMX_VMCS16_HOST_FS_SEL, false },
6611 { "VMX_VMCS16_HOST_GS_SEL", VMX_VMCS16_HOST_GS_SEL, false },
6612 { "VMX_VMCS16_HOST_TR_SEL", VMX_VMCS16_HOST_TR_SEL, false },
6613 /* End of ordered selector fields. */
6614 { "VMX_VMCS_HOST_TR_BASE", VMX_VMCS_HOST_TR_BASE, false },
6615 { "VMX_VMCS_HOST_GDTR_BASE", VMX_VMCS_HOST_GDTR_BASE, false },
6616 { "VMX_VMCS_HOST_IDTR_BASE", VMX_VMCS_HOST_IDTR_BASE, false },
6617 { "VMX_VMCS32_HOST_SYSENTER_CS", VMX_VMCS32_HOST_SYSENTER_CS, false },
6618 { "VMX_VMCS_HOST_SYSENTER_EIP", VMX_VMCS_HOST_SYSENTER_EIP, false },
6619 { "VMX_VMCS_HOST_SYSENTER_ESP", VMX_VMCS_HOST_SYSENTER_ESP, false },
6620 { "VMX_VMCS_HOST_RSP", VMX_VMCS_HOST_RSP, false },
6621 { "VMX_VMCS_HOST_RIP", VMX_VMCS_HOST_RIP, false }
6622 };
6623
6624 RTGDTR HostGdtr;
6625 ASMGetGDTR(&HostGdtr);
6626
6627 uint32_t const cVmcsFields = RT_ELEMENTS(s_aVmcsFields);
6628 for (uint32_t i = 0; i < cVmcsFields; i++)
6629 {
6630 uint32_t const uVmcsField = s_aVmcsFields[i].uVmcsField;
6631
6632 bool fSupported;
6633 if (!s_aVmcsFields[i].fCheckSupport)
6634 fSupported = true;
6635 else
6636 {
6637 PVM pVM = pVCpu->CTX_SUFF(pVM);
6638 switch (uVmcsField)
6639 {
6640 case VMX_VMCS64_CTRL_EPTP_FULL: fSupported = pVM->hm.s.fNestedPaging; break;
6641 case VMX_VMCS16_VPID: fSupported = pVM->hm.s.vmx.fVpid; break;
6642 case VMX_VMCS32_CTRL_PROC_EXEC2:
6643 fSupported = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
6644 break;
6645 default:
6646 AssertMsgFailedReturnVoid(("Failed to provide VMCS field support for %#RX32\n", uVmcsField));
6647 }
6648 }
6649
6650 if (fSupported)
6651 {
6652 uint8_t const uWidth = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH);
6653 switch (uWidth)
6654 {
6655 case VMX_VMCSFIELD_WIDTH_16BIT:
6656 {
6657 uint16_t u16Val;
6658 rc = VMXReadVmcs16(uVmcsField, &u16Val);
6659 AssertRC(rc);
6660 Log4(("%-40s = %#RX16\n", s_aVmcsFields[i].pszName, u16Val));
6661
6662 if ( uVmcsField >= VMX_VMCS16_HOST_ES_SEL
6663 && uVmcsField <= VMX_VMCS16_HOST_TR_SEL)
6664 {
6665 if (u16Val < HostGdtr.cbGdt)
6666 {
6667 /* Order of selectors in s_apszSel is fixed and matches the order in s_aVmcsFields. */
6668 static const char * const s_apszSel[] = { "Host ES", "Host CS", "Host SS", "Host DS",
6669 "Host FS", "Host GS", "Host TR" };
6670 uint8_t const idxSel = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_INDEX);
6671 Assert(idxSel < RT_ELEMENTS(s_apszSel));
6672 PCX86DESCHC pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u16Val & X86_SEL_MASK));
6673 hmR0DumpDescriptor(pDesc, u16Val, s_apszSel[idxSel]);
6674 }
6675 else
6676 Log4((" Selector value exceeds GDT limit!\n"));
6677 }
6678 break;
6679 }
6680
6681 case VMX_VMCSFIELD_WIDTH_32BIT:
6682 {
6683 uint32_t u32Val;
6684 rc = VMXReadVmcs32(uVmcsField, &u32Val);
6685 AssertRC(rc);
6686 Log4(("%-40s = %#RX32\n", s_aVmcsFields[i].pszName, u32Val));
6687 break;
6688 }
6689
6690 case VMX_VMCSFIELD_WIDTH_64BIT:
6691 case VMX_VMCSFIELD_WIDTH_NATURAL:
6692 {
6693 uint64_t u64Val;
6694 rc = VMXReadVmcs64(uVmcsField, &u64Val);
6695 AssertRC(rc);
6696 Log4(("%-40s = %#RX64\n", s_aVmcsFields[i].pszName, u64Val));
6697 break;
6698 }
6699 }
6700 }
6701 }
6702
6703 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
6704 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
6705 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
6706 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
6707 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
6708 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
6709#endif /* VBOX_STRICT */
6710 break;
6711 }
6712
6713 default:
6714 /* Impossible */
6715 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
6716 break;
6717 }
6718}
6719
6720
6721/**
6722 * Sets up the usage of TSC-offsetting and updates the VMCS.
6723 *
6724 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
6725 * VMX-preemption timer.
6726 *
6727 * @returns VBox status code.
6728 * @param pVCpu The cross context virtual CPU structure.
6729 * @param pVmxTransient The VMX-transient structure.
6730 *
6731 * @remarks No-long-jump zone!!!
6732 */
6733static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
6734{
6735 bool fOffsettedTsc;
6736 bool fParavirtTsc;
6737 uint64_t uTscOffset;
6738 PVM pVM = pVCpu->CTX_SUFF(pVM);
6739 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6740
6741 if (pVM->hm.s.vmx.fUsePreemptTimer)
6742 {
6743 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &uTscOffset, &fOffsettedTsc, &fParavirtTsc);
6744
6745 /* Make sure the returned values have sane upper and lower boundaries. */
6746 uint64_t u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
6747 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second */
6748 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
6749 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
6750
6751 /** @todo r=ramshankar: We need to find a way to integrate nested-guest
6752 * preemption timers here. We probably need to clamp the preemption timer,
6753 * after converting the timer value to the host. */
6754 uint32_t cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
6755 int rc = VMXWriteVmcs32(VMX_VMCS32_PREEMPT_TIMER_VALUE, cPreemptionTickCount);
6756 AssertRC(rc);
6757 }
6758 else
6759 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
6760
6761 if (fParavirtTsc)
6762 {
6763 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
6764 information before every VM-entry, hence disable it for performance sake. */
6765#if 0
6766 int rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
6767 AssertRC(rc);
6768#endif
6769 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
6770 }
6771
6772 if ( fOffsettedTsc
6773 && RT_LIKELY(!pVCpu->hm.s.fDebugWantRdTscExit))
6774 {
6775 if (pVmxTransient->fIsNestedGuest)
6776 uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
6777 hmR0VmxSetTscOffsetVmcs(pVmcsInfo, uTscOffset);
6778 hmR0VmxRemoveProcCtlsVmcs(pVCpu, pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
6779 }
6780 else
6781 {
6782 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
6783 hmR0VmxSetProcCtlsVmcs(pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
6784 }
6785}
6786
6787
6788/**
6789 * Gets the IEM exception flags for the specified vector and IDT vectoring /
6790 * VM-exit interruption info type.
6791 *
6792 * @returns The IEM exception flags.
6793 * @param uVector The event vector.
6794 * @param uVmxEventType The VMX event type.
6795 *
6796 * @remarks This function currently only constructs flags required for
6797 * IEMEvaluateRecursiveXcpt and not the complete flags (e.g, error-code
6798 * and CR2 aspects of an exception are not included).
6799 */
6800static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxEventType)
6801{
6802 uint32_t fIemXcptFlags;
6803 switch (uVmxEventType)
6804 {
6805 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
6806 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
6807 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
6808 break;
6809
6810 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
6811 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
6812 break;
6813
6814 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
6815 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
6816 break;
6817
6818 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
6819 {
6820 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6821 if (uVector == X86_XCPT_BP)
6822 fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
6823 else if (uVector == X86_XCPT_OF)
6824 fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
6825 else
6826 {
6827 fIemXcptFlags = 0;
6828 AssertMsgFailed(("Unexpected vector for software exception. uVector=%#x", uVector));
6829 }
6830 break;
6831 }
6832
6833 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
6834 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6835 break;
6836
6837 default:
6838 fIemXcptFlags = 0;
6839 AssertMsgFailed(("Unexpected vector type! uVmxEventType=%#x uVector=%#x", uVmxEventType, uVector));
6840 break;
6841 }
6842 return fIemXcptFlags;
6843}
6844
6845
6846/**
6847 * Sets an event as a pending event to be injected into the guest.
6848 *
6849 * @param pVCpu The cross context virtual CPU structure.
6850 * @param u32IntInfo The VM-entry interruption-information field.
6851 * @param cbInstr The VM-entry instruction length in bytes (for software
6852 * interrupts, exceptions and privileged software
6853 * exceptions).
6854 * @param u32ErrCode The VM-entry exception error code.
6855 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
6856 * page-fault.
6857 */
6858DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPU pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
6859 RTGCUINTPTR GCPtrFaultAddress)
6860{
6861 Assert(!pVCpu->hm.s.Event.fPending);
6862 pVCpu->hm.s.Event.fPending = true;
6863 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
6864 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
6865 pVCpu->hm.s.Event.cbInstr = cbInstr;
6866 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
6867}
6868
6869
6870/**
6871 * Sets an external interrupt as pending-for-injection into the VM.
6872 *
6873 * @param pVCpu The cross context virtual CPU structure.
6874 * @param u8Interrupt The external interrupt vector.
6875 */
6876DECLINLINE(void) hmR0VmxSetPendingExtInt(PVMCPU pVCpu, uint8_t u8Interrupt)
6877{
6878 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, u8Interrupt)
6879 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
6880 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6881 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6882 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6883}
6884
6885
6886/**
6887 * Sets an NMI (\#NMI) exception as pending-for-injection into the VM.
6888 *
6889 * @param pVCpu The cross context virtual CPU structure.
6890 */
6891DECLINLINE(void) hmR0VmxSetPendingXcptNmi(PVMCPU pVCpu)
6892{
6893 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI)
6894 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI)
6895 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6896 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6897 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6898}
6899
6900
6901/**
6902 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
6903 *
6904 * @param pVCpu The cross context virtual CPU structure.
6905 */
6906DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu)
6907{
6908 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
6909 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6910 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6911 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6912 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6913}
6914
6915
6916/**
6917 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
6918 *
6919 * @param pVCpu The cross context virtual CPU structure.
6920 */
6921DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPU pVCpu)
6922{
6923 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_UD)
6924 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6925 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6926 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6927 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6928}
6929
6930
6931/**
6932 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
6933 *
6934 * @param pVCpu The cross context virtual CPU structure.
6935 */
6936DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPU pVCpu)
6937{
6938 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
6939 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6940 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6941 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6942 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6943}
6944
6945
6946#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6947/**
6948 * Sets a general-protection (\#GP) exception as pending-for-injection into the VM.
6949 *
6950 * @param pVCpu The cross context virtual CPU structure.
6951 * @param u32ErrCode The error code for the general-protection exception.
6952 */
6953DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPU pVCpu, uint32_t u32ErrCode)
6954{
6955 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
6956 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6957 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6958 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6959 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
6960}
6961
6962
6963/**
6964 * Sets a stack (\#SS) exception as pending-for-injection into the VM.
6965 *
6966 * @param pVCpu The cross context virtual CPU structure.
6967 * @param u32ErrCode The error code for the stack exception.
6968 */
6969DECLINLINE(void) hmR0VmxSetPendingXcptSS(PVMCPU pVCpu, uint32_t u32ErrCode)
6970{
6971 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_SS)
6972 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6973 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6974 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6975 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
6976}
6977#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
6978
6979
6980/**
6981 * Fixes up attributes for the specified segment register.
6982 *
6983 * @param pVCpu The cross context virtual CPU structure.
6984 * @param pSelReg The segment register that needs fixing.
6985 * @param idxSel The VMCS field for the corresponding segment register.
6986 */
6987static void hmR0VmxFixUnusableSegRegAttr(PVMCPU pVCpu, PCPUMSELREG pSelReg, uint32_t idxSel)
6988{
6989 Assert(pSelReg->Attr.u & X86DESCATTR_UNUSABLE);
6990
6991 /*
6992 * If VT-x marks the segment as unusable, most other bits remain undefined:
6993 * - For CS the L, D and G bits have meaning.
6994 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
6995 * - For the remaining data segments no bits are defined.
6996 *
6997 * The present bit and the unusable bit has been observed to be set at the
6998 * same time (the selector was supposed to be invalid as we started executing
6999 * a V8086 interrupt in ring-0).
7000 *
7001 * What should be important for the rest of the VBox code, is that the P bit is
7002 * cleared. Some of the other VBox code recognizes the unusable bit, but
7003 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
7004 * safe side here, we'll strip off P and other bits we don't care about. If
7005 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
7006 *
7007 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
7008 */
7009#ifdef VBOX_STRICT
7010 uint32_t const uAttr = pSelReg->Attr.u;
7011#endif
7012
7013 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
7014 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
7015 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
7016
7017#ifdef VBOX_STRICT
7018 VMMRZCallRing3Disable(pVCpu);
7019 Log4Func(("Unusable %#x: sel=%#x attr=%#x -> %#x\n", idxSel, pSelReg->Sel, uAttr, pSelReg->Attr.u));
7020# ifdef DEBUG_bird
7021 AssertMsg((uAttr & ~X86DESCATTR_P) == pSelReg->Attr.u,
7022 ("%#x: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
7023 idxSel, uAttr, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
7024# endif
7025 VMMRZCallRing3Enable(pVCpu);
7026 NOREF(uAttr);
7027#endif
7028 RT_NOREF2(pVCpu, idxSel);
7029}
7030
7031
7032/**
7033 * Imports a guest segment register from the current VMCS into the guest-CPU
7034 * context.
7035 *
7036 * @param pVCpu The cross context virtual CPU structure.
7037 * @param iSegReg The segment register number (X86_SREG_XXX).
7038 *
7039 * @remarks Called with interrupts and/or preemption disabled.
7040 */
7041static void hmR0VmxImportGuestSegReg(PVMCPU pVCpu, uint8_t iSegReg)
7042{
7043 Assert(iSegReg < X86_SREG_COUNT);
7044
7045 uint32_t const idxSel = g_aVmcsSegSel[iSegReg];
7046 uint32_t const idxLimit = g_aVmcsSegLimit[iSegReg];
7047 uint32_t const idxAttr = g_aVmcsSegAttr[iSegReg];
7048 uint32_t const idxBase = g_aVmcsSegBase[iSegReg];
7049
7050 uint16_t u16Sel;
7051 uint64_t u64Base;
7052 uint32_t u32Limit, u32Attr;
7053 int rc = VMXReadVmcs16(idxSel, &u16Sel); AssertRC(rc);
7054 rc = VMXReadVmcs32(idxLimit, &u32Limit); AssertRC(rc);
7055 rc = VMXReadVmcs32(idxAttr, &u32Attr); AssertRC(rc);
7056 rc = VMXReadVmcsNw(idxBase, &u64Base); AssertRC(rc);
7057
7058 PCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
7059 pSelReg->Sel = u16Sel;
7060 pSelReg->ValidSel = u16Sel;
7061 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
7062 pSelReg->u32Limit = u32Limit;
7063 pSelReg->u64Base = u64Base;
7064 pSelReg->Attr.u = u32Attr;
7065 if (u32Attr & X86DESCATTR_UNUSABLE)
7066 hmR0VmxFixUnusableSegRegAttr(pVCpu, pSelReg, idxSel);
7067}
7068
7069
7070/**
7071 * Imports the guest LDTR from the current VMCS into the guest-CPU context.
7072 *
7073 * @param pVCpu The cross context virtual CPU structure.
7074 *
7075 * @remarks Called with interrupts and/or preemption disabled.
7076 */
7077static void hmR0VmxImportGuestLdtr(PVMCPU pVCpu)
7078{
7079 uint16_t u16Sel;
7080 uint64_t u64Base;
7081 uint32_t u32Limit, u32Attr;
7082 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, &u16Sel); AssertRC(rc);
7083 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, &u32Limit); AssertRC(rc);
7084 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7085 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, &u64Base); AssertRC(rc);
7086
7087 pVCpu->cpum.GstCtx.ldtr.Sel = u16Sel;
7088 pVCpu->cpum.GstCtx.ldtr.ValidSel = u16Sel;
7089 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
7090 pVCpu->cpum.GstCtx.ldtr.u32Limit = u32Limit;
7091 pVCpu->cpum.GstCtx.ldtr.u64Base = u64Base;
7092 pVCpu->cpum.GstCtx.ldtr.Attr.u = u32Attr;
7093 if (u32Attr & X86DESCATTR_UNUSABLE)
7094 hmR0VmxFixUnusableSegRegAttr(pVCpu, &pVCpu->cpum.GstCtx.ldtr, VMX_VMCS16_GUEST_LDTR_SEL);
7095}
7096
7097
7098/**
7099 * Imports the guest TR from the current VMCS into the guest-CPU context.
7100 *
7101 * @param pVCpu The cross context virtual CPU structure.
7102 *
7103 * @remarks Called with interrupts and/or preemption disabled.
7104 */
7105static void hmR0VmxImportGuestTr(PVMCPU pVCpu)
7106{
7107 uint16_t u16Sel;
7108 uint64_t u64Base;
7109 uint32_t u32Limit, u32Attr;
7110 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_TR_SEL, &u16Sel); AssertRC(rc);
7111 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, &u32Limit); AssertRC(rc);
7112 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7113 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_TR_BASE, &u64Base); AssertRC(rc);
7114
7115 pVCpu->cpum.GstCtx.tr.Sel = u16Sel;
7116 pVCpu->cpum.GstCtx.tr.ValidSel = u16Sel;
7117 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
7118 pVCpu->cpum.GstCtx.tr.u32Limit = u32Limit;
7119 pVCpu->cpum.GstCtx.tr.u64Base = u64Base;
7120 pVCpu->cpum.GstCtx.tr.Attr.u = u32Attr;
7121 /* TR is the only selector that can never be unusable. */
7122 Assert(!(u32Attr & X86DESCATTR_UNUSABLE));
7123}
7124
7125
7126/**
7127 * Imports the guest RIP from the VMCS back into the guest-CPU context.
7128 *
7129 * @param pVCpu The cross context virtual CPU structure.
7130 *
7131 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7132 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7133 * instead!!!
7134 */
7135static void hmR0VmxImportGuestRip(PVMCPU pVCpu)
7136{
7137 uint64_t u64Val;
7138 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7139 if (pCtx->fExtrn & CPUMCTX_EXTRN_RIP)
7140 {
7141 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
7142 AssertRC(rc);
7143
7144 pCtx->rip = u64Val;
7145 EMR0HistoryUpdatePC(pVCpu, pCtx->rip, false);
7146 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RIP;
7147 }
7148}
7149
7150
7151/**
7152 * Imports the guest RFLAGS from the VMCS back into the guest-CPU context.
7153 *
7154 * @param pVCpu The cross context virtual CPU structure.
7155 * @param pVmcsInfo The VMCS info. object.
7156 *
7157 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7158 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7159 * instead!!!
7160 */
7161static void hmR0VmxImportGuestRFlags(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
7162{
7163 RTHCUINTREG HCRegVal;
7164 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7165 if (pCtx->fExtrn & CPUMCTX_EXTRN_RFLAGS)
7166 {
7167 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &HCRegVal);
7168 AssertRC(rc);
7169
7170 pCtx->rflags.u64 = HCRegVal;
7171 if (pVmcsInfo->RealMode.fRealOnV86Active)
7172 {
7173 pCtx->eflags.Bits.u1VM = 0;
7174 pCtx->eflags.Bits.u2IOPL = pVmcsInfo->RealMode.Eflags.Bits.u2IOPL;
7175 }
7176 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RFLAGS;
7177 }
7178}
7179
7180
7181/**
7182 * Imports the guest interruptibility-state from the VMCS back into the guest-CPU
7183 * context.
7184 *
7185 * @param pVCpu The cross context virtual CPU structure.
7186 * @param pVmcsInfo The VMCS info. object.
7187 *
7188 * @remarks Called with interrupts and/or preemption disabled, try not to assert and
7189 * do not log!
7190 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7191 * instead!!!
7192 */
7193static void hmR0VmxImportGuestIntrState(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
7194{
7195 uint32_t u32Val;
7196 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32Val); AssertRC(rc);
7197 if (!u32Val)
7198 {
7199 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7200 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7201 CPUMSetGuestNmiBlocking(pVCpu, false);
7202 }
7203 else
7204 {
7205 /*
7206 * We must import RIP here to set our EM interrupt-inhibited state.
7207 * We also import RFLAGS as our code that evaluates pending interrupts
7208 * before VM-entry requires it.
7209 */
7210 hmR0VmxImportGuestRip(pVCpu);
7211 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7212
7213 if (u32Val & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
7214 EMSetInhibitInterruptsPC(pVCpu, pVCpu->cpum.GstCtx.rip);
7215 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7216 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7217
7218 bool const fNmiBlocking = RT_BOOL(u32Val & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
7219 CPUMSetGuestNmiBlocking(pVCpu, fNmiBlocking);
7220 }
7221}
7222
7223
7224/**
7225 * Worker for VMXR0ImportStateOnDemand.
7226 *
7227 * @returns VBox status code.
7228 * @param pVCpu The cross context virtual CPU structure.
7229 * @param pVmcsInfo The VMCS info. object.
7230 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7231 */
7232static int hmR0VmxImportGuestState(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
7233{
7234 int rc = VINF_SUCCESS;
7235 PVM pVM = pVCpu->CTX_SUFF(pVM);
7236 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7237 uint32_t u32Val;
7238 RTHCUINTREG HCRegVal;
7239
7240 /*
7241 * Note! This is hack to workaround a mysterious BSOD observed with release builds
7242 * on Windows 10 64-bit hosts. Profile and debug builds are not affected and
7243 * neither are other host platforms.
7244 *
7245 * Committing this temporarily as it prevents BSOD.
7246 *
7247 * Update: This is very likely a compiler optimization bug, see @bugref{9180}.
7248 */
7249#ifdef RT_OS_WINDOWS
7250 if (pVM == 0 || pVM == (void *)(uintptr_t)-1)
7251 return VERR_HM_IPE_1;
7252#endif
7253
7254 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatImportGuestState, x);
7255
7256 /*
7257 * We disable interrupts to make the updating of the state and in particular
7258 * the fExtrn modification atomic wrt to preemption hooks.
7259 */
7260 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
7261
7262 fWhat &= pCtx->fExtrn;
7263 if (fWhat)
7264 {
7265 do
7266 {
7267 if (fWhat & CPUMCTX_EXTRN_RIP)
7268 hmR0VmxImportGuestRip(pVCpu);
7269
7270 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
7271 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7272
7273 if (fWhat & CPUMCTX_EXTRN_HM_VMX_INT_STATE)
7274 hmR0VmxImportGuestIntrState(pVCpu, pVmcsInfo);
7275
7276 if (fWhat & CPUMCTX_EXTRN_RSP)
7277 {
7278 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RSP, &HCRegVal);
7279 AssertRC(rc);
7280 pCtx->rsp = HCRegVal;
7281 }
7282
7283 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
7284 {
7285 bool const fRealOnV86Active = pVmcsInfo->RealMode.fRealOnV86Active;
7286 if (fWhat & CPUMCTX_EXTRN_CS)
7287 {
7288 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_CS);
7289 hmR0VmxImportGuestRip(pVCpu);
7290 if (fRealOnV86Active)
7291 pCtx->cs.Attr.u = pVmcsInfo->RealMode.AttrCS.u;
7292 EMR0HistoryUpdatePC(pVCpu, pCtx->cs.u64Base + pCtx->rip, true /* fFlattened */);
7293 }
7294 if (fWhat & CPUMCTX_EXTRN_SS)
7295 {
7296 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_SS);
7297 if (fRealOnV86Active)
7298 pCtx->ss.Attr.u = pVmcsInfo->RealMode.AttrSS.u;
7299 }
7300 if (fWhat & CPUMCTX_EXTRN_DS)
7301 {
7302 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_DS);
7303 if (fRealOnV86Active)
7304 pCtx->ds.Attr.u = pVmcsInfo->RealMode.AttrDS.u;
7305 }
7306 if (fWhat & CPUMCTX_EXTRN_ES)
7307 {
7308 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_ES);
7309 if (fRealOnV86Active)
7310 pCtx->es.Attr.u = pVmcsInfo->RealMode.AttrES.u;
7311 }
7312 if (fWhat & CPUMCTX_EXTRN_FS)
7313 {
7314 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_FS);
7315 if (fRealOnV86Active)
7316 pCtx->fs.Attr.u = pVmcsInfo->RealMode.AttrFS.u;
7317 }
7318 if (fWhat & CPUMCTX_EXTRN_GS)
7319 {
7320 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_GS);
7321 if (fRealOnV86Active)
7322 pCtx->gs.Attr.u = pVmcsInfo->RealMode.AttrGS.u;
7323 }
7324 }
7325
7326 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
7327 {
7328 if (fWhat & CPUMCTX_EXTRN_LDTR)
7329 hmR0VmxImportGuestLdtr(pVCpu);
7330
7331 if (fWhat & CPUMCTX_EXTRN_GDTR)
7332 {
7333 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &HCRegVal); AssertRC(rc);
7334 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRC(rc);
7335 pCtx->gdtr.pGdt = HCRegVal;
7336 pCtx->gdtr.cbGdt = u32Val;
7337 }
7338
7339 /* Guest IDTR. */
7340 if (fWhat & CPUMCTX_EXTRN_IDTR)
7341 {
7342 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &HCRegVal); AssertRC(rc);
7343 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRC(rc);
7344 pCtx->idtr.pIdt = HCRegVal;
7345 pCtx->idtr.cbIdt = u32Val;
7346 }
7347
7348 /* Guest TR. */
7349 if (fWhat & CPUMCTX_EXTRN_TR)
7350 {
7351 /* Real-mode emulation using virtual-8086 mode has the fake TSS (pRealModeTSS) in TR,
7352 don't need to import that one. */
7353 if (!pVmcsInfo->RealMode.fRealOnV86Active)
7354 hmR0VmxImportGuestTr(pVCpu);
7355 }
7356 }
7357
7358 if (fWhat & CPUMCTX_EXTRN_DR7)
7359 {
7360 if (!pVCpu->hm.s.fUsingHyperDR7)
7361 {
7362 /* Upper 32-bits are always zero. See Intel spec. 2.7.3 "Loading and Storing Debug Registers". */
7363 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_DR7, &HCRegVal); AssertRC(rc);
7364 pCtx->dr[7] = HCRegVal;
7365 }
7366 }
7367
7368 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
7369 {
7370 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, &HCRegVal); AssertRC(rc);
7371 pCtx->SysEnter.eip = HCRegVal;
7372 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, &HCRegVal); AssertRC(rc);
7373 pCtx->SysEnter.esp = HCRegVal;
7374 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRC(rc);
7375 pCtx->SysEnter.cs = u32Val;
7376 }
7377
7378 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
7379 {
7380 if ( pVM->hm.s.fAllow64BitGuests
7381 && (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7382 pCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
7383 }
7384
7385 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
7386 {
7387 if ( pVM->hm.s.fAllow64BitGuests
7388 && (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7389 {
7390 pCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
7391 pCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
7392 pCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
7393 }
7394 }
7395
7396 if (fWhat & (CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS))
7397 {
7398 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
7399 uint32_t const cMsrs = pVmcsInfo->cExitMsrStore;
7400 Assert(pMsrs);
7401 Assert(cMsrs <= VMX_MISC_MAX_MSRS(pVM->hm.s.vmx.Msrs.u64Misc));
7402 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
7403 for (uint32_t i = 0; i < cMsrs; i++)
7404 {
7405 uint32_t const idMsr = pMsrs[i].u32Msr;
7406 switch (idMsr)
7407 {
7408 case MSR_K8_TSC_AUX: CPUMSetGuestTscAux(pVCpu, pMsrs[i].u64Value); break;
7409 case MSR_IA32_SPEC_CTRL: CPUMSetGuestSpecCtrl(pVCpu, pMsrs[i].u64Value); break;
7410 case MSR_K6_EFER: /* Can't be changed without causing a VM-exit */ break;
7411 default:
7412 {
7413 pCtx->fExtrn = 0;
7414 pVCpu->hm.s.u32HMError = pMsrs->u32Msr;
7415 ASMSetFlags(fEFlags);
7416 AssertMsgFailed(("Unexpected MSR in auto-load/store area. idMsr=%#RX32 cMsrs=%u\n", idMsr, cMsrs));
7417 return VERR_HM_UNEXPECTED_LD_ST_MSR;
7418 }
7419 }
7420 }
7421 }
7422
7423 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
7424 {
7425 if (fWhat & CPUMCTX_EXTRN_CR0)
7426 {
7427 RTHCUINTREG HCRegShadow;
7428 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &HCRegVal); AssertRC(rc);
7429 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &HCRegShadow); AssertRC(rc);
7430 HCRegVal = (HCRegVal & ~pVmcsInfo->u64Cr0Mask)
7431 | (HCRegShadow & pVmcsInfo->u64Cr0Mask);
7432#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7433 /*
7434 * Reapply the nested-guest's CR0 fixed bits that might have been altered while
7435 * exporting the nested-guest CR0 for executing using hardware-assisted VMX.
7436 */
7437 if (CPUMIsGuestInVmxNonRootMode(pCtx))
7438 {
7439 HCRegVal |= pCtx->hwvirt.vmx.Msrs.u64Cr0Fixed0;
7440 HCRegVal &= pCtx->hwvirt.vmx.Msrs.u64Cr0Fixed1;
7441 }
7442#endif
7443 VMMRZCallRing3Disable(pVCpu); /* May call into PGM which has Log statements. */
7444 CPUMSetGuestCR0(pVCpu, HCRegVal);
7445 VMMRZCallRing3Enable(pVCpu);
7446 }
7447
7448 if (fWhat & CPUMCTX_EXTRN_CR4)
7449 {
7450 RTHCUINTREG HCRegShadow;
7451 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &HCRegVal); AssertRC(rc);
7452 rc |= VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &HCRegShadow); AssertRC(rc);
7453 HCRegVal = (HCRegVal & ~pVmcsInfo->u64Cr4Mask)
7454 | (HCRegShadow & pVmcsInfo->u64Cr4Mask);
7455#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7456 /*
7457 * Reapply the nested-guest's CR4 fixed bits that might have been altered while
7458 * exporting the nested-guest CR4 for executing using hardware-assisted VMX.
7459 */
7460 if (CPUMIsGuestInVmxNonRootMode(pCtx))
7461 {
7462 HCRegVal |= pCtx->hwvirt.vmx.Msrs.u64Cr4Fixed0;
7463 HCRegVal &= pCtx->hwvirt.vmx.Msrs.u64Cr4Fixed1;
7464 }
7465#endif
7466 pCtx->cr4 = HCRegVal;
7467 }
7468
7469 if (fWhat & CPUMCTX_EXTRN_CR3)
7470 {
7471 /* CR0.PG bit changes are always intercepted, so it's up to date. */
7472 if ( pVM->hm.s.vmx.fUnrestrictedGuest
7473 || ( pVM->hm.s.fNestedPaging
7474 && CPUMIsGuestPagingEnabledEx(pCtx)))
7475 {
7476 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR3, &HCRegVal); AssertRC(rc);
7477 if (pCtx->cr3 != HCRegVal)
7478 {
7479 pCtx->cr3 = HCRegVal;
7480 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
7481 }
7482
7483 /* If the guest is in PAE mode, sync back the PDPE's into the guest state.
7484 Note: CR4.PAE, CR0.PG, EFER MSR changes are always intercepted, so they're up to date. */
7485 if (CPUMIsGuestInPAEModeEx(pCtx))
7486 {
7487 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
7488 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
7489 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
7490 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
7491 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
7492 }
7493 }
7494 }
7495 }
7496
7497#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7498 if (fWhat & CPUMCTX_EXTRN_HWVIRT)
7499 {
7500 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
7501 && !CPUMIsGuestInVmxNonRootMode(pCtx))
7502 {
7503 Assert(CPUMIsGuestInVmxRootMode(pCtx));
7504 rc = hmR0VmxCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
7505 if (RT_SUCCESS(rc))
7506 { /* likely */ }
7507 else
7508 break;
7509 }
7510 }
7511#endif
7512 } while (0);
7513
7514 if (RT_SUCCESS(rc))
7515 {
7516 /* Update fExtrn. */
7517 pCtx->fExtrn &= ~fWhat;
7518
7519 /* If everything has been imported, clear the HM keeper bit. */
7520 if (!(pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL))
7521 {
7522 pCtx->fExtrn &= ~CPUMCTX_EXTRN_KEEPER_HM;
7523 Assert(!pCtx->fExtrn);
7524 }
7525 }
7526 }
7527 else
7528 AssertMsg(!pCtx->fExtrn || (pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL), ("%#RX64\n", pCtx->fExtrn));
7529
7530 /*
7531 * Restore interrupts.
7532 */
7533 ASMSetFlags(fEFlags);
7534
7535 STAM_PROFILE_ADV_STOP(& pVCpu->hm.s.StatImportGuestState, x);
7536
7537 if (RT_SUCCESS(rc))
7538 { /* likely */ }
7539 else
7540 return rc;
7541
7542 /*
7543 * Honor any pending CR3 updates.
7544 *
7545 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> hmR0VmxCallRing3Callback()
7546 * -> VMMRZCallRing3Disable() -> hmR0VmxImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
7547 * -> continue with VM-exit handling -> hmR0VmxImportGuestState() and here we are.
7548 *
7549 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
7550 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
7551 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
7552 * -NOT- check if CPUMCTX_EXTRN_CR3 is set!
7553 *
7554 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
7555 */
7556 if (VMMRZCallRing3IsEnabled(pVCpu))
7557 {
7558 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
7559 {
7560 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & CPUMCTX_EXTRN_CR3));
7561 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
7562 }
7563
7564 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
7565 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
7566
7567 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
7568 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
7569 }
7570
7571 return VINF_SUCCESS;
7572}
7573
7574
7575/**
7576 * Saves the guest state from the VMCS into the guest-CPU context.
7577 *
7578 * @returns VBox status code.
7579 * @param pVCpu The cross context virtual CPU structure.
7580 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7581 */
7582VMMR0DECL(int) VMXR0ImportStateOnDemand(PVMCPU pVCpu, uint64_t fWhat)
7583{
7584 AssertPtr(pVCpu);
7585 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7586 return hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fWhat);
7587}
7588
7589
7590/**
7591 * Check per-VM and per-VCPU force flag actions that require us to go back to
7592 * ring-3 for one reason or another.
7593 *
7594 * @returns Strict VBox status code (i.e. informational status codes too)
7595 * @retval VINF_SUCCESS if we don't have any actions that require going back to
7596 * ring-3.
7597 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
7598 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
7599 * interrupts)
7600 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
7601 * all EMTs to be in ring-3.
7602 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
7603 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
7604 * to the EM loop.
7605 *
7606 * @param pVCpu The cross context virtual CPU structure.
7607 * @param fStepping Whether we are single-stepping the guest using the
7608 * hypervisor debugger.
7609 *
7610 * @remarks This might cause nested-guest VM-exits, caller must check if the guest
7611 * is no longer in VMX non-root mode.
7612 */
7613static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVMCPU pVCpu, bool fStepping)
7614{
7615 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7616
7617 /*
7618 * Update pending interrupts into the APIC's IRR.
7619 */
7620 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
7621 APICUpdatePendingInterrupts(pVCpu);
7622
7623 /*
7624 * Anything pending? Should be more likely than not if we're doing a good job.
7625 */
7626 PVM pVM = pVCpu->CTX_SUFF(pVM);
7627 if ( !fStepping
7628 ? !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_MASK)
7629 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
7630 : !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
7631 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
7632 return VINF_SUCCESS;
7633
7634 /* Pending PGM C3 sync. */
7635 if (VMCPU_FF_IS_ANY_SET(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
7636 {
7637 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7638 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & (CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4)));
7639 VBOXSTRICTRC rcStrict = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4,
7640 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
7641 if (rcStrict != VINF_SUCCESS)
7642 {
7643 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
7644 Log4Func(("PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
7645 return rcStrict;
7646 }
7647 }
7648
7649 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
7650 if ( VM_FF_IS_ANY_SET(pVM, VM_FF_HM_TO_R3_MASK)
7651 || VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
7652 {
7653 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
7654 int rc = RT_LIKELY(!VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_RAW_TO_R3 : VINF_EM_NO_MEMORY;
7655 Log4Func(("HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc));
7656 return rc;
7657 }
7658
7659 /* Pending VM request packets, such as hardware interrupts. */
7660 if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
7661 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
7662 {
7663 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchVmReq);
7664 Log4Func(("Pending VM request forcing us back to ring-3\n"));
7665 return VINF_EM_PENDING_REQUEST;
7666 }
7667
7668 /* Pending PGM pool flushes. */
7669 if (VM_FF_IS_SET(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
7670 {
7671 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPgmPoolFlush);
7672 Log4Func(("PGM pool flush pending forcing us back to ring-3\n"));
7673 return VINF_PGM_POOL_FLUSH_PENDING;
7674 }
7675
7676 /* Pending DMA requests. */
7677 if (VM_FF_IS_SET(pVM, VM_FF_PDM_DMA))
7678 {
7679 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchDma);
7680 Log4Func(("Pending DMA request forcing us back to ring-3\n"));
7681 return VINF_EM_RAW_TO_R3;
7682 }
7683
7684#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7685 /* Pending nested-guest APIC-write (has highest priority among nested-guest FFs). */
7686 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
7687 {
7688 Log4Func(("Pending nested-guest APIC-write\n"));
7689 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitApicWrite(pVCpu);
7690 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
7691 return rcStrict;
7692 }
7693 /** @todo VMCPU_FF_VMX_MTF, VMCPU_FF_VMX_PREEMPT_TIMER */
7694#endif
7695
7696 return VINF_SUCCESS;
7697}
7698
7699
7700/**
7701 * Converts any TRPM trap into a pending HM event. This is typically used when
7702 * entering from ring-3 (not longjmp returns).
7703 *
7704 * @param pVCpu The cross context virtual CPU structure.
7705 */
7706static void hmR0VmxTrpmTrapToPendingEvent(PVMCPU pVCpu)
7707{
7708 Assert(TRPMHasTrap(pVCpu));
7709 Assert(!pVCpu->hm.s.Event.fPending);
7710
7711 uint8_t uVector;
7712 TRPMEVENT enmTrpmEvent;
7713 RTGCUINT uErrCode;
7714 RTGCUINTPTR GCPtrFaultAddress;
7715 uint8_t cbInstr;
7716
7717 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr);
7718 AssertRC(rc);
7719
7720 uint32_t u32IntInfo;
7721 u32IntInfo = uVector | VMX_IDT_VECTORING_INFO_VALID;
7722 u32IntInfo |= HMTrpmEventTypeToVmxEventType(uVector, enmTrpmEvent);
7723
7724 rc = TRPMResetTrap(pVCpu);
7725 AssertRC(rc);
7726 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
7727 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
7728
7729 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
7730}
7731
7732
7733/**
7734 * Converts the pending HM event into a TRPM trap.
7735 *
7736 * @param pVCpu The cross context virtual CPU structure.
7737 */
7738static void hmR0VmxPendingEventToTrpmTrap(PVMCPU pVCpu)
7739{
7740 Assert(pVCpu->hm.s.Event.fPending);
7741
7742 /* If a trap was already pending, we did something wrong! */
7743 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
7744
7745 uint32_t const u32IntInfo = pVCpu->hm.s.Event.u64IntInfo;
7746 uint32_t const uVector = VMX_IDT_VECTORING_INFO_VECTOR(u32IntInfo);
7747 TRPMEVENT const enmTrapType = HMVmxEventTypeToTrpmEventType(u32IntInfo);
7748
7749 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
7750
7751 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
7752 AssertRC(rc);
7753
7754 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
7755 TRPMSetErrorCode(pVCpu, pVCpu->hm.s.Event.u32ErrCode);
7756
7757 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(u32IntInfo))
7758 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
7759 else if (VMX_IDT_VECTORING_INFO_TYPE(u32IntInfo) == VMX_IDT_VECTORING_INFO_TYPE_SW_INT)
7760 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
7761
7762 /* We're now done converting the pending event. */
7763 pVCpu->hm.s.Event.fPending = false;
7764}
7765
7766
7767/**
7768 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
7769 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
7770 *
7771 * @param pVCpu The cross context virtual CPU structure.
7772 * @param pVmcsInfo The VMCS info. object.
7773 */
7774static void hmR0VmxSetIntWindowExitVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
7775{
7776 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7777 {
7778 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
7779 {
7780 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_INT_WINDOW_EXIT;
7781 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7782 AssertRC(rc);
7783 }
7784 } /* else we will deliver interrupts whenever the guest Vm-exits next and is in a state to receive the interrupt. */
7785}
7786
7787
7788/**
7789 * Clears the interrupt-window exiting control in the VMCS.
7790 *
7791 * @param pVmcsInfo The VMCS info. object.
7792 */
7793DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
7794{
7795 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7796 {
7797 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_INT_WINDOW_EXIT;
7798 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7799 AssertRC(rc);
7800 }
7801}
7802
7803
7804/**
7805 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
7806 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
7807 *
7808 * @param pVCpu The cross context virtual CPU structure.
7809 * @param pVmcsInfo The VMCS info. object.
7810 */
7811static void hmR0VmxSetNmiWindowExitVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
7812{
7813 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7814 {
7815 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
7816 {
7817 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_NMI_WINDOW_EXIT;
7818 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7819 AssertRC(rc);
7820 Log4Func(("Setup NMI-window exiting\n"));
7821 }
7822 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
7823}
7824
7825
7826/**
7827 * Clears the NMI-window exiting control in the VMCS.
7828 *
7829 * @param pVmcsInfo The VMCS info. object.
7830 */
7831DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
7832{
7833 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7834 {
7835 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_NMI_WINDOW_EXIT;
7836 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7837 AssertRC(rc);
7838 }
7839}
7840
7841
7842/**
7843 * Does the necessary state syncing before returning to ring-3 for any reason
7844 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
7845 *
7846 * @returns VBox status code.
7847 * @param pVCpu The cross context virtual CPU structure.
7848 * @param fImportState Whether to import the guest state from the VMCS back
7849 * to the guest-CPU context.
7850 *
7851 * @remarks No-long-jmp zone!!!
7852 */
7853static int hmR0VmxLeave(PVMCPU pVCpu, bool fImportState)
7854{
7855 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7856 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7857
7858 RTCPUID const idCpu = RTMpCpuId();
7859 Log4Func(("HostCpuId=%u\n", idCpu));
7860
7861 /*
7862 * !!! IMPORTANT !!!
7863 * If you modify code here, check whether hmR0VmxCallRing3Callback() needs to be updated too.
7864 */
7865
7866 /* Save the guest state if necessary. */
7867 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7868 if (fImportState)
7869 {
7870 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
7871 AssertRCReturn(rc, rc);
7872 }
7873
7874 /* Restore host FPU state if necessary. We will resync on next R0 reentry. */
7875 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
7876 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
7877
7878 /* Restore host debug registers if necessary. We will resync on next R0 reentry. */
7879#ifdef VBOX_STRICT
7880 if (CPUMIsHyperDebugStateActive(pVCpu))
7881 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT);
7882#endif
7883 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
7884 Assert(!CPUMIsGuestDebugStateActive(pVCpu) && !CPUMIsGuestDebugStateActivePending(pVCpu));
7885 Assert(!CPUMIsHyperDebugStateActive(pVCpu) && !CPUMIsHyperDebugStateActivePending(pVCpu));
7886
7887 /* Restore host-state bits that VT-x only restores partially. */
7888 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7889 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7890 {
7891 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags, idCpu));
7892 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7893 }
7894 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7895
7896 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7897 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
7898 {
7899 /* We shouldn't restore the host MSRs without saving the guest MSRs first. */
7900 if (!fImportState)
7901 {
7902 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS);
7903 AssertRCReturn(rc, rc);
7904 }
7905 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7906 Assert(!pVCpu->hm.s.vmx.fLazyMsrs);
7907 }
7908 else
7909 pVCpu->hm.s.vmx.fLazyMsrs = 0;
7910
7911 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7912 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
7913
7914 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
7915 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatImportGuestState);
7916 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExportGuestState);
7917 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatPreExit);
7918 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitHandling);
7919 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
7920 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
7921 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
7922 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitVmentry);
7923 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7924
7925 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7926
7927 /** @todo This partially defeats the purpose of having preemption hooks.
7928 * The problem is, deregistering the hooks should be moved to a place that
7929 * lasts until the EMT is about to be destroyed not everytime while leaving HM
7930 * context.
7931 */
7932 int rc = hmR0VmxClearVmcs(pVmcsInfo);
7933 AssertRCReturn(rc, rc);
7934
7935#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7936 /*
7937 * A valid shadow VMCS is made active as part of VM-entry. It is necessary to
7938 * clear a shadow VMCS before allowing that VMCS to become active on another
7939 * logical processor. We may or may not be importing guest state which clears
7940 * it, so cover for it here.
7941 *
7942 * See Intel spec. 24.11.1 "Software Use of Virtual-Machine Control Structures".
7943 */
7944 if ( pVmcsInfo->pvShadowVmcs
7945 && pVmcsInfo->fShadowVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
7946 {
7947 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
7948 AssertRCReturn(rc, rc);
7949 }
7950
7951 /*
7952 * Flag that we need to re-import the host state if we switch to this VMCS before
7953 * executing guest or nested-guest code.
7954 */
7955 pVmcsInfo->idHostCpu = NIL_RTCPUID;
7956#endif
7957
7958 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
7959 NOREF(idCpu);
7960 return VINF_SUCCESS;
7961}
7962
7963
7964/**
7965 * Leaves the VT-x session.
7966 *
7967 * @returns VBox status code.
7968 * @param pVCpu The cross context virtual CPU structure.
7969 *
7970 * @remarks No-long-jmp zone!!!
7971 */
7972static int hmR0VmxLeaveSession(PVMCPU pVCpu)
7973{
7974 HM_DISABLE_PREEMPT(pVCpu);
7975 HMVMX_ASSERT_CPU_SAFE(pVCpu);
7976 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7977 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7978
7979 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
7980 and done this from the VMXR0ThreadCtxCallback(). */
7981 if (!pVCpu->hm.s.fLeaveDone)
7982 {
7983 int rc2 = hmR0VmxLeave(pVCpu, true /* fImportState */);
7984 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
7985 pVCpu->hm.s.fLeaveDone = true;
7986 }
7987 Assert(!pVCpu->cpum.GstCtx.fExtrn);
7988
7989 /*
7990 * !!! IMPORTANT !!!
7991 * If you modify code here, make sure to check whether hmR0VmxCallRing3Callback() needs to be updated too.
7992 */
7993
7994 /* Deregister hook now that we've left HM context before re-enabling preemption. */
7995 /** @todo Deregistering here means we need to VMCLEAR always
7996 * (longjmp/exit-to-r3) in VT-x which is not efficient, eliminate need
7997 * for calling VMMR0ThreadCtxHookDisable here! */
7998 VMMR0ThreadCtxHookDisable(pVCpu);
7999
8000 /* Leave HM context. This takes care of local init (term). */
8001 int rc = HMR0LeaveCpu(pVCpu);
8002
8003 HM_RESTORE_PREEMPT();
8004 return rc;
8005}
8006
8007
8008/**
8009 * Does the necessary state syncing before doing a longjmp to ring-3.
8010 *
8011 * @returns VBox status code.
8012 * @param pVCpu The cross context virtual CPU structure.
8013 *
8014 * @remarks No-long-jmp zone!!!
8015 */
8016DECLINLINE(int) hmR0VmxLongJmpToRing3(PVMCPU pVCpu)
8017{
8018 return hmR0VmxLeaveSession(pVCpu);
8019}
8020
8021
8022/**
8023 * Take necessary actions before going back to ring-3.
8024 *
8025 * An action requires us to go back to ring-3. This function does the necessary
8026 * steps before we can safely return to ring-3. This is not the same as longjmps
8027 * to ring-3, this is voluntary and prepares the guest so it may continue
8028 * executing outside HM (recompiler/IEM).
8029 *
8030 * @returns VBox status code.
8031 * @param pVCpu The cross context virtual CPU structure.
8032 * @param rcExit The reason for exiting to ring-3. Can be
8033 * VINF_VMM_UNKNOWN_RING3_CALL.
8034 */
8035static int hmR0VmxExitToRing3(PVMCPU pVCpu, VBOXSTRICTRC rcExit)
8036{
8037 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8038
8039 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8040 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
8041 {
8042 VMXGetCurrentVmcs(&pVCpu->hm.s.vmx.LastError.HCPhysCurrentVmcs);
8043 pVCpu->hm.s.vmx.LastError.u32VmcsRev = *(uint32_t *)pVmcsInfo->pvVmcs;
8044 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
8045 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
8046 }
8047
8048 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
8049 VMMRZCallRing3Disable(pVCpu);
8050 Log4Func(("rcExit=%d\n", VBOXSTRICTRC_VAL(rcExit)));
8051
8052 /*
8053 * Convert any pending HM events back to TRPM due to premature exits to ring-3.
8054 * We need to do this only on returns to ring-3 and not for longjmps to ring3.
8055 *
8056 * This is because execution may continue from ring-3 and we would need to inject
8057 * the event from there (hence place it back in TRPM).
8058 */
8059 if (pVCpu->hm.s.Event.fPending)
8060 {
8061 hmR0VmxPendingEventToTrpmTrap(pVCpu);
8062 Assert(!pVCpu->hm.s.Event.fPending);
8063
8064 /* Clear the events from the VMCS. */
8065 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0);
8066 AssertRC(rc);
8067 }
8068#ifdef VBOX_STRICT
8069 else
8070 {
8071 /*
8072 * Ensure we don't accidentally clear a pending HM event without clearing the VMCS.
8073 * This can be pretty hard to debug otherwise, interrupts might get injected twice
8074 * occasionally, see @bugref{9180#c42}.
8075 *
8076 * However, if the VM-entry failed, any VM entry-interruption info. field would
8077 * be left unmodified as the event would not have been injected to the guest. In
8078 * such cases, don't assert, we're not going to continue guest execution anyway.
8079 */
8080 uint32_t uExitReason;
8081 uint32_t uEntryIntInfo;
8082 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8083 rc |= VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &uEntryIntInfo);
8084 AssertRC(rc);
8085 Assert(VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason) || !VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo));
8086 }
8087#endif
8088
8089 /*
8090 * Clear the interrupt-window and NMI-window VMCS controls as we could have got
8091 * a VM-exit with higher priority than interrupt-window or NMI-window VM-exits
8092 * (e.g. TPR below threshold).
8093 */
8094 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8095 {
8096 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
8097 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
8098 }
8099
8100 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
8101 and if we're injecting an event we should have a TRPM trap pending. */
8102 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8103#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a triple fault in progress. */
8104 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8105#endif
8106
8107 /* Save guest state and restore host state bits. */
8108 int rc = hmR0VmxLeaveSession(pVCpu);
8109 AssertRCReturn(rc, rc);
8110 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8111
8112 /* Thread-context hooks are unregistered at this point!!! */
8113
8114 /* Sync recompiler state. */
8115 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
8116 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
8117 | CPUM_CHANGED_LDTR
8118 | CPUM_CHANGED_GDTR
8119 | CPUM_CHANGED_IDTR
8120 | CPUM_CHANGED_TR
8121 | CPUM_CHANGED_HIDDEN_SEL_REGS);
8122 if ( pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging
8123 && CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx))
8124 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
8125
8126 Assert(!pVCpu->hm.s.fClearTrapFlag);
8127
8128 /* Update the exit-to-ring 3 reason. */
8129 pVCpu->hm.s.rcLastExitToR3 = VBOXSTRICTRC_VAL(rcExit);
8130
8131 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
8132 if ( rcExit != VINF_EM_RAW_INTERRUPT
8133 || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8134 {
8135 Assert(!(pVCpu->cpum.GstCtx.fExtrn & HMVMX_CPUMCTX_EXTRN_ALL));
8136 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
8137 }
8138
8139 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
8140
8141 /* We do -not- want any longjmp notifications after this! We must return to ring-3 ASAP. */
8142 VMMRZCallRing3RemoveNotification(pVCpu);
8143 VMMRZCallRing3Enable(pVCpu);
8144
8145 return rc;
8146}
8147
8148
8149/**
8150 * VMMRZCallRing3() callback wrapper which saves the guest state before we
8151 * longjump to ring-3 and possibly get preempted.
8152 *
8153 * @returns VBox status code.
8154 * @param pVCpu The cross context virtual CPU structure.
8155 * @param enmOperation The operation causing the ring-3 longjump.
8156 * @param pvUser User argument, currently unused, NULL.
8157 */
8158static DECLCALLBACK(int) hmR0VmxCallRing3Callback(PVMCPU pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
8159{
8160 RT_NOREF(pvUser);
8161 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
8162 {
8163 /*
8164 * !!! IMPORTANT !!!
8165 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
8166 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
8167 */
8168 VMMRZCallRing3RemoveNotification(pVCpu);
8169 VMMRZCallRing3Disable(pVCpu);
8170 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
8171 RTThreadPreemptDisable(&PreemptState);
8172
8173 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8174 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8175 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8176 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8177
8178 /* Restore host-state bits that VT-x only restores partially. */
8179 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
8180 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
8181 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
8182 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
8183
8184 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8185 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8186 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8187
8188 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8189 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
8190 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8191
8192 /* Clear the current VMCS data back to memory (shadow VMCS if any would have been
8193 cleared as part of importing the guest state above. */
8194 hmR0VmxClearVmcs(pVmcsInfo);
8195
8196 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
8197 VMMR0ThreadCtxHookDisable(pVCpu);
8198 HMR0LeaveCpu(pVCpu);
8199 RTThreadPreemptRestore(&PreemptState);
8200 return VINF_SUCCESS;
8201 }
8202
8203 Assert(pVCpu);
8204 Assert(pvUser);
8205 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8206 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8207
8208 VMMRZCallRing3Disable(pVCpu);
8209 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8210
8211 Log4Func((" -> hmR0VmxLongJmpToRing3 enmOperation=%d\n", enmOperation));
8212
8213 int rc = hmR0VmxLongJmpToRing3(pVCpu);
8214 AssertRCReturn(rc, rc);
8215
8216 VMMRZCallRing3Enable(pVCpu);
8217 return VINF_SUCCESS;
8218}
8219
8220
8221/**
8222 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
8223 * stack.
8224 *
8225 * @returns Strict VBox status code (i.e. informational status codes too).
8226 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
8227 * @param pVCpu The cross context virtual CPU structure.
8228 * @param uValue The value to push to the guest stack.
8229 */
8230static VBOXSTRICTRC hmR0VmxRealModeGuestStackPush(PVMCPU pVCpu, uint16_t uValue)
8231{
8232 /*
8233 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
8234 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
8235 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
8236 */
8237 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8238 if (pCtx->sp == 1)
8239 return VINF_EM_RESET;
8240 pCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
8241 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), pCtx->ss.u64Base + pCtx->sp, &uValue, sizeof(uint16_t));
8242 AssertRC(rc);
8243 return rc;
8244}
8245
8246
8247/**
8248 * Injects an event into the guest upon VM-entry by updating the relevant fields
8249 * in the VM-entry area in the VMCS.
8250 *
8251 * @returns Strict VBox status code (i.e. informational status codes too).
8252 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
8253 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
8254 *
8255 * @param pVCpu The cross context virtual CPU structure.
8256 * @param pVmxTransient The VMX-transient structure.
8257 * @param pEvent The event being injected.
8258 * @param pfIntrState Pointer to the VT-x guest-interruptibility-state. This
8259 * will be updated if necessary. This cannot not be NULL.
8260 * @param fStepping Whether we're single-stepping guest execution and should
8261 * return VINF_EM_DBG_STEPPED if the event is injected
8262 * directly (registers modified by us, not by hardware on
8263 * VM-entry).
8264 */
8265static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PCHMEVENT pEvent, bool fStepping,
8266 uint32_t *pfIntrState)
8267{
8268 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
8269 AssertMsg(!RT_HI_U32(pEvent->u64IntInfo), ("%#RX64\n", pEvent->u64IntInfo));
8270 Assert(pfIntrState);
8271
8272 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8273 uint32_t u32IntInfo = pEvent->u64IntInfo;
8274 uint32_t const u32ErrCode = pEvent->u32ErrCode;
8275 uint32_t const cbInstr = pEvent->cbInstr;
8276 RTGCUINTPTR const GCPtrFault = pEvent->GCPtrFaultAddress;
8277 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(u32IntInfo);
8278 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(u32IntInfo);
8279
8280#ifdef VBOX_STRICT
8281 /*
8282 * Validate the error-code-valid bit for hardware exceptions.
8283 * No error codes for exceptions in real-mode.
8284 *
8285 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8286 */
8287 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8288 && !CPUMIsGuestInRealModeEx(pCtx))
8289 {
8290 switch (uVector)
8291 {
8292 case X86_XCPT_PF:
8293 case X86_XCPT_DF:
8294 case X86_XCPT_TS:
8295 case X86_XCPT_NP:
8296 case X86_XCPT_SS:
8297 case X86_XCPT_GP:
8298 case X86_XCPT_AC:
8299 AssertMsg(VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo),
8300 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
8301 RT_FALL_THRU();
8302 default:
8303 break;
8304 }
8305 }
8306
8307 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
8308 Assert( uIntType != VMX_EXIT_INT_INFO_TYPE_NMI
8309 || !(*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
8310#endif
8311
8312 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
8313
8314 /*
8315 * Hardware interrupts & exceptions cannot be delivered through the software interrupt
8316 * redirection bitmap to the real mode task in virtual-8086 mode. We must jump to the
8317 * interrupt handler in the (real-mode) guest.
8318 *
8319 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode".
8320 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
8321 */
8322 if (CPUMIsGuestInRealModeEx(pCtx)) /* CR0.PE bit changes are always intercepted, so it's up to date. */
8323 {
8324 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest)
8325 {
8326 /*
8327 * For CPUs with unrestricted guest execution enabled and with the guest
8328 * in real-mode, we must not set the deliver-error-code bit.
8329 *
8330 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8331 */
8332 u32IntInfo &= ~VMX_ENTRY_INT_INFO_ERROR_CODE_VALID;
8333 }
8334 else
8335 {
8336 PVM pVM = pVCpu->CTX_SUFF(pVM);
8337 Assert(PDMVmmDevHeapIsEnabled(pVM));
8338 Assert(pVM->hm.s.vmx.pRealModeTSS);
8339 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
8340
8341 /* We require RIP, RSP, RFLAGS, CS, IDTR, import them. */
8342 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8343 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TABLE_MASK
8344 | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS);
8345 AssertRCReturn(rc2, rc2);
8346
8347 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8348 size_t const cbIdtEntry = sizeof(X86IDTR16);
8349 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pCtx->idtr.cbIdt)
8350 {
8351 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8352 if (uVector == X86_XCPT_DF)
8353 return VINF_EM_RESET;
8354
8355 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault.
8356 No error codes for exceptions in real-mode. */
8357 if (uVector == X86_XCPT_GP)
8358 {
8359 uint32_t const uXcptDfInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
8360 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8361 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8362 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8363 HMEVENT EventXcptDf;
8364 RT_ZERO(EventXcptDf);
8365 EventXcptDf.u64IntInfo = uXcptDfInfo;
8366 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptDf, fStepping, pfIntrState);
8367 }
8368
8369 /*
8370 * If we're injecting an event with no valid IDT entry, inject a #GP.
8371 * No error codes for exceptions in real-mode.
8372 *
8373 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8374 */
8375 uint32_t const uXcptGpInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
8376 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8377 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8378 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8379 HMEVENT EventXcptGp;
8380 RT_ZERO(EventXcptGp);
8381 EventXcptGp.u64IntInfo = uXcptGpInfo;
8382 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptGp, fStepping, pfIntrState);
8383 }
8384
8385 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8386 uint16_t uGuestIp = pCtx->ip;
8387 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT)
8388 {
8389 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8390 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8391 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8392 }
8393 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_INT)
8394 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8395
8396 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8397 X86IDTR16 IdtEntry;
8398 RTGCPHYS const GCPhysIdtEntry = (RTGCPHYS)pCtx->idtr.pIdt + uVector * cbIdtEntry;
8399 rc2 = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8400 AssertRCReturn(rc2, rc2);
8401
8402 /* Construct the stack frame for the interrupt/exception handler. */
8403 VBOXSTRICTRC rcStrict;
8404 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->eflags.u32);
8405 if (rcStrict == VINF_SUCCESS)
8406 {
8407 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->cs.Sel);
8408 if (rcStrict == VINF_SUCCESS)
8409 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, uGuestIp);
8410 }
8411
8412 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8413 if (rcStrict == VINF_SUCCESS)
8414 {
8415 pCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8416 pCtx->rip = IdtEntry.offSel;
8417 pCtx->cs.Sel = IdtEntry.uSel;
8418 pCtx->cs.ValidSel = IdtEntry.uSel;
8419 pCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8420 if ( uIntType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
8421 && uVector == X86_XCPT_PF)
8422 pCtx->cr2 = GCPtrFault;
8423
8424 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CS | HM_CHANGED_GUEST_CR2
8425 | HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
8426 | HM_CHANGED_GUEST_RSP);
8427
8428 /*
8429 * If we delivered a hardware exception (other than an NMI) and if there was
8430 * block-by-STI in effect, we should clear it.
8431 */
8432 if (*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
8433 {
8434 Assert( uIntType != VMX_ENTRY_INT_INFO_TYPE_NMI
8435 && uIntType != VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
8436 Log4Func(("Clearing inhibition due to STI\n"));
8437 *pfIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
8438 }
8439
8440 Log4(("Injected real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8441 u32IntInfo, u32ErrCode, cbInstr, pCtx->eflags.u, pCtx->cs.Sel, pCtx->eip));
8442
8443 /*
8444 * The event has been truly dispatched to the guest. Mark it as no longer pending so
8445 * we don't attempt to undo it if we are returning to ring-3 before executing guest code.
8446 */
8447 pVCpu->hm.s.Event.fPending = false;
8448
8449 /*
8450 * If we eventually support nested-guest execution without unrestricted guest execution,
8451 * we should set fInterceptEvents here.
8452 */
8453 Assert(!pVmxTransient->fIsNestedGuest);
8454
8455 /* If we're stepping and we've changed cs:rip above, bail out of the VMX R0 execution loop. */
8456 if (fStepping)
8457 rcStrict = VINF_EM_DBG_STEPPED;
8458 }
8459 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8460 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8461 return rcStrict;
8462 }
8463 }
8464
8465 /*
8466 * Validate.
8467 */
8468 Assert(VMX_ENTRY_INT_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
8469 Assert(!(u32IntInfo & VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK)); /* Bits 30:12 MBZ. */
8470
8471 /*
8472 * Inject the event into the VMCS.
8473 */
8474 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8475 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8476 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8477 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8478 AssertRC(rc);
8479
8480 /*
8481 * Update guest CR2 if this is a page-fault.
8482 */
8483 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
8484 pCtx->cr2 = GCPtrFault;
8485
8486 Log4(("Injecting u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x CR2=%#RX64\n", u32IntInfo, u32ErrCode, cbInstr, pCtx->cr2));
8487 return VINF_SUCCESS;
8488}
8489
8490
8491/**
8492 * Evaluates the event to be delivered to the guest and sets it as the pending
8493 * event.
8494 *
8495 * @returns Strict VBox status code (i.e. informational status codes too).
8496 * @param pVCpu The cross context virtual CPU structure.
8497 * @param pVmxTransient The VMX-transient structure.
8498 * @param pfIntrState Where to store the VT-x guest-interruptibility state.
8499 */
8500static VBOXSTRICTRC hmR0VmxEvaluatePendingEvent(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t *pfIntrState)
8501{
8502 Assert(pfIntrState);
8503 Assert(!TRPMHasTrap(pVCpu));
8504
8505 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8506 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8507 bool const fIsNestedGuest = pVmxTransient->fIsNestedGuest;
8508
8509 /*
8510 * Get the current interruptibility-state of the guest or nested-guest and
8511 * then figure out what needs to be injected.
8512 */
8513 uint32_t const fIntrState = hmR0VmxGetGuestIntrState(pVCpu, pVmxTransient);
8514 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
8515 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
8516 bool const fBlockNmi = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
8517
8518 /* We don't support block-by-SMI yet.*/
8519 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI));
8520
8521 /* Block-by-STI must not be set when interrupts are disabled. */
8522 if (fBlockSti)
8523 {
8524 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
8525 Assert(pCtx->eflags.Bits.u1IF);
8526 }
8527
8528 /* Update interruptibility state to the caller. */
8529 *pfIntrState = fIntrState;
8530
8531 /*
8532 * Toggling of interrupt force-flags here is safe since we update TRPM on
8533 * premature exits to ring-3 before executing guest code, see hmR0VmxExitToRing3().
8534 * We must NOT restore these force-flags.
8535 */
8536
8537 /** @todo SMI. SMIs take priority over NMIs. */
8538
8539 /*
8540 * Check if an NMI is pending and if the guest or nested-guest can receive them.
8541 * NMIs take priority over external interrupts.
8542 */
8543 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
8544 {
8545 /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
8546 if ( !pVCpu->hm.s.Event.fPending
8547 && !fBlockNmi
8548 && !fBlockSti
8549 && !fBlockMovSS)
8550 {
8551#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8552 if ( fIsNestedGuest
8553 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_NMI_EXIT))
8554 return IEMExecVmxVmexitXcptNmi(pVCpu);
8555#endif
8556 hmR0VmxSetPendingXcptNmi(pVCpu);
8557 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
8558 Log4Func(("Pending NMI\n"));
8559 }
8560 else if (!fIsNestedGuest)
8561 hmR0VmxSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
8562 /* else: for nested-guests, NMI-window exiting will be picked up when merging VMCS controls. */
8563 }
8564 /*
8565 * Check if an external interrupt (PIC/APIC) is pending and if the guest or nested-guest
8566 * can receive them. Once PDMGetInterrupt() returns a valid interrupt we -must- deliver
8567 * the interrupt. We can no longer re-request it from the APIC.
8568 */
8569 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
8570 && !pVCpu->hm.s.fSingleInstruction)
8571 {
8572 Assert(!DBGFIsStepping(pVCpu));
8573 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
8574 AssertRCReturn(rc, rc);
8575
8576 bool const fBlockInt = !(pCtx->eflags.u32 & X86_EFL_IF);
8577 if ( !pVCpu->hm.s.Event.fPending
8578 && !fBlockInt
8579 && !fBlockSti
8580 && !fBlockMovSS)
8581 {
8582#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8583 if ( fIsNestedGuest
8584 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
8585 && !CPUMIsGuestVmxExitCtlsSet(pVCpu, pCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
8586 {
8587 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
8588 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8589 return rcStrict;
8590 }
8591#endif
8592 uint8_t u8Interrupt;
8593 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
8594 if (RT_SUCCESS(rc))
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, u8Interrupt, false /* fIntPending */);
8602 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8603 return rcStrict;
8604 }
8605#endif
8606 hmR0VmxSetPendingExtInt(pVCpu, u8Interrupt);
8607 Log4Func(("Pending external interrupt vector %#x\n", u8Interrupt));
8608 }
8609 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
8610 {
8611 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
8612
8613 if ( !fIsNestedGuest
8614 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
8615 hmR0VmxApicSetTprThreshold(pVmcsInfo, u8Interrupt >> 4);
8616 /* else: for nested-guests, TPR threshold is picked up while merging VMCS controls. */
8617
8618 /*
8619 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
8620 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
8621 * need to re-set this force-flag here.
8622 */
8623 }
8624 else
8625 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
8626 }
8627 else if (!fIsNestedGuest)
8628 hmR0VmxSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
8629 /* else: for nested-guests, interrupt-window exiting will be picked up when merging VMCS controls. */
8630 }
8631
8632 return VINF_SUCCESS;
8633}
8634
8635
8636/**
8637 * Injects any pending events into the guest if the guest is in a state to
8638 * receive them.
8639 *
8640 * @returns Strict VBox status code (i.e. informational status codes too).
8641 * @param pVCpu The cross context virtual CPU structure.
8642 * @param pVmxTransient The VMX-transient structure.
8643 * @param fIntrState The VT-x guest-interruptibility state.
8644 * @param fStepping Whether we are single-stepping the guest using the
8645 * hypervisor debugger and should return
8646 * VINF_EM_DBG_STEPPED if the event was dispatched
8647 * directly.
8648 */
8649static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t fIntrState, bool fStepping)
8650{
8651 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8652 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8653
8654 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
8655 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
8656
8657 Assert(!fBlockSti || !(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_RFLAGS));
8658 Assert(!fBlockSti || pVCpu->cpum.GstCtx.eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
8659 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
8660 Assert(!TRPMHasTrap(pVCpu));
8661
8662 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
8663 if (pVCpu->hm.s.Event.fPending)
8664 {
8665 /*
8666 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
8667 * pending even while injecting an event and in this case, we want a VM-exit as soon as
8668 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
8669 *
8670 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
8671 */
8672 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
8673#ifdef VBOX_STRICT
8674 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
8675 {
8676 bool const fBlockInt = !(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_IF);
8677 Assert(!fBlockInt);
8678 Assert(!fBlockSti);
8679 Assert(!fBlockMovSS);
8680 }
8681 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_NMI)
8682 {
8683 bool const fBlockNmi = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
8684 Assert(!fBlockSti);
8685 Assert(!fBlockMovSS);
8686 Assert(!fBlockNmi);
8687 }
8688#endif
8689 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
8690 uIntType));
8691
8692 /*
8693 * Inject the event and get any changes to the guest-interruptibility state.
8694 *
8695 * The guest-interruptibility state may need to be updated if we inject the event
8696 * into the guest IDT ourselves (for real-on-v86 guest injecting software interrupts).
8697 */
8698 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &pVCpu->hm.s.Event, fStepping, &fIntrState);
8699 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
8700
8701 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
8702 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
8703 else
8704 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
8705 }
8706
8707 /*
8708 * Update the guest-interruptibility state.
8709 *
8710 * This is required for the real-on-v86 software interrupt injection case above, as well as
8711 * updates to the guest state from ring-3 or IEM/REM.
8712 */
8713 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
8714 AssertRC(rc);
8715
8716 /*
8717 * There's no need to clear the VM-entry interruption-information field here if we're not
8718 * injecting anything. VT-x clears the valid bit on every VM-exit.
8719 *
8720 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
8721 */
8722
8723 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
8724 NOREF(fBlockMovSS); NOREF(fBlockSti);
8725 return rcStrict;
8726}
8727
8728
8729/**
8730 * Enters the VT-x session.
8731 *
8732 * @returns VBox status code.
8733 * @param pVCpu The cross context virtual CPU structure.
8734 */
8735VMMR0DECL(int) VMXR0Enter(PVMCPU pVCpu)
8736{
8737 AssertPtr(pVCpu);
8738 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported);
8739 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8740
8741 LogFlowFunc(("pVCpu=%p\n", pVCpu));
8742 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
8743 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
8744
8745#ifdef VBOX_STRICT
8746 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
8747 RTCCUINTREG uHostCr4 = ASMGetCR4();
8748 if (!(uHostCr4 & X86_CR4_VMXE))
8749 {
8750 LogRelFunc(("X86_CR4_VMXE bit in CR4 is not set!\n"));
8751 return VERR_VMX_X86_CR4_VMXE_CLEARED;
8752 }
8753#endif
8754
8755 /*
8756 * Load the appropriate VMCS as the current and active one.
8757 */
8758 PVMXVMCSINFO pVmcsInfo;
8759 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx);
8760 if (!fInNestedGuestMode)
8761 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfo;
8762 else
8763 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
8764 int rc = hmR0VmxLoadVmcs(pVmcsInfo);
8765 if (RT_SUCCESS(rc))
8766 {
8767 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs = fInNestedGuestMode;
8768 pVCpu->hm.s.fLeaveDone = false;
8769 Log4Func(("Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8770
8771 /*
8772 * Do the EMT scheduled L1D flush here if needed.
8773 */
8774 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
8775 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
8776 else if (pVCpu->CTX_SUFF(pVM)->hm.s.fMdsClearOnSched)
8777 hmR0MdsClear();
8778 }
8779 return rc;
8780}
8781
8782
8783/**
8784 * The thread-context callback (only on platforms which support it).
8785 *
8786 * @param enmEvent The thread-context event.
8787 * @param pVCpu The cross context virtual CPU structure.
8788 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
8789 * @thread EMT(pVCpu)
8790 */
8791VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPU pVCpu, bool fGlobalInit)
8792{
8793 AssertPtr(pVCpu);
8794 RT_NOREF1(fGlobalInit);
8795
8796 switch (enmEvent)
8797 {
8798 case RTTHREADCTXEVENT_OUT:
8799 {
8800 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8801 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8802 VMCPU_ASSERT_EMT(pVCpu);
8803
8804 /* No longjmps (logger flushes, locks) in this fragile context. */
8805 VMMRZCallRing3Disable(pVCpu);
8806 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
8807
8808 /* Restore host-state (FPU, debug etc.) */
8809 if (!pVCpu->hm.s.fLeaveDone)
8810 {
8811 /*
8812 * Do -not- import the guest-state here as we might already be in the middle of importing
8813 * it, esp. bad if we're holding the PGM lock, see comment in hmR0VmxImportGuestState().
8814 */
8815 hmR0VmxLeave(pVCpu, false /* fImportState */);
8816 pVCpu->hm.s.fLeaveDone = true;
8817 }
8818
8819 /* Leave HM context, takes care of local init (term). */
8820 int rc = HMR0LeaveCpu(pVCpu);
8821 AssertRC(rc);
8822
8823 /* Restore longjmp state. */
8824 VMMRZCallRing3Enable(pVCpu);
8825 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
8826 break;
8827 }
8828
8829 case RTTHREADCTXEVENT_IN:
8830 {
8831 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8832 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8833 VMCPU_ASSERT_EMT(pVCpu);
8834
8835 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
8836 VMMRZCallRing3Disable(pVCpu);
8837 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
8838
8839 /* Initialize the bare minimum state required for HM. This takes care of
8840 initializing VT-x if necessary (onlined CPUs, local init etc.) */
8841 int rc = hmR0EnterCpu(pVCpu);
8842 AssertRC(rc);
8843 Assert( (pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
8844 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
8845
8846 /* Load the active VMCS as the current one. */
8847 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8848 rc = hmR0VmxLoadVmcs(pVmcsInfo);
8849 AssertRC(rc);
8850 Log4Func(("Resumed: Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8851 pVCpu->hm.s.fLeaveDone = false;
8852
8853 /* Do the EMT scheduled L1D flush if needed. */
8854 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
8855 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
8856
8857 /* Restore longjmp state. */
8858 VMMRZCallRing3Enable(pVCpu);
8859 break;
8860 }
8861
8862 default:
8863 break;
8864 }
8865}
8866
8867
8868/**
8869 * Exports the host state into the VMCS host-state area.
8870 * Sets up the VM-exit MSR-load area.
8871 *
8872 * The CPU state will be loaded from these fields on every successful VM-exit.
8873 *
8874 * @returns VBox status code.
8875 * @param pVCpu The cross context virtual CPU structure.
8876 *
8877 * @remarks No-long-jump zone!!!
8878 */
8879static int hmR0VmxExportHostState(PVMCPU pVCpu)
8880{
8881 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8882
8883 int rc = VINF_SUCCESS;
8884 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
8885 {
8886 hmR0VmxExportHostControlRegs();
8887
8888 rc = hmR0VmxExportHostSegmentRegs(pVCpu);
8889 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8890
8891 hmR0VmxExportHostMsrs(pVCpu);
8892
8893 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_HOST_CONTEXT;
8894 }
8895 return rc;
8896}
8897
8898
8899/**
8900 * Saves the host state in the VMCS host-state.
8901 *
8902 * @returns VBox status code.
8903 * @param pVCpu The cross context virtual CPU structure.
8904 *
8905 * @remarks No-long-jump zone!!!
8906 */
8907VMMR0DECL(int) VMXR0ExportHostState(PVMCPU pVCpu)
8908{
8909 AssertPtr(pVCpu);
8910 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8911
8912 /*
8913 * Export the host state here while entering HM context.
8914 * When thread-context hooks are used, we might get preempted and have to re-save the host
8915 * state but most of the time we won't be, so do it here before we disable interrupts.
8916 */
8917 return hmR0VmxExportHostState(pVCpu);
8918}
8919
8920
8921/**
8922 * Exports the guest state into the VMCS guest-state area.
8923 *
8924 * The will typically be done before VM-entry when the guest-CPU state and the
8925 * VMCS state may potentially be out of sync.
8926 *
8927 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
8928 * VM-entry controls.
8929 * Sets up the appropriate VMX non-root function to execute guest code based on
8930 * the guest CPU mode.
8931 *
8932 * @returns VBox strict status code.
8933 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8934 * without unrestricted guest execution and the VMMDev is not presently
8935 * mapped (e.g. EFI32).
8936 *
8937 * @param pVCpu The cross context virtual CPU structure.
8938 * @param pVmxTransient The VMX-transient structure.
8939 *
8940 * @remarks No-long-jump zone!!!
8941 */
8942static VBOXSTRICTRC hmR0VmxExportGuestState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
8943{
8944 AssertPtr(pVCpu);
8945 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8946 LogFlowFunc(("pVCpu=%p\n", pVCpu));
8947
8948 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExportGuestState, x);
8949
8950 /*
8951 * Determine real-on-v86 mode.
8952 * Used when the guest is in real-mode and unrestricted guest execution is not used.
8953 */
8954 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8955 if ( pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest
8956 || !CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx))
8957 pVmcsInfo->RealMode. fRealOnV86Active = false;
8958 else
8959 {
8960 Assert(!pVmxTransient->fIsNestedGuest);
8961 pVmcsInfo->RealMode.fRealOnV86Active = true;
8962 }
8963
8964 /*
8965 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
8966 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
8967 */
8968 /** @todo r=ramshankar: Move hmR0VmxSelectVMRunHandler inside
8969 * hmR0VmxExportGuestEntryExitCtls and do it conditionally. There shouldn't
8970 * be a need to evaluate this everytime since I'm pretty sure we intercept
8971 * all guest paging mode changes. */
8972 int rc = hmR0VmxSelectVMRunHandler(pVCpu, pVmxTransient);
8973 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8974
8975 rc = hmR0VmxExportGuestEntryExitCtls(pVCpu, pVmxTransient);
8976 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8977
8978 rc = hmR0VmxExportGuestCR0(pVCpu, pVmxTransient);
8979 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8980
8981 VBOXSTRICTRC rcStrict = hmR0VmxExportGuestCR3AndCR4(pVCpu, pVmxTransient);
8982 if (rcStrict == VINF_SUCCESS)
8983 { /* likely */ }
8984 else
8985 {
8986 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
8987 return rcStrict;
8988 }
8989
8990 rc = hmR0VmxExportGuestSegRegsXdtr(pVCpu, pVmxTransient);
8991 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8992
8993 rc = hmR0VmxExportGuestMsrs(pVCpu, pVmxTransient);
8994 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8995
8996 rc = hmR0VmxExportGuestApicTpr(pVCpu, pVmxTransient);
8997 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8998
8999 rc = hmR0VmxExportGuestXcptIntercepts(pVCpu, pVmxTransient);
9000 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9001
9002 rc = hmR0VmxExportGuestRip(pVCpu);
9003 rc |= hmR0VmxExportGuestRsp(pVCpu);
9004 rc |= hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9005 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9006
9007 rc = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9008 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9009
9010 /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
9011 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~( (HM_CHANGED_GUEST_GPRS_MASK & ~HM_CHANGED_GUEST_RSP)
9012 | HM_CHANGED_GUEST_CR2
9013 | (HM_CHANGED_GUEST_DR_MASK & ~HM_CHANGED_GUEST_DR7)
9014 | HM_CHANGED_GUEST_X87
9015 | HM_CHANGED_GUEST_SSE_AVX
9016 | HM_CHANGED_GUEST_OTHER_XSAVE
9017 | HM_CHANGED_GUEST_XCRx
9018 | HM_CHANGED_GUEST_KERNEL_GS_BASE /* Part of lazy or auto load-store MSRs. */
9019 | HM_CHANGED_GUEST_SYSCALL_MSRS /* Part of lazy or auto load-store MSRs. */
9020 | HM_CHANGED_GUEST_TSC_AUX
9021 | HM_CHANGED_GUEST_OTHER_MSRS
9022 | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
9023
9024 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExportGuestState, x);
9025 return rc;
9026}
9027
9028
9029/**
9030 * Exports the state shared between the host and guest into the VMCS.
9031 *
9032 * @param pVCpu The cross context virtual CPU structure.
9033 * @param pVmxTransient The VMX-transient structure.
9034 *
9035 * @remarks No-long-jump zone!!!
9036 */
9037static void hmR0VmxExportSharedState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
9038{
9039 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9040 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9041
9042 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_DR_MASK)
9043 {
9044 int rc = hmR0VmxExportSharedDebugState(pVCpu, pVmxTransient);
9045 AssertRC(rc);
9046 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_GUEST_DR_MASK;
9047
9048 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
9049 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_RFLAGS)
9050 {
9051 rc = hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9052 AssertRC(rc);
9053 }
9054 }
9055
9056 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_GUEST_LAZY_MSRS)
9057 {
9058 hmR0VmxLazyLoadGuestMsrs(pVCpu);
9059 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_VMX_GUEST_LAZY_MSRS;
9060 }
9061
9062 AssertMsg(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE),
9063 ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
9064}
9065
9066
9067/**
9068 * Worker for loading the guest-state bits in the inner VT-x execution loop.
9069 *
9070 * @returns Strict VBox status code (i.e. informational status codes too).
9071 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9072 * without unrestricted guest execution and the VMMDev is not presently
9073 * mapped (e.g. EFI32).
9074 *
9075 * @param pVCpu The cross context virtual CPU structure.
9076 * @param pVmxTransient The VMX-transient structure.
9077 *
9078 * @remarks No-long-jump zone!!!
9079 */
9080static VBOXSTRICTRC hmR0VmxExportGuestStateOptimal(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
9081{
9082 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9083 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9084 Assert(VMMR0IsLogFlushDisabled(pVCpu));
9085
9086#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
9087 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
9088#endif
9089
9090 /*
9091 * For many exits it's only RIP that changes and hence try to export it first
9092 * without going through a lot of change flag checks.
9093 */
9094 VBOXSTRICTRC rcStrict;
9095 uint64_t fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9096 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
9097 if ((fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)) == HM_CHANGED_GUEST_RIP)
9098 {
9099 rcStrict = hmR0VmxExportGuestRip(pVCpu);
9100 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9101 { /* likely */}
9102 else
9103 AssertMsgFailedReturn(("Failed to export guest RIP! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)), rcStrict);
9104 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportMinimal);
9105 }
9106 else if (fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9107 {
9108 rcStrict = hmR0VmxExportGuestState(pVCpu, pVmxTransient);
9109 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9110 { /* likely */}
9111 else
9112 {
9113 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM, ("Failed to export guest state! rc=%Rrc\n",
9114 VBOXSTRICTRC_VAL(rcStrict)));
9115 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9116 return rcStrict;
9117 }
9118 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportFull);
9119 }
9120 else
9121 rcStrict = VINF_SUCCESS;
9122
9123#ifdef VBOX_STRICT
9124 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
9125 fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9126 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
9127 AssertMsg(!(fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)),
9128 ("fCtxChanged=%#RX64\n", fCtxChanged));
9129#endif
9130 return rcStrict;
9131}
9132
9133
9134/**
9135 * Tries to determine what part of the guest-state VT-x has deemed as invalid
9136 * and update error record fields accordingly.
9137 *
9138 * @returns VMX_IGS_* error codes.
9139 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
9140 * wrong with the guest state.
9141 *
9142 * @param pVCpu The cross context virtual CPU structure.
9143 * @param pVmcsInfo The VMCS info. object.
9144 *
9145 * @remarks This function assumes our cache of the VMCS controls
9146 * are valid, i.e. hmR0VmxCheckVmcsCtls() succeeded.
9147 */
9148static uint32_t hmR0VmxCheckGuestState(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
9149{
9150#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
9151#define HMVMX_CHECK_BREAK(expr, err) do { \
9152 if (!(expr)) { uError = (err); break; } \
9153 } while (0)
9154
9155 int rc;
9156 PVM pVM = pVCpu->CTX_SUFF(pVM);
9157 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9158 uint32_t uError = VMX_IGS_ERROR;
9159 uint32_t u32Val;
9160 bool const fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuest;
9161
9162 do
9163 {
9164 /*
9165 * CR0.
9166 */
9167 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9168 uint32_t fSetCr0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
9169 uint32_t const fZapCr0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
9170 /* Exceptions for unrestricted guest execution for fixed CR0 bits (PE, PG).
9171 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
9172 if (fUnrestrictedGuest)
9173 fSetCr0 &= ~(X86_CR0_PE | X86_CR0_PG);
9174
9175 uint32_t u32GuestCr0;
9176 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32GuestCr0);
9177 AssertRCBreak(rc);
9178 HMVMX_CHECK_BREAK((u32GuestCr0 & fSetCr0) == fSetCr0, VMX_IGS_CR0_FIXED1);
9179 HMVMX_CHECK_BREAK(!(u32GuestCr0 & ~fZapCr0), VMX_IGS_CR0_FIXED0);
9180 if ( !fUnrestrictedGuest
9181 && (u32GuestCr0 & X86_CR0_PG)
9182 && !(u32GuestCr0 & X86_CR0_PE))
9183 {
9184 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
9185 }
9186
9187 /*
9188 * CR4.
9189 */
9190 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9191 uint64_t const fSetCr4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
9192 uint64_t const fZapCr4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
9193
9194 uint32_t u32GuestCr4;
9195 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR4, &u32GuestCr4);
9196 AssertRCBreak(rc);
9197 HMVMX_CHECK_BREAK((u32GuestCr4 & fSetCr4) == fSetCr4, VMX_IGS_CR4_FIXED1);
9198 HMVMX_CHECK_BREAK(!(u32GuestCr4 & ~fZapCr4), VMX_IGS_CR4_FIXED0);
9199
9200 /*
9201 * IA32_DEBUGCTL MSR.
9202 */
9203 uint64_t u64Val;
9204 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
9205 AssertRCBreak(rc);
9206 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9207 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
9208 {
9209 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
9210 }
9211 uint64_t u64DebugCtlMsr = u64Val;
9212
9213#ifdef VBOX_STRICT
9214 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
9215 AssertRCBreak(rc);
9216 Assert(u32Val == pVmcsInfo->u32EntryCtls);
9217#endif
9218 bool const fLongModeGuest = RT_BOOL(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
9219
9220 /*
9221 * RIP and RFLAGS.
9222 */
9223 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
9224 AssertRCBreak(rc);
9225 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
9226 if ( !fLongModeGuest
9227 || !pCtx->cs.Attr.n.u1Long)
9228 {
9229 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
9230 }
9231 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
9232 * must be identical if the "IA-32e mode guest" VM-entry
9233 * control is 1 and CS.L is 1. No check applies if the
9234 * CPU supports 64 linear-address bits. */
9235
9236 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
9237 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
9238 AssertRCBreak(rc);
9239 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
9240 VMX_IGS_RFLAGS_RESERVED);
9241 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
9242 uint32_t const u32Eflags = u64Val;
9243
9244 if ( fLongModeGuest
9245 || ( fUnrestrictedGuest
9246 && !(u32GuestCr0 & X86_CR0_PE)))
9247 {
9248 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
9249 }
9250
9251 uint32_t u32EntryInfo;
9252 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
9253 AssertRCBreak(rc);
9254 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9255 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
9256
9257 /*
9258 * 64-bit checks.
9259 */
9260 if (fLongModeGuest)
9261 {
9262 HMVMX_CHECK_BREAK(u32GuestCr0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
9263 HMVMX_CHECK_BREAK(u32GuestCr4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
9264 }
9265
9266 if ( !fLongModeGuest
9267 && (u32GuestCr4 & X86_CR4_PCIDE))
9268 {
9269 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
9270 }
9271
9272 /** @todo CR3 field must be such that bits 63:52 and bits in the range
9273 * 51:32 beyond the processor's physical-address width are 0. */
9274
9275 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9276 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
9277 {
9278 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
9279 }
9280
9281 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
9282 AssertRCBreak(rc);
9283 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
9284
9285 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
9286 AssertRCBreak(rc);
9287 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
9288
9289 /*
9290 * PERF_GLOBAL MSR.
9291 */
9292 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR)
9293 {
9294 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
9295 AssertRCBreak(rc);
9296 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
9297 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
9298 }
9299
9300 /*
9301 * PAT MSR.
9302 */
9303 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
9304 {
9305 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
9306 AssertRCBreak(rc);
9307 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
9308 for (unsigned i = 0; i < 8; i++)
9309 {
9310 uint8_t u8Val = (u64Val & 0xff);
9311 if ( u8Val != 0 /* UC */
9312 && u8Val != 1 /* WC */
9313 && u8Val != 4 /* WT */
9314 && u8Val != 5 /* WP */
9315 && u8Val != 6 /* WB */
9316 && u8Val != 7 /* UC- */)
9317 {
9318 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
9319 }
9320 u64Val >>= 8;
9321 }
9322 }
9323
9324 /*
9325 * EFER MSR.
9326 */
9327 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
9328 {
9329 Assert(pVM->hm.s.vmx.fSupportsVmcsEfer);
9330 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
9331 AssertRCBreak(rc);
9332 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
9333 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
9334 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVmcsInfo->u32EntryCtls
9335 & VMX_ENTRY_CTLS_IA32E_MODE_GUEST),
9336 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
9337 /** @todo r=ramshankar: Unrestricted check here is probably wrong, see
9338 * iemVmxVmentryCheckGuestState(). */
9339 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9340 || !(u32GuestCr0 & X86_CR0_PG)
9341 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
9342 VMX_IGS_EFER_LMA_LME_MISMATCH);
9343 }
9344
9345 /*
9346 * Segment registers.
9347 */
9348 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9349 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
9350 if (!(u32Eflags & X86_EFL_VM))
9351 {
9352 /* CS */
9353 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
9354 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
9355 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
9356 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
9357 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9358 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
9359 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9360 /* CS cannot be loaded with NULL in protected mode. */
9361 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
9362 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
9363 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
9364 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
9365 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
9366 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
9367 else if (pVM->hm.s.vmx.fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
9368 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
9369 else
9370 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
9371
9372 /* SS */
9373 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9374 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
9375 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
9376 if ( !(pCtx->cr0 & X86_CR0_PE)
9377 || pCtx->cs.Attr.n.u4Type == 3)
9378 {
9379 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
9380 }
9381 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
9382 {
9383 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
9384 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
9385 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
9386 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
9387 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
9388 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9389 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
9390 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9391 }
9392
9393 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSReg(). */
9394 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
9395 {
9396 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
9397 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
9398 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9399 || pCtx->ds.Attr.n.u4Type > 11
9400 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9401 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
9402 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
9403 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
9404 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9405 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
9406 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9407 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9408 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
9409 }
9410 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
9411 {
9412 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
9413 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
9414 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9415 || pCtx->es.Attr.n.u4Type > 11
9416 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9417 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
9418 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
9419 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
9420 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9421 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
9422 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9423 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9424 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
9425 }
9426 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
9427 {
9428 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
9429 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
9430 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9431 || pCtx->fs.Attr.n.u4Type > 11
9432 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
9433 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
9434 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
9435 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
9436 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9437 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
9438 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9439 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9440 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
9441 }
9442 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
9443 {
9444 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
9445 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
9446 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9447 || pCtx->gs.Attr.n.u4Type > 11
9448 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
9449 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
9450 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
9451 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
9452 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9453 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
9454 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9455 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9456 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
9457 }
9458 /* 64-bit capable CPUs. */
9459 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9460 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9461 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9462 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9463 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9464 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9465 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9466 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9467 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9468 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9469 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9470 }
9471 else
9472 {
9473 /* V86 mode checks. */
9474 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
9475 if (pVmcsInfo->RealMode.fRealOnV86Active)
9476 {
9477 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
9478 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
9479 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
9480 }
9481 else
9482 {
9483 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
9484 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
9485 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
9486 }
9487
9488 /* CS */
9489 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
9490 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
9491 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
9492 /* SS */
9493 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
9494 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
9495 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
9496 /* DS */
9497 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
9498 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
9499 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
9500 /* ES */
9501 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
9502 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
9503 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
9504 /* FS */
9505 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
9506 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
9507 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
9508 /* GS */
9509 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
9510 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
9511 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
9512 /* 64-bit capable CPUs. */
9513 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9514 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9515 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9516 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9517 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9518 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9519 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9520 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9521 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9522 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9523 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9524 }
9525
9526 /*
9527 * TR.
9528 */
9529 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
9530 /* 64-bit capable CPUs. */
9531 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
9532 if (fLongModeGuest)
9533 {
9534 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
9535 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
9536 }
9537 else
9538 {
9539 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
9540 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
9541 VMX_IGS_TR_ATTR_TYPE_INVALID);
9542 }
9543 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
9544 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
9545 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
9546 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
9547 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
9548 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
9549 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
9550 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
9551
9552 /*
9553 * GDTR and IDTR (64-bit capable checks).
9554 */
9555 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
9556 AssertRCBreak(rc);
9557 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
9558
9559 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
9560 AssertRCBreak(rc);
9561 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
9562
9563 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
9564 AssertRCBreak(rc);
9565 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
9566
9567 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
9568 AssertRCBreak(rc);
9569 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
9570
9571 /*
9572 * Guest Non-Register State.
9573 */
9574 /* Activity State. */
9575 uint32_t u32ActivityState;
9576 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
9577 AssertRCBreak(rc);
9578 HMVMX_CHECK_BREAK( !u32ActivityState
9579 || (u32ActivityState & RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Misc, VMX_BF_MISC_ACTIVITY_STATES)),
9580 VMX_IGS_ACTIVITY_STATE_INVALID);
9581 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
9582 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
9583 uint32_t u32IntrState;
9584 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32IntrState);
9585 AssertRCBreak(rc);
9586 if ( u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS
9587 || u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9588 {
9589 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
9590 }
9591
9592 /** @todo Activity state and injecting interrupts. Left as a todo since we
9593 * currently don't use activity states but ACTIVE. */
9594
9595 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
9596 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
9597
9598 /* Guest interruptibility-state. */
9599 HMVMX_CHECK_BREAK(!(u32IntrState & 0xffffffe0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
9600 HMVMX_CHECK_BREAK((u32IntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
9601 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9602 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
9603 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
9604 || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
9605 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
9606 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9607 {
9608 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9609 && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9610 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
9611 }
9612 else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
9613 {
9614 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9615 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
9616 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
9617 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
9618 }
9619 /** @todo Assumes the processor is not in SMM. */
9620 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
9621 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
9622 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
9623 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
9624 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
9625 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
9626 && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
9627 {
9628 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI),
9629 VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
9630 }
9631
9632 /* Pending debug exceptions. */
9633 rc = VMXReadVmcs64(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &u64Val);
9634 AssertRCBreak(rc);
9635 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
9636 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
9637 u32Val = u64Val; /* For pending debug exceptions checks below. */
9638
9639 if ( (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9640 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
9641 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
9642 {
9643 if ( (u32Eflags & X86_EFL_TF)
9644 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
9645 {
9646 /* Bit 14 is PendingDebug.BS. */
9647 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
9648 }
9649 if ( !(u32Eflags & X86_EFL_TF)
9650 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
9651 {
9652 /* Bit 14 is PendingDebug.BS. */
9653 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
9654 }
9655 }
9656
9657 /* VMCS link pointer. */
9658 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
9659 AssertRCBreak(rc);
9660 if (u64Val != UINT64_C(0xffffffffffffffff))
9661 {
9662 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
9663 /** @todo Bits beyond the processor's physical-address width MBZ. */
9664 /** @todo SMM checks. */
9665 Assert(pVmcsInfo->HCPhysShadowVmcs == u64Val);
9666 Assert(pVmcsInfo->pvShadowVmcs);
9667 VMXVMCSREVID VmcsRevId;
9668 VmcsRevId.u = *(uint32_t *)pVmcsInfo->pvShadowVmcs;
9669 HMVMX_CHECK_BREAK(VmcsRevId.n.u31RevisionId == RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID),
9670 VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID);
9671 HMVMX_CHECK_BREAK(VmcsRevId.n.fIsShadowVmcs == (uint32_t)!!(pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING),
9672 VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW);
9673 }
9674
9675 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
9676 * not using nested paging? */
9677 if ( pVM->hm.s.fNestedPaging
9678 && !fLongModeGuest
9679 && CPUMIsGuestInPAEModeEx(pCtx))
9680 {
9681 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
9682 AssertRCBreak(rc);
9683 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9684
9685 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
9686 AssertRCBreak(rc);
9687 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9688
9689 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
9690 AssertRCBreak(rc);
9691 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9692
9693 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
9694 AssertRCBreak(rc);
9695 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9696 }
9697
9698 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
9699 if (uError == VMX_IGS_ERROR)
9700 uError = VMX_IGS_REASON_NOT_FOUND;
9701 } while (0);
9702
9703 pVCpu->hm.s.u32HMError = uError;
9704 return uError;
9705
9706#undef HMVMX_ERROR_BREAK
9707#undef HMVMX_CHECK_BREAK
9708}
9709
9710
9711/**
9712 * Map the APIC-access page for virtualizing APIC accesses.
9713 *
9714 * This can cause a longjumps to R3 due to the acquisition of the PGM lock. Hence,
9715 * this not done as part of exporting guest state, see @bugref{8721}.
9716 *
9717 * @returns VBox status code.
9718 * @param pVCpu The cross context virtual CPU structure.
9719 */
9720static int hmR0VmxMapHCApicAccessPage(PVMCPU pVCpu)
9721{
9722 PVM pVM = pVCpu->CTX_SUFF(pVM);
9723 uint64_t const u64MsrApicBase = APICGetBaseMsrNoCheck(pVCpu);
9724
9725 Assert(PDMHasApic(pVM));
9726 Assert(u64MsrApicBase);
9727
9728 RTGCPHYS const GCPhysApicBase = u64MsrApicBase & PAGE_BASE_GC_MASK;
9729 Log4Func(("Mappping HC APIC-access page at %#RGp\n", GCPhysApicBase));
9730
9731 /* Unalias the existing mapping. */
9732 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
9733 AssertRCReturn(rc, rc);
9734
9735 /* Map the HC APIC-access page in place of the MMIO page, also updates the shadow page tables if necessary. */
9736 Assert(pVM->hm.s.vmx.HCPhysApicAccess != NIL_RTHCPHYS);
9737 rc = IOMMMIOMapMMIOHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hm.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
9738 AssertRCReturn(rc, rc);
9739
9740 /* Update the per-VCPU cache of the APIC base MSR. */
9741 pVCpu->hm.s.vmx.u64GstMsrApicBase = u64MsrApicBase;
9742 return VINF_SUCCESS;
9743}
9744
9745
9746/**
9747 * Worker function passed to RTMpOnSpecific() that is to be called on the target
9748 * CPU.
9749 *
9750 * @param idCpu The ID for the CPU the function is called on.
9751 * @param pvUser1 Null, not used.
9752 * @param pvUser2 Null, not used.
9753 */
9754static DECLCALLBACK(void) hmR0DispatchHostNmi(RTCPUID idCpu, void *pvUser1, void *pvUser2)
9755{
9756 RT_NOREF3(idCpu, pvUser1, pvUser2);
9757 VMXDispatchHostNmi();
9758}
9759
9760
9761/**
9762 * Dispatching an NMI on the host CPU that received it.
9763 *
9764 * @returns VBox status code.
9765 * @param pVCpu The cross context virtual CPU structure.
9766 * @param pVmcsInfo The VMCS info. object corresponding to the VMCS that was
9767 * executing when receiving the host NMI in VMX non-root
9768 * operation.
9769 */
9770static int hmR0VmxExitHostNmi(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
9771{
9772 RTCPUID const idCpu = pVmcsInfo->idHostCpu;
9773
9774 /*
9775 * We don't want to delay dispatching the NMI any more than we have to. However,
9776 * we have already chosen -not- to dispatch NMIs when interrupts were still disabled
9777 * after executing guest or nested-guest code for the following reasons:
9778 *
9779 * - We would need to perform VMREADs with interrupts disabled and is orders of
9780 * magnitude worse when we run as a guest hypervisor without VMCS shadowing
9781 * supported by the host hypervisor.
9782 *
9783 * - It affects the common VM-exit scenario and keeps interrupts disabled for a
9784 * longer period of time just for handling an edge case like host NMIs which do
9785 * not occur nearly as frequently as other VM-exits.
9786 *
9787 * Let's cover the most likely scenario first. Check if we are on the target CPU
9788 * and dispatch the NMI right away. This should be much faster than calling into
9789 * RTMpOnSpecific() machinery.
9790 */
9791 bool fDispatched = false;
9792 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
9793 if (idCpu == RTMpCpuId())
9794 {
9795 VMXDispatchHostNmi();
9796 fDispatched = true;
9797 }
9798 ASMSetFlags(fEFlags);
9799 if (fDispatched)
9800 {
9801 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
9802 return VINF_SUCCESS;
9803 }
9804
9805 /*
9806 * RTMpOnSpecific() waits until the worker function has run on the target CPU. So
9807 * there should be no race or recursion even if we are unlucky enough to be preempted
9808 * (to the target CPU) without dispatching the host NMI above.
9809 */
9810 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGCIpi);
9811 return RTMpOnSpecific(idCpu, &hmR0DispatchHostNmi, NULL /* pvUser1 */, NULL /* pvUser2 */);
9812}
9813
9814
9815#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9816/**
9817 * Merges the guest with the nested-guest MSR bitmap in preparation of executing the
9818 * nested-guest using hardware-assisted VMX.
9819 *
9820 * @param pVCpu The cross context virtual CPU structure.
9821 * @param pVmcsInfoNstGst The nested-guest VMCS info. object.
9822 * @param pVmcsInfoGst The guest VMCS info. object.
9823 */
9824static void hmR0VmxMergeMsrBitmapNested(PCVMCPU pVCpu, PVMXVMCSINFO pVmcsInfoNstGst, PCVMXVMCSINFO pVmcsInfoGst)
9825{
9826 uint32_t const cbMsrBitmap = X86_PAGE_4K_SIZE;
9827 uint64_t *pu64MsrBitmap = (uint64_t *)pVmcsInfoNstGst->pvMsrBitmap;
9828 Assert(pu64MsrBitmap);
9829
9830 /*
9831 * We merge the guest MSR bitmap with the nested-guest MSR bitmap such that any
9832 * MSR that is intercepted by the guest is also intercepted while executing the
9833 * nested-guest using hardware-assisted VMX.
9834 *
9835 * Note! If the nested-guest is not using an MSR bitmap, ever MSR must cause a
9836 * nested-guest VM-exit even if the outer guest is not intercepting some
9837 * MSRs. We cannot assume the caller has initialized the nested-guest
9838 * MSR bitmap in this case.
9839 *
9840 * The guest hypervisor may also switch whether it uses MSR bitmaps for
9841 * each VM-entry, hence initializing it once per-VM while setting up the
9842 * nested-guest VMCS is not sufficient.
9843 */
9844 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
9845 if (pVmcsNstGst->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
9846 {
9847 uint64_t const *pu64MsrBitmapNstGst = (uint64_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
9848 uint64_t const *pu64MsrBitmapGst = (uint64_t const *)pVmcsInfoGst->pvMsrBitmap;
9849 Assert(pu64MsrBitmapNstGst);
9850 Assert(pu64MsrBitmapGst);
9851
9852 uint32_t const cFrags = cbMsrBitmap / sizeof(uint64_t);
9853 for (uint32_t i = 0; i < cFrags; i++)
9854 pu64MsrBitmap[i] = pu64MsrBitmapNstGst[i] | pu64MsrBitmapGst[i];
9855 }
9856 else
9857 ASMMemFill32(pu64MsrBitmap, cbMsrBitmap, UINT32_C(0xffffffff));
9858}
9859
9860
9861/**
9862 * Merges the guest VMCS in to the nested-guest VMCS controls in preparation of
9863 * hardware-assisted VMX execution of the nested-guest.
9864 *
9865 * For a guest, we don't modify these controls once we set up the VMCS and hence
9866 * this function is never called.
9867 *
9868 * For nested-guests since the guest hypervisor provides these controls on every
9869 * nested-guest VM-entry and could potentially change them everytime we need to
9870 * merge them before every nested-guest VM-entry.
9871 *
9872 * @returns VBox status code.
9873 * @param pVCpu The cross context virtual CPU structure.
9874 */
9875static int hmR0VmxMergeVmcsNested(PVMCPU pVCpu)
9876{
9877 PVM pVM = pVCpu->CTX_SUFF(pVM);
9878 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hm.s.vmx.VmcsInfo;
9879 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
9880 Assert(pVmcsNstGst);
9881
9882 /*
9883 * Merge the controls with the requirements of the guest VMCS.
9884 *
9885 * We do not need to validate the nested-guest VMX features specified in the nested-guest
9886 * VMCS with the features supported by the physical CPU as it's already done by the
9887 * VMLAUNCH/VMRESUME instruction emulation.
9888 *
9889 * This is because the VMX features exposed by CPUM (through CPUID/MSRs) to the guest are
9890 * derived from the VMX features supported by the physical CPU.
9891 */
9892
9893 /* Pin-based VM-execution controls. */
9894 uint32_t const u32PinCtls = pVmcsNstGst->u32PinCtls | pVmcsInfoGst->u32PinCtls;
9895
9896 /* Processor-based VM-execution controls. */
9897 uint32_t u32ProcCtls = (pVmcsNstGst->u32ProcCtls & ~VMX_PROC_CTLS_USE_IO_BITMAPS)
9898 | (pVmcsInfoGst->u32ProcCtls & ~( VMX_PROC_CTLS_INT_WINDOW_EXIT
9899 | VMX_PROC_CTLS_NMI_WINDOW_EXIT
9900 | VMX_PROC_CTLS_USE_TPR_SHADOW
9901 | VMX_PROC_CTLS_MONITOR_TRAP_FLAG));
9902
9903 /* Secondary processor-based VM-execution controls. */
9904 uint32_t const u32ProcCtls2 = (pVmcsNstGst->u32ProcCtls2 & ~VMX_PROC_CTLS2_VPID)
9905 | (pVmcsInfoGst->u32ProcCtls2 & ~( VMX_PROC_CTLS2_VIRT_APIC_ACCESS
9906 | VMX_PROC_CTLS2_INVPCID
9907 | VMX_PROC_CTLS2_VMCS_SHADOWING
9908 | VMX_PROC_CTLS2_RDTSCP
9909 | VMX_PROC_CTLS2_XSAVES_XRSTORS
9910 | VMX_PROC_CTLS2_APIC_REG_VIRT
9911 | VMX_PROC_CTLS2_VIRT_INT_DELIVERY
9912 | VMX_PROC_CTLS2_VMFUNC));
9913
9914 /*
9915 * VM-entry controls:
9916 * These controls contains state that depends on the nested-guest state (primarily
9917 * EFER MSR) and is thus not constant between VMLAUNCH/VMRESUME and the nested-guest
9918 * VM-exit. Although the guest hypervisor cannot change it, we need to in order to
9919 * properly continue executing the nested-guest if the EFER MSR changes but does not
9920 * cause a nested-guest VM-exits.
9921 *
9922 * VM-exit controls:
9923 * These controls specify the host state on return. We cannot use the controls from
9924 * the guest hypervisor state as is as it would contain the guest state rather than
9925 * the host state. Since the host state is subject to change (e.g. preemption, trips
9926 * to ring-3, longjmp and rescheduling to a different host CPU) they are not constant
9927 * through VMLAUNCH/VMRESUME and the nested-guest VM-exit.
9928 *
9929 * VM-entry MSR-load:
9930 * The guest MSRs from the VM-entry MSR-load area are already loaded into the guest-CPU
9931 * context by the VMLAUNCH/VMRESUME instruction emulation.
9932 *
9933 * VM-exit MSR-store:
9934 * The VM-exit emulation will take care of populating the MSRs from the guest-CPU context
9935 * back into the VM-exit MSR-store area.
9936 *
9937 * VM-exit MSR-load areas:
9938 * This must contain the real host MSRs with hardware-assisted VMX execution. Hence, we
9939 * can entirely ignore what the guest hypervisor wants to load here.
9940 */
9941
9942 /*
9943 * Exception bitmap.
9944 *
9945 * We could remove #UD from the guest bitmap and merge it with the nested-guest bitmap
9946 * here (and avoid doing anything while exporting nested-guest state), but to keep the
9947 * code more flexible if intercepting exceptions become more dynamic in the future we do
9948 * it as part of exporting the nested-guest state.
9949 */
9950 uint32_t const u32XcptBitmap = pVmcsNstGst->u32XcptBitmap | pVmcsInfoGst->u32XcptBitmap;
9951
9952 /*
9953 * CR0/CR4 guest/host mask.
9954 *
9955 * Modifications by the nested-guest to CR0/CR4 bits owned by the host and the guest must
9956 * cause VM-exits, so we need to merge them here.
9957 */
9958 uint64_t const u64Cr0Mask = pVmcsNstGst->u64Cr0Mask.u | pVmcsInfoGst->u64Cr0Mask;
9959 uint64_t const u64Cr4Mask = pVmcsNstGst->u64Cr4Mask.u | pVmcsInfoGst->u64Cr4Mask;
9960
9961 /*
9962 * Page-fault error-code mask and match.
9963 *
9964 * Although we require unrestricted guest execution (and thereby nested-paging) for
9965 * hardware-assisted VMX execution of nested-guests and thus the outer guest doesn't
9966 * normally intercept #PFs, it might intercept them for debugging purposes.
9967 *
9968 * If the outer guest is not intercepting #PFs, we can use the nested-guest #PF filters.
9969 * If the outer guest is intercepting #PFs, we must intercept all #PFs.
9970 */
9971 uint32_t u32XcptPFMask;
9972 uint32_t u32XcptPFMatch;
9973 if (!(pVmcsInfoGst->u32XcptBitmap & RT_BIT(X86_XCPT_PF)))
9974 {
9975 u32XcptPFMask = pVmcsNstGst->u32XcptPFMask;
9976 u32XcptPFMatch = pVmcsNstGst->u32XcptPFMatch;
9977 }
9978 else
9979 {
9980 u32XcptPFMask = 0;
9981 u32XcptPFMatch = 0;
9982 }
9983
9984 /*
9985 * Pause-Loop exiting.
9986 */
9987 uint32_t const cPleGapTicks = RT_MIN(pVM->hm.s.vmx.cPleGapTicks, pVmcsNstGst->u32PleGap);
9988 uint32_t const cPleWindowTicks = RT_MIN(pVM->hm.s.vmx.cPleWindowTicks, pVmcsNstGst->u32PleWindow);
9989
9990 /*
9991 * I/O Bitmap.
9992 *
9993 * We do not use the I/O bitmap that may be provided by the guest hypervisor as we always
9994 * intercept all I/O port accesses.
9995 */
9996 Assert(u32ProcCtls & VMX_PROC_CTLS_UNCOND_IO_EXIT);
9997
9998 /*
9999 * VMCS shadowing.
10000 *
10001 * We do not yet expose VMCS shadowing to the guest and thus VMCS shadowing should not be
10002 * enabled while executing the nested-guest.
10003 */
10004 Assert(!(u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING));
10005
10006 /*
10007 * APIC-access page.
10008 */
10009 RTHCPHYS HCPhysApicAccess;
10010 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10011 {
10012 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
10013 RTGCPHYS const GCPhysApicAccess = pVmcsNstGst->u64AddrApicAccess.u;
10014
10015 /** @todo NSTVMX: This is not really correct but currently is required to make
10016 * things work. We need to re-register the page handler when we fallback to
10017 * IEM execution of the nested-guest! */
10018 PGMHandlerPhysicalDeregister(pVM, GCPhysApicAccess);
10019
10020 void *pvPage;
10021 PGMPAGEMAPLOCK PgMapLockApicAccess;
10022 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysApicAccess, &pvPage, &PgMapLockApicAccess);
10023 if (RT_SUCCESS(rc))
10024 {
10025 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysApicAccess, &HCPhysApicAccess);
10026 AssertMsgRCReturn(rc, ("Failed to get host-physical address for APIC-access page at %#RGp\n", GCPhysApicAccess), rc);
10027
10028 /*
10029 * We can release the page lock here because the APIC-access page is never read or
10030 * written to but merely serves as a placeholder in the shadow/nested page tables
10031 * to cause VM-exits or re-direct the access to the virtual-APIC page.
10032 */
10033 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgMapLockApicAccess);
10034 }
10035 else
10036 return rc;
10037 }
10038 else
10039 HCPhysApicAccess = 0;
10040
10041 /*
10042 * Virtual-APIC page and TPR threshold.
10043 */
10044 PVMXVMCSINFO pVmcsInfoNstGst = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
10045 RTHCPHYS HCPhysVirtApic;
10046 uint32_t u32TprThreshold;
10047 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10048 {
10049 Assert(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW);
10050
10051 void *pvPage;
10052 RTGCPHYS const GCPhysVirtApic = pVmcsNstGst->u64AddrVirtApic.u;
10053 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysVirtApic, &pvPage, &pVCpu->hm.s.vmx.PgMapLockVirtApic);
10054 AssertMsgRCReturn(rc, ("Failed to get current-context pointer for virtual-APIC page at %#RGp\n", GCPhysVirtApic), rc);
10055
10056 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysVirtApic, &HCPhysVirtApic);
10057 AssertMsgRCReturn(rc, ("Failed to get host-physical address for virtual-APIC page at %#RGp\n", GCPhysVirtApic), rc);
10058 pVCpu->hm.s.vmx.fVirtApicPageLocked = true;
10059
10060 u32TprThreshold = pVmcsNstGst->u32TprThreshold;
10061 }
10062 else
10063 {
10064 HCPhysVirtApic = 0;
10065 u32TprThreshold = 0;
10066
10067 /*
10068 * We must make sure CR8 reads/write must cause VM-exits when TPR shadowing is not
10069 * used by the guest hypervisor. Preventing MMIO accesses to the physical APIC will
10070 * be taken care of by EPT/shadow paging.
10071 */
10072 if (pVM->hm.s.fAllow64BitGuests)
10073 {
10074 u32ProcCtls |= VMX_PROC_CTLS_CR8_STORE_EXIT
10075 | VMX_PROC_CTLS_CR8_LOAD_EXIT;
10076 }
10077 }
10078
10079 /*
10080 * Validate basic assumptions.
10081 */
10082 Assert(pVM->hm.s.vmx.fAllowUnrestricted);
10083 Assert(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
10084 Assert(hmGetVmxActiveVmcsInfo(pVCpu) == pVmcsInfoNstGst);
10085
10086 /*
10087 * Commit it to the nested-guest VMCS.
10088 */
10089 int rc = VINF_SUCCESS;
10090 if (pVmcsInfoNstGst->u32PinCtls != u32PinCtls)
10091 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, u32PinCtls);
10092 if (pVmcsInfoNstGst->u32ProcCtls != u32ProcCtls)
10093 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, u32ProcCtls);
10094 if (pVmcsInfoNstGst->u32ProcCtls2 != u32ProcCtls2)
10095 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, u32ProcCtls2);
10096 if (pVmcsInfoNstGst->u32XcptBitmap != u32XcptBitmap)
10097 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
10098 if (pVmcsInfoNstGst->u64Cr0Mask != u64Cr0Mask)
10099 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask);
10100 if (pVmcsInfoNstGst->u64Cr4Mask != u64Cr4Mask)
10101 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask);
10102 if (pVmcsInfoNstGst->u32XcptPFMask != u32XcptPFMask)
10103 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, u32XcptPFMask);
10104 if (pVmcsInfoNstGst->u32XcptPFMatch != u32XcptPFMatch)
10105 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, u32XcptPFMatch);
10106 if ( !(u32ProcCtls & VMX_PROC_CTLS_PAUSE_EXIT)
10107 && (u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
10108 {
10109 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT);
10110 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, cPleGapTicks);
10111 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, cPleWindowTicks);
10112 }
10113 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10114 {
10115 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
10116 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
10117 }
10118 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10119 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
10120 AssertRC(rc);
10121
10122 /*
10123 * Update the nested-guest VMCS cache.
10124 */
10125 pVmcsInfoNstGst->u32PinCtls = u32PinCtls;
10126 pVmcsInfoNstGst->u32ProcCtls = u32ProcCtls;
10127 pVmcsInfoNstGst->u32ProcCtls2 = u32ProcCtls2;
10128 pVmcsInfoNstGst->u32XcptBitmap = u32XcptBitmap;
10129 pVmcsInfoNstGst->u64Cr0Mask = u64Cr0Mask;
10130 pVmcsInfoNstGst->u64Cr4Mask = u64Cr4Mask;
10131 pVmcsInfoNstGst->u32XcptPFMask = u32XcptPFMask;
10132 pVmcsInfoNstGst->u32XcptPFMatch = u32XcptPFMatch;
10133 pVmcsInfoNstGst->HCPhysVirtApic = HCPhysVirtApic;
10134
10135 /*
10136 * We need to flush the TLB if we are switching the APIC-access page address.
10137 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
10138 */
10139 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10140 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = true;
10141
10142 /*
10143 * MSR bitmap.
10144 *
10145 * The MSR bitmap address has already been initialized while setting up the nested-guest
10146 * VMCS, here we need to merge the MSR bitmaps.
10147 */
10148 if (u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10149 hmR0VmxMergeMsrBitmapNested(pVCpu, pVmcsInfoNstGst, pVmcsInfoGst);
10150
10151 return VINF_SUCCESS;
10152}
10153#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10154
10155
10156/**
10157 * Does the preparations before executing guest code in VT-x.
10158 *
10159 * This may cause longjmps to ring-3 and may even result in rescheduling to the
10160 * recompiler/IEM. We must be cautious what we do here regarding committing
10161 * guest-state information into the VMCS assuming we assuredly execute the
10162 * guest in VT-x mode.
10163 *
10164 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
10165 * the common-state (TRPM/forceflags), we must undo those changes so that the
10166 * recompiler/IEM can (and should) use them when it resumes guest execution.
10167 * Otherwise such operations must be done when we can no longer exit to ring-3.
10168 *
10169 * @returns Strict VBox status code (i.e. informational status codes too).
10170 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
10171 * have been disabled.
10172 * @retval VINF_VMX_VMEXIT if a nested-guest VM-exit occurs (e.g., while evaluating
10173 * pending events).
10174 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
10175 * double-fault into the guest.
10176 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
10177 * dispatched directly.
10178 * @retval VINF_* scheduling changes, we have to go back to ring-3.
10179 *
10180 * @param pVCpu The cross context virtual CPU structure.
10181 * @param pVmxTransient The VMX-transient structure.
10182 * @param fStepping Whether we are single-stepping the guest in the
10183 * hypervisor debugger. Makes us ignore some of the reasons
10184 * for returning to ring-3, and return VINF_EM_DBG_STEPPED
10185 * if event dispatching took place.
10186 */
10187static VBOXSTRICTRC hmR0VmxPreRunGuest(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, bool fStepping)
10188{
10189 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10190
10191#ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
10192 if (pVmxTransient->fIsNestedGuest)
10193 {
10194 RT_NOREF2(pVCpu, fStepping);
10195 Log2Func(("Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
10196 return VINF_EM_RESCHEDULE_REM;
10197 }
10198#endif
10199
10200#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
10201 PGMRZDynMapFlushAutoSet(pVCpu);
10202#endif
10203
10204 /*
10205 * Check and process force flag actions, some of which might require us to go back to ring-3.
10206 */
10207 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVCpu, fStepping);
10208 if (rcStrict == VINF_SUCCESS)
10209 {
10210 /* FFs don't get set all the time. */
10211#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10212 if ( pVmxTransient->fIsNestedGuest
10213 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10214 {
10215 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10216 return VINF_VMX_VMEXIT;
10217 }
10218#endif
10219 }
10220 else
10221 return rcStrict;
10222
10223 /*
10224 * Virtualize memory-mapped accesses to the physical APIC (may take locks).
10225 */
10226 /** @todo Doing this from ring-3 after VM setup phase causes a
10227 * VERR_IOM_MMIO_RANGE_NOT_FOUND guru while booting Visa 64 SMP VM. No
10228 * idea why atm. */
10229 PVM pVM = pVCpu->CTX_SUFF(pVM);
10230 if ( !pVCpu->hm.s.vmx.u64GstMsrApicBase
10231 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10232 && PDMHasApic(pVM))
10233 {
10234 int rc = hmR0VmxMapHCApicAccessPage(pVCpu);
10235 AssertRCReturn(rc, rc);
10236 }
10237
10238#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10239 /*
10240 * Merge guest VMCS controls with the nested-guest VMCS controls.
10241 *
10242 * Even if we have not executed the guest prior to this (e.g. when resuming from a
10243 * saved state), we should be okay with merging controls as we initialize the
10244 * guest VMCS controls as part of VM setup phase.
10245 */
10246 if ( pVmxTransient->fIsNestedGuest
10247 && !pVCpu->hm.s.vmx.fMergedNstGstCtls)
10248 {
10249 int rc = hmR0VmxMergeVmcsNested(pVCpu);
10250 AssertRCReturn(rc, rc);
10251 pVCpu->hm.s.vmx.fMergedNstGstCtls = true;
10252 }
10253#endif
10254
10255 /*
10256 * Evaluate events to be injected into the guest.
10257 *
10258 * Events in TRPM can be injected without inspecting the guest state.
10259 * If any new events (interrupts/NMI) are pending currently, we try to set up the
10260 * guest to cause a VM-exit the next time they are ready to receive the event.
10261 *
10262 * With nested-guests, evaluating pending events may cause VM-exits.
10263 */
10264 if (TRPMHasTrap(pVCpu))
10265 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
10266
10267 uint32_t fIntrState;
10268 rcStrict = hmR0VmxEvaluatePendingEvent(pVCpu, pVmxTransient, &fIntrState);
10269
10270#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10271 /*
10272 * While evaluating pending events if something failed (unlikely) or if we were
10273 * preparing to run a nested-guest but performed a nested-guest VM-exit, we should bail.
10274 */
10275 if (rcStrict != VINF_SUCCESS)
10276 return rcStrict;
10277 if ( pVmxTransient->fIsNestedGuest
10278 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10279 {
10280 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10281 return VINF_VMX_VMEXIT;
10282 }
10283#else
10284 Assert(rcStrict == VINF_SUCCESS);
10285#endif
10286
10287 /*
10288 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus
10289 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might
10290 * also result in triple-faulting the VM.
10291 *
10292 * With nested-guests, the above does not apply since unrestricted guest execution is a
10293 * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
10294 */
10295 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pVmxTransient, fIntrState, fStepping);
10296 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10297 { /* likely */ }
10298 else
10299 {
10300 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
10301 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
10302 return rcStrict;
10303 }
10304
10305 /*
10306 * A longjump might result in importing CR3 even for VM-exits that don't necessarily
10307 * import CR3 themselves. We will need to update them here, as even as late as the above
10308 * hmR0VmxInjectPendingEvent() call may lazily import guest-CPU state on demand causing
10309 * the below force flags to be set.
10310 */
10311 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
10312 {
10313 Assert(!(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_CR3));
10314 int rc2 = PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
10315 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
10316 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
10317 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10318 }
10319 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
10320 {
10321 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
10322 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10323 }
10324
10325#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10326 /* Paranoia. */
10327 Assert(!pVmxTransient->fIsNestedGuest || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10328#endif
10329
10330 /*
10331 * No longjmps to ring-3 from this point on!!!
10332 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
10333 * This also disables flushing of the R0-logger instance (if any).
10334 */
10335 VMMRZCallRing3Disable(pVCpu);
10336
10337 /*
10338 * Export the guest state bits.
10339 *
10340 * We cannot perform longjmps while loading the guest state because we do not preserve the
10341 * host/guest state (although the VMCS will be preserved) across longjmps which can cause
10342 * CPU migration.
10343 *
10344 * If we are injecting events to a real-on-v86 mode guest, we would have updated RIP and some segment
10345 * registers. Hence, exporting of the guest state needs to be done -after- injection of events.
10346 */
10347 rcStrict = hmR0VmxExportGuestStateOptimal(pVCpu, pVmxTransient);
10348 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10349 { /* likely */ }
10350 else
10351 {
10352 VMMRZCallRing3Enable(pVCpu);
10353 return rcStrict;
10354 }
10355
10356 /*
10357 * We disable interrupts so that we don't miss any interrupts that would flag preemption
10358 * (IPI/timers etc.) when thread-context hooks aren't used and we've been running with
10359 * preemption disabled for a while. Since this is purely to aid the
10360 * RTThreadPreemptIsPending() code, it doesn't matter that it may temporarily reenable and
10361 * disable interrupt on NT.
10362 *
10363 * We need to check for force-flags that could've possible been altered since we last
10364 * checked them (e.g. by PDMGetInterrupt() leaving the PDM critical section,
10365 * see @bugref{6398}).
10366 *
10367 * We also check a couple of other force-flags as a last opportunity to get the EMT back
10368 * to ring-3 before executing guest code.
10369 */
10370 pVmxTransient->fEFlags = ASMIntDisableFlags();
10371
10372 if ( ( !VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
10373 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
10374 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
10375 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
10376 {
10377 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
10378 {
10379#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10380 /*
10381 * If we are executing a nested-guest make sure that we should intercept subsequent
10382 * events. The one we are injecting might be part of VM-entry. This is mainly to keep
10383 * the VM-exit instruction emulation happy.
10384 */
10385 if (pVmxTransient->fIsNestedGuest)
10386 pVCpu->cpum.GstCtx.hwvirt.vmx.fInterceptEvents = true;
10387#endif
10388
10389 /*
10390 * We've injected any pending events. This is really the point of no return (to ring-3).
10391 *
10392 * Note! The caller expects to continue with interrupts & longjmps disabled on successful
10393 * returns from this function, so do -not- enable them here.
10394 */
10395 pVCpu->hm.s.Event.fPending = false;
10396 return VINF_SUCCESS;
10397 }
10398
10399 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPendingHostIrq);
10400 rcStrict = VINF_EM_RAW_INTERRUPT;
10401 }
10402 else
10403 {
10404 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
10405 rcStrict = VINF_EM_RAW_TO_R3;
10406 }
10407
10408 ASMSetFlags(pVmxTransient->fEFlags);
10409 VMMRZCallRing3Enable(pVCpu);
10410
10411 return rcStrict;
10412}
10413
10414
10415/**
10416 * Final preparations before executing guest code using hardware-assisted VMX.
10417 *
10418 * We can no longer get preempted to a different host CPU and there are no returns
10419 * to ring-3. We ignore any errors that may happen from this point (e.g. VMWRITE
10420 * failures), this function is not intended to fail sans unrecoverable hardware
10421 * errors.
10422 *
10423 * @param pVCpu The cross context virtual CPU structure.
10424 * @param pVmxTransient The VMX-transient structure.
10425 *
10426 * @remarks Called with preemption disabled.
10427 * @remarks No-long-jump zone!!!
10428 */
10429static void hmR0VmxPreRunGuestCommitted(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
10430{
10431 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10432 Assert(VMMR0IsLogFlushDisabled(pVCpu));
10433 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
10434 Assert(!pVCpu->hm.s.Event.fPending);
10435
10436 /*
10437 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
10438 */
10439 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10440 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
10441
10442 PVM pVM = pVCpu->CTX_SUFF(pVM);
10443 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10444 PHMPHYSCPU pHostCpu = hmR0GetCurrentCpu();
10445 RTCPUID const idCurrentCpu = pHostCpu->idCpu;
10446
10447 if (!CPUMIsGuestFPUStateActive(pVCpu))
10448 {
10449 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10450 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
10451 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_HOST_CONTEXT;
10452 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10453 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadGuestFpu);
10454 }
10455
10456 /*
10457 * Re-export the host state bits as we may've been preempted (only happens when
10458 * thread-context hooks are used or when the VM start function changes) or if
10459 * the host CR0 is modified while loading the guest FPU state above.
10460 *
10461 * The 64-on-32 switcher saves the (64-bit) host state into the VMCS and if we
10462 * changed the switcher back to 32-bit, we *must* save the 32-bit host state here,
10463 * see @bugref{8432}.
10464 *
10465 * This may also happen when switching to/from a nested-guest VMCS without leaving
10466 * ring-0.
10467 */
10468 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
10469 {
10470 hmR0VmxExportHostState(pVCpu);
10471 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportHostState);
10472 }
10473 Assert(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT));
10474
10475 /*
10476 * Export the state shared between host and guest (FPU, debug, lazy MSRs).
10477 */
10478 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)
10479 hmR0VmxExportSharedState(pVCpu, pVmxTransient);
10480 AssertMsg(!pVCpu->hm.s.fCtxChanged, ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
10481
10482 /*
10483 * Store status of the shared guest/host debug state at the time of VM-entry.
10484 */
10485 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
10486 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
10487
10488 /*
10489 * Always cache the TPR-shadow if the virtual-APIC page exists, thereby skipping
10490 * more than one conditional check. The post-run side of our code shall determine
10491 * if it needs to sync. the virtual APIC TPR with the TPR-shadow.
10492 */
10493 if (pVmcsInfo->pbVirtApic)
10494 pVmxTransient->u8GuestTpr = pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR];
10495
10496 /*
10497 * Update the host MSRs values in the VM-exit MSR-load area.
10498 */
10499 if (!pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs)
10500 {
10501 if (pVmcsInfo->cExitMsrLoad > 0)
10502 hmR0VmxUpdateAutoLoadHostMsrs(pVCpu, pVmcsInfo);
10503 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = true;
10504 }
10505
10506 /*
10507 * Evaluate if we need to intercept guest RDTSC/P accesses. Set up the
10508 * VMX-preemption timer based on the next virtual sync clock deadline.
10509 */
10510 if ( !pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer
10511 || idCurrentCpu != pVCpu->hm.s.idLastCpu)
10512 {
10513 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVCpu, pVmxTransient);
10514 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = true;
10515 }
10516
10517 /* Record statistics of how often we use TSC offsetting as opposed to intercepting RDTSC/P. */
10518 bool const fIsRdtscIntercepted = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT);
10519 if (!fIsRdtscIntercepted)
10520 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
10521 else
10522 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
10523
10524 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
10525 hmR0VmxFlushTaggedTlb(pHostCpu, pVCpu, pVmcsInfo); /* Invalidate the appropriate guest entries from the TLB. */
10526 Assert(idCurrentCpu == pVCpu->hm.s.idLastCpu);
10527 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Update the error reporting info. with the current host CPU. */
10528 pVmcsInfo->idHostCpu = idCurrentCpu; /* Update the CPU for which we updated host-state in this VMCS. */
10529
10530 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
10531
10532 TMNotifyStartOfExecution(pVCpu); /* Notify TM to resume its clocks when TSC is tied to execution,
10533 as we're about to start executing the guest . */
10534
10535 /*
10536 * Load the guest TSC_AUX MSR when we are not intercepting RDTSCP.
10537 *
10538 * This is done this late as updating the TSC offsetting/preemption timer above
10539 * figures out if we can skip intercepting RDTSCP by calculating the number of
10540 * host CPU ticks till the next virtual sync deadline (for the dynamic case).
10541 */
10542 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_RDTSCP)
10543 && !fIsRdtscIntercepted)
10544 {
10545 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_TSC_AUX);
10546
10547 /* NB: Because we call hmR0VmxAddAutoLoadStoreMsr with fUpdateHostMsr=true,
10548 it's safe even after hmR0VmxUpdateAutoLoadHostMsrs has already been done. */
10549 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX, CPUMGetGuestTscAux(pVCpu),
10550 true /* fSetReadWrite */, true /* fUpdateHostMsr */);
10551 AssertRC(rc);
10552 Assert(!pVmxTransient->fRemoveTscAuxMsr);
10553 pVmxTransient->fRemoveTscAuxMsr = true;
10554 }
10555
10556#ifdef VBOX_STRICT
10557 Assert(pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs);
10558 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
10559 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo);
10560 AssertRC(hmR0VmxCheckVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest));
10561#endif
10562
10563#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
10564 /** @todo r=ramshankar: We can now probably use iemVmxVmentryCheckGuestState here.
10565 * Add a PVMXMSRS parameter to it, so that IEM can look at the host MSRs,
10566 * see @bugref{9180#c54}. */
10567 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
10568 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
10569 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
10570#endif
10571}
10572
10573
10574/**
10575 * First C routine invoked after running guest code using hardware-assisted VMX.
10576 *
10577 * @param pVCpu The cross context virtual CPU structure.
10578 * @param pVmxTransient The VMX-transient structure.
10579 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
10580 *
10581 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
10582 *
10583 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
10584 * unconditionally when it is safe to do so.
10585 */
10586static void hmR0VmxPostRunGuest(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, int rcVMRun)
10587{
10588 uint64_t const uHostTsc = ASMReadTSC(); /** @todo We can do a lot better here, see @bugref{9180#c38}. */
10589
10590 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
10591 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
10592 pVCpu->hm.s.fCtxChanged = 0; /* Exits/longjmps to ring-3 requires saving the guest state. */
10593 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
10594 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
10595 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
10596
10597 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10598 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
10599 {
10600 uint64_t uGstTsc;
10601 if (!pVmxTransient->fIsNestedGuest)
10602 uGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
10603 else
10604 {
10605 uint64_t const uNstGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
10606 uGstTsc = CPUMRemoveNestedGuestTscOffset(pVCpu, uNstGstTsc);
10607 }
10608 TMCpuTickSetLastSeen(pVCpu, uGstTsc); /* Update TM with the guest TSC. */
10609 }
10610
10611 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatPreExit, x);
10612 TMNotifyEndOfExecution(pVCpu); /* Notify TM that the guest is no longer running. */
10613 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10614
10615 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Some host state messed up by VMX needs restoring. */
10616 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
10617#ifdef VBOX_STRICT
10618 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo); /* Verify that the host EFER MSR wasn't modified. */
10619#endif
10620 Assert(!ASMIntAreEnabled());
10621 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
10622 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10623
10624#ifdef HMVMX_ALWAYS_CLEAN_TRANSIENT
10625 /*
10626 * Clean all the VMCS fields in the transient structure before reading
10627 * anything from the VMCS.
10628 */
10629 pVmxTransient->uExitReason = 0;
10630 pVmxTransient->uExitIntErrorCode = 0;
10631 pVmxTransient->uExitQual = 0;
10632 pVmxTransient->uGuestLinearAddr = 0;
10633 pVmxTransient->uExitIntInfo = 0;
10634 pVmxTransient->cbInstr = 0;
10635 pVmxTransient->ExitInstrInfo.u = 0;
10636 pVmxTransient->uEntryIntInfo = 0;
10637 pVmxTransient->uEntryXcptErrorCode = 0;
10638 pVmxTransient->cbEntryInstr = 0;
10639 pVmxTransient->uIdtVectoringInfo = 0;
10640 pVmxTransient->uIdtVectoringErrorCode = 0;
10641#endif
10642
10643 /*
10644 * Save the basic VM-exit reason and check if the VM-entry failed.
10645 * See Intel spec. 24.9.1 "Basic VM-exit Information".
10646 */
10647 uint32_t uExitReason;
10648 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
10649 AssertRC(rc);
10650 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason);
10651 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
10652
10653 /*
10654 * Log the VM-exit before logging anything else as otherwise it might be a
10655 * tad confusing what happens before and after the world-switch.
10656 */
10657 HMVMX_LOG_EXIT(pVCpu, uExitReason);
10658
10659 /*
10660 * Remove the TSC_AUX MSR from the auto-load/store MSR area and reset any MSR
10661 * bitmap permissions, if it was added before VM-entry.
10662 */
10663 if (pVmxTransient->fRemoveTscAuxMsr)
10664 {
10665 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX);
10666 pVmxTransient->fRemoveTscAuxMsr = false;
10667 }
10668
10669 /*
10670 * Check if VMLAUNCH/VMRESUME succeeded.
10671 * If this failed, we cause a guru meditation and cease further execution.
10672 *
10673 * However, if we are executing a nested-guest we might fail if we use the
10674 * fast path rather than fully emulating VMLAUNCH/VMRESUME instruction in IEM.
10675 */
10676 if (RT_LIKELY(rcVMRun == VINF_SUCCESS))
10677 {
10678 /*
10679 * Update the VM-exit history array here even if the VM-entry failed due to:
10680 * - Invalid guest state.
10681 * - MSR loading.
10682 * - Machine-check event.
10683 *
10684 * In any of the above cases we will still have a "valid" VM-exit reason
10685 * despite @a fVMEntryFailed being false.
10686 *
10687 * See Intel spec. 26.7 "VM-Entry failures during or after loading guest state".
10688 *
10689 * Note! We don't have CS or RIP at this point. Will probably address that later
10690 * by amending the history entry added here.
10691 */
10692 EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_VMX, pVmxTransient->uExitReason & EMEXIT_F_TYPE_MASK),
10693 UINT64_MAX, uHostTsc);
10694
10695 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
10696 {
10697 VMMRZCallRing3Enable(pVCpu);
10698
10699 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10700 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10701
10702#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
10703 hmR0VmxReadAllRoFieldsVmcs(pVmxTransient);
10704#endif
10705#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
10706 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
10707 AssertRC(rc);
10708#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
10709 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_RFLAGS);
10710 AssertRC(rc);
10711#else
10712 /*
10713 * Import the guest-interruptibility state always as we need it while evaluating
10714 * injecting events on re-entry.
10715 *
10716 * We don't import CR0 (when unrestricted guest execution is unavailable) despite
10717 * checking for real-mode while exporting the state because all bits that cause
10718 * mode changes wrt CR0 are intercepted.
10719 */
10720 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_HM_VMX_INT_STATE);
10721 AssertRC(rc);
10722#endif
10723
10724 /*
10725 * Sync the TPR shadow with our APIC state.
10726 */
10727 if ( !pVmxTransient->fIsNestedGuest
10728 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
10729 {
10730 Assert(pVmcsInfo->pbVirtApic);
10731 if (pVmxTransient->u8GuestTpr != pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR])
10732 {
10733 rc = APICSetTpr(pVCpu, pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR]);
10734 AssertRC(rc);
10735 ASMAtomicOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
10736 }
10737 }
10738
10739 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10740 return;
10741 }
10742 }
10743#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10744 else if (pVmxTransient->fIsNestedGuest)
10745 AssertMsgFailed(("VMLAUNCH/VMRESUME failed but shouldn't happen when VMLAUNCH/VMRESUME was emulated in IEM!\n"));
10746#endif
10747 else
10748 Log4Func(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
10749
10750 VMMRZCallRing3Enable(pVCpu);
10751}
10752
10753
10754/**
10755 * Runs the guest code using hardware-assisted VMX the normal way.
10756 *
10757 * @returns VBox status code.
10758 * @param pVCpu The cross context virtual CPU structure.
10759 * @param pcLoops Pointer to the number of executed loops.
10760 */
10761static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVMCPU pVCpu, uint32_t *pcLoops)
10762{
10763 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
10764 Assert(pcLoops);
10765 Assert(*pcLoops <= cMaxResumeLoops);
10766 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10767
10768#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10769 /*
10770 * Switch to the guest VMCS as we may have transitioned from executing the nested-guest
10771 * without leaving ring-0. Otherwise, if we came from ring-3 we would have loaded the
10772 * guest VMCS while entering the VMX ring-0 session.
10773 */
10774 if (pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs)
10775 {
10776 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, false /* fSwitchToNstGstVmcs */);
10777 if (RT_SUCCESS(rc))
10778 { /* likely */ }
10779 else
10780 {
10781 LogRelFunc(("Failed to switch to the guest VMCS. rc=%Rrc\n", rc));
10782 return rc;
10783 }
10784 }
10785#endif
10786
10787 VMXTRANSIENT VmxTransient;
10788 RT_ZERO(VmxTransient);
10789 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
10790
10791 /* Paranoia. */
10792 Assert(VmxTransient.pVmcsInfo == &pVCpu->hm.s.vmx.VmcsInfo);
10793
10794 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10795 for (;;)
10796 {
10797 Assert(!HMR0SuspendPending());
10798 HMVMX_ASSERT_CPU_SAFE(pVCpu);
10799 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10800
10801 /*
10802 * Preparatory work for running nested-guest code, this may force us to
10803 * return to ring-3.
10804 *
10805 * Warning! This bugger disables interrupts on VINF_SUCCESS!
10806 */
10807 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
10808 if (rcStrict != VINF_SUCCESS)
10809 break;
10810
10811 /* Interrupts are disabled at this point! */
10812 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
10813 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
10814 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
10815 /* Interrupts are re-enabled at this point! */
10816
10817 /*
10818 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
10819 */
10820 if (RT_SUCCESS(rcRun))
10821 { /* very likely */ }
10822 else
10823 {
10824 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
10825 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
10826 return rcRun;
10827 }
10828
10829 /*
10830 * Profile the VM-exit.
10831 */
10832 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10833 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10834 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10835 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
10836 HMVMX_START_EXIT_DISPATCH_PROF();
10837
10838 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
10839
10840 /*
10841 * Handle the VM-exit.
10842 */
10843#ifdef HMVMX_USE_FUNCTION_TABLE
10844 rcStrict = g_apfnVMExitHandlers[VmxTransient.uExitReason](pVCpu, &VmxTransient);
10845#else
10846 rcStrict = hmR0VmxHandleExit(pVCpu, &VmxTransient);
10847#endif
10848 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
10849 if (rcStrict == VINF_SUCCESS)
10850 {
10851 if (++(*pcLoops) <= cMaxResumeLoops)
10852 continue;
10853 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10854 rcStrict = VINF_EM_RAW_INTERRUPT;
10855 }
10856 break;
10857 }
10858
10859 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10860 return rcStrict;
10861}
10862
10863
10864#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10865/**
10866 * Runs the nested-guest code using hardware-assisted VMX.
10867 *
10868 * @returns VBox status code.
10869 * @param pVCpu The cross context virtual CPU structure.
10870 * @param pcLoops Pointer to the number of executed loops.
10871 *
10872 * @sa hmR0VmxRunGuestCodeNormal.
10873 */
10874static VBOXSTRICTRC hmR0VmxRunGuestCodeNested(PVMCPU pVCpu, uint32_t *pcLoops)
10875{
10876 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
10877 Assert(pcLoops);
10878 Assert(*pcLoops <= cMaxResumeLoops);
10879 Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10880
10881 /*
10882 * Switch to the nested-guest VMCS as we may have transitioned from executing the
10883 * guest without leaving ring-0. Otherwise, if we came from ring-3 we would have
10884 * loaded the nested-guest VMCS while entering the VMX ring-0 session.
10885 */
10886 if (!pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs)
10887 {
10888 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, true /* fSwitchToNstGstVmcs */);
10889 if (RT_SUCCESS(rc))
10890 { /* likely */ }
10891 else
10892 {
10893 LogRelFunc(("Failed to switch to the nested-guest VMCS. rc=%Rrc\n", rc));
10894 return rc;
10895 }
10896 }
10897
10898 VMXTRANSIENT VmxTransient;
10899 RT_ZERO(VmxTransient);
10900 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
10901 VmxTransient.fIsNestedGuest = true;
10902
10903 /* Paranoia. */
10904 Assert(VmxTransient.pVmcsInfo == &pVCpu->hm.s.vmx.VmcsInfoNstGst);
10905
10906 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10907 for (;;)
10908 {
10909 Assert(!HMR0SuspendPending());
10910 HMVMX_ASSERT_CPU_SAFE(pVCpu);
10911 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10912
10913 /*
10914 * Preparatory work for running guest code, this may force us to
10915 * return to ring-3.
10916 *
10917 * Warning! This bugger disables interrupts on VINF_SUCCESS!
10918 */
10919 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
10920 if (rcStrict != VINF_SUCCESS)
10921 break;
10922
10923 /* Interrupts are disabled at this point! */
10924 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
10925 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
10926 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
10927 /* Interrupts are re-enabled at this point! */
10928
10929 /*
10930 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
10931 */
10932 if (RT_SUCCESS(rcRun))
10933 { /* very likely */ }
10934 else
10935 {
10936 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
10937 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
10938 return rcRun;
10939 }
10940
10941 /*
10942 * Profile the VM-exit.
10943 */
10944 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10945 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10946 STAM_COUNTER_INC(&pVCpu->hm.s.StatNestedExitAll);
10947 STAM_COUNTER_INC(&pVCpu->hm.s.paStatNestedExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10948 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
10949 HMVMX_START_EXIT_DISPATCH_PROF();
10950
10951 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
10952
10953 /*
10954 * Handle the VM-exit.
10955 */
10956 rcStrict = hmR0VmxHandleExitNested(pVCpu, &VmxTransient);
10957 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
10958 if (rcStrict == VINF_SUCCESS)
10959 {
10960 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10961 {
10962 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10963 rcStrict = VINF_VMX_VMEXIT;
10964 }
10965 else
10966 {
10967 if (++(*pcLoops) <= cMaxResumeLoops)
10968 continue;
10969 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10970 rcStrict = VINF_EM_RAW_INTERRUPT;
10971 }
10972 }
10973 else
10974 Assert(rcStrict != VINF_VMX_VMEXIT);
10975 break;
10976 }
10977
10978 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10979 return rcStrict;
10980}
10981#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10982
10983
10984/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
10985 * probes.
10986 *
10987 * The following few functions and associated structure contains the bloat
10988 * necessary for providing detailed debug events and dtrace probes as well as
10989 * reliable host side single stepping. This works on the principle of
10990 * "subclassing" the normal execution loop and workers. We replace the loop
10991 * method completely and override selected helpers to add necessary adjustments
10992 * to their core operation.
10993 *
10994 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
10995 * any performance for debug and analysis features.
10996 *
10997 * @{
10998 */
10999
11000/**
11001 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
11002 * the debug run loop.
11003 */
11004typedef struct VMXRUNDBGSTATE
11005{
11006 /** The RIP we started executing at. This is for detecting that we stepped. */
11007 uint64_t uRipStart;
11008 /** The CS we started executing with. */
11009 uint16_t uCsStart;
11010
11011 /** Whether we've actually modified the 1st execution control field. */
11012 bool fModifiedProcCtls : 1;
11013 /** Whether we've actually modified the 2nd execution control field. */
11014 bool fModifiedProcCtls2 : 1;
11015 /** Whether we've actually modified the exception bitmap. */
11016 bool fModifiedXcptBitmap : 1;
11017
11018 /** We desire the modified the CR0 mask to be cleared. */
11019 bool fClearCr0Mask : 1;
11020 /** We desire the modified the CR4 mask to be cleared. */
11021 bool fClearCr4Mask : 1;
11022 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
11023 uint32_t fCpe1Extra;
11024 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
11025 uint32_t fCpe1Unwanted;
11026 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
11027 uint32_t fCpe2Extra;
11028 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
11029 uint32_t bmXcptExtra;
11030 /** The sequence number of the Dtrace provider settings the state was
11031 * configured against. */
11032 uint32_t uDtraceSettingsSeqNo;
11033 /** VM-exits to check (one bit per VM-exit). */
11034 uint32_t bmExitsToCheck[3];
11035
11036 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
11037 uint32_t fProcCtlsInitial;
11038 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
11039 uint32_t fProcCtls2Initial;
11040 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
11041 uint32_t bmXcptInitial;
11042} VMXRUNDBGSTATE;
11043AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
11044typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
11045
11046
11047/**
11048 * Initializes the VMXRUNDBGSTATE structure.
11049 *
11050 * @param pVCpu The cross context virtual CPU structure of the
11051 * calling EMT.
11052 * @param pVmxTransient The VMX-transient structure.
11053 * @param pDbgState The debug state to initialize.
11054 */
11055static void hmR0VmxRunDebugStateInit(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11056{
11057 pDbgState->uRipStart = pVCpu->cpum.GstCtx.rip;
11058 pDbgState->uCsStart = pVCpu->cpum.GstCtx.cs.Sel;
11059
11060 pDbgState->fModifiedProcCtls = false;
11061 pDbgState->fModifiedProcCtls2 = false;
11062 pDbgState->fModifiedXcptBitmap = false;
11063 pDbgState->fClearCr0Mask = false;
11064 pDbgState->fClearCr4Mask = false;
11065 pDbgState->fCpe1Extra = 0;
11066 pDbgState->fCpe1Unwanted = 0;
11067 pDbgState->fCpe2Extra = 0;
11068 pDbgState->bmXcptExtra = 0;
11069 pDbgState->fProcCtlsInitial = pVmxTransient->pVmcsInfo->u32ProcCtls;
11070 pDbgState->fProcCtls2Initial = pVmxTransient->pVmcsInfo->u32ProcCtls2;
11071 pDbgState->bmXcptInitial = pVmxTransient->pVmcsInfo->u32XcptBitmap;
11072}
11073
11074
11075/**
11076 * Updates the VMSC fields with changes requested by @a pDbgState.
11077 *
11078 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
11079 * immediately before executing guest code, i.e. when interrupts are disabled.
11080 * We don't check status codes here as we cannot easily assert or return in the
11081 * latter case.
11082 *
11083 * @param pVCpu The cross context virtual CPU structure.
11084 * @param pVmxTransient The VMX-transient structure.
11085 * @param pDbgState The debug state.
11086 */
11087static void hmR0VmxPreRunGuestDebugStateApply(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11088{
11089 /*
11090 * Ensure desired flags in VMCS control fields are set.
11091 * (Ignoring write failure here, as we're committed and it's just debug extras.)
11092 *
11093 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
11094 * there should be no stale data in pCtx at this point.
11095 */
11096 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11097 if ( (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
11098 || (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Unwanted))
11099 {
11100 pVmcsInfo->u32ProcCtls |= pDbgState->fCpe1Extra;
11101 pVmcsInfo->u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
11102 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
11103 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVmcsInfo->u32ProcCtls));
11104 pDbgState->fModifiedProcCtls = true;
11105 }
11106
11107 if ((pVmcsInfo->u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
11108 {
11109 pVmcsInfo->u32ProcCtls2 |= pDbgState->fCpe2Extra;
11110 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVmcsInfo->u32ProcCtls2);
11111 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVmcsInfo->u32ProcCtls2));
11112 pDbgState->fModifiedProcCtls2 = true;
11113 }
11114
11115 if ((pVmcsInfo->u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
11116 {
11117 pVmcsInfo->u32XcptBitmap |= pDbgState->bmXcptExtra;
11118 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVmcsInfo->u32XcptBitmap);
11119 Log6Func(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVmcsInfo->u32XcptBitmap));
11120 pDbgState->fModifiedXcptBitmap = true;
11121 }
11122
11123 if (pDbgState->fClearCr0Mask && pVmcsInfo->u64Cr0Mask != 0)
11124 {
11125 pVmcsInfo->u64Cr0Mask = 0;
11126 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, 0);
11127 Log6Func(("VMX_VMCS_CTRL_CR0_MASK: 0\n"));
11128 }
11129
11130 if (pDbgState->fClearCr4Mask && pVmcsInfo->u64Cr4Mask != 0)
11131 {
11132 pVmcsInfo->u64Cr4Mask = 0;
11133 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, 0);
11134 Log6Func(("VMX_VMCS_CTRL_CR4_MASK: 0\n"));
11135 }
11136
11137 NOREF(pVCpu);
11138}
11139
11140
11141/**
11142 * Restores VMCS fields that were changed by hmR0VmxPreRunGuestDebugStateApply for
11143 * re-entry next time around.
11144 *
11145 * @returns Strict VBox status code (i.e. informational status codes too).
11146 * @param pVCpu The cross context virtual CPU structure.
11147 * @param pVmxTransient The VMX-transient structure.
11148 * @param pDbgState The debug state.
11149 * @param rcStrict The return code from executing the guest using single
11150 * stepping.
11151 */
11152static VBOXSTRICTRC hmR0VmxRunDebugStateRevert(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState,
11153 VBOXSTRICTRC rcStrict)
11154{
11155 /*
11156 * Restore VM-exit control settings as we may not reenter this function the
11157 * next time around.
11158 */
11159 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11160
11161 /* We reload the initial value, trigger what we can of recalculations the
11162 next time around. From the looks of things, that's all that's required atm. */
11163 if (pDbgState->fModifiedProcCtls)
11164 {
11165 if (!(pDbgState->fProcCtlsInitial & VMX_PROC_CTLS_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
11166 pDbgState->fProcCtlsInitial |= VMX_PROC_CTLS_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
11167 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
11168 AssertRC(rc2);
11169 pVmcsInfo->u32ProcCtls = pDbgState->fProcCtlsInitial;
11170 }
11171
11172 /* We're currently the only ones messing with this one, so just restore the
11173 cached value and reload the field. */
11174 if ( pDbgState->fModifiedProcCtls2
11175 && pVmcsInfo->u32ProcCtls2 != pDbgState->fProcCtls2Initial)
11176 {
11177 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
11178 AssertRC(rc2);
11179 pVmcsInfo->u32ProcCtls2 = pDbgState->fProcCtls2Initial;
11180 }
11181
11182 /* If we've modified the exception bitmap, we restore it and trigger
11183 reloading and partial recalculation the next time around. */
11184 if (pDbgState->fModifiedXcptBitmap)
11185 pVmcsInfo->u32XcptBitmap = pDbgState->bmXcptInitial;
11186
11187 return rcStrict;
11188}
11189
11190
11191/**
11192 * Configures VM-exit controls for current DBGF and DTrace settings.
11193 *
11194 * This updates @a pDbgState and the VMCS execution control fields to reflect
11195 * the necessary VM-exits demanded by DBGF and DTrace.
11196 *
11197 * @param pVCpu The cross context virtual CPU structure.
11198 * @param pVmxTransient The VMX-transient structure. May update
11199 * fUpdatedTscOffsettingAndPreemptTimer.
11200 * @param pDbgState The debug state.
11201 */
11202static void hmR0VmxPreRunGuestDebugStateUpdate(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11203{
11204 /*
11205 * Take down the dtrace serial number so we can spot changes.
11206 */
11207 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
11208 ASMCompilerBarrier();
11209
11210 /*
11211 * We'll rebuild most of the middle block of data members (holding the
11212 * current settings) as we go along here, so start by clearing it all.
11213 */
11214 pDbgState->bmXcptExtra = 0;
11215 pDbgState->fCpe1Extra = 0;
11216 pDbgState->fCpe1Unwanted = 0;
11217 pDbgState->fCpe2Extra = 0;
11218 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
11219 pDbgState->bmExitsToCheck[i] = 0;
11220
11221 /*
11222 * Software interrupts (INT XXh) - no idea how to trigger these...
11223 */
11224 PVM pVM = pVCpu->CTX_SUFF(pVM);
11225 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
11226 || VBOXVMM_INT_SOFTWARE_ENABLED())
11227 {
11228 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11229 }
11230
11231 /*
11232 * INT3 breakpoints - triggered by #BP exceptions.
11233 */
11234 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
11235 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11236
11237 /*
11238 * Exception bitmap and XCPT events+probes.
11239 */
11240 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
11241 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
11242 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
11243
11244 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
11245 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
11246 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11247 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
11248 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
11249 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
11250 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
11251 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
11252 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
11253 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
11254 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
11255 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
11256 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
11257 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
11258 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
11259 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
11260 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
11261 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
11262
11263 if (pDbgState->bmXcptExtra)
11264 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11265
11266 /*
11267 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
11268 *
11269 * Note! This is the reverse of what hmR0VmxHandleExitDtraceEvents does.
11270 * So, when adding/changing/removing please don't forget to update it.
11271 *
11272 * Some of the macros are picking up local variables to save horizontal space,
11273 * (being able to see it in a table is the lesser evil here).
11274 */
11275#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
11276 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
11277 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
11278#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
11279 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11280 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11281 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11282 } else do { } while (0)
11283#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
11284 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11285 { \
11286 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
11287 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11288 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11289 } else do { } while (0)
11290#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
11291 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11292 { \
11293 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
11294 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11295 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11296 } else do { } while (0)
11297#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
11298 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11299 { \
11300 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
11301 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11302 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11303 } else do { } while (0)
11304
11305 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
11306 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
11307 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
11308 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
11309 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
11310
11311 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
11312 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
11313 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
11314 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
11315 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_PROC_CTLS_HLT_EXIT); /* paranoia */
11316 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
11317 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
11318 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
11319 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_PROC_CTLS_INVLPG_EXIT);
11320 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
11321 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_PROC_CTLS_RDPMC_EXIT);
11322 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
11323 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_PROC_CTLS_RDTSC_EXIT);
11324 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
11325 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
11326 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
11327 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
11328 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
11329 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
11330 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
11331 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
11332 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
11333 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
11334 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
11335 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
11336 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
11337 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
11338 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
11339 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
11340 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
11341 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
11342 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
11343 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
11344 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
11345 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
11346 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
11347
11348 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
11349 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11350 {
11351 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4
11352 | CPUMCTX_EXTRN_APIC_TPR);
11353 AssertRC(rc);
11354
11355#if 0 /** @todo fix me */
11356 pDbgState->fClearCr0Mask = true;
11357 pDbgState->fClearCr4Mask = true;
11358#endif
11359 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
11360 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_STORE_EXIT | VMX_PROC_CTLS_CR8_STORE_EXIT;
11361 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11362 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_LOAD_EXIT | VMX_PROC_CTLS_CR8_LOAD_EXIT;
11363 pDbgState->fCpe1Unwanted |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* risky? */
11364 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
11365 require clearing here and in the loop if we start using it. */
11366 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
11367 }
11368 else
11369 {
11370 if (pDbgState->fClearCr0Mask)
11371 {
11372 pDbgState->fClearCr0Mask = false;
11373 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR0);
11374 }
11375 if (pDbgState->fClearCr4Mask)
11376 {
11377 pDbgState->fClearCr4Mask = false;
11378 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR4);
11379 }
11380 }
11381 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
11382 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
11383
11384 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
11385 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
11386 {
11387 /** @todo later, need to fix handler as it assumes this won't usually happen. */
11388 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
11389 }
11390 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
11391 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
11392
11393 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS); /* risky clearing this? */
11394 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
11395 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS);
11396 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
11397 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_PROC_CTLS_MWAIT_EXIT); /* paranoia */
11398 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
11399 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_PROC_CTLS_MONITOR_EXIT); /* paranoia */
11400 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
11401#if 0 /** @todo too slow, fix handler. */
11402 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_PROC_CTLS_PAUSE_EXIT);
11403#endif
11404 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
11405
11406 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
11407 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
11408 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
11409 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
11410 {
11411 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11412 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_GDTR_IDTR_ACCESS);
11413 }
11414 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11415 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11416 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11417 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11418
11419 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
11420 || IS_EITHER_ENABLED(pVM, INSTR_STR)
11421 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
11422 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
11423 {
11424 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11425 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_LDTR_TR_ACCESS);
11426 }
11427 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_LDTR_TR_ACCESS);
11428 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_LDTR_TR_ACCESS);
11429 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_LDTR_TR_ACCESS);
11430 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_LDTR_TR_ACCESS);
11431
11432 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
11433 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
11434 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_PROC_CTLS_RDTSC_EXIT);
11435 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
11436 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
11437 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
11438 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_PROC_CTLS2_WBINVD_EXIT);
11439 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
11440 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
11441 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
11442 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_PROC_CTLS2_RDRAND_EXIT);
11443 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
11444 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_PROC_CTLS_INVLPG_EXIT);
11445 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
11446 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
11447 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
11448 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_PROC_CTLS2_RDSEED_EXIT);
11449 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
11450 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
11451 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
11452 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
11453 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
11454
11455#undef IS_EITHER_ENABLED
11456#undef SET_ONLY_XBM_IF_EITHER_EN
11457#undef SET_CPE1_XBM_IF_EITHER_EN
11458#undef SET_CPEU_XBM_IF_EITHER_EN
11459#undef SET_CPE2_XBM_IF_EITHER_EN
11460
11461 /*
11462 * Sanitize the control stuff.
11463 */
11464 pDbgState->fCpe2Extra &= pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1;
11465 if (pDbgState->fCpe2Extra)
11466 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
11467 pDbgState->fCpe1Extra &= pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1;
11468 pDbgState->fCpe1Unwanted &= ~pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0;
11469 if (pVCpu->hm.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_PROC_CTLS_RDTSC_EXIT))
11470 {
11471 pVCpu->hm.s.fDebugWantRdTscExit ^= true;
11472 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
11473 }
11474
11475 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
11476 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
11477 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
11478 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
11479}
11480
11481
11482/**
11483 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
11484 * appropriate.
11485 *
11486 * The caller has checked the VM-exit against the
11487 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
11488 * already, so we don't have to do that either.
11489 *
11490 * @returns Strict VBox status code (i.e. informational status codes too).
11491 * @param pVCpu The cross context virtual CPU structure.
11492 * @param pVmxTransient The VMX-transient structure.
11493 * @param uExitReason The VM-exit reason.
11494 *
11495 * @remarks The name of this function is displayed by dtrace, so keep it short
11496 * and to the point. No longer than 33 chars long, please.
11497 */
11498static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
11499{
11500 /*
11501 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
11502 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
11503 *
11504 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
11505 * does. Must add/change/remove both places. Same ordering, please.
11506 *
11507 * Added/removed events must also be reflected in the next section
11508 * where we dispatch dtrace events.
11509 */
11510 bool fDtrace1 = false;
11511 bool fDtrace2 = false;
11512 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
11513 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
11514 uint32_t uEventArg = 0;
11515#define SET_EXIT(a_EventSubName) \
11516 do { \
11517 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11518 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11519 } while (0)
11520#define SET_BOTH(a_EventSubName) \
11521 do { \
11522 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
11523 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11524 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
11525 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11526 } while (0)
11527 switch (uExitReason)
11528 {
11529 case VMX_EXIT_MTF:
11530 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
11531
11532 case VMX_EXIT_XCPT_OR_NMI:
11533 {
11534 uint8_t const idxVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
11535 switch (VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo))
11536 {
11537 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
11538 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
11539 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
11540 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
11541 {
11542 if (VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uExitIntInfo))
11543 {
11544 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
11545 uEventArg = pVmxTransient->uExitIntErrorCode;
11546 }
11547 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
11548 switch (enmEvent1)
11549 {
11550 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
11551 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
11552 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
11553 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
11554 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
11555 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
11556 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
11557 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
11558 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
11559 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
11560 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
11561 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
11562 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
11563 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
11564 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
11565 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
11566 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
11567 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
11568 default: break;
11569 }
11570 }
11571 else
11572 AssertFailed();
11573 break;
11574
11575 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
11576 uEventArg = idxVector;
11577 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
11578 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
11579 break;
11580 }
11581 break;
11582 }
11583
11584 case VMX_EXIT_TRIPLE_FAULT:
11585 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
11586 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
11587 break;
11588 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
11589 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
11590 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
11591 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
11592 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
11593
11594 /* Instruction specific VM-exits: */
11595 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
11596 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
11597 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
11598 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
11599 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
11600 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
11601 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
11602 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
11603 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
11604 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
11605 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
11606 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
11607 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
11608 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
11609 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
11610 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
11611 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
11612 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
11613 case VMX_EXIT_MOV_CRX:
11614 hmR0VmxReadExitQualVmcs(pVmxTransient);
11615 if (VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_CRX_ACCESS_READ)
11616 SET_BOTH(CRX_READ);
11617 else
11618 SET_BOTH(CRX_WRITE);
11619 uEventArg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
11620 break;
11621 case VMX_EXIT_MOV_DRX:
11622 hmR0VmxReadExitQualVmcs(pVmxTransient);
11623 if ( VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual)
11624 == VMX_EXIT_QUAL_DRX_DIRECTION_READ)
11625 SET_BOTH(DRX_READ);
11626 else
11627 SET_BOTH(DRX_WRITE);
11628 uEventArg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
11629 break;
11630 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
11631 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
11632 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
11633 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
11634 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
11635 case VMX_EXIT_GDTR_IDTR_ACCESS:
11636 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
11637 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_XDTR_INSINFO_INSTR_ID))
11638 {
11639 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
11640 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
11641 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
11642 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
11643 }
11644 break;
11645
11646 case VMX_EXIT_LDTR_TR_ACCESS:
11647 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
11648 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_YYTR_INSINFO_INSTR_ID))
11649 {
11650 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
11651 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
11652 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
11653 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
11654 }
11655 break;
11656
11657 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
11658 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
11659 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
11660 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
11661 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
11662 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
11663 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
11664 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
11665 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
11666 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
11667 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
11668
11669 /* Events that aren't relevant at this point. */
11670 case VMX_EXIT_EXT_INT:
11671 case VMX_EXIT_INT_WINDOW:
11672 case VMX_EXIT_NMI_WINDOW:
11673 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11674 case VMX_EXIT_PREEMPT_TIMER:
11675 case VMX_EXIT_IO_INSTR:
11676 break;
11677
11678 /* Errors and unexpected events. */
11679 case VMX_EXIT_INIT_SIGNAL:
11680 case VMX_EXIT_SIPI:
11681 case VMX_EXIT_IO_SMI:
11682 case VMX_EXIT_SMI:
11683 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
11684 case VMX_EXIT_ERR_MSR_LOAD:
11685 case VMX_EXIT_ERR_MACHINE_CHECK:
11686 case VMX_EXIT_PML_FULL:
11687 case VMX_EXIT_VIRTUALIZED_EOI:
11688 break;
11689
11690 default:
11691 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
11692 break;
11693 }
11694#undef SET_BOTH
11695#undef SET_EXIT
11696
11697 /*
11698 * Dtrace tracepoints go first. We do them here at once so we don't
11699 * have to copy the guest state saving and stuff a few dozen times.
11700 * Down side is that we've got to repeat the switch, though this time
11701 * we use enmEvent since the probes are a subset of what DBGF does.
11702 */
11703 if (fDtrace1 || fDtrace2)
11704 {
11705 hmR0VmxReadExitQualVmcs(pVmxTransient);
11706 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
11707 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
11708 switch (enmEvent1)
11709 {
11710 /** @todo consider which extra parameters would be helpful for each probe. */
11711 case DBGFEVENT_END: break;
11712 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pCtx); break;
11713 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pCtx, pCtx->dr[6]); break;
11714 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pCtx); break;
11715 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pCtx); break;
11716 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pCtx); break;
11717 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pCtx); break;
11718 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pCtx); break;
11719 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pCtx); break;
11720 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pCtx, uEventArg); break;
11721 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pCtx, uEventArg); break;
11722 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pCtx, uEventArg); break;
11723 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pCtx, uEventArg); break;
11724 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pCtx, uEventArg, pCtx->cr2); break;
11725 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pCtx); break;
11726 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pCtx); break;
11727 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pCtx); break;
11728 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pCtx); break;
11729 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pCtx, uEventArg); break;
11730 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11731 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11732 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pCtx); break;
11733 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pCtx); break;
11734 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pCtx); break;
11735 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pCtx); break;
11736 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pCtx); break;
11737 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pCtx); break;
11738 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pCtx); break;
11739 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11740 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11741 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11742 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11743 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11744 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pCtx, pCtx->ecx,
11745 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11746 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pCtx); break;
11747 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pCtx); break;
11748 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pCtx); break;
11749 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pCtx); break;
11750 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pCtx); break;
11751 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pCtx); break;
11752 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pCtx); break;
11753 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pCtx); break;
11754 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pCtx); break;
11755 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pCtx); break;
11756 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pCtx); break;
11757 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pCtx); break;
11758 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pCtx); break;
11759 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pCtx); break;
11760 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pCtx); break;
11761 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pCtx); break;
11762 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pCtx); break;
11763 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pCtx); break;
11764 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pCtx); break;
11765 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pCtx); break;
11766 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pCtx); break;
11767 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pCtx); break;
11768 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pCtx); break;
11769 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pCtx); break;
11770 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pCtx); break;
11771 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pCtx); break;
11772 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pCtx); break;
11773 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pCtx); break;
11774 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pCtx); break;
11775 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pCtx); break;
11776 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pCtx); break;
11777 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pCtx); break;
11778 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
11779 }
11780 switch (enmEvent2)
11781 {
11782 /** @todo consider which extra parameters would be helpful for each probe. */
11783 case DBGFEVENT_END: break;
11784 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pCtx); break;
11785 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11786 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pCtx); break;
11787 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pCtx); break;
11788 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pCtx); break;
11789 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pCtx); break;
11790 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pCtx); break;
11791 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pCtx); break;
11792 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pCtx); break;
11793 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11794 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11795 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11796 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11797 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11798 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pCtx, pCtx->ecx,
11799 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11800 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pCtx); break;
11801 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pCtx); break;
11802 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pCtx); break;
11803 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pCtx); break;
11804 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pCtx); break;
11805 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pCtx); break;
11806 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pCtx); break;
11807 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pCtx); break;
11808 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pCtx); break;
11809 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pCtx); break;
11810 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pCtx); break;
11811 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pCtx); break;
11812 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pCtx); break;
11813 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pCtx); break;
11814 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pCtx); break;
11815 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pCtx); break;
11816 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pCtx); break;
11817 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pCtx); break;
11818 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pCtx); break;
11819 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pCtx); break;
11820 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pCtx); break;
11821 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pCtx); break;
11822 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pCtx); break;
11823 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pCtx); break;
11824 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pCtx); break;
11825 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pCtx); break;
11826 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pCtx); break;
11827 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pCtx); break;
11828 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pCtx); break;
11829 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pCtx); break;
11830 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pCtx); break;
11831 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pCtx); break;
11832 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pCtx); break;
11833 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pCtx); break;
11834 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pCtx); break;
11835 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pCtx); break;
11836 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
11837 }
11838 }
11839
11840 /*
11841 * Fire of the DBGF event, if enabled (our check here is just a quick one,
11842 * the DBGF call will do a full check).
11843 *
11844 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
11845 * Note! If we have to events, we prioritize the first, i.e. the instruction
11846 * one, in order to avoid event nesting.
11847 */
11848 PVM pVM = pVCpu->CTX_SUFF(pVM);
11849 if ( enmEvent1 != DBGFEVENT_END
11850 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
11851 {
11852 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11853 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent1, DBGFEVENTCTX_HM, 1, uEventArg);
11854 if (rcStrict != VINF_SUCCESS)
11855 return rcStrict;
11856 }
11857 else if ( enmEvent2 != DBGFEVENT_END
11858 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
11859 {
11860 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11861 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent2, DBGFEVENTCTX_HM, 1, uEventArg);
11862 if (rcStrict != VINF_SUCCESS)
11863 return rcStrict;
11864 }
11865
11866 return VINF_SUCCESS;
11867}
11868
11869
11870/**
11871 * Single-stepping VM-exit filtering.
11872 *
11873 * This is preprocessing the VM-exits and deciding whether we've gotten far
11874 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
11875 * handling is performed.
11876 *
11877 * @returns Strict VBox status code (i.e. informational status codes too).
11878 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
11879 * @param pVmxTransient The VMX-transient structure.
11880 * @param pDbgState The debug state.
11881 */
11882DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11883{
11884 /*
11885 * Expensive (saves context) generic dtrace VM-exit probe.
11886 */
11887 uint32_t const uExitReason = pVmxTransient->uExitReason;
11888 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
11889 { /* more likely */ }
11890 else
11891 {
11892 hmR0VmxReadExitQualVmcs(pVmxTransient);
11893 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
11894 AssertRC(rc);
11895 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, &pVCpu->cpum.GstCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
11896 }
11897
11898 /*
11899 * Check for host NMI, just to get that out of the way.
11900 */
11901 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
11902 { /* normally likely */ }
11903 else
11904 {
11905 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
11906 uint32_t const uIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
11907 if (uIntType == VMX_EXIT_INT_INFO_TYPE_NMI)
11908 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
11909 }
11910
11911 /*
11912 * Check for single stepping event if we're stepping.
11913 */
11914 if (pVCpu->hm.s.fSingleInstruction)
11915 {
11916 switch (uExitReason)
11917 {
11918 case VMX_EXIT_MTF:
11919 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
11920
11921 /* Various events: */
11922 case VMX_EXIT_XCPT_OR_NMI:
11923 case VMX_EXIT_EXT_INT:
11924 case VMX_EXIT_TRIPLE_FAULT:
11925 case VMX_EXIT_INT_WINDOW:
11926 case VMX_EXIT_NMI_WINDOW:
11927 case VMX_EXIT_TASK_SWITCH:
11928 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11929 case VMX_EXIT_APIC_ACCESS:
11930 case VMX_EXIT_EPT_VIOLATION:
11931 case VMX_EXIT_EPT_MISCONFIG:
11932 case VMX_EXIT_PREEMPT_TIMER:
11933
11934 /* Instruction specific VM-exits: */
11935 case VMX_EXIT_CPUID:
11936 case VMX_EXIT_GETSEC:
11937 case VMX_EXIT_HLT:
11938 case VMX_EXIT_INVD:
11939 case VMX_EXIT_INVLPG:
11940 case VMX_EXIT_RDPMC:
11941 case VMX_EXIT_RDTSC:
11942 case VMX_EXIT_RSM:
11943 case VMX_EXIT_VMCALL:
11944 case VMX_EXIT_VMCLEAR:
11945 case VMX_EXIT_VMLAUNCH:
11946 case VMX_EXIT_VMPTRLD:
11947 case VMX_EXIT_VMPTRST:
11948 case VMX_EXIT_VMREAD:
11949 case VMX_EXIT_VMRESUME:
11950 case VMX_EXIT_VMWRITE:
11951 case VMX_EXIT_VMXOFF:
11952 case VMX_EXIT_VMXON:
11953 case VMX_EXIT_MOV_CRX:
11954 case VMX_EXIT_MOV_DRX:
11955 case VMX_EXIT_IO_INSTR:
11956 case VMX_EXIT_RDMSR:
11957 case VMX_EXIT_WRMSR:
11958 case VMX_EXIT_MWAIT:
11959 case VMX_EXIT_MONITOR:
11960 case VMX_EXIT_PAUSE:
11961 case VMX_EXIT_GDTR_IDTR_ACCESS:
11962 case VMX_EXIT_LDTR_TR_ACCESS:
11963 case VMX_EXIT_INVEPT:
11964 case VMX_EXIT_RDTSCP:
11965 case VMX_EXIT_INVVPID:
11966 case VMX_EXIT_WBINVD:
11967 case VMX_EXIT_XSETBV:
11968 case VMX_EXIT_RDRAND:
11969 case VMX_EXIT_INVPCID:
11970 case VMX_EXIT_VMFUNC:
11971 case VMX_EXIT_RDSEED:
11972 case VMX_EXIT_XSAVES:
11973 case VMX_EXIT_XRSTORS:
11974 {
11975 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11976 AssertRCReturn(rc, rc);
11977 if ( pVCpu->cpum.GstCtx.rip != pDbgState->uRipStart
11978 || pVCpu->cpum.GstCtx.cs.Sel != pDbgState->uCsStart)
11979 return VINF_EM_DBG_STEPPED;
11980 break;
11981 }
11982
11983 /* Errors and unexpected events: */
11984 case VMX_EXIT_INIT_SIGNAL:
11985 case VMX_EXIT_SIPI:
11986 case VMX_EXIT_IO_SMI:
11987 case VMX_EXIT_SMI:
11988 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
11989 case VMX_EXIT_ERR_MSR_LOAD:
11990 case VMX_EXIT_ERR_MACHINE_CHECK:
11991 case VMX_EXIT_PML_FULL:
11992 case VMX_EXIT_VIRTUALIZED_EOI:
11993 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
11994 break;
11995
11996 default:
11997 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
11998 break;
11999 }
12000 }
12001
12002 /*
12003 * Check for debugger event breakpoints and dtrace probes.
12004 */
12005 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
12006 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
12007 {
12008 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVCpu, pVmxTransient, uExitReason);
12009 if (rcStrict != VINF_SUCCESS)
12010 return rcStrict;
12011 }
12012
12013 /*
12014 * Normal processing.
12015 */
12016#ifdef HMVMX_USE_FUNCTION_TABLE
12017 return g_apfnVMExitHandlers[uExitReason](pVCpu, pVmxTransient);
12018#else
12019 return hmR0VmxHandleExit(pVCpu, pVmxTransient, uExitReason);
12020#endif
12021}
12022
12023
12024/**
12025 * Single steps guest code using hardware-assisted VMX.
12026 *
12027 * This is -not- the same as the guest single-stepping itself (say using EFLAGS.TF)
12028 * but single-stepping through the hypervisor debugger.
12029 *
12030 * @returns Strict VBox status code (i.e. informational status codes too).
12031 * @param pVCpu The cross context virtual CPU structure.
12032 * @param pcLoops Pointer to the number of executed loops.
12033 *
12034 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
12035 */
12036static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVMCPU pVCpu, uint32_t *pcLoops)
12037{
12038 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
12039 Assert(pcLoops);
12040 Assert(*pcLoops <= cMaxResumeLoops);
12041
12042 VMXTRANSIENT VmxTransient;
12043 RT_ZERO(VmxTransient);
12044 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
12045
12046 /* Set HMCPU indicators. */
12047 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
12048 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
12049 pVCpu->hm.s.fDebugWantRdTscExit = false;
12050 pVCpu->hm.s.fUsingDebugLoop = true;
12051
12052 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
12053 VMXRUNDBGSTATE DbgState;
12054 hmR0VmxRunDebugStateInit(pVCpu, &VmxTransient, &DbgState);
12055 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12056
12057 /*
12058 * The loop.
12059 */
12060 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
12061 for (;;)
12062 {
12063 Assert(!HMR0SuspendPending());
12064 HMVMX_ASSERT_CPU_SAFE(pVCpu);
12065 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
12066 bool fStepping = pVCpu->hm.s.fSingleInstruction;
12067
12068 /* Set up VM-execution controls the next two can respond to. */
12069 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12070
12071 /*
12072 * Preparatory work for running guest code, this may force us to
12073 * return to ring-3.
12074 *
12075 * Warning! This bugger disables interrupts on VINF_SUCCESS!
12076 */
12077 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, fStepping);
12078 if (rcStrict != VINF_SUCCESS)
12079 break;
12080
12081 /* Interrupts are disabled at this point! */
12082 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
12083
12084 /* Override any obnoxious code in the above two calls. */
12085 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12086
12087 /*
12088 * Finally execute the guest.
12089 */
12090 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
12091
12092 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
12093 /* Interrupts are re-enabled at this point! */
12094
12095 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
12096 if (RT_SUCCESS(rcRun))
12097 { /* very likely */ }
12098 else
12099 {
12100 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
12101 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
12102 return rcRun;
12103 }
12104
12105 /* Profile the VM-exit. */
12106 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
12107 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
12108 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
12109 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
12110 HMVMX_START_EXIT_DISPATCH_PROF();
12111
12112 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
12113
12114 /*
12115 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
12116 */
12117 rcStrict = hmR0VmxRunDebugHandleExit(pVCpu, &VmxTransient, &DbgState);
12118 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
12119 if (rcStrict != VINF_SUCCESS)
12120 break;
12121 if (++(*pcLoops) > cMaxResumeLoops)
12122 {
12123 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
12124 rcStrict = VINF_EM_RAW_INTERRUPT;
12125 break;
12126 }
12127
12128 /*
12129 * Stepping: Did the RIP change, if so, consider it a single step.
12130 * Otherwise, make sure one of the TFs gets set.
12131 */
12132 if (fStepping)
12133 {
12134 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12135 AssertRC(rc);
12136 if ( pVCpu->cpum.GstCtx.rip != DbgState.uRipStart
12137 || pVCpu->cpum.GstCtx.cs.Sel != DbgState.uCsStart)
12138 {
12139 rcStrict = VINF_EM_DBG_STEPPED;
12140 break;
12141 }
12142 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
12143 }
12144
12145 /*
12146 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
12147 */
12148 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
12149 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12150 }
12151
12152 /*
12153 * Clear the X86_EFL_TF if necessary.
12154 */
12155 if (pVCpu->hm.s.fClearTrapFlag)
12156 {
12157 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
12158 AssertRC(rc);
12159 pVCpu->hm.s.fClearTrapFlag = false;
12160 pVCpu->cpum.GstCtx.eflags.Bits.u1TF = 0;
12161 }
12162 /** @todo there seems to be issues with the resume flag when the monitor trap
12163 * flag is pending without being used. Seen early in bios init when
12164 * accessing APIC page in protected mode. */
12165
12166 /*
12167 * Restore VM-exit control settings as we may not re-enter this function the
12168 * next time around.
12169 */
12170 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &VmxTransient, &DbgState, rcStrict);
12171
12172 /* Restore HMCPU indicators. */
12173 pVCpu->hm.s.fUsingDebugLoop = false;
12174 pVCpu->hm.s.fDebugWantRdTscExit = false;
12175 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
12176
12177 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
12178 return rcStrict;
12179}
12180
12181
12182/** @} */
12183
12184
12185/**
12186 * Checks if any expensive dtrace probes are enabled and we should go to the
12187 * debug loop.
12188 *
12189 * @returns true if we should use debug loop, false if not.
12190 */
12191static bool hmR0VmxAnyExpensiveProbesEnabled(void)
12192{
12193 /* It's probably faster to OR the raw 32-bit counter variables together.
12194 Since the variables are in an array and the probes are next to one
12195 another (more or less), we have good locality. So, better read
12196 eight-nine cache lines ever time and only have one conditional, than
12197 128+ conditionals, right? */
12198 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
12199 | VBOXVMM_XCPT_DE_ENABLED_RAW()
12200 | VBOXVMM_XCPT_DB_ENABLED_RAW()
12201 | VBOXVMM_XCPT_BP_ENABLED_RAW()
12202 | VBOXVMM_XCPT_OF_ENABLED_RAW()
12203 | VBOXVMM_XCPT_BR_ENABLED_RAW()
12204 | VBOXVMM_XCPT_UD_ENABLED_RAW()
12205 | VBOXVMM_XCPT_NM_ENABLED_RAW()
12206 | VBOXVMM_XCPT_DF_ENABLED_RAW()
12207 | VBOXVMM_XCPT_TS_ENABLED_RAW()
12208 | VBOXVMM_XCPT_NP_ENABLED_RAW()
12209 | VBOXVMM_XCPT_SS_ENABLED_RAW()
12210 | VBOXVMM_XCPT_GP_ENABLED_RAW()
12211 | VBOXVMM_XCPT_PF_ENABLED_RAW()
12212 | VBOXVMM_XCPT_MF_ENABLED_RAW()
12213 | VBOXVMM_XCPT_AC_ENABLED_RAW()
12214 | VBOXVMM_XCPT_XF_ENABLED_RAW()
12215 | VBOXVMM_XCPT_VE_ENABLED_RAW()
12216 | VBOXVMM_XCPT_SX_ENABLED_RAW()
12217 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
12218 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
12219 ) != 0
12220 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
12221 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
12222 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
12223 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
12224 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
12225 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
12226 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
12227 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
12228 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
12229 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
12230 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
12231 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
12232 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
12233 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
12234 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
12235 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
12236 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
12237 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
12238 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
12239 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
12240 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
12241 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
12242 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
12243 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
12244 | VBOXVMM_INSTR_STR_ENABLED_RAW()
12245 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
12246 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
12247 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
12248 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
12249 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
12250 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
12251 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
12252 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
12253 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
12254 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
12255 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
12256 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
12257 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
12258 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
12259 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
12260 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
12261 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
12262 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
12263 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
12264 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
12265 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
12266 ) != 0
12267 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
12268 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
12269 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
12270 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
12271 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
12272 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
12273 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
12274 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
12275 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
12276 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
12277 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
12278 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
12279 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
12280 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
12281 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
12282 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
12283 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
12284 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
12285 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
12286 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
12287 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
12288 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
12289 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
12290 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
12291 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
12292 | VBOXVMM_EXIT_STR_ENABLED_RAW()
12293 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
12294 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
12295 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
12296 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
12297 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
12298 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
12299 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
12300 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
12301 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
12302 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
12303 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
12304 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
12305 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
12306 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
12307 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
12308 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
12309 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
12310 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
12311 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
12312 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
12313 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
12314 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
12315 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
12316 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
12317 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
12318 ) != 0;
12319}
12320
12321
12322/**
12323 * Runs the guest using hardware-assisted VMX.
12324 *
12325 * @returns Strict VBox status code (i.e. informational status codes too).
12326 * @param pVCpu The cross context virtual CPU structure.
12327 */
12328VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVMCPU pVCpu)
12329{
12330 AssertPtr(pVCpu);
12331 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12332 Assert(VMMRZCallRing3IsEnabled(pVCpu));
12333 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12334 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
12335
12336 VMMRZCallRing3SetNotification(pVCpu, hmR0VmxCallRing3Callback, pCtx);
12337
12338 VBOXSTRICTRC rcStrict;
12339 uint32_t cLoops = 0;
12340 for (;;)
12341 {
12342#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12343 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(pCtx);
12344#else
12345 bool const fInNestedGuestMode = false;
12346#endif
12347 if (!fInNestedGuestMode)
12348 {
12349 if ( !pVCpu->hm.s.fUseDebugLoop
12350 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
12351 && !DBGFIsStepping(pVCpu)
12352 && !pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
12353 rcStrict = hmR0VmxRunGuestCodeNormal(pVCpu, &cLoops);
12354 else
12355 rcStrict = hmR0VmxRunGuestCodeDebug(pVCpu, &cLoops);
12356 }
12357#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12358 else
12359 rcStrict = hmR0VmxRunGuestCodeNested(pVCpu, &cLoops);
12360
12361 if (rcStrict == VINF_VMX_VMLAUNCH_VMRESUME)
12362 {
12363 Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
12364 continue;
12365 }
12366 if (rcStrict == VINF_VMX_VMEXIT)
12367 {
12368 Assert(!CPUMIsGuestInVmxNonRootMode(pCtx));
12369 continue;
12370 }
12371#endif
12372 break;
12373 }
12374
12375 int const rcLoop = VBOXSTRICTRC_VAL(rcStrict);
12376 switch (rcLoop)
12377 {
12378 case VERR_EM_INTERPRETER: rcStrict = VINF_EM_RAW_EMULATE_INSTR; break;
12379 case VINF_EM_RESET: rcStrict = VINF_EM_TRIPLE_FAULT; break;
12380 }
12381
12382 int rc2 = hmR0VmxExitToRing3(pVCpu, rcStrict);
12383 if (RT_FAILURE(rc2))
12384 {
12385 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
12386 rcStrict = rc2;
12387 }
12388 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12389 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
12390 return rcStrict;
12391}
12392
12393
12394#ifndef HMVMX_USE_FUNCTION_TABLE
12395/**
12396 * Handles a guest VM-exit from hardware-assisted VMX execution.
12397 *
12398 * @returns Strict VBox status code (i.e. informational status codes too).
12399 * @param pVCpu The cross context virtual CPU structure.
12400 * @param pVmxTransient The VMX-transient structure.
12401 */
12402DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
12403{
12404#ifdef DEBUG_ramshankar
12405#define VMEXIT_CALL_RET(a_fSave, a_CallExpr) \
12406 do { \
12407 if (a_fSave != 0) \
12408 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL); \
12409 VBOXSTRICTRC rcStrict = a_CallExpr; \
12410 if (a_fSave != 0) \
12411 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST); \
12412 return rcStrict; \
12413 } while (0)
12414#else
12415# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) return a_CallExpr
12416#endif
12417 uint32_t const uExitReason = pVmxTransient->uExitReason;
12418 switch (uExitReason)
12419 {
12420 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient));
12421 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, hmR0VmxExitEptViolation(pVCpu, pVmxTransient));
12422 case VMX_EXIT_IO_INSTR: VMEXIT_CALL_RET(0, hmR0VmxExitIoInstr(pVCpu, pVmxTransient));
12423 case VMX_EXIT_CPUID: VMEXIT_CALL_RET(0, hmR0VmxExitCpuid(pVCpu, pVmxTransient));
12424 case VMX_EXIT_RDTSC: VMEXIT_CALL_RET(0, hmR0VmxExitRdtsc(pVCpu, pVmxTransient));
12425 case VMX_EXIT_RDTSCP: VMEXIT_CALL_RET(0, hmR0VmxExitRdtscp(pVCpu, pVmxTransient));
12426 case VMX_EXIT_APIC_ACCESS: VMEXIT_CALL_RET(0, hmR0VmxExitApicAccess(pVCpu, pVmxTransient));
12427 case VMX_EXIT_XCPT_OR_NMI: VMEXIT_CALL_RET(0, hmR0VmxExitXcptOrNmi(pVCpu, pVmxTransient));
12428 case VMX_EXIT_MOV_CRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovCRx(pVCpu, pVmxTransient));
12429 case VMX_EXIT_EXT_INT: VMEXIT_CALL_RET(0, hmR0VmxExitExtInt(pVCpu, pVmxTransient));
12430 case VMX_EXIT_INT_WINDOW: VMEXIT_CALL_RET(0, hmR0VmxExitIntWindow(pVCpu, pVmxTransient));
12431 case VMX_EXIT_TPR_BELOW_THRESHOLD: VMEXIT_CALL_RET(0, hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient));
12432 case VMX_EXIT_MWAIT: VMEXIT_CALL_RET(0, hmR0VmxExitMwait(pVCpu, pVmxTransient));
12433 case VMX_EXIT_MONITOR: VMEXIT_CALL_RET(0, hmR0VmxExitMonitor(pVCpu, pVmxTransient));
12434 case VMX_EXIT_TASK_SWITCH: VMEXIT_CALL_RET(0, hmR0VmxExitTaskSwitch(pVCpu, pVmxTransient));
12435 case VMX_EXIT_PREEMPT_TIMER: VMEXIT_CALL_RET(0, hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient));
12436 case VMX_EXIT_RDMSR: VMEXIT_CALL_RET(0, hmR0VmxExitRdmsr(pVCpu, pVmxTransient));
12437 case VMX_EXIT_WRMSR: VMEXIT_CALL_RET(0, hmR0VmxExitWrmsr(pVCpu, pVmxTransient));
12438 case VMX_EXIT_VMCALL: VMEXIT_CALL_RET(0, hmR0VmxExitVmcall(pVCpu, pVmxTransient));
12439 case VMX_EXIT_MOV_DRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovDRx(pVCpu, pVmxTransient));
12440 case VMX_EXIT_HLT: VMEXIT_CALL_RET(0, hmR0VmxExitHlt(pVCpu, pVmxTransient));
12441 case VMX_EXIT_INVD: VMEXIT_CALL_RET(0, hmR0VmxExitInvd(pVCpu, pVmxTransient));
12442 case VMX_EXIT_INVLPG: VMEXIT_CALL_RET(0, hmR0VmxExitInvlpg(pVCpu, pVmxTransient));
12443 case VMX_EXIT_MTF: VMEXIT_CALL_RET(0, hmR0VmxExitMtf(pVCpu, pVmxTransient));
12444 case VMX_EXIT_PAUSE: VMEXIT_CALL_RET(0, hmR0VmxExitPause(pVCpu, pVmxTransient));
12445 case VMX_EXIT_WBINVD: VMEXIT_CALL_RET(0, hmR0VmxExitWbinvd(pVCpu, pVmxTransient));
12446 case VMX_EXIT_XSETBV: VMEXIT_CALL_RET(0, hmR0VmxExitXsetbv(pVCpu, pVmxTransient));
12447 case VMX_EXIT_INVPCID: VMEXIT_CALL_RET(0, hmR0VmxExitInvpcid(pVCpu, pVmxTransient));
12448 case VMX_EXIT_GETSEC: VMEXIT_CALL_RET(0, hmR0VmxExitGetsec(pVCpu, pVmxTransient));
12449 case VMX_EXIT_RDPMC: VMEXIT_CALL_RET(0, hmR0VmxExitRdpmc(pVCpu, pVmxTransient));
12450#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12451 case VMX_EXIT_VMCLEAR: VMEXIT_CALL_RET(0, hmR0VmxExitVmclear(pVCpu, pVmxTransient));
12452 case VMX_EXIT_VMLAUNCH: VMEXIT_CALL_RET(0, hmR0VmxExitVmlaunch(pVCpu, pVmxTransient));
12453 case VMX_EXIT_VMPTRLD: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrld(pVCpu, pVmxTransient));
12454 case VMX_EXIT_VMPTRST: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrst(pVCpu, pVmxTransient));
12455 case VMX_EXIT_VMREAD: VMEXIT_CALL_RET(0, hmR0VmxExitVmread(pVCpu, pVmxTransient));
12456 case VMX_EXIT_VMRESUME: VMEXIT_CALL_RET(0, hmR0VmxExitVmwrite(pVCpu, pVmxTransient));
12457 case VMX_EXIT_VMWRITE: VMEXIT_CALL_RET(0, hmR0VmxExitVmresume(pVCpu, pVmxTransient));
12458 case VMX_EXIT_VMXOFF: VMEXIT_CALL_RET(0, hmR0VmxExitVmxoff(pVCpu, pVmxTransient));
12459 case VMX_EXIT_VMXON: VMEXIT_CALL_RET(0, hmR0VmxExitVmxon(pVCpu, pVmxTransient));
12460 case VMX_EXIT_INVVPID: VMEXIT_CALL_RET(0, hmR0VmxExitInvvpid(pVCpu, pVmxTransient));
12461 case VMX_EXIT_INVEPT: VMEXIT_CALL_RET(0, hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient));
12462#else
12463 case VMX_EXIT_VMCLEAR:
12464 case VMX_EXIT_VMLAUNCH:
12465 case VMX_EXIT_VMPTRLD:
12466 case VMX_EXIT_VMPTRST:
12467 case VMX_EXIT_VMREAD:
12468 case VMX_EXIT_VMRESUME:
12469 case VMX_EXIT_VMWRITE:
12470 case VMX_EXIT_VMXOFF:
12471 case VMX_EXIT_VMXON:
12472 case VMX_EXIT_INVVPID:
12473 case VMX_EXIT_INVEPT:
12474 return hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient);
12475#endif
12476
12477 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pVmxTransient);
12478 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pVmxTransient);
12479 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
12480
12481 case VMX_EXIT_INIT_SIGNAL:
12482 case VMX_EXIT_SIPI:
12483 case VMX_EXIT_IO_SMI:
12484 case VMX_EXIT_SMI:
12485 case VMX_EXIT_ERR_MSR_LOAD:
12486 case VMX_EXIT_ERR_MACHINE_CHECK:
12487 case VMX_EXIT_PML_FULL:
12488 case VMX_EXIT_VIRTUALIZED_EOI:
12489 case VMX_EXIT_GDTR_IDTR_ACCESS:
12490 case VMX_EXIT_LDTR_TR_ACCESS:
12491 case VMX_EXIT_APIC_WRITE:
12492 case VMX_EXIT_RDRAND:
12493 case VMX_EXIT_RSM:
12494 case VMX_EXIT_VMFUNC:
12495 case VMX_EXIT_ENCLS:
12496 case VMX_EXIT_RDSEED:
12497 case VMX_EXIT_XSAVES:
12498 case VMX_EXIT_XRSTORS:
12499 case VMX_EXIT_UMWAIT:
12500 case VMX_EXIT_TPAUSE:
12501 default:
12502 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
12503 }
12504#undef VMEXIT_CALL_RET
12505}
12506#endif /* !HMVMX_USE_FUNCTION_TABLE */
12507
12508
12509#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12510/**
12511 * Handles a nested-guest VM-exit from hardware-assisted VMX execution.
12512 *
12513 * @returns Strict VBox status code (i.e. informational status codes too).
12514 * @param pVCpu The cross context virtual CPU structure.
12515 * @param pVmxTransient The VMX-transient structure.
12516 */
12517DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
12518{
12519 uint32_t const uExitReason = pVmxTransient->uExitReason;
12520 switch (uExitReason)
12521 {
12522 case VMX_EXIT_EPT_MISCONFIG: return hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient);
12523 case VMX_EXIT_EPT_VIOLATION: return hmR0VmxExitEptViolation(pVCpu, pVmxTransient);
12524 case VMX_EXIT_XCPT_OR_NMI: return hmR0VmxExitXcptOrNmiNested(pVCpu, pVmxTransient);
12525 case VMX_EXIT_IO_INSTR: return hmR0VmxExitIoInstrNested(pVCpu, pVmxTransient);
12526 case VMX_EXIT_HLT: return hmR0VmxExitHltNested(pVCpu, pVmxTransient);
12527
12528 /*
12529 * We shouldn't direct host physical interrupts to the nested-guest.
12530 */
12531 case VMX_EXIT_EXT_INT:
12532 return hmR0VmxExitExtInt(pVCpu, pVmxTransient);
12533
12534 /*
12535 * Instructions that cause VM-exits unconditionally or the condition is
12536 * always is taken solely from the guest hypervisor (meaning if the VM-exit
12537 * happens, it's guaranteed to be a nested-guest VM-exit).
12538 *
12539 * - Provides VM-exit instruction length ONLY.
12540 */
12541 case VMX_EXIT_CPUID: /* Unconditional. */
12542 case VMX_EXIT_VMCALL:
12543 case VMX_EXIT_GETSEC:
12544 case VMX_EXIT_INVD:
12545 case VMX_EXIT_XSETBV:
12546 case VMX_EXIT_VMLAUNCH:
12547 case VMX_EXIT_VMRESUME:
12548 case VMX_EXIT_VMXOFF:
12549 case VMX_EXIT_ENCLS: /* Condition specified solely by guest hypervisor. */
12550 case VMX_EXIT_VMFUNC:
12551 return hmR0VmxExitInstrNested(pVCpu, pVmxTransient);
12552
12553 /*
12554 * Instructions that cause VM-exits unconditionally or the condition is
12555 * always is taken solely from the guest hypervisor (meaning if the VM-exit
12556 * happens, it's guaranteed to be a nested-guest VM-exit).
12557 *
12558 * - Provides VM-exit instruction length.
12559 * - Provides VM-exit information.
12560 * - Optionally provides Exit qualification.
12561 *
12562 * Since Exit qualification is 0 for all VM-exits where it is not
12563 * applicable, reading and passing it to the guest should produce
12564 * defined behavior.
12565 *
12566 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
12567 */
12568 case VMX_EXIT_INVEPT: /* Unconditional. */
12569 case VMX_EXIT_INVVPID:
12570 case VMX_EXIT_VMCLEAR:
12571 case VMX_EXIT_VMPTRLD:
12572 case VMX_EXIT_VMPTRST:
12573 case VMX_EXIT_VMXON:
12574 case VMX_EXIT_GDTR_IDTR_ACCESS: /* Condition specified solely by guest hypervisor. */
12575 case VMX_EXIT_LDTR_TR_ACCESS:
12576 case VMX_EXIT_RDRAND:
12577 case VMX_EXIT_RDSEED:
12578 case VMX_EXIT_XSAVES:
12579 case VMX_EXIT_XRSTORS:
12580 case VMX_EXIT_UMWAIT:
12581 case VMX_EXIT_TPAUSE:
12582 return hmR0VmxExitInstrWithInfoNested(pVCpu, pVmxTransient);
12583
12584 case VMX_EXIT_RDTSC: return hmR0VmxExitRdtscNested(pVCpu, pVmxTransient);
12585 case VMX_EXIT_RDTSCP: return hmR0VmxExitRdtscpNested(pVCpu, pVmxTransient);
12586 case VMX_EXIT_RDMSR: return hmR0VmxExitRdmsrNested(pVCpu, pVmxTransient);
12587 case VMX_EXIT_WRMSR: return hmR0VmxExitWrmsrNested(pVCpu, pVmxTransient);
12588 case VMX_EXIT_INVLPG: return hmR0VmxExitInvlpgNested(pVCpu, pVmxTransient);
12589 case VMX_EXIT_INVPCID: return hmR0VmxExitInvpcidNested(pVCpu, pVmxTransient);
12590 case VMX_EXIT_TASK_SWITCH: return hmR0VmxExitTaskSwitchNested(pVCpu, pVmxTransient);
12591 case VMX_EXIT_WBINVD: return hmR0VmxExitWbinvdNested(pVCpu, pVmxTransient);
12592 case VMX_EXIT_MTF: return hmR0VmxExitMtfNested(pVCpu, pVmxTransient);
12593 case VMX_EXIT_APIC_ACCESS: return hmR0VmxExitApicAccessNested(pVCpu, pVmxTransient);
12594 case VMX_EXIT_APIC_WRITE: return hmR0VmxExitApicWriteNested(pVCpu, pVmxTransient);
12595 case VMX_EXIT_VIRTUALIZED_EOI: return hmR0VmxExitVirtEoiNested(pVCpu, pVmxTransient);
12596 case VMX_EXIT_MOV_CRX: return hmR0VmxExitMovCRxNested(pVCpu, pVmxTransient);
12597 case VMX_EXIT_INT_WINDOW: return hmR0VmxExitIntWindowNested(pVCpu, pVmxTransient);
12598 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindowNested(pVCpu, pVmxTransient);
12599 case VMX_EXIT_TPR_BELOW_THRESHOLD: return hmR0VmxExitTprBelowThresholdNested(pVCpu, pVmxTransient);
12600 case VMX_EXIT_MWAIT: return hmR0VmxExitMwaitNested(pVCpu, pVmxTransient);
12601 case VMX_EXIT_MONITOR: return hmR0VmxExitMonitorNested(pVCpu, pVmxTransient);
12602 case VMX_EXIT_PAUSE: return hmR0VmxExitPauseNested(pVCpu, pVmxTransient);
12603
12604 case VMX_EXIT_PREEMPT_TIMER:
12605 {
12606 /** @todo NSTVMX: Preempt timer. */
12607 return hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient);
12608 }
12609
12610 case VMX_EXIT_MOV_DRX: return hmR0VmxExitMovDRxNested(pVCpu, pVmxTransient);
12611 case VMX_EXIT_RDPMC: return hmR0VmxExitRdpmcNested(pVCpu, pVmxTransient);
12612
12613 case VMX_EXIT_VMREAD:
12614 case VMX_EXIT_VMWRITE: return hmR0VmxExitVmreadVmwriteNested(pVCpu, pVmxTransient);
12615
12616 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFaultNested(pVCpu, pVmxTransient);
12617 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestStateNested(pVCpu, pVmxTransient);
12618
12619 case VMX_EXIT_INIT_SIGNAL:
12620 case VMX_EXIT_SIPI:
12621 case VMX_EXIT_IO_SMI:
12622 case VMX_EXIT_SMI:
12623 case VMX_EXIT_ERR_MSR_LOAD:
12624 case VMX_EXIT_ERR_MACHINE_CHECK:
12625 case VMX_EXIT_PML_FULL:
12626 case VMX_EXIT_RSM:
12627 default:
12628 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
12629 }
12630}
12631#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
12632
12633
12634/** @name VM-exit helpers.
12635 * @{
12636 */
12637/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12638/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= VM-exit helpers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
12639/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12640
12641/** Macro for VM-exits called unexpectedly. */
12642#define HMVMX_UNEXPECTED_EXIT_RET(a_pVCpu, a_HmError) \
12643 do { \
12644 (a_pVCpu)->hm.s.u32HMError = (a_HmError); \
12645 return VERR_VMX_UNEXPECTED_EXIT; \
12646 } while (0)
12647
12648#ifdef VBOX_STRICT
12649/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
12650# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
12651 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
12652
12653# define HMVMX_ASSERT_PREEMPT_CPUID() \
12654 do { \
12655 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
12656 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
12657 } while (0)
12658
12659# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12660 do { \
12661 AssertPtr((a_pVCpu)); \
12662 AssertPtr((a_pVmxTransient)); \
12663 Assert((a_pVmxTransient)->fVMEntryFailed == false); \
12664 Assert((a_pVmxTransient)->pVmcsInfo); \
12665 Assert(ASMIntAreEnabled()); \
12666 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
12667 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
12668 Log4Func(("vcpu[%RU32]\n", (a_pVCpu)->idCpu)); \
12669 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
12670 if (VMMR0IsLogFlushDisabled((a_pVCpu))) \
12671 HMVMX_ASSERT_PREEMPT_CPUID(); \
12672 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
12673 } while (0)
12674
12675# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12676 do { \
12677 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); \
12678 Assert((a_pVmxTransient)->fIsNestedGuest); \
12679 } while (0)
12680
12681# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12682 do { \
12683 Log4Func(("\n")); \
12684 } while (0)
12685#else
12686# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12687 do { \
12688 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
12689 NOREF((a_pVCpu)); NOREF((a_pVmxTransient)); \
12690 } while (0)
12691
12692# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12693 do { HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); } while (0)
12694
12695# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) do { } while (0)
12696#endif
12697
12698#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12699/** Macro that does the necessary privilege checks and intercepted VM-exits for
12700 * guests that attempted to execute a VMX instruction. */
12701# define HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(a_pVCpu, a_uExitReason) \
12702 do \
12703 { \
12704 VBOXSTRICTRC rcStrictTmp = hmR0VmxCheckExitDueToVmxInstr((a_pVCpu), (a_uExitReason)); \
12705 if (rcStrictTmp == VINF_SUCCESS) \
12706 { /* likely */ } \
12707 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
12708 { \
12709 Assert((a_pVCpu)->hm.s.Event.fPending); \
12710 Log4Func(("Privilege checks failed -> %#x\n", VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo))); \
12711 return VINF_SUCCESS; \
12712 } \
12713 else \
12714 { \
12715 int rcTmp = VBOXSTRICTRC_VAL(rcStrictTmp); \
12716 AssertMsgFailedReturn(("Unexpected failure. rc=%Rrc", rcTmp), rcTmp); \
12717 } \
12718 } while (0)
12719
12720/** Macro that decodes a memory operand for an VM-exit caused by an instruction. */
12721# define HMVMX_DECODE_MEM_OPERAND(a_pVCpu, a_uExitInstrInfo, a_uExitQual, a_enmMemAccess, a_pGCPtrEffAddr) \
12722 do \
12723 { \
12724 VBOXSTRICTRC rcStrictTmp = hmR0VmxDecodeMemOperand((a_pVCpu), (a_uExitInstrInfo), (a_uExitQual), (a_enmMemAccess), \
12725 (a_pGCPtrEffAddr)); \
12726 if (rcStrictTmp == VINF_SUCCESS) \
12727 { /* likely */ } \
12728 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
12729 { \
12730 uint8_t const uXcptTmp = VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo); \
12731 Log4Func(("Memory operand decoding failed, raising xcpt %#x\n", uXcptTmp)); \
12732 NOREF(uXcptTmp); \
12733 return VINF_SUCCESS; \
12734 } \
12735 else \
12736 { \
12737 Log4Func(("hmR0VmxDecodeMemOperand failed. rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrictTmp))); \
12738 return rcStrictTmp; \
12739 } \
12740 } while (0)
12741#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
12742
12743
12744/**
12745 * Advances the guest RIP by the specified number of bytes.
12746 *
12747 * @param pVCpu The cross context virtual CPU structure.
12748 * @param cbInstr Number of bytes to advance the RIP by.
12749 *
12750 * @remarks No-long-jump zone!!!
12751 */
12752DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPU pVCpu, uint32_t cbInstr)
12753{
12754 /* Advance the RIP. */
12755 pVCpu->cpum.GstCtx.rip += cbInstr;
12756 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
12757
12758 /* Update interrupt inhibition. */
12759 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
12760 && pVCpu->cpum.GstCtx.rip != EMGetInhibitInterruptsPC(pVCpu))
12761 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
12762}
12763
12764
12765/**
12766 * Advances the guest RIP after reading it from the VMCS.
12767 *
12768 * @returns VBox status code, no informational status codes.
12769 * @param pVCpu The cross context virtual CPU structure.
12770 * @param pVmxTransient The VMX-transient structure.
12771 *
12772 * @remarks No-long-jump zone!!!
12773 */
12774static int hmR0VmxAdvanceGuestRip(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
12775{
12776 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12777 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
12778 AssertRCReturn(rc, rc);
12779
12780 hmR0VmxAdvanceGuestRipBy(pVCpu, pVmxTransient->cbInstr);
12781 return VINF_SUCCESS;
12782}
12783
12784
12785/**
12786 * Handle a condition that occurred while delivering an event through the guest or
12787 * nested-guest IDT.
12788 *
12789 * @returns Strict VBox status code (i.e. informational status codes too).
12790 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
12791 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
12792 * to continue execution of the guest which will delivery the \#DF.
12793 * @retval VINF_EM_RESET if we detected a triple-fault condition.
12794 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
12795 *
12796 * @param pVCpu The cross context virtual CPU structure.
12797 * @param pVmxTransient The VMX-transient structure.
12798 *
12799 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
12800 * Additionally, HMVMX_READ_EXIT_QUALIFICATION is required if the VM-exit
12801 * is due to an EPT violation, PML full or SPP-related event.
12802 *
12803 * @remarks No-long-jump zone!!!
12804 */
12805static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
12806{
12807 Assert(!pVCpu->hm.s.Event.fPending);
12808 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
12809 if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
12810 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
12811 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
12812 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_EXIT_QUALIFICATION);
12813
12814 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
12815 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
12816 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo;
12817 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
12818 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo))
12819 {
12820 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo);
12821 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo);
12822
12823 /*
12824 * If the event was a software interrupt (generated with INT n) or a software exception
12825 * (generated by INT3/INTO) or a privileged software exception (generated by INT1), we
12826 * can handle the VM-exit and continue guest execution which will re-execute the
12827 * instruction rather than re-injecting the exception, as that can cause premature
12828 * trips to ring-3 before injection and involve TRPM which currently has no way of
12829 * storing that these exceptions were caused by these instructions (ICEBP's #DB poses
12830 * the problem).
12831 */
12832 IEMXCPTRAISE enmRaise;
12833 IEMXCPTRAISEINFO fRaiseInfo;
12834 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
12835 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
12836 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
12837 {
12838 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
12839 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
12840 }
12841 else if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo))
12842 {
12843 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
12844 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo);
12845 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT);
12846
12847 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
12848 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
12849
12850 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo);
12851
12852 /* Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF(). */
12853 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
12854 {
12855 pVmxTransient->fVectoringPF = true;
12856 enmRaise = IEMXCPTRAISE_PREV_EVENT;
12857 }
12858 }
12859 else
12860 {
12861 /*
12862 * If an exception or hardware interrupt delivery caused an EPT violation/misconfig or APIC access
12863 * VM-exit, then the VM-exit interruption-information will not be valid and we end up here.
12864 * It is sufficient to reflect the original event to the guest after handling the VM-exit.
12865 */
12866 Assert( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
12867 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
12868 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
12869 enmRaise = IEMXCPTRAISE_PREV_EVENT;
12870 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
12871 }
12872
12873 /*
12874 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
12875 * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
12876 * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
12877 * subsequent VM-entry would fail, see @bugref{7445}.
12878 *
12879 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception".
12880 */
12881 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
12882 && enmRaise == IEMXCPTRAISE_PREV_EVENT
12883 && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
12884 && CPUMIsGuestNmiBlocking(pVCpu))
12885 {
12886 CPUMSetGuestNmiBlocking(pVCpu, false);
12887 }
12888
12889 switch (enmRaise)
12890 {
12891 case IEMXCPTRAISE_CURRENT_XCPT:
12892 {
12893 Log4Func(("IDT: Pending secondary Xcpt: idtinfo=%#RX64 exitinfo=%#RX64\n", uIdtVectorInfo, uExitIntInfo));
12894 Assert(rcStrict == VINF_SUCCESS);
12895 break;
12896 }
12897
12898 case IEMXCPTRAISE_PREV_EVENT:
12899 {
12900 uint32_t u32ErrCode;
12901 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo))
12902 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
12903 else
12904 u32ErrCode = 0;
12905
12906 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
12907 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflect);
12908 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(uIdtVectorInfo), 0 /* cbInstr */,
12909 u32ErrCode, pVCpu->cpum.GstCtx.cr2);
12910
12911 Log4Func(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntInfo,
12912 pVCpu->hm.s.Event.u32ErrCode));
12913 Assert(rcStrict == VINF_SUCCESS);
12914 break;
12915 }
12916
12917 case IEMXCPTRAISE_REEXEC_INSTR:
12918 Assert(rcStrict == VINF_SUCCESS);
12919 break;
12920
12921 case IEMXCPTRAISE_DOUBLE_FAULT:
12922 {
12923 /*
12924 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
12925 * second #PF as a guest #PF (and not a shadow #PF) and needs to be converted into a #DF.
12926 */
12927 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
12928 {
12929 pVmxTransient->fVectoringDoublePF = true;
12930 Log4Func(("IDT: Vectoring double #PF %#RX64 cr2=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo,
12931 pVCpu->cpum.GstCtx.cr2));
12932 rcStrict = VINF_SUCCESS;
12933 }
12934 else
12935 {
12936 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectConvertDF);
12937 hmR0VmxSetPendingXcptDF(pVCpu);
12938 Log4Func(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntInfo,
12939 uIdtVector, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
12940 rcStrict = VINF_HM_DOUBLE_FAULT;
12941 }
12942 break;
12943 }
12944
12945 case IEMXCPTRAISE_TRIPLE_FAULT:
12946 {
12947 Log4Func(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector,
12948 VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
12949 rcStrict = VINF_EM_RESET;
12950 break;
12951 }
12952
12953 case IEMXCPTRAISE_CPU_HANG:
12954 {
12955 Log4Func(("IDT: Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", fRaiseInfo));
12956 rcStrict = VERR_EM_GUEST_CPU_HANG;
12957 break;
12958 }
12959
12960 default:
12961 {
12962 AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
12963 rcStrict = VERR_VMX_IPE_2;
12964 break;
12965 }
12966 }
12967 }
12968 else if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
12969 && !CPUMIsGuestNmiBlocking(pVCpu))
12970 {
12971 if ( VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)
12972 && VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo) != X86_XCPT_DF
12973 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(uExitIntInfo))
12974 {
12975 /*
12976 * Execution of IRET caused a fault when NMI blocking was in effect (i.e we're in
12977 * the guest or nested-guest NMI handler). We need to set the block-by-NMI field so
12978 * that NMIs remain blocked until the IRET execution is completed.
12979 *
12980 * See Intel spec. 31.7.1.2 "Resuming Guest Software After Handling An Exception".
12981 */
12982 CPUMSetGuestNmiBlocking(pVCpu, true);
12983 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
12984 }
12985 else if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
12986 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
12987 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
12988 {
12989 /*
12990 * Execution of IRET caused an EPT violation, page-modification log-full event or
12991 * SPP-related event VM-exit when NMI blocking was in effect (i.e. we're in the
12992 * guest or nested-guest NMI handler). We need to set the block-by-NMI field so
12993 * that NMIs remain blocked until the IRET execution is completed.
12994 *
12995 * See Intel spec. 27.2.3 "Information about NMI unblocking due to IRET"
12996 */
12997 if (VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(pVmxTransient->uExitQual))
12998 {
12999 CPUMSetGuestNmiBlocking(pVCpu, true);
13000 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13001 }
13002 }
13003 }
13004
13005 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
13006 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
13007 return rcStrict;
13008}
13009
13010
13011#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13012/**
13013 * Perform the relevant VMX instruction checks for VM-exits that occurred due to the
13014 * guest attempting to execute a VMX instruction.
13015 *
13016 * @returns Strict VBox status code (i.e. informational status codes too).
13017 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13018 * @retval VINF_HM_PENDING_XCPT if an exception was raised.
13019 *
13020 * @param pVCpu The cross context virtual CPU structure.
13021 * @param uExitReason The VM-exit reason.
13022 *
13023 * @todo NSTVMX: Document other error codes when VM-exit is implemented.
13024 * @remarks No-long-jump zone!!!
13025 */
13026static VBOXSTRICTRC hmR0VmxCheckExitDueToVmxInstr(PVMCPU pVCpu, uint32_t uExitReason)
13027{
13028 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS
13029 | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
13030
13031 /*
13032 * The physical CPU would have already checked the CPU mode/code segment.
13033 * We shall just assert here for paranoia.
13034 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
13035 */
13036 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13037 Assert( !CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx)
13038 || CPUMIsGuestIn64BitCodeEx(&pVCpu->cpum.GstCtx));
13039
13040 if (uExitReason == VMX_EXIT_VMXON)
13041 {
13042 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
13043
13044 /*
13045 * We check CR4.VMXE because it is required to be always set while in VMX operation
13046 * by physical CPUs and our CR4 read-shadow is only consulted when executing specific
13047 * instructions (CLTS, LMSW, MOV CR, and SMSW) and thus doesn't affect CPU operation
13048 * otherwise (i.e. physical CPU won't automatically #UD if Cr4Shadow.VMXE is 0).
13049 */
13050 if (!CPUMIsGuestVmxEnabled(&pVCpu->cpum.GstCtx))
13051 {
13052 Log4Func(("CR4.VMXE is not set -> #UD\n"));
13053 hmR0VmxSetPendingXcptUD(pVCpu);
13054 return VINF_HM_PENDING_XCPT;
13055 }
13056 }
13057 else if (!CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx))
13058 {
13059 /*
13060 * The guest has not entered VMX operation but attempted to execute a VMX instruction
13061 * (other than VMXON), we need to raise a #UD.
13062 */
13063 Log4Func(("Not in VMX root mode -> #UD\n"));
13064 hmR0VmxSetPendingXcptUD(pVCpu);
13065 return VINF_HM_PENDING_XCPT;
13066 }
13067
13068 /* All other checks (including VM-exit intercepts) are handled by IEM instruction emulation. */
13069 return VINF_SUCCESS;
13070}
13071
13072
13073/**
13074 * Decodes the memory operand of an instruction that caused a VM-exit.
13075 *
13076 * The Exit qualification field provides the displacement field for memory
13077 * operand instructions, if any.
13078 *
13079 * @returns Strict VBox status code (i.e. informational status codes too).
13080 * @retval VINF_SUCCESS if the operand was successfully decoded.
13081 * @retval VINF_HM_PENDING_XCPT if an exception was raised while decoding the
13082 * operand.
13083 * @param pVCpu The cross context virtual CPU structure.
13084 * @param uExitInstrInfo The VM-exit instruction information field.
13085 * @param enmMemAccess The memory operand's access type (read or write).
13086 * @param GCPtrDisp The instruction displacement field, if any. For
13087 * RIP-relative addressing pass RIP + displacement here.
13088 * @param pGCPtrMem Where to store the effective destination memory address.
13089 *
13090 * @remarks Warning! This function ASSUMES the instruction cannot be used in real or
13091 * virtual-8086 mode hence skips those checks while verifying if the
13092 * segment is valid.
13093 */
13094static VBOXSTRICTRC hmR0VmxDecodeMemOperand(PVMCPU pVCpu, uint32_t uExitInstrInfo, RTGCPTR GCPtrDisp, VMXMEMACCESS enmMemAccess,
13095 PRTGCPTR pGCPtrMem)
13096{
13097 Assert(pGCPtrMem);
13098 Assert(!CPUMIsGuestInRealOrV86Mode(pVCpu));
13099 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_EFER
13100 | CPUMCTX_EXTRN_CR0);
13101
13102 static uint64_t const s_auAddrSizeMasks[] = { UINT64_C(0xffff), UINT64_C(0xffffffff), UINT64_C(0xffffffffffffffff) };
13103 static uint64_t const s_auAccessSizeMasks[] = { sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t) };
13104 AssertCompile(RT_ELEMENTS(s_auAccessSizeMasks) == RT_ELEMENTS(s_auAddrSizeMasks));
13105
13106 VMXEXITINSTRINFO ExitInstrInfo;
13107 ExitInstrInfo.u = uExitInstrInfo;
13108 uint8_t const uAddrSize = ExitInstrInfo.All.u3AddrSize;
13109 uint8_t const iSegReg = ExitInstrInfo.All.iSegReg;
13110 bool const fIdxRegValid = !ExitInstrInfo.All.fIdxRegInvalid;
13111 uint8_t const iIdxReg = ExitInstrInfo.All.iIdxReg;
13112 uint8_t const uScale = ExitInstrInfo.All.u2Scaling;
13113 bool const fBaseRegValid = !ExitInstrInfo.All.fBaseRegInvalid;
13114 uint8_t const iBaseReg = ExitInstrInfo.All.iBaseReg;
13115 bool const fIsMemOperand = !ExitInstrInfo.All.fIsRegOperand;
13116 bool const fIsLongMode = CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx);
13117
13118 /*
13119 * Validate instruction information.
13120 * This shouldn't happen on real hardware but useful while testing our nested hardware-virtualization code.
13121 */
13122 AssertLogRelMsgReturn(uAddrSize < RT_ELEMENTS(s_auAddrSizeMasks),
13123 ("Invalid address size. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_1);
13124 AssertLogRelMsgReturn(iSegReg < X86_SREG_COUNT,
13125 ("Invalid segment register. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_2);
13126 AssertLogRelMsgReturn(fIsMemOperand,
13127 ("Expected memory operand. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_3);
13128
13129 /*
13130 * Compute the complete effective address.
13131 *
13132 * See AMD instruction spec. 1.4.2 "SIB Byte Format"
13133 * See AMD spec. 4.5.2 "Segment Registers".
13134 */
13135 RTGCPTR GCPtrMem = GCPtrDisp;
13136 if (fBaseRegValid)
13137 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iBaseReg].u64;
13138 if (fIdxRegValid)
13139 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iIdxReg].u64 << uScale;
13140
13141 RTGCPTR const GCPtrOff = GCPtrMem;
13142 if ( !fIsLongMode
13143 || iSegReg >= X86_SREG_FS)
13144 GCPtrMem += pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
13145 GCPtrMem &= s_auAddrSizeMasks[uAddrSize];
13146
13147 /*
13148 * Validate effective address.
13149 * See AMD spec. 4.5.3 "Segment Registers in 64-Bit Mode".
13150 */
13151 uint8_t const cbAccess = s_auAccessSizeMasks[uAddrSize];
13152 Assert(cbAccess > 0);
13153 if (fIsLongMode)
13154 {
13155 if (X86_IS_CANONICAL(GCPtrMem))
13156 {
13157 *pGCPtrMem = GCPtrMem;
13158 return VINF_SUCCESS;
13159 }
13160
13161 /** @todo r=ramshankar: We should probably raise \#SS or \#GP. See AMD spec. 4.12.2
13162 * "Data Limit Checks in 64-bit Mode". */
13163 Log4Func(("Long mode effective address is not canonical GCPtrMem=%#RX64\n", GCPtrMem));
13164 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13165 return VINF_HM_PENDING_XCPT;
13166 }
13167
13168 /*
13169 * This is a watered down version of iemMemApplySegment().
13170 * Parts that are not applicable for VMX instructions like real-or-v8086 mode
13171 * and segment CPL/DPL checks are skipped.
13172 */
13173 RTGCPTR32 const GCPtrFirst32 = (RTGCPTR32)GCPtrOff;
13174 RTGCPTR32 const GCPtrLast32 = GCPtrFirst32 + cbAccess - 1;
13175 PCCPUMSELREG pSel = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
13176
13177 /* Check if the segment is present and usable. */
13178 if ( pSel->Attr.n.u1Present
13179 && !pSel->Attr.n.u1Unusable)
13180 {
13181 Assert(pSel->Attr.n.u1DescType);
13182 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
13183 {
13184 /* Check permissions for the data segment. */
13185 if ( enmMemAccess == VMXMEMACCESS_WRITE
13186 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE))
13187 {
13188 Log4Func(("Data segment access invalid. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13189 hmR0VmxSetPendingXcptGP(pVCpu, iSegReg);
13190 return VINF_HM_PENDING_XCPT;
13191 }
13192
13193 /* Check limits if it's a normal data segment. */
13194 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
13195 {
13196 if ( GCPtrFirst32 > pSel->u32Limit
13197 || GCPtrLast32 > pSel->u32Limit)
13198 {
13199 Log4Func(("Data segment limit exceeded. "
13200 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13201 GCPtrLast32, pSel->u32Limit));
13202 if (iSegReg == X86_SREG_SS)
13203 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13204 else
13205 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13206 return VINF_HM_PENDING_XCPT;
13207 }
13208 }
13209 else
13210 {
13211 /* Check limits if it's an expand-down data segment.
13212 Note! The upper boundary is defined by the B bit, not the G bit! */
13213 if ( GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
13214 || GCPtrLast32 > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
13215 {
13216 Log4Func(("Expand-down data segment limit exceeded. "
13217 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13218 GCPtrLast32, pSel->u32Limit));
13219 if (iSegReg == X86_SREG_SS)
13220 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13221 else
13222 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13223 return VINF_HM_PENDING_XCPT;
13224 }
13225 }
13226 }
13227 else
13228 {
13229 /* Check permissions for the code segment. */
13230 if ( enmMemAccess == VMXMEMACCESS_WRITE
13231 || ( enmMemAccess == VMXMEMACCESS_READ
13232 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)))
13233 {
13234 Log4Func(("Code segment access invalid. Attr=%#RX32\n", pSel->Attr.u));
13235 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13236 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13237 return VINF_HM_PENDING_XCPT;
13238 }
13239
13240 /* Check limits for the code segment (normal/expand-down not applicable for code segments). */
13241 if ( GCPtrFirst32 > pSel->u32Limit
13242 || GCPtrLast32 > pSel->u32Limit)
13243 {
13244 Log4Func(("Code segment limit exceeded. GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n",
13245 GCPtrFirst32, GCPtrLast32, pSel->u32Limit));
13246 if (iSegReg == X86_SREG_SS)
13247 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13248 else
13249 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13250 return VINF_HM_PENDING_XCPT;
13251 }
13252 }
13253 }
13254 else
13255 {
13256 Log4Func(("Not present or unusable segment. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13257 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13258 return VINF_HM_PENDING_XCPT;
13259 }
13260
13261 *pGCPtrMem = GCPtrMem;
13262 return VINF_SUCCESS;
13263}
13264#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13265
13266
13267/**
13268 * VM-exit helper for LMSW.
13269 */
13270static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst)
13271{
13272 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13273 AssertRCReturn(rc, rc);
13274
13275 VBOXSTRICTRC rcStrict = IEMExecDecodedLmsw(pVCpu, cbInstr, uMsw, GCPtrEffDst);
13276 AssertMsg( rcStrict == VINF_SUCCESS
13277 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13278
13279 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13280 if (rcStrict == VINF_IEM_RAISED_XCPT)
13281 {
13282 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13283 rcStrict = VINF_SUCCESS;
13284 }
13285
13286 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
13287 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13288 return rcStrict;
13289}
13290
13291
13292/**
13293 * VM-exit helper for CLTS.
13294 */
13295static VBOXSTRICTRC hmR0VmxExitClts(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
13296{
13297 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13298 AssertRCReturn(rc, rc);
13299
13300 VBOXSTRICTRC rcStrict = IEMExecDecodedClts(pVCpu, cbInstr);
13301 AssertMsg( rcStrict == VINF_SUCCESS
13302 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13303
13304 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13305 if (rcStrict == VINF_IEM_RAISED_XCPT)
13306 {
13307 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13308 rcStrict = VINF_SUCCESS;
13309 }
13310
13311 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
13312 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13313 return rcStrict;
13314}
13315
13316
13317/**
13318 * VM-exit helper for MOV from CRx (CRx read).
13319 */
13320static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13321{
13322 Assert(iCrReg < 16);
13323 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
13324
13325 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13326 AssertRCReturn(rc, rc);
13327
13328 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxRead(pVCpu, cbInstr, iGReg, iCrReg);
13329 AssertMsg( rcStrict == VINF_SUCCESS
13330 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13331
13332 if (iGReg == X86_GREG_xSP)
13333 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_RSP);
13334 else
13335 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13336#ifdef VBOX_WITH_STATISTICS
13337 switch (iCrReg)
13338 {
13339 case 0: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Read); break;
13340 case 2: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Read); break;
13341 case 3: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Read); break;
13342 case 4: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Read); break;
13343 case 8: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Read); break;
13344 }
13345#endif
13346 Log4Func(("CR%d Read access rcStrict=%Rrc\n", iCrReg, VBOXSTRICTRC_VAL(rcStrict)));
13347 return rcStrict;
13348}
13349
13350
13351/**
13352 * VM-exit helper for MOV to CRx (CRx write).
13353 */
13354static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13355{
13356 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13357 AssertRCReturn(rc, rc);
13358
13359 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, cbInstr, iCrReg, iGReg);
13360 AssertMsg( rcStrict == VINF_SUCCESS
13361 || rcStrict == VINF_IEM_RAISED_XCPT
13362 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13363
13364 switch (iCrReg)
13365 {
13366 case 0:
13367 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13368 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Write);
13369 Log4Func(("CR0 write. rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr0));
13370 break;
13371
13372 case 2:
13373 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Write);
13374 /* Nothing to do here, CR2 it's not part of the VMCS. */
13375 break;
13376
13377 case 3:
13378 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR3);
13379 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Write);
13380 Log4Func(("CR3 write. rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr3));
13381 break;
13382
13383 case 4:
13384 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR4);
13385 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Write);
13386 Log4Func(("CR4 write. rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n", VBOXSTRICTRC_VAL(rcStrict),
13387 pVCpu->cpum.GstCtx.cr4, pVCpu->hm.s.fLoadSaveGuestXcr0));
13388 break;
13389
13390 case 8:
13391 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged,
13392 HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_APIC_TPR);
13393 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Write);
13394 break;
13395
13396 default:
13397 AssertMsgFailed(("Invalid CRx register %#x\n", iCrReg));
13398 break;
13399 }
13400
13401 if (rcStrict == VINF_IEM_RAISED_XCPT)
13402 {
13403 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13404 rcStrict = VINF_SUCCESS;
13405 }
13406 return rcStrict;
13407}
13408
13409
13410/**
13411 * VM-exit exception handler for \#PF (Page-fault exception).
13412 *
13413 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13414 */
13415static VBOXSTRICTRC hmR0VmxExitXcptPF(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13416{
13417 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13418 PVM pVM = pVCpu->CTX_SUFF(pVM);
13419 hmR0VmxReadExitQualVmcs(pVmxTransient);
13420
13421 if (!pVM->hm.s.fNestedPaging)
13422 { /* likely */ }
13423 else
13424 {
13425#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13426 Assert(pVmxTransient->fIsNestedGuest || pVCpu->hm.s.fUsingDebugLoop);
13427#endif
13428 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13429 if (!pVmxTransient->fVectoringDoublePF)
13430 {
13431 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13432 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual);
13433 }
13434 else
13435 {
13436 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13437 Assert(!pVmxTransient->fIsNestedGuest);
13438 hmR0VmxSetPendingXcptDF(pVCpu);
13439 Log4Func(("Pending #DF due to vectoring #PF w/ NestedPaging\n"));
13440 }
13441 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13442 return VINF_SUCCESS;
13443 }
13444
13445 Assert(!pVmxTransient->fIsNestedGuest);
13446
13447 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
13448 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
13449 if (pVmxTransient->fVectoringPF)
13450 {
13451 Assert(pVCpu->hm.s.Event.fPending);
13452 return VINF_EM_RAW_INJECT_TRPM_EVENT;
13453 }
13454
13455 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13456 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13457 AssertRCReturn(rc, rc);
13458
13459 Log4Func(("#PF: cr2=%#RX64 cs:rip=%#04x:%#RX64 uErrCode %#RX32 cr3=%#RX64\n", pVmxTransient->uExitQual, pCtx->cs.Sel,
13460 pCtx->rip, pVmxTransient->uExitIntErrorCode, pCtx->cr3));
13461
13462 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQual, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
13463 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pCtx), (RTGCPTR)pVmxTransient->uExitQual);
13464
13465 Log4Func(("#PF: rc=%Rrc\n", rc));
13466 if (rc == VINF_SUCCESS)
13467 {
13468 /*
13469 * This is typically a shadow page table sync or a MMIO instruction. But we may have
13470 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
13471 */
13472 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13473 TRPMResetTrap(pVCpu);
13474 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
13475 return rc;
13476 }
13477
13478 if (rc == VINF_EM_RAW_GUEST_TRAP)
13479 {
13480 if (!pVmxTransient->fVectoringDoublePF)
13481 {
13482 /* It's a guest page fault and needs to be reflected to the guest. */
13483 uint32_t uGstErrorCode = TRPMGetErrorCode(pVCpu);
13484 TRPMResetTrap(pVCpu);
13485 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
13486 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13487 uGstErrorCode, pVmxTransient->uExitQual);
13488 }
13489 else
13490 {
13491 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13492 TRPMResetTrap(pVCpu);
13493 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
13494 hmR0VmxSetPendingXcptDF(pVCpu);
13495 Log4Func(("#PF: Pending #DF due to vectoring #PF\n"));
13496 }
13497
13498 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13499 return VINF_SUCCESS;
13500 }
13501
13502 TRPMResetTrap(pVCpu);
13503 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
13504 return rc;
13505}
13506
13507
13508/**
13509 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
13510 *
13511 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13512 */
13513static VBOXSTRICTRC hmR0VmxExitXcptMF(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13514{
13515 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13516 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
13517
13518 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0);
13519 AssertRCReturn(rc, rc);
13520
13521 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_NE))
13522 {
13523 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
13524 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
13525
13526 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
13527 * provides VM-exit instruction length. If this causes problem later,
13528 * disassemble the instruction like it's done on AMD-V. */
13529 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
13530 AssertRCReturn(rc2, rc2);
13531 return rc;
13532 }
13533
13534 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13535 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13536 return VINF_SUCCESS;
13537}
13538
13539
13540/**
13541 * VM-exit exception handler for \#BP (Breakpoint exception).
13542 *
13543 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13544 */
13545static VBOXSTRICTRC hmR0VmxExitXcptBP(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13546{
13547 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13548 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
13549
13550 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13551 AssertRCReturn(rc, rc);
13552
13553 if (!pVmxTransient->fIsNestedGuest)
13554 rc = DBGFRZTrap03Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(&pVCpu->cpum.GstCtx));
13555 else
13556 rc = VINF_EM_RAW_GUEST_TRAP;
13557 if (rc == VINF_EM_RAW_GUEST_TRAP)
13558 {
13559 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13560 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13561 }
13562
13563 Assert(rc == VINF_SUCCESS || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_EM_DBG_BREAKPOINT);
13564 return rc;
13565}
13566
13567
13568/**
13569 * VM-exit exception handler for \#AC (Alignment-check exception).
13570 *
13571 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13572 */
13573static VBOXSTRICTRC hmR0VmxExitXcptAC(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13574{
13575 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13576 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC);
13577
13578 /* Re-inject it. We'll detect any nesting before getting here. */
13579 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13580 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13581 return VINF_SUCCESS;
13582}
13583
13584
13585/**
13586 * VM-exit exception handler for \#DB (Debug exception).
13587 *
13588 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13589 */
13590static VBOXSTRICTRC hmR0VmxExitXcptDB(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13591{
13592 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13593 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
13594
13595 /*
13596 * Get the DR6-like values from the Exit qualification and pass it to DBGF for processing.
13597 */
13598 hmR0VmxReadExitQualVmcs(pVmxTransient);
13599
13600 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
13601 uint64_t const uDR6 = X86_DR6_INIT_VAL
13602 | (pVmxTransient->uExitQual & ( X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3
13603 | X86_DR6_BD | X86_DR6_BS));
13604
13605 int rc;
13606 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13607 if (!pVmxTransient->fIsNestedGuest)
13608 rc = DBGFRZTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
13609 else
13610 rc = VINF_EM_RAW_GUEST_TRAP;
13611 Log6Func(("rc=%Rrc\n", rc));
13612 if (rc == VINF_EM_RAW_GUEST_TRAP)
13613 {
13614 /*
13615 * The exception was for the guest. Update DR6, DR7.GD and
13616 * IA32_DEBUGCTL.LBR before forwarding it.
13617 * See Intel spec. 27.1 "Architectural State before a VM-Exit".
13618 */
13619 VMMRZCallRing3Disable(pVCpu);
13620 HM_DISABLE_PREEMPT(pVCpu);
13621
13622 pCtx->dr[6] &= ~X86_DR6_B_MASK;
13623 pCtx->dr[6] |= uDR6;
13624 if (CPUMIsGuestDebugStateActive(pVCpu))
13625 ASMSetDR6(pCtx->dr[6]);
13626
13627 HM_RESTORE_PREEMPT();
13628 VMMRZCallRing3Enable(pVCpu);
13629
13630 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_DR7);
13631 AssertRCReturn(rc, rc);
13632
13633 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
13634 pCtx->dr[7] &= ~(uint64_t)X86_DR7_GD;
13635
13636 /* Paranoia. */
13637 pCtx->dr[7] &= ~(uint64_t)X86_DR7_RAZ_MASK;
13638 pCtx->dr[7] |= X86_DR7_RA1_MASK;
13639
13640 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, pCtx->dr[7]);
13641 AssertRC(rc);
13642
13643 /*
13644 * Raise #DB in the guest.
13645 *
13646 * It is important to reflect exactly what the VM-exit gave us (preserving the
13647 * interruption-type) rather than use hmR0VmxSetPendingXcptDB() as the #DB could've
13648 * been raised while executing ICEBP (INT1) and not the regular #DB. Thus it may
13649 * trigger different handling in the CPU (like skipping DPL checks), see @bugref{6398}.
13650 *
13651 * Intel re-documented ICEBP/INT1 on May 2018 previously documented as part of
13652 * Intel 386, see Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
13653 */
13654 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13655 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13656 return VINF_SUCCESS;
13657 }
13658
13659 /*
13660 * Not a guest trap, must be a hypervisor related debug event then.
13661 * Update DR6 in case someone is interested in it.
13662 */
13663 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
13664 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
13665 CPUMSetHyperDR6(pVCpu, uDR6);
13666
13667 return rc;
13668}
13669
13670
13671/**
13672 * Hacks its way around the lovely mesa driver's backdoor accesses.
13673 *
13674 * @sa hmR0SvmHandleMesaDrvGp.
13675 */
13676static int hmR0VmxHandleMesaDrvGp(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
13677{
13678 LogFunc(("cs:rip=%#04x:%#RX64 rcx=%#RX64 rbx=%#RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->rcx, pCtx->rbx));
13679 RT_NOREF(pCtx);
13680
13681 /* For now we'll just skip the instruction. */
13682 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
13683}
13684
13685
13686/**
13687 * Checks if the \#GP'ing instruction is the mesa driver doing it's lovely
13688 * backdoor logging w/o checking what it is running inside.
13689 *
13690 * This recognizes an "IN EAX,DX" instruction executed in flat ring-3, with the
13691 * backdoor port and magic numbers loaded in registers.
13692 *
13693 * @returns true if it is, false if it isn't.
13694 * @sa hmR0SvmIsMesaDrvGp.
13695 */
13696DECLINLINE(bool) hmR0VmxIsMesaDrvGp(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
13697{
13698 /* 0xed: IN eAX,dx */
13699 uint8_t abInstr[1];
13700 if (pVmxTransient->cbInstr != sizeof(abInstr))
13701 return false;
13702
13703 /* Check that it is #GP(0). */
13704 if (pVmxTransient->uExitIntErrorCode != 0)
13705 return false;
13706
13707 /* Check magic and port. */
13708 Assert(!(pCtx->fExtrn & (CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX)));
13709 /*Log(("hmR0VmxIsMesaDrvGp: rax=%RX64 rdx=%RX64\n", pCtx->rax, pCtx->rdx));*/
13710 if (pCtx->rax != UINT32_C(0x564d5868))
13711 return false;
13712 if (pCtx->dx != UINT32_C(0x5658))
13713 return false;
13714
13715 /* Flat ring-3 CS. */
13716 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_CS);
13717 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_CS));
13718 /*Log(("hmR0VmxIsMesaDrvGp: cs.Attr.n.u2Dpl=%d base=%Rx64\n", pCtx->cs.Attr.n.u2Dpl, pCtx->cs.u64Base));*/
13719 if (pCtx->cs.Attr.n.u2Dpl != 3)
13720 return false;
13721 if (pCtx->cs.u64Base != 0)
13722 return false;
13723
13724 /* Check opcode. */
13725 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_RIP);
13726 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_RIP));
13727 int rc = PGMPhysSimpleReadGCPtr(pVCpu, abInstr, pCtx->rip, sizeof(abInstr));
13728 /*Log(("hmR0VmxIsMesaDrvGp: PGMPhysSimpleReadGCPtr -> %Rrc %#x\n", rc, abInstr[0]));*/
13729 if (RT_FAILURE(rc))
13730 return false;
13731 if (abInstr[0] != 0xed)
13732 return false;
13733
13734 return true;
13735}
13736
13737
13738/**
13739 * VM-exit exception handler for \#GP (General-protection exception).
13740 *
13741 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13742 */
13743static VBOXSTRICTRC hmR0VmxExitXcptGP(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13744{
13745 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13746 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
13747
13748 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13749 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13750 if (pVmcsInfo->RealMode.fRealOnV86Active)
13751 { /* likely */ }
13752 else
13753 {
13754#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13755 Assert(pVCpu->hm.s.fUsingDebugLoop || pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
13756#endif
13757 /*
13758 * If the guest is not in real-mode or we have unrestricted guest execution support, or if we are
13759 * executing a nested-guest, reflect #GP to the guest or nested-guest.
13760 */
13761 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13762 AssertRCReturn(rc, rc);
13763 Log4Func(("Gst: cs:rip=%#04x:%#RX64 ErrorCode=%#x cr0=%#RX64 cpl=%u tr=%#04x\n", pCtx->cs.Sel, pCtx->rip,
13764 pVmxTransient->uExitIntErrorCode, pCtx->cr0, CPUMGetGuestCPL(pVCpu), pCtx->tr.Sel));
13765
13766 if ( pVmxTransient->fIsNestedGuest
13767 || !pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv
13768 || !hmR0VmxIsMesaDrvGp(pVCpu, pVmxTransient, pCtx))
13769 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13770 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13771 else
13772 rc = hmR0VmxHandleMesaDrvGp(pVCpu, pVmxTransient, pCtx);
13773 return rc;
13774 }
13775
13776 Assert(CPUMIsGuestInRealModeEx(pCtx));
13777 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest);
13778 Assert(!pVmxTransient->fIsNestedGuest);
13779
13780 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13781 AssertRCReturn(rc, rc);
13782
13783 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
13784 if (rcStrict == VINF_SUCCESS)
13785 {
13786 if (!CPUMIsGuestInRealModeEx(pCtx))
13787 {
13788 /*
13789 * The guest is no longer in real-mode, check if we can continue executing the
13790 * guest using hardware-assisted VMX. Otherwise, fall back to emulation.
13791 */
13792 pVmcsInfo->RealMode.fRealOnV86Active = false;
13793 if (HMCanExecuteVmxGuest(pVCpu, pCtx))
13794 {
13795 Log4Func(("Mode changed but guest still suitable for executing using hardware-assisted VMX\n"));
13796 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13797 }
13798 else
13799 {
13800 Log4Func(("Mode changed -> VINF_EM_RESCHEDULE\n"));
13801 rcStrict = VINF_EM_RESCHEDULE;
13802 }
13803 }
13804 else
13805 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13806 }
13807 else if (rcStrict == VINF_IEM_RAISED_XCPT)
13808 {
13809 rcStrict = VINF_SUCCESS;
13810 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13811 }
13812 return VBOXSTRICTRC_VAL(rcStrict);
13813}
13814
13815
13816/**
13817 * VM-exit exception handler wrapper for all other exceptions that are not handled
13818 * by a specific handler.
13819 *
13820 * This simply re-injects the exception back into the VM without any special
13821 * processing.
13822 *
13823 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13824 */
13825static VBOXSTRICTRC hmR0VmxExitXcptOthers(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13826{
13827 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13828
13829#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13830 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13831 AssertMsg(pVCpu->hm.s.fUsingDebugLoop || pVmcsInfo->RealMode.fRealOnV86Active || pVmxTransient->fIsNestedGuest,
13832 ("uVector=%#x u32XcptBitmap=%#X32\n",
13833 VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVmcsInfo->u32XcptBitmap));
13834 NOREF(pVmcsInfo);
13835#endif
13836
13837 /*
13838 * Re-inject the exception into the guest. This cannot be a double-fault condition which
13839 * would have been handled while checking exits due to event delivery.
13840 */
13841 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13842
13843#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13844 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
13845 AssertRCReturn(rc, rc);
13846 Log4Func(("Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
13847#endif
13848
13849#ifdef VBOX_WITH_STATISTICS
13850 switch (uVector)
13851 {
13852 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE); break;
13853 case X86_XCPT_DB: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB); break;
13854 case X86_XCPT_BP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP); break;
13855 case X86_XCPT_OF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
13856 case X86_XCPT_BR: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBR); break;
13857 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD); break;
13858 case X86_XCPT_NM: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
13859 case X86_XCPT_DF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDF); break;
13860 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS); break;
13861 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP); break;
13862 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS); break;
13863 case X86_XCPT_GP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP); break;
13864 case X86_XCPT_PF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF); break;
13865 case X86_XCPT_MF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF); break;
13866 case X86_XCPT_AC: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC); break;
13867 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF); break;
13868 default:
13869 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
13870 break;
13871 }
13872#endif
13873
13874 /* We should never call this function for a page-fault, we'd need to pass on the fault address below otherwise. */
13875 Assert(!VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo));
13876 NOREF(uVector);
13877
13878 /* Re-inject the original exception into the guest. */
13879 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13880 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13881 return VINF_SUCCESS;
13882}
13883
13884
13885/**
13886 * VM-exit exception handler for all exceptions (except NMIs!).
13887 *
13888 * @remarks This may be called for both guests and nested-guests. Take care to not
13889 * make assumptions and avoid doing anything that is not relevant when
13890 * executing a nested-guest (e.g., Mesa driver hacks).
13891 */
13892static VBOXSTRICTRC hmR0VmxExitXcpt(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13893{
13894 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
13895
13896 /*
13897 * If this VM-exit occurred while delivering an event through the guest IDT, take
13898 * action based on the return code and additional hints (e.g. for page-faults)
13899 * that will be updated in the VMX transient structure.
13900 */
13901 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
13902 if (rcStrict == VINF_SUCCESS)
13903 {
13904 /*
13905 * If an exception caused a VM-exit due to delivery of an event, the original
13906 * event may have to be re-injected into the guest. We shall reinject it and
13907 * continue guest execution. However, page-fault is a complicated case and
13908 * needs additional processing done in hmR0VmxExitXcptPF().
13909 */
13910 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
13911 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13912 if ( !pVCpu->hm.s.Event.fPending
13913 || uVector == X86_XCPT_PF)
13914 {
13915 switch (uVector)
13916 {
13917 case X86_XCPT_PF: return hmR0VmxExitXcptPF(pVCpu, pVmxTransient);
13918 case X86_XCPT_GP: return hmR0VmxExitXcptGP(pVCpu, pVmxTransient);
13919 case X86_XCPT_MF: return hmR0VmxExitXcptMF(pVCpu, pVmxTransient);
13920 case X86_XCPT_DB: return hmR0VmxExitXcptDB(pVCpu, pVmxTransient);
13921 case X86_XCPT_BP: return hmR0VmxExitXcptBP(pVCpu, pVmxTransient);
13922 case X86_XCPT_AC: return hmR0VmxExitXcptAC(pVCpu, pVmxTransient);
13923 default:
13924 return hmR0VmxExitXcptOthers(pVCpu, pVmxTransient);
13925 }
13926 }
13927 /* else: inject pending event before resuming guest execution. */
13928 }
13929 else if (rcStrict == VINF_HM_DOUBLE_FAULT)
13930 {
13931 Assert(pVCpu->hm.s.Event.fPending);
13932 rcStrict = VINF_SUCCESS;
13933 }
13934
13935 return rcStrict;
13936}
13937/** @} */
13938
13939
13940/** @name VM-exit handlers.
13941 * @{
13942 */
13943/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13944/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
13945/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13946
13947/**
13948 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
13949 */
13950HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13951{
13952 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13953 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
13954 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
13955 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
13956 return VINF_SUCCESS;
13957 return VINF_EM_RAW_INTERRUPT;
13958}
13959
13960
13961/**
13962 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI). Conditional
13963 * VM-exit.
13964 */
13965HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13966{
13967 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13968 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
13969
13970 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13971
13972 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
13973 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13974 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
13975
13976 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13977 Assert( !(pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT)
13978 && uExitIntType != VMX_EXIT_INT_INFO_TYPE_EXT_INT);
13979 NOREF(pVmcsInfo);
13980
13981 VBOXSTRICTRC rcStrict;
13982 switch (uExitIntType)
13983 {
13984 /*
13985 * Host physical NMIs:
13986 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we
13987 * injected it ourselves and anything we inject is not going to cause a VM-exit directly
13988 * for the event being injected[1]. Go ahead and dispatch the NMI to the host[2].
13989 *
13990 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
13991 * See Intel spec. 27.5.5 "Updating Non-Register State".
13992 */
13993 case VMX_EXIT_INT_INFO_TYPE_NMI:
13994 {
13995 rcStrict = hmR0VmxExitHostNmi(pVCpu, pVmcsInfo);
13996 break;
13997 }
13998
13999 /*
14000 * Privileged software exceptions (#DB from ICEBP),
14001 * Software exceptions (#BP and #OF),
14002 * Hardware exceptions:
14003 * Process the required exceptions and resume guest execution if possible.
14004 */
14005 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
14006 Assert(uVector == X86_XCPT_DB);
14007 RT_FALL_THRU();
14008 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
14009 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uExitIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT);
14010 RT_FALL_THRU();
14011 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
14012 {
14013 NOREF(uVector);
14014 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
14015 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14016 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
14017 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
14018
14019 rcStrict = hmR0VmxExitXcpt(pVCpu, pVmxTransient);
14020 break;
14021 }
14022
14023 default:
14024 {
14025 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
14026 rcStrict = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
14027 AssertMsgFailed(("Invalid/unexpected VM-exit interruption info %#x\n", pVmxTransient->uExitIntInfo));
14028 break;
14029 }
14030 }
14031
14032 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
14033 return rcStrict;
14034}
14035
14036
14037/**
14038 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
14039 */
14040HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14041{
14042 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14043
14044 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
14045 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14046 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
14047
14048 /* Evaluate and deliver pending events and resume guest execution. */
14049 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
14050 return VINF_SUCCESS;
14051}
14052
14053
14054/**
14055 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
14056 */
14057HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14058{
14059 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14060
14061 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14062 if (RT_UNLIKELY(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))) /** @todo NSTVMX: Turn this into an assertion. */
14063 {
14064 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
14065 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14066 }
14067
14068 Assert(!CPUMIsGuestNmiBlocking(pVCpu));
14069
14070 /*
14071 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
14072 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
14073 */
14074 uint32_t fIntrState;
14075 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
14076 AssertRC(rc);
14077 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
14078 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
14079 {
14080 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
14081 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
14082
14083 fIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
14084 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
14085 AssertRC(rc);
14086 }
14087
14088 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
14089 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
14090
14091 /* Evaluate and deliver pending events and resume guest execution. */
14092 return VINF_SUCCESS;
14093}
14094
14095
14096/**
14097 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
14098 */
14099HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14100{
14101 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14102 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14103}
14104
14105
14106/**
14107 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
14108 */
14109HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14110{
14111 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14112 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14113}
14114
14115
14116/**
14117 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
14118 */
14119HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14120{
14121 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14122
14123 /*
14124 * Get the state we need and update the exit history entry.
14125 */
14126 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14127 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14128
14129 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14130 AssertRCReturn(rc, rc);
14131
14132 VBOXSTRICTRC rcStrict;
14133 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
14134 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_CPUID),
14135 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
14136 if (!pExitRec)
14137 {
14138 /*
14139 * Regular CPUID instruction execution.
14140 */
14141 rcStrict = IEMExecDecodedCpuid(pVCpu, pVmxTransient->cbInstr);
14142 if (rcStrict == VINF_SUCCESS)
14143 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14144 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14145 {
14146 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14147 rcStrict = VINF_SUCCESS;
14148 }
14149 }
14150 else
14151 {
14152 /*
14153 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
14154 */
14155 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14156 AssertRCReturn(rc2, rc2);
14157
14158 Log4(("CpuIdExit/%u: %04x:%08RX64: %#x/%#x -> EMHistoryExec\n",
14159 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx));
14160
14161 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
14162 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14163
14164 Log4(("CpuIdExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
14165 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
14166 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
14167 }
14168 return rcStrict;
14169}
14170
14171
14172/**
14173 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
14174 */
14175HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14176{
14177 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14178
14179 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14180 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4);
14181 AssertRCReturn(rc, rc);
14182
14183 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_SMXE)
14184 return VINF_EM_RAW_EMULATE_INSTR;
14185
14186 AssertMsgFailed(("hmR0VmxExitGetsec: Unexpected VM-exit when CR4.SMXE is 0.\n"));
14187 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14188}
14189
14190
14191/**
14192 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
14193 */
14194HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14195{
14196 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14197
14198 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14199 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14200 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14201 AssertRCReturn(rc, rc);
14202
14203 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtsc(pVCpu, pVmxTransient->cbInstr);
14204 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14205 {
14206 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14207 we must reset offsetting on VM-entry. See @bugref{6634}. */
14208 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14209 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14210 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14211 }
14212 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14213 {
14214 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14215 rcStrict = VINF_SUCCESS;
14216 }
14217 return rcStrict;
14218}
14219
14220
14221/**
14222 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
14223 */
14224HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14225{
14226 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14227
14228 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14229 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14230 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_TSC_AUX);
14231 AssertRCReturn(rc, rc);
14232
14233 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtscp(pVCpu, pVmxTransient->cbInstr);
14234 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14235 {
14236 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14237 we must reset offsetting on VM-reentry. See @bugref{6634}. */
14238 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14239 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14240 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14241 }
14242 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14243 {
14244 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14245 rcStrict = VINF_SUCCESS;
14246 }
14247 return rcStrict;
14248}
14249
14250
14251/**
14252 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
14253 */
14254HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14255{
14256 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14257
14258 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14259 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_CR0
14260 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS);
14261 AssertRCReturn(rc, rc);
14262
14263 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14264 rc = EMInterpretRdpmc(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
14265 if (RT_LIKELY(rc == VINF_SUCCESS))
14266 {
14267 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14268 Assert(pVmxTransient->cbInstr == 2);
14269 }
14270 else
14271 {
14272 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
14273 rc = VERR_EM_INTERPRETER;
14274 }
14275 return rc;
14276}
14277
14278
14279/**
14280 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
14281 */
14282HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14283{
14284 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14285
14286 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
14287 if (EMAreHypercallInstructionsEnabled(pVCpu))
14288 {
14289 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14290 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CR0
14291 | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
14292 AssertRCReturn(rc, rc);
14293
14294 /* Perform the hypercall. */
14295 rcStrict = GIMHypercall(pVCpu, &pVCpu->cpum.GstCtx);
14296 if (rcStrict == VINF_SUCCESS)
14297 {
14298 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14299 AssertRCReturn(rc, rc);
14300 }
14301 else
14302 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
14303 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
14304 || RT_FAILURE(rcStrict));
14305
14306 /* If the hypercall changes anything other than guest's general-purpose registers,
14307 we would need to reload the guest changed bits here before VM-entry. */
14308 }
14309 else
14310 Log4Func(("Hypercalls not enabled\n"));
14311
14312 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
14313 if (RT_FAILURE(rcStrict))
14314 {
14315 hmR0VmxSetPendingXcptUD(pVCpu);
14316 rcStrict = VINF_SUCCESS;
14317 }
14318
14319 return rcStrict;
14320}
14321
14322
14323/**
14324 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
14325 */
14326HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14327{
14328 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14329 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging || pVCpu->hm.s.fUsingDebugLoop);
14330
14331 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14332 hmR0VmxReadExitQualVmcs(pVmxTransient);
14333 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14334 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
14335 AssertRCReturn(rc, rc);
14336
14337 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpg(pVCpu, pVmxTransient->cbInstr, pVmxTransient->uExitQual);
14338
14339 if (rcStrict == VINF_SUCCESS || rcStrict == VINF_PGM_SYNC_CR3)
14340 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14341 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14342 {
14343 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14344 rcStrict = VINF_SUCCESS;
14345 }
14346 else
14347 AssertMsgFailed(("Unexpected IEMExecDecodedInvlpg(%#RX64) status: %Rrc\n", pVmxTransient->uExitQual,
14348 VBOXSTRICTRC_VAL(rcStrict)));
14349 return rcStrict;
14350}
14351
14352
14353/**
14354 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
14355 */
14356HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14357{
14358 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14359
14360 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14361 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14362 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_DS);
14363 AssertRCReturn(rc, rc);
14364
14365 VBOXSTRICTRC rcStrict = IEMExecDecodedMonitor(pVCpu, pVmxTransient->cbInstr);
14366 if (rcStrict == VINF_SUCCESS)
14367 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14368 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14369 {
14370 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14371 rcStrict = VINF_SUCCESS;
14372 }
14373
14374 return rcStrict;
14375}
14376
14377
14378/**
14379 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
14380 */
14381HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14382{
14383 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14384
14385 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14386 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14387 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14388 AssertRCReturn(rc, rc);
14389
14390 VBOXSTRICTRC rcStrict = IEMExecDecodedMwait(pVCpu, pVmxTransient->cbInstr);
14391 if (RT_SUCCESS(rcStrict))
14392 {
14393 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14394 if (EMMonitorWaitShouldContinue(pVCpu, &pVCpu->cpum.GstCtx))
14395 rcStrict = VINF_SUCCESS;
14396 }
14397
14398 return rcStrict;
14399}
14400
14401
14402/**
14403 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
14404 * VM-exit.
14405 */
14406HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14407{
14408 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14409 return VINF_EM_RESET;
14410}
14411
14412
14413/**
14414 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
14415 */
14416HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14417{
14418 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14419
14420 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14421 AssertRCReturn(rc, rc);
14422
14423 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS); /* Advancing the RIP above should've imported eflags. */
14424 if (EMShouldContinueAfterHalt(pVCpu, &pVCpu->cpum.GstCtx)) /* Requires eflags. */
14425 rc = VINF_SUCCESS;
14426 else
14427 rc = VINF_EM_HALT;
14428
14429 if (rc != VINF_SUCCESS)
14430 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
14431 return rc;
14432}
14433
14434
14435/**
14436 * VM-exit handler for instructions that result in a \#UD exception delivered to
14437 * the guest.
14438 */
14439HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14440{
14441 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14442 hmR0VmxSetPendingXcptUD(pVCpu);
14443 return VINF_SUCCESS;
14444}
14445
14446
14447/**
14448 * VM-exit handler for expiry of the VMX-preemption timer.
14449 */
14450HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14451{
14452 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14453
14454 /* If the VMX-preemption timer has expired, reinitialize the preemption timer on next VM-entry. */
14455 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14456
14457 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
14458 PVM pVM = pVCpu->CTX_SUFF(pVM);
14459 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
14460 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
14461 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
14462}
14463
14464
14465/**
14466 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
14467 */
14468HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14469{
14470 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14471
14472 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14473 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14474 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_CR4);
14475 AssertRCReturn(rc, rc);
14476
14477 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbInstr);
14478 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
14479 : HM_CHANGED_RAISED_XCPT_MASK);
14480
14481 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14482 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
14483
14484 return rcStrict;
14485}
14486
14487
14488/**
14489 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
14490 */
14491HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14492{
14493 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14494 /** @todo Use VM-exit instruction information. */
14495 return VERR_EM_INTERPRETER;
14496}
14497
14498
14499/**
14500 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error
14501 * VM-exit.
14502 */
14503HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14504{
14505 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14506 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14507 AssertRCReturn(rc, rc);
14508
14509 rc = hmR0VmxCheckVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
14510 if (RT_FAILURE(rc))
14511 return rc;
14512
14513 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
14514 NOREF(uInvalidReason);
14515
14516#ifdef VBOX_STRICT
14517 uint32_t fIntrState;
14518 RTHCUINTREG uHCReg;
14519 uint64_t u64Val;
14520 uint32_t u32Val;
14521 hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
14522 hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
14523 hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
14524 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
14525 AssertRC(rc);
14526
14527 Log4(("uInvalidReason %u\n", uInvalidReason));
14528 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
14529 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
14530 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
14531 Log4(("VMX_VMCS32_GUEST_INT_STATE %#RX32\n", fIntrState));
14532
14533 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32Val); AssertRC(rc);
14534 Log4(("VMX_VMCS_GUEST_CR0 %#RX32\n", u32Val));
14535 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_MASK, &uHCReg); AssertRC(rc);
14536 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RHr\n", uHCReg));
14537 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uHCReg); AssertRC(rc);
14538 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
14539 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_MASK, &uHCReg); AssertRC(rc);
14540 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RHr\n", uHCReg));
14541 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uHCReg); AssertRC(rc);
14542 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
14543 if (pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging)
14544 {
14545 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
14546 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
14547 }
14548
14549 hmR0DumpRegs(pVCpu);
14550#endif
14551
14552 return VERR_VMX_INVALID_GUEST_STATE;
14553}
14554
14555/**
14556 * VM-exit handler for all undefined/unexpected reasons. Should never happen.
14557 */
14558HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUnexpected(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14559{
14560 /*
14561 * Cummulative notes of all recognized but unexpected VM-exits.
14562 *
14563 * 1. This does -not- cover scenarios like like a page-fault VM-exit occurring when
14564 * nested-paging is used.
14565 *
14566 * 2. Any instruction that causes a VM-exit unconditionally (for e.g. VMXON) must be
14567 * emulated or a #UD must be raised in the guest. Therefore, we should -not- be using
14568 * this function (and thereby stop VM execution) for handling such instructions.
14569 *
14570 *
14571 * VMX_EXIT_INIT_SIGNAL:
14572 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
14573 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these
14574 * VM-exits. However, we should not receive INIT signals VM-exit while executing a VM.
14575 *
14576 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery"
14577 * See Intel spec. 29.3 "VMX Instructions" for "VMXON".
14578 * See Intel spec. "23.8 Restrictions on VMX operation".
14579 *
14580 * VMX_EXIT_SIPI:
14581 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest
14582 * activity state is used. We don't make use of it as our guests don't have direct
14583 * access to the host local APIC.
14584 *
14585 * See Intel spec. 25.3 "Other Causes of VM-exits".
14586 *
14587 * VMX_EXIT_IO_SMI:
14588 * VMX_EXIT_SMI:
14589 * This can only happen if we support dual-monitor treatment of SMI, which can be
14590 * activated by executing VMCALL in VMX root operation. Only an STM (SMM transfer
14591 * monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL in
14592 * VMX root mode or receive an SMI. If we get here, something funny is going on.
14593 *
14594 * See Intel spec. 33.15.6 "Activating the Dual-Monitor Treatment"
14595 * See Intel spec. 25.3 "Other Causes of VM-Exits"
14596 *
14597 * VMX_EXIT_ERR_MSR_LOAD:
14598 * Failures while loading MSRs are part of the VM-entry MSR-load area are unexpected
14599 * and typically indicates a bug in the hypervisor code. We thus cannot not resume
14600 * execution.
14601 *
14602 * See Intel spec. 26.7 "VM-Entry Failures During Or After Loading Guest State".
14603 *
14604 * VMX_EXIT_ERR_MACHINE_CHECK:
14605 * Machine check exceptions indicates a fatal/unrecoverable hardware condition
14606 * including but not limited to system bus, ECC, parity, cache and TLB errors. A
14607 * #MC exception abort class exception is raised. We thus cannot assume a
14608 * reasonable chance of continuing any sort of execution and we bail.
14609 *
14610 * See Intel spec. 15.1 "Machine-check Architecture".
14611 * See Intel spec. 27.1 "Architectural State Before A VM Exit".
14612 *
14613 * VMX_EXIT_PML_FULL:
14614 * VMX_EXIT_VIRTUALIZED_EOI:
14615 * VMX_EXIT_APIC_WRITE:
14616 * We do not currently support any of these features and thus they are all unexpected
14617 * VM-exits.
14618 *
14619 * VMX_EXIT_GDTR_IDTR_ACCESS:
14620 * VMX_EXIT_LDTR_TR_ACCESS:
14621 * VMX_EXIT_RDRAND:
14622 * VMX_EXIT_RSM:
14623 * VMX_EXIT_VMFUNC:
14624 * VMX_EXIT_ENCLS:
14625 * VMX_EXIT_RDSEED:
14626 * VMX_EXIT_XSAVES:
14627 * VMX_EXIT_XRSTORS:
14628 * VMX_EXIT_UMWAIT:
14629 * VMX_EXIT_TPAUSE:
14630 * These VM-exits are -not- caused unconditionally by execution of the corresponding
14631 * instruction. Any VM-exit for these instructions indicate a hardware problem,
14632 * unsupported CPU modes (like SMM) or potentially corrupt VMCS controls.
14633 *
14634 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
14635 */
14636 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14637 AssertMsgFailed(("Unexpected VM-exit %u\n", pVmxTransient->uExitReason));
14638 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14639}
14640
14641
14642/**
14643 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
14644 */
14645HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14646{
14647 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14648
14649 /** @todo Optimize this: We currently drag in in the whole MSR state
14650 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
14651 * MSRs required. That would require changes to IEM and possibly CPUM too.
14652 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
14653 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14654 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
14655 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
14656 switch (idMsr)
14657 {
14658 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
14659 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
14660 }
14661
14662 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14663 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
14664 AssertRCReturn(rc, rc);
14665
14666 Log4Func(("ecx=%#RX32\n", idMsr));
14667
14668#ifdef VBOX_STRICT
14669 Assert(!pVmxTransient->fIsNestedGuest);
14670 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
14671 {
14672 if ( hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr)
14673 && idMsr != MSR_K6_EFER)
14674 {
14675 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", idMsr));
14676 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14677 }
14678 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14679 {
14680 Assert(pVmcsInfo->pvMsrBitmap);
14681 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
14682 if (fMsrpm & VMXMSRPM_ALLOW_RD)
14683 {
14684 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", idMsr));
14685 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14686 }
14687 }
14688 }
14689#endif
14690
14691 VBOXSTRICTRC rcStrict = IEMExecDecodedRdmsr(pVCpu, pVmxTransient->cbInstr);
14692 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
14693 if (rcStrict == VINF_SUCCESS)
14694 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
14695 | HM_CHANGED_GUEST_RAX | HM_CHANGED_GUEST_RDX);
14696 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14697 {
14698 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14699 rcStrict = VINF_SUCCESS;
14700 }
14701 else
14702 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_READ, ("Unexpected IEMExecDecodedRdmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
14703
14704 return rcStrict;
14705}
14706
14707
14708/**
14709 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
14710 */
14711HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14712{
14713 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14714
14715 /** @todo Optimize this: We currently drag in in the whole MSR state
14716 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
14717 * MSRs required. That would require changes to IEM and possibly CPUM too.
14718 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
14719 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
14720 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
14721
14722 /*
14723 * The FS and GS base MSRs are not part of the above all-MSRs mask.
14724 * Although we don't need to fetch the base as it will be overwritten shortly, while
14725 * loading guest-state we would also load the entire segment register including limit
14726 * and attributes and thus we need to load them here.
14727 */
14728 switch (idMsr)
14729 {
14730 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
14731 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
14732 }
14733
14734 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14735 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14736 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
14737 AssertRCReturn(rc, rc);
14738
14739 Log4Func(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", idMsr, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.eax));
14740
14741 VBOXSTRICTRC rcStrict = IEMExecDecodedWrmsr(pVCpu, pVmxTransient->cbInstr);
14742 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
14743
14744 if (rcStrict == VINF_SUCCESS)
14745 {
14746 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14747
14748 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
14749 if ( idMsr == MSR_IA32_APICBASE
14750 || ( idMsr >= MSR_IA32_X2APIC_START
14751 && idMsr <= MSR_IA32_X2APIC_END))
14752 {
14753 /*
14754 * We've already saved the APIC related guest-state (TPR) in post-run phase.
14755 * When full APIC register virtualization is implemented we'll have to make
14756 * sure APIC state is saved from the VMCS before IEM changes it.
14757 */
14758 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
14759 }
14760 else if (idMsr == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
14761 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14762 else if (idMsr == MSR_K6_EFER)
14763 {
14764 /*
14765 * If the guest touches the EFER MSR we need to update the VM-Entry and VM-Exit controls
14766 * as well, even if it is -not- touching bits that cause paging mode changes (LMA/LME).
14767 * We care about the other bits as well, SCE and NXE. See @bugref{7368}.
14768 */
14769 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
14770 }
14771
14772 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not used. */
14773 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
14774 {
14775 switch (idMsr)
14776 {
14777 case MSR_IA32_SYSENTER_CS: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
14778 case MSR_IA32_SYSENTER_EIP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
14779 case MSR_IA32_SYSENTER_ESP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
14780 case MSR_K8_FS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_FS); break;
14781 case MSR_K8_GS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_GS); break;
14782 case MSR_K6_EFER: /* Nothing to do, already handled above. */ break;
14783 default:
14784 {
14785 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14786 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_LAZY_MSRS);
14787 else if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
14788 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
14789 break;
14790 }
14791 }
14792 }
14793#ifdef VBOX_STRICT
14794 else
14795 {
14796 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
14797 switch (idMsr)
14798 {
14799 case MSR_IA32_SYSENTER_CS:
14800 case MSR_IA32_SYSENTER_EIP:
14801 case MSR_IA32_SYSENTER_ESP:
14802 case MSR_K8_FS_BASE:
14803 case MSR_K8_GS_BASE:
14804 {
14805 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", idMsr));
14806 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14807 }
14808
14809 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
14810 default:
14811 {
14812 if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
14813 {
14814 /* EFER MSR writes are always intercepted. */
14815 if (idMsr != MSR_K6_EFER)
14816 {
14817 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
14818 idMsr));
14819 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14820 }
14821 }
14822
14823 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14824 {
14825 Assert(pVmcsInfo->pvMsrBitmap);
14826 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
14827 if (fMsrpm & VMXMSRPM_ALLOW_WR)
14828 {
14829 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", idMsr));
14830 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14831 }
14832 }
14833 break;
14834 }
14835 }
14836 }
14837#endif /* VBOX_STRICT */
14838 }
14839 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14840 {
14841 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14842 rcStrict = VINF_SUCCESS;
14843 }
14844 else
14845 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_WRITE, ("Unexpected IEMExecDecodedWrmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
14846
14847 return rcStrict;
14848}
14849
14850
14851/**
14852 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
14853 */
14854HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14855{
14856 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14857
14858 /** @todo The guest has likely hit a contended spinlock. We might want to
14859 * poke a schedule different guest VCPU. */
14860 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14861 if (RT_SUCCESS(rc))
14862 return VINF_EM_RAW_INTERRUPT;
14863
14864 AssertMsgFailed(("hmR0VmxExitPause: Failed to increment RIP. rc=%Rrc\n", rc));
14865 return rc;
14866}
14867
14868
14869/**
14870 * VM-exit handler for when the TPR value is lowered below the specified
14871 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
14872 */
14873HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14874{
14875 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14876 Assert(pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
14877
14878 /*
14879 * The TPR shadow would've been synced with the APIC TPR in the post-run phase.
14880 * We'll re-evaluate pending interrupts and inject them before the next VM
14881 * entry so we can just continue execution here.
14882 */
14883 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
14884 return VINF_SUCCESS;
14885}
14886
14887
14888/**
14889 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
14890 * VM-exit.
14891 *
14892 * @retval VINF_SUCCESS when guest execution can continue.
14893 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
14894 * @retval VERR_EM_RESCHEDULE_REM when we need to return to ring-3 due to
14895 * incompatible guest state for VMX execution (real-on-v86 case).
14896 */
14897HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14898{
14899 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14900 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
14901
14902 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14903 hmR0VmxReadExitQualVmcs(pVmxTransient);
14904 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14905
14906 VBOXSTRICTRC rcStrict;
14907 PVM pVM = pVCpu->CTX_SUFF(pVM);
14908 uint64_t const uExitQual = pVmxTransient->uExitQual;
14909 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(uExitQual);
14910 switch (uAccessType)
14911 {
14912 /*
14913 * MOV to CRx.
14914 */
14915 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
14916 {
14917 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14918 AssertRCReturn(rc, rc);
14919
14920 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
14921 uint32_t const uOldCr0 = pVCpu->cpum.GstCtx.cr0;
14922 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
14923 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
14924
14925 /*
14926 * MOV to CR3 only cause a VM-exit when one or more of the following are true:
14927 * - When nested paging isn't used.
14928 * - If the guest doesn't have paging enabled (intercept CR3 to update shadow page tables).
14929 * - We are executing in the VM debug loop.
14930 */
14931 Assert( iCrReg != 3
14932 || !pVM->hm.s.fNestedPaging
14933 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
14934 || pVCpu->hm.s.fUsingDebugLoop);
14935
14936 /* MOV to CR8 writes only cause VM-exits when TPR shadow is not used. */
14937 Assert( iCrReg != 8
14938 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
14939
14940 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmcsInfo, pVmxTransient->cbInstr, iGReg, iCrReg);
14941 AssertMsg( rcStrict == VINF_SUCCESS
14942 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
14943
14944 /*
14945 * This is a kludge for handling switches back to real mode when we try to use
14946 * V86 mode to run real mode code directly. Problem is that V86 mode cannot
14947 * deal with special selector values, so we have to return to ring-3 and run
14948 * there till the selector values are V86 mode compatible.
14949 *
14950 * Note! Using VINF_EM_RESCHEDULE_REM here rather than VINF_EM_RESCHEDULE since the
14951 * latter is an alias for VINF_IEM_RAISED_XCPT which is asserted at the end of
14952 * this function.
14953 */
14954 if ( iCrReg == 0
14955 && rcStrict == VINF_SUCCESS
14956 && !pVM->hm.s.vmx.fUnrestrictedGuest
14957 && CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx)
14958 && (uOldCr0 & X86_CR0_PE)
14959 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
14960 {
14961 /** @todo Check selectors rather than returning all the time. */
14962 Assert(!pVmxTransient->fIsNestedGuest);
14963 Log4Func(("CR0 write, back to real mode -> VINF_EM_RESCHEDULE_REM\n"));
14964 rcStrict = VINF_EM_RESCHEDULE_REM;
14965 }
14966 break;
14967 }
14968
14969 /*
14970 * MOV from CRx.
14971 */
14972 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
14973 {
14974 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
14975 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
14976
14977 /*
14978 * MOV from CR3 only cause a VM-exit when one or more of the following are true:
14979 * - When nested paging isn't used.
14980 * - If the guest doesn't have paging enabled (pass guest's CR3 rather than our identity mapped CR3).
14981 * - We are executing in the VM debug loop.
14982 */
14983 Assert( iCrReg != 3
14984 || !pVM->hm.s.fNestedPaging
14985 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
14986 || pVCpu->hm.s.fUsingDebugLoop);
14987
14988 /* MOV from CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
14989 Assert( iCrReg != 8
14990 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
14991
14992 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmcsInfo, pVmxTransient->cbInstr, iGReg, iCrReg);
14993 break;
14994 }
14995
14996 /*
14997 * CLTS (Clear Task-Switch Flag in CR0).
14998 */
14999 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
15000 {
15001 rcStrict = hmR0VmxExitClts(pVCpu, pVmcsInfo, pVmxTransient->cbInstr);
15002 break;
15003 }
15004
15005 /*
15006 * LMSW (Load Machine-Status Word into CR0).
15007 * LMSW cannot clear CR0.PE, so no fRealOnV86Active kludge needed here.
15008 */
15009 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW:
15010 {
15011 RTGCPTR GCPtrEffDst;
15012 uint8_t const cbInstr = pVmxTransient->cbInstr;
15013 uint16_t const uMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(uExitQual);
15014 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(uExitQual);
15015 if (fMemOperand)
15016 {
15017 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
15018 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
15019 }
15020 else
15021 GCPtrEffDst = NIL_RTGCPTR;
15022 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmcsInfo, cbInstr, uMsw, GCPtrEffDst);
15023 break;
15024 }
15025
15026 default:
15027 {
15028 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
15029 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
15030 }
15031 }
15032
15033 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS))
15034 == (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS));
15035 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15036
15037 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
15038 NOREF(pVM);
15039 return rcStrict;
15040}
15041
15042
15043/**
15044 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
15045 * VM-exit.
15046 */
15047HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15048{
15049 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15050 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
15051
15052 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15053 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15054 hmR0VmxReadExitQualVmcs(pVmxTransient);
15055 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15056 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_SREG_MASK
15057 | CPUMCTX_EXTRN_EFER);
15058 /* EFER MSR also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
15059 AssertRCReturn(rc, rc);
15060
15061 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
15062 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
15063 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
15064 bool const fIOWrite = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
15065 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
15066 bool const fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
15067 bool const fDbgStepping = pVCpu->hm.s.fSingleInstruction;
15068 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
15069
15070 /*
15071 * Update exit history to see if this exit can be optimized.
15072 */
15073 VBOXSTRICTRC rcStrict;
15074 PCEMEXITREC pExitRec = NULL;
15075 if ( !fGstStepping
15076 && !fDbgStepping)
15077 pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15078 !fIOString
15079 ? !fIOWrite
15080 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_READ)
15081 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_WRITE)
15082 : !fIOWrite
15083 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_READ)
15084 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_WRITE),
15085 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15086 if (!pExitRec)
15087 {
15088 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
15089 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving result in AL/AX/EAX. */
15090
15091 uint32_t const cbValue = s_aIOSizes[uIOSize];
15092 uint32_t const cbInstr = pVmxTransient->cbInstr;
15093 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
15094 PVM pVM = pVCpu->CTX_SUFF(pVM);
15095 if (fIOString)
15096 {
15097 /*
15098 * INS/OUTS - I/O String instruction.
15099 *
15100 * Use instruction-information if available, otherwise fall back on
15101 * interpreting the instruction.
15102 */
15103 Log4Func(("cs:rip=%#04x:%#RX64 %#06x/%u %c str\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15104 AssertReturn(pCtx->dx == uIOPort, VERR_VMX_IPE_2);
15105 bool const fInsOutsInfo = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS);
15106 if (fInsOutsInfo)
15107 {
15108 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15109 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
15110 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
15111 IEMMODE const enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
15112 bool const fRep = VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual);
15113 if (fIOWrite)
15114 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
15115 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
15116 else
15117 {
15118 /*
15119 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
15120 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
15121 * See Intel Instruction spec. for "INS".
15122 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
15123 */
15124 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
15125 }
15126 }
15127 else
15128 rcStrict = IEMExecOne(pVCpu);
15129
15130 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15131 fUpdateRipAlready = true;
15132 }
15133 else
15134 {
15135 /*
15136 * IN/OUT - I/O instruction.
15137 */
15138 Log4Func(("cs:rip=%04x:%08RX64 %#06x/%u %c\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15139 uint32_t const uAndVal = s_aIOOpAnd[uIOSize];
15140 Assert(!VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual));
15141 if (fIOWrite)
15142 {
15143 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pCtx->eax & uAndVal, cbValue);
15144 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
15145 if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15146 && !pCtx->eflags.Bits.u1TF)
15147 rcStrict = EMRZSetPendingIoPortWrite(pVCpu, uIOPort, cbInstr, cbValue, pCtx->eax & uAndVal);
15148 }
15149 else
15150 {
15151 uint32_t u32Result = 0;
15152 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
15153 if (IOM_SUCCESS(rcStrict))
15154 {
15155 /* Save result of I/O IN instr. in AL/AX/EAX. */
15156 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Result & uAndVal);
15157 }
15158 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15159 && !pCtx->eflags.Bits.u1TF)
15160 rcStrict = EMRZSetPendingIoPortRead(pVCpu, uIOPort, cbInstr, cbValue);
15161 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
15162 }
15163 }
15164
15165 if (IOM_SUCCESS(rcStrict))
15166 {
15167 if (!fUpdateRipAlready)
15168 {
15169 hmR0VmxAdvanceGuestRipBy(pVCpu, cbInstr);
15170 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15171 }
15172
15173 /*
15174 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru
15175 * while booting Fedora 17 64-bit guest.
15176 *
15177 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
15178 */
15179 if (fIOString)
15180 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RFLAGS);
15181
15182 /*
15183 * If any I/O breakpoints are armed, we need to check if one triggered
15184 * and take appropriate action.
15185 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
15186 */
15187 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_DR7);
15188 AssertRCReturn(rc, rc);
15189
15190 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
15191 * execution engines about whether hyper BPs and such are pending. */
15192 uint32_t const uDr7 = pCtx->dr[7];
15193 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
15194 && X86_DR7_ANY_RW_IO(uDr7)
15195 && (pCtx->cr4 & X86_CR4_DE))
15196 || DBGFBpIsHwIoArmed(pVM)))
15197 {
15198 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
15199
15200 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
15201 VMMRZCallRing3Disable(pVCpu);
15202 HM_DISABLE_PREEMPT(pVCpu);
15203
15204 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
15205
15206 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, uIOPort, cbValue);
15207 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
15208 {
15209 /* Raise #DB. */
15210 if (fIsGuestDbgActive)
15211 ASMSetDR6(pCtx->dr[6]);
15212 if (pCtx->dr[7] != uDr7)
15213 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_DR7;
15214
15215 hmR0VmxSetPendingXcptDB(pVCpu);
15216 }
15217 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
15218 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
15219 else if ( rcStrict2 != VINF_SUCCESS
15220 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
15221 rcStrict = rcStrict2;
15222 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
15223
15224 HM_RESTORE_PREEMPT();
15225 VMMRZCallRing3Enable(pVCpu);
15226 }
15227 }
15228
15229#ifdef VBOX_STRICT
15230 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15231 || rcStrict == VINF_EM_PENDING_R3_IOPORT_READ)
15232 Assert(!fIOWrite);
15233 else if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15234 || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
15235 || rcStrict == VINF_EM_PENDING_R3_IOPORT_WRITE)
15236 Assert(fIOWrite);
15237 else
15238 {
15239# if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
15240 * statuses, that the VMM device and some others may return. See
15241 * IOM_SUCCESS() for guidance. */
15242 AssertMsg( RT_FAILURE(rcStrict)
15243 || rcStrict == VINF_SUCCESS
15244 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
15245 || rcStrict == VINF_EM_DBG_BREAKPOINT
15246 || rcStrict == VINF_EM_RAW_GUEST_TRAP
15247 || rcStrict == VINF_EM_RAW_TO_R3
15248 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15249# endif
15250 }
15251#endif
15252 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
15253 }
15254 else
15255 {
15256 /*
15257 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
15258 */
15259 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15260 AssertRCReturn(rc2, rc2);
15261 STAM_COUNTER_INC(!fIOString ? fIOWrite ? &pVCpu->hm.s.StatExitIOWrite : &pVCpu->hm.s.StatExitIORead
15262 : fIOWrite ? &pVCpu->hm.s.StatExitIOStringWrite : &pVCpu->hm.s.StatExitIOStringRead);
15263 Log4(("IOExit/%u: %04x:%08RX64: %s%s%s %#x LB %u -> EMHistoryExec\n",
15264 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15265 VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual) ? "REP " : "",
15266 fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOSize));
15267
15268 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15269 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15270
15271 Log4(("IOExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15272 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15273 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15274 }
15275 return rcStrict;
15276}
15277
15278
15279/**
15280 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
15281 * VM-exit.
15282 */
15283HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15284{
15285 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15286
15287 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
15288 hmR0VmxReadExitQualVmcs(pVmxTransient);
15289 if (VMX_EXIT_QUAL_TASK_SWITCH_TYPE(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT)
15290 {
15291 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15292 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
15293 {
15294 uint32_t uErrCode;
15295 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uIdtVectoringInfo))
15296 {
15297 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15298 uErrCode = pVmxTransient->uIdtVectoringErrorCode;
15299 }
15300 else
15301 uErrCode = 0;
15302
15303 RTGCUINTPTR GCPtrFaultAddress;
15304 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(pVmxTransient->uIdtVectoringInfo))
15305 GCPtrFaultAddress = pVCpu->cpum.GstCtx.cr2;
15306 else
15307 GCPtrFaultAddress = 0;
15308
15309 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15310
15311 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
15312 pVmxTransient->cbInstr, uErrCode, GCPtrFaultAddress);
15313
15314 Log4Func(("Pending event. uIntType=%#x uVector=%#x\n", VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo),
15315 VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo)));
15316 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15317 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15318 }
15319 }
15320
15321 /* Fall back to the interpreter to emulate the task-switch. */
15322 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15323 return VERR_EM_INTERPRETER;
15324}
15325
15326
15327/**
15328 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
15329 */
15330HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15331{
15332 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15333
15334 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15335 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
15336 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15337 AssertRC(rc);
15338 return VINF_EM_DBG_STEPPED;
15339}
15340
15341
15342/**
15343 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
15344 */
15345HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15346{
15347 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15348 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
15349
15350 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15351 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15352 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15353 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15354 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15355
15356 /*
15357 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15358 */
15359 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15360 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15361 {
15362 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
15363 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
15364 {
15365 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15366 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15367 }
15368 }
15369 else
15370 {
15371 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15372 return rcStrict;
15373 }
15374
15375 /* IOMMIOPhysHandler() below may call into IEM, save the necessary state. */
15376 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15377 hmR0VmxReadExitQualVmcs(pVmxTransient);
15378 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15379 AssertRCReturn(rc, rc);
15380
15381 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
15382 uint32_t const uAccessType = VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual);
15383 switch (uAccessType)
15384 {
15385 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
15386 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
15387 {
15388 AssertMsg( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
15389 || VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual) != XAPIC_OFF_TPR,
15390 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
15391
15392 RTGCPHYS GCPhys = pVCpu->hm.s.vmx.u64GstMsrApicBase; /* Always up-to-date, as it is not part of the VMCS. */
15393 GCPhys &= PAGE_BASE_GC_MASK;
15394 GCPhys += VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual);
15395 Log4Func(("Linear access uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
15396 VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual)));
15397
15398 PVM pVM = pVCpu->CTX_SUFF(pVM);
15399 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15400 rcStrict = IOMMMIOPhysHandler(pVM, pVCpu,
15401 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW,
15402 CPUMCTX2CORE(pCtx), GCPhys);
15403 Log4Func(("IOMMMIOPhysHandler returned %Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15404 if ( rcStrict == VINF_SUCCESS
15405 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15406 || rcStrict == VERR_PAGE_NOT_PRESENT)
15407 {
15408 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15409 | HM_CHANGED_GUEST_APIC_TPR);
15410 rcStrict = VINF_SUCCESS;
15411 }
15412 break;
15413 }
15414
15415 default:
15416 {
15417 Log4Func(("uAccessType=%#x\n", uAccessType));
15418 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
15419 break;
15420 }
15421 }
15422
15423 if (rcStrict != VINF_SUCCESS)
15424 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
15425 return rcStrict;
15426}
15427
15428
15429/**
15430 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
15431 * VM-exit.
15432 */
15433HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15434{
15435 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15436 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15437
15438 /* We might get this VM-exit if the nested-guest is not intercepting MOV DRx accesses. */
15439 if (!pVmxTransient->fIsNestedGuest)
15440 {
15441 /* We should -not- get this VM-exit if the guest's debug registers were active. */
15442 if (pVmxTransient->fWasGuestDebugStateActive)
15443 {
15444 AssertMsgFailed(("Unexpected MOV DRx exit\n"));
15445 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
15446 }
15447
15448 if ( !pVCpu->hm.s.fSingleInstruction
15449 && !pVmxTransient->fWasHyperDebugStateActive)
15450 {
15451 Assert(!DBGFIsStepping(pVCpu));
15452 Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB));
15453
15454 /* Don't intercept MOV DRx any more. */
15455 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
15456 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15457 AssertRC(rc);
15458
15459 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
15460 VMMRZCallRing3Disable(pVCpu);
15461 HM_DISABLE_PREEMPT(pVCpu);
15462
15463 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
15464 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
15465 Assert(CPUMIsGuestDebugStateActive(pVCpu));
15466
15467 HM_RESTORE_PREEMPT();
15468 VMMRZCallRing3Enable(pVCpu);
15469
15470#ifdef VBOX_WITH_STATISTICS
15471 hmR0VmxReadExitQualVmcs(pVmxTransient);
15472 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
15473 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
15474 else
15475 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
15476#endif
15477 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
15478 return VINF_SUCCESS;
15479 }
15480 }
15481
15482 /*
15483 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER MSR, CS.
15484 * The EFER MSR is always up-to-date.
15485 * Update the segment registers and DR7 from the CPU.
15486 */
15487 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15488 hmR0VmxReadExitQualVmcs(pVmxTransient);
15489 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_DR7);
15490 AssertRCReturn(rc, rc);
15491 Log4Func(("cs:rip=%#04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
15492
15493 PVM pVM = pVCpu->CTX_SUFF(pVM);
15494 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
15495 {
15496 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pCtx),
15497 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual),
15498 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual));
15499 if (RT_SUCCESS(rc))
15500 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
15501 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
15502 }
15503 else
15504 {
15505 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pCtx),
15506 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual),
15507 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual));
15508 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
15509 }
15510
15511 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
15512 if (RT_SUCCESS(rc))
15513 {
15514 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15515 AssertRCReturn(rc2, rc2);
15516 return VINF_SUCCESS;
15517 }
15518 return rc;
15519}
15520
15521
15522/**
15523 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
15524 * Conditional VM-exit.
15525 */
15526HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15527{
15528 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15529 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
15530
15531 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15532 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15533 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15534 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15535 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15536
15537 /*
15538 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15539 */
15540 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15541 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15542 {
15543 /*
15544 * In the unlikely case where delivering an event causes an EPT misconfig (MMIO), go back to
15545 * instruction emulation to inject the original event. Otherwise, injecting the original event
15546 * using hardware-assisted VMX would would trigger the same EPT misconfig VM-exit again.
15547 */
15548 if (!pVCpu->hm.s.Event.fPending)
15549 { /* likely */ }
15550 else
15551 {
15552 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15553#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
15554 /** @todo NSTVMX: Think about how this should be handled. */
15555 if (pVmxTransient->fIsNestedGuest)
15556 return VERR_VMX_IPE_3;
15557#endif
15558 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15559 }
15560 }
15561 else
15562 {
15563 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15564 return rcStrict;
15565 }
15566
15567 /*
15568 * Get sufficent state and update the exit history entry.
15569 */
15570 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15571 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
15572 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15573 AssertRCReturn(rc, rc);
15574
15575 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
15576 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15577 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_MMIO),
15578 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15579 if (!pExitRec)
15580 {
15581 /*
15582 * If we succeed, resume guest execution.
15583 * If we fail in interpreting the instruction because we couldn't get the guest physical address
15584 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
15585 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
15586 * weird case. See @bugref{6043}.
15587 */
15588 PVM pVM = pVCpu->CTX_SUFF(pVM);
15589 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15590 rcStrict = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pCtx), GCPhys, UINT32_MAX);
15591 Log4Func(("At %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pCtx->rip, VBOXSTRICTRC_VAL(rcStrict)));
15592 if ( rcStrict == VINF_SUCCESS
15593 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15594 || rcStrict == VERR_PAGE_NOT_PRESENT)
15595 {
15596 /* Successfully handled MMIO operation. */
15597 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15598 | HM_CHANGED_GUEST_APIC_TPR);
15599 rcStrict = VINF_SUCCESS;
15600 }
15601 }
15602 else
15603 {
15604 /*
15605 * Frequent exit or something needing probing. Call EMHistoryExec.
15606 */
15607 Log4(("EptMisscfgExit/%u: %04x:%08RX64: %RGp -> EMHistoryExec\n",
15608 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPhys));
15609
15610 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15611 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15612
15613 Log4(("EptMisscfgExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15614 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15615 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15616 }
15617 return rcStrict;
15618}
15619
15620
15621/**
15622 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
15623 * VM-exit.
15624 */
15625HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15626{
15627 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15628 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
15629
15630 hmR0VmxReadExitQualVmcs(pVmxTransient);
15631 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15632 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15633 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15634 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15635 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15636
15637 /*
15638 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15639 */
15640 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15641 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15642 {
15643 /*
15644 * If delivery of an event causes an EPT violation (true nested #PF and not MMIO),
15645 * we shall resolve the nested #PF and re-inject the original event.
15646 */
15647 if (pVCpu->hm.s.Event.fPending)
15648 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflectNPF);
15649 }
15650 else
15651 {
15652 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15653 return rcStrict;
15654 }
15655
15656 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15657 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
15658 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15659 AssertRCReturn(rc, rc);
15660
15661 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
15662 uint64_t const uExitQual = pVmxTransient->uExitQual;
15663 AssertMsg(((pVmxTransient->uExitQual >> 7) & 3) != 2, ("%#RX64", uExitQual));
15664
15665 RTGCUINT uErrorCode = 0;
15666 if (uExitQual & VMX_EXIT_QUAL_EPT_INSTR_FETCH)
15667 uErrorCode |= X86_TRAP_PF_ID;
15668 if (uExitQual & VMX_EXIT_QUAL_EPT_DATA_WRITE)
15669 uErrorCode |= X86_TRAP_PF_RW;
15670 if (uExitQual & VMX_EXIT_QUAL_EPT_ENTRY_PRESENT)
15671 uErrorCode |= X86_TRAP_PF_P;
15672
15673 PVM pVM = pVCpu->CTX_SUFF(pVM);
15674 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15675 Log4Func(("at %#RX64 (%#RX64 errcode=%#x) cs:rip=%#04x:%#RX64\n", GCPhys, uExitQual, uErrorCode, pCtx->cs.Sel, pCtx->rip));
15676
15677 /*
15678 * Handle the pagefault trap for the nested shadow table.
15679 */
15680 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
15681 rcStrict = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pCtx), GCPhys);
15682 TRPMResetTrap(pVCpu);
15683
15684 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
15685 if ( rcStrict == VINF_SUCCESS
15686 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15687 || rcStrict == VERR_PAGE_NOT_PRESENT)
15688 {
15689 /* Successfully synced our nested page tables. */
15690 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
15691 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS);
15692 return VINF_SUCCESS;
15693 }
15694
15695 Log4Func(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15696 return rcStrict;
15697}
15698
15699
15700#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
15701/**
15702 * VM-exit handler for VMCLEAR (VMX_EXIT_VMCLEAR). Unconditional VM-exit.
15703 */
15704HMVMX_EXIT_DECL hmR0VmxExitVmclear(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15705{
15706 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15707
15708 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15709 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15710 hmR0VmxReadExitQualVmcs(pVmxTransient);
15711 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15712 | CPUMCTX_EXTRN_HWVIRT
15713 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15714 AssertRCReturn(rc, rc);
15715
15716 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15717
15718 VMXVEXITINFO ExitInfo;
15719 RT_ZERO(ExitInfo);
15720 ExitInfo.uReason = pVmxTransient->uExitReason;
15721 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15722 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15723 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15724 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15725
15726 VBOXSTRICTRC rcStrict = IEMExecDecodedVmclear(pVCpu, &ExitInfo);
15727 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15728 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15729 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15730 {
15731 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15732 rcStrict = VINF_SUCCESS;
15733 }
15734 return rcStrict;
15735}
15736
15737
15738/**
15739 * VM-exit handler for VMLAUNCH (VMX_EXIT_VMLAUNCH). Unconditional VM-exit.
15740 */
15741HMVMX_EXIT_DECL hmR0VmxExitVmlaunch(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15742{
15743 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15744
15745 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMLAUNCH,
15746 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
15747 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15748 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15749 AssertRCReturn(rc, rc);
15750
15751 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15752
15753 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
15754 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbInstr, VMXINSTRID_VMLAUNCH);
15755 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
15756 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15757 {
15758 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15759 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
15760 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
15761 }
15762 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15763 return rcStrict;
15764}
15765
15766
15767/**
15768 * VM-exit handler for VMPTRLD (VMX_EXIT_VMPTRLD). Unconditional VM-exit.
15769 */
15770HMVMX_EXIT_DECL hmR0VmxExitVmptrld(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15771{
15772 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15773
15774 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15775 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15776 hmR0VmxReadExitQualVmcs(pVmxTransient);
15777 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15778 | CPUMCTX_EXTRN_HWVIRT
15779 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15780 AssertRCReturn(rc, rc);
15781
15782 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15783
15784 VMXVEXITINFO ExitInfo;
15785 RT_ZERO(ExitInfo);
15786 ExitInfo.uReason = pVmxTransient->uExitReason;
15787 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15788 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15789 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15790 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15791
15792 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrld(pVCpu, &ExitInfo);
15793 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15794 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15795 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15796 {
15797 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15798 rcStrict = VINF_SUCCESS;
15799 }
15800 return rcStrict;
15801}
15802
15803
15804/**
15805 * VM-exit handler for VMPTRST (VMX_EXIT_VMPTRST). Unconditional VM-exit.
15806 */
15807HMVMX_EXIT_DECL hmR0VmxExitVmptrst(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15808{
15809 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15810
15811 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15812 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15813 hmR0VmxReadExitQualVmcs(pVmxTransient);
15814 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15815 | CPUMCTX_EXTRN_HWVIRT
15816 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15817 AssertRCReturn(rc, rc);
15818
15819 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15820
15821 VMXVEXITINFO ExitInfo;
15822 RT_ZERO(ExitInfo);
15823 ExitInfo.uReason = pVmxTransient->uExitReason;
15824 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15825 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15826 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15827 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
15828
15829 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrst(pVCpu, &ExitInfo);
15830 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15831 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15832 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15833 {
15834 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15835 rcStrict = VINF_SUCCESS;
15836 }
15837 return rcStrict;
15838}
15839
15840
15841/**
15842 * VM-exit handler for VMREAD (VMX_EXIT_VMREAD). Conditional VM-exit.
15843 */
15844HMVMX_EXIT_DECL hmR0VmxExitVmread(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15845{
15846 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15847
15848 /*
15849 * Strictly speaking we should not get VMREAD VM-exits for shadow VMCS fields and
15850 * thus might not need to import the shadow VMCS state, it's safer just in case
15851 * code elsewhere dares look at unsynced VMCS fields.
15852 */
15853 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15854 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15855 hmR0VmxReadExitQualVmcs(pVmxTransient);
15856 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15857 | CPUMCTX_EXTRN_HWVIRT
15858 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15859 AssertRCReturn(rc, rc);
15860
15861 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15862
15863 VMXVEXITINFO ExitInfo;
15864 RT_ZERO(ExitInfo);
15865 ExitInfo.uReason = pVmxTransient->uExitReason;
15866 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15867 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15868 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15869 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
15870 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
15871
15872 VBOXSTRICTRC rcStrict = IEMExecDecodedVmread(pVCpu, &ExitInfo);
15873 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15874 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15875 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15876 {
15877 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15878 rcStrict = VINF_SUCCESS;
15879 }
15880 return rcStrict;
15881}
15882
15883
15884/**
15885 * VM-exit handler for VMRESUME (VMX_EXIT_VMRESUME). Unconditional VM-exit.
15886 */
15887HMVMX_EXIT_DECL hmR0VmxExitVmresume(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15888{
15889 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15890
15891 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMRESUME,
15892 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
15893 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15894 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15895 AssertRCReturn(rc, rc);
15896
15897 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15898
15899 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
15900 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbInstr, VMXINSTRID_VMRESUME);
15901 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
15902 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15903 {
15904 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15905 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
15906 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
15907 }
15908 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15909 return rcStrict;
15910}
15911
15912
15913/**
15914 * VM-exit handler for VMWRITE (VMX_EXIT_VMWRITE). Conditional VM-exit.
15915 */
15916HMVMX_EXIT_DECL hmR0VmxExitVmwrite(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15917{
15918 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15919
15920 /*
15921 * Although we should not get VMWRITE VM-exits for shadow VMCS fields, since our HM hook
15922 * gets invoked when IEM's VMWRITE instruction emulation modifies the current VMCS and it
15923 * flags re-loading the entire shadow VMCS, we should save the entire shadow VMCS here.
15924 */
15925 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15926 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15927 hmR0VmxReadExitQualVmcs(pVmxTransient);
15928 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15929 | CPUMCTX_EXTRN_HWVIRT
15930 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15931 AssertRCReturn(rc, rc);
15932
15933 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15934
15935 VMXVEXITINFO ExitInfo;
15936 RT_ZERO(ExitInfo);
15937 ExitInfo.uReason = pVmxTransient->uExitReason;
15938 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15939 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15940 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15941 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
15942 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15943
15944 VBOXSTRICTRC rcStrict = IEMExecDecodedVmwrite(pVCpu, &ExitInfo);
15945 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15946 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15947 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15948 {
15949 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15950 rcStrict = VINF_SUCCESS;
15951 }
15952 return rcStrict;
15953}
15954
15955
15956/**
15957 * VM-exit handler for VMXOFF (VMX_EXIT_VMXOFF). Unconditional VM-exit.
15958 */
15959HMVMX_EXIT_DECL hmR0VmxExitVmxoff(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15960{
15961 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15962
15963 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15964 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR4
15965 | CPUMCTX_EXTRN_HWVIRT
15966 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
15967 AssertRCReturn(rc, rc);
15968
15969 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15970
15971 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxoff(pVCpu, pVmxTransient->cbInstr);
15972 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15973 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_HWVIRT);
15974 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15975 {
15976 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15977 rcStrict = VINF_SUCCESS;
15978 }
15979 return rcStrict;
15980}
15981
15982
15983/**
15984 * VM-exit handler for VMXON (VMX_EXIT_VMXON). Unconditional VM-exit.
15985 */
15986HMVMX_EXIT_DECL hmR0VmxExitVmxon(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15987{
15988 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15989
15990 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15991 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15992 hmR0VmxReadExitQualVmcs(pVmxTransient);
15993 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15994 | CPUMCTX_EXTRN_HWVIRT
15995 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15996 AssertRCReturn(rc, rc);
15997
15998 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15999
16000 VMXVEXITINFO ExitInfo;
16001 RT_ZERO(ExitInfo);
16002 ExitInfo.uReason = pVmxTransient->uExitReason;
16003 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16004 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16005 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16006 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16007
16008 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxon(pVCpu, &ExitInfo);
16009 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16010 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16011 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16012 {
16013 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16014 rcStrict = VINF_SUCCESS;
16015 }
16016 return rcStrict;
16017}
16018
16019
16020/**
16021 * VM-exit handler for INVVPID (VMX_EXIT_INVVPID). Unconditional VM-exit.
16022 */
16023HMVMX_EXIT_DECL hmR0VmxExitInvvpid(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16024{
16025 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16026
16027 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16028 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16029 hmR0VmxReadExitQualVmcs(pVmxTransient);
16030 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16031 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16032 AssertRCReturn(rc, rc);
16033
16034 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16035
16036 VMXVEXITINFO ExitInfo;
16037 RT_ZERO(ExitInfo);
16038 ExitInfo.uReason = pVmxTransient->uExitReason;
16039 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16040 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16041 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16042 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16043
16044 VBOXSTRICTRC rcStrict = IEMExecDecodedInvvpid(pVCpu, &ExitInfo);
16045 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16046 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16047 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16048 {
16049 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16050 rcStrict = VINF_SUCCESS;
16051 }
16052 return rcStrict;
16053}
16054#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16055/** @} */
16056
16057
16058#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16059/** @name Nested-guest VM-exit handlers.
16060 * @{
16061 */
16062/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16063/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Nested-guest VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16064/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16065
16066/**
16067 * Nested-guest VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
16068 * Conditional VM-exit.
16069 */
16070HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmiNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16071{
16072 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16073
16074 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16075
16076 uint64_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
16077 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
16078 Assert(VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo));
16079
16080 switch (uExitIntType)
16081 {
16082 /*
16083 * Physical NMIs:
16084 * We shouldn't direct host physical NMIs to the nested-guest. Dispatch it to the host.
16085 */
16086 case VMX_EXIT_INT_INFO_TYPE_NMI:
16087 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
16088
16089 /*
16090 * Hardware exceptions,
16091 * Software exceptions,
16092 * Privileged software exceptions:
16093 * Figure out if the exception must be delivered to the guest or the nested-guest.
16094 */
16095 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
16096 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
16097 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
16098 {
16099 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16100 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16101 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16102 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16103
16104 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16105 bool const fIntercept = CPUMIsGuestVmxXcptInterceptSet(pVCpu, pCtx, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo),
16106 pVmxTransient->uExitIntErrorCode);
16107 if (fIntercept)
16108 {
16109 /* Exit qualification is required for debug and page-fault exceptions. */
16110 hmR0VmxReadExitQualVmcs(pVmxTransient);
16111
16112 /*
16113 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged
16114 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
16115 * length. However, if delivery of a software interrupt, software exception or privileged
16116 * software exception causes a VM-exit, that too provides the VM-exit instruction length.
16117 */
16118 VMXVEXITINFO ExitInfo;
16119 RT_ZERO(ExitInfo);
16120 ExitInfo.uReason = pVmxTransient->uExitReason;
16121 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16122 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16123
16124 VMXVEXITEVENTINFO ExitEventInfo;
16125 RT_ZERO(ExitEventInfo);
16126 ExitEventInfo.uExitIntInfo = pVmxTransient->uExitIntInfo;
16127 ExitEventInfo.uExitIntErrCode = pVmxTransient->uExitIntErrorCode;
16128 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16129 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16130
16131#ifdef DEBUG_ramshankar
16132 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
16133 Log4Func(("cs:rip=%#04x:%#RX64 %s err_code=%#x exit_qual=%#RX64\n", pCtx->cs.Sel, pCtx->rip,
16134 VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo) ? "#PF" : "Unk",
16135 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual));
16136 Log4Func(("idt_info=%#RX64 (%s) idt_errcode=%#RX32\n", pVmxTransient->uIdtVectoringInfo,
16137 VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo) ? "Valid" : "Invalid",
16138 pVmxTransient->uIdtVectoringErrorCode));
16139#endif
16140 return IEMExecVmxVmexitXcpt(pVCpu, &ExitInfo, &ExitEventInfo);
16141 }
16142
16143 /* Nested paging is currently a requirement, otherwise we would need to handle shadow #PFs in hmR0VmxExitXcptPF. */
16144 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
16145 return hmR0VmxExitXcpt(pVCpu, pVmxTransient);
16146 }
16147
16148 /*
16149 * Software interrupts:
16150 * VM-exits cannot be caused by software interrupts.
16151 *
16152 * External interrupts:
16153 * This should only happen when "acknowledge external interrupts on VM-exit"
16154 * control is set. However, we never set this when executing a guest or
16155 * nested-guest. For nested-guests it is emulated while injecting interrupts into
16156 * the guest.
16157 */
16158 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
16159 case VMX_EXIT_INT_INFO_TYPE_EXT_INT:
16160 default:
16161 {
16162 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
16163 return VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
16164 }
16165 }
16166}
16167
16168
16169/**
16170 * Nested-guest VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT).
16171 * Unconditional VM-exit.
16172 */
16173HMVMX_EXIT_DECL hmR0VmxExitTripleFaultNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16174{
16175 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16176 return IEMExecVmxVmexitTripleFault(pVCpu);
16177}
16178
16179
16180/**
16181 * Nested-guest VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
16182 */
16183HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindowNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16184{
16185 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16186
16187 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
16188 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16189 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16190}
16191
16192
16193/**
16194 * Nested-guest VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
16195 */
16196HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindowNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16197{
16198 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16199
16200 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT))
16201 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16202 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16203}
16204
16205
16206/**
16207 * Nested-guest VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH).
16208 * Unconditional VM-exit.
16209 */
16210HMVMX_EXIT_DECL hmR0VmxExitTaskSwitchNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16211{
16212 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16213
16214 hmR0VmxReadExitQualVmcs(pVmxTransient);
16215 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16216 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16217 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16218
16219 VMXVEXITINFO ExitInfo;
16220 RT_ZERO(ExitInfo);
16221 ExitInfo.uReason = pVmxTransient->uExitReason;
16222 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16223 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16224
16225 VMXVEXITEVENTINFO ExitEventInfo;
16226 RT_ZERO(ExitEventInfo);
16227 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16228 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16229 return IEMExecVmxVmexitTaskSwitch(pVCpu, &ExitInfo, &ExitEventInfo);
16230}
16231
16232
16233/**
16234 * Nested-guest VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
16235 */
16236HMVMX_EXIT_DECL hmR0VmxExitHltNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16237{
16238 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16239
16240 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_HLT_EXIT))
16241 {
16242 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16243 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16244 }
16245 return hmR0VmxExitHlt(pVCpu, pVmxTransient);
16246}
16247
16248
16249/**
16250 * Nested-guest VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
16251 */
16252HMVMX_EXIT_DECL hmR0VmxExitInvlpgNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16253{
16254 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16255
16256 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16257 {
16258 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16259 hmR0VmxReadExitQualVmcs(pVmxTransient);
16260
16261 VMXVEXITINFO ExitInfo;
16262 RT_ZERO(ExitInfo);
16263 ExitInfo.uReason = pVmxTransient->uExitReason;
16264 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16265 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16266 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16267 }
16268 return hmR0VmxExitInvlpg(pVCpu, pVmxTransient);
16269}
16270
16271
16272/**
16273 * Nested-guest VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
16274 */
16275HMVMX_EXIT_DECL hmR0VmxExitRdpmcNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16276{
16277 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16278
16279 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDPMC_EXIT))
16280 {
16281 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16282 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16283 }
16284 return hmR0VmxExitRdpmc(pVCpu, pVmxTransient);
16285}
16286
16287
16288/**
16289 * Nested-guest VM-exit handler for VMREAD (VMX_EXIT_VMREAD) and VMWRITE
16290 * (VMX_EXIT_VMWRITE). Conditional VM-exit.
16291 */
16292HMVMX_EXIT_DECL hmR0VmxExitVmreadVmwriteNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16293{
16294 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16295
16296 Assert( pVmxTransient->uExitReason == VMX_EXIT_VMREAD
16297 || pVmxTransient->uExitReason == VMX_EXIT_VMWRITE);
16298
16299 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16300
16301 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
16302 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16303 uint64_t u64VmcsField = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16304
16305 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
16306 if (!CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
16307 u64VmcsField &= UINT64_C(0xffffffff);
16308
16309 if (CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, pVmxTransient->uExitReason, u64VmcsField))
16310 {
16311 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16312 hmR0VmxReadExitQualVmcs(pVmxTransient);
16313
16314 VMXVEXITINFO ExitInfo;
16315 RT_ZERO(ExitInfo);
16316 ExitInfo.uReason = pVmxTransient->uExitReason;
16317 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16318 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16319 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16320 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16321 }
16322
16323 if (pVmxTransient->uExitReason == VMX_EXIT_VMREAD)
16324 return hmR0VmxExitVmread(pVCpu, pVmxTransient);
16325 return hmR0VmxExitVmwrite(pVCpu, pVmxTransient);
16326}
16327
16328
16329/**
16330 * Nested-guest VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
16331 */
16332HMVMX_EXIT_DECL hmR0VmxExitRdtscNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16333{
16334 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16335
16336 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16337 {
16338 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16339 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16340 }
16341
16342 return hmR0VmxExitRdtsc(pVCpu, pVmxTransient);
16343}
16344
16345
16346/**
16347 * Nested-guest VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX).
16348 * Conditional VM-exit.
16349 */
16350HMVMX_EXIT_DECL hmR0VmxExitMovCRxNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16351{
16352 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16353
16354 hmR0VmxReadExitQualVmcs(pVmxTransient);
16355 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16356
16357 VBOXSTRICTRC rcStrict;
16358 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual);
16359 switch (uAccessType)
16360 {
16361 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
16362 {
16363 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16364 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
16365 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16366 uint64_t const uNewCrX = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16367
16368 bool fIntercept;
16369 switch (iCrReg)
16370 {
16371 case 0:
16372 case 4:
16373 fIntercept = CPUMIsGuestVmxMovToCr0Cr4InterceptSet(pVCpu, &pVCpu->cpum.GstCtx, iCrReg, uNewCrX);
16374 break;
16375
16376 case 3:
16377 fIntercept = CPUMIsGuestVmxMovToCr3InterceptSet(pVCpu, uNewCrX);
16378 break;
16379
16380 case 8:
16381 fIntercept = CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_CR8_LOAD_EXIT);
16382 break;
16383
16384 default:
16385 fIntercept = false;
16386 break;
16387 }
16388 if (fIntercept)
16389 {
16390 VMXVEXITINFO ExitInfo;
16391 RT_ZERO(ExitInfo);
16392 ExitInfo.uReason = pVmxTransient->uExitReason;
16393 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16394 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16395 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16396 }
16397 else
16398 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbInstr, iGReg, iCrReg);
16399 break;
16400 }
16401
16402 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
16403 {
16404 /*
16405 * CR0/CR4 reads do not cause VM-exits, the read-shadow is used (subject to masking).
16406 * CR2 reads do not cause a VM-exit.
16407 * CR3 reads cause a VM-exit depending on the "CR3 store exiting" control.
16408 * CR8 reads cause a VM-exit depending on the "CR8 store exiting" control.
16409 */
16410 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16411 if ( iCrReg == 3
16412 || iCrReg == 8)
16413 {
16414 static const uint32_t s_auCrXReadIntercepts[] = { 0, 0, 0, VMX_PROC_CTLS_CR3_STORE_EXIT, 0,
16415 0, 0, 0, VMX_PROC_CTLS_CR8_STORE_EXIT };
16416 uint32_t const uIntercept = s_auCrXReadIntercepts[iCrReg];
16417 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uIntercept))
16418 {
16419 VMXVEXITINFO ExitInfo;
16420 RT_ZERO(ExitInfo);
16421 ExitInfo.uReason = pVmxTransient->uExitReason;
16422 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16423 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16424 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16425 }
16426 else
16427 {
16428 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
16429 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbInstr, iGReg, iCrReg);
16430 }
16431 }
16432 else
16433 {
16434 AssertMsgFailed(("MOV from CR%d VM-exit must not happen\n", iCrReg));
16435 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, iCrReg);
16436 }
16437 break;
16438 }
16439
16440 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
16441 {
16442 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
16443 Assert(pVmcsNstGst);
16444 uint64_t const uGstHostMask = pVmcsNstGst->u64Cr0Mask.u;
16445 uint64_t const uReadShadow = pVmcsNstGst->u64Cr0ReadShadow.u;
16446 if ( (uGstHostMask & X86_CR0_TS)
16447 && (uReadShadow & X86_CR0_TS))
16448 {
16449 VMXVEXITINFO ExitInfo;
16450 RT_ZERO(ExitInfo);
16451 ExitInfo.uReason = pVmxTransient->uExitReason;
16452 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16453 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16454 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16455 }
16456 else
16457 rcStrict = hmR0VmxExitClts(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbInstr);
16458 break;
16459 }
16460
16461 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
16462 {
16463 RTGCPTR GCPtrEffDst;
16464 uint16_t const uNewMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(pVmxTransient->uExitQual);
16465 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(pVmxTransient->uExitQual);
16466 if (fMemOperand)
16467 {
16468 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
16469 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
16470 }
16471 else
16472 GCPtrEffDst = NIL_RTGCPTR;
16473
16474 if (CPUMIsGuestVmxLmswInterceptSet(pVCpu, &pVCpu->cpum.GstCtx, uNewMsw))
16475 {
16476 VMXVEXITINFO ExitInfo;
16477 RT_ZERO(ExitInfo);
16478 ExitInfo.uReason = pVmxTransient->uExitReason;
16479 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16480 ExitInfo.u64GuestLinearAddr = GCPtrEffDst;
16481 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16482 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16483 }
16484 else
16485 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbInstr, uNewMsw, GCPtrEffDst);
16486 break;
16487 }
16488
16489 default:
16490 {
16491 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
16492 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
16493 }
16494 }
16495
16496 if (rcStrict == VINF_IEM_RAISED_XCPT)
16497 {
16498 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16499 rcStrict = VINF_SUCCESS;
16500 }
16501 return rcStrict;
16502}
16503
16504
16505/**
16506 * Nested-guest VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX).
16507 * Conditional VM-exit.
16508 */
16509HMVMX_EXIT_DECL hmR0VmxExitMovDRxNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16510{
16511 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16512
16513 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MOV_DR_EXIT))
16514 {
16515 hmR0VmxReadExitQualVmcs(pVmxTransient);
16516 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16517
16518 VMXVEXITINFO ExitInfo;
16519 RT_ZERO(ExitInfo);
16520 ExitInfo.uReason = pVmxTransient->uExitReason;
16521 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16522 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16523 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16524 }
16525 return hmR0VmxExitMovDRx(pVCpu, pVmxTransient);
16526}
16527
16528
16529/**
16530 * Nested-guest VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR).
16531 * Conditional VM-exit.
16532 */
16533HMVMX_EXIT_DECL hmR0VmxExitIoInstrNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16534{
16535 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16536
16537 hmR0VmxReadExitQualVmcs(pVmxTransient);
16538
16539 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
16540 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
16541 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
16542
16543 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
16544 uint8_t const cbAccess = s_aIOSizes[uIOSize];
16545 if (CPUMIsGuestVmxIoInterceptSet(pVCpu, uIOPort, cbAccess))
16546 {
16547 /*
16548 * IN/OUT instruction:
16549 * - Provides VM-exit instruction length.
16550 *
16551 * INS/OUTS instruction:
16552 * - Provides VM-exit instruction length.
16553 * - Provides Guest-linear address.
16554 * - Optionally provides VM-exit instruction info (depends on CPU feature).
16555 */
16556 PVM pVM = pVCpu->CTX_SUFF(pVM);
16557 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16558
16559 /* Make sure we don't use stale/uninitialized VMX-transient info. below. */
16560 pVmxTransient->ExitInstrInfo.u = 0;
16561 pVmxTransient->uGuestLinearAddr = 0;
16562
16563 bool const fVmxInsOutsInfo = pVM->cpum.ro.GuestFeatures.fVmxInsOutInfo;
16564 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
16565 if (fIOString)
16566 {
16567 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
16568 if (fVmxInsOutsInfo)
16569 {
16570 Assert(RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS)); /* Paranoia. */
16571 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16572 }
16573 }
16574
16575 VMXVEXITINFO ExitInfo;
16576 RT_ZERO(ExitInfo);
16577 ExitInfo.uReason = pVmxTransient->uExitReason;
16578 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16579 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16580 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16581 ExitInfo.u64GuestLinearAddr = pVmxTransient->uGuestLinearAddr;
16582 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16583 }
16584 return hmR0VmxExitIoInstr(pVCpu, pVmxTransient);
16585}
16586
16587
16588/**
16589 * Nested-guest VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
16590 */
16591HMVMX_EXIT_DECL hmR0VmxExitRdmsrNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16592{
16593 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16594
16595 uint32_t fMsrpm;
16596 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
16597 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
16598 else
16599 fMsrpm = VMXMSRPM_EXIT_RD;
16600
16601 if (fMsrpm & VMXMSRPM_EXIT_RD)
16602 {
16603 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16604 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16605 }
16606 return hmR0VmxExitRdmsr(pVCpu, pVmxTransient);
16607}
16608
16609
16610/**
16611 * Nested-guest VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
16612 */
16613HMVMX_EXIT_DECL hmR0VmxExitWrmsrNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16614{
16615 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16616
16617 uint32_t fMsrpm;
16618 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
16619 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
16620 else
16621 fMsrpm = VMXMSRPM_EXIT_WR;
16622
16623 if (fMsrpm & VMXMSRPM_EXIT_WR)
16624 {
16625 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16626 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16627 }
16628 return hmR0VmxExitWrmsr(pVCpu, pVmxTransient);
16629}
16630
16631
16632/**
16633 * Nested-guest VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
16634 */
16635HMVMX_EXIT_DECL hmR0VmxExitMwaitNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16636{
16637 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16638
16639 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MWAIT_EXIT))
16640 {
16641 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16642 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16643 }
16644 return hmR0VmxExitMwait(pVCpu, pVmxTransient);
16645}
16646
16647
16648/**
16649 * Nested-guest VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional
16650 * VM-exit.
16651 */
16652HMVMX_EXIT_DECL hmR0VmxExitMtfNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16653{
16654 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16655
16656 /** @todo NSTVMX: Should consider debugging nested-guests using VM debugger. */
16657 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16658}
16659
16660
16661/**
16662 * Nested-guest VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
16663 */
16664HMVMX_EXIT_DECL hmR0VmxExitMonitorNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16665{
16666 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16667
16668 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MONITOR_EXIT))
16669 {
16670 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16671 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16672 }
16673 return hmR0VmxExitMonitor(pVCpu, pVmxTransient);
16674}
16675
16676
16677/**
16678 * Nested-guest VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
16679 */
16680HMVMX_EXIT_DECL hmR0VmxExitPauseNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16681{
16682 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16683
16684 /** @todo NSTVMX: Think about this more. Does the outer guest need to intercept
16685 * PAUSE when executing a nested-guest? If it does not, we would not need
16686 * to check for the intercepts here. Just call VM-exit... */
16687
16688 /* The CPU would have already performed the necessary CPL checks for PAUSE-loop exiting. */
16689 if ( CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_PAUSE_EXIT)
16690 || CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
16691 {
16692 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16693 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16694 }
16695 return hmR0VmxExitPause(pVCpu, pVmxTransient);
16696}
16697
16698
16699/**
16700 * Nested-guest VM-exit handler for when the TPR value is lowered below the
16701 * specified threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
16702 */
16703HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThresholdNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16704{
16705 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16706
16707 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_TPR_SHADOW))
16708 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16709 return hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient);
16710}
16711
16712
16713/**
16714 * Nested-guest VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional
16715 * VM-exit.
16716 */
16717HMVMX_EXIT_DECL hmR0VmxExitApicAccessNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16718{
16719 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16720
16721 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16722 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16723 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16724 hmR0VmxReadExitQualVmcs(pVmxTransient);
16725
16726 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
16727
16728 VMXVEXITINFO ExitInfo;
16729 RT_ZERO(ExitInfo);
16730 ExitInfo.uReason = pVmxTransient->uExitReason;
16731 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16732 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16733
16734 VMXVEXITEVENTINFO ExitEventInfo;
16735 RT_ZERO(ExitEventInfo);
16736 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16737 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16738 return IEMExecVmxVmexitApicAccess(pVCpu, &ExitInfo, &ExitEventInfo);
16739}
16740
16741
16742/**
16743 * Nested-guest VM-exit handler for APIC write emulation (VMX_EXIT_APIC_WRITE).
16744 * Conditional VM-exit.
16745 */
16746HMVMX_EXIT_DECL hmR0VmxExitApicWriteNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16747{
16748 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16749
16750 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_APIC_REG_VIRT));
16751 hmR0VmxReadExitQualVmcs(pVmxTransient);
16752 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
16753}
16754
16755
16756/**
16757 * Nested-guest VM-exit handler for virtualized EOI (VMX_EXIT_VIRTUALIZED_EOI).
16758 * Conditional VM-exit.
16759 */
16760HMVMX_EXIT_DECL hmR0VmxExitVirtEoiNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16761{
16762 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16763
16764 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_INT_DELIVERY));
16765 hmR0VmxReadExitQualVmcs(pVmxTransient);
16766 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
16767}
16768
16769
16770/**
16771 * Nested-guest VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
16772 */
16773HMVMX_EXIT_DECL hmR0VmxExitRdtscpNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16774{
16775 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16776
16777 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16778 {
16779 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_RDTSCP));
16780 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16781 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16782 }
16783 return hmR0VmxExitRdtscp(pVCpu, pVmxTransient);
16784}
16785
16786
16787/**
16788 * Nested-guest VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
16789 */
16790HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvdNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16791{
16792 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16793
16794 if (CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_WBINVD_EXIT))
16795 {
16796 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16797 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16798 }
16799 return hmR0VmxExitWbinvd(pVCpu, pVmxTransient);
16800}
16801
16802
16803/**
16804 * Nested-guest VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
16805 */
16806HMVMX_EXIT_DECL hmR0VmxExitInvpcidNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16807{
16808 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16809
16810 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16811 {
16812 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_INVPCID));
16813 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16814 hmR0VmxReadExitQualVmcs(pVmxTransient);
16815 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16816
16817 VMXVEXITINFO ExitInfo;
16818 RT_ZERO(ExitInfo);
16819 ExitInfo.uReason = pVmxTransient->uExitReason;
16820 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16821 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16822 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16823 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16824 }
16825 return hmR0VmxExitInvpcid(pVCpu, pVmxTransient);
16826}
16827
16828
16829/**
16830 * Nested-guest VM-exit handler for invalid-guest state
16831 * (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error VM-exit.
16832 */
16833HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestStateNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16834{
16835 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16836
16837 /*
16838 * Currently this should never happen because we fully emulate VMLAUNCH/VMRESUME in IEM.
16839 * So if it does happen, it indicates a bug possibly in the hardware-assisted VMX code.
16840 * Handle it like it's in an invalid guest state of the outer guest.
16841 *
16842 * When the fast path is implemented, this should be changed to cause the corresponding
16843 * nested-guest VM-exit.
16844 */
16845 return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
16846}
16847
16848
16849/**
16850 * Nested-guest VM-exit handler for instructions that cause VM-exits uncondtionally
16851 * and only provide the instruction length.
16852 *
16853 * Unconditional VM-exit.
16854 */
16855HMVMX_EXIT_DECL hmR0VmxExitInstrNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16856{
16857 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16858
16859#ifdef VBOX_STRICT
16860 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16861 switch (pVmxTransient->uExitReason)
16862 {
16863 case VMX_EXIT_ENCLS:
16864 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_ENCLS_EXIT));
16865 break;
16866
16867 case VMX_EXIT_VMFUNC:
16868 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_VMFUNC));
16869 break;
16870 }
16871#endif
16872
16873 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16874 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16875}
16876
16877
16878/**
16879 * Nested-guest VM-exit handler for instructions that provide instruction length as
16880 * well as more information.
16881 *
16882 * Unconditional VM-exit.
16883 */
16884HMVMX_EXIT_DECL hmR0VmxExitInstrWithInfoNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16885{
16886 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16887
16888#ifdef VBOX_STRICT
16889 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16890 switch (pVmxTransient->uExitReason)
16891 {
16892 case VMX_EXIT_GDTR_IDTR_ACCESS:
16893 case VMX_EXIT_LDTR_TR_ACCESS:
16894 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_DESC_TABLE_EXIT));
16895 break;
16896
16897 case VMX_EXIT_RDRAND:
16898 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_RDRAND_EXIT));
16899 break;
16900
16901 case VMX_EXIT_RDSEED:
16902 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_RDSEED_EXIT));
16903 break;
16904
16905 case VMX_EXIT_XSAVES:
16906 case VMX_EXIT_XRSTORS:
16907 /** @todo NSTVMX: Verify XSS-bitmap. */
16908 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_XSAVES_XRSTORS));
16909 break;
16910
16911 case VMX_EXIT_UMWAIT:
16912 case VMX_EXIT_TPAUSE:
16913 Assert(CPUMIsGuestVmxProcCtlsSet(pVCpu, pCtx, VMX_PROC_CTLS_RDTSC_EXIT));
16914 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_USER_WAIT_PAUSE));
16915 break;
16916 }
16917#endif
16918
16919 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16920 hmR0VmxReadExitQualVmcs(pVmxTransient);
16921 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16922
16923 VMXVEXITINFO ExitInfo;
16924 RT_ZERO(ExitInfo);
16925 ExitInfo.uReason = pVmxTransient->uExitReason;
16926 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16927 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16928 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16929 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16930}
16931
16932/** @} */
16933#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16934
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