VirtualBox

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

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

VMM/HMVMXR0: Nested VMX: bugref:9180 Set VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS while merging VMCS. nits.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 700.1 KB
Line 
1/* $Id: HMVMXR0.cpp 80196 2019-08-08 08:35:30Z 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 pVmcsInfo The VMCS info. object.
4745 * @param u32TprThreshold The TPR threshold (task-priority class only).
4746 */
4747DECLINLINE(void) hmR0VmxApicSetTprThreshold(PVMXVMCSINFO pVmcsInfo, uint32_t u32TprThreshold)
4748{
4749 Assert(!(u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)); /* Bits 31:4 MBZ. */
4750 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
4751 RT_NOREF(pVmcsInfo);
4752 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
4753 AssertRC(rc);
4754}
4755
4756
4757/**
4758 * Exports the guest APIC TPR state into the VMCS.
4759 *
4760 * @returns VBox status code.
4761 * @param pVCpu The cross context virtual CPU structure.
4762 * @param pVmxTransient The VMX-transient structure.
4763 *
4764 * @remarks No-long-jump zone!!!
4765 */
4766static int hmR0VmxExportGuestApicTpr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
4767{
4768 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_APIC_TPR)
4769 {
4770 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
4771
4772 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4773 if (!pVmxTransient->fIsNestedGuest)
4774 {
4775 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
4776 && APICIsEnabled(pVCpu))
4777 {
4778 /*
4779 * Setup TPR shadowing.
4780 */
4781 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
4782 {
4783 bool fPendingIntr = false;
4784 uint8_t u8Tpr = 0;
4785 uint8_t u8PendingIntr = 0;
4786 int rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
4787 AssertRCReturn(rc, rc);
4788
4789 /*
4790 * If there are interrupts pending but masked by the TPR, instruct VT-x to
4791 * cause a TPR-below-threshold VM-exit when the guest lowers its TPR below the
4792 * priority of the pending interrupt so we can deliver the interrupt. If there
4793 * are no interrupts pending, set threshold to 0 to not cause any
4794 * TPR-below-threshold VM-exits.
4795 */
4796 uint32_t u32TprThreshold = 0;
4797 if (fPendingIntr)
4798 {
4799 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR
4800 (which is the Task-Priority Class). */
4801 const uint8_t u8PendingPriority = u8PendingIntr >> 4;
4802 const uint8_t u8TprPriority = u8Tpr >> 4;
4803 if (u8PendingPriority <= u8TprPriority)
4804 u32TprThreshold = u8PendingPriority;
4805 }
4806
4807 hmR0VmxApicSetTprThreshold(pVmcsInfo, u32TprThreshold);
4808 }
4809 }
4810 }
4811 /* else: the TPR threshold has already been updated while merging the nested-guest VMCS. */
4812 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
4813 }
4814 return VINF_SUCCESS;
4815}
4816
4817
4818/**
4819 * Gets the guest interruptibility-state.
4820 *
4821 * @returns Guest's interruptibility-state.
4822 * @param pVCpu The cross context virtual CPU structure.
4823 * @param pVmxTransient The VMX-transient structure.
4824 *
4825 * @remarks No-long-jump zone!!!
4826 */
4827static uint32_t hmR0VmxGetGuestIntrState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
4828{
4829 /*
4830 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
4831 */
4832 uint32_t fIntrState = 0;
4833 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
4834 {
4835 /* If inhibition is active, RIP and RFLAGS should've been imported from the VMCS already. */
4836 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
4837
4838 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4839 if (pCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
4840 {
4841 if (pCtx->eflags.Bits.u1IF)
4842 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
4843 else
4844 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS;
4845 }
4846 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
4847 {
4848 /*
4849 * We can clear the inhibit force flag as even if we go back to the recompiler
4850 * without executing guest code in VT-x, the flag's condition to be cleared is
4851 * met and thus the cleared state is correct.
4852 */
4853 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
4854 }
4855 }
4856
4857 /*
4858 * NMIs to the guest are blocked after an NMI is injected until the guest executes an IRET. We only
4859 * bother with virtual-NMI blocking when we have support for virtual NMIs in the CPU, otherwise
4860 * setting this would block host-NMIs and IRET will not clear the blocking.
4861 *
4862 * We always set NMI-exiting so when the host receives an NMI we get a VM-exit.
4863 *
4864 * See Intel spec. 26.6.1 "Interruptibility state". See @bugref{7445}.
4865 */
4866 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4867 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
4868 && CPUMIsGuestNmiBlocking(pVCpu))
4869 fIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
4870
4871 return fIntrState;
4872}
4873
4874
4875/**
4876 * Exports the exception intercepts required for guest execution in the VMCS.
4877 *
4878 * @returns VBox status code.
4879 * @param pVCpu The cross context virtual CPU structure.
4880 * @param pVmxTransient The VMX-transient structure.
4881 *
4882 * @remarks No-long-jump zone!!!
4883 */
4884static int hmR0VmxExportGuestXcptIntercepts(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
4885{
4886 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_XCPT_INTERCEPTS)
4887 {
4888 /* When executing a nested-guest, we do not need to trap GIM hypercalls by intercepting #UD. */
4889 if ( !pVmxTransient->fIsNestedGuest
4890 && pVCpu->hm.s.fGIMTrapXcptUD)
4891 hmR0VmxAddXcptIntercept(pVmxTransient, X86_XCPT_UD);
4892 else
4893 hmR0VmxRemoveXcptIntercept(pVCpu, pVmxTransient, X86_XCPT_UD);
4894
4895 /* Other exception intercepts are handled elsewhere, e.g. while exporting guest CR0. */
4896 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_XCPT_INTERCEPTS);
4897 }
4898 return VINF_SUCCESS;
4899}
4900
4901
4902/**
4903 * Exports the guest's RIP into the guest-state area in the VMCS.
4904 *
4905 * @returns VBox status code.
4906 * @param pVCpu The cross context virtual CPU structure.
4907 *
4908 * @remarks No-long-jump zone!!!
4909 */
4910static int hmR0VmxExportGuestRip(PVMCPU pVCpu)
4911{
4912 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RIP)
4913 {
4914 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP);
4915
4916 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RIP, pVCpu->cpum.GstCtx.rip);
4917 AssertRC(rc);
4918
4919 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RIP);
4920 Log4Func(("rip=%#RX64\n", pVCpu->cpum.GstCtx.rip));
4921 }
4922 return VINF_SUCCESS;
4923}
4924
4925
4926/**
4927 * Exports the guest's RSP into the guest-state area in the VMCS.
4928 *
4929 * @returns VBox status code.
4930 * @param pVCpu The cross context virtual CPU structure.
4931 *
4932 * @remarks No-long-jump zone!!!
4933 */
4934static int hmR0VmxExportGuestRsp(PVMCPU pVCpu)
4935{
4936 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RSP)
4937 {
4938 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RSP);
4939
4940 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RSP, pVCpu->cpum.GstCtx.rsp);
4941 AssertRC(rc);
4942
4943 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RSP);
4944 }
4945 return VINF_SUCCESS;
4946}
4947
4948
4949/**
4950 * Exports the guest's RFLAGS into the guest-state area in the VMCS.
4951 *
4952 * @returns VBox status code.
4953 * @param pVCpu The cross context virtual CPU structure.
4954 * @param pVmxTransient The VMX-transient structure.
4955 *
4956 * @remarks No-long-jump zone!!!
4957 */
4958static int hmR0VmxExportGuestRflags(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
4959{
4960 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RFLAGS)
4961 {
4962 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
4963
4964 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
4965 Let us assert it as such and use 32-bit VMWRITE. */
4966 Assert(!RT_HI_U32(pVCpu->cpum.GstCtx.rflags.u64));
4967 X86EFLAGS fEFlags = pVCpu->cpum.GstCtx.eflags;
4968 Assert(fEFlags.u32 & X86_EFL_RA1_MASK);
4969 Assert(!(fEFlags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
4970
4971 /*
4972 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so
4973 * we can restore them on VM-exit. Modify the real-mode guest's eflags so that VT-x
4974 * can run the real-mode guest code under Virtual 8086 mode.
4975 */
4976 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4977 if (pVmcsInfo->RealMode.fRealOnV86Active)
4978 {
4979 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
4980 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
4981 Assert(!pVmxTransient->fIsNestedGuest);
4982 pVmcsInfo->RealMode.Eflags.u32 = fEFlags.u32; /* Save the original eflags of the real-mode guest. */
4983 fEFlags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
4984 fEFlags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
4985 }
4986
4987 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RFLAGS, fEFlags.u32);
4988 AssertRC(rc);
4989
4990 /*
4991 * Setup pending debug exceptions if the guest is single-stepping using EFLAGS.TF.
4992 *
4993 * We must avoid setting any automatic debug exceptions delivery when single-stepping
4994 * through the hypervisor debugger using EFLAGS.TF.
4995 */
4996 if ( !pVmxTransient->fIsNestedGuest
4997 && !pVCpu->hm.s.fSingleInstruction
4998 && fEFlags.Bits.u1TF)
4999 {
5000 /** @todo r=ramshankar: Warning!! We ASSUME EFLAGS.TF will not cleared on
5001 * premature trips to ring-3 esp since IEM does not yet handle it. */
5002 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS);
5003 AssertRC(rc);
5004 }
5005 /* else: for nested-guest currently handling while merging controls. */
5006
5007 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RFLAGS);
5008 Log4Func(("eflags=%#RX32\n", fEFlags.u32));
5009 }
5010 return VINF_SUCCESS;
5011}
5012
5013
5014#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5015/**
5016 * Copies the nested-guest VMCS to the shadow VMCS.
5017 *
5018 * @returns VBox status code.
5019 * @param pVCpu The cross context virtual CPU structure.
5020 * @param pVmcsInfo The VMCS info. object.
5021 *
5022 * @remarks No-long-jump zone!!!
5023 */
5024static int hmR0VmxCopyNstGstToShadowVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
5025{
5026 PVM pVM = pVCpu->CTX_SUFF(pVM);
5027 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5028
5029 /*
5030 * Disable interrupts so we don't get preempted while the shadow VMCS is the
5031 * current VMCS, as we may try saving guest lazy MSRs.
5032 *
5033 * Strictly speaking the lazy MSRs are not in the VMCS, but I'd rather not risk
5034 * calling the import VMCS code which is currently performing the guest MSR reads
5035 * (on 64-bit hosts) and accessing the auto-load/store MSR area on 32-bit hosts
5036 * and the rest of the VMX leave session machinery.
5037 */
5038 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
5039
5040 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5041 if (RT_SUCCESS(rc))
5042 {
5043 /*
5044 * Copy all guest read/write VMCS fields.
5045 *
5046 * We don't check for VMWRITE failures here for performance reasons and
5047 * because they are not expected to fail, barring irrecoverable conditions
5048 * like hardware errors.
5049 */
5050 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
5051 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5052 {
5053 uint64_t u64Val;
5054 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
5055 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5056 VMXWriteVmcs64(uVmcsField, u64Val);
5057 }
5058
5059 /*
5060 * If the host CPU supports writing all VMCS fields, copy the guest read-only
5061 * VMCS fields, so the guest can VMREAD them without causing a VM-exit.
5062 */
5063 if (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL)
5064 {
5065 uint32_t const cShadowVmcsRoFields = pVM->hm.s.vmx.cShadowVmcsRoFields;
5066 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
5067 {
5068 uint64_t u64Val;
5069 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsRoFields[i];
5070 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5071 VMXWriteVmcs64(uVmcsField, u64Val);
5072 }
5073 }
5074
5075 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5076 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5077 }
5078
5079 ASMSetFlags(fEFlags);
5080 return rc;
5081}
5082
5083
5084/**
5085 * Copies the shadow VMCS to the nested-guest VMCS.
5086 *
5087 * @returns VBox status code.
5088 * @param pVCpu The cross context virtual CPU structure.
5089 * @param pVmcsInfo The VMCS info. object.
5090 *
5091 * @remarks Called with interrupts disabled.
5092 */
5093static int hmR0VmxCopyShadowToNstGstVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
5094{
5095 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5096 PVM pVM = pVCpu->CTX_SUFF(pVM);
5097 PVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5098
5099 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5100 if (RT_SUCCESS(rc))
5101 {
5102 /*
5103 * Copy guest read/write fields from the shadow VMCS.
5104 * Guest read-only fields cannot be modified, so no need to copy them.
5105 *
5106 * We don't check for VMREAD failures here for performance reasons and
5107 * because they are not expected to fail, barring irrecoverable conditions
5108 * like hardware errors.
5109 */
5110 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
5111 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5112 {
5113 uint64_t u64Val;
5114 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
5115 VMXReadVmcs64(uVmcsField, &u64Val);
5116 IEMWriteVmxVmcsField(pVmcsNstGst, uVmcsField, u64Val);
5117 }
5118
5119 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5120 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5121 }
5122 return rc;
5123}
5124
5125
5126/**
5127 * Enables VMCS shadowing for the given VMCS info. object.
5128 *
5129 * @param pVmcsInfo The VMCS info. object.
5130 *
5131 * @remarks No-long-jump zone!!!
5132 */
5133static void hmR0VmxEnableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5134{
5135 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5136 if (!(uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING))
5137 {
5138 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
5139 uProcCtls2 |= VMX_PROC_CTLS2_VMCS_SHADOWING;
5140 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5141 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, pVmcsInfo->HCPhysShadowVmcs); AssertRC(rc);
5142 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5143 pVmcsInfo->u64VmcsLinkPtr = pVmcsInfo->HCPhysShadowVmcs;
5144 Log4Func(("Enabled\n"));
5145 }
5146}
5147
5148
5149/**
5150 * Disables VMCS shadowing for the given VMCS info. object.
5151 *
5152 * @param pVmcsInfo The VMCS info. object.
5153 *
5154 * @remarks No-long-jump zone!!!
5155 */
5156static void hmR0VmxDisableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5157{
5158 /*
5159 * We want all VMREAD and VMWRITE instructions to cause VM-exits, so we clear the
5160 * VMCS shadowing control. However, VM-entry requires the shadow VMCS indicator bit
5161 * to match the VMCS shadowing control if the VMCS link pointer is not NIL_RTHCPHYS.
5162 * Hence, we must also reset the VMCS link pointer to ensure VM-entry does not fail.
5163 *
5164 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
5165 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5166 */
5167 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5168 if (uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
5169 {
5170 uProcCtls2 &= ~VMX_PROC_CTLS2_VMCS_SHADOWING;
5171 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5172 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS); AssertRC(rc);
5173 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5174 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
5175 Log4Func(("Disabled\n"));
5176 }
5177}
5178#endif
5179
5180
5181/**
5182 * Exports the guest hardware-virtualization state.
5183 *
5184 * @returns VBox status code.
5185 * @param pVCpu The cross context virtual CPU structure.
5186 * @param pVmxTransient The VMX-transient structure.
5187 *
5188 * @remarks No-long-jump zone!!!
5189 */
5190static int hmR0VmxExportGuestHwvirtState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
5191{
5192 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_HWVIRT)
5193 {
5194#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5195 /*
5196 * Check if the VMX feature is exposed to the guest and if the host CPU supports
5197 * VMCS shadowing.
5198 */
5199 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
5200 {
5201 /*
5202 * If the guest hypervisor has loaded a current VMCS and is in VMX root mode,
5203 * copy the guest hypervisor's current VMCS into the shadow VMCS and enable
5204 * VMCS shadowing to skip intercepting some or all VMREAD/VMWRITE VM-exits.
5205 *
5206 * We check for VMX root mode here in case the guest executes VMXOFF without
5207 * clearing the current VMCS pointer and our VMXOFF instruction emulation does
5208 * not clear the current VMCS pointer.
5209 */
5210 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5211 if ( CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx)
5212 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx)
5213 && CPUMIsGuestVmxCurrentVmcsValid(pVCpu, &pVCpu->cpum.GstCtx))
5214 {
5215 /* Paranoia. */
5216 Assert(!pVmxTransient->fIsNestedGuest);
5217
5218 /*
5219 * For performance reasons, also check if the guest hypervisor's current VMCS
5220 * was newly loaded or modified before copying it to the shadow VMCS.
5221 */
5222 if (!pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs)
5223 {
5224 int rc = hmR0VmxCopyNstGstToShadowVmcs(pVCpu, pVmcsInfo);
5225 AssertRCReturn(rc, rc);
5226 pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs = true;
5227 }
5228 hmR0VmxEnableVmcsShadowing(pVmcsInfo);
5229 }
5230 else
5231 hmR0VmxDisableVmcsShadowing(pVmcsInfo);
5232 }
5233#else
5234 NOREF(pVmxTransient);
5235#endif
5236 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_HWVIRT);
5237 }
5238 return VINF_SUCCESS;
5239}
5240
5241
5242/**
5243 * Exports the guest CR0 control register into the guest-state area in the VMCS.
5244 *
5245 * The guest FPU state is always pre-loaded hence we don't need to bother about
5246 * sharing FPU related CR0 bits between the guest and host.
5247 *
5248 * @returns VBox status code.
5249 * @param pVCpu The cross context virtual CPU structure.
5250 * @param pVmxTransient The VMX-transient structure.
5251 *
5252 * @remarks No-long-jump zone!!!
5253 */
5254static int hmR0VmxExportGuestCR0(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
5255{
5256 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR0)
5257 {
5258 PVM pVM = pVCpu->CTX_SUFF(pVM);
5259 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5260
5261 /*
5262 * Figure out fixed CR0 bits in VMX operation.
5263 */
5264 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
5265 uint64_t fSetCr0 = pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1;
5266 uint64_t const fZapCr0 = pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1;
5267 if (pVM->hm.s.vmx.fUnrestrictedGuest)
5268 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
5269 else
5270 Assert((fSetCr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
5271
5272 if (!pVmxTransient->fIsNestedGuest)
5273 {
5274 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5275 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5276 uint64_t const u64ShadowCr0 = u64GuestCr0;
5277 Assert(!RT_HI_U32(u64GuestCr0));
5278
5279 /*
5280 * Setup VT-x's view of the guest CR0.
5281 */
5282 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5283 if (pVM->hm.s.fNestedPaging)
5284 {
5285 if (CPUMIsGuestPagingEnabled(pVCpu))
5286 {
5287 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
5288 uProcCtls &= ~( VMX_PROC_CTLS_CR3_LOAD_EXIT
5289 | VMX_PROC_CTLS_CR3_STORE_EXIT);
5290 }
5291 else
5292 {
5293 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
5294 uProcCtls |= VMX_PROC_CTLS_CR3_LOAD_EXIT
5295 | VMX_PROC_CTLS_CR3_STORE_EXIT;
5296 }
5297
5298 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
5299 if (pVM->hm.s.vmx.fUnrestrictedGuest)
5300 uProcCtls &= ~VMX_PROC_CTLS_CR3_STORE_EXIT;
5301 }
5302 else
5303 {
5304 /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
5305 u64GuestCr0 |= X86_CR0_WP;
5306 }
5307
5308 /*
5309 * Guest FPU bits.
5310 *
5311 * Since we pre-load the guest FPU always before VM-entry there is no need to track lazy state
5312 * using CR0.TS.
5313 *
5314 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be
5315 * set on the first CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
5316 */
5317 u64GuestCr0 |= X86_CR0_NE;
5318
5319 /* If CR0.NE isn't set, we need to intercept #MF exceptions and report them to the guest differently. */
5320 bool const fInterceptMF = !(u64ShadowCr0 & X86_CR0_NE);
5321
5322 /*
5323 * Update exception intercepts.
5324 */
5325 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
5326 if (pVmcsInfo->RealMode.fRealOnV86Active)
5327 {
5328 Assert(PDMVmmDevHeapIsEnabled(pVM));
5329 Assert(pVM->hm.s.vmx.pRealModeTSS);
5330 uXcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
5331 }
5332 else
5333 {
5334 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
5335 uXcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
5336 if (fInterceptMF)
5337 uXcptBitmap |= RT_BIT(X86_XCPT_MF);
5338 }
5339
5340 /* Additional intercepts for debugging, define these yourself explicitly. */
5341#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
5342 uXcptBitmap |= 0
5343 | RT_BIT(X86_XCPT_BP)
5344 | RT_BIT(X86_XCPT_DE)
5345 | RT_BIT(X86_XCPT_NM)
5346 | RT_BIT(X86_XCPT_TS)
5347 | RT_BIT(X86_XCPT_UD)
5348 | RT_BIT(X86_XCPT_NP)
5349 | RT_BIT(X86_XCPT_SS)
5350 | RT_BIT(X86_XCPT_GP)
5351 | RT_BIT(X86_XCPT_PF)
5352 | RT_BIT(X86_XCPT_MF)
5353 ;
5354#elif defined(HMVMX_ALWAYS_TRAP_PF)
5355 uXcptBitmap |= RT_BIT(X86_XCPT_PF);
5356#endif
5357 if (pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv)
5358 uXcptBitmap |= RT_BIT(X86_XCPT_GP);
5359 Assert(pVM->hm.s.fNestedPaging || (uXcptBitmap & RT_BIT(X86_XCPT_PF)));
5360
5361 /* Apply the hardware specified fixed CR0 bits and enable caching. */
5362 u64GuestCr0 |= fSetCr0;
5363 u64GuestCr0 &= fZapCr0;
5364 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5365
5366 /* Commit the CR0 and related fields to the guest VMCS. */
5367 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5368 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5369 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5370 {
5371 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5372 AssertRC(rc);
5373 }
5374 if (uXcptBitmap != pVmcsInfo->u32XcptBitmap)
5375 {
5376 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
5377 AssertRC(rc);
5378 }
5379
5380 /* Update our caches. */
5381 pVmcsInfo->u32ProcCtls = uProcCtls;
5382 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
5383
5384 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5385 }
5386 else
5387 {
5388 /*
5389 * With nested-guests, we may have extended the guest/host mask here since we
5390 * merged in the outer guest's mask. Thus, the merged mask can include more bits
5391 * (to read from the nested-guest CR0 read-shadow) than the guest hypervisor
5392 * originally supplied. We must copy those bits from the nested-guest CR0 into
5393 * the nested-guest CR0 read-shadow.
5394 */
5395 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5396 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5397 uint64_t const u64ShadowCr0 = CPUMGetGuestVmxMaskedCr0(pVCpu, &pVCpu->cpum.GstCtx, pVmcsInfo->u64Cr0Mask);
5398 Assert(!RT_HI_U32(u64GuestCr0));
5399 Assert(u64GuestCr0 & X86_CR0_NE);
5400
5401 /*
5402 * Apply the hardware specified fixed CR0 bits and enable caching.
5403 * Note! We could be altering our VMX emulation's fixed bits. We thus
5404 * need to re-apply them while importing CR0.
5405 */
5406 u64GuestCr0 |= fSetCr0;
5407 u64GuestCr0 &= fZapCr0;
5408 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5409
5410 /* Commit the CR0 and CR0 read-shadow to the nested-guest VMCS. */
5411 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5412 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5413
5414 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5415 }
5416
5417 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR0);
5418 }
5419
5420 return VINF_SUCCESS;
5421}
5422
5423
5424/**
5425 * Exports the guest control registers (CR3, CR4) into the guest-state area
5426 * in the VMCS.
5427 *
5428 * @returns VBox strict status code.
5429 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
5430 * without unrestricted guest access and the VMMDev is not presently
5431 * mapped (e.g. EFI32).
5432 *
5433 * @param pVCpu The cross context virtual CPU structure.
5434 * @param pVmxTransient The VMX-transient structure.
5435 *
5436 * @remarks No-long-jump zone!!!
5437 */
5438static VBOXSTRICTRC hmR0VmxExportGuestCR3AndCR4(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
5439{
5440 int rc = VINF_SUCCESS;
5441 PVM pVM = pVCpu->CTX_SUFF(pVM);
5442
5443 /*
5444 * Guest CR2.
5445 * It's always loaded in the assembler code. Nothing to do here.
5446 */
5447
5448 /*
5449 * Guest CR3.
5450 */
5451 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR3)
5452 {
5453 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
5454
5455 if (pVM->hm.s.fNestedPaging)
5456 {
5457 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5458 pVmcsInfo->HCPhysEPTP = PGMGetHyperCR3(pVCpu);
5459
5460 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
5461 Assert(pVmcsInfo->HCPhysEPTP != NIL_RTHCPHYS);
5462 Assert(!(pVmcsInfo->HCPhysEPTP & UINT64_C(0xfff0000000000000)));
5463 Assert(!(pVmcsInfo->HCPhysEPTP & 0xfff));
5464
5465 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
5466 pVmcsInfo->HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
5467 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
5468
5469 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
5470 AssertMsg( ((pVmcsInfo->HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
5471 && ((pVmcsInfo->HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
5472 ("EPTP %#RX64\n", pVmcsInfo->HCPhysEPTP));
5473 AssertMsg( !((pVmcsInfo->HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
5474 || (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
5475 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVmcsInfo->HCPhysEPTP));
5476
5477 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVmcsInfo->HCPhysEPTP);
5478 AssertRC(rc);
5479
5480 uint64_t u64GuestCr3;
5481 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5482 if ( pVM->hm.s.vmx.fUnrestrictedGuest
5483 || CPUMIsGuestPagingEnabledEx(pCtx))
5484 {
5485 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
5486 if (CPUMIsGuestInPAEModeEx(pCtx))
5487 {
5488 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
5489 AssertRC(rc);
5490 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
5491 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
5492 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
5493 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
5494 }
5495
5496 /*
5497 * The guest's view of its CR3 is unblemished with nested paging when the
5498 * guest is using paging or we have unrestricted guest execution to handle
5499 * the guest when it's not using paging.
5500 */
5501 u64GuestCr3 = pCtx->cr3;
5502 }
5503 else
5504 {
5505 /*
5506 * The guest is not using paging, but the CPU (VT-x) has to. While the guest
5507 * thinks it accesses physical memory directly, we use our identity-mapped
5508 * page table to map guest-linear to guest-physical addresses. EPT takes care
5509 * of translating it to host-physical addresses.
5510 */
5511 RTGCPHYS GCPhys;
5512 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
5513
5514 /* We obtain it here every time as the guest could have relocated this PCI region. */
5515 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
5516 if (RT_SUCCESS(rc))
5517 { /* likely */ }
5518 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
5519 {
5520 Log4Func(("VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n"));
5521 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
5522 }
5523 else
5524 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
5525
5526 u64GuestCr3 = GCPhys;
5527 }
5528
5529 Log4Func(("guest_cr3=%#RX64 (GstN)\n", u64GuestCr3));
5530 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, u64GuestCr3);
5531 AssertRC(rc);
5532 }
5533 else
5534 {
5535 /* Non-nested paging case, just use the hypervisor's CR3. */
5536 RTHCPHYS const HCPhysGuestCr3 = PGMGetHyperCR3(pVCpu);
5537
5538 Log4Func(("guest_cr3=%#RX64 (HstN)\n", HCPhysGuestCr3));
5539 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, HCPhysGuestCr3);
5540 AssertRC(rc);
5541 }
5542
5543 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR3);
5544 }
5545
5546 /*
5547 * Guest CR4.
5548 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
5549 */
5550 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR4)
5551 {
5552 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5553 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5554
5555 /*
5556 * Figure out fixed CR4 bits in VMX operation.
5557 */
5558 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
5559 uint64_t const fSetCr4 = pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1;
5560 uint64_t const fZapCr4 = pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1;
5561
5562 /*
5563 * With nested-guests, we may have extended the guest/host mask here (since we
5564 * merged in the outer guest's mask, see hmR0VmxMergeVmcsNested). This means, the
5565 * mask can include more bits (to read from the nested-guest CR4 read-shadow) than
5566 * the guest hypervisor originally supplied. Thus, we should, in essence, copy
5567 * those bits from the nested-guest CR4 into the nested-guest CR4 read-shadow.
5568 */
5569 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
5570 uint64_t u64GuestCr4 = pCtx->cr4;
5571 uint64_t const u64ShadowCr4 = !pVmxTransient->fIsNestedGuest
5572 ? pCtx->cr4
5573 : CPUMGetGuestVmxMaskedCr4(pVCpu, pCtx, pVmcsInfo->u64Cr4Mask);
5574 Assert(!RT_HI_U32(u64GuestCr4));
5575
5576 /*
5577 * Setup VT-x's view of the guest CR4.
5578 *
5579 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software
5580 * interrupts to the 8086 program interrupt handler. Clear the VME bit (the interrupt
5581 * redirection bitmap is already all 0, see hmR3InitFinalizeR0())
5582 *
5583 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
5584 */
5585 if (pVmcsInfo->RealMode.fRealOnV86Active)
5586 {
5587 Assert(pVM->hm.s.vmx.pRealModeTSS);
5588 Assert(PDMVmmDevHeapIsEnabled(pVM));
5589 u64GuestCr4 &= ~(uint64_t)X86_CR4_VME;
5590 }
5591
5592 if (pVM->hm.s.fNestedPaging)
5593 {
5594 if ( !CPUMIsGuestPagingEnabledEx(pCtx)
5595 && !pVM->hm.s.vmx.fUnrestrictedGuest)
5596 {
5597 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
5598 u64GuestCr4 |= X86_CR4_PSE;
5599 /* Our identity mapping is a 32-bit page directory. */
5600 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5601 }
5602 /* else use guest CR4.*/
5603 }
5604 else
5605 {
5606 Assert(!pVmxTransient->fIsNestedGuest);
5607
5608 /*
5609 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
5610 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
5611 */
5612 switch (pVCpu->hm.s.enmShadowMode)
5613 {
5614 case PGMMODE_REAL: /* Real-mode. */
5615 case PGMMODE_PROTECTED: /* Protected mode without paging. */
5616 case PGMMODE_32_BIT: /* 32-bit paging. */
5617 {
5618 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5619 break;
5620 }
5621
5622 case PGMMODE_PAE: /* PAE paging. */
5623 case PGMMODE_PAE_NX: /* PAE paging with NX. */
5624 {
5625 u64GuestCr4 |= X86_CR4_PAE;
5626 break;
5627 }
5628
5629 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
5630 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
5631#ifdef VBOX_WITH_64_BITS_GUESTS
5632 break;
5633#endif
5634 default:
5635 AssertFailed();
5636 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
5637 }
5638 }
5639
5640 /*
5641 * Apply the hardware specified fixed CR4 bits (mainly CR4.VMXE).
5642 * Note! For nested-guests, we could be altering our VMX emulation's
5643 * fixed bits. We thus need to re-apply them while importing CR4.
5644 */
5645 u64GuestCr4 |= fSetCr4;
5646 u64GuestCr4 &= fZapCr4;
5647
5648 /* Commit the CR4 and CR4 read-shadow to the guest VMCS. */
5649 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR4, u64GuestCr4); AssertRC(rc);
5650 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, u64ShadowCr4); AssertRC(rc);
5651
5652 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
5653 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
5654
5655 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR4);
5656
5657 Log4Func(("cr4=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64)\n", u64GuestCr4, u64ShadowCr4, fSetCr4, fZapCr4));
5658 }
5659 return rc;
5660}
5661
5662
5663/**
5664 * Exports the guest debug registers into the guest-state area in the VMCS.
5665 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
5666 *
5667 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
5668 *
5669 * @returns VBox status code.
5670 * @param pVCpu The cross context virtual CPU structure.
5671 * @param pVmxTransient The VMX-transient structure.
5672 *
5673 * @remarks No-long-jump zone!!!
5674 */
5675static int hmR0VmxExportSharedDebugState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
5676{
5677 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5678
5679 /** @todo NSTVMX: Figure out what we want to do with nested-guest instruction
5680 * stepping. */
5681 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5682 if (pVmxTransient->fIsNestedGuest)
5683 {
5684 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, CPUMGetGuestDR7(pVCpu));
5685 AssertRC(rc);
5686
5687 /* Always intercept Mov DRx accesses for the nested-guest for now. */
5688 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
5689 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
5690 AssertRC(rc);
5691 return VINF_SUCCESS;
5692 }
5693
5694#ifdef VBOX_STRICT
5695 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
5696 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
5697 {
5698 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
5699 Assert((pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0);
5700 Assert((pVCpu->cpum.GstCtx.dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK);
5701 }
5702#endif
5703
5704 bool fSteppingDB = false;
5705 bool fInterceptMovDRx = false;
5706 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5707 if (pVCpu->hm.s.fSingleInstruction)
5708 {
5709 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
5710 PVM pVM = pVCpu->CTX_SUFF(pVM);
5711 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
5712 {
5713 uProcCtls |= VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
5714 Assert(fSteppingDB == false);
5715 }
5716 else
5717 {
5718 pVCpu->cpum.GstCtx.eflags.u32 |= X86_EFL_TF;
5719 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_RFLAGS;
5720 pVCpu->hm.s.fClearTrapFlag = true;
5721 fSteppingDB = true;
5722 }
5723 }
5724
5725 uint64_t u64GuestDr7;
5726 if ( fSteppingDB
5727 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
5728 {
5729 /*
5730 * Use the combined guest and host DRx values found in the hypervisor register set
5731 * because the hypervisor debugger has breakpoints active or someone is single stepping
5732 * on the host side without a monitor trap flag.
5733 *
5734 * Note! DBGF expects a clean DR6 state before executing guest code.
5735 */
5736 if (!CPUMIsHyperDebugStateActive(pVCpu))
5737 {
5738 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
5739 Assert(CPUMIsHyperDebugStateActive(pVCpu));
5740 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
5741 }
5742
5743 /* Update DR7 with the hypervisor value (other DRx registers are handled by CPUM one way or another). */
5744 u64GuestDr7 = CPUMGetHyperDR7(pVCpu);
5745 pVCpu->hm.s.fUsingHyperDR7 = true;
5746 fInterceptMovDRx = true;
5747 }
5748 else
5749 {
5750 /*
5751 * If the guest has enabled debug registers, we need to load them prior to
5752 * executing guest code so they'll trigger at the right time.
5753 */
5754 if (pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
5755 {
5756 if (!CPUMIsGuestDebugStateActive(pVCpu))
5757 {
5758 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
5759 Assert(CPUMIsGuestDebugStateActive(pVCpu));
5760 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
5761 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
5762 }
5763 Assert(!fInterceptMovDRx);
5764 }
5765 else if (!CPUMIsGuestDebugStateActive(pVCpu))
5766 {
5767 /*
5768 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
5769 * must intercept #DB in order to maintain a correct DR6 guest value, and
5770 * because we need to intercept it to prevent nested #DBs from hanging the
5771 * CPU, we end up always having to intercept it. See hmR0VmxSetupVmcsXcptBitmap().
5772 */
5773 fInterceptMovDRx = true;
5774 }
5775
5776 /* Update DR7 with the actual guest value. */
5777 u64GuestDr7 = pVCpu->cpum.GstCtx.dr[7];
5778 pVCpu->hm.s.fUsingHyperDR7 = false;
5779 }
5780
5781 if (fInterceptMovDRx)
5782 uProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
5783 else
5784 uProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
5785
5786 /*
5787 * Update the processor-based VM-execution controls with the MOV-DRx intercepts and the
5788 * monitor-trap flag and update our cache.
5789 */
5790 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5791 {
5792 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5793 AssertRC(rc);
5794 pVmcsInfo->u32ProcCtls = uProcCtls;
5795 }
5796
5797 /*
5798 * Update guest DR7.
5799 */
5800 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, u64GuestDr7);
5801 AssertRC(rc);
5802
5803 /*
5804 * If we have forced EFLAGS.TF to be set because we're single-stepping in the hypervisor debugger,
5805 * we need to clear interrupt inhibition if any as otherwise it causes a VM-entry failure.
5806 *
5807 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5808 */
5809 if (fSteppingDB)
5810 {
5811 Assert(pVCpu->hm.s.fSingleInstruction);
5812 Assert(pVCpu->cpum.GstCtx.eflags.Bits.u1TF);
5813
5814 uint32_t fIntrState = 0;
5815 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
5816 AssertRC(rc);
5817
5818 if (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
5819 {
5820 fIntrState &= ~(VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
5821 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
5822 AssertRC(rc);
5823 }
5824 }
5825
5826 return VINF_SUCCESS;
5827}
5828
5829
5830#ifdef VBOX_STRICT
5831/**
5832 * Strict function to validate segment registers.
5833 *
5834 * @param pVCpu The cross context virtual CPU structure.
5835 * @param pVmcsInfo The VMCS info. object.
5836 *
5837 * @remarks Will import guest CR0 on strict builds during validation of
5838 * segments.
5839 */
5840static void hmR0VmxValidateSegmentRegs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
5841{
5842 /*
5843 * Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
5844 *
5845 * The reason we check for attribute value 0 in this function and not just the unusable bit is
5846 * because hmR0VmxExportGuestSegReg() only updates the VMCS' copy of the value with the
5847 * unusable bit and doesn't change the guest-context value.
5848 */
5849 PVM pVM = pVCpu->CTX_SUFF(pVM);
5850 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5851 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR0);
5852 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
5853 && ( !CPUMIsGuestInRealModeEx(pCtx)
5854 && !CPUMIsGuestInV86ModeEx(pCtx)))
5855 {
5856 /* Protected mode checks */
5857 /* CS */
5858 Assert(pCtx->cs.Attr.n.u1Present);
5859 Assert(!(pCtx->cs.Attr.u & 0xf00));
5860 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
5861 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
5862 || !(pCtx->cs.Attr.n.u1Granularity));
5863 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
5864 || (pCtx->cs.Attr.n.u1Granularity));
5865 /* CS cannot be loaded with NULL in protected mode. */
5866 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
5867 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
5868 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
5869 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
5870 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
5871 else
5872 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
5873 /* SS */
5874 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
5875 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
5876 if ( !(pCtx->cr0 & X86_CR0_PE)
5877 || pCtx->cs.Attr.n.u4Type == 3)
5878 {
5879 Assert(!pCtx->ss.Attr.n.u2Dpl);
5880 }
5881 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
5882 {
5883 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
5884 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
5885 Assert(pCtx->ss.Attr.n.u1Present);
5886 Assert(!(pCtx->ss.Attr.u & 0xf00));
5887 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
5888 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
5889 || !(pCtx->ss.Attr.n.u1Granularity));
5890 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
5891 || (pCtx->ss.Attr.n.u1Granularity));
5892 }
5893 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSegReg(). */
5894 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
5895 {
5896 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5897 Assert(pCtx->ds.Attr.n.u1Present);
5898 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
5899 Assert(!(pCtx->ds.Attr.u & 0xf00));
5900 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
5901 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
5902 || !(pCtx->ds.Attr.n.u1Granularity));
5903 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
5904 || (pCtx->ds.Attr.n.u1Granularity));
5905 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5906 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
5907 }
5908 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
5909 {
5910 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5911 Assert(pCtx->es.Attr.n.u1Present);
5912 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
5913 Assert(!(pCtx->es.Attr.u & 0xf00));
5914 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
5915 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
5916 || !(pCtx->es.Attr.n.u1Granularity));
5917 Assert( !(pCtx->es.u32Limit & 0xfff00000)
5918 || (pCtx->es.Attr.n.u1Granularity));
5919 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5920 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
5921 }
5922 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
5923 {
5924 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5925 Assert(pCtx->fs.Attr.n.u1Present);
5926 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
5927 Assert(!(pCtx->fs.Attr.u & 0xf00));
5928 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
5929 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
5930 || !(pCtx->fs.Attr.n.u1Granularity));
5931 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
5932 || (pCtx->fs.Attr.n.u1Granularity));
5933 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5934 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
5935 }
5936 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
5937 {
5938 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5939 Assert(pCtx->gs.Attr.n.u1Present);
5940 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
5941 Assert(!(pCtx->gs.Attr.u & 0xf00));
5942 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
5943 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
5944 || !(pCtx->gs.Attr.n.u1Granularity));
5945 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
5946 || (pCtx->gs.Attr.n.u1Granularity));
5947 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5948 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
5949 }
5950 /* 64-bit capable CPUs. */
5951 Assert(!RT_HI_U32(pCtx->cs.u64Base));
5952 Assert(!pCtx->ss.Attr.u || !RT_HI_U32(pCtx->ss.u64Base));
5953 Assert(!pCtx->ds.Attr.u || !RT_HI_U32(pCtx->ds.u64Base));
5954 Assert(!pCtx->es.Attr.u || !RT_HI_U32(pCtx->es.u64Base));
5955 }
5956 else if ( CPUMIsGuestInV86ModeEx(pCtx)
5957 || ( CPUMIsGuestInRealModeEx(pCtx)
5958 && !pVM->hm.s.vmx.fUnrestrictedGuest))
5959 {
5960 /* Real and v86 mode checks. */
5961 /* hmR0VmxExportGuestSegReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
5962 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
5963 if (pVmcsInfo->RealMode.fRealOnV86Active)
5964 {
5965 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3;
5966 u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
5967 }
5968 else
5969 {
5970 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
5971 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
5972 }
5973
5974 /* CS */
5975 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
5976 Assert(pCtx->cs.u32Limit == 0xffff);
5977 Assert(u32CSAttr == 0xf3);
5978 /* SS */
5979 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
5980 Assert(pCtx->ss.u32Limit == 0xffff);
5981 Assert(u32SSAttr == 0xf3);
5982 /* DS */
5983 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
5984 Assert(pCtx->ds.u32Limit == 0xffff);
5985 Assert(u32DSAttr == 0xf3);
5986 /* ES */
5987 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
5988 Assert(pCtx->es.u32Limit == 0xffff);
5989 Assert(u32ESAttr == 0xf3);
5990 /* FS */
5991 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
5992 Assert(pCtx->fs.u32Limit == 0xffff);
5993 Assert(u32FSAttr == 0xf3);
5994 /* GS */
5995 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
5996 Assert(pCtx->gs.u32Limit == 0xffff);
5997 Assert(u32GSAttr == 0xf3);
5998 /* 64-bit capable CPUs. */
5999 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6000 Assert(!u32SSAttr || !RT_HI_U32(pCtx->ss.u64Base));
6001 Assert(!u32DSAttr || !RT_HI_U32(pCtx->ds.u64Base));
6002 Assert(!u32ESAttr || !RT_HI_U32(pCtx->es.u64Base));
6003 }
6004}
6005#endif /* VBOX_STRICT */
6006
6007
6008/**
6009 * Exports a guest segment register into the guest-state area in the VMCS.
6010 *
6011 * @returns VBox status code.
6012 * @param pVCpu The cross context virtual CPU structure.
6013 * @param pVmcsInfo The VMCS info. object.
6014 * @param iSegReg The segment register number (X86_SREG_XXX).
6015 * @param pSelReg Pointer to the segment selector.
6016 *
6017 * @remarks No-long-jump zone!!!
6018 */
6019static int hmR0VmxExportGuestSegReg(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t iSegReg, PCCPUMSELREG pSelReg)
6020{
6021 Assert(iSegReg < X86_SREG_COUNT);
6022 uint32_t const idxSel = g_aVmcsSegSel[iSegReg];
6023 uint32_t const idxLimit = g_aVmcsSegLimit[iSegReg];
6024 uint32_t const idxBase = g_aVmcsSegBase[iSegReg];
6025 uint32_t const idxAttr = g_aVmcsSegAttr[iSegReg];
6026
6027 uint32_t u32Access = pSelReg->Attr.u;
6028 if (pVmcsInfo->RealMode.fRealOnV86Active)
6029 {
6030 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
6031 u32Access = 0xf3;
6032 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6033 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
6034 RT_NOREF_PV(pVCpu);
6035 }
6036 else
6037 {
6038 /*
6039 * The way to differentiate between whether this is really a null selector or was just
6040 * a selector loaded with 0 in real-mode is using the segment attributes. A selector
6041 * loaded in real-mode with the value 0 is valid and usable in protected-mode and we
6042 * should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures
6043 * NULL selectors loaded in protected-mode have their attribute as 0.
6044 */
6045 if (!u32Access)
6046 u32Access = X86DESCATTR_UNUSABLE;
6047 }
6048
6049 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
6050 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
6051 ("Access bit not set for usable segment. idx=%#x sel=%#x attr %#x\n", idxBase, pSelReg, pSelReg->Attr.u));
6052
6053 /*
6054 * Commit it to the VMCS.
6055 */
6056 int rc = VMXWriteVmcs32(idxSel, pSelReg->Sel); AssertRC(rc);
6057 rc = VMXWriteVmcs32(idxLimit, pSelReg->u32Limit); AssertRC(rc);
6058 rc = VMXWriteVmcsNw(idxBase, pSelReg->u64Base); AssertRC(rc);
6059 rc = VMXWriteVmcs32(idxAttr, u32Access); AssertRC(rc);
6060 return VINF_SUCCESS;
6061}
6062
6063
6064/**
6065 * Exports the guest segment registers, GDTR, IDTR, LDTR, TR into the guest-state
6066 * area in the VMCS.
6067 *
6068 * @returns VBox status code.
6069 * @param pVCpu The cross context virtual CPU structure.
6070 * @param pVmxTransient The VMX-transient structure.
6071 *
6072 * @remarks Will import guest CR0 on strict builds during validation of
6073 * segments.
6074 * @remarks No-long-jump zone!!!
6075 */
6076static int hmR0VmxExportGuestSegRegsXdtr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
6077{
6078 int rc = VERR_INTERNAL_ERROR_5;
6079 PVM pVM = pVCpu->CTX_SUFF(pVM);
6080 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6081 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6082
6083 /*
6084 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
6085 */
6086 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SREG_MASK)
6087 {
6088#ifdef VBOX_WITH_REM
6089 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
6090 {
6091 Assert(!pVmxTransient->fIsNestedGuest);
6092 Assert(pVM->hm.s.vmx.pRealModeTSS);
6093 AssertCompile(PGMMODE_REAL < PGMMODE_PROTECTED);
6094 if ( pVmcsInfo->fWasInRealMode
6095 && PGMGetGuestMode(pVCpu) >= PGMMODE_PROTECTED)
6096 {
6097 /*
6098 * Notify the recompiler must flush its code-cache as the guest -may-
6099 * rewrite code it in real-mode (e.g. OpenBSD 4.0).
6100 */
6101 REMFlushTBs(pVM);
6102 Log4Func(("Switch to protected mode detected!\n"));
6103 pVmcsInfo->fWasInRealMode = false;
6104 }
6105 }
6106#endif
6107 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CS)
6108 {
6109 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CS);
6110 if (pVmcsInfo->RealMode.fRealOnV86Active)
6111 pVmcsInfo->RealMode.AttrCS.u = pCtx->cs.Attr.u;
6112 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_CS, &pCtx->cs);
6113 AssertRC(rc);
6114 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CS);
6115 }
6116
6117 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SS)
6118 {
6119 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SS);
6120 if (pVmcsInfo->RealMode.fRealOnV86Active)
6121 pVmcsInfo->RealMode.AttrSS.u = pCtx->ss.Attr.u;
6122 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_SS, &pCtx->ss);
6123 AssertRC(rc);
6124 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SS);
6125 }
6126
6127 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_DS)
6128 {
6129 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DS);
6130 if (pVmcsInfo->RealMode.fRealOnV86Active)
6131 pVmcsInfo->RealMode.AttrDS.u = pCtx->ds.Attr.u;
6132 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_DS, &pCtx->ds);
6133 AssertRC(rc);
6134 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_DS);
6135 }
6136
6137 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_ES)
6138 {
6139 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_ES);
6140 if (pVmcsInfo->RealMode.fRealOnV86Active)
6141 pVmcsInfo->RealMode.AttrES.u = pCtx->es.Attr.u;
6142 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_ES, &pCtx->es);
6143 AssertRC(rc);
6144 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_ES);
6145 }
6146
6147 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_FS)
6148 {
6149 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_FS);
6150 if (pVmcsInfo->RealMode.fRealOnV86Active)
6151 pVmcsInfo->RealMode.AttrFS.u = pCtx->fs.Attr.u;
6152 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_FS, &pCtx->fs);
6153 AssertRC(rc);
6154 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_FS);
6155 }
6156
6157 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GS)
6158 {
6159 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GS);
6160 if (pVmcsInfo->RealMode.fRealOnV86Active)
6161 pVmcsInfo->RealMode.AttrGS.u = pCtx->gs.Attr.u;
6162 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_GS, &pCtx->gs);
6163 AssertRC(rc);
6164 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GS);
6165 }
6166
6167#ifdef VBOX_STRICT
6168 hmR0VmxValidateSegmentRegs(pVCpu, pVmcsInfo);
6169#endif
6170 Log4Func(("cs={%#04x base=%#RX64 limit=%#RX32 attr=%#RX32}\n", pCtx->cs.Sel, pCtx->cs.u64Base, pCtx->cs.u32Limit,
6171 pCtx->cs.Attr.u));
6172 }
6173
6174 /*
6175 * Guest TR.
6176 */
6177 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_TR)
6178 {
6179 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_TR);
6180
6181 /*
6182 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is
6183 * achieved using the interrupt redirection bitmap (all bits cleared to let the guest
6184 * handle INT-n's) in the TSS. See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
6185 */
6186 uint16_t u16Sel;
6187 uint32_t u32Limit;
6188 uint64_t u64Base;
6189 uint32_t u32AccessRights;
6190 if (!pVmcsInfo->RealMode.fRealOnV86Active)
6191 {
6192 u16Sel = pCtx->tr.Sel;
6193 u32Limit = pCtx->tr.u32Limit;
6194 u64Base = pCtx->tr.u64Base;
6195 u32AccessRights = pCtx->tr.Attr.u;
6196 }
6197 else
6198 {
6199 Assert(!pVmxTransient->fIsNestedGuest);
6200 Assert(pVM->hm.s.vmx.pRealModeTSS);
6201 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMCanExecuteGuest() -XXX- what about inner loop changes? */
6202
6203 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
6204 RTGCPHYS GCPhys;
6205 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
6206 AssertRCReturn(rc, rc);
6207
6208 X86DESCATTR DescAttr;
6209 DescAttr.u = 0;
6210 DescAttr.n.u1Present = 1;
6211 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
6212
6213 u16Sel = 0;
6214 u32Limit = HM_VTX_TSS_SIZE;
6215 u64Base = GCPhys;
6216 u32AccessRights = DescAttr.u;
6217 }
6218
6219 /* Validate. */
6220 Assert(!(u16Sel & RT_BIT(2)));
6221 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
6222 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
6223 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
6224 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
6225 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
6226 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
6227 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
6228 Assert( (u32Limit & 0xfff) == 0xfff
6229 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
6230 Assert( !(pCtx->tr.u32Limit & 0xfff00000)
6231 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
6232
6233 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_TR_SEL, u16Sel); AssertRC(rc);
6234 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit); AssertRC(rc);
6235 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights); AssertRC(rc);
6236 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_TR_BASE, u64Base); AssertRC(rc);
6237
6238 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_TR);
6239 Log4Func(("tr base=%#RX64 limit=%#RX32\n", pCtx->tr.u64Base, pCtx->tr.u32Limit));
6240 }
6241
6242 /*
6243 * Guest GDTR.
6244 */
6245 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GDTR)
6246 {
6247 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GDTR);
6248
6249 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt); AssertRC(rc);
6250 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, pCtx->gdtr.pGdt); AssertRC(rc);
6251
6252 /* Validate. */
6253 Assert(!(pCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6254
6255 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GDTR);
6256 Log4Func(("gdtr base=%#RX64 limit=%#RX32\n", pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt));
6257 }
6258
6259 /*
6260 * Guest LDTR.
6261 */
6262 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_LDTR)
6263 {
6264 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_LDTR);
6265
6266 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
6267 uint32_t u32Access;
6268 if ( !pVmxTransient->fIsNestedGuest
6269 && !pCtx->ldtr.Attr.u)
6270 u32Access = X86DESCATTR_UNUSABLE;
6271 else
6272 u32Access = pCtx->ldtr.Attr.u;
6273
6274 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, pCtx->ldtr.Sel); AssertRC(rc);
6275 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtr.u32Limit); AssertRC(rc);
6276 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access); AssertRC(rc);
6277 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, pCtx->ldtr.u64Base); AssertRC(rc);
6278
6279 /* Validate. */
6280 if (!(u32Access & X86DESCATTR_UNUSABLE))
6281 {
6282 Assert(!(pCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
6283 Assert(pCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
6284 Assert(!pCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
6285 Assert(pCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
6286 Assert(!pCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
6287 Assert(!(pCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
6288 Assert( (pCtx->ldtr.u32Limit & 0xfff) == 0xfff
6289 || !pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
6290 Assert( !(pCtx->ldtr.u32Limit & 0xfff00000)
6291 || pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
6292 }
6293
6294 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_LDTR);
6295 Log4Func(("ldtr base=%#RX64 limit=%#RX32\n", pCtx->ldtr.u64Base, pCtx->ldtr.u32Limit));
6296 }
6297
6298 /*
6299 * Guest IDTR.
6300 */
6301 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_IDTR)
6302 {
6303 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_IDTR);
6304
6305 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt); AssertRC(rc);
6306 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, pCtx->idtr.pIdt); AssertRC(rc);
6307
6308 /* Validate. */
6309 Assert(!(pCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6310
6311 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_IDTR);
6312 Log4Func(("idtr base=%#RX64 limit=%#RX32\n", pCtx->idtr.pIdt, pCtx->idtr.cbIdt));
6313 }
6314
6315 return VINF_SUCCESS;
6316}
6317
6318
6319/**
6320 * Exports certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
6321 * areas.
6322 *
6323 * These MSRs will automatically be loaded to the host CPU on every successful
6324 * VM-entry and stored from the host CPU on every successful VM-exit.
6325 *
6326 * We creates/updates MSR slots for the host MSRs in the VM-exit MSR-load area. The
6327 * actual host MSR values are not- updated here for performance reasons. See
6328 * hmR0VmxExportHostMsrs().
6329 *
6330 * We also exports the guest sysenter MSRs into the guest-state area in the VMCS.
6331 *
6332 * @returns VBox status code.
6333 * @param pVCpu The cross context virtual CPU structure.
6334 * @param pVmxTransient The VMX-transient structure.
6335 *
6336 * @remarks No-long-jump zone!!!
6337 */
6338static int hmR0VmxExportGuestMsrs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
6339{
6340 AssertPtr(pVCpu);
6341 AssertPtr(pVmxTransient);
6342
6343 PVM pVM = pVCpu->CTX_SUFF(pVM);
6344 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6345
6346 /*
6347 * MSRs that we use the auto-load/store MSR area in the VMCS.
6348 * For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(),
6349 * nothing to do here. The host MSR values are updated when it's safe in
6350 * hmR0VmxLazySaveHostMsrs().
6351 *
6352 * For nested-guests, the guests MSRs from the VM-entry MSR-load area are already
6353 * loaded (into the guest-CPU context) by the VMLAUNCH/VMRESUME instruction
6354 * emulation, nothing to do here.
6355 */
6356 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_GUEST_AUTO_MSRS)
6357 {
6358 /* No auto-load/store MSRs currently. */
6359 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_GUEST_AUTO_MSRS);
6360 }
6361
6362 /*
6363 * Guest Sysenter MSRs.
6364 */
6365 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_MSR_MASK)
6366 {
6367 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SYSENTER_MSRS);
6368
6369 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_CS_MSR)
6370 {
6371 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pCtx->SysEnter.cs);
6372 AssertRC(rc);
6373 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_CS_MSR);
6374 }
6375
6376 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_EIP_MSR)
6377 {
6378 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, pCtx->SysEnter.eip);
6379 AssertRC(rc);
6380 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
6381 }
6382
6383 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_ESP_MSR)
6384 {
6385 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, pCtx->SysEnter.esp);
6386 AssertRC(rc);
6387 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
6388 }
6389 }
6390
6391 /*
6392 * Guest/host EFER MSR.
6393 */
6394 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_EFER_MSR)
6395 {
6396 /* Whether we are using the VMCS to swap the EFER MSR must have been
6397 determined earlier while exporting VM-entry/VM-exit controls. */
6398 Assert(!(ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS));
6399 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
6400
6401 if (hmR0VmxShouldSwapEferMsr(pVCpu))
6402 {
6403 /*
6404 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
6405 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
6406 */
6407 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
6408 {
6409 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, pCtx->msrEFER);
6410 AssertRC(rc);
6411 }
6412 else
6413 {
6414 /*
6415 * We shall use the auto-load/store MSR area only for loading the EFER MSR but we must
6416 * continue to intercept guest read and write accesses to it, see @bugref{7386#c16}.
6417 */
6418 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER, pCtx->msrEFER,
6419 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6420 AssertRCReturn(rc, rc);
6421 }
6422 }
6423 else if (!pVM->hm.s.vmx.fSupportsVmcsEfer)
6424 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER);
6425
6426 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_EFER_MSR);
6427 }
6428
6429 /*
6430 * Other MSRs.
6431 * Speculation Control (R/W).
6432 */
6433 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_OTHER_MSRS)
6434 {
6435 HMVMX_CPUMCTX_ASSERT(pVCpu, HM_CHANGED_GUEST_OTHER_MSRS);
6436 if (pVM->cpum.ro.GuestFeatures.fIbrs)
6437 {
6438 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_IA32_SPEC_CTRL, CPUMGetGuestSpecCtrl(pVCpu),
6439 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6440 AssertRCReturn(rc, rc);
6441 }
6442 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
6443 }
6444
6445 return VINF_SUCCESS;
6446}
6447
6448
6449/**
6450 * Selects up the appropriate function to run guest code.
6451 *
6452 * @returns VBox status code.
6453 * @param pVCpu The cross context virtual CPU structure.
6454 * @param pVmxTransient The VMX-transient structure.
6455 *
6456 * @remarks No-long-jump zone!!!
6457 */
6458static int hmR0VmxSelectVMRunHandler(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
6459{
6460 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6461 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6462
6463 if (CPUMIsGuestInLongModeEx(pCtx))
6464 {
6465#ifndef VBOX_WITH_64_BITS_GUESTS
6466 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
6467#else
6468 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
6469 /* Guest is in long mode, use the 64-bit handler (host is 64-bit). */
6470 pVmcsInfo->pfnStartVM = VMXR0StartVM64;
6471#endif
6472 }
6473 else
6474 {
6475 /* Guest is not in long mode, use the 32-bit handler. */
6476 pVmcsInfo->pfnStartVM = VMXR0StartVM32;
6477 }
6478 Assert(pVmcsInfo->pfnStartVM);
6479 return VINF_SUCCESS;
6480}
6481
6482
6483/**
6484 * Wrapper for running the guest code in VT-x.
6485 *
6486 * @returns VBox status code, no informational status codes.
6487 * @param pVCpu The cross context virtual CPU structure.
6488 * @param pVmxTransient The VMX-transient structure.
6489 *
6490 * @remarks No-long-jump zone!!!
6491 */
6492DECLINLINE(int) hmR0VmxRunGuest(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient)
6493{
6494 /* Mark that HM is the keeper of all guest-CPU registers now that we're going to execute guest code. */
6495 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6496 pCtx->fExtrn |= HMVMX_CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_KEEPER_HM;
6497
6498 /** @todo Add stats for VMRESUME vs VMLAUNCH. */
6499
6500 /*
6501 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses
6502 * floating-point operations using SSE instructions. Some XMM registers (XMM6-XMM15) are
6503 * callee-saved and thus the need for this XMM wrapper.
6504 *
6505 * See MSDN "Configuring Programs for 64-bit/x64 Software Conventions / Register Usage".
6506 */
6507 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6508 bool const fResumeVM = RT_BOOL(pVmcsInfo->fVmcsState & VMX_V_VMCS_LAUNCH_STATE_LAUNCHED);
6509 PVM pVM = pVCpu->CTX_SUFF(pVM);
6510#ifdef VBOX_WITH_KERNEL_USING_XMM
6511 int rc = hmR0VMXStartVMWrapXMM(fResumeVM, pCtx, NULL /*pvUnused*/, pVM, pVCpu, pVmcsInfo->pfnStartVM);
6512#else
6513 int rc = pVmcsInfo->pfnStartVM(fResumeVM, pCtx, NULL /*pvUnused*/, pVM, pVCpu);
6514#endif
6515 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
6516 return rc;
6517}
6518
6519
6520/**
6521 * Reports world-switch error and dumps some useful debug info.
6522 *
6523 * @param pVCpu The cross context virtual CPU structure.
6524 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
6525 * @param pVmxTransient The VMX-transient structure (only
6526 * exitReason updated).
6527 */
6528static void hmR0VmxReportWorldSwitchError(PVMCPU pVCpu, int rcVMRun, PVMXTRANSIENT pVmxTransient)
6529{
6530 Assert(pVCpu);
6531 Assert(pVmxTransient);
6532 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
6533
6534 Log4Func(("VM-entry failure: %Rrc\n", rcVMRun));
6535 switch (rcVMRun)
6536 {
6537 case VERR_VMX_INVALID_VMXON_PTR:
6538 AssertFailed();
6539 break;
6540 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
6541 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
6542 {
6543 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
6544 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
6545 AssertRC(rc);
6546 hmR0VmxReadExitQualVmcs(pVmxTransient);
6547
6548 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
6549 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
6550 Cannot do it here as we may have been long preempted. */
6551
6552#ifdef VBOX_STRICT
6553 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6554 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
6555 pVmxTransient->uExitReason));
6556 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQual));
6557 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
6558 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
6559 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
6560 else
6561 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
6562 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
6563 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
6564
6565 static struct
6566 {
6567 /** Name of the field to log. */
6568 const char *pszName;
6569 /** The VMCS field. */
6570 uint32_t uVmcsField;
6571 /** Whether host support of this field needs to be checked. */
6572 bool fCheckSupport;
6573 } const s_aVmcsFields[] =
6574 {
6575 { "VMX_VMCS32_CTRL_PIN_EXEC", VMX_VMCS32_CTRL_PIN_EXEC, false },
6576 { "VMX_VMCS32_CTRL_PROC_EXEC", VMX_VMCS32_CTRL_PROC_EXEC, false },
6577 { "VMX_VMCS32_CTRL_PROC_EXEC2", VMX_VMCS32_CTRL_PROC_EXEC2, true },
6578 { "VMX_VMCS32_CTRL_ENTRY", VMX_VMCS32_CTRL_ENTRY, false },
6579 { "VMX_VMCS32_CTRL_EXIT", VMX_VMCS32_CTRL_EXIT, false },
6580 { "VMX_VMCS32_CTRL_CR3_TARGET_COUNT", VMX_VMCS32_CTRL_CR3_TARGET_COUNT, false },
6581 { "VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO", VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, false },
6582 { "VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE", VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, false },
6583 { "VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH", VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, false },
6584 { "VMX_VMCS32_CTRL_TPR_THRESHOLD", VMX_VMCS32_CTRL_TPR_THRESHOLD, false },
6585 { "VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, false },
6586 { "VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, false },
6587 { "VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, false },
6588 { "VMX_VMCS32_CTRL_EXCEPTION_BITMAP", VMX_VMCS32_CTRL_EXCEPTION_BITMAP, false },
6589 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, false },
6590 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, false },
6591 { "VMX_VMCS_CTRL_CR0_MASK", VMX_VMCS_CTRL_CR0_MASK, false },
6592 { "VMX_VMCS_CTRL_CR0_READ_SHADOW", VMX_VMCS_CTRL_CR0_READ_SHADOW, false },
6593 { "VMX_VMCS_CTRL_CR4_MASK", VMX_VMCS_CTRL_CR4_MASK, false },
6594 { "VMX_VMCS_CTRL_CR4_READ_SHADOW", VMX_VMCS_CTRL_CR4_READ_SHADOW, false },
6595 { "VMX_VMCS64_CTRL_EPTP_FULL", VMX_VMCS64_CTRL_EPTP_FULL, true },
6596 { "VMX_VMCS_GUEST_RIP", VMX_VMCS_GUEST_RIP, false },
6597 { "VMX_VMCS_GUEST_RSP", VMX_VMCS_GUEST_RSP, false },
6598 { "VMX_VMCS_GUEST_RFLAGS", VMX_VMCS_GUEST_RFLAGS, false },
6599 { "VMX_VMCS16_VPID", VMX_VMCS16_VPID, true, },
6600 { "VMX_VMCS_HOST_CR0", VMX_VMCS_HOST_CR0, false },
6601 { "VMX_VMCS_HOST_CR3", VMX_VMCS_HOST_CR3, false },
6602 { "VMX_VMCS_HOST_CR4", VMX_VMCS_HOST_CR4, false },
6603 /* The order of selector fields below are fixed! */
6604 { "VMX_VMCS16_HOST_ES_SEL", VMX_VMCS16_HOST_ES_SEL, false },
6605 { "VMX_VMCS16_HOST_CS_SEL", VMX_VMCS16_HOST_CS_SEL, false },
6606 { "VMX_VMCS16_HOST_SS_SEL", VMX_VMCS16_HOST_SS_SEL, false },
6607 { "VMX_VMCS16_HOST_DS_SEL", VMX_VMCS16_HOST_DS_SEL, false },
6608 { "VMX_VMCS16_HOST_FS_SEL", VMX_VMCS16_HOST_FS_SEL, false },
6609 { "VMX_VMCS16_HOST_GS_SEL", VMX_VMCS16_HOST_GS_SEL, false },
6610 { "VMX_VMCS16_HOST_TR_SEL", VMX_VMCS16_HOST_TR_SEL, false },
6611 /* End of ordered selector fields. */
6612 { "VMX_VMCS_HOST_TR_BASE", VMX_VMCS_HOST_TR_BASE, false },
6613 { "VMX_VMCS_HOST_GDTR_BASE", VMX_VMCS_HOST_GDTR_BASE, false },
6614 { "VMX_VMCS_HOST_IDTR_BASE", VMX_VMCS_HOST_IDTR_BASE, false },
6615 { "VMX_VMCS32_HOST_SYSENTER_CS", VMX_VMCS32_HOST_SYSENTER_CS, false },
6616 { "VMX_VMCS_HOST_SYSENTER_EIP", VMX_VMCS_HOST_SYSENTER_EIP, false },
6617 { "VMX_VMCS_HOST_SYSENTER_ESP", VMX_VMCS_HOST_SYSENTER_ESP, false },
6618 { "VMX_VMCS_HOST_RSP", VMX_VMCS_HOST_RSP, false },
6619 { "VMX_VMCS_HOST_RIP", VMX_VMCS_HOST_RIP, false }
6620 };
6621
6622 RTGDTR HostGdtr;
6623 ASMGetGDTR(&HostGdtr);
6624
6625 uint32_t const cVmcsFields = RT_ELEMENTS(s_aVmcsFields);
6626 for (uint32_t i = 0; i < cVmcsFields; i++)
6627 {
6628 uint32_t const uVmcsField = s_aVmcsFields[i].uVmcsField;
6629
6630 bool fSupported;
6631 if (!s_aVmcsFields[i].fCheckSupport)
6632 fSupported = true;
6633 else
6634 {
6635 PVM pVM = pVCpu->CTX_SUFF(pVM);
6636 switch (uVmcsField)
6637 {
6638 case VMX_VMCS64_CTRL_EPTP_FULL: fSupported = pVM->hm.s.fNestedPaging; break;
6639 case VMX_VMCS16_VPID: fSupported = pVM->hm.s.vmx.fVpid; break;
6640 case VMX_VMCS32_CTRL_PROC_EXEC2:
6641 fSupported = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
6642 break;
6643 default:
6644 AssertMsgFailedReturnVoid(("Failed to provide VMCS field support for %#RX32\n", uVmcsField));
6645 }
6646 }
6647
6648 if (fSupported)
6649 {
6650 uint8_t const uWidth = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH);
6651 switch (uWidth)
6652 {
6653 case VMX_VMCSFIELD_WIDTH_16BIT:
6654 {
6655 uint16_t u16Val;
6656 rc = VMXReadVmcs16(uVmcsField, &u16Val);
6657 AssertRC(rc);
6658 Log4(("%-40s = %#RX16\n", s_aVmcsFields[i].pszName, u16Val));
6659
6660 if ( uVmcsField >= VMX_VMCS16_HOST_ES_SEL
6661 && uVmcsField <= VMX_VMCS16_HOST_TR_SEL)
6662 {
6663 if (u16Val < HostGdtr.cbGdt)
6664 {
6665 /* Order of selectors in s_apszSel is fixed and matches the order in s_aVmcsFields. */
6666 static const char * const s_apszSel[] = { "Host ES", "Host CS", "Host SS", "Host DS",
6667 "Host FS", "Host GS", "Host TR" };
6668 uint8_t const idxSel = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_INDEX);
6669 Assert(idxSel < RT_ELEMENTS(s_apszSel));
6670 PCX86DESCHC pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u16Val & X86_SEL_MASK));
6671 hmR0DumpDescriptor(pDesc, u16Val, s_apszSel[idxSel]);
6672 }
6673 else
6674 Log4((" Selector value exceeds GDT limit!\n"));
6675 }
6676 break;
6677 }
6678
6679 case VMX_VMCSFIELD_WIDTH_32BIT:
6680 {
6681 uint32_t u32Val;
6682 rc = VMXReadVmcs32(uVmcsField, &u32Val);
6683 AssertRC(rc);
6684 Log4(("%-40s = %#RX32\n", s_aVmcsFields[i].pszName, u32Val));
6685 break;
6686 }
6687
6688 case VMX_VMCSFIELD_WIDTH_64BIT:
6689 case VMX_VMCSFIELD_WIDTH_NATURAL:
6690 {
6691 uint64_t u64Val;
6692 rc = VMXReadVmcs64(uVmcsField, &u64Val);
6693 AssertRC(rc);
6694 Log4(("%-40s = %#RX64\n", s_aVmcsFields[i].pszName, u64Val));
6695 break;
6696 }
6697 }
6698 }
6699 }
6700
6701 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
6702 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
6703 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
6704 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
6705 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
6706 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
6707#endif /* VBOX_STRICT */
6708 break;
6709 }
6710
6711 default:
6712 /* Impossible */
6713 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
6714 break;
6715 }
6716}
6717
6718
6719/**
6720 * Sets up the usage of TSC-offsetting and updates the VMCS.
6721 *
6722 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
6723 * VMX-preemption timer.
6724 *
6725 * @returns VBox status code.
6726 * @param pVCpu The cross context virtual CPU structure.
6727 * @param pVmxTransient The VMX-transient structure.
6728 *
6729 * @remarks No-long-jump zone!!!
6730 */
6731static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
6732{
6733 bool fOffsettedTsc;
6734 bool fParavirtTsc;
6735 uint64_t uTscOffset;
6736 PVM pVM = pVCpu->CTX_SUFF(pVM);
6737 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6738
6739 if (pVM->hm.s.vmx.fUsePreemptTimer)
6740 {
6741 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &uTscOffset, &fOffsettedTsc, &fParavirtTsc);
6742
6743 /* Make sure the returned values have sane upper and lower boundaries. */
6744 uint64_t u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
6745 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second */
6746 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
6747 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
6748
6749 /** @todo r=ramshankar: We need to find a way to integrate nested-guest
6750 * preemption timers here. We probably need to clamp the preemption timer,
6751 * after converting the timer value to the host. */
6752 uint32_t cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
6753 int rc = VMXWriteVmcs32(VMX_VMCS32_PREEMPT_TIMER_VALUE, cPreemptionTickCount);
6754 AssertRC(rc);
6755 }
6756 else
6757 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
6758
6759 if (fParavirtTsc)
6760 {
6761 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
6762 information before every VM-entry, hence disable it for performance sake. */
6763#if 0
6764 int rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
6765 AssertRC(rc);
6766#endif
6767 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
6768 }
6769
6770 if ( fOffsettedTsc
6771 && RT_LIKELY(!pVCpu->hm.s.fDebugWantRdTscExit))
6772 {
6773 if (pVmxTransient->fIsNestedGuest)
6774 uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
6775 hmR0VmxSetTscOffsetVmcs(pVmcsInfo, uTscOffset);
6776 hmR0VmxRemoveProcCtlsVmcs(pVCpu, pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
6777 }
6778 else
6779 {
6780 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
6781 hmR0VmxSetProcCtlsVmcs(pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
6782 }
6783}
6784
6785
6786/**
6787 * Gets the IEM exception flags for the specified vector and IDT vectoring /
6788 * VM-exit interruption info type.
6789 *
6790 * @returns The IEM exception flags.
6791 * @param uVector The event vector.
6792 * @param uVmxEventType The VMX event type.
6793 *
6794 * @remarks This function currently only constructs flags required for
6795 * IEMEvaluateRecursiveXcpt and not the complete flags (e.g, error-code
6796 * and CR2 aspects of an exception are not included).
6797 */
6798static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxEventType)
6799{
6800 uint32_t fIemXcptFlags;
6801 switch (uVmxEventType)
6802 {
6803 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
6804 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
6805 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
6806 break;
6807
6808 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
6809 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
6810 break;
6811
6812 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
6813 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
6814 break;
6815
6816 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
6817 {
6818 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6819 if (uVector == X86_XCPT_BP)
6820 fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
6821 else if (uVector == X86_XCPT_OF)
6822 fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
6823 else
6824 {
6825 fIemXcptFlags = 0;
6826 AssertMsgFailed(("Unexpected vector for software exception. uVector=%#x", uVector));
6827 }
6828 break;
6829 }
6830
6831 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
6832 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6833 break;
6834
6835 default:
6836 fIemXcptFlags = 0;
6837 AssertMsgFailed(("Unexpected vector type! uVmxEventType=%#x uVector=%#x", uVmxEventType, uVector));
6838 break;
6839 }
6840 return fIemXcptFlags;
6841}
6842
6843
6844/**
6845 * Sets an event as a pending event to be injected into the guest.
6846 *
6847 * @param pVCpu The cross context virtual CPU structure.
6848 * @param u32IntInfo The VM-entry interruption-information field.
6849 * @param cbInstr The VM-entry instruction length in bytes (for software
6850 * interrupts, exceptions and privileged software
6851 * exceptions).
6852 * @param u32ErrCode The VM-entry exception error code.
6853 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
6854 * page-fault.
6855 */
6856DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPU pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
6857 RTGCUINTPTR GCPtrFaultAddress)
6858{
6859 Assert(!pVCpu->hm.s.Event.fPending);
6860 pVCpu->hm.s.Event.fPending = true;
6861 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
6862 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
6863 pVCpu->hm.s.Event.cbInstr = cbInstr;
6864 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
6865}
6866
6867
6868/**
6869 * Sets an external interrupt as pending-for-injection into the VM.
6870 *
6871 * @param pVCpu The cross context virtual CPU structure.
6872 * @param u8Interrupt The external interrupt vector.
6873 */
6874DECLINLINE(void) hmR0VmxSetPendingExtInt(PVMCPU pVCpu, uint8_t u8Interrupt)
6875{
6876 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, u8Interrupt)
6877 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
6878 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6879 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6880 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6881}
6882
6883
6884/**
6885 * Sets an NMI (\#NMI) exception as pending-for-injection into the VM.
6886 *
6887 * @param pVCpu The cross context virtual CPU structure.
6888 */
6889DECLINLINE(void) hmR0VmxSetPendingXcptNmi(PVMCPU pVCpu)
6890{
6891 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI)
6892 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI)
6893 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6894 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6895 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6896}
6897
6898
6899/**
6900 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
6901 *
6902 * @param pVCpu The cross context virtual CPU structure.
6903 */
6904DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu)
6905{
6906 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
6907 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6908 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6909 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6910 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6911}
6912
6913
6914/**
6915 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
6916 *
6917 * @param pVCpu The cross context virtual CPU structure.
6918 */
6919DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPU pVCpu)
6920{
6921 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_UD)
6922 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6923 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6924 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6925 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6926}
6927
6928
6929/**
6930 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
6931 *
6932 * @param pVCpu The cross context virtual CPU structure.
6933 */
6934DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPU pVCpu)
6935{
6936 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
6937 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6938 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6939 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6940 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6941}
6942
6943
6944#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6945/**
6946 * Sets a general-protection (\#GP) exception as pending-for-injection into the VM.
6947 *
6948 * @param pVCpu The cross context virtual CPU structure.
6949 * @param u32ErrCode The error code for the general-protection exception.
6950 */
6951DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPU pVCpu, uint32_t u32ErrCode)
6952{
6953 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
6954 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6955 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6956 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6957 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
6958}
6959
6960
6961/**
6962 * Sets a stack (\#SS) exception as pending-for-injection into the VM.
6963 *
6964 * @param pVCpu The cross context virtual CPU structure.
6965 * @param u32ErrCode The error code for the stack exception.
6966 */
6967DECLINLINE(void) hmR0VmxSetPendingXcptSS(PVMCPU pVCpu, uint32_t u32ErrCode)
6968{
6969 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_SS)
6970 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6971 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6972 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6973 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
6974}
6975#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
6976
6977
6978/**
6979 * Fixes up attributes for the specified segment register.
6980 *
6981 * @param pVCpu The cross context virtual CPU structure.
6982 * @param pSelReg The segment register that needs fixing.
6983 * @param idxSel The VMCS field for the corresponding segment register.
6984 */
6985static void hmR0VmxFixUnusableSegRegAttr(PVMCPU pVCpu, PCPUMSELREG pSelReg, uint32_t idxSel)
6986{
6987 Assert(pSelReg->Attr.u & X86DESCATTR_UNUSABLE);
6988
6989 /*
6990 * If VT-x marks the segment as unusable, most other bits remain undefined:
6991 * - For CS the L, D and G bits have meaning.
6992 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
6993 * - For the remaining data segments no bits are defined.
6994 *
6995 * The present bit and the unusable bit has been observed to be set at the
6996 * same time (the selector was supposed to be invalid as we started executing
6997 * a V8086 interrupt in ring-0).
6998 *
6999 * What should be important for the rest of the VBox code, is that the P bit is
7000 * cleared. Some of the other VBox code recognizes the unusable bit, but
7001 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
7002 * safe side here, we'll strip off P and other bits we don't care about. If
7003 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
7004 *
7005 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
7006 */
7007#ifdef VBOX_STRICT
7008 uint32_t const uAttr = pSelReg->Attr.u;
7009#endif
7010
7011 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
7012 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
7013 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
7014
7015#ifdef VBOX_STRICT
7016 VMMRZCallRing3Disable(pVCpu);
7017 Log4Func(("Unusable %#x: sel=%#x attr=%#x -> %#x\n", idxSel, pSelReg->Sel, uAttr, pSelReg->Attr.u));
7018# ifdef DEBUG_bird
7019 AssertMsg((uAttr & ~X86DESCATTR_P) == pSelReg->Attr.u,
7020 ("%#x: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
7021 idxSel, uAttr, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
7022# endif
7023 VMMRZCallRing3Enable(pVCpu);
7024 NOREF(uAttr);
7025#endif
7026 RT_NOREF2(pVCpu, idxSel);
7027}
7028
7029
7030/**
7031 * Imports a guest segment register from the current VMCS into the guest-CPU
7032 * context.
7033 *
7034 * @param pVCpu The cross context virtual CPU structure.
7035 * @param iSegReg The segment register number (X86_SREG_XXX).
7036 *
7037 * @remarks Called with interrupts and/or preemption disabled.
7038 */
7039static void hmR0VmxImportGuestSegReg(PVMCPU pVCpu, uint8_t iSegReg)
7040{
7041 Assert(iSegReg < X86_SREG_COUNT);
7042
7043 uint32_t const idxSel = g_aVmcsSegSel[iSegReg];
7044 uint32_t const idxLimit = g_aVmcsSegLimit[iSegReg];
7045 uint32_t const idxAttr = g_aVmcsSegAttr[iSegReg];
7046 uint32_t const idxBase = g_aVmcsSegBase[iSegReg];
7047
7048 uint16_t u16Sel;
7049 uint64_t u64Base;
7050 uint32_t u32Limit, u32Attr;
7051 int rc = VMXReadVmcs16(idxSel, &u16Sel); AssertRC(rc);
7052 rc = VMXReadVmcs32(idxLimit, &u32Limit); AssertRC(rc);
7053 rc = VMXReadVmcs32(idxAttr, &u32Attr); AssertRC(rc);
7054 rc = VMXReadVmcsNw(idxBase, &u64Base); AssertRC(rc);
7055
7056 PCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
7057 pSelReg->Sel = u16Sel;
7058 pSelReg->ValidSel = u16Sel;
7059 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
7060 pSelReg->u32Limit = u32Limit;
7061 pSelReg->u64Base = u64Base;
7062 pSelReg->Attr.u = u32Attr;
7063 if (u32Attr & X86DESCATTR_UNUSABLE)
7064 hmR0VmxFixUnusableSegRegAttr(pVCpu, pSelReg, idxSel);
7065}
7066
7067
7068/**
7069 * Imports the guest LDTR from the current VMCS into the guest-CPU context.
7070 *
7071 * @param pVCpu The cross context virtual CPU structure.
7072 *
7073 * @remarks Called with interrupts and/or preemption disabled.
7074 */
7075static void hmR0VmxImportGuestLdtr(PVMCPU pVCpu)
7076{
7077 uint16_t u16Sel;
7078 uint64_t u64Base;
7079 uint32_t u32Limit, u32Attr;
7080 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, &u16Sel); AssertRC(rc);
7081 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, &u32Limit); AssertRC(rc);
7082 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7083 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, &u64Base); AssertRC(rc);
7084
7085 pVCpu->cpum.GstCtx.ldtr.Sel = u16Sel;
7086 pVCpu->cpum.GstCtx.ldtr.ValidSel = u16Sel;
7087 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
7088 pVCpu->cpum.GstCtx.ldtr.u32Limit = u32Limit;
7089 pVCpu->cpum.GstCtx.ldtr.u64Base = u64Base;
7090 pVCpu->cpum.GstCtx.ldtr.Attr.u = u32Attr;
7091 if (u32Attr & X86DESCATTR_UNUSABLE)
7092 hmR0VmxFixUnusableSegRegAttr(pVCpu, &pVCpu->cpum.GstCtx.ldtr, VMX_VMCS16_GUEST_LDTR_SEL);
7093}
7094
7095
7096/**
7097 * Imports the guest TR from the current VMCS into the guest-CPU context.
7098 *
7099 * @param pVCpu The cross context virtual CPU structure.
7100 *
7101 * @remarks Called with interrupts and/or preemption disabled.
7102 */
7103static void hmR0VmxImportGuestTr(PVMCPU pVCpu)
7104{
7105 uint16_t u16Sel;
7106 uint64_t u64Base;
7107 uint32_t u32Limit, u32Attr;
7108 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_TR_SEL, &u16Sel); AssertRC(rc);
7109 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, &u32Limit); AssertRC(rc);
7110 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7111 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_TR_BASE, &u64Base); AssertRC(rc);
7112
7113 pVCpu->cpum.GstCtx.tr.Sel = u16Sel;
7114 pVCpu->cpum.GstCtx.tr.ValidSel = u16Sel;
7115 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
7116 pVCpu->cpum.GstCtx.tr.u32Limit = u32Limit;
7117 pVCpu->cpum.GstCtx.tr.u64Base = u64Base;
7118 pVCpu->cpum.GstCtx.tr.Attr.u = u32Attr;
7119 /* TR is the only selector that can never be unusable. */
7120 Assert(!(u32Attr & X86DESCATTR_UNUSABLE));
7121}
7122
7123
7124/**
7125 * Imports the guest RIP from the VMCS back into the guest-CPU context.
7126 *
7127 * @param pVCpu The cross context virtual CPU structure.
7128 *
7129 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7130 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7131 * instead!!!
7132 */
7133static void hmR0VmxImportGuestRip(PVMCPU pVCpu)
7134{
7135 uint64_t u64Val;
7136 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7137 if (pCtx->fExtrn & CPUMCTX_EXTRN_RIP)
7138 {
7139 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
7140 AssertRC(rc);
7141
7142 pCtx->rip = u64Val;
7143 EMR0HistoryUpdatePC(pVCpu, pCtx->rip, false);
7144 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RIP;
7145 }
7146}
7147
7148
7149/**
7150 * Imports the guest RFLAGS from the VMCS back into the guest-CPU context.
7151 *
7152 * @param pVCpu The cross context virtual CPU structure.
7153 * @param pVmcsInfo The VMCS info. object.
7154 *
7155 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7156 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7157 * instead!!!
7158 */
7159static void hmR0VmxImportGuestRFlags(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
7160{
7161 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7162 if (pCtx->fExtrn & CPUMCTX_EXTRN_RFLAGS)
7163 {
7164 uint64_t u64Val;
7165 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
7166 AssertRC(rc);
7167
7168 pCtx->rflags.u64 = u64Val;
7169 if (pVmcsInfo->RealMode.fRealOnV86Active)
7170 {
7171 pCtx->eflags.Bits.u1VM = 0;
7172 pCtx->eflags.Bits.u2IOPL = pVmcsInfo->RealMode.Eflags.Bits.u2IOPL;
7173 }
7174 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RFLAGS;
7175 }
7176}
7177
7178
7179/**
7180 * Imports the guest interruptibility-state from the VMCS back into the guest-CPU
7181 * context.
7182 *
7183 * @param pVCpu The cross context virtual CPU structure.
7184 * @param pVmcsInfo The VMCS info. object.
7185 *
7186 * @remarks Called with interrupts and/or preemption disabled, try not to assert and
7187 * do not log!
7188 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7189 * instead!!!
7190 */
7191static void hmR0VmxImportGuestIntrState(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
7192{
7193 uint32_t u32Val;
7194 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32Val); AssertRC(rc);
7195 if (!u32Val)
7196 {
7197 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7198 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7199 CPUMSetGuestNmiBlocking(pVCpu, false);
7200 }
7201 else
7202 {
7203 /*
7204 * We must import RIP here to set our EM interrupt-inhibited state.
7205 * We also import RFLAGS as our code that evaluates pending interrupts
7206 * before VM-entry requires it.
7207 */
7208 hmR0VmxImportGuestRip(pVCpu);
7209 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7210
7211 if (u32Val & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
7212 EMSetInhibitInterruptsPC(pVCpu, pVCpu->cpum.GstCtx.rip);
7213 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7214 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7215
7216 bool const fNmiBlocking = RT_BOOL(u32Val & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
7217 CPUMSetGuestNmiBlocking(pVCpu, fNmiBlocking);
7218 }
7219}
7220
7221
7222/**
7223 * Worker for VMXR0ImportStateOnDemand.
7224 *
7225 * @returns VBox status code.
7226 * @param pVCpu The cross context virtual CPU structure.
7227 * @param pVmcsInfo The VMCS info. object.
7228 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7229 */
7230static int hmR0VmxImportGuestState(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
7231{
7232 int rc = VINF_SUCCESS;
7233 PVM pVM = pVCpu->CTX_SUFF(pVM);
7234 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7235 uint32_t u32Val;
7236
7237 /*
7238 * Note! This is hack to workaround a mysterious BSOD observed with release builds
7239 * on Windows 10 64-bit hosts. Profile and debug builds are not affected and
7240 * neither are other host platforms.
7241 *
7242 * Committing this temporarily as it prevents BSOD.
7243 *
7244 * Update: This is very likely a compiler optimization bug, see @bugref{9180}.
7245 */
7246#ifdef RT_OS_WINDOWS
7247 if (pVM == 0 || pVM == (void *)(uintptr_t)-1)
7248 return VERR_HM_IPE_1;
7249#endif
7250
7251 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatImportGuestState, x);
7252
7253 /*
7254 * We disable interrupts to make the updating of the state and in particular
7255 * the fExtrn modification atomic wrt to preemption hooks.
7256 */
7257 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
7258
7259 fWhat &= pCtx->fExtrn;
7260 if (fWhat)
7261 {
7262 do
7263 {
7264 if (fWhat & CPUMCTX_EXTRN_RIP)
7265 hmR0VmxImportGuestRip(pVCpu);
7266
7267 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
7268 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7269
7270 if (fWhat & CPUMCTX_EXTRN_HM_VMX_INT_STATE)
7271 hmR0VmxImportGuestIntrState(pVCpu, pVmcsInfo);
7272
7273 if (fWhat & CPUMCTX_EXTRN_RSP)
7274 {
7275 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RSP, &pCtx->rsp);
7276 AssertRC(rc);
7277 }
7278
7279 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
7280 {
7281 bool const fRealOnV86Active = pVmcsInfo->RealMode.fRealOnV86Active;
7282 if (fWhat & CPUMCTX_EXTRN_CS)
7283 {
7284 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_CS);
7285 hmR0VmxImportGuestRip(pVCpu);
7286 if (fRealOnV86Active)
7287 pCtx->cs.Attr.u = pVmcsInfo->RealMode.AttrCS.u;
7288 EMR0HistoryUpdatePC(pVCpu, pCtx->cs.u64Base + pCtx->rip, true /* fFlattened */);
7289 }
7290 if (fWhat & CPUMCTX_EXTRN_SS)
7291 {
7292 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_SS);
7293 if (fRealOnV86Active)
7294 pCtx->ss.Attr.u = pVmcsInfo->RealMode.AttrSS.u;
7295 }
7296 if (fWhat & CPUMCTX_EXTRN_DS)
7297 {
7298 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_DS);
7299 if (fRealOnV86Active)
7300 pCtx->ds.Attr.u = pVmcsInfo->RealMode.AttrDS.u;
7301 }
7302 if (fWhat & CPUMCTX_EXTRN_ES)
7303 {
7304 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_ES);
7305 if (fRealOnV86Active)
7306 pCtx->es.Attr.u = pVmcsInfo->RealMode.AttrES.u;
7307 }
7308 if (fWhat & CPUMCTX_EXTRN_FS)
7309 {
7310 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_FS);
7311 if (fRealOnV86Active)
7312 pCtx->fs.Attr.u = pVmcsInfo->RealMode.AttrFS.u;
7313 }
7314 if (fWhat & CPUMCTX_EXTRN_GS)
7315 {
7316 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_GS);
7317 if (fRealOnV86Active)
7318 pCtx->gs.Attr.u = pVmcsInfo->RealMode.AttrGS.u;
7319 }
7320 }
7321
7322 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
7323 {
7324 if (fWhat & CPUMCTX_EXTRN_LDTR)
7325 hmR0VmxImportGuestLdtr(pVCpu);
7326
7327 if (fWhat & CPUMCTX_EXTRN_GDTR)
7328 {
7329 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &pCtx->gdtr.pGdt); AssertRC(rc);
7330 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRC(rc);
7331 pCtx->gdtr.cbGdt = u32Val;
7332 }
7333
7334 /* Guest IDTR. */
7335 if (fWhat & CPUMCTX_EXTRN_IDTR)
7336 {
7337 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &pCtx->idtr.pIdt); AssertRC(rc);
7338 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRC(rc);
7339 pCtx->idtr.cbIdt = u32Val;
7340 }
7341
7342 /* Guest TR. */
7343 if (fWhat & CPUMCTX_EXTRN_TR)
7344 {
7345 /* Real-mode emulation using virtual-8086 mode has the fake TSS (pRealModeTSS) in TR,
7346 don't need to import that one. */
7347 if (!pVmcsInfo->RealMode.fRealOnV86Active)
7348 hmR0VmxImportGuestTr(pVCpu);
7349 }
7350 }
7351
7352 if (fWhat & CPUMCTX_EXTRN_DR7)
7353 {
7354 if (!pVCpu->hm.s.fUsingHyperDR7)
7355 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_DR7, &pCtx->dr[7]); AssertRC(rc);
7356 }
7357
7358 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
7359 {
7360 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, &pCtx->SysEnter.eip); AssertRC(rc);
7361 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, &pCtx->SysEnter.esp); AssertRC(rc);
7362 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRC(rc);
7363 pCtx->SysEnter.cs = u32Val;
7364 }
7365
7366 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
7367 {
7368 if ( pVM->hm.s.fAllow64BitGuests
7369 && (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7370 pCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
7371 }
7372
7373 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
7374 {
7375 if ( pVM->hm.s.fAllow64BitGuests
7376 && (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7377 {
7378 pCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
7379 pCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
7380 pCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
7381 }
7382 }
7383
7384 if (fWhat & (CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS))
7385 {
7386 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
7387 uint32_t const cMsrs = pVmcsInfo->cExitMsrStore;
7388 Assert(pMsrs);
7389 Assert(cMsrs <= VMX_MISC_MAX_MSRS(pVM->hm.s.vmx.Msrs.u64Misc));
7390 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
7391 for (uint32_t i = 0; i < cMsrs; i++)
7392 {
7393 uint32_t const idMsr = pMsrs[i].u32Msr;
7394 switch (idMsr)
7395 {
7396 case MSR_K8_TSC_AUX: CPUMSetGuestTscAux(pVCpu, pMsrs[i].u64Value); break;
7397 case MSR_IA32_SPEC_CTRL: CPUMSetGuestSpecCtrl(pVCpu, pMsrs[i].u64Value); break;
7398 case MSR_K6_EFER: /* Can't be changed without causing a VM-exit */ break;
7399 default:
7400 {
7401 pCtx->fExtrn = 0;
7402 pVCpu->hm.s.u32HMError = pMsrs->u32Msr;
7403 ASMSetFlags(fEFlags);
7404 AssertMsgFailed(("Unexpected MSR in auto-load/store area. idMsr=%#RX32 cMsrs=%u\n", idMsr, cMsrs));
7405 return VERR_HM_UNEXPECTED_LD_ST_MSR;
7406 }
7407 }
7408 }
7409 }
7410
7411 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
7412 {
7413 if (fWhat & CPUMCTX_EXTRN_CR0)
7414 {
7415 uint64_t u64Cr0;
7416 uint64_t u64Shadow;
7417 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Cr0); AssertRC(rc);
7418 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Shadow); AssertRC(rc);
7419 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7420 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7421#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7422 /*
7423 * Reapply the nested-guest's CR0 fixed bits that might have been altered while
7424 * exporting the nested-guest CR0 for executing using hardware-assisted VMX.
7425 */
7426 if (CPUMIsGuestInVmxNonRootMode(pCtx))
7427 {
7428 u64Cr0 |= pCtx->hwvirt.vmx.Msrs.u64Cr0Fixed0;
7429 u64Cr0 &= pCtx->hwvirt.vmx.Msrs.u64Cr0Fixed1;
7430 }
7431#endif
7432 VMMRZCallRing3Disable(pVCpu); /* May call into PGM which has Log statements. */
7433 CPUMSetGuestCR0(pVCpu, u64Cr0);
7434 VMMRZCallRing3Enable(pVCpu);
7435 }
7436
7437 if (fWhat & CPUMCTX_EXTRN_CR4)
7438 {
7439 uint64_t u64Cr4;
7440 uint64_t u64Shadow;
7441 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64Cr4); AssertRC(rc);
7442 rc |= VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Shadow); AssertRC(rc);
7443 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7444 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7445#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7446 /*
7447 * Reapply the nested-guest's CR4 fixed bits that might have been altered while
7448 * exporting the nested-guest CR4 for executing using hardware-assisted VMX.
7449 */
7450 if (CPUMIsGuestInVmxNonRootMode(pCtx))
7451 {
7452 u64Cr4 |= pCtx->hwvirt.vmx.Msrs.u64Cr4Fixed0;
7453 u64Cr4 &= pCtx->hwvirt.vmx.Msrs.u64Cr4Fixed1;
7454 }
7455#endif
7456 pCtx->cr4 = u64Cr4;
7457 }
7458
7459 if (fWhat & CPUMCTX_EXTRN_CR3)
7460 {
7461 /* CR0.PG bit changes are always intercepted, so it's up to date. */
7462 if ( pVM->hm.s.vmx.fUnrestrictedGuest
7463 || ( pVM->hm.s.fNestedPaging
7464 && CPUMIsGuestPagingEnabledEx(pCtx)))
7465 {
7466 uint64_t u64Cr3;
7467 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR3, &u64Cr3); AssertRC(rc);
7468 if (pCtx->cr3 != u64Cr3)
7469 {
7470 pCtx->cr3 = u64Cr3;
7471 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
7472 }
7473
7474 /* If the guest is in PAE mode, sync back the PDPE's into the guest state.
7475 Note: CR4.PAE, CR0.PG, EFER MSR changes are always intercepted, so they're up to date. */
7476 if (CPUMIsGuestInPAEModeEx(pCtx))
7477 {
7478 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
7479 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
7480 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
7481 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
7482 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
7483 }
7484 }
7485 }
7486 }
7487
7488#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7489 if (fWhat & CPUMCTX_EXTRN_HWVIRT)
7490 {
7491 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
7492 && !CPUMIsGuestInVmxNonRootMode(pCtx))
7493 {
7494 Assert(CPUMIsGuestInVmxRootMode(pCtx));
7495 rc = hmR0VmxCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
7496 if (RT_SUCCESS(rc))
7497 { /* likely */ }
7498 else
7499 break;
7500 }
7501 }
7502#endif
7503 } while (0);
7504
7505 if (RT_SUCCESS(rc))
7506 {
7507 /* Update fExtrn. */
7508 pCtx->fExtrn &= ~fWhat;
7509
7510 /* If everything has been imported, clear the HM keeper bit. */
7511 if (!(pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL))
7512 {
7513 pCtx->fExtrn &= ~CPUMCTX_EXTRN_KEEPER_HM;
7514 Assert(!pCtx->fExtrn);
7515 }
7516 }
7517 }
7518 else
7519 AssertMsg(!pCtx->fExtrn || (pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL), ("%#RX64\n", pCtx->fExtrn));
7520
7521 /*
7522 * Restore interrupts.
7523 */
7524 ASMSetFlags(fEFlags);
7525
7526 STAM_PROFILE_ADV_STOP(& pVCpu->hm.s.StatImportGuestState, x);
7527
7528 if (RT_SUCCESS(rc))
7529 { /* likely */ }
7530 else
7531 return rc;
7532
7533 /*
7534 * Honor any pending CR3 updates.
7535 *
7536 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> hmR0VmxCallRing3Callback()
7537 * -> VMMRZCallRing3Disable() -> hmR0VmxImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
7538 * -> continue with VM-exit handling -> hmR0VmxImportGuestState() and here we are.
7539 *
7540 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
7541 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
7542 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
7543 * -NOT- check if CPUMCTX_EXTRN_CR3 is set!
7544 *
7545 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
7546 */
7547 if (VMMRZCallRing3IsEnabled(pVCpu))
7548 {
7549 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
7550 {
7551 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & CPUMCTX_EXTRN_CR3));
7552 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
7553 }
7554
7555 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
7556 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
7557
7558 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
7559 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
7560 }
7561
7562 return VINF_SUCCESS;
7563}
7564
7565
7566/**
7567 * Saves the guest state from the VMCS into the guest-CPU context.
7568 *
7569 * @returns VBox status code.
7570 * @param pVCpu The cross context virtual CPU structure.
7571 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7572 */
7573VMMR0DECL(int) VMXR0ImportStateOnDemand(PVMCPU pVCpu, uint64_t fWhat)
7574{
7575 AssertPtr(pVCpu);
7576 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7577 return hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fWhat);
7578}
7579
7580
7581/**
7582 * Check per-VM and per-VCPU force flag actions that require us to go back to
7583 * ring-3 for one reason or another.
7584 *
7585 * @returns Strict VBox status code (i.e. informational status codes too)
7586 * @retval VINF_SUCCESS if we don't have any actions that require going back to
7587 * ring-3.
7588 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
7589 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
7590 * interrupts)
7591 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
7592 * all EMTs to be in ring-3.
7593 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
7594 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
7595 * to the EM loop.
7596 *
7597 * @param pVCpu The cross context virtual CPU structure.
7598 * @param fStepping Whether we are single-stepping the guest using the
7599 * hypervisor debugger.
7600 *
7601 * @remarks This might cause nested-guest VM-exits, caller must check if the guest
7602 * is no longer in VMX non-root mode.
7603 */
7604static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVMCPU pVCpu, bool fStepping)
7605{
7606 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7607
7608 /*
7609 * Update pending interrupts into the APIC's IRR.
7610 */
7611 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
7612 APICUpdatePendingInterrupts(pVCpu);
7613
7614 /*
7615 * Anything pending? Should be more likely than not if we're doing a good job.
7616 */
7617 PVM pVM = pVCpu->CTX_SUFF(pVM);
7618 if ( !fStepping
7619 ? !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_MASK)
7620 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
7621 : !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
7622 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
7623 return VINF_SUCCESS;
7624
7625 /* Pending PGM C3 sync. */
7626 if (VMCPU_FF_IS_ANY_SET(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
7627 {
7628 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7629 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & (CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4)));
7630 VBOXSTRICTRC rcStrict = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4,
7631 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
7632 if (rcStrict != VINF_SUCCESS)
7633 {
7634 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
7635 Log4Func(("PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
7636 return rcStrict;
7637 }
7638 }
7639
7640 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
7641 if ( VM_FF_IS_ANY_SET(pVM, VM_FF_HM_TO_R3_MASK)
7642 || VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
7643 {
7644 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
7645 int rc = RT_LIKELY(!VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_RAW_TO_R3 : VINF_EM_NO_MEMORY;
7646 Log4Func(("HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc));
7647 return rc;
7648 }
7649
7650 /* Pending VM request packets, such as hardware interrupts. */
7651 if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
7652 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
7653 {
7654 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchVmReq);
7655 Log4Func(("Pending VM request forcing us back to ring-3\n"));
7656 return VINF_EM_PENDING_REQUEST;
7657 }
7658
7659 /* Pending PGM pool flushes. */
7660 if (VM_FF_IS_SET(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
7661 {
7662 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPgmPoolFlush);
7663 Log4Func(("PGM pool flush pending forcing us back to ring-3\n"));
7664 return VINF_PGM_POOL_FLUSH_PENDING;
7665 }
7666
7667 /* Pending DMA requests. */
7668 if (VM_FF_IS_SET(pVM, VM_FF_PDM_DMA))
7669 {
7670 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchDma);
7671 Log4Func(("Pending DMA request forcing us back to ring-3\n"));
7672 return VINF_EM_RAW_TO_R3;
7673 }
7674
7675#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7676 /* Pending nested-guest APIC-write (has highest priority among nested-guest FFs). */
7677 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
7678 {
7679 Log4Func(("Pending nested-guest APIC-write\n"));
7680 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitApicWrite(pVCpu);
7681 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
7682 return rcStrict;
7683 }
7684 /** @todo VMCPU_FF_VMX_MTF, VMCPU_FF_VMX_PREEMPT_TIMER */
7685#endif
7686
7687 return VINF_SUCCESS;
7688}
7689
7690
7691/**
7692 * Converts any TRPM trap into a pending HM event. This is typically used when
7693 * entering from ring-3 (not longjmp returns).
7694 *
7695 * @param pVCpu The cross context virtual CPU structure.
7696 */
7697static void hmR0VmxTrpmTrapToPendingEvent(PVMCPU pVCpu)
7698{
7699 Assert(TRPMHasTrap(pVCpu));
7700 Assert(!pVCpu->hm.s.Event.fPending);
7701
7702 uint8_t uVector;
7703 TRPMEVENT enmTrpmEvent;
7704 RTGCUINT uErrCode;
7705 RTGCUINTPTR GCPtrFaultAddress;
7706 uint8_t cbInstr;
7707
7708 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr);
7709 AssertRC(rc);
7710
7711 uint32_t u32IntInfo;
7712 u32IntInfo = uVector | VMX_IDT_VECTORING_INFO_VALID;
7713 u32IntInfo |= HMTrpmEventTypeToVmxEventType(uVector, enmTrpmEvent);
7714
7715 rc = TRPMResetTrap(pVCpu);
7716 AssertRC(rc);
7717 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
7718 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
7719
7720 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
7721}
7722
7723
7724/**
7725 * Converts the pending HM event into a TRPM trap.
7726 *
7727 * @param pVCpu The cross context virtual CPU structure.
7728 */
7729static void hmR0VmxPendingEventToTrpmTrap(PVMCPU pVCpu)
7730{
7731 Assert(pVCpu->hm.s.Event.fPending);
7732
7733 /* If a trap was already pending, we did something wrong! */
7734 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
7735
7736 uint32_t const u32IntInfo = pVCpu->hm.s.Event.u64IntInfo;
7737 uint32_t const uVector = VMX_IDT_VECTORING_INFO_VECTOR(u32IntInfo);
7738 TRPMEVENT const enmTrapType = HMVmxEventTypeToTrpmEventType(u32IntInfo);
7739
7740 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
7741
7742 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
7743 AssertRC(rc);
7744
7745 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
7746 TRPMSetErrorCode(pVCpu, pVCpu->hm.s.Event.u32ErrCode);
7747
7748 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(u32IntInfo))
7749 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
7750 else if (VMX_IDT_VECTORING_INFO_TYPE(u32IntInfo) == VMX_IDT_VECTORING_INFO_TYPE_SW_INT)
7751 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
7752
7753 /* We're now done converting the pending event. */
7754 pVCpu->hm.s.Event.fPending = false;
7755}
7756
7757
7758/**
7759 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
7760 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
7761 *
7762 * @param pVCpu The cross context virtual CPU structure.
7763 * @param pVmcsInfo The VMCS info. object.
7764 */
7765static void hmR0VmxSetIntWindowExitVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
7766{
7767 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7768 {
7769 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
7770 {
7771 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_INT_WINDOW_EXIT;
7772 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7773 AssertRC(rc);
7774 }
7775 } /* else we will deliver interrupts whenever the guest Vm-exits next and is in a state to receive the interrupt. */
7776}
7777
7778
7779/**
7780 * Clears the interrupt-window exiting control in the VMCS.
7781 *
7782 * @param pVmcsInfo The VMCS info. object.
7783 */
7784DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
7785{
7786 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7787 {
7788 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_INT_WINDOW_EXIT;
7789 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7790 AssertRC(rc);
7791 }
7792}
7793
7794
7795/**
7796 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
7797 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
7798 *
7799 * @param pVCpu The cross context virtual CPU structure.
7800 * @param pVmcsInfo The VMCS info. object.
7801 */
7802static void hmR0VmxSetNmiWindowExitVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
7803{
7804 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7805 {
7806 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
7807 {
7808 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_NMI_WINDOW_EXIT;
7809 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7810 AssertRC(rc);
7811 Log4Func(("Setup NMI-window exiting\n"));
7812 }
7813 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
7814}
7815
7816
7817/**
7818 * Clears the NMI-window exiting control in the VMCS.
7819 *
7820 * @param pVmcsInfo The VMCS info. object.
7821 */
7822DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
7823{
7824 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7825 {
7826 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_NMI_WINDOW_EXIT;
7827 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7828 AssertRC(rc);
7829 }
7830}
7831
7832
7833/**
7834 * Does the necessary state syncing before returning to ring-3 for any reason
7835 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
7836 *
7837 * @returns VBox status code.
7838 * @param pVCpu The cross context virtual CPU structure.
7839 * @param fImportState Whether to import the guest state from the VMCS back
7840 * to the guest-CPU context.
7841 *
7842 * @remarks No-long-jmp zone!!!
7843 */
7844static int hmR0VmxLeave(PVMCPU pVCpu, bool fImportState)
7845{
7846 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7847 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7848
7849 RTCPUID const idCpu = RTMpCpuId();
7850 Log4Func(("HostCpuId=%u\n", idCpu));
7851
7852 /*
7853 * !!! IMPORTANT !!!
7854 * If you modify code here, check whether hmR0VmxCallRing3Callback() needs to be updated too.
7855 */
7856
7857 /* Save the guest state if necessary. */
7858 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7859 if (fImportState)
7860 {
7861 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
7862 AssertRCReturn(rc, rc);
7863 }
7864
7865 /* Restore host FPU state if necessary. We will resync on next R0 reentry. */
7866 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
7867 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
7868
7869 /* Restore host debug registers if necessary. We will resync on next R0 reentry. */
7870#ifdef VBOX_STRICT
7871 if (CPUMIsHyperDebugStateActive(pVCpu))
7872 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT);
7873#endif
7874 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
7875 Assert(!CPUMIsGuestDebugStateActive(pVCpu) && !CPUMIsGuestDebugStateActivePending(pVCpu));
7876 Assert(!CPUMIsHyperDebugStateActive(pVCpu) && !CPUMIsHyperDebugStateActivePending(pVCpu));
7877
7878 /* Restore host-state bits that VT-x only restores partially. */
7879 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7880 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7881 {
7882 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags, idCpu));
7883 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7884 }
7885 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7886
7887 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7888 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
7889 {
7890 /* We shouldn't restore the host MSRs without saving the guest MSRs first. */
7891 if (!fImportState)
7892 {
7893 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS);
7894 AssertRCReturn(rc, rc);
7895 }
7896 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7897 Assert(!pVCpu->hm.s.vmx.fLazyMsrs);
7898 }
7899 else
7900 pVCpu->hm.s.vmx.fLazyMsrs = 0;
7901
7902 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7903 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
7904
7905 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
7906 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatImportGuestState);
7907 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExportGuestState);
7908 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatPreExit);
7909 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitHandling);
7910 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
7911 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
7912 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
7913 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitVmentry);
7914 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7915
7916 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7917
7918 /** @todo This partially defeats the purpose of having preemption hooks.
7919 * The problem is, deregistering the hooks should be moved to a place that
7920 * lasts until the EMT is about to be destroyed not everytime while leaving HM
7921 * context.
7922 */
7923 int rc = hmR0VmxClearVmcs(pVmcsInfo);
7924 AssertRCReturn(rc, rc);
7925
7926#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7927 /*
7928 * A valid shadow VMCS is made active as part of VM-entry. It is necessary to
7929 * clear a shadow VMCS before allowing that VMCS to become active on another
7930 * logical processor. We may or may not be importing guest state which clears
7931 * it, so cover for it here.
7932 *
7933 * See Intel spec. 24.11.1 "Software Use of Virtual-Machine Control Structures".
7934 */
7935 if ( pVmcsInfo->pvShadowVmcs
7936 && pVmcsInfo->fShadowVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
7937 {
7938 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
7939 AssertRCReturn(rc, rc);
7940 }
7941
7942 /*
7943 * Flag that we need to re-import the host state if we switch to this VMCS before
7944 * executing guest or nested-guest code.
7945 */
7946 pVmcsInfo->idHostCpu = NIL_RTCPUID;
7947#endif
7948
7949 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
7950 NOREF(idCpu);
7951 return VINF_SUCCESS;
7952}
7953
7954
7955/**
7956 * Leaves the VT-x session.
7957 *
7958 * @returns VBox status code.
7959 * @param pVCpu The cross context virtual CPU structure.
7960 *
7961 * @remarks No-long-jmp zone!!!
7962 */
7963static int hmR0VmxLeaveSession(PVMCPU pVCpu)
7964{
7965 HM_DISABLE_PREEMPT(pVCpu);
7966 HMVMX_ASSERT_CPU_SAFE(pVCpu);
7967 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7968 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7969
7970 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
7971 and done this from the VMXR0ThreadCtxCallback(). */
7972 if (!pVCpu->hm.s.fLeaveDone)
7973 {
7974 int rc2 = hmR0VmxLeave(pVCpu, true /* fImportState */);
7975 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
7976 pVCpu->hm.s.fLeaveDone = true;
7977 }
7978 Assert(!pVCpu->cpum.GstCtx.fExtrn);
7979
7980 /*
7981 * !!! IMPORTANT !!!
7982 * If you modify code here, make sure to check whether hmR0VmxCallRing3Callback() needs to be updated too.
7983 */
7984
7985 /* Deregister hook now that we've left HM context before re-enabling preemption. */
7986 /** @todo Deregistering here means we need to VMCLEAR always
7987 * (longjmp/exit-to-r3) in VT-x which is not efficient, eliminate need
7988 * for calling VMMR0ThreadCtxHookDisable here! */
7989 VMMR0ThreadCtxHookDisable(pVCpu);
7990
7991 /* Leave HM context. This takes care of local init (term). */
7992 int rc = HMR0LeaveCpu(pVCpu);
7993
7994 HM_RESTORE_PREEMPT();
7995 return rc;
7996}
7997
7998
7999/**
8000 * Does the necessary state syncing before doing a longjmp to ring-3.
8001 *
8002 * @returns VBox status code.
8003 * @param pVCpu The cross context virtual CPU structure.
8004 *
8005 * @remarks No-long-jmp zone!!!
8006 */
8007DECLINLINE(int) hmR0VmxLongJmpToRing3(PVMCPU pVCpu)
8008{
8009 return hmR0VmxLeaveSession(pVCpu);
8010}
8011
8012
8013/**
8014 * Take necessary actions before going back to ring-3.
8015 *
8016 * An action requires us to go back to ring-3. This function does the necessary
8017 * steps before we can safely return to ring-3. This is not the same as longjmps
8018 * to ring-3, this is voluntary and prepares the guest so it may continue
8019 * executing outside HM (recompiler/IEM).
8020 *
8021 * @returns VBox status code.
8022 * @param pVCpu The cross context virtual CPU structure.
8023 * @param rcExit The reason for exiting to ring-3. Can be
8024 * VINF_VMM_UNKNOWN_RING3_CALL.
8025 */
8026static int hmR0VmxExitToRing3(PVMCPU pVCpu, VBOXSTRICTRC rcExit)
8027{
8028 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8029
8030 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8031 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
8032 {
8033 VMXGetCurrentVmcs(&pVCpu->hm.s.vmx.LastError.HCPhysCurrentVmcs);
8034 pVCpu->hm.s.vmx.LastError.u32VmcsRev = *(uint32_t *)pVmcsInfo->pvVmcs;
8035 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
8036 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
8037 }
8038
8039 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
8040 VMMRZCallRing3Disable(pVCpu);
8041 Log4Func(("rcExit=%d\n", VBOXSTRICTRC_VAL(rcExit)));
8042
8043 /*
8044 * Convert any pending HM events back to TRPM due to premature exits to ring-3.
8045 * We need to do this only on returns to ring-3 and not for longjmps to ring3.
8046 *
8047 * This is because execution may continue from ring-3 and we would need to inject
8048 * the event from there (hence place it back in TRPM).
8049 */
8050 if (pVCpu->hm.s.Event.fPending)
8051 {
8052 hmR0VmxPendingEventToTrpmTrap(pVCpu);
8053 Assert(!pVCpu->hm.s.Event.fPending);
8054
8055 /* Clear the events from the VMCS. */
8056 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0);
8057 AssertRC(rc);
8058 }
8059#ifdef VBOX_STRICT
8060 else
8061 {
8062 /*
8063 * Ensure we don't accidentally clear a pending HM event without clearing the VMCS.
8064 * This can be pretty hard to debug otherwise, interrupts might get injected twice
8065 * occasionally, see @bugref{9180#c42}.
8066 *
8067 * However, if the VM-entry failed, any VM entry-interruption info. field would
8068 * be left unmodified as the event would not have been injected to the guest. In
8069 * such cases, don't assert, we're not going to continue guest execution anyway.
8070 */
8071 uint32_t uExitReason;
8072 uint32_t uEntryIntInfo;
8073 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8074 rc |= VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &uEntryIntInfo);
8075 AssertRC(rc);
8076 Assert(VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason) || !VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo));
8077 }
8078#endif
8079
8080 /*
8081 * Clear the interrupt-window and NMI-window VMCS controls as we could have got
8082 * a VM-exit with higher priority than interrupt-window or NMI-window VM-exits
8083 * (e.g. TPR below threshold).
8084 */
8085 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8086 {
8087 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
8088 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
8089 }
8090
8091 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
8092 and if we're injecting an event we should have a TRPM trap pending. */
8093 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8094#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a triple fault in progress. */
8095 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8096#endif
8097
8098 /* Save guest state and restore host state bits. */
8099 int rc = hmR0VmxLeaveSession(pVCpu);
8100 AssertRCReturn(rc, rc);
8101 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8102
8103 /* Thread-context hooks are unregistered at this point!!! */
8104
8105 /* Sync recompiler state. */
8106 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
8107 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
8108 | CPUM_CHANGED_LDTR
8109 | CPUM_CHANGED_GDTR
8110 | CPUM_CHANGED_IDTR
8111 | CPUM_CHANGED_TR
8112 | CPUM_CHANGED_HIDDEN_SEL_REGS);
8113 if ( pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging
8114 && CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx))
8115 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
8116
8117 Assert(!pVCpu->hm.s.fClearTrapFlag);
8118
8119 /* Update the exit-to-ring 3 reason. */
8120 pVCpu->hm.s.rcLastExitToR3 = VBOXSTRICTRC_VAL(rcExit);
8121
8122 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
8123 if ( rcExit != VINF_EM_RAW_INTERRUPT
8124 || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8125 {
8126 Assert(!(pVCpu->cpum.GstCtx.fExtrn & HMVMX_CPUMCTX_EXTRN_ALL));
8127 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
8128 }
8129
8130 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
8131
8132 /* We do -not- want any longjmp notifications after this! We must return to ring-3 ASAP. */
8133 VMMRZCallRing3RemoveNotification(pVCpu);
8134 VMMRZCallRing3Enable(pVCpu);
8135
8136 return rc;
8137}
8138
8139
8140/**
8141 * VMMRZCallRing3() callback wrapper which saves the guest state before we
8142 * longjump to ring-3 and possibly get preempted.
8143 *
8144 * @returns VBox status code.
8145 * @param pVCpu The cross context virtual CPU structure.
8146 * @param enmOperation The operation causing the ring-3 longjump.
8147 * @param pvUser User argument, currently unused, NULL.
8148 */
8149static DECLCALLBACK(int) hmR0VmxCallRing3Callback(PVMCPU pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
8150{
8151 RT_NOREF(pvUser);
8152 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
8153 {
8154 /*
8155 * !!! IMPORTANT !!!
8156 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
8157 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
8158 */
8159 VMMRZCallRing3RemoveNotification(pVCpu);
8160 VMMRZCallRing3Disable(pVCpu);
8161 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
8162 RTThreadPreemptDisable(&PreemptState);
8163
8164 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8165 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8166 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8167 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8168
8169 /* Restore host-state bits that VT-x only restores partially. */
8170 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
8171 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
8172 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
8173 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
8174
8175 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8176 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8177 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8178
8179 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8180 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
8181 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8182
8183 /* Clear the current VMCS data back to memory (shadow VMCS if any would have been
8184 cleared as part of importing the guest state above. */
8185 hmR0VmxClearVmcs(pVmcsInfo);
8186
8187 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
8188 VMMR0ThreadCtxHookDisable(pVCpu);
8189 HMR0LeaveCpu(pVCpu);
8190 RTThreadPreemptRestore(&PreemptState);
8191 return VINF_SUCCESS;
8192 }
8193
8194 Assert(pVCpu);
8195 Assert(pvUser);
8196 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8197 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8198
8199 VMMRZCallRing3Disable(pVCpu);
8200 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8201
8202 Log4Func((" -> hmR0VmxLongJmpToRing3 enmOperation=%d\n", enmOperation));
8203
8204 int rc = hmR0VmxLongJmpToRing3(pVCpu);
8205 AssertRCReturn(rc, rc);
8206
8207 VMMRZCallRing3Enable(pVCpu);
8208 return VINF_SUCCESS;
8209}
8210
8211
8212/**
8213 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
8214 * stack.
8215 *
8216 * @returns Strict VBox status code (i.e. informational status codes too).
8217 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
8218 * @param pVCpu The cross context virtual CPU structure.
8219 * @param uValue The value to push to the guest stack.
8220 */
8221static VBOXSTRICTRC hmR0VmxRealModeGuestStackPush(PVMCPU pVCpu, uint16_t uValue)
8222{
8223 /*
8224 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
8225 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
8226 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
8227 */
8228 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8229 if (pCtx->sp == 1)
8230 return VINF_EM_RESET;
8231 pCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
8232 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), pCtx->ss.u64Base + pCtx->sp, &uValue, sizeof(uint16_t));
8233 AssertRC(rc);
8234 return rc;
8235}
8236
8237
8238/**
8239 * Injects an event into the guest upon VM-entry by updating the relevant fields
8240 * in the VM-entry area in the VMCS.
8241 *
8242 * @returns Strict VBox status code (i.e. informational status codes too).
8243 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
8244 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
8245 *
8246 * @param pVCpu The cross context virtual CPU structure.
8247 * @param pVmxTransient The VMX-transient structure.
8248 * @param pEvent The event being injected.
8249 * @param pfIntrState Pointer to the VT-x guest-interruptibility-state. This
8250 * will be updated if necessary. This cannot not be NULL.
8251 * @param fStepping Whether we're single-stepping guest execution and should
8252 * return VINF_EM_DBG_STEPPED if the event is injected
8253 * directly (registers modified by us, not by hardware on
8254 * VM-entry).
8255 */
8256static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PCHMEVENT pEvent, bool fStepping,
8257 uint32_t *pfIntrState)
8258{
8259 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
8260 AssertMsg(!RT_HI_U32(pEvent->u64IntInfo), ("%#RX64\n", pEvent->u64IntInfo));
8261 Assert(pfIntrState);
8262
8263 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8264 uint32_t u32IntInfo = pEvent->u64IntInfo;
8265 uint32_t const u32ErrCode = pEvent->u32ErrCode;
8266 uint32_t const cbInstr = pEvent->cbInstr;
8267 RTGCUINTPTR const GCPtrFault = pEvent->GCPtrFaultAddress;
8268 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(u32IntInfo);
8269 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(u32IntInfo);
8270
8271#ifdef VBOX_STRICT
8272 /*
8273 * Validate the error-code-valid bit for hardware exceptions.
8274 * No error codes for exceptions in real-mode.
8275 *
8276 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8277 */
8278 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8279 && !CPUMIsGuestInRealModeEx(pCtx))
8280 {
8281 switch (uVector)
8282 {
8283 case X86_XCPT_PF:
8284 case X86_XCPT_DF:
8285 case X86_XCPT_TS:
8286 case X86_XCPT_NP:
8287 case X86_XCPT_SS:
8288 case X86_XCPT_GP:
8289 case X86_XCPT_AC:
8290 AssertMsg(VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo),
8291 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
8292 RT_FALL_THRU();
8293 default:
8294 break;
8295 }
8296 }
8297
8298 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
8299 Assert( uIntType != VMX_EXIT_INT_INFO_TYPE_NMI
8300 || !(*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
8301#endif
8302
8303 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
8304
8305 /*
8306 * Hardware interrupts & exceptions cannot be delivered through the software interrupt
8307 * redirection bitmap to the real mode task in virtual-8086 mode. We must jump to the
8308 * interrupt handler in the (real-mode) guest.
8309 *
8310 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode".
8311 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
8312 */
8313 if (CPUMIsGuestInRealModeEx(pCtx)) /* CR0.PE bit changes are always intercepted, so it's up to date. */
8314 {
8315 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest)
8316 {
8317 /*
8318 * For CPUs with unrestricted guest execution enabled and with the guest
8319 * in real-mode, we must not set the deliver-error-code bit.
8320 *
8321 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8322 */
8323 u32IntInfo &= ~VMX_ENTRY_INT_INFO_ERROR_CODE_VALID;
8324 }
8325 else
8326 {
8327 PVM pVM = pVCpu->CTX_SUFF(pVM);
8328 Assert(PDMVmmDevHeapIsEnabled(pVM));
8329 Assert(pVM->hm.s.vmx.pRealModeTSS);
8330 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
8331
8332 /* We require RIP, RSP, RFLAGS, CS, IDTR, import them. */
8333 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8334 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TABLE_MASK
8335 | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS);
8336 AssertRCReturn(rc2, rc2);
8337
8338 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8339 size_t const cbIdtEntry = sizeof(X86IDTR16);
8340 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pCtx->idtr.cbIdt)
8341 {
8342 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8343 if (uVector == X86_XCPT_DF)
8344 return VINF_EM_RESET;
8345
8346 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault.
8347 No error codes for exceptions in real-mode. */
8348 if (uVector == X86_XCPT_GP)
8349 {
8350 uint32_t const uXcptDfInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
8351 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8352 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8353 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8354 HMEVENT EventXcptDf;
8355 RT_ZERO(EventXcptDf);
8356 EventXcptDf.u64IntInfo = uXcptDfInfo;
8357 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptDf, fStepping, pfIntrState);
8358 }
8359
8360 /*
8361 * If we're injecting an event with no valid IDT entry, inject a #GP.
8362 * No error codes for exceptions in real-mode.
8363 *
8364 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8365 */
8366 uint32_t const uXcptGpInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
8367 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8368 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8369 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8370 HMEVENT EventXcptGp;
8371 RT_ZERO(EventXcptGp);
8372 EventXcptGp.u64IntInfo = uXcptGpInfo;
8373 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptGp, fStepping, pfIntrState);
8374 }
8375
8376 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8377 uint16_t uGuestIp = pCtx->ip;
8378 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT)
8379 {
8380 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8381 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8382 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8383 }
8384 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_INT)
8385 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8386
8387 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8388 X86IDTR16 IdtEntry;
8389 RTGCPHYS const GCPhysIdtEntry = (RTGCPHYS)pCtx->idtr.pIdt + uVector * cbIdtEntry;
8390 rc2 = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8391 AssertRCReturn(rc2, rc2);
8392
8393 /* Construct the stack frame for the interrupt/exception handler. */
8394 VBOXSTRICTRC rcStrict;
8395 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->eflags.u32);
8396 if (rcStrict == VINF_SUCCESS)
8397 {
8398 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->cs.Sel);
8399 if (rcStrict == VINF_SUCCESS)
8400 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, uGuestIp);
8401 }
8402
8403 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8404 if (rcStrict == VINF_SUCCESS)
8405 {
8406 pCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8407 pCtx->rip = IdtEntry.offSel;
8408 pCtx->cs.Sel = IdtEntry.uSel;
8409 pCtx->cs.ValidSel = IdtEntry.uSel;
8410 pCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8411 if ( uIntType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
8412 && uVector == X86_XCPT_PF)
8413 pCtx->cr2 = GCPtrFault;
8414
8415 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CS | HM_CHANGED_GUEST_CR2
8416 | HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
8417 | HM_CHANGED_GUEST_RSP);
8418
8419 /*
8420 * If we delivered a hardware exception (other than an NMI) and if there was
8421 * block-by-STI in effect, we should clear it.
8422 */
8423 if (*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
8424 {
8425 Assert( uIntType != VMX_ENTRY_INT_INFO_TYPE_NMI
8426 && uIntType != VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
8427 Log4Func(("Clearing inhibition due to STI\n"));
8428 *pfIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
8429 }
8430
8431 Log4(("Injected real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8432 u32IntInfo, u32ErrCode, cbInstr, pCtx->eflags.u, pCtx->cs.Sel, pCtx->eip));
8433
8434 /*
8435 * The event has been truly dispatched to the guest. Mark it as no longer pending so
8436 * we don't attempt to undo it if we are returning to ring-3 before executing guest code.
8437 */
8438 pVCpu->hm.s.Event.fPending = false;
8439
8440 /*
8441 * If we eventually support nested-guest execution without unrestricted guest execution,
8442 * we should set fInterceptEvents here.
8443 */
8444 Assert(!pVmxTransient->fIsNestedGuest);
8445
8446 /* If we're stepping and we've changed cs:rip above, bail out of the VMX R0 execution loop. */
8447 if (fStepping)
8448 rcStrict = VINF_EM_DBG_STEPPED;
8449 }
8450 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8451 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8452 return rcStrict;
8453 }
8454 }
8455
8456 /*
8457 * Validate.
8458 */
8459 Assert(VMX_ENTRY_INT_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
8460 Assert(!(u32IntInfo & VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK)); /* Bits 30:12 MBZ. */
8461
8462 /*
8463 * Inject the event into the VMCS.
8464 */
8465 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8466 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8467 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8468 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8469 AssertRC(rc);
8470
8471 /*
8472 * Update guest CR2 if this is a page-fault.
8473 */
8474 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
8475 pCtx->cr2 = GCPtrFault;
8476
8477 Log4(("Injecting u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x CR2=%#RX64\n", u32IntInfo, u32ErrCode, cbInstr, pCtx->cr2));
8478 return VINF_SUCCESS;
8479}
8480
8481
8482/**
8483 * Evaluates the event to be delivered to the guest and sets it as the pending
8484 * event.
8485 *
8486 * @returns Strict VBox status code (i.e. informational status codes too).
8487 * @param pVCpu The cross context virtual CPU structure.
8488 * @param pVmxTransient The VMX-transient structure.
8489 * @param pfIntrState Where to store the VT-x guest-interruptibility state.
8490 */
8491static VBOXSTRICTRC hmR0VmxEvaluatePendingEvent(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t *pfIntrState)
8492{
8493 Assert(pfIntrState);
8494 Assert(!TRPMHasTrap(pVCpu));
8495
8496 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8497 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8498 bool const fIsNestedGuest = pVmxTransient->fIsNestedGuest;
8499
8500 /*
8501 * Get the current interruptibility-state of the guest or nested-guest and
8502 * then figure out what needs to be injected.
8503 */
8504 uint32_t const fIntrState = hmR0VmxGetGuestIntrState(pVCpu, pVmxTransient);
8505 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
8506 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
8507 bool const fBlockNmi = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
8508
8509 /* We don't support block-by-SMI yet.*/
8510 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI));
8511
8512 /* Block-by-STI must not be set when interrupts are disabled. */
8513 if (fBlockSti)
8514 {
8515 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
8516 Assert(pCtx->eflags.Bits.u1IF);
8517 }
8518
8519 /* Update interruptibility state to the caller. */
8520 *pfIntrState = fIntrState;
8521
8522 /*
8523 * Toggling of interrupt force-flags here is safe since we update TRPM on
8524 * premature exits to ring-3 before executing guest code, see hmR0VmxExitToRing3().
8525 * We must NOT restore these force-flags.
8526 */
8527
8528 /** @todo SMI. SMIs take priority over NMIs. */
8529
8530 /*
8531 * Check if an NMI is pending and if the guest or nested-guest can receive them.
8532 * NMIs take priority over external interrupts.
8533 */
8534 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
8535 {
8536 /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
8537 if ( !pVCpu->hm.s.Event.fPending
8538 && !fBlockNmi
8539 && !fBlockSti
8540 && !fBlockMovSS)
8541 {
8542#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8543 if ( fIsNestedGuest
8544 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_NMI_EXIT))
8545 return IEMExecVmxVmexitXcptNmi(pVCpu);
8546#endif
8547 hmR0VmxSetPendingXcptNmi(pVCpu);
8548 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
8549 Log4Func(("Pending NMI\n"));
8550 }
8551 else if (!fIsNestedGuest)
8552 hmR0VmxSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
8553 /* else: for nested-guests, NMI-window exiting will be picked up when merging VMCS controls. */
8554 }
8555 /*
8556 * Check if an external interrupt (PIC/APIC) is pending and if the guest or nested-guest
8557 * can receive them. Once PDMGetInterrupt() returns a valid interrupt we -must- deliver
8558 * the interrupt. We can no longer re-request it from the APIC.
8559 */
8560 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
8561 && !pVCpu->hm.s.fSingleInstruction)
8562 {
8563 Assert(!DBGFIsStepping(pVCpu));
8564 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
8565 AssertRCReturn(rc, rc);
8566
8567 bool const fBlockInt = !(pCtx->eflags.u32 & X86_EFL_IF);
8568 if ( !pVCpu->hm.s.Event.fPending
8569 && !fBlockInt
8570 && !fBlockSti
8571 && !fBlockMovSS)
8572 {
8573#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8574 if ( fIsNestedGuest
8575 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
8576 && !CPUMIsGuestVmxExitCtlsSet(pVCpu, pCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
8577 {
8578 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
8579 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8580 return rcStrict;
8581 }
8582#endif
8583 uint8_t u8Interrupt;
8584 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
8585 if (RT_SUCCESS(rc))
8586 {
8587#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8588 if ( fIsNestedGuest
8589 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
8590 && CPUMIsGuestVmxExitCtlsSet(pVCpu, pCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
8591 {
8592 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, u8Interrupt, false /* fIntPending */);
8593 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8594 return rcStrict;
8595 }
8596#endif
8597 hmR0VmxSetPendingExtInt(pVCpu, u8Interrupt);
8598 Log4Func(("Pending external interrupt vector %#x\n", u8Interrupt));
8599 }
8600 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
8601 {
8602 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
8603
8604 if ( !fIsNestedGuest
8605 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
8606 hmR0VmxApicSetTprThreshold(pVmcsInfo, u8Interrupt >> 4);
8607 /* else: for nested-guests, TPR threshold is picked up while merging VMCS controls. */
8608
8609 /*
8610 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
8611 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
8612 * need to re-set this force-flag here.
8613 */
8614 }
8615 else
8616 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
8617 }
8618 else if (!fIsNestedGuest)
8619 hmR0VmxSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
8620 /* else: for nested-guests, interrupt-window exiting will be picked up when merging VMCS controls. */
8621 }
8622
8623 return VINF_SUCCESS;
8624}
8625
8626
8627/**
8628 * Injects any pending events into the guest if the guest is in a state to
8629 * receive them.
8630 *
8631 * @returns Strict VBox status code (i.e. informational status codes too).
8632 * @param pVCpu The cross context virtual CPU structure.
8633 * @param pVmxTransient The VMX-transient structure.
8634 * @param fIntrState The VT-x guest-interruptibility state.
8635 * @param fStepping Whether we are single-stepping the guest using the
8636 * hypervisor debugger and should return
8637 * VINF_EM_DBG_STEPPED if the event was dispatched
8638 * directly.
8639 */
8640static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t fIntrState, bool fStepping)
8641{
8642 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8643 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8644
8645 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
8646 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
8647
8648 Assert(!fBlockSti || !(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_RFLAGS));
8649 Assert(!fBlockSti || pVCpu->cpum.GstCtx.eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
8650 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
8651 Assert(!TRPMHasTrap(pVCpu));
8652
8653 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
8654 if (pVCpu->hm.s.Event.fPending)
8655 {
8656 /*
8657 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
8658 * pending even while injecting an event and in this case, we want a VM-exit as soon as
8659 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
8660 *
8661 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
8662 */
8663 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
8664#ifdef VBOX_STRICT
8665 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
8666 {
8667 bool const fBlockInt = !(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_IF);
8668 Assert(!fBlockInt);
8669 Assert(!fBlockSti);
8670 Assert(!fBlockMovSS);
8671 }
8672 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_NMI)
8673 {
8674 bool const fBlockNmi = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
8675 Assert(!fBlockSti);
8676 Assert(!fBlockMovSS);
8677 Assert(!fBlockNmi);
8678 }
8679#endif
8680 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
8681 uIntType));
8682
8683 /*
8684 * Inject the event and get any changes to the guest-interruptibility state.
8685 *
8686 * The guest-interruptibility state may need to be updated if we inject the event
8687 * into the guest IDT ourselves (for real-on-v86 guest injecting software interrupts).
8688 */
8689 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &pVCpu->hm.s.Event, fStepping, &fIntrState);
8690 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
8691
8692 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
8693 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
8694 else
8695 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
8696 }
8697
8698 /*
8699 * Update the guest-interruptibility state.
8700 *
8701 * This is required for the real-on-v86 software interrupt injection case above, as well as
8702 * updates to the guest state from ring-3 or IEM/REM.
8703 */
8704 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
8705 AssertRC(rc);
8706
8707 /*
8708 * There's no need to clear the VM-entry interruption-information field here if we're not
8709 * injecting anything. VT-x clears the valid bit on every VM-exit.
8710 *
8711 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
8712 */
8713
8714 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
8715 NOREF(fBlockMovSS); NOREF(fBlockSti);
8716 return rcStrict;
8717}
8718
8719
8720/**
8721 * Enters the VT-x session.
8722 *
8723 * @returns VBox status code.
8724 * @param pVCpu The cross context virtual CPU structure.
8725 */
8726VMMR0DECL(int) VMXR0Enter(PVMCPU pVCpu)
8727{
8728 AssertPtr(pVCpu);
8729 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported);
8730 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8731
8732 LogFlowFunc(("pVCpu=%p\n", pVCpu));
8733 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
8734 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
8735
8736#ifdef VBOX_STRICT
8737 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
8738 RTCCUINTREG uHostCr4 = ASMGetCR4();
8739 if (!(uHostCr4 & X86_CR4_VMXE))
8740 {
8741 LogRelFunc(("X86_CR4_VMXE bit in CR4 is not set!\n"));
8742 return VERR_VMX_X86_CR4_VMXE_CLEARED;
8743 }
8744#endif
8745
8746 /*
8747 * Load the appropriate VMCS as the current and active one.
8748 */
8749 PVMXVMCSINFO pVmcsInfo;
8750 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx);
8751 if (!fInNestedGuestMode)
8752 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfo;
8753 else
8754 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
8755 int rc = hmR0VmxLoadVmcs(pVmcsInfo);
8756 if (RT_SUCCESS(rc))
8757 {
8758 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs = fInNestedGuestMode;
8759 pVCpu->hm.s.fLeaveDone = false;
8760 Log4Func(("Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8761
8762 /*
8763 * Do the EMT scheduled L1D flush here if needed.
8764 */
8765 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
8766 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
8767 else if (pVCpu->CTX_SUFF(pVM)->hm.s.fMdsClearOnSched)
8768 hmR0MdsClear();
8769 }
8770 return rc;
8771}
8772
8773
8774/**
8775 * The thread-context callback (only on platforms which support it).
8776 *
8777 * @param enmEvent The thread-context event.
8778 * @param pVCpu The cross context virtual CPU structure.
8779 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
8780 * @thread EMT(pVCpu)
8781 */
8782VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPU pVCpu, bool fGlobalInit)
8783{
8784 AssertPtr(pVCpu);
8785 RT_NOREF1(fGlobalInit);
8786
8787 switch (enmEvent)
8788 {
8789 case RTTHREADCTXEVENT_OUT:
8790 {
8791 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8792 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8793 VMCPU_ASSERT_EMT(pVCpu);
8794
8795 /* No longjmps (logger flushes, locks) in this fragile context. */
8796 VMMRZCallRing3Disable(pVCpu);
8797 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
8798
8799 /* Restore host-state (FPU, debug etc.) */
8800 if (!pVCpu->hm.s.fLeaveDone)
8801 {
8802 /*
8803 * Do -not- import the guest-state here as we might already be in the middle of importing
8804 * it, esp. bad if we're holding the PGM lock, see comment in hmR0VmxImportGuestState().
8805 */
8806 hmR0VmxLeave(pVCpu, false /* fImportState */);
8807 pVCpu->hm.s.fLeaveDone = true;
8808 }
8809
8810 /* Leave HM context, takes care of local init (term). */
8811 int rc = HMR0LeaveCpu(pVCpu);
8812 AssertRC(rc);
8813
8814 /* Restore longjmp state. */
8815 VMMRZCallRing3Enable(pVCpu);
8816 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
8817 break;
8818 }
8819
8820 case RTTHREADCTXEVENT_IN:
8821 {
8822 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8823 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8824 VMCPU_ASSERT_EMT(pVCpu);
8825
8826 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
8827 VMMRZCallRing3Disable(pVCpu);
8828 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
8829
8830 /* Initialize the bare minimum state required for HM. This takes care of
8831 initializing VT-x if necessary (onlined CPUs, local init etc.) */
8832 int rc = hmR0EnterCpu(pVCpu);
8833 AssertRC(rc);
8834 Assert( (pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
8835 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
8836
8837 /* Load the active VMCS as the current one. */
8838 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8839 rc = hmR0VmxLoadVmcs(pVmcsInfo);
8840 AssertRC(rc);
8841 Log4Func(("Resumed: Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8842 pVCpu->hm.s.fLeaveDone = false;
8843
8844 /* Do the EMT scheduled L1D flush if needed. */
8845 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
8846 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
8847
8848 /* Restore longjmp state. */
8849 VMMRZCallRing3Enable(pVCpu);
8850 break;
8851 }
8852
8853 default:
8854 break;
8855 }
8856}
8857
8858
8859/**
8860 * Exports the host state into the VMCS host-state area.
8861 * Sets up the VM-exit MSR-load area.
8862 *
8863 * The CPU state will be loaded from these fields on every successful VM-exit.
8864 *
8865 * @returns VBox status code.
8866 * @param pVCpu The cross context virtual CPU structure.
8867 *
8868 * @remarks No-long-jump zone!!!
8869 */
8870static int hmR0VmxExportHostState(PVMCPU pVCpu)
8871{
8872 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8873
8874 int rc = VINF_SUCCESS;
8875 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
8876 {
8877 hmR0VmxExportHostControlRegs();
8878
8879 rc = hmR0VmxExportHostSegmentRegs(pVCpu);
8880 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8881
8882 hmR0VmxExportHostMsrs(pVCpu);
8883
8884 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_HOST_CONTEXT;
8885 }
8886 return rc;
8887}
8888
8889
8890/**
8891 * Saves the host state in the VMCS host-state.
8892 *
8893 * @returns VBox status code.
8894 * @param pVCpu The cross context virtual CPU structure.
8895 *
8896 * @remarks No-long-jump zone!!!
8897 */
8898VMMR0DECL(int) VMXR0ExportHostState(PVMCPU pVCpu)
8899{
8900 AssertPtr(pVCpu);
8901 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8902
8903 /*
8904 * Export the host state here while entering HM context.
8905 * When thread-context hooks are used, we might get preempted and have to re-save the host
8906 * state but most of the time we won't be, so do it here before we disable interrupts.
8907 */
8908 return hmR0VmxExportHostState(pVCpu);
8909}
8910
8911
8912/**
8913 * Exports the guest state into the VMCS guest-state area.
8914 *
8915 * The will typically be done before VM-entry when the guest-CPU state and the
8916 * VMCS state may potentially be out of sync.
8917 *
8918 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
8919 * VM-entry controls.
8920 * Sets up the appropriate VMX non-root function to execute guest code based on
8921 * the guest CPU mode.
8922 *
8923 * @returns VBox strict status code.
8924 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8925 * without unrestricted guest execution and the VMMDev is not presently
8926 * mapped (e.g. EFI32).
8927 *
8928 * @param pVCpu The cross context virtual CPU structure.
8929 * @param pVmxTransient The VMX-transient structure.
8930 *
8931 * @remarks No-long-jump zone!!!
8932 */
8933static VBOXSTRICTRC hmR0VmxExportGuestState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
8934{
8935 AssertPtr(pVCpu);
8936 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8937 LogFlowFunc(("pVCpu=%p\n", pVCpu));
8938
8939 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExportGuestState, x);
8940
8941 /*
8942 * Determine real-on-v86 mode.
8943 * Used when the guest is in real-mode and unrestricted guest execution is not used.
8944 */
8945 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8946 if ( pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest
8947 || !CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx))
8948 pVmcsInfo->RealMode. fRealOnV86Active = false;
8949 else
8950 {
8951 Assert(!pVmxTransient->fIsNestedGuest);
8952 pVmcsInfo->RealMode.fRealOnV86Active = true;
8953 }
8954
8955 /*
8956 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
8957 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
8958 */
8959 /** @todo r=ramshankar: Move hmR0VmxSelectVMRunHandler inside
8960 * hmR0VmxExportGuestEntryExitCtls and do it conditionally. There shouldn't
8961 * be a need to evaluate this everytime since I'm pretty sure we intercept
8962 * all guest paging mode changes. */
8963 int rc = hmR0VmxSelectVMRunHandler(pVCpu, pVmxTransient);
8964 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8965
8966 rc = hmR0VmxExportGuestEntryExitCtls(pVCpu, pVmxTransient);
8967 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8968
8969 rc = hmR0VmxExportGuestCR0(pVCpu, pVmxTransient);
8970 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8971
8972 VBOXSTRICTRC rcStrict = hmR0VmxExportGuestCR3AndCR4(pVCpu, pVmxTransient);
8973 if (rcStrict == VINF_SUCCESS)
8974 { /* likely */ }
8975 else
8976 {
8977 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
8978 return rcStrict;
8979 }
8980
8981 rc = hmR0VmxExportGuestSegRegsXdtr(pVCpu, pVmxTransient);
8982 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8983
8984 rc = hmR0VmxExportGuestMsrs(pVCpu, pVmxTransient);
8985 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8986
8987 rc = hmR0VmxExportGuestApicTpr(pVCpu, pVmxTransient);
8988 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8989
8990 rc = hmR0VmxExportGuestXcptIntercepts(pVCpu, pVmxTransient);
8991 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8992
8993 rc = hmR0VmxExportGuestRip(pVCpu);
8994 rc |= hmR0VmxExportGuestRsp(pVCpu);
8995 rc |= hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
8996 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8997
8998 rc = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
8999 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9000
9001 /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
9002 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~( (HM_CHANGED_GUEST_GPRS_MASK & ~HM_CHANGED_GUEST_RSP)
9003 | HM_CHANGED_GUEST_CR2
9004 | (HM_CHANGED_GUEST_DR_MASK & ~HM_CHANGED_GUEST_DR7)
9005 | HM_CHANGED_GUEST_X87
9006 | HM_CHANGED_GUEST_SSE_AVX
9007 | HM_CHANGED_GUEST_OTHER_XSAVE
9008 | HM_CHANGED_GUEST_XCRx
9009 | HM_CHANGED_GUEST_KERNEL_GS_BASE /* Part of lazy or auto load-store MSRs. */
9010 | HM_CHANGED_GUEST_SYSCALL_MSRS /* Part of lazy or auto load-store MSRs. */
9011 | HM_CHANGED_GUEST_TSC_AUX
9012 | HM_CHANGED_GUEST_OTHER_MSRS
9013 | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
9014
9015 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExportGuestState, x);
9016 return rc;
9017}
9018
9019
9020/**
9021 * Exports the state shared between the host and guest into the VMCS.
9022 *
9023 * @param pVCpu The cross context virtual CPU structure.
9024 * @param pVmxTransient The VMX-transient structure.
9025 *
9026 * @remarks No-long-jump zone!!!
9027 */
9028static void hmR0VmxExportSharedState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
9029{
9030 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9031 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9032
9033 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_DR_MASK)
9034 {
9035 int rc = hmR0VmxExportSharedDebugState(pVCpu, pVmxTransient);
9036 AssertRC(rc);
9037 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_GUEST_DR_MASK;
9038
9039 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
9040 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_RFLAGS)
9041 {
9042 rc = hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9043 AssertRC(rc);
9044 }
9045 }
9046
9047 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_GUEST_LAZY_MSRS)
9048 {
9049 hmR0VmxLazyLoadGuestMsrs(pVCpu);
9050 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_VMX_GUEST_LAZY_MSRS;
9051 }
9052
9053 AssertMsg(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE),
9054 ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
9055}
9056
9057
9058/**
9059 * Worker for loading the guest-state bits in the inner VT-x execution loop.
9060 *
9061 * @returns Strict VBox status code (i.e. informational status codes too).
9062 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9063 * without unrestricted guest execution and the VMMDev is not presently
9064 * mapped (e.g. EFI32).
9065 *
9066 * @param pVCpu The cross context virtual CPU structure.
9067 * @param pVmxTransient The VMX-transient structure.
9068 *
9069 * @remarks No-long-jump zone!!!
9070 */
9071static VBOXSTRICTRC hmR0VmxExportGuestStateOptimal(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
9072{
9073 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9074 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9075 Assert(VMMR0IsLogFlushDisabled(pVCpu));
9076
9077#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
9078 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
9079#endif
9080
9081 /*
9082 * For many exits it's only RIP that changes and hence try to export it first
9083 * without going through a lot of change flag checks.
9084 */
9085 VBOXSTRICTRC rcStrict;
9086 uint64_t fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9087 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
9088 if ((fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)) == HM_CHANGED_GUEST_RIP)
9089 {
9090 rcStrict = hmR0VmxExportGuestRip(pVCpu);
9091 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9092 { /* likely */}
9093 else
9094 AssertMsgFailedReturn(("Failed to export guest RIP! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)), rcStrict);
9095 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportMinimal);
9096 }
9097 else if (fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9098 {
9099 rcStrict = hmR0VmxExportGuestState(pVCpu, pVmxTransient);
9100 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9101 { /* likely */}
9102 else
9103 {
9104 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM, ("Failed to export guest state! rc=%Rrc\n",
9105 VBOXSTRICTRC_VAL(rcStrict)));
9106 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9107 return rcStrict;
9108 }
9109 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportFull);
9110 }
9111 else
9112 rcStrict = VINF_SUCCESS;
9113
9114#ifdef VBOX_STRICT
9115 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
9116 fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9117 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
9118 AssertMsg(!(fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)),
9119 ("fCtxChanged=%#RX64\n", fCtxChanged));
9120#endif
9121 return rcStrict;
9122}
9123
9124
9125/**
9126 * Tries to determine what part of the guest-state VT-x has deemed as invalid
9127 * and update error record fields accordingly.
9128 *
9129 * @returns VMX_IGS_* error codes.
9130 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
9131 * wrong with the guest state.
9132 *
9133 * @param pVCpu The cross context virtual CPU structure.
9134 * @param pVmcsInfo The VMCS info. object.
9135 *
9136 * @remarks This function assumes our cache of the VMCS controls
9137 * are valid, i.e. hmR0VmxCheckVmcsCtls() succeeded.
9138 */
9139static uint32_t hmR0VmxCheckGuestState(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
9140{
9141#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
9142#define HMVMX_CHECK_BREAK(expr, err) do { \
9143 if (!(expr)) { uError = (err); break; } \
9144 } while (0)
9145
9146 int rc;
9147 PVM pVM = pVCpu->CTX_SUFF(pVM);
9148 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9149 uint32_t uError = VMX_IGS_ERROR;
9150 uint32_t u32Val;
9151 bool const fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuest;
9152
9153 do
9154 {
9155 /*
9156 * CR0.
9157 */
9158 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9159 uint64_t fSetCr0 = (pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
9160 uint64_t const fZapCr0 = (pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
9161 /* Exceptions for unrestricted guest execution for fixed CR0 bits (PE, PG).
9162 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
9163 if (fUnrestrictedGuest)
9164 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
9165
9166 uint64_t u64GuestCr0;
9167 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64GuestCr0);
9168 AssertRC(rc);
9169 HMVMX_CHECK_BREAK((u64GuestCr0 & fSetCr0) == fSetCr0, VMX_IGS_CR0_FIXED1);
9170 HMVMX_CHECK_BREAK(!(u64GuestCr0 & ~fZapCr0), VMX_IGS_CR0_FIXED0);
9171 if ( !fUnrestrictedGuest
9172 && (u64GuestCr0 & X86_CR0_PG)
9173 && !(u64GuestCr0 & X86_CR0_PE))
9174 {
9175 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
9176 }
9177
9178 /*
9179 * CR4.
9180 */
9181 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9182 uint64_t const fSetCr4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
9183 uint64_t const fZapCr4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
9184
9185 uint64_t u64GuestCr4;
9186 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64GuestCr4);
9187 AssertRC(rc);
9188 HMVMX_CHECK_BREAK((u64GuestCr4 & fSetCr4) == fSetCr4, VMX_IGS_CR4_FIXED1);
9189 HMVMX_CHECK_BREAK(!(u64GuestCr4 & ~fZapCr4), VMX_IGS_CR4_FIXED0);
9190
9191 /*
9192 * IA32_DEBUGCTL MSR.
9193 */
9194 uint64_t u64Val;
9195 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
9196 AssertRC(rc);
9197 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9198 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
9199 {
9200 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
9201 }
9202 uint64_t u64DebugCtlMsr = u64Val;
9203
9204#ifdef VBOX_STRICT
9205 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
9206 AssertRC(rc);
9207 Assert(u32Val == pVmcsInfo->u32EntryCtls);
9208#endif
9209 bool const fLongModeGuest = RT_BOOL(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
9210
9211 /*
9212 * RIP and RFLAGS.
9213 */
9214 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
9215 AssertRC(rc);
9216 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
9217 if ( !fLongModeGuest
9218 || !pCtx->cs.Attr.n.u1Long)
9219 {
9220 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
9221 }
9222 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
9223 * must be identical if the "IA-32e mode guest" VM-entry
9224 * control is 1 and CS.L is 1. No check applies if the
9225 * CPU supports 64 linear-address bits. */
9226
9227 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
9228 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
9229 AssertRC(rc);
9230 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
9231 VMX_IGS_RFLAGS_RESERVED);
9232 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
9233 uint32_t const u32Eflags = u64Val;
9234
9235 if ( fLongModeGuest
9236 || ( fUnrestrictedGuest
9237 && !(u64GuestCr0 & X86_CR0_PE)))
9238 {
9239 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
9240 }
9241
9242 uint32_t u32EntryInfo;
9243 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
9244 AssertRC(rc);
9245 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9246 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
9247
9248 /*
9249 * 64-bit checks.
9250 */
9251 if (fLongModeGuest)
9252 {
9253 HMVMX_CHECK_BREAK(u64GuestCr0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
9254 HMVMX_CHECK_BREAK(u64GuestCr4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
9255 }
9256
9257 if ( !fLongModeGuest
9258 && (u64GuestCr4 & X86_CR4_PCIDE))
9259 {
9260 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
9261 }
9262
9263 /** @todo CR3 field must be such that bits 63:52 and bits in the range
9264 * 51:32 beyond the processor's physical-address width are 0. */
9265
9266 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9267 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
9268 {
9269 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
9270 }
9271
9272 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
9273 AssertRC(rc);
9274 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
9275
9276 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
9277 AssertRC(rc);
9278 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
9279
9280 /*
9281 * PERF_GLOBAL MSR.
9282 */
9283 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR)
9284 {
9285 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
9286 AssertRC(rc);
9287 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
9288 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
9289 }
9290
9291 /*
9292 * PAT MSR.
9293 */
9294 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
9295 {
9296 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
9297 AssertRC(rc);
9298 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
9299 for (unsigned i = 0; i < 8; i++)
9300 {
9301 uint8_t u8Val = (u64Val & 0xff);
9302 if ( u8Val != 0 /* UC */
9303 && u8Val != 1 /* WC */
9304 && u8Val != 4 /* WT */
9305 && u8Val != 5 /* WP */
9306 && u8Val != 6 /* WB */
9307 && u8Val != 7 /* UC- */)
9308 {
9309 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
9310 }
9311 u64Val >>= 8;
9312 }
9313 }
9314
9315 /*
9316 * EFER MSR.
9317 */
9318 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
9319 {
9320 Assert(pVM->hm.s.vmx.fSupportsVmcsEfer);
9321 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
9322 AssertRC(rc);
9323 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
9324 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
9325 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVmcsInfo->u32EntryCtls
9326 & VMX_ENTRY_CTLS_IA32E_MODE_GUEST),
9327 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
9328 /** @todo r=ramshankar: Unrestricted check here is probably wrong, see
9329 * iemVmxVmentryCheckGuestState(). */
9330 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9331 || !(u64GuestCr0 & X86_CR0_PG)
9332 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
9333 VMX_IGS_EFER_LMA_LME_MISMATCH);
9334 }
9335
9336 /*
9337 * Segment registers.
9338 */
9339 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9340 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
9341 if (!(u32Eflags & X86_EFL_VM))
9342 {
9343 /* CS */
9344 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
9345 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
9346 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
9347 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
9348 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9349 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
9350 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9351 /* CS cannot be loaded with NULL in protected mode. */
9352 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
9353 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
9354 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
9355 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
9356 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
9357 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
9358 else if (pVM->hm.s.vmx.fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
9359 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
9360 else
9361 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
9362
9363 /* SS */
9364 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9365 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
9366 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
9367 if ( !(pCtx->cr0 & X86_CR0_PE)
9368 || pCtx->cs.Attr.n.u4Type == 3)
9369 {
9370 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
9371 }
9372 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
9373 {
9374 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
9375 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
9376 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
9377 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
9378 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
9379 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9380 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
9381 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9382 }
9383
9384 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSReg(). */
9385 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
9386 {
9387 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
9388 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
9389 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9390 || pCtx->ds.Attr.n.u4Type > 11
9391 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9392 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
9393 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
9394 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
9395 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9396 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
9397 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9398 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9399 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
9400 }
9401 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
9402 {
9403 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
9404 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
9405 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9406 || pCtx->es.Attr.n.u4Type > 11
9407 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9408 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
9409 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
9410 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
9411 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9412 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
9413 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9414 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9415 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
9416 }
9417 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
9418 {
9419 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
9420 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
9421 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9422 || pCtx->fs.Attr.n.u4Type > 11
9423 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
9424 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
9425 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
9426 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
9427 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9428 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
9429 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9430 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9431 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
9432 }
9433 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
9434 {
9435 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
9436 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
9437 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9438 || pCtx->gs.Attr.n.u4Type > 11
9439 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
9440 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
9441 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
9442 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
9443 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9444 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
9445 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9446 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9447 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
9448 }
9449 /* 64-bit capable CPUs. */
9450 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9451 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9452 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9453 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9454 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9455 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9456 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9457 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9458 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9459 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9460 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9461 }
9462 else
9463 {
9464 /* V86 mode checks. */
9465 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
9466 if (pVmcsInfo->RealMode.fRealOnV86Active)
9467 {
9468 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
9469 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
9470 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
9471 }
9472 else
9473 {
9474 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
9475 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
9476 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
9477 }
9478
9479 /* CS */
9480 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
9481 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
9482 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
9483 /* SS */
9484 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
9485 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
9486 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
9487 /* DS */
9488 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
9489 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
9490 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
9491 /* ES */
9492 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
9493 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
9494 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
9495 /* FS */
9496 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
9497 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
9498 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
9499 /* GS */
9500 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
9501 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
9502 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
9503 /* 64-bit capable CPUs. */
9504 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9505 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9506 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9507 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9508 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9509 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9510 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9511 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9512 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9513 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9514 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9515 }
9516
9517 /*
9518 * TR.
9519 */
9520 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
9521 /* 64-bit capable CPUs. */
9522 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
9523 if (fLongModeGuest)
9524 {
9525 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
9526 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
9527 }
9528 else
9529 {
9530 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
9531 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
9532 VMX_IGS_TR_ATTR_TYPE_INVALID);
9533 }
9534 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
9535 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
9536 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
9537 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
9538 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
9539 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
9540 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
9541 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
9542
9543 /*
9544 * GDTR and IDTR (64-bit capable checks).
9545 */
9546 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
9547 AssertRC(rc);
9548 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
9549
9550 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
9551 AssertRC(rc);
9552 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
9553
9554 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
9555 AssertRC(rc);
9556 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
9557
9558 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
9559 AssertRC(rc);
9560 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
9561
9562 /*
9563 * Guest Non-Register State.
9564 */
9565 /* Activity State. */
9566 uint32_t u32ActivityState;
9567 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
9568 AssertRC(rc);
9569 HMVMX_CHECK_BREAK( !u32ActivityState
9570 || (u32ActivityState & RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Misc, VMX_BF_MISC_ACTIVITY_STATES)),
9571 VMX_IGS_ACTIVITY_STATE_INVALID);
9572 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
9573 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
9574 uint32_t u32IntrState;
9575 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32IntrState);
9576 AssertRC(rc);
9577 if ( u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS
9578 || u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9579 {
9580 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
9581 }
9582
9583 /** @todo Activity state and injecting interrupts. Left as a todo since we
9584 * currently don't use activity states but ACTIVE. */
9585
9586 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
9587 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
9588
9589 /* Guest interruptibility-state. */
9590 HMVMX_CHECK_BREAK(!(u32IntrState & 0xffffffe0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
9591 HMVMX_CHECK_BREAK((u32IntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
9592 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9593 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
9594 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
9595 || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
9596 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
9597 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9598 {
9599 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9600 && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9601 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
9602 }
9603 else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
9604 {
9605 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9606 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
9607 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
9608 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
9609 }
9610 /** @todo Assumes the processor is not in SMM. */
9611 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
9612 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
9613 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
9614 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
9615 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
9616 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
9617 && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
9618 {
9619 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI),
9620 VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
9621 }
9622
9623 /* Pending debug exceptions. */
9624 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &u64Val);
9625 AssertRC(rc);
9626 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
9627 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
9628 u32Val = u64Val; /* For pending debug exceptions checks below. */
9629
9630 if ( (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9631 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
9632 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
9633 {
9634 if ( (u32Eflags & X86_EFL_TF)
9635 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
9636 {
9637 /* Bit 14 is PendingDebug.BS. */
9638 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
9639 }
9640 if ( !(u32Eflags & X86_EFL_TF)
9641 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
9642 {
9643 /* Bit 14 is PendingDebug.BS. */
9644 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
9645 }
9646 }
9647
9648 /* VMCS link pointer. */
9649 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
9650 AssertRC(rc);
9651 if (u64Val != UINT64_C(0xffffffffffffffff))
9652 {
9653 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
9654 /** @todo Bits beyond the processor's physical-address width MBZ. */
9655 /** @todo SMM checks. */
9656 Assert(pVmcsInfo->HCPhysShadowVmcs == u64Val);
9657 Assert(pVmcsInfo->pvShadowVmcs);
9658 VMXVMCSREVID VmcsRevId;
9659 VmcsRevId.u = *(uint32_t *)pVmcsInfo->pvShadowVmcs;
9660 HMVMX_CHECK_BREAK(VmcsRevId.n.u31RevisionId == RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID),
9661 VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID);
9662 HMVMX_CHECK_BREAK(VmcsRevId.n.fIsShadowVmcs == (uint32_t)!!(pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING),
9663 VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW);
9664 }
9665
9666 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
9667 * not using nested paging? */
9668 if ( pVM->hm.s.fNestedPaging
9669 && !fLongModeGuest
9670 && CPUMIsGuestInPAEModeEx(pCtx))
9671 {
9672 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
9673 AssertRC(rc);
9674 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9675
9676 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
9677 AssertRC(rc);
9678 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9679
9680 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
9681 AssertRC(rc);
9682 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9683
9684 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
9685 AssertRC(rc);
9686 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9687 }
9688
9689 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
9690 if (uError == VMX_IGS_ERROR)
9691 uError = VMX_IGS_REASON_NOT_FOUND;
9692 } while (0);
9693
9694 pVCpu->hm.s.u32HMError = uError;
9695 return uError;
9696
9697#undef HMVMX_ERROR_BREAK
9698#undef HMVMX_CHECK_BREAK
9699}
9700
9701
9702/**
9703 * Map the APIC-access page for virtualizing APIC accesses.
9704 *
9705 * This can cause a longjumps to R3 due to the acquisition of the PGM lock. Hence,
9706 * this not done as part of exporting guest state, see @bugref{8721}.
9707 *
9708 * @returns VBox status code.
9709 * @param pVCpu The cross context virtual CPU structure.
9710 */
9711static int hmR0VmxMapHCApicAccessPage(PVMCPU pVCpu)
9712{
9713 PVM pVM = pVCpu->CTX_SUFF(pVM);
9714 uint64_t const u64MsrApicBase = APICGetBaseMsrNoCheck(pVCpu);
9715
9716 Assert(PDMHasApic(pVM));
9717 Assert(u64MsrApicBase);
9718
9719 RTGCPHYS const GCPhysApicBase = u64MsrApicBase & PAGE_BASE_GC_MASK;
9720 Log4Func(("Mappping HC APIC-access page at %#RGp\n", GCPhysApicBase));
9721
9722 /* Unalias the existing mapping. */
9723 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
9724 AssertRCReturn(rc, rc);
9725
9726 /* Map the HC APIC-access page in place of the MMIO page, also updates the shadow page tables if necessary. */
9727 Assert(pVM->hm.s.vmx.HCPhysApicAccess != NIL_RTHCPHYS);
9728 rc = IOMMMIOMapMMIOHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hm.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
9729 AssertRCReturn(rc, rc);
9730
9731 /* Update the per-VCPU cache of the APIC base MSR. */
9732 pVCpu->hm.s.vmx.u64GstMsrApicBase = u64MsrApicBase;
9733 return VINF_SUCCESS;
9734}
9735
9736
9737/**
9738 * Worker function passed to RTMpOnSpecific() that is to be called on the target
9739 * CPU.
9740 *
9741 * @param idCpu The ID for the CPU the function is called on.
9742 * @param pvUser1 Null, not used.
9743 * @param pvUser2 Null, not used.
9744 */
9745static DECLCALLBACK(void) hmR0DispatchHostNmi(RTCPUID idCpu, void *pvUser1, void *pvUser2)
9746{
9747 RT_NOREF3(idCpu, pvUser1, pvUser2);
9748 VMXDispatchHostNmi();
9749}
9750
9751
9752/**
9753 * Dispatching an NMI on the host CPU that received it.
9754 *
9755 * @returns VBox status code.
9756 * @param pVCpu The cross context virtual CPU structure.
9757 * @param pVmcsInfo The VMCS info. object corresponding to the VMCS that was
9758 * executing when receiving the host NMI in VMX non-root
9759 * operation.
9760 */
9761static int hmR0VmxExitHostNmi(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
9762{
9763 RTCPUID const idCpu = pVmcsInfo->idHostCpu;
9764
9765 /*
9766 * We don't want to delay dispatching the NMI any more than we have to. However,
9767 * we have already chosen -not- to dispatch NMIs when interrupts were still disabled
9768 * after executing guest or nested-guest code for the following reasons:
9769 *
9770 * - We would need to perform VMREADs with interrupts disabled and is orders of
9771 * magnitude worse when we run as a guest hypervisor without VMCS shadowing
9772 * supported by the host hypervisor.
9773 *
9774 * - It affects the common VM-exit scenario and keeps interrupts disabled for a
9775 * longer period of time just for handling an edge case like host NMIs which do
9776 * not occur nearly as frequently as other VM-exits.
9777 *
9778 * Let's cover the most likely scenario first. Check if we are on the target CPU
9779 * and dispatch the NMI right away. This should be much faster than calling into
9780 * RTMpOnSpecific() machinery.
9781 */
9782 bool fDispatched = false;
9783 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
9784 if (idCpu == RTMpCpuId())
9785 {
9786 VMXDispatchHostNmi();
9787 fDispatched = true;
9788 }
9789 ASMSetFlags(fEFlags);
9790 if (fDispatched)
9791 {
9792 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
9793 return VINF_SUCCESS;
9794 }
9795
9796 /*
9797 * RTMpOnSpecific() waits until the worker function has run on the target CPU. So
9798 * there should be no race or recursion even if we are unlucky enough to be preempted
9799 * (to the target CPU) without dispatching the host NMI above.
9800 */
9801 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGCIpi);
9802 return RTMpOnSpecific(idCpu, &hmR0DispatchHostNmi, NULL /* pvUser1 */, NULL /* pvUser2 */);
9803}
9804
9805
9806#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9807/**
9808 * Merges the guest with the nested-guest MSR bitmap in preparation of executing the
9809 * nested-guest using hardware-assisted VMX.
9810 *
9811 * @param pVCpu The cross context virtual CPU structure.
9812 * @param pVmcsInfoNstGst The nested-guest VMCS info. object.
9813 * @param pVmcsInfoGst The guest VMCS info. object.
9814 */
9815static void hmR0VmxMergeMsrBitmapNested(PCVMCPU pVCpu, PVMXVMCSINFO pVmcsInfoNstGst, PCVMXVMCSINFO pVmcsInfoGst)
9816{
9817 uint32_t const cbMsrBitmap = X86_PAGE_4K_SIZE;
9818 uint64_t *pu64MsrBitmap = (uint64_t *)pVmcsInfoNstGst->pvMsrBitmap;
9819 Assert(pu64MsrBitmap);
9820
9821 /*
9822 * We merge the guest MSR bitmap with the nested-guest MSR bitmap such that any
9823 * MSR that is intercepted by the guest is also intercepted while executing the
9824 * nested-guest using hardware-assisted VMX.
9825 *
9826 * Note! If the nested-guest is not using an MSR bitmap, ever MSR must cause a
9827 * nested-guest VM-exit even if the outer guest is not intercepting some
9828 * MSRs. We cannot assume the caller has initialized the nested-guest
9829 * MSR bitmap in this case.
9830 *
9831 * The guest hypervisor may also switch whether it uses MSR bitmaps for
9832 * each VM-entry, hence initializing it once per-VM while setting up the
9833 * nested-guest VMCS is not sufficient.
9834 */
9835 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
9836 if (pVmcsNstGst->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
9837 {
9838 uint64_t const *pu64MsrBitmapNstGst = (uint64_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
9839 uint64_t const *pu64MsrBitmapGst = (uint64_t const *)pVmcsInfoGst->pvMsrBitmap;
9840 Assert(pu64MsrBitmapNstGst);
9841 Assert(pu64MsrBitmapGst);
9842
9843 uint32_t const cFrags = cbMsrBitmap / sizeof(uint64_t);
9844 for (uint32_t i = 0; i < cFrags; i++)
9845 pu64MsrBitmap[i] = pu64MsrBitmapNstGst[i] | pu64MsrBitmapGst[i];
9846 }
9847 else
9848 ASMMemFill32(pu64MsrBitmap, cbMsrBitmap, UINT32_C(0xffffffff));
9849}
9850
9851
9852/**
9853 * Merges the guest VMCS in to the nested-guest VMCS controls in preparation of
9854 * hardware-assisted VMX execution of the nested-guest.
9855 *
9856 * For a guest, we don't modify these controls once we set up the VMCS and hence
9857 * this function is never called.
9858 *
9859 * For nested-guests since the guest hypervisor provides these controls on every
9860 * nested-guest VM-entry and could potentially change them everytime we need to
9861 * merge them before every nested-guest VM-entry.
9862 *
9863 * @returns VBox status code.
9864 * @param pVCpu The cross context virtual CPU structure.
9865 */
9866static int hmR0VmxMergeVmcsNested(PVMCPU pVCpu)
9867{
9868 PVM pVM = pVCpu->CTX_SUFF(pVM);
9869 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hm.s.vmx.VmcsInfo;
9870 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
9871 Assert(pVmcsNstGst);
9872
9873 /*
9874 * Merge the controls with the requirements of the guest VMCS.
9875 *
9876 * We do not need to validate the nested-guest VMX features specified in the nested-guest
9877 * VMCS with the features supported by the physical CPU as it's already done by the
9878 * VMLAUNCH/VMRESUME instruction emulation.
9879 *
9880 * This is because the VMX features exposed by CPUM (through CPUID/MSRs) to the guest are
9881 * derived from the VMX features supported by the physical CPU.
9882 */
9883
9884 /* Pin-based VM-execution controls. */
9885 uint32_t const u32PinCtls = pVmcsNstGst->u32PinCtls | pVmcsInfoGst->u32PinCtls;
9886
9887 /* Processor-based VM-execution controls. */
9888 uint32_t u32ProcCtls = (pVmcsNstGst->u32ProcCtls & ~VMX_PROC_CTLS_USE_IO_BITMAPS)
9889 | (pVmcsInfoGst->u32ProcCtls & ~( VMX_PROC_CTLS_INT_WINDOW_EXIT
9890 | VMX_PROC_CTLS_NMI_WINDOW_EXIT
9891 | VMX_PROC_CTLS_USE_TPR_SHADOW
9892 | VMX_PROC_CTLS_MONITOR_TRAP_FLAG));
9893
9894 /* Secondary processor-based VM-execution controls. */
9895 uint32_t const u32ProcCtls2 = (pVmcsNstGst->u32ProcCtls2 & ~VMX_PROC_CTLS2_VPID)
9896 | (pVmcsInfoGst->u32ProcCtls2 & ~( VMX_PROC_CTLS2_VIRT_APIC_ACCESS
9897 | VMX_PROC_CTLS2_INVPCID
9898 | VMX_PROC_CTLS2_VMCS_SHADOWING
9899 | VMX_PROC_CTLS2_RDTSCP
9900 | VMX_PROC_CTLS2_XSAVES_XRSTORS
9901 | VMX_PROC_CTLS2_APIC_REG_VIRT
9902 | VMX_PROC_CTLS2_VIRT_INT_DELIVERY
9903 | VMX_PROC_CTLS2_VMFUNC));
9904
9905 /*
9906 * VM-entry controls:
9907 * These controls contains state that depends on the nested-guest state (primarily
9908 * EFER MSR) and is thus not constant between VMLAUNCH/VMRESUME and the nested-guest
9909 * VM-exit. Although the guest hypervisor cannot change it, we need to in order to
9910 * properly continue executing the nested-guest if the EFER MSR changes but does not
9911 * cause a nested-guest VM-exits.
9912 *
9913 * VM-exit controls:
9914 * These controls specify the host state on return. We cannot use the controls from
9915 * the guest hypervisor state as is as it would contain the guest state rather than
9916 * the host state. Since the host state is subject to change (e.g. preemption, trips
9917 * to ring-3, longjmp and rescheduling to a different host CPU) they are not constant
9918 * through VMLAUNCH/VMRESUME and the nested-guest VM-exit.
9919 *
9920 * VM-entry MSR-load:
9921 * The guest MSRs from the VM-entry MSR-load area are already loaded into the guest-CPU
9922 * context by the VMLAUNCH/VMRESUME instruction emulation.
9923 *
9924 * VM-exit MSR-store:
9925 * The VM-exit emulation will take care of populating the MSRs from the guest-CPU context
9926 * back into the VM-exit MSR-store area.
9927 *
9928 * VM-exit MSR-load areas:
9929 * This must contain the real host MSRs with hardware-assisted VMX execution. Hence, we
9930 * can entirely ignore what the guest hypervisor wants to load here.
9931 */
9932
9933 /*
9934 * Exception bitmap.
9935 *
9936 * We could remove #UD from the guest bitmap and merge it with the nested-guest bitmap
9937 * here (and avoid doing anything while exporting nested-guest state), but to keep the
9938 * code more flexible if intercepting exceptions become more dynamic in the future we do
9939 * it as part of exporting the nested-guest state.
9940 */
9941 uint32_t const u32XcptBitmap = pVmcsNstGst->u32XcptBitmap | pVmcsInfoGst->u32XcptBitmap;
9942
9943 /*
9944 * CR0/CR4 guest/host mask.
9945 *
9946 * Modifications by the nested-guest to CR0/CR4 bits owned by the host and the guest must
9947 * cause VM-exits, so we need to merge them here.
9948 */
9949 uint64_t const u64Cr0Mask = pVmcsNstGst->u64Cr0Mask.u | pVmcsInfoGst->u64Cr0Mask;
9950 uint64_t const u64Cr4Mask = pVmcsNstGst->u64Cr4Mask.u | pVmcsInfoGst->u64Cr4Mask;
9951
9952 /*
9953 * Page-fault error-code mask and match.
9954 *
9955 * Although we require unrestricted guest execution (and thereby nested-paging) for
9956 * hardware-assisted VMX execution of nested-guests and thus the outer guest doesn't
9957 * normally intercept #PFs, it might intercept them for debugging purposes.
9958 *
9959 * If the outer guest is not intercepting #PFs, we can use the nested-guest #PF filters.
9960 * If the outer guest is intercepting #PFs, we must intercept all #PFs.
9961 */
9962 uint32_t u32XcptPFMask;
9963 uint32_t u32XcptPFMatch;
9964 if (!(pVmcsInfoGst->u32XcptBitmap & RT_BIT(X86_XCPT_PF)))
9965 {
9966 u32XcptPFMask = pVmcsNstGst->u32XcptPFMask;
9967 u32XcptPFMatch = pVmcsNstGst->u32XcptPFMatch;
9968 }
9969 else
9970 {
9971 u32XcptPFMask = 0;
9972 u32XcptPFMatch = 0;
9973 }
9974
9975 /*
9976 * Pause-Loop exiting.
9977 */
9978 uint32_t const cPleGapTicks = RT_MIN(pVM->hm.s.vmx.cPleGapTicks, pVmcsNstGst->u32PleGap);
9979 uint32_t const cPleWindowTicks = RT_MIN(pVM->hm.s.vmx.cPleWindowTicks, pVmcsNstGst->u32PleWindow);
9980
9981 /*
9982 * Pending debug exceptions.
9983 * Currently just copy whatever the nested-guest provides us.
9984 */
9985 uint64_t const uPendingDbgXcpt = pVmcsNstGst->u64GuestPendingDbgXcpt.u;
9986
9987 /*
9988 * I/O Bitmap.
9989 *
9990 * We do not use the I/O bitmap that may be provided by the guest hypervisor as we always
9991 * intercept all I/O port accesses.
9992 */
9993 Assert(u32ProcCtls & VMX_PROC_CTLS_UNCOND_IO_EXIT);
9994
9995 /*
9996 * VMCS shadowing.
9997 *
9998 * We do not yet expose VMCS shadowing to the guest and thus VMCS shadowing should not be
9999 * enabled while executing the nested-guest.
10000 */
10001 Assert(!(u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING));
10002
10003 /*
10004 * APIC-access page.
10005 */
10006 RTHCPHYS HCPhysApicAccess;
10007 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10008 {
10009 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
10010 RTGCPHYS const GCPhysApicAccess = pVmcsNstGst->u64AddrApicAccess.u;
10011
10012 /** @todo NSTVMX: This is not really correct but currently is required to make
10013 * things work. We need to re-enable the page handler when we fallback to
10014 * IEM execution of the nested-guest! */
10015 PGMHandlerPhysicalPageTempOff(pVM, GCPhysApicAccess, GCPhysApicAccess);
10016
10017 void *pvPage;
10018 PGMPAGEMAPLOCK PgLockApicAccess;
10019 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysApicAccess, &pvPage, &PgLockApicAccess);
10020 if (RT_SUCCESS(rc))
10021 {
10022 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysApicAccess, &HCPhysApicAccess);
10023 AssertMsgRCReturn(rc, ("Failed to get host-physical address for APIC-access page at %#RGp\n", GCPhysApicAccess), rc);
10024
10025 /** @todo Handle proper releasing of page-mapping lock later. */
10026 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockApicAccess);
10027 }
10028 else
10029 return rc;
10030 }
10031 else
10032 HCPhysApicAccess = 0;
10033
10034 /*
10035 * Virtual-APIC page and TPR threshold.
10036 */
10037 PVMXVMCSINFO pVmcsInfoNstGst = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
10038 RTHCPHYS HCPhysVirtApic;
10039 uint32_t u32TprThreshold;
10040 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10041 {
10042 Assert(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW);
10043 RTGCPHYS const GCPhysVirtApic = pVmcsNstGst->u64AddrVirtApic.u;
10044
10045 void *pvPage;
10046 PGMPAGEMAPLOCK PgLockVirtApic;
10047 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysVirtApic, &pvPage, &PgLockVirtApic);
10048 if (RT_SUCCESS(rc))
10049 {
10050 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysVirtApic, &HCPhysVirtApic);
10051 AssertMsgRCReturn(rc, ("Failed to get host-physical address for virtual-APIC page at %#RGp\n", GCPhysVirtApic), rc);
10052
10053 /** @todo Handle proper releasing of page-mapping lock later. */
10054 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockVirtApic);
10055 }
10056 else
10057 return rc;
10058
10059 u32TprThreshold = pVmcsNstGst->u32TprThreshold;
10060 }
10061 else
10062 {
10063 HCPhysVirtApic = 0;
10064 u32TprThreshold = 0;
10065
10066 /*
10067 * We must make sure CR8 reads/write must cause VM-exits when TPR shadowing is not
10068 * used by the guest hypervisor. Preventing MMIO accesses to the physical APIC will
10069 * be taken care of by EPT/shadow paging.
10070 */
10071 if (pVM->hm.s.fAllow64BitGuests)
10072 {
10073 u32ProcCtls |= VMX_PROC_CTLS_CR8_STORE_EXIT
10074 | VMX_PROC_CTLS_CR8_LOAD_EXIT;
10075 }
10076 }
10077
10078 /*
10079 * Validate basic assumptions.
10080 */
10081 Assert(pVM->hm.s.vmx.fAllowUnrestricted);
10082 Assert(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
10083 Assert(hmGetVmxActiveVmcsInfo(pVCpu) == pVmcsInfoNstGst);
10084
10085 /*
10086 * Commit it to the nested-guest VMCS.
10087 */
10088 int rc = VINF_SUCCESS;
10089 if (pVmcsInfoNstGst->u32PinCtls != u32PinCtls)
10090 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, u32PinCtls);
10091 if (pVmcsInfoNstGst->u32ProcCtls != u32ProcCtls)
10092 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, u32ProcCtls);
10093 if (pVmcsInfoNstGst->u32ProcCtls2 != u32ProcCtls2)
10094 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, u32ProcCtls2);
10095 if (pVmcsInfoNstGst->u32XcptBitmap != u32XcptBitmap)
10096 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
10097 if (pVmcsInfoNstGst->u64Cr0Mask != u64Cr0Mask)
10098 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask);
10099 if (pVmcsInfoNstGst->u64Cr4Mask != u64Cr4Mask)
10100 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask);
10101 if (pVmcsInfoNstGst->u32XcptPFMask != u32XcptPFMask)
10102 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, u32XcptPFMask);
10103 if (pVmcsInfoNstGst->u32XcptPFMatch != u32XcptPFMatch)
10104 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, u32XcptPFMatch);
10105 if ( !(u32ProcCtls & VMX_PROC_CTLS_PAUSE_EXIT)
10106 && (u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
10107 {
10108 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT);
10109 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, cPleGapTicks);
10110 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, cPleWindowTicks);
10111 }
10112 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10113 {
10114 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
10115 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
10116 }
10117 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10118 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
10119 rc |= VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, uPendingDbgXcpt);
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 Log4Func(("fIsNested=%RTbool fStepping=%RTbool\n", pVmxTransient->fIsNestedGuest, fStepping));
10192
10193#ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
10194 if (pVmxTransient->fIsNestedGuest)
10195 {
10196 RT_NOREF2(pVCpu, fStepping);
10197 Log2Func(("Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
10198 return VINF_EM_RESCHEDULE_REM;
10199 }
10200#endif
10201
10202#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
10203 PGMRZDynMapFlushAutoSet(pVCpu);
10204#endif
10205
10206 /*
10207 * Check and process force flag actions, some of which might require us to go back to ring-3.
10208 */
10209 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVCpu, fStepping);
10210 if (rcStrict == VINF_SUCCESS)
10211 {
10212 /* FFs don't get set all the time. */
10213#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10214 if ( pVmxTransient->fIsNestedGuest
10215 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10216 {
10217 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10218 return VINF_VMX_VMEXIT;
10219 }
10220#endif
10221 }
10222 else
10223 return rcStrict;
10224
10225 /*
10226 * Virtualize memory-mapped accesses to the physical APIC (may take locks).
10227 */
10228 /** @todo Doing this from ring-3 after VM setup phase causes a
10229 * VERR_IOM_MMIO_RANGE_NOT_FOUND guru while booting Visa 64 SMP VM. No
10230 * idea why atm. */
10231 PVM pVM = pVCpu->CTX_SUFF(pVM);
10232 if ( !pVCpu->hm.s.vmx.u64GstMsrApicBase
10233 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10234 && PDMHasApic(pVM))
10235 {
10236 int rc = hmR0VmxMapHCApicAccessPage(pVCpu);
10237 AssertRCReturn(rc, rc);
10238 }
10239
10240#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10241 /*
10242 * Merge guest VMCS controls with the nested-guest VMCS controls.
10243 *
10244 * Even if we have not executed the guest prior to this (e.g. when resuming from a
10245 * saved state), we should be okay with merging controls as we initialize the
10246 * guest VMCS controls as part of VM setup phase.
10247 */
10248 if ( pVmxTransient->fIsNestedGuest
10249 && !pVCpu->hm.s.vmx.fMergedNstGstCtls)
10250 {
10251 int rc = hmR0VmxMergeVmcsNested(pVCpu);
10252 AssertRCReturn(rc, rc);
10253 pVCpu->hm.s.vmx.fMergedNstGstCtls = true;
10254 }
10255#endif
10256
10257 /*
10258 * Evaluate events to be injected into the guest.
10259 *
10260 * Events in TRPM can be injected without inspecting the guest state.
10261 * If any new events (interrupts/NMI) are pending currently, we try to set up the
10262 * guest to cause a VM-exit the next time they are ready to receive the event.
10263 *
10264 * With nested-guests, evaluating pending events may cause VM-exits.
10265 */
10266 if (TRPMHasTrap(pVCpu))
10267 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
10268
10269 uint32_t fIntrState;
10270 rcStrict = hmR0VmxEvaluatePendingEvent(pVCpu, pVmxTransient, &fIntrState);
10271
10272#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10273 /*
10274 * While evaluating pending events if something failed (unlikely) or if we were
10275 * preparing to run a nested-guest but performed a nested-guest VM-exit, we should bail.
10276 */
10277 if (rcStrict != VINF_SUCCESS)
10278 return rcStrict;
10279 if ( pVmxTransient->fIsNestedGuest
10280 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10281 {
10282 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10283 return VINF_VMX_VMEXIT;
10284 }
10285#else
10286 Assert(rcStrict == VINF_SUCCESS);
10287#endif
10288
10289 /*
10290 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus
10291 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might
10292 * also result in triple-faulting the VM.
10293 *
10294 * With nested-guests, the above does not apply since unrestricted guest execution is a
10295 * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
10296 */
10297 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pVmxTransient, fIntrState, fStepping);
10298 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10299 { /* likely */ }
10300 else
10301 {
10302 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
10303 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
10304 return rcStrict;
10305 }
10306
10307 /*
10308 * A longjump might result in importing CR3 even for VM-exits that don't necessarily
10309 * import CR3 themselves. We will need to update them here, as even as late as the above
10310 * hmR0VmxInjectPendingEvent() call may lazily import guest-CPU state on demand causing
10311 * the below force flags to be set.
10312 */
10313 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
10314 {
10315 Assert(!(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_CR3));
10316 int rc2 = PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
10317 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
10318 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
10319 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10320 }
10321 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
10322 {
10323 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
10324 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10325 }
10326
10327#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10328 /* Paranoia. */
10329 Assert(!pVmxTransient->fIsNestedGuest || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10330#endif
10331
10332 /*
10333 * No longjmps to ring-3 from this point on!!!
10334 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
10335 * This also disables flushing of the R0-logger instance (if any).
10336 */
10337 VMMRZCallRing3Disable(pVCpu);
10338
10339 /*
10340 * Export the guest state bits.
10341 *
10342 * We cannot perform longjmps while loading the guest state because we do not preserve the
10343 * host/guest state (although the VMCS will be preserved) across longjmps which can cause
10344 * CPU migration.
10345 *
10346 * If we are injecting events to a real-on-v86 mode guest, we would have updated RIP and some segment
10347 * registers. Hence, exporting of the guest state needs to be done -after- injection of events.
10348 */
10349 rcStrict = hmR0VmxExportGuestStateOptimal(pVCpu, pVmxTransient);
10350 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10351 { /* likely */ }
10352 else
10353 {
10354 VMMRZCallRing3Enable(pVCpu);
10355 return rcStrict;
10356 }
10357
10358 /*
10359 * We disable interrupts so that we don't miss any interrupts that would flag preemption
10360 * (IPI/timers etc.) when thread-context hooks aren't used and we've been running with
10361 * preemption disabled for a while. Since this is purely to aid the
10362 * RTThreadPreemptIsPending() code, it doesn't matter that it may temporarily reenable and
10363 * disable interrupt on NT.
10364 *
10365 * We need to check for force-flags that could've possible been altered since we last
10366 * checked them (e.g. by PDMGetInterrupt() leaving the PDM critical section,
10367 * see @bugref{6398}).
10368 *
10369 * We also check a couple of other force-flags as a last opportunity to get the EMT back
10370 * to ring-3 before executing guest code.
10371 */
10372 pVmxTransient->fEFlags = ASMIntDisableFlags();
10373
10374 if ( ( !VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
10375 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
10376 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
10377 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
10378 {
10379 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
10380 {
10381#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10382 /*
10383 * If we are executing a nested-guest make sure that we should intercept subsequent
10384 * events. The one we are injecting might be part of VM-entry. This is mainly to keep
10385 * the VM-exit instruction emulation happy.
10386 */
10387 if (pVmxTransient->fIsNestedGuest)
10388 pVCpu->cpum.GstCtx.hwvirt.vmx.fInterceptEvents = true;
10389#endif
10390
10391 /*
10392 * We've injected any pending events. This is really the point of no return (to ring-3).
10393 *
10394 * Note! The caller expects to continue with interrupts & longjmps disabled on successful
10395 * returns from this function, so do -not- enable them here.
10396 */
10397 pVCpu->hm.s.Event.fPending = false;
10398 return VINF_SUCCESS;
10399 }
10400
10401 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPendingHostIrq);
10402 rcStrict = VINF_EM_RAW_INTERRUPT;
10403 }
10404 else
10405 {
10406 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
10407 rcStrict = VINF_EM_RAW_TO_R3;
10408 }
10409
10410 ASMSetFlags(pVmxTransient->fEFlags);
10411 VMMRZCallRing3Enable(pVCpu);
10412
10413 return rcStrict;
10414}
10415
10416
10417/**
10418 * Final preparations before executing guest code using hardware-assisted VMX.
10419 *
10420 * We can no longer get preempted to a different host CPU and there are no returns
10421 * to ring-3. We ignore any errors that may happen from this point (e.g. VMWRITE
10422 * failures), this function is not intended to fail sans unrecoverable hardware
10423 * errors.
10424 *
10425 * @param pVCpu The cross context virtual CPU structure.
10426 * @param pVmxTransient The VMX-transient structure.
10427 *
10428 * @remarks Called with preemption disabled.
10429 * @remarks No-long-jump zone!!!
10430 */
10431static void hmR0VmxPreRunGuestCommitted(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
10432{
10433 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10434 Assert(VMMR0IsLogFlushDisabled(pVCpu));
10435 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
10436 Assert(!pVCpu->hm.s.Event.fPending);
10437
10438 /*
10439 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
10440 */
10441 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10442 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
10443
10444 PVM pVM = pVCpu->CTX_SUFF(pVM);
10445 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10446 PHMPHYSCPU pHostCpu = hmR0GetCurrentCpu();
10447 RTCPUID const idCurrentCpu = pHostCpu->idCpu;
10448
10449 if (!CPUMIsGuestFPUStateActive(pVCpu))
10450 {
10451 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10452 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
10453 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_HOST_CONTEXT;
10454 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10455 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadGuestFpu);
10456 }
10457
10458 /*
10459 * Re-export the host state bits as we may've been preempted (only happens when
10460 * thread-context hooks are used or when the VM start function changes) or if
10461 * the host CR0 is modified while loading the guest FPU state above.
10462 *
10463 * The 64-on-32 switcher saves the (64-bit) host state into the VMCS and if we
10464 * changed the switcher back to 32-bit, we *must* save the 32-bit host state here,
10465 * see @bugref{8432}.
10466 *
10467 * This may also happen when switching to/from a nested-guest VMCS without leaving
10468 * ring-0.
10469 */
10470 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
10471 {
10472 hmR0VmxExportHostState(pVCpu);
10473 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportHostState);
10474 }
10475 Assert(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT));
10476
10477 /*
10478 * Export the state shared between host and guest (FPU, debug, lazy MSRs).
10479 */
10480 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)
10481 hmR0VmxExportSharedState(pVCpu, pVmxTransient);
10482 AssertMsg(!pVCpu->hm.s.fCtxChanged, ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
10483
10484 /*
10485 * Store status of the shared guest/host debug state at the time of VM-entry.
10486 */
10487 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
10488 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
10489
10490 /*
10491 * Always cache the TPR-shadow if the virtual-APIC page exists, thereby skipping
10492 * more than one conditional check. The post-run side of our code shall determine
10493 * if it needs to sync. the virtual APIC TPR with the TPR-shadow.
10494 */
10495 if (pVmcsInfo->pbVirtApic)
10496 pVmxTransient->u8GuestTpr = pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR];
10497
10498 /*
10499 * Update the host MSRs values in the VM-exit MSR-load area.
10500 */
10501 if (!pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs)
10502 {
10503 if (pVmcsInfo->cExitMsrLoad > 0)
10504 hmR0VmxUpdateAutoLoadHostMsrs(pVCpu, pVmcsInfo);
10505 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = true;
10506 }
10507
10508 /*
10509 * Evaluate if we need to intercept guest RDTSC/P accesses. Set up the
10510 * VMX-preemption timer based on the next virtual sync clock deadline.
10511 */
10512 if ( !pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer
10513 || idCurrentCpu != pVCpu->hm.s.idLastCpu)
10514 {
10515 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVCpu, pVmxTransient);
10516 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = true;
10517 }
10518
10519 /* Record statistics of how often we use TSC offsetting as opposed to intercepting RDTSC/P. */
10520 bool const fIsRdtscIntercepted = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT);
10521 if (!fIsRdtscIntercepted)
10522 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
10523 else
10524 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
10525
10526 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
10527 hmR0VmxFlushTaggedTlb(pHostCpu, pVCpu, pVmcsInfo); /* Invalidate the appropriate guest entries from the TLB. */
10528 Assert(idCurrentCpu == pVCpu->hm.s.idLastCpu);
10529 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Update the error reporting info. with the current host CPU. */
10530 pVmcsInfo->idHostCpu = idCurrentCpu; /* Update the CPU for which we updated host-state in this VMCS. */
10531
10532 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
10533
10534 TMNotifyStartOfExecution(pVCpu); /* Notify TM to resume its clocks when TSC is tied to execution,
10535 as we're about to start executing the guest . */
10536
10537 /*
10538 * Load the guest TSC_AUX MSR when we are not intercepting RDTSCP.
10539 *
10540 * This is done this late as updating the TSC offsetting/preemption timer above
10541 * figures out if we can skip intercepting RDTSCP by calculating the number of
10542 * host CPU ticks till the next virtual sync deadline (for the dynamic case).
10543 */
10544 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_RDTSCP)
10545 && !fIsRdtscIntercepted)
10546 {
10547 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_TSC_AUX);
10548
10549 /* NB: Because we call hmR0VmxAddAutoLoadStoreMsr with fUpdateHostMsr=true,
10550 it's safe even after hmR0VmxUpdateAutoLoadHostMsrs has already been done. */
10551 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX, CPUMGetGuestTscAux(pVCpu),
10552 true /* fSetReadWrite */, true /* fUpdateHostMsr */);
10553 AssertRC(rc);
10554 Assert(!pVmxTransient->fRemoveTscAuxMsr);
10555 pVmxTransient->fRemoveTscAuxMsr = true;
10556 }
10557
10558#ifdef VBOX_STRICT
10559 Assert(pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs);
10560 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
10561 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo);
10562 AssertRC(hmR0VmxCheckVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest));
10563#endif
10564
10565#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
10566 /** @todo r=ramshankar: We can now probably use iemVmxVmentryCheckGuestState here.
10567 * Add a PVMXMSRS parameter to it, so that IEM can look at the host MSRs,
10568 * see @bugref{9180#c54}. */
10569 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
10570 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
10571 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
10572#endif
10573}
10574
10575
10576/**
10577 * First C routine invoked after running guest code using hardware-assisted VMX.
10578 *
10579 * @param pVCpu The cross context virtual CPU structure.
10580 * @param pVmxTransient The VMX-transient structure.
10581 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
10582 *
10583 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
10584 *
10585 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
10586 * unconditionally when it is safe to do so.
10587 */
10588static void hmR0VmxPostRunGuest(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, int rcVMRun)
10589{
10590 uint64_t const uHostTsc = ASMReadTSC(); /** @todo We can do a lot better here, see @bugref{9180#c38}. */
10591
10592 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
10593 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
10594 pVCpu->hm.s.fCtxChanged = 0; /* Exits/longjmps to ring-3 requires saving the guest state. */
10595 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
10596 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
10597 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
10598
10599 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10600 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
10601 {
10602 uint64_t uGstTsc;
10603 if (!pVmxTransient->fIsNestedGuest)
10604 uGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
10605 else
10606 {
10607 uint64_t const uNstGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
10608 uGstTsc = CPUMRemoveNestedGuestTscOffset(pVCpu, uNstGstTsc);
10609 }
10610 TMCpuTickSetLastSeen(pVCpu, uGstTsc); /* Update TM with the guest TSC. */
10611 }
10612
10613 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatPreExit, x);
10614 TMNotifyEndOfExecution(pVCpu); /* Notify TM that the guest is no longer running. */
10615 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10616
10617 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Some host state messed up by VMX needs restoring. */
10618 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
10619#ifdef VBOX_STRICT
10620 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo); /* Verify that the host EFER MSR wasn't modified. */
10621#endif
10622 Assert(!ASMIntAreEnabled());
10623 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
10624 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10625
10626#ifdef HMVMX_ALWAYS_CLEAN_TRANSIENT
10627 /*
10628 * Clean all the VMCS fields in the transient structure before reading
10629 * anything from the VMCS.
10630 */
10631 pVmxTransient->uExitReason = 0;
10632 pVmxTransient->uExitIntErrorCode = 0;
10633 pVmxTransient->uExitQual = 0;
10634 pVmxTransient->uGuestLinearAddr = 0;
10635 pVmxTransient->uExitIntInfo = 0;
10636 pVmxTransient->cbInstr = 0;
10637 pVmxTransient->ExitInstrInfo.u = 0;
10638 pVmxTransient->uEntryIntInfo = 0;
10639 pVmxTransient->uEntryXcptErrorCode = 0;
10640 pVmxTransient->cbEntryInstr = 0;
10641 pVmxTransient->uIdtVectoringInfo = 0;
10642 pVmxTransient->uIdtVectoringErrorCode = 0;
10643#endif
10644
10645 /*
10646 * Save the basic VM-exit reason and check if the VM-entry failed.
10647 * See Intel spec. 24.9.1 "Basic VM-exit Information".
10648 */
10649 uint32_t uExitReason;
10650 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
10651 AssertRC(rc);
10652 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason);
10653 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
10654
10655 /*
10656 * Log the VM-exit before logging anything else as otherwise it might be a
10657 * tad confusing what happens before and after the world-switch.
10658 */
10659 HMVMX_LOG_EXIT(pVCpu, uExitReason);
10660
10661 /*
10662 * Remove the TSC_AUX MSR from the auto-load/store MSR area and reset any MSR
10663 * bitmap permissions, if it was added before VM-entry.
10664 */
10665 if (pVmxTransient->fRemoveTscAuxMsr)
10666 {
10667 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX);
10668 pVmxTransient->fRemoveTscAuxMsr = false;
10669 }
10670
10671 /*
10672 * Check if VMLAUNCH/VMRESUME succeeded.
10673 * If this failed, we cause a guru meditation and cease further execution.
10674 *
10675 * However, if we are executing a nested-guest we might fail if we use the
10676 * fast path rather than fully emulating VMLAUNCH/VMRESUME instruction in IEM.
10677 */
10678 if (RT_LIKELY(rcVMRun == VINF_SUCCESS))
10679 {
10680 /*
10681 * Update the VM-exit history array here even if the VM-entry failed due to:
10682 * - Invalid guest state.
10683 * - MSR loading.
10684 * - Machine-check event.
10685 *
10686 * In any of the above cases we will still have a "valid" VM-exit reason
10687 * despite @a fVMEntryFailed being false.
10688 *
10689 * See Intel spec. 26.7 "VM-Entry failures during or after loading guest state".
10690 *
10691 * Note! We don't have CS or RIP at this point. Will probably address that later
10692 * by amending the history entry added here.
10693 */
10694 EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_VMX, pVmxTransient->uExitReason & EMEXIT_F_TYPE_MASK),
10695 UINT64_MAX, uHostTsc);
10696
10697 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
10698 {
10699 VMMRZCallRing3Enable(pVCpu);
10700
10701 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10702 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10703
10704#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
10705 hmR0VmxReadAllRoFieldsVmcs(pVmxTransient);
10706#endif
10707#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
10708 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
10709 AssertRC(rc);
10710#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
10711 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_RFLAGS);
10712 AssertRC(rc);
10713#else
10714 /*
10715 * Import the guest-interruptibility state always as we need it while evaluating
10716 * injecting events on re-entry.
10717 *
10718 * We don't import CR0 (when unrestricted guest execution is unavailable) despite
10719 * checking for real-mode while exporting the state because all bits that cause
10720 * mode changes wrt CR0 are intercepted.
10721 */
10722 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_HM_VMX_INT_STATE);
10723 AssertRC(rc);
10724#endif
10725
10726 /*
10727 * Sync the TPR shadow with our APIC state.
10728 */
10729 if ( !pVmxTransient->fIsNestedGuest
10730 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
10731 {
10732 Assert(pVmcsInfo->pbVirtApic);
10733 if (pVmxTransient->u8GuestTpr != pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR])
10734 {
10735 rc = APICSetTpr(pVCpu, pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR]);
10736 AssertRC(rc);
10737 ASMAtomicOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
10738 }
10739 }
10740
10741 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10742 return;
10743 }
10744 }
10745#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10746 else if (pVmxTransient->fIsNestedGuest)
10747 AssertMsgFailed(("VMLAUNCH/VMRESUME failed but shouldn't happen when VMLAUNCH/VMRESUME was emulated in IEM!\n"));
10748#endif
10749 else
10750 Log4Func(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
10751
10752 VMMRZCallRing3Enable(pVCpu);
10753}
10754
10755
10756/**
10757 * Runs the guest code using hardware-assisted VMX the normal way.
10758 *
10759 * @returns VBox status code.
10760 * @param pVCpu The cross context virtual CPU structure.
10761 * @param pcLoops Pointer to the number of executed loops.
10762 */
10763static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVMCPU pVCpu, uint32_t *pcLoops)
10764{
10765 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
10766 Assert(pcLoops);
10767 Assert(*pcLoops <= cMaxResumeLoops);
10768 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10769
10770#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10771 /*
10772 * Switch to the guest VMCS as we may have transitioned from executing the nested-guest
10773 * without leaving ring-0. Otherwise, if we came from ring-3 we would have loaded the
10774 * guest VMCS while entering the VMX ring-0 session.
10775 */
10776 if (pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs)
10777 {
10778 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, false /* fSwitchToNstGstVmcs */);
10779 if (RT_SUCCESS(rc))
10780 { /* likely */ }
10781 else
10782 {
10783 LogRelFunc(("Failed to switch to the guest VMCS. rc=%Rrc\n", rc));
10784 return rc;
10785 }
10786 }
10787#endif
10788
10789 VMXTRANSIENT VmxTransient;
10790 RT_ZERO(VmxTransient);
10791 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
10792
10793 /* Paranoia. */
10794 Assert(VmxTransient.pVmcsInfo == &pVCpu->hm.s.vmx.VmcsInfo);
10795
10796 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10797 for (;;)
10798 {
10799 Assert(!HMR0SuspendPending());
10800 HMVMX_ASSERT_CPU_SAFE(pVCpu);
10801 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10802
10803 /*
10804 * Preparatory work for running nested-guest code, this may force us to
10805 * return to ring-3.
10806 *
10807 * Warning! This bugger disables interrupts on VINF_SUCCESS!
10808 */
10809 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
10810 if (rcStrict != VINF_SUCCESS)
10811 break;
10812
10813 /* Interrupts are disabled at this point! */
10814 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
10815 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
10816 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
10817 /* Interrupts are re-enabled at this point! */
10818
10819 /*
10820 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
10821 */
10822 if (RT_SUCCESS(rcRun))
10823 { /* very likely */ }
10824 else
10825 {
10826 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
10827 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
10828 return rcRun;
10829 }
10830
10831 /*
10832 * Profile the VM-exit.
10833 */
10834 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10835 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10836 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10837 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
10838 HMVMX_START_EXIT_DISPATCH_PROF();
10839
10840 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
10841
10842 /*
10843 * Handle the VM-exit.
10844 */
10845#ifdef HMVMX_USE_FUNCTION_TABLE
10846 rcStrict = g_apfnVMExitHandlers[VmxTransient.uExitReason](pVCpu, &VmxTransient);
10847#else
10848 rcStrict = hmR0VmxHandleExit(pVCpu, &VmxTransient);
10849#endif
10850 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
10851 if (rcStrict == VINF_SUCCESS)
10852 {
10853 if (++(*pcLoops) <= cMaxResumeLoops)
10854 continue;
10855 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10856 rcStrict = VINF_EM_RAW_INTERRUPT;
10857 }
10858 break;
10859 }
10860
10861 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10862 return rcStrict;
10863}
10864
10865
10866#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10867/**
10868 * Runs the nested-guest code using hardware-assisted VMX.
10869 *
10870 * @returns VBox status code.
10871 * @param pVCpu The cross context virtual CPU structure.
10872 * @param pcLoops Pointer to the number of executed loops.
10873 *
10874 * @sa hmR0VmxRunGuestCodeNormal.
10875 */
10876static VBOXSTRICTRC hmR0VmxRunGuestCodeNested(PVMCPU pVCpu, uint32_t *pcLoops)
10877{
10878 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
10879 Assert(pcLoops);
10880 Assert(*pcLoops <= cMaxResumeLoops);
10881 Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10882
10883 /*
10884 * Switch to the nested-guest VMCS as we may have transitioned from executing the
10885 * guest without leaving ring-0. Otherwise, if we came from ring-3 we would have
10886 * loaded the nested-guest VMCS while entering the VMX ring-0 session.
10887 */
10888 if (!pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs)
10889 {
10890 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, true /* fSwitchToNstGstVmcs */);
10891 if (RT_SUCCESS(rc))
10892 { /* likely */ }
10893 else
10894 {
10895 LogRelFunc(("Failed to switch to the nested-guest VMCS. rc=%Rrc\n", rc));
10896 return rc;
10897 }
10898 }
10899
10900 VMXTRANSIENT VmxTransient;
10901 RT_ZERO(VmxTransient);
10902 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
10903 VmxTransient.fIsNestedGuest = true;
10904
10905 /* Paranoia. */
10906 Assert(VmxTransient.pVmcsInfo == &pVCpu->hm.s.vmx.VmcsInfoNstGst);
10907
10908 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10909 for (;;)
10910 {
10911 Assert(!HMR0SuspendPending());
10912 HMVMX_ASSERT_CPU_SAFE(pVCpu);
10913 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10914
10915 /*
10916 * Preparatory work for running guest code, this may force us to
10917 * return to ring-3.
10918 *
10919 * Warning! This bugger disables interrupts on VINF_SUCCESS!
10920 */
10921 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
10922 if (rcStrict != VINF_SUCCESS)
10923 break;
10924
10925 /* Interrupts are disabled at this point! */
10926 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
10927 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
10928 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
10929 /* Interrupts are re-enabled at this point! */
10930
10931 /*
10932 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
10933 */
10934 if (RT_SUCCESS(rcRun))
10935 { /* very likely */ }
10936 else
10937 {
10938 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
10939 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
10940 return rcRun;
10941 }
10942
10943 /*
10944 * Profile the VM-exit.
10945 */
10946 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10947 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10948 STAM_COUNTER_INC(&pVCpu->hm.s.StatNestedExitAll);
10949 STAM_COUNTER_INC(&pVCpu->hm.s.paStatNestedExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10950 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
10951 HMVMX_START_EXIT_DISPATCH_PROF();
10952
10953 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
10954
10955 /*
10956 * Handle the VM-exit.
10957 */
10958 rcStrict = hmR0VmxHandleExitNested(pVCpu, &VmxTransient);
10959 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
10960 if (rcStrict == VINF_SUCCESS)
10961 {
10962 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10963 {
10964 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10965 rcStrict = VINF_VMX_VMEXIT;
10966 }
10967 else
10968 {
10969 if (++(*pcLoops) <= cMaxResumeLoops)
10970 continue;
10971 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10972 rcStrict = VINF_EM_RAW_INTERRUPT;
10973 }
10974 }
10975 else
10976 Assert(rcStrict != VINF_VMX_VMEXIT);
10977 break;
10978 }
10979
10980 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10981 return rcStrict;
10982}
10983#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10984
10985
10986/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
10987 * probes.
10988 *
10989 * The following few functions and associated structure contains the bloat
10990 * necessary for providing detailed debug events and dtrace probes as well as
10991 * reliable host side single stepping. This works on the principle of
10992 * "subclassing" the normal execution loop and workers. We replace the loop
10993 * method completely and override selected helpers to add necessary adjustments
10994 * to their core operation.
10995 *
10996 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
10997 * any performance for debug and analysis features.
10998 *
10999 * @{
11000 */
11001
11002/**
11003 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
11004 * the debug run loop.
11005 */
11006typedef struct VMXRUNDBGSTATE
11007{
11008 /** The RIP we started executing at. This is for detecting that we stepped. */
11009 uint64_t uRipStart;
11010 /** The CS we started executing with. */
11011 uint16_t uCsStart;
11012
11013 /** Whether we've actually modified the 1st execution control field. */
11014 bool fModifiedProcCtls : 1;
11015 /** Whether we've actually modified the 2nd execution control field. */
11016 bool fModifiedProcCtls2 : 1;
11017 /** Whether we've actually modified the exception bitmap. */
11018 bool fModifiedXcptBitmap : 1;
11019
11020 /** We desire the modified the CR0 mask to be cleared. */
11021 bool fClearCr0Mask : 1;
11022 /** We desire the modified the CR4 mask to be cleared. */
11023 bool fClearCr4Mask : 1;
11024 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
11025 uint32_t fCpe1Extra;
11026 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
11027 uint32_t fCpe1Unwanted;
11028 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
11029 uint32_t fCpe2Extra;
11030 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
11031 uint32_t bmXcptExtra;
11032 /** The sequence number of the Dtrace provider settings the state was
11033 * configured against. */
11034 uint32_t uDtraceSettingsSeqNo;
11035 /** VM-exits to check (one bit per VM-exit). */
11036 uint32_t bmExitsToCheck[3];
11037
11038 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
11039 uint32_t fProcCtlsInitial;
11040 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
11041 uint32_t fProcCtls2Initial;
11042 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
11043 uint32_t bmXcptInitial;
11044} VMXRUNDBGSTATE;
11045AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
11046typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
11047
11048
11049/**
11050 * Initializes the VMXRUNDBGSTATE structure.
11051 *
11052 * @param pVCpu The cross context virtual CPU structure of the
11053 * calling EMT.
11054 * @param pVmxTransient The VMX-transient structure.
11055 * @param pDbgState The debug state to initialize.
11056 */
11057static void hmR0VmxRunDebugStateInit(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11058{
11059 pDbgState->uRipStart = pVCpu->cpum.GstCtx.rip;
11060 pDbgState->uCsStart = pVCpu->cpum.GstCtx.cs.Sel;
11061
11062 pDbgState->fModifiedProcCtls = false;
11063 pDbgState->fModifiedProcCtls2 = false;
11064 pDbgState->fModifiedXcptBitmap = false;
11065 pDbgState->fClearCr0Mask = false;
11066 pDbgState->fClearCr4Mask = false;
11067 pDbgState->fCpe1Extra = 0;
11068 pDbgState->fCpe1Unwanted = 0;
11069 pDbgState->fCpe2Extra = 0;
11070 pDbgState->bmXcptExtra = 0;
11071 pDbgState->fProcCtlsInitial = pVmxTransient->pVmcsInfo->u32ProcCtls;
11072 pDbgState->fProcCtls2Initial = pVmxTransient->pVmcsInfo->u32ProcCtls2;
11073 pDbgState->bmXcptInitial = pVmxTransient->pVmcsInfo->u32XcptBitmap;
11074}
11075
11076
11077/**
11078 * Updates the VMSC fields with changes requested by @a pDbgState.
11079 *
11080 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
11081 * immediately before executing guest code, i.e. when interrupts are disabled.
11082 * We don't check status codes here as we cannot easily assert or return in the
11083 * latter case.
11084 *
11085 * @param pVCpu The cross context virtual CPU structure.
11086 * @param pVmxTransient The VMX-transient structure.
11087 * @param pDbgState The debug state.
11088 */
11089static void hmR0VmxPreRunGuestDebugStateApply(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11090{
11091 /*
11092 * Ensure desired flags in VMCS control fields are set.
11093 * (Ignoring write failure here, as we're committed and it's just debug extras.)
11094 *
11095 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
11096 * there should be no stale data in pCtx at this point.
11097 */
11098 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11099 if ( (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
11100 || (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Unwanted))
11101 {
11102 pVmcsInfo->u32ProcCtls |= pDbgState->fCpe1Extra;
11103 pVmcsInfo->u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
11104 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
11105 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVmcsInfo->u32ProcCtls));
11106 pDbgState->fModifiedProcCtls = true;
11107 }
11108
11109 if ((pVmcsInfo->u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
11110 {
11111 pVmcsInfo->u32ProcCtls2 |= pDbgState->fCpe2Extra;
11112 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVmcsInfo->u32ProcCtls2);
11113 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVmcsInfo->u32ProcCtls2));
11114 pDbgState->fModifiedProcCtls2 = true;
11115 }
11116
11117 if ((pVmcsInfo->u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
11118 {
11119 pVmcsInfo->u32XcptBitmap |= pDbgState->bmXcptExtra;
11120 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVmcsInfo->u32XcptBitmap);
11121 Log6Func(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVmcsInfo->u32XcptBitmap));
11122 pDbgState->fModifiedXcptBitmap = true;
11123 }
11124
11125 if (pDbgState->fClearCr0Mask && pVmcsInfo->u64Cr0Mask != 0)
11126 {
11127 pVmcsInfo->u64Cr0Mask = 0;
11128 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, 0);
11129 Log6Func(("VMX_VMCS_CTRL_CR0_MASK: 0\n"));
11130 }
11131
11132 if (pDbgState->fClearCr4Mask && pVmcsInfo->u64Cr4Mask != 0)
11133 {
11134 pVmcsInfo->u64Cr4Mask = 0;
11135 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, 0);
11136 Log6Func(("VMX_VMCS_CTRL_CR4_MASK: 0\n"));
11137 }
11138
11139 NOREF(pVCpu);
11140}
11141
11142
11143/**
11144 * Restores VMCS fields that were changed by hmR0VmxPreRunGuestDebugStateApply for
11145 * re-entry next time around.
11146 *
11147 * @returns Strict VBox status code (i.e. informational status codes too).
11148 * @param pVCpu The cross context virtual CPU structure.
11149 * @param pVmxTransient The VMX-transient structure.
11150 * @param pDbgState The debug state.
11151 * @param rcStrict The return code from executing the guest using single
11152 * stepping.
11153 */
11154static VBOXSTRICTRC hmR0VmxRunDebugStateRevert(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState,
11155 VBOXSTRICTRC rcStrict)
11156{
11157 /*
11158 * Restore VM-exit control settings as we may not reenter this function the
11159 * next time around.
11160 */
11161 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11162
11163 /* We reload the initial value, trigger what we can of recalculations the
11164 next time around. From the looks of things, that's all that's required atm. */
11165 if (pDbgState->fModifiedProcCtls)
11166 {
11167 if (!(pDbgState->fProcCtlsInitial & VMX_PROC_CTLS_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
11168 pDbgState->fProcCtlsInitial |= VMX_PROC_CTLS_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
11169 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
11170 AssertRC(rc2);
11171 pVmcsInfo->u32ProcCtls = pDbgState->fProcCtlsInitial;
11172 }
11173
11174 /* We're currently the only ones messing with this one, so just restore the
11175 cached value and reload the field. */
11176 if ( pDbgState->fModifiedProcCtls2
11177 && pVmcsInfo->u32ProcCtls2 != pDbgState->fProcCtls2Initial)
11178 {
11179 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
11180 AssertRC(rc2);
11181 pVmcsInfo->u32ProcCtls2 = pDbgState->fProcCtls2Initial;
11182 }
11183
11184 /* If we've modified the exception bitmap, we restore it and trigger
11185 reloading and partial recalculation the next time around. */
11186 if (pDbgState->fModifiedXcptBitmap)
11187 pVmcsInfo->u32XcptBitmap = pDbgState->bmXcptInitial;
11188
11189 return rcStrict;
11190}
11191
11192
11193/**
11194 * Configures VM-exit controls for current DBGF and DTrace settings.
11195 *
11196 * This updates @a pDbgState and the VMCS execution control fields to reflect
11197 * the necessary VM-exits demanded by DBGF and DTrace.
11198 *
11199 * @param pVCpu The cross context virtual CPU structure.
11200 * @param pVmxTransient The VMX-transient structure. May update
11201 * fUpdatedTscOffsettingAndPreemptTimer.
11202 * @param pDbgState The debug state.
11203 */
11204static void hmR0VmxPreRunGuestDebugStateUpdate(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11205{
11206 /*
11207 * Take down the dtrace serial number so we can spot changes.
11208 */
11209 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
11210 ASMCompilerBarrier();
11211
11212 /*
11213 * We'll rebuild most of the middle block of data members (holding the
11214 * current settings) as we go along here, so start by clearing it all.
11215 */
11216 pDbgState->bmXcptExtra = 0;
11217 pDbgState->fCpe1Extra = 0;
11218 pDbgState->fCpe1Unwanted = 0;
11219 pDbgState->fCpe2Extra = 0;
11220 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
11221 pDbgState->bmExitsToCheck[i] = 0;
11222
11223 /*
11224 * Software interrupts (INT XXh) - no idea how to trigger these...
11225 */
11226 PVM pVM = pVCpu->CTX_SUFF(pVM);
11227 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
11228 || VBOXVMM_INT_SOFTWARE_ENABLED())
11229 {
11230 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11231 }
11232
11233 /*
11234 * INT3 breakpoints - triggered by #BP exceptions.
11235 */
11236 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
11237 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11238
11239 /*
11240 * Exception bitmap and XCPT events+probes.
11241 */
11242 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
11243 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
11244 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
11245
11246 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
11247 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
11248 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11249 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
11250 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
11251 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
11252 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
11253 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
11254 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
11255 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
11256 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
11257 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
11258 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
11259 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
11260 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
11261 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
11262 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
11263 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
11264
11265 if (pDbgState->bmXcptExtra)
11266 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11267
11268 /*
11269 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
11270 *
11271 * Note! This is the reverse of what hmR0VmxHandleExitDtraceEvents does.
11272 * So, when adding/changing/removing please don't forget to update it.
11273 *
11274 * Some of the macros are picking up local variables to save horizontal space,
11275 * (being able to see it in a table is the lesser evil here).
11276 */
11277#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
11278 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
11279 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
11280#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
11281 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11282 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11283 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11284 } else do { } while (0)
11285#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
11286 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11287 { \
11288 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
11289 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11290 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11291 } else do { } while (0)
11292#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
11293 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11294 { \
11295 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
11296 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11297 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11298 } else do { } while (0)
11299#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
11300 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11301 { \
11302 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
11303 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11304 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11305 } else do { } while (0)
11306
11307 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
11308 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
11309 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
11310 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
11311 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
11312
11313 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
11314 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
11315 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
11316 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
11317 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_PROC_CTLS_HLT_EXIT); /* paranoia */
11318 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
11319 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
11320 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
11321 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_PROC_CTLS_INVLPG_EXIT);
11322 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
11323 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_PROC_CTLS_RDPMC_EXIT);
11324 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
11325 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_PROC_CTLS_RDTSC_EXIT);
11326 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
11327 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
11328 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
11329 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
11330 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
11331 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
11332 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
11333 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
11334 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
11335 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
11336 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
11337 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
11338 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
11339 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
11340 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
11341 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
11342 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
11343 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
11344 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
11345 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
11346 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
11347 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
11348 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
11349
11350 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
11351 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11352 {
11353 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4
11354 | CPUMCTX_EXTRN_APIC_TPR);
11355 AssertRC(rc);
11356
11357#if 0 /** @todo fix me */
11358 pDbgState->fClearCr0Mask = true;
11359 pDbgState->fClearCr4Mask = true;
11360#endif
11361 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
11362 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_STORE_EXIT | VMX_PROC_CTLS_CR8_STORE_EXIT;
11363 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11364 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_LOAD_EXIT | VMX_PROC_CTLS_CR8_LOAD_EXIT;
11365 pDbgState->fCpe1Unwanted |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* risky? */
11366 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
11367 require clearing here and in the loop if we start using it. */
11368 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
11369 }
11370 else
11371 {
11372 if (pDbgState->fClearCr0Mask)
11373 {
11374 pDbgState->fClearCr0Mask = false;
11375 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR0);
11376 }
11377 if (pDbgState->fClearCr4Mask)
11378 {
11379 pDbgState->fClearCr4Mask = false;
11380 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR4);
11381 }
11382 }
11383 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
11384 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
11385
11386 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
11387 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
11388 {
11389 /** @todo later, need to fix handler as it assumes this won't usually happen. */
11390 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
11391 }
11392 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
11393 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
11394
11395 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS); /* risky clearing this? */
11396 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
11397 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS);
11398 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
11399 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_PROC_CTLS_MWAIT_EXIT); /* paranoia */
11400 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
11401 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_PROC_CTLS_MONITOR_EXIT); /* paranoia */
11402 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
11403#if 0 /** @todo too slow, fix handler. */
11404 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_PROC_CTLS_PAUSE_EXIT);
11405#endif
11406 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
11407
11408 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
11409 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
11410 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
11411 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
11412 {
11413 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11414 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_GDTR_IDTR_ACCESS);
11415 }
11416 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11417 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11418 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11419 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11420
11421 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
11422 || IS_EITHER_ENABLED(pVM, INSTR_STR)
11423 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
11424 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
11425 {
11426 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11427 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_LDTR_TR_ACCESS);
11428 }
11429 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_LDTR_TR_ACCESS);
11430 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_LDTR_TR_ACCESS);
11431 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_LDTR_TR_ACCESS);
11432 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_LDTR_TR_ACCESS);
11433
11434 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
11435 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
11436 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_PROC_CTLS_RDTSC_EXIT);
11437 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
11438 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
11439 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
11440 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_PROC_CTLS2_WBINVD_EXIT);
11441 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
11442 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
11443 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
11444 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_PROC_CTLS2_RDRAND_EXIT);
11445 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
11446 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_PROC_CTLS_INVLPG_EXIT);
11447 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
11448 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
11449 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
11450 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_PROC_CTLS2_RDSEED_EXIT);
11451 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
11452 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
11453 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
11454 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
11455 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
11456
11457#undef IS_EITHER_ENABLED
11458#undef SET_ONLY_XBM_IF_EITHER_EN
11459#undef SET_CPE1_XBM_IF_EITHER_EN
11460#undef SET_CPEU_XBM_IF_EITHER_EN
11461#undef SET_CPE2_XBM_IF_EITHER_EN
11462
11463 /*
11464 * Sanitize the control stuff.
11465 */
11466 pDbgState->fCpe2Extra &= pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1;
11467 if (pDbgState->fCpe2Extra)
11468 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
11469 pDbgState->fCpe1Extra &= pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1;
11470 pDbgState->fCpe1Unwanted &= ~pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0;
11471 if (pVCpu->hm.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_PROC_CTLS_RDTSC_EXIT))
11472 {
11473 pVCpu->hm.s.fDebugWantRdTscExit ^= true;
11474 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
11475 }
11476
11477 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
11478 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
11479 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
11480 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
11481}
11482
11483
11484/**
11485 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
11486 * appropriate.
11487 *
11488 * The caller has checked the VM-exit against the
11489 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
11490 * already, so we don't have to do that either.
11491 *
11492 * @returns Strict VBox status code (i.e. informational status codes too).
11493 * @param pVCpu The cross context virtual CPU structure.
11494 * @param pVmxTransient The VMX-transient structure.
11495 * @param uExitReason The VM-exit reason.
11496 *
11497 * @remarks The name of this function is displayed by dtrace, so keep it short
11498 * and to the point. No longer than 33 chars long, please.
11499 */
11500static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
11501{
11502 /*
11503 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
11504 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
11505 *
11506 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
11507 * does. Must add/change/remove both places. Same ordering, please.
11508 *
11509 * Added/removed events must also be reflected in the next section
11510 * where we dispatch dtrace events.
11511 */
11512 bool fDtrace1 = false;
11513 bool fDtrace2 = false;
11514 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
11515 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
11516 uint32_t uEventArg = 0;
11517#define SET_EXIT(a_EventSubName) \
11518 do { \
11519 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11520 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11521 } while (0)
11522#define SET_BOTH(a_EventSubName) \
11523 do { \
11524 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
11525 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11526 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
11527 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11528 } while (0)
11529 switch (uExitReason)
11530 {
11531 case VMX_EXIT_MTF:
11532 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
11533
11534 case VMX_EXIT_XCPT_OR_NMI:
11535 {
11536 uint8_t const idxVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
11537 switch (VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo))
11538 {
11539 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
11540 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
11541 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
11542 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
11543 {
11544 if (VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uExitIntInfo))
11545 {
11546 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
11547 uEventArg = pVmxTransient->uExitIntErrorCode;
11548 }
11549 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
11550 switch (enmEvent1)
11551 {
11552 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
11553 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
11554 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
11555 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
11556 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
11557 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
11558 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
11559 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
11560 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
11561 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
11562 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
11563 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
11564 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
11565 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
11566 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
11567 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
11568 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
11569 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
11570 default: break;
11571 }
11572 }
11573 else
11574 AssertFailed();
11575 break;
11576
11577 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
11578 uEventArg = idxVector;
11579 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
11580 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
11581 break;
11582 }
11583 break;
11584 }
11585
11586 case VMX_EXIT_TRIPLE_FAULT:
11587 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
11588 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
11589 break;
11590 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
11591 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
11592 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
11593 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
11594 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
11595
11596 /* Instruction specific VM-exits: */
11597 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
11598 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
11599 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
11600 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
11601 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
11602 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
11603 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
11604 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
11605 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
11606 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
11607 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
11608 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
11609 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
11610 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
11611 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
11612 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
11613 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
11614 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
11615 case VMX_EXIT_MOV_CRX:
11616 hmR0VmxReadExitQualVmcs(pVmxTransient);
11617 if (VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_CRX_ACCESS_READ)
11618 SET_BOTH(CRX_READ);
11619 else
11620 SET_BOTH(CRX_WRITE);
11621 uEventArg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
11622 break;
11623 case VMX_EXIT_MOV_DRX:
11624 hmR0VmxReadExitQualVmcs(pVmxTransient);
11625 if ( VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual)
11626 == VMX_EXIT_QUAL_DRX_DIRECTION_READ)
11627 SET_BOTH(DRX_READ);
11628 else
11629 SET_BOTH(DRX_WRITE);
11630 uEventArg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
11631 break;
11632 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
11633 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
11634 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
11635 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
11636 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
11637 case VMX_EXIT_GDTR_IDTR_ACCESS:
11638 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
11639 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_XDTR_INSINFO_INSTR_ID))
11640 {
11641 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
11642 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
11643 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
11644 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
11645 }
11646 break;
11647
11648 case VMX_EXIT_LDTR_TR_ACCESS:
11649 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
11650 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_YYTR_INSINFO_INSTR_ID))
11651 {
11652 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
11653 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
11654 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
11655 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
11656 }
11657 break;
11658
11659 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
11660 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
11661 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
11662 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
11663 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
11664 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
11665 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
11666 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
11667 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
11668 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
11669 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
11670
11671 /* Events that aren't relevant at this point. */
11672 case VMX_EXIT_EXT_INT:
11673 case VMX_EXIT_INT_WINDOW:
11674 case VMX_EXIT_NMI_WINDOW:
11675 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11676 case VMX_EXIT_PREEMPT_TIMER:
11677 case VMX_EXIT_IO_INSTR:
11678 break;
11679
11680 /* Errors and unexpected events. */
11681 case VMX_EXIT_INIT_SIGNAL:
11682 case VMX_EXIT_SIPI:
11683 case VMX_EXIT_IO_SMI:
11684 case VMX_EXIT_SMI:
11685 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
11686 case VMX_EXIT_ERR_MSR_LOAD:
11687 case VMX_EXIT_ERR_MACHINE_CHECK:
11688 case VMX_EXIT_PML_FULL:
11689 case VMX_EXIT_VIRTUALIZED_EOI:
11690 break;
11691
11692 default:
11693 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
11694 break;
11695 }
11696#undef SET_BOTH
11697#undef SET_EXIT
11698
11699 /*
11700 * Dtrace tracepoints go first. We do them here at once so we don't
11701 * have to copy the guest state saving and stuff a few dozen times.
11702 * Down side is that we've got to repeat the switch, though this time
11703 * we use enmEvent since the probes are a subset of what DBGF does.
11704 */
11705 if (fDtrace1 || fDtrace2)
11706 {
11707 hmR0VmxReadExitQualVmcs(pVmxTransient);
11708 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
11709 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
11710 switch (enmEvent1)
11711 {
11712 /** @todo consider which extra parameters would be helpful for each probe. */
11713 case DBGFEVENT_END: break;
11714 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pCtx); break;
11715 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pCtx, pCtx->dr[6]); break;
11716 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pCtx); break;
11717 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pCtx); break;
11718 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pCtx); break;
11719 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pCtx); break;
11720 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pCtx); break;
11721 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pCtx); break;
11722 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pCtx, uEventArg); break;
11723 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pCtx, uEventArg); break;
11724 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pCtx, uEventArg); break;
11725 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pCtx, uEventArg); break;
11726 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pCtx, uEventArg, pCtx->cr2); break;
11727 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pCtx); break;
11728 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pCtx); break;
11729 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pCtx); break;
11730 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pCtx); break;
11731 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pCtx, uEventArg); break;
11732 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11733 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11734 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pCtx); break;
11735 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pCtx); break;
11736 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pCtx); break;
11737 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pCtx); break;
11738 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pCtx); break;
11739 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pCtx); break;
11740 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pCtx); break;
11741 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11742 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11743 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11744 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11745 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11746 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pCtx, pCtx->ecx,
11747 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11748 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pCtx); break;
11749 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pCtx); break;
11750 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pCtx); break;
11751 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pCtx); break;
11752 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pCtx); break;
11753 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pCtx); break;
11754 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pCtx); break;
11755 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pCtx); break;
11756 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pCtx); break;
11757 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pCtx); break;
11758 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pCtx); break;
11759 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pCtx); break;
11760 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pCtx); break;
11761 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pCtx); break;
11762 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pCtx); break;
11763 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pCtx); break;
11764 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pCtx); break;
11765 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pCtx); break;
11766 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pCtx); break;
11767 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pCtx); break;
11768 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pCtx); break;
11769 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pCtx); break;
11770 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pCtx); break;
11771 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pCtx); break;
11772 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pCtx); break;
11773 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pCtx); break;
11774 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pCtx); break;
11775 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pCtx); break;
11776 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pCtx); break;
11777 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pCtx); break;
11778 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pCtx); break;
11779 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pCtx); break;
11780 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
11781 }
11782 switch (enmEvent2)
11783 {
11784 /** @todo consider which extra parameters would be helpful for each probe. */
11785 case DBGFEVENT_END: break;
11786 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pCtx); break;
11787 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11788 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pCtx); break;
11789 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pCtx); break;
11790 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pCtx); break;
11791 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pCtx); break;
11792 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pCtx); break;
11793 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pCtx); break;
11794 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pCtx); break;
11795 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11796 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11797 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11798 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11799 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11800 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pCtx, pCtx->ecx,
11801 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11802 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pCtx); break;
11803 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pCtx); break;
11804 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pCtx); break;
11805 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pCtx); break;
11806 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pCtx); break;
11807 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pCtx); break;
11808 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pCtx); break;
11809 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pCtx); break;
11810 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pCtx); break;
11811 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pCtx); break;
11812 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pCtx); break;
11813 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pCtx); break;
11814 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pCtx); break;
11815 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pCtx); break;
11816 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pCtx); break;
11817 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pCtx); break;
11818 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pCtx); break;
11819 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pCtx); break;
11820 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pCtx); break;
11821 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pCtx); break;
11822 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pCtx); break;
11823 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pCtx); break;
11824 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pCtx); break;
11825 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pCtx); break;
11826 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pCtx); break;
11827 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pCtx); break;
11828 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pCtx); break;
11829 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pCtx); break;
11830 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pCtx); break;
11831 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pCtx); break;
11832 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pCtx); break;
11833 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pCtx); break;
11834 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pCtx); break;
11835 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pCtx); break;
11836 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pCtx); break;
11837 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pCtx); break;
11838 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
11839 }
11840 }
11841
11842 /*
11843 * Fire of the DBGF event, if enabled (our check here is just a quick one,
11844 * the DBGF call will do a full check).
11845 *
11846 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
11847 * Note! If we have to events, we prioritize the first, i.e. the instruction
11848 * one, in order to avoid event nesting.
11849 */
11850 PVM pVM = pVCpu->CTX_SUFF(pVM);
11851 if ( enmEvent1 != DBGFEVENT_END
11852 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
11853 {
11854 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11855 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent1, DBGFEVENTCTX_HM, 1, uEventArg);
11856 if (rcStrict != VINF_SUCCESS)
11857 return rcStrict;
11858 }
11859 else if ( enmEvent2 != DBGFEVENT_END
11860 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
11861 {
11862 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11863 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent2, DBGFEVENTCTX_HM, 1, uEventArg);
11864 if (rcStrict != VINF_SUCCESS)
11865 return rcStrict;
11866 }
11867
11868 return VINF_SUCCESS;
11869}
11870
11871
11872/**
11873 * Single-stepping VM-exit filtering.
11874 *
11875 * This is preprocessing the VM-exits and deciding whether we've gotten far
11876 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
11877 * handling is performed.
11878 *
11879 * @returns Strict VBox status code (i.e. informational status codes too).
11880 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
11881 * @param pVmxTransient The VMX-transient structure.
11882 * @param pDbgState The debug state.
11883 */
11884DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11885{
11886 /*
11887 * Expensive (saves context) generic dtrace VM-exit probe.
11888 */
11889 uint32_t const uExitReason = pVmxTransient->uExitReason;
11890 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
11891 { /* more likely */ }
11892 else
11893 {
11894 hmR0VmxReadExitQualVmcs(pVmxTransient);
11895 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
11896 AssertRC(rc);
11897 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, &pVCpu->cpum.GstCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
11898 }
11899
11900 /*
11901 * Check for host NMI, just to get that out of the way.
11902 */
11903 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
11904 { /* normally likely */ }
11905 else
11906 {
11907 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
11908 uint32_t const uIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
11909 if (uIntType == VMX_EXIT_INT_INFO_TYPE_NMI)
11910 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
11911 }
11912
11913 /*
11914 * Check for single stepping event if we're stepping.
11915 */
11916 if (pVCpu->hm.s.fSingleInstruction)
11917 {
11918 switch (uExitReason)
11919 {
11920 case VMX_EXIT_MTF:
11921 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
11922
11923 /* Various events: */
11924 case VMX_EXIT_XCPT_OR_NMI:
11925 case VMX_EXIT_EXT_INT:
11926 case VMX_EXIT_TRIPLE_FAULT:
11927 case VMX_EXIT_INT_WINDOW:
11928 case VMX_EXIT_NMI_WINDOW:
11929 case VMX_EXIT_TASK_SWITCH:
11930 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11931 case VMX_EXIT_APIC_ACCESS:
11932 case VMX_EXIT_EPT_VIOLATION:
11933 case VMX_EXIT_EPT_MISCONFIG:
11934 case VMX_EXIT_PREEMPT_TIMER:
11935
11936 /* Instruction specific VM-exits: */
11937 case VMX_EXIT_CPUID:
11938 case VMX_EXIT_GETSEC:
11939 case VMX_EXIT_HLT:
11940 case VMX_EXIT_INVD:
11941 case VMX_EXIT_INVLPG:
11942 case VMX_EXIT_RDPMC:
11943 case VMX_EXIT_RDTSC:
11944 case VMX_EXIT_RSM:
11945 case VMX_EXIT_VMCALL:
11946 case VMX_EXIT_VMCLEAR:
11947 case VMX_EXIT_VMLAUNCH:
11948 case VMX_EXIT_VMPTRLD:
11949 case VMX_EXIT_VMPTRST:
11950 case VMX_EXIT_VMREAD:
11951 case VMX_EXIT_VMRESUME:
11952 case VMX_EXIT_VMWRITE:
11953 case VMX_EXIT_VMXOFF:
11954 case VMX_EXIT_VMXON:
11955 case VMX_EXIT_MOV_CRX:
11956 case VMX_EXIT_MOV_DRX:
11957 case VMX_EXIT_IO_INSTR:
11958 case VMX_EXIT_RDMSR:
11959 case VMX_EXIT_WRMSR:
11960 case VMX_EXIT_MWAIT:
11961 case VMX_EXIT_MONITOR:
11962 case VMX_EXIT_PAUSE:
11963 case VMX_EXIT_GDTR_IDTR_ACCESS:
11964 case VMX_EXIT_LDTR_TR_ACCESS:
11965 case VMX_EXIT_INVEPT:
11966 case VMX_EXIT_RDTSCP:
11967 case VMX_EXIT_INVVPID:
11968 case VMX_EXIT_WBINVD:
11969 case VMX_EXIT_XSETBV:
11970 case VMX_EXIT_RDRAND:
11971 case VMX_EXIT_INVPCID:
11972 case VMX_EXIT_VMFUNC:
11973 case VMX_EXIT_RDSEED:
11974 case VMX_EXIT_XSAVES:
11975 case VMX_EXIT_XRSTORS:
11976 {
11977 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11978 AssertRCReturn(rc, rc);
11979 if ( pVCpu->cpum.GstCtx.rip != pDbgState->uRipStart
11980 || pVCpu->cpum.GstCtx.cs.Sel != pDbgState->uCsStart)
11981 return VINF_EM_DBG_STEPPED;
11982 break;
11983 }
11984
11985 /* Errors and unexpected events: */
11986 case VMX_EXIT_INIT_SIGNAL:
11987 case VMX_EXIT_SIPI:
11988 case VMX_EXIT_IO_SMI:
11989 case VMX_EXIT_SMI:
11990 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
11991 case VMX_EXIT_ERR_MSR_LOAD:
11992 case VMX_EXIT_ERR_MACHINE_CHECK:
11993 case VMX_EXIT_PML_FULL:
11994 case VMX_EXIT_VIRTUALIZED_EOI:
11995 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
11996 break;
11997
11998 default:
11999 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12000 break;
12001 }
12002 }
12003
12004 /*
12005 * Check for debugger event breakpoints and dtrace probes.
12006 */
12007 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
12008 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
12009 {
12010 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVCpu, pVmxTransient, uExitReason);
12011 if (rcStrict != VINF_SUCCESS)
12012 return rcStrict;
12013 }
12014
12015 /*
12016 * Normal processing.
12017 */
12018#ifdef HMVMX_USE_FUNCTION_TABLE
12019 return g_apfnVMExitHandlers[uExitReason](pVCpu, pVmxTransient);
12020#else
12021 return hmR0VmxHandleExit(pVCpu, pVmxTransient, uExitReason);
12022#endif
12023}
12024
12025
12026/**
12027 * Single steps guest code using hardware-assisted VMX.
12028 *
12029 * This is -not- the same as the guest single-stepping itself (say using EFLAGS.TF)
12030 * but single-stepping through the hypervisor debugger.
12031 *
12032 * @returns Strict VBox status code (i.e. informational status codes too).
12033 * @param pVCpu The cross context virtual CPU structure.
12034 * @param pcLoops Pointer to the number of executed loops.
12035 *
12036 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
12037 */
12038static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVMCPU pVCpu, uint32_t *pcLoops)
12039{
12040 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
12041 Assert(pcLoops);
12042 Assert(*pcLoops <= cMaxResumeLoops);
12043
12044 VMXTRANSIENT VmxTransient;
12045 RT_ZERO(VmxTransient);
12046 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
12047
12048 /* Set HMCPU indicators. */
12049 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
12050 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
12051 pVCpu->hm.s.fDebugWantRdTscExit = false;
12052 pVCpu->hm.s.fUsingDebugLoop = true;
12053
12054 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
12055 VMXRUNDBGSTATE DbgState;
12056 hmR0VmxRunDebugStateInit(pVCpu, &VmxTransient, &DbgState);
12057 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12058
12059 /*
12060 * The loop.
12061 */
12062 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
12063 for (;;)
12064 {
12065 Assert(!HMR0SuspendPending());
12066 HMVMX_ASSERT_CPU_SAFE(pVCpu);
12067 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
12068 bool fStepping = pVCpu->hm.s.fSingleInstruction;
12069
12070 /* Set up VM-execution controls the next two can respond to. */
12071 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12072
12073 /*
12074 * Preparatory work for running guest code, this may force us to
12075 * return to ring-3.
12076 *
12077 * Warning! This bugger disables interrupts on VINF_SUCCESS!
12078 */
12079 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, fStepping);
12080 if (rcStrict != VINF_SUCCESS)
12081 break;
12082
12083 /* Interrupts are disabled at this point! */
12084 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
12085
12086 /* Override any obnoxious code in the above two calls. */
12087 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12088
12089 /*
12090 * Finally execute the guest.
12091 */
12092 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
12093
12094 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
12095 /* Interrupts are re-enabled at this point! */
12096
12097 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
12098 if (RT_SUCCESS(rcRun))
12099 { /* very likely */ }
12100 else
12101 {
12102 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
12103 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
12104 return rcRun;
12105 }
12106
12107 /* Profile the VM-exit. */
12108 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
12109 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
12110 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
12111 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
12112 HMVMX_START_EXIT_DISPATCH_PROF();
12113
12114 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
12115
12116 /*
12117 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
12118 */
12119 rcStrict = hmR0VmxRunDebugHandleExit(pVCpu, &VmxTransient, &DbgState);
12120 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
12121 if (rcStrict != VINF_SUCCESS)
12122 break;
12123 if (++(*pcLoops) > cMaxResumeLoops)
12124 {
12125 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
12126 rcStrict = VINF_EM_RAW_INTERRUPT;
12127 break;
12128 }
12129
12130 /*
12131 * Stepping: Did the RIP change, if so, consider it a single step.
12132 * Otherwise, make sure one of the TFs gets set.
12133 */
12134 if (fStepping)
12135 {
12136 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12137 AssertRC(rc);
12138 if ( pVCpu->cpum.GstCtx.rip != DbgState.uRipStart
12139 || pVCpu->cpum.GstCtx.cs.Sel != DbgState.uCsStart)
12140 {
12141 rcStrict = VINF_EM_DBG_STEPPED;
12142 break;
12143 }
12144 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
12145 }
12146
12147 /*
12148 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
12149 */
12150 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
12151 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12152 }
12153
12154 /*
12155 * Clear the X86_EFL_TF if necessary.
12156 */
12157 if (pVCpu->hm.s.fClearTrapFlag)
12158 {
12159 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
12160 AssertRC(rc);
12161 pVCpu->hm.s.fClearTrapFlag = false;
12162 pVCpu->cpum.GstCtx.eflags.Bits.u1TF = 0;
12163 }
12164 /** @todo there seems to be issues with the resume flag when the monitor trap
12165 * flag is pending without being used. Seen early in bios init when
12166 * accessing APIC page in protected mode. */
12167
12168 /*
12169 * Restore VM-exit control settings as we may not re-enter this function the
12170 * next time around.
12171 */
12172 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &VmxTransient, &DbgState, rcStrict);
12173
12174 /* Restore HMCPU indicators. */
12175 pVCpu->hm.s.fUsingDebugLoop = false;
12176 pVCpu->hm.s.fDebugWantRdTscExit = false;
12177 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
12178
12179 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
12180 return rcStrict;
12181}
12182
12183
12184/** @} */
12185
12186
12187/**
12188 * Checks if any expensive dtrace probes are enabled and we should go to the
12189 * debug loop.
12190 *
12191 * @returns true if we should use debug loop, false if not.
12192 */
12193static bool hmR0VmxAnyExpensiveProbesEnabled(void)
12194{
12195 /* It's probably faster to OR the raw 32-bit counter variables together.
12196 Since the variables are in an array and the probes are next to one
12197 another (more or less), we have good locality. So, better read
12198 eight-nine cache lines ever time and only have one conditional, than
12199 128+ conditionals, right? */
12200 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
12201 | VBOXVMM_XCPT_DE_ENABLED_RAW()
12202 | VBOXVMM_XCPT_DB_ENABLED_RAW()
12203 | VBOXVMM_XCPT_BP_ENABLED_RAW()
12204 | VBOXVMM_XCPT_OF_ENABLED_RAW()
12205 | VBOXVMM_XCPT_BR_ENABLED_RAW()
12206 | VBOXVMM_XCPT_UD_ENABLED_RAW()
12207 | VBOXVMM_XCPT_NM_ENABLED_RAW()
12208 | VBOXVMM_XCPT_DF_ENABLED_RAW()
12209 | VBOXVMM_XCPT_TS_ENABLED_RAW()
12210 | VBOXVMM_XCPT_NP_ENABLED_RAW()
12211 | VBOXVMM_XCPT_SS_ENABLED_RAW()
12212 | VBOXVMM_XCPT_GP_ENABLED_RAW()
12213 | VBOXVMM_XCPT_PF_ENABLED_RAW()
12214 | VBOXVMM_XCPT_MF_ENABLED_RAW()
12215 | VBOXVMM_XCPT_AC_ENABLED_RAW()
12216 | VBOXVMM_XCPT_XF_ENABLED_RAW()
12217 | VBOXVMM_XCPT_VE_ENABLED_RAW()
12218 | VBOXVMM_XCPT_SX_ENABLED_RAW()
12219 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
12220 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
12221 ) != 0
12222 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
12223 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
12224 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
12225 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
12226 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
12227 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
12228 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
12229 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
12230 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
12231 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
12232 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
12233 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
12234 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
12235 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
12236 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
12237 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
12238 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
12239 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
12240 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
12241 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
12242 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
12243 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
12244 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
12245 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
12246 | VBOXVMM_INSTR_STR_ENABLED_RAW()
12247 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
12248 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
12249 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
12250 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
12251 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
12252 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
12253 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
12254 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
12255 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
12256 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
12257 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
12258 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
12259 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
12260 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
12261 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
12262 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
12263 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
12264 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
12265 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
12266 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
12267 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
12268 ) != 0
12269 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
12270 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
12271 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
12272 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
12273 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
12274 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
12275 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
12276 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
12277 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
12278 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
12279 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
12280 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
12281 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
12282 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
12283 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
12284 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
12285 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
12286 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
12287 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
12288 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
12289 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
12290 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
12291 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
12292 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
12293 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
12294 | VBOXVMM_EXIT_STR_ENABLED_RAW()
12295 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
12296 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
12297 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
12298 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
12299 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
12300 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
12301 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
12302 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
12303 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
12304 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
12305 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
12306 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
12307 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
12308 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
12309 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
12310 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
12311 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
12312 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
12313 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
12314 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
12315 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
12316 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
12317 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
12318 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
12319 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
12320 ) != 0;
12321}
12322
12323
12324/**
12325 * Runs the guest using hardware-assisted VMX.
12326 *
12327 * @returns Strict VBox status code (i.e. informational status codes too).
12328 * @param pVCpu The cross context virtual CPU structure.
12329 */
12330VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVMCPU pVCpu)
12331{
12332 AssertPtr(pVCpu);
12333 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12334 Assert(VMMRZCallRing3IsEnabled(pVCpu));
12335 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12336 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
12337
12338 VMMRZCallRing3SetNotification(pVCpu, hmR0VmxCallRing3Callback, pCtx);
12339
12340 VBOXSTRICTRC rcStrict;
12341 uint32_t cLoops = 0;
12342 for (;;)
12343 {
12344#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12345 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(pCtx);
12346#else
12347 bool const fInNestedGuestMode = false;
12348#endif
12349 if (!fInNestedGuestMode)
12350 {
12351 if ( !pVCpu->hm.s.fUseDebugLoop
12352 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
12353 && !DBGFIsStepping(pVCpu)
12354 && !pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
12355 rcStrict = hmR0VmxRunGuestCodeNormal(pVCpu, &cLoops);
12356 else
12357 rcStrict = hmR0VmxRunGuestCodeDebug(pVCpu, &cLoops);
12358 }
12359#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12360 else
12361 rcStrict = hmR0VmxRunGuestCodeNested(pVCpu, &cLoops);
12362
12363 if (rcStrict == VINF_VMX_VMLAUNCH_VMRESUME)
12364 {
12365 Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
12366 continue;
12367 }
12368 if (rcStrict == VINF_VMX_VMEXIT)
12369 {
12370 Assert(!CPUMIsGuestInVmxNonRootMode(pCtx));
12371 continue;
12372 }
12373#endif
12374 break;
12375 }
12376
12377 int const rcLoop = VBOXSTRICTRC_VAL(rcStrict);
12378 switch (rcLoop)
12379 {
12380 case VERR_EM_INTERPRETER: rcStrict = VINF_EM_RAW_EMULATE_INSTR; break;
12381 case VINF_EM_RESET: rcStrict = VINF_EM_TRIPLE_FAULT; break;
12382 }
12383
12384 int rc2 = hmR0VmxExitToRing3(pVCpu, rcStrict);
12385 if (RT_FAILURE(rc2))
12386 {
12387 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
12388 rcStrict = rc2;
12389 }
12390 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12391 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
12392 return rcStrict;
12393}
12394
12395
12396#ifndef HMVMX_USE_FUNCTION_TABLE
12397/**
12398 * Handles a guest VM-exit from hardware-assisted VMX execution.
12399 *
12400 * @returns Strict VBox status code (i.e. informational status codes too).
12401 * @param pVCpu The cross context virtual CPU structure.
12402 * @param pVmxTransient The VMX-transient structure.
12403 */
12404DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
12405{
12406#ifdef DEBUG_ramshankar
12407#define VMEXIT_CALL_RET(a_fSave, a_CallExpr) \
12408 do { \
12409 if (a_fSave != 0) \
12410 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL); \
12411 VBOXSTRICTRC rcStrict = a_CallExpr; \
12412 if (a_fSave != 0) \
12413 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST); \
12414 return rcStrict; \
12415 } while (0)
12416#else
12417# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) return a_CallExpr
12418#endif
12419 uint32_t const uExitReason = pVmxTransient->uExitReason;
12420 switch (uExitReason)
12421 {
12422 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient));
12423 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, hmR0VmxExitEptViolation(pVCpu, pVmxTransient));
12424 case VMX_EXIT_IO_INSTR: VMEXIT_CALL_RET(0, hmR0VmxExitIoInstr(pVCpu, pVmxTransient));
12425 case VMX_EXIT_CPUID: VMEXIT_CALL_RET(0, hmR0VmxExitCpuid(pVCpu, pVmxTransient));
12426 case VMX_EXIT_RDTSC: VMEXIT_CALL_RET(0, hmR0VmxExitRdtsc(pVCpu, pVmxTransient));
12427 case VMX_EXIT_RDTSCP: VMEXIT_CALL_RET(0, hmR0VmxExitRdtscp(pVCpu, pVmxTransient));
12428 case VMX_EXIT_APIC_ACCESS: VMEXIT_CALL_RET(0, hmR0VmxExitApicAccess(pVCpu, pVmxTransient));
12429 case VMX_EXIT_XCPT_OR_NMI: VMEXIT_CALL_RET(0, hmR0VmxExitXcptOrNmi(pVCpu, pVmxTransient));
12430 case VMX_EXIT_MOV_CRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovCRx(pVCpu, pVmxTransient));
12431 case VMX_EXIT_EXT_INT: VMEXIT_CALL_RET(0, hmR0VmxExitExtInt(pVCpu, pVmxTransient));
12432 case VMX_EXIT_INT_WINDOW: VMEXIT_CALL_RET(0, hmR0VmxExitIntWindow(pVCpu, pVmxTransient));
12433 case VMX_EXIT_TPR_BELOW_THRESHOLD: VMEXIT_CALL_RET(0, hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient));
12434 case VMX_EXIT_MWAIT: VMEXIT_CALL_RET(0, hmR0VmxExitMwait(pVCpu, pVmxTransient));
12435 case VMX_EXIT_MONITOR: VMEXIT_CALL_RET(0, hmR0VmxExitMonitor(pVCpu, pVmxTransient));
12436 case VMX_EXIT_TASK_SWITCH: VMEXIT_CALL_RET(0, hmR0VmxExitTaskSwitch(pVCpu, pVmxTransient));
12437 case VMX_EXIT_PREEMPT_TIMER: VMEXIT_CALL_RET(0, hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient));
12438 case VMX_EXIT_RDMSR: VMEXIT_CALL_RET(0, hmR0VmxExitRdmsr(pVCpu, pVmxTransient));
12439 case VMX_EXIT_WRMSR: VMEXIT_CALL_RET(0, hmR0VmxExitWrmsr(pVCpu, pVmxTransient));
12440 case VMX_EXIT_VMCALL: VMEXIT_CALL_RET(0, hmR0VmxExitVmcall(pVCpu, pVmxTransient));
12441 case VMX_EXIT_MOV_DRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovDRx(pVCpu, pVmxTransient));
12442 case VMX_EXIT_HLT: VMEXIT_CALL_RET(0, hmR0VmxExitHlt(pVCpu, pVmxTransient));
12443 case VMX_EXIT_INVD: VMEXIT_CALL_RET(0, hmR0VmxExitInvd(pVCpu, pVmxTransient));
12444 case VMX_EXIT_INVLPG: VMEXIT_CALL_RET(0, hmR0VmxExitInvlpg(pVCpu, pVmxTransient));
12445 case VMX_EXIT_MTF: VMEXIT_CALL_RET(0, hmR0VmxExitMtf(pVCpu, pVmxTransient));
12446 case VMX_EXIT_PAUSE: VMEXIT_CALL_RET(0, hmR0VmxExitPause(pVCpu, pVmxTransient));
12447 case VMX_EXIT_WBINVD: VMEXIT_CALL_RET(0, hmR0VmxExitWbinvd(pVCpu, pVmxTransient));
12448 case VMX_EXIT_XSETBV: VMEXIT_CALL_RET(0, hmR0VmxExitXsetbv(pVCpu, pVmxTransient));
12449 case VMX_EXIT_INVPCID: VMEXIT_CALL_RET(0, hmR0VmxExitInvpcid(pVCpu, pVmxTransient));
12450 case VMX_EXIT_GETSEC: VMEXIT_CALL_RET(0, hmR0VmxExitGetsec(pVCpu, pVmxTransient));
12451 case VMX_EXIT_RDPMC: VMEXIT_CALL_RET(0, hmR0VmxExitRdpmc(pVCpu, pVmxTransient));
12452#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12453 case VMX_EXIT_VMCLEAR: VMEXIT_CALL_RET(0, hmR0VmxExitVmclear(pVCpu, pVmxTransient));
12454 case VMX_EXIT_VMLAUNCH: VMEXIT_CALL_RET(0, hmR0VmxExitVmlaunch(pVCpu, pVmxTransient));
12455 case VMX_EXIT_VMPTRLD: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrld(pVCpu, pVmxTransient));
12456 case VMX_EXIT_VMPTRST: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrst(pVCpu, pVmxTransient));
12457 case VMX_EXIT_VMREAD: VMEXIT_CALL_RET(0, hmR0VmxExitVmread(pVCpu, pVmxTransient));
12458 case VMX_EXIT_VMRESUME: VMEXIT_CALL_RET(0, hmR0VmxExitVmwrite(pVCpu, pVmxTransient));
12459 case VMX_EXIT_VMWRITE: VMEXIT_CALL_RET(0, hmR0VmxExitVmresume(pVCpu, pVmxTransient));
12460 case VMX_EXIT_VMXOFF: VMEXIT_CALL_RET(0, hmR0VmxExitVmxoff(pVCpu, pVmxTransient));
12461 case VMX_EXIT_VMXON: VMEXIT_CALL_RET(0, hmR0VmxExitVmxon(pVCpu, pVmxTransient));
12462 case VMX_EXIT_INVVPID: VMEXIT_CALL_RET(0, hmR0VmxExitInvvpid(pVCpu, pVmxTransient));
12463 case VMX_EXIT_INVEPT: VMEXIT_CALL_RET(0, hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient));
12464#else
12465 case VMX_EXIT_VMCLEAR:
12466 case VMX_EXIT_VMLAUNCH:
12467 case VMX_EXIT_VMPTRLD:
12468 case VMX_EXIT_VMPTRST:
12469 case VMX_EXIT_VMREAD:
12470 case VMX_EXIT_VMRESUME:
12471 case VMX_EXIT_VMWRITE:
12472 case VMX_EXIT_VMXOFF:
12473 case VMX_EXIT_VMXON:
12474 case VMX_EXIT_INVVPID:
12475 case VMX_EXIT_INVEPT:
12476 return hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient);
12477#endif
12478
12479 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pVmxTransient);
12480 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pVmxTransient);
12481 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
12482
12483 case VMX_EXIT_INIT_SIGNAL:
12484 case VMX_EXIT_SIPI:
12485 case VMX_EXIT_IO_SMI:
12486 case VMX_EXIT_SMI:
12487 case VMX_EXIT_ERR_MSR_LOAD:
12488 case VMX_EXIT_ERR_MACHINE_CHECK:
12489 case VMX_EXIT_PML_FULL:
12490 case VMX_EXIT_VIRTUALIZED_EOI:
12491 case VMX_EXIT_GDTR_IDTR_ACCESS:
12492 case VMX_EXIT_LDTR_TR_ACCESS:
12493 case VMX_EXIT_APIC_WRITE:
12494 case VMX_EXIT_RDRAND:
12495 case VMX_EXIT_RSM:
12496 case VMX_EXIT_VMFUNC:
12497 case VMX_EXIT_ENCLS:
12498 case VMX_EXIT_RDSEED:
12499 case VMX_EXIT_XSAVES:
12500 case VMX_EXIT_XRSTORS:
12501 case VMX_EXIT_UMWAIT:
12502 case VMX_EXIT_TPAUSE:
12503 default:
12504 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
12505 }
12506#undef VMEXIT_CALL_RET
12507}
12508#endif /* !HMVMX_USE_FUNCTION_TABLE */
12509
12510
12511#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12512/**
12513 * Handles a nested-guest VM-exit from hardware-assisted VMX execution.
12514 *
12515 * @returns Strict VBox status code (i.e. informational status codes too).
12516 * @param pVCpu The cross context virtual CPU structure.
12517 * @param pVmxTransient The VMX-transient structure.
12518 */
12519DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
12520{
12521 uint32_t const uExitReason = pVmxTransient->uExitReason;
12522 switch (uExitReason)
12523 {
12524 case VMX_EXIT_EPT_MISCONFIG: return hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient);
12525 case VMX_EXIT_EPT_VIOLATION: return hmR0VmxExitEptViolation(pVCpu, pVmxTransient);
12526 case VMX_EXIT_XCPT_OR_NMI: return hmR0VmxExitXcptOrNmiNested(pVCpu, pVmxTransient);
12527 case VMX_EXIT_IO_INSTR: return hmR0VmxExitIoInstrNested(pVCpu, pVmxTransient);
12528 case VMX_EXIT_HLT: return hmR0VmxExitHltNested(pVCpu, pVmxTransient);
12529
12530 /*
12531 * We shouldn't direct host physical interrupts to the nested-guest.
12532 */
12533 case VMX_EXIT_EXT_INT:
12534 return hmR0VmxExitExtInt(pVCpu, pVmxTransient);
12535
12536 /*
12537 * Instructions that cause VM-exits unconditionally or the condition is
12538 * always is taken solely from the guest hypervisor (meaning if the VM-exit
12539 * happens, it's guaranteed to be a nested-guest VM-exit).
12540 *
12541 * - Provides VM-exit instruction length ONLY.
12542 */
12543 case VMX_EXIT_CPUID: /* Unconditional. */
12544 case VMX_EXIT_VMCALL:
12545 case VMX_EXIT_GETSEC:
12546 case VMX_EXIT_INVD:
12547 case VMX_EXIT_XSETBV:
12548 case VMX_EXIT_VMLAUNCH:
12549 case VMX_EXIT_VMRESUME:
12550 case VMX_EXIT_VMXOFF:
12551 case VMX_EXIT_ENCLS: /* Condition specified solely by guest hypervisor. */
12552 case VMX_EXIT_VMFUNC:
12553 return hmR0VmxExitInstrNested(pVCpu, pVmxTransient);
12554
12555 /*
12556 * Instructions that cause VM-exits unconditionally or the condition is
12557 * always is taken solely from the guest hypervisor (meaning if the VM-exit
12558 * happens, it's guaranteed to be a nested-guest VM-exit).
12559 *
12560 * - Provides VM-exit instruction length.
12561 * - Provides VM-exit information.
12562 * - Optionally provides Exit qualification.
12563 *
12564 * Since Exit qualification is 0 for all VM-exits where it is not
12565 * applicable, reading and passing it to the guest should produce
12566 * defined behavior.
12567 *
12568 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
12569 */
12570 case VMX_EXIT_INVEPT: /* Unconditional. */
12571 case VMX_EXIT_INVVPID:
12572 case VMX_EXIT_VMCLEAR:
12573 case VMX_EXIT_VMPTRLD:
12574 case VMX_EXIT_VMPTRST:
12575 case VMX_EXIT_VMXON:
12576 case VMX_EXIT_GDTR_IDTR_ACCESS: /* Condition specified solely by guest hypervisor. */
12577 case VMX_EXIT_LDTR_TR_ACCESS:
12578 case VMX_EXIT_RDRAND:
12579 case VMX_EXIT_RDSEED:
12580 case VMX_EXIT_XSAVES:
12581 case VMX_EXIT_XRSTORS:
12582 case VMX_EXIT_UMWAIT:
12583 case VMX_EXIT_TPAUSE:
12584 return hmR0VmxExitInstrWithInfoNested(pVCpu, pVmxTransient);
12585
12586 case VMX_EXIT_RDTSC: return hmR0VmxExitRdtscNested(pVCpu, pVmxTransient);
12587 case VMX_EXIT_RDTSCP: return hmR0VmxExitRdtscpNested(pVCpu, pVmxTransient);
12588 case VMX_EXIT_RDMSR: return hmR0VmxExitRdmsrNested(pVCpu, pVmxTransient);
12589 case VMX_EXIT_WRMSR: return hmR0VmxExitWrmsrNested(pVCpu, pVmxTransient);
12590 case VMX_EXIT_INVLPG: return hmR0VmxExitInvlpgNested(pVCpu, pVmxTransient);
12591 case VMX_EXIT_INVPCID: return hmR0VmxExitInvpcidNested(pVCpu, pVmxTransient);
12592 case VMX_EXIT_TASK_SWITCH: return hmR0VmxExitTaskSwitchNested(pVCpu, pVmxTransient);
12593 case VMX_EXIT_WBINVD: return hmR0VmxExitWbinvdNested(pVCpu, pVmxTransient);
12594 case VMX_EXIT_MTF: return hmR0VmxExitMtfNested(pVCpu, pVmxTransient);
12595 case VMX_EXIT_APIC_ACCESS: return hmR0VmxExitApicAccessNested(pVCpu, pVmxTransient);
12596 case VMX_EXIT_APIC_WRITE: return hmR0VmxExitApicWriteNested(pVCpu, pVmxTransient);
12597 case VMX_EXIT_VIRTUALIZED_EOI: return hmR0VmxExitVirtEoiNested(pVCpu, pVmxTransient);
12598 case VMX_EXIT_MOV_CRX: return hmR0VmxExitMovCRxNested(pVCpu, pVmxTransient);
12599 case VMX_EXIT_INT_WINDOW: return hmR0VmxExitIntWindowNested(pVCpu, pVmxTransient);
12600 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindowNested(pVCpu, pVmxTransient);
12601 case VMX_EXIT_TPR_BELOW_THRESHOLD: return hmR0VmxExitTprBelowThresholdNested(pVCpu, pVmxTransient);
12602 case VMX_EXIT_MWAIT: return hmR0VmxExitMwaitNested(pVCpu, pVmxTransient);
12603 case VMX_EXIT_MONITOR: return hmR0VmxExitMonitorNested(pVCpu, pVmxTransient);
12604 case VMX_EXIT_PAUSE: return hmR0VmxExitPauseNested(pVCpu, pVmxTransient);
12605
12606 case VMX_EXIT_PREEMPT_TIMER:
12607 {
12608 /** @todo NSTVMX: Preempt timer. */
12609 return hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient);
12610 }
12611
12612 case VMX_EXIT_MOV_DRX: return hmR0VmxExitMovDRxNested(pVCpu, pVmxTransient);
12613 case VMX_EXIT_RDPMC: return hmR0VmxExitRdpmcNested(pVCpu, pVmxTransient);
12614
12615 case VMX_EXIT_VMREAD:
12616 case VMX_EXIT_VMWRITE: return hmR0VmxExitVmreadVmwriteNested(pVCpu, pVmxTransient);
12617
12618 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFaultNested(pVCpu, pVmxTransient);
12619 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestStateNested(pVCpu, pVmxTransient);
12620
12621 case VMX_EXIT_INIT_SIGNAL:
12622 case VMX_EXIT_SIPI:
12623 case VMX_EXIT_IO_SMI:
12624 case VMX_EXIT_SMI:
12625 case VMX_EXIT_ERR_MSR_LOAD:
12626 case VMX_EXIT_ERR_MACHINE_CHECK:
12627 case VMX_EXIT_PML_FULL:
12628 case VMX_EXIT_RSM:
12629 default:
12630 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
12631 }
12632}
12633#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
12634
12635
12636/** @name VM-exit helpers.
12637 * @{
12638 */
12639/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12640/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= VM-exit helpers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
12641/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12642
12643/** Macro for VM-exits called unexpectedly. */
12644#define HMVMX_UNEXPECTED_EXIT_RET(a_pVCpu, a_HmError) \
12645 do { \
12646 (a_pVCpu)->hm.s.u32HMError = (a_HmError); \
12647 return VERR_VMX_UNEXPECTED_EXIT; \
12648 } while (0)
12649
12650#ifdef VBOX_STRICT
12651/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
12652# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
12653 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
12654
12655# define HMVMX_ASSERT_PREEMPT_CPUID() \
12656 do { \
12657 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
12658 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
12659 } while (0)
12660
12661# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12662 do { \
12663 AssertPtr((a_pVCpu)); \
12664 AssertPtr((a_pVmxTransient)); \
12665 Assert((a_pVmxTransient)->fVMEntryFailed == false); \
12666 Assert((a_pVmxTransient)->pVmcsInfo); \
12667 Assert(ASMIntAreEnabled()); \
12668 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
12669 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
12670 Log4Func(("vcpu[%RU32]\n", (a_pVCpu)->idCpu)); \
12671 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
12672 if (VMMR0IsLogFlushDisabled((a_pVCpu))) \
12673 HMVMX_ASSERT_PREEMPT_CPUID(); \
12674 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
12675 } while (0)
12676
12677# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12678 do { \
12679 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); \
12680 Assert((a_pVmxTransient)->fIsNestedGuest); \
12681 } while (0)
12682
12683# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12684 do { \
12685 Log4Func(("\n")); \
12686 } while (0)
12687#else
12688# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12689 do { \
12690 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
12691 NOREF((a_pVCpu)); NOREF((a_pVmxTransient)); \
12692 } while (0)
12693
12694# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12695 do { HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); } while (0)
12696
12697# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) do { } while (0)
12698#endif
12699
12700#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12701/** Macro that does the necessary privilege checks and intercepted VM-exits for
12702 * guests that attempted to execute a VMX instruction. */
12703# define HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(a_pVCpu, a_uExitReason) \
12704 do \
12705 { \
12706 VBOXSTRICTRC rcStrictTmp = hmR0VmxCheckExitDueToVmxInstr((a_pVCpu), (a_uExitReason)); \
12707 if (rcStrictTmp == VINF_SUCCESS) \
12708 { /* likely */ } \
12709 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
12710 { \
12711 Assert((a_pVCpu)->hm.s.Event.fPending); \
12712 Log4Func(("Privilege checks failed -> %#x\n", VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo))); \
12713 return VINF_SUCCESS; \
12714 } \
12715 else \
12716 { \
12717 int rcTmp = VBOXSTRICTRC_VAL(rcStrictTmp); \
12718 AssertMsgFailedReturn(("Unexpected failure. rc=%Rrc", rcTmp), rcTmp); \
12719 } \
12720 } while (0)
12721
12722/** Macro that decodes a memory operand for an VM-exit caused by an instruction. */
12723# define HMVMX_DECODE_MEM_OPERAND(a_pVCpu, a_uExitInstrInfo, a_uExitQual, a_enmMemAccess, a_pGCPtrEffAddr) \
12724 do \
12725 { \
12726 VBOXSTRICTRC rcStrictTmp = hmR0VmxDecodeMemOperand((a_pVCpu), (a_uExitInstrInfo), (a_uExitQual), (a_enmMemAccess), \
12727 (a_pGCPtrEffAddr)); \
12728 if (rcStrictTmp == VINF_SUCCESS) \
12729 { /* likely */ } \
12730 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
12731 { \
12732 uint8_t const uXcptTmp = VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo); \
12733 Log4Func(("Memory operand decoding failed, raising xcpt %#x\n", uXcptTmp)); \
12734 NOREF(uXcptTmp); \
12735 return VINF_SUCCESS; \
12736 } \
12737 else \
12738 { \
12739 Log4Func(("hmR0VmxDecodeMemOperand failed. rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrictTmp))); \
12740 return rcStrictTmp; \
12741 } \
12742 } while (0)
12743#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
12744
12745
12746/**
12747 * Advances the guest RIP by the specified number of bytes.
12748 *
12749 * @param pVCpu The cross context virtual CPU structure.
12750 * @param cbInstr Number of bytes to advance the RIP by.
12751 *
12752 * @remarks No-long-jump zone!!!
12753 */
12754DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPU pVCpu, uint32_t cbInstr)
12755{
12756 /* Advance the RIP. */
12757 pVCpu->cpum.GstCtx.rip += cbInstr;
12758 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
12759
12760 /* Update interrupt inhibition. */
12761 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
12762 && pVCpu->cpum.GstCtx.rip != EMGetInhibitInterruptsPC(pVCpu))
12763 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
12764}
12765
12766
12767/**
12768 * Advances the guest RIP after reading it from the VMCS.
12769 *
12770 * @returns VBox status code, no informational status codes.
12771 * @param pVCpu The cross context virtual CPU structure.
12772 * @param pVmxTransient The VMX-transient structure.
12773 *
12774 * @remarks No-long-jump zone!!!
12775 */
12776static int hmR0VmxAdvanceGuestRip(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
12777{
12778 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12779 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
12780 AssertRCReturn(rc, rc);
12781
12782 hmR0VmxAdvanceGuestRipBy(pVCpu, pVmxTransient->cbInstr);
12783 return VINF_SUCCESS;
12784}
12785
12786
12787/**
12788 * Handle a condition that occurred while delivering an event through the guest or
12789 * nested-guest IDT.
12790 *
12791 * @returns Strict VBox status code (i.e. informational status codes too).
12792 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
12793 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
12794 * to continue execution of the guest which will delivery the \#DF.
12795 * @retval VINF_EM_RESET if we detected a triple-fault condition.
12796 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
12797 *
12798 * @param pVCpu The cross context virtual CPU structure.
12799 * @param pVmxTransient The VMX-transient structure.
12800 *
12801 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
12802 * Additionally, HMVMX_READ_EXIT_QUALIFICATION is required if the VM-exit
12803 * is due to an EPT violation, PML full or SPP-related event.
12804 *
12805 * @remarks No-long-jump zone!!!
12806 */
12807static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
12808{
12809 Assert(!pVCpu->hm.s.Event.fPending);
12810 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
12811 if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
12812 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
12813 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
12814 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_EXIT_QUALIFICATION);
12815
12816 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
12817 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
12818 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo;
12819 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
12820 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo))
12821 {
12822 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo);
12823 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo);
12824
12825 /*
12826 * If the event was a software interrupt (generated with INT n) or a software exception
12827 * (generated by INT3/INTO) or a privileged software exception (generated by INT1), we
12828 * can handle the VM-exit and continue guest execution which will re-execute the
12829 * instruction rather than re-injecting the exception, as that can cause premature
12830 * trips to ring-3 before injection and involve TRPM which currently has no way of
12831 * storing that these exceptions were caused by these instructions (ICEBP's #DB poses
12832 * the problem).
12833 */
12834 IEMXCPTRAISE enmRaise;
12835 IEMXCPTRAISEINFO fRaiseInfo;
12836 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
12837 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
12838 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
12839 {
12840 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
12841 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
12842 }
12843 else if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo))
12844 {
12845 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
12846 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo);
12847 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT);
12848
12849 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
12850 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
12851
12852 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo);
12853
12854 /* Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF(). */
12855 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
12856 {
12857 pVmxTransient->fVectoringPF = true;
12858 enmRaise = IEMXCPTRAISE_PREV_EVENT;
12859 }
12860 }
12861 else
12862 {
12863 /*
12864 * If an exception or hardware interrupt delivery caused an EPT violation/misconfig or APIC access
12865 * VM-exit, then the VM-exit interruption-information will not be valid and we end up here.
12866 * It is sufficient to reflect the original event to the guest after handling the VM-exit.
12867 */
12868 Assert( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
12869 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
12870 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
12871 enmRaise = IEMXCPTRAISE_PREV_EVENT;
12872 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
12873 }
12874
12875 /*
12876 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
12877 * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
12878 * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
12879 * subsequent VM-entry would fail, see @bugref{7445}.
12880 *
12881 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception".
12882 */
12883 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
12884 && enmRaise == IEMXCPTRAISE_PREV_EVENT
12885 && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
12886 && CPUMIsGuestNmiBlocking(pVCpu))
12887 {
12888 CPUMSetGuestNmiBlocking(pVCpu, false);
12889 }
12890
12891 switch (enmRaise)
12892 {
12893 case IEMXCPTRAISE_CURRENT_XCPT:
12894 {
12895 Log4Func(("IDT: Pending secondary Xcpt: idtinfo=%#RX64 exitinfo=%#RX64\n", uIdtVectorInfo, uExitIntInfo));
12896 Assert(rcStrict == VINF_SUCCESS);
12897 break;
12898 }
12899
12900 case IEMXCPTRAISE_PREV_EVENT:
12901 {
12902 uint32_t u32ErrCode;
12903 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo))
12904 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
12905 else
12906 u32ErrCode = 0;
12907
12908 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
12909 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflect);
12910 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(uIdtVectorInfo), 0 /* cbInstr */,
12911 u32ErrCode, pVCpu->cpum.GstCtx.cr2);
12912
12913 Log4Func(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntInfo,
12914 pVCpu->hm.s.Event.u32ErrCode));
12915 Assert(rcStrict == VINF_SUCCESS);
12916 break;
12917 }
12918
12919 case IEMXCPTRAISE_REEXEC_INSTR:
12920 Assert(rcStrict == VINF_SUCCESS);
12921 break;
12922
12923 case IEMXCPTRAISE_DOUBLE_FAULT:
12924 {
12925 /*
12926 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
12927 * second #PF as a guest #PF (and not a shadow #PF) and needs to be converted into a #DF.
12928 */
12929 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
12930 {
12931 pVmxTransient->fVectoringDoublePF = true;
12932 Log4Func(("IDT: Vectoring double #PF %#RX64 cr2=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo,
12933 pVCpu->cpum.GstCtx.cr2));
12934 rcStrict = VINF_SUCCESS;
12935 }
12936 else
12937 {
12938 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectConvertDF);
12939 hmR0VmxSetPendingXcptDF(pVCpu);
12940 Log4Func(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntInfo,
12941 uIdtVector, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
12942 rcStrict = VINF_HM_DOUBLE_FAULT;
12943 }
12944 break;
12945 }
12946
12947 case IEMXCPTRAISE_TRIPLE_FAULT:
12948 {
12949 Log4Func(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector,
12950 VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
12951 rcStrict = VINF_EM_RESET;
12952 break;
12953 }
12954
12955 case IEMXCPTRAISE_CPU_HANG:
12956 {
12957 Log4Func(("IDT: Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", fRaiseInfo));
12958 rcStrict = VERR_EM_GUEST_CPU_HANG;
12959 break;
12960 }
12961
12962 default:
12963 {
12964 AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
12965 rcStrict = VERR_VMX_IPE_2;
12966 break;
12967 }
12968 }
12969 }
12970 else if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
12971 && !CPUMIsGuestNmiBlocking(pVCpu))
12972 {
12973 if ( VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)
12974 && VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo) != X86_XCPT_DF
12975 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(uExitIntInfo))
12976 {
12977 /*
12978 * Execution of IRET caused a fault when NMI blocking was in effect (i.e we're in
12979 * the guest or nested-guest NMI handler). We need to set the block-by-NMI field so
12980 * that NMIs remain blocked until the IRET execution is completed.
12981 *
12982 * See Intel spec. 31.7.1.2 "Resuming Guest Software After Handling An Exception".
12983 */
12984 CPUMSetGuestNmiBlocking(pVCpu, true);
12985 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
12986 }
12987 else if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
12988 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
12989 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
12990 {
12991 /*
12992 * Execution of IRET caused an EPT violation, page-modification log-full event or
12993 * SPP-related event VM-exit when NMI blocking was in effect (i.e. we're in the
12994 * guest or nested-guest NMI handler). We need to set the block-by-NMI field so
12995 * that NMIs remain blocked until the IRET execution is completed.
12996 *
12997 * See Intel spec. 27.2.3 "Information about NMI unblocking due to IRET"
12998 */
12999 if (VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(pVmxTransient->uExitQual))
13000 {
13001 CPUMSetGuestNmiBlocking(pVCpu, true);
13002 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13003 }
13004 }
13005 }
13006
13007 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
13008 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
13009 return rcStrict;
13010}
13011
13012
13013#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13014/**
13015 * Perform the relevant VMX instruction checks for VM-exits that occurred due to the
13016 * guest attempting to execute a VMX instruction.
13017 *
13018 * @returns Strict VBox status code (i.e. informational status codes too).
13019 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13020 * @retval VINF_HM_PENDING_XCPT if an exception was raised.
13021 *
13022 * @param pVCpu The cross context virtual CPU structure.
13023 * @param uExitReason The VM-exit reason.
13024 *
13025 * @todo NSTVMX: Document other error codes when VM-exit is implemented.
13026 * @remarks No-long-jump zone!!!
13027 */
13028static VBOXSTRICTRC hmR0VmxCheckExitDueToVmxInstr(PVMCPU pVCpu, uint32_t uExitReason)
13029{
13030 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS
13031 | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
13032
13033 /*
13034 * The physical CPU would have already checked the CPU mode/code segment.
13035 * We shall just assert here for paranoia.
13036 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
13037 */
13038 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13039 Assert( !CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx)
13040 || CPUMIsGuestIn64BitCodeEx(&pVCpu->cpum.GstCtx));
13041
13042 if (uExitReason == VMX_EXIT_VMXON)
13043 {
13044 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
13045
13046 /*
13047 * We check CR4.VMXE because it is required to be always set while in VMX operation
13048 * by physical CPUs and our CR4 read-shadow is only consulted when executing specific
13049 * instructions (CLTS, LMSW, MOV CR, and SMSW) and thus doesn't affect CPU operation
13050 * otherwise (i.e. physical CPU won't automatically #UD if Cr4Shadow.VMXE is 0).
13051 */
13052 if (!CPUMIsGuestVmxEnabled(&pVCpu->cpum.GstCtx))
13053 {
13054 Log4Func(("CR4.VMXE is not set -> #UD\n"));
13055 hmR0VmxSetPendingXcptUD(pVCpu);
13056 return VINF_HM_PENDING_XCPT;
13057 }
13058 }
13059 else if (!CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx))
13060 {
13061 /*
13062 * The guest has not entered VMX operation but attempted to execute a VMX instruction
13063 * (other than VMXON), we need to raise a #UD.
13064 */
13065 Log4Func(("Not in VMX root mode -> #UD\n"));
13066 hmR0VmxSetPendingXcptUD(pVCpu);
13067 return VINF_HM_PENDING_XCPT;
13068 }
13069
13070 /* All other checks (including VM-exit intercepts) are handled by IEM instruction emulation. */
13071 return VINF_SUCCESS;
13072}
13073
13074
13075/**
13076 * Decodes the memory operand of an instruction that caused a VM-exit.
13077 *
13078 * The Exit qualification field provides the displacement field for memory
13079 * operand instructions, if any.
13080 *
13081 * @returns Strict VBox status code (i.e. informational status codes too).
13082 * @retval VINF_SUCCESS if the operand was successfully decoded.
13083 * @retval VINF_HM_PENDING_XCPT if an exception was raised while decoding the
13084 * operand.
13085 * @param pVCpu The cross context virtual CPU structure.
13086 * @param uExitInstrInfo The VM-exit instruction information field.
13087 * @param enmMemAccess The memory operand's access type (read or write).
13088 * @param GCPtrDisp The instruction displacement field, if any. For
13089 * RIP-relative addressing pass RIP + displacement here.
13090 * @param pGCPtrMem Where to store the effective destination memory address.
13091 *
13092 * @remarks Warning! This function ASSUMES the instruction cannot be used in real or
13093 * virtual-8086 mode hence skips those checks while verifying if the
13094 * segment is valid.
13095 */
13096static VBOXSTRICTRC hmR0VmxDecodeMemOperand(PVMCPU pVCpu, uint32_t uExitInstrInfo, RTGCPTR GCPtrDisp, VMXMEMACCESS enmMemAccess,
13097 PRTGCPTR pGCPtrMem)
13098{
13099 Assert(pGCPtrMem);
13100 Assert(!CPUMIsGuestInRealOrV86Mode(pVCpu));
13101 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_EFER
13102 | CPUMCTX_EXTRN_CR0);
13103
13104 static uint64_t const s_auAddrSizeMasks[] = { UINT64_C(0xffff), UINT64_C(0xffffffff), UINT64_C(0xffffffffffffffff) };
13105 static uint64_t const s_auAccessSizeMasks[] = { sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t) };
13106 AssertCompile(RT_ELEMENTS(s_auAccessSizeMasks) == RT_ELEMENTS(s_auAddrSizeMasks));
13107
13108 VMXEXITINSTRINFO ExitInstrInfo;
13109 ExitInstrInfo.u = uExitInstrInfo;
13110 uint8_t const uAddrSize = ExitInstrInfo.All.u3AddrSize;
13111 uint8_t const iSegReg = ExitInstrInfo.All.iSegReg;
13112 bool const fIdxRegValid = !ExitInstrInfo.All.fIdxRegInvalid;
13113 uint8_t const iIdxReg = ExitInstrInfo.All.iIdxReg;
13114 uint8_t const uScale = ExitInstrInfo.All.u2Scaling;
13115 bool const fBaseRegValid = !ExitInstrInfo.All.fBaseRegInvalid;
13116 uint8_t const iBaseReg = ExitInstrInfo.All.iBaseReg;
13117 bool const fIsMemOperand = !ExitInstrInfo.All.fIsRegOperand;
13118 bool const fIsLongMode = CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx);
13119
13120 /*
13121 * Validate instruction information.
13122 * This shouldn't happen on real hardware but useful while testing our nested hardware-virtualization code.
13123 */
13124 AssertLogRelMsgReturn(uAddrSize < RT_ELEMENTS(s_auAddrSizeMasks),
13125 ("Invalid address size. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_1);
13126 AssertLogRelMsgReturn(iSegReg < X86_SREG_COUNT,
13127 ("Invalid segment register. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_2);
13128 AssertLogRelMsgReturn(fIsMemOperand,
13129 ("Expected memory operand. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_3);
13130
13131 /*
13132 * Compute the complete effective address.
13133 *
13134 * See AMD instruction spec. 1.4.2 "SIB Byte Format"
13135 * See AMD spec. 4.5.2 "Segment Registers".
13136 */
13137 RTGCPTR GCPtrMem = GCPtrDisp;
13138 if (fBaseRegValid)
13139 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iBaseReg].u64;
13140 if (fIdxRegValid)
13141 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iIdxReg].u64 << uScale;
13142
13143 RTGCPTR const GCPtrOff = GCPtrMem;
13144 if ( !fIsLongMode
13145 || iSegReg >= X86_SREG_FS)
13146 GCPtrMem += pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
13147 GCPtrMem &= s_auAddrSizeMasks[uAddrSize];
13148
13149 /*
13150 * Validate effective address.
13151 * See AMD spec. 4.5.3 "Segment Registers in 64-Bit Mode".
13152 */
13153 uint8_t const cbAccess = s_auAccessSizeMasks[uAddrSize];
13154 Assert(cbAccess > 0);
13155 if (fIsLongMode)
13156 {
13157 if (X86_IS_CANONICAL(GCPtrMem))
13158 {
13159 *pGCPtrMem = GCPtrMem;
13160 return VINF_SUCCESS;
13161 }
13162
13163 /** @todo r=ramshankar: We should probably raise \#SS or \#GP. See AMD spec. 4.12.2
13164 * "Data Limit Checks in 64-bit Mode". */
13165 Log4Func(("Long mode effective address is not canonical GCPtrMem=%#RX64\n", GCPtrMem));
13166 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13167 return VINF_HM_PENDING_XCPT;
13168 }
13169
13170 /*
13171 * This is a watered down version of iemMemApplySegment().
13172 * Parts that are not applicable for VMX instructions like real-or-v8086 mode
13173 * and segment CPL/DPL checks are skipped.
13174 */
13175 RTGCPTR32 const GCPtrFirst32 = (RTGCPTR32)GCPtrOff;
13176 RTGCPTR32 const GCPtrLast32 = GCPtrFirst32 + cbAccess - 1;
13177 PCCPUMSELREG pSel = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
13178
13179 /* Check if the segment is present and usable. */
13180 if ( pSel->Attr.n.u1Present
13181 && !pSel->Attr.n.u1Unusable)
13182 {
13183 Assert(pSel->Attr.n.u1DescType);
13184 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
13185 {
13186 /* Check permissions for the data segment. */
13187 if ( enmMemAccess == VMXMEMACCESS_WRITE
13188 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE))
13189 {
13190 Log4Func(("Data segment access invalid. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13191 hmR0VmxSetPendingXcptGP(pVCpu, iSegReg);
13192 return VINF_HM_PENDING_XCPT;
13193 }
13194
13195 /* Check limits if it's a normal data segment. */
13196 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
13197 {
13198 if ( GCPtrFirst32 > pSel->u32Limit
13199 || GCPtrLast32 > pSel->u32Limit)
13200 {
13201 Log4Func(("Data segment limit exceeded. "
13202 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13203 GCPtrLast32, pSel->u32Limit));
13204 if (iSegReg == X86_SREG_SS)
13205 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13206 else
13207 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13208 return VINF_HM_PENDING_XCPT;
13209 }
13210 }
13211 else
13212 {
13213 /* Check limits if it's an expand-down data segment.
13214 Note! The upper boundary is defined by the B bit, not the G bit! */
13215 if ( GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
13216 || GCPtrLast32 > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
13217 {
13218 Log4Func(("Expand-down data segment limit exceeded. "
13219 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13220 GCPtrLast32, pSel->u32Limit));
13221 if (iSegReg == X86_SREG_SS)
13222 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13223 else
13224 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13225 return VINF_HM_PENDING_XCPT;
13226 }
13227 }
13228 }
13229 else
13230 {
13231 /* Check permissions for the code segment. */
13232 if ( enmMemAccess == VMXMEMACCESS_WRITE
13233 || ( enmMemAccess == VMXMEMACCESS_READ
13234 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)))
13235 {
13236 Log4Func(("Code segment access invalid. Attr=%#RX32\n", pSel->Attr.u));
13237 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13238 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13239 return VINF_HM_PENDING_XCPT;
13240 }
13241
13242 /* Check limits for the code segment (normal/expand-down not applicable for code segments). */
13243 if ( GCPtrFirst32 > pSel->u32Limit
13244 || GCPtrLast32 > pSel->u32Limit)
13245 {
13246 Log4Func(("Code segment limit exceeded. GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n",
13247 GCPtrFirst32, GCPtrLast32, pSel->u32Limit));
13248 if (iSegReg == X86_SREG_SS)
13249 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13250 else
13251 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13252 return VINF_HM_PENDING_XCPT;
13253 }
13254 }
13255 }
13256 else
13257 {
13258 Log4Func(("Not present or unusable segment. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13259 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13260 return VINF_HM_PENDING_XCPT;
13261 }
13262
13263 *pGCPtrMem = GCPtrMem;
13264 return VINF_SUCCESS;
13265}
13266#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13267
13268
13269/**
13270 * VM-exit helper for LMSW.
13271 */
13272static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst)
13273{
13274 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13275 AssertRCReturn(rc, rc);
13276
13277 VBOXSTRICTRC rcStrict = IEMExecDecodedLmsw(pVCpu, cbInstr, uMsw, GCPtrEffDst);
13278 AssertMsg( rcStrict == VINF_SUCCESS
13279 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13280
13281 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13282 if (rcStrict == VINF_IEM_RAISED_XCPT)
13283 {
13284 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13285 rcStrict = VINF_SUCCESS;
13286 }
13287
13288 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
13289 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13290 return rcStrict;
13291}
13292
13293
13294/**
13295 * VM-exit helper for CLTS.
13296 */
13297static VBOXSTRICTRC hmR0VmxExitClts(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
13298{
13299 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13300 AssertRCReturn(rc, rc);
13301
13302 VBOXSTRICTRC rcStrict = IEMExecDecodedClts(pVCpu, cbInstr);
13303 AssertMsg( rcStrict == VINF_SUCCESS
13304 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13305
13306 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13307 if (rcStrict == VINF_IEM_RAISED_XCPT)
13308 {
13309 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13310 rcStrict = VINF_SUCCESS;
13311 }
13312
13313 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
13314 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13315 return rcStrict;
13316}
13317
13318
13319/**
13320 * VM-exit helper for MOV from CRx (CRx read).
13321 */
13322static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13323{
13324 Assert(iCrReg < 16);
13325 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
13326
13327 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13328 AssertRCReturn(rc, rc);
13329
13330 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxRead(pVCpu, cbInstr, iGReg, iCrReg);
13331 AssertMsg( rcStrict == VINF_SUCCESS
13332 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13333
13334 if (iGReg == X86_GREG_xSP)
13335 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_RSP);
13336 else
13337 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13338#ifdef VBOX_WITH_STATISTICS
13339 switch (iCrReg)
13340 {
13341 case 0: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Read); break;
13342 case 2: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Read); break;
13343 case 3: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Read); break;
13344 case 4: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Read); break;
13345 case 8: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Read); break;
13346 }
13347#endif
13348 Log4Func(("CR%d Read access rcStrict=%Rrc\n", iCrReg, VBOXSTRICTRC_VAL(rcStrict)));
13349 return rcStrict;
13350}
13351
13352
13353/**
13354 * VM-exit helper for MOV to CRx (CRx write).
13355 */
13356static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13357{
13358 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13359 AssertRCReturn(rc, rc);
13360
13361 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, cbInstr, iCrReg, iGReg);
13362 AssertMsg( rcStrict == VINF_SUCCESS
13363 || rcStrict == VINF_IEM_RAISED_XCPT
13364 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13365
13366 switch (iCrReg)
13367 {
13368 case 0:
13369 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13370 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Write);
13371 Log4Func(("CR0 write. rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr0));
13372 break;
13373
13374 case 2:
13375 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Write);
13376 /* Nothing to do here, CR2 it's not part of the VMCS. */
13377 break;
13378
13379 case 3:
13380 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR3);
13381 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Write);
13382 Log4Func(("CR3 write. rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr3));
13383 break;
13384
13385 case 4:
13386 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR4);
13387 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Write);
13388 Log4Func(("CR4 write. rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n", VBOXSTRICTRC_VAL(rcStrict),
13389 pVCpu->cpum.GstCtx.cr4, pVCpu->hm.s.fLoadSaveGuestXcr0));
13390 break;
13391
13392 case 8:
13393 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged,
13394 HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_APIC_TPR);
13395 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Write);
13396 break;
13397
13398 default:
13399 AssertMsgFailed(("Invalid CRx register %#x\n", iCrReg));
13400 break;
13401 }
13402
13403 if (rcStrict == VINF_IEM_RAISED_XCPT)
13404 {
13405 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13406 rcStrict = VINF_SUCCESS;
13407 }
13408 return rcStrict;
13409}
13410
13411
13412/**
13413 * VM-exit exception handler for \#PF (Page-fault exception).
13414 *
13415 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13416 */
13417static VBOXSTRICTRC hmR0VmxExitXcptPF(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13418{
13419 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13420 PVM pVM = pVCpu->CTX_SUFF(pVM);
13421 hmR0VmxReadExitQualVmcs(pVmxTransient);
13422
13423 if (!pVM->hm.s.fNestedPaging)
13424 { /* likely */ }
13425 else
13426 {
13427#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13428 Assert(pVmxTransient->fIsNestedGuest || pVCpu->hm.s.fUsingDebugLoop);
13429#endif
13430 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13431 if (!pVmxTransient->fVectoringDoublePF)
13432 {
13433 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13434 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual);
13435 }
13436 else
13437 {
13438 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13439 Assert(!pVmxTransient->fIsNestedGuest);
13440 hmR0VmxSetPendingXcptDF(pVCpu);
13441 Log4Func(("Pending #DF due to vectoring #PF w/ NestedPaging\n"));
13442 }
13443 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13444 return VINF_SUCCESS;
13445 }
13446
13447 Assert(!pVmxTransient->fIsNestedGuest);
13448
13449 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
13450 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
13451 if (pVmxTransient->fVectoringPF)
13452 {
13453 Assert(pVCpu->hm.s.Event.fPending);
13454 return VINF_EM_RAW_INJECT_TRPM_EVENT;
13455 }
13456
13457 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13458 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13459 AssertRCReturn(rc, rc);
13460
13461 Log4Func(("#PF: cr2=%#RX64 cs:rip=%#04x:%#RX64 uErrCode %#RX32 cr3=%#RX64\n", pVmxTransient->uExitQual, pCtx->cs.Sel,
13462 pCtx->rip, pVmxTransient->uExitIntErrorCode, pCtx->cr3));
13463
13464 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQual, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
13465 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pCtx), (RTGCPTR)pVmxTransient->uExitQual);
13466
13467 Log4Func(("#PF: rc=%Rrc\n", rc));
13468 if (rc == VINF_SUCCESS)
13469 {
13470 /*
13471 * This is typically a shadow page table sync or a MMIO instruction. But we may have
13472 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
13473 */
13474 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13475 TRPMResetTrap(pVCpu);
13476 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
13477 return rc;
13478 }
13479
13480 if (rc == VINF_EM_RAW_GUEST_TRAP)
13481 {
13482 if (!pVmxTransient->fVectoringDoublePF)
13483 {
13484 /* It's a guest page fault and needs to be reflected to the guest. */
13485 uint32_t uGstErrorCode = TRPMGetErrorCode(pVCpu);
13486 TRPMResetTrap(pVCpu);
13487 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
13488 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13489 uGstErrorCode, pVmxTransient->uExitQual);
13490 }
13491 else
13492 {
13493 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13494 TRPMResetTrap(pVCpu);
13495 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
13496 hmR0VmxSetPendingXcptDF(pVCpu);
13497 Log4Func(("#PF: Pending #DF due to vectoring #PF\n"));
13498 }
13499
13500 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13501 return VINF_SUCCESS;
13502 }
13503
13504 TRPMResetTrap(pVCpu);
13505 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
13506 return rc;
13507}
13508
13509
13510/**
13511 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
13512 *
13513 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13514 */
13515static VBOXSTRICTRC hmR0VmxExitXcptMF(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13516{
13517 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13518 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
13519
13520 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0);
13521 AssertRCReturn(rc, rc);
13522
13523 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_NE))
13524 {
13525 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
13526 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
13527
13528 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
13529 * provides VM-exit instruction length. If this causes problem later,
13530 * disassemble the instruction like it's done on AMD-V. */
13531 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
13532 AssertRCReturn(rc2, rc2);
13533 return rc;
13534 }
13535
13536 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13537 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13538 return VINF_SUCCESS;
13539}
13540
13541
13542/**
13543 * VM-exit exception handler for \#BP (Breakpoint exception).
13544 *
13545 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13546 */
13547static VBOXSTRICTRC hmR0VmxExitXcptBP(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13548{
13549 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13550 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
13551
13552 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13553 AssertRCReturn(rc, rc);
13554
13555 if (!pVmxTransient->fIsNestedGuest)
13556 rc = DBGFRZTrap03Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(&pVCpu->cpum.GstCtx));
13557 else
13558 rc = VINF_EM_RAW_GUEST_TRAP;
13559 if (rc == VINF_EM_RAW_GUEST_TRAP)
13560 {
13561 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13562 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13563 }
13564
13565 Assert(rc == VINF_SUCCESS || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_EM_DBG_BREAKPOINT);
13566 return rc;
13567}
13568
13569
13570/**
13571 * VM-exit exception handler for \#AC (Alignment-check exception).
13572 *
13573 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13574 */
13575static VBOXSTRICTRC hmR0VmxExitXcptAC(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13576{
13577 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13578 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC);
13579
13580 /* Re-inject it. We'll detect any nesting before getting here. */
13581 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13582 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13583 return VINF_SUCCESS;
13584}
13585
13586
13587/**
13588 * VM-exit exception handler for \#DB (Debug exception).
13589 *
13590 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13591 */
13592static VBOXSTRICTRC hmR0VmxExitXcptDB(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13593{
13594 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13595 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
13596
13597 /*
13598 * Get the DR6-like values from the Exit qualification and pass it to DBGF for processing.
13599 */
13600 hmR0VmxReadExitQualVmcs(pVmxTransient);
13601
13602 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
13603 uint64_t const uDR6 = X86_DR6_INIT_VAL
13604 | (pVmxTransient->uExitQual & ( X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3
13605 | X86_DR6_BD | X86_DR6_BS));
13606
13607 int rc;
13608 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13609 if (!pVmxTransient->fIsNestedGuest)
13610 rc = DBGFRZTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
13611 else
13612 rc = VINF_EM_RAW_GUEST_TRAP;
13613 Log6Func(("rc=%Rrc\n", rc));
13614 if (rc == VINF_EM_RAW_GUEST_TRAP)
13615 {
13616 /*
13617 * The exception was for the guest. Update DR6, DR7.GD and
13618 * IA32_DEBUGCTL.LBR before forwarding it.
13619 * See Intel spec. 27.1 "Architectural State before a VM-Exit".
13620 */
13621 VMMRZCallRing3Disable(pVCpu);
13622 HM_DISABLE_PREEMPT(pVCpu);
13623
13624 pCtx->dr[6] &= ~X86_DR6_B_MASK;
13625 pCtx->dr[6] |= uDR6;
13626 if (CPUMIsGuestDebugStateActive(pVCpu))
13627 ASMSetDR6(pCtx->dr[6]);
13628
13629 HM_RESTORE_PREEMPT();
13630 VMMRZCallRing3Enable(pVCpu);
13631
13632 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_DR7);
13633 AssertRCReturn(rc, rc);
13634
13635 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
13636 pCtx->dr[7] &= ~(uint64_t)X86_DR7_GD;
13637
13638 /* Paranoia. */
13639 pCtx->dr[7] &= ~(uint64_t)X86_DR7_RAZ_MASK;
13640 pCtx->dr[7] |= X86_DR7_RA1_MASK;
13641
13642 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, pCtx->dr[7]);
13643 AssertRC(rc);
13644
13645 /*
13646 * Raise #DB in the guest.
13647 *
13648 * It is important to reflect exactly what the VM-exit gave us (preserving the
13649 * interruption-type) rather than use hmR0VmxSetPendingXcptDB() as the #DB could've
13650 * been raised while executing ICEBP (INT1) and not the regular #DB. Thus it may
13651 * trigger different handling in the CPU (like skipping DPL checks), see @bugref{6398}.
13652 *
13653 * Intel re-documented ICEBP/INT1 on May 2018 previously documented as part of
13654 * Intel 386, see Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
13655 */
13656 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13657 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13658 return VINF_SUCCESS;
13659 }
13660
13661 /*
13662 * Not a guest trap, must be a hypervisor related debug event then.
13663 * Update DR6 in case someone is interested in it.
13664 */
13665 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
13666 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
13667 CPUMSetHyperDR6(pVCpu, uDR6);
13668
13669 return rc;
13670}
13671
13672
13673/**
13674 * Hacks its way around the lovely mesa driver's backdoor accesses.
13675 *
13676 * @sa hmR0SvmHandleMesaDrvGp.
13677 */
13678static int hmR0VmxHandleMesaDrvGp(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
13679{
13680 LogFunc(("cs:rip=%#04x:%#RX64 rcx=%#RX64 rbx=%#RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->rcx, pCtx->rbx));
13681 RT_NOREF(pCtx);
13682
13683 /* For now we'll just skip the instruction. */
13684 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
13685}
13686
13687
13688/**
13689 * Checks if the \#GP'ing instruction is the mesa driver doing it's lovely
13690 * backdoor logging w/o checking what it is running inside.
13691 *
13692 * This recognizes an "IN EAX,DX" instruction executed in flat ring-3, with the
13693 * backdoor port and magic numbers loaded in registers.
13694 *
13695 * @returns true if it is, false if it isn't.
13696 * @sa hmR0SvmIsMesaDrvGp.
13697 */
13698DECLINLINE(bool) hmR0VmxIsMesaDrvGp(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
13699{
13700 /* 0xed: IN eAX,dx */
13701 uint8_t abInstr[1];
13702 if (pVmxTransient->cbInstr != sizeof(abInstr))
13703 return false;
13704
13705 /* Check that it is #GP(0). */
13706 if (pVmxTransient->uExitIntErrorCode != 0)
13707 return false;
13708
13709 /* Check magic and port. */
13710 Assert(!(pCtx->fExtrn & (CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX)));
13711 /*Log(("hmR0VmxIsMesaDrvGp: rax=%RX64 rdx=%RX64\n", pCtx->rax, pCtx->rdx));*/
13712 if (pCtx->rax != UINT32_C(0x564d5868))
13713 return false;
13714 if (pCtx->dx != UINT32_C(0x5658))
13715 return false;
13716
13717 /* Flat ring-3 CS. */
13718 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_CS);
13719 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_CS));
13720 /*Log(("hmR0VmxIsMesaDrvGp: cs.Attr.n.u2Dpl=%d base=%Rx64\n", pCtx->cs.Attr.n.u2Dpl, pCtx->cs.u64Base));*/
13721 if (pCtx->cs.Attr.n.u2Dpl != 3)
13722 return false;
13723 if (pCtx->cs.u64Base != 0)
13724 return false;
13725
13726 /* Check opcode. */
13727 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_RIP);
13728 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_RIP));
13729 int rc = PGMPhysSimpleReadGCPtr(pVCpu, abInstr, pCtx->rip, sizeof(abInstr));
13730 /*Log(("hmR0VmxIsMesaDrvGp: PGMPhysSimpleReadGCPtr -> %Rrc %#x\n", rc, abInstr[0]));*/
13731 if (RT_FAILURE(rc))
13732 return false;
13733 if (abInstr[0] != 0xed)
13734 return false;
13735
13736 return true;
13737}
13738
13739
13740/**
13741 * VM-exit exception handler for \#GP (General-protection exception).
13742 *
13743 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13744 */
13745static VBOXSTRICTRC hmR0VmxExitXcptGP(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13746{
13747 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13748 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
13749
13750 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13751 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13752 if (pVmcsInfo->RealMode.fRealOnV86Active)
13753 { /* likely */ }
13754 else
13755 {
13756#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13757 Assert(pVCpu->hm.s.fUsingDebugLoop || pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
13758#endif
13759 /*
13760 * If the guest is not in real-mode or we have unrestricted guest execution support, or if we are
13761 * executing a nested-guest, reflect #GP to the guest or nested-guest.
13762 */
13763 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13764 AssertRCReturn(rc, rc);
13765 Log4Func(("Gst: cs:rip=%#04x:%#RX64 ErrorCode=%#x cr0=%#RX64 cpl=%u tr=%#04x\n", pCtx->cs.Sel, pCtx->rip,
13766 pVmxTransient->uExitIntErrorCode, pCtx->cr0, CPUMGetGuestCPL(pVCpu), pCtx->tr.Sel));
13767
13768 if ( pVmxTransient->fIsNestedGuest
13769 || !pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv
13770 || !hmR0VmxIsMesaDrvGp(pVCpu, pVmxTransient, pCtx))
13771 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13772 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13773 else
13774 rc = hmR0VmxHandleMesaDrvGp(pVCpu, pVmxTransient, pCtx);
13775 return rc;
13776 }
13777
13778 Assert(CPUMIsGuestInRealModeEx(pCtx));
13779 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest);
13780 Assert(!pVmxTransient->fIsNestedGuest);
13781
13782 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13783 AssertRCReturn(rc, rc);
13784
13785 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
13786 if (rcStrict == VINF_SUCCESS)
13787 {
13788 if (!CPUMIsGuestInRealModeEx(pCtx))
13789 {
13790 /*
13791 * The guest is no longer in real-mode, check if we can continue executing the
13792 * guest using hardware-assisted VMX. Otherwise, fall back to emulation.
13793 */
13794 pVmcsInfo->RealMode.fRealOnV86Active = false;
13795 if (HMCanExecuteVmxGuest(pVCpu, pCtx))
13796 {
13797 Log4Func(("Mode changed but guest still suitable for executing using hardware-assisted VMX\n"));
13798 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13799 }
13800 else
13801 {
13802 Log4Func(("Mode changed -> VINF_EM_RESCHEDULE\n"));
13803 rcStrict = VINF_EM_RESCHEDULE;
13804 }
13805 }
13806 else
13807 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13808 }
13809 else if (rcStrict == VINF_IEM_RAISED_XCPT)
13810 {
13811 rcStrict = VINF_SUCCESS;
13812 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13813 }
13814 return VBOXSTRICTRC_VAL(rcStrict);
13815}
13816
13817
13818/**
13819 * VM-exit exception handler wrapper for all other exceptions that are not handled
13820 * by a specific handler.
13821 *
13822 * This simply re-injects the exception back into the VM without any special
13823 * processing.
13824 *
13825 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13826 */
13827static VBOXSTRICTRC hmR0VmxExitXcptOthers(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13828{
13829 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13830
13831#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13832 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13833 AssertMsg(pVCpu->hm.s.fUsingDebugLoop || pVmcsInfo->RealMode.fRealOnV86Active || pVmxTransient->fIsNestedGuest,
13834 ("uVector=%#x u32XcptBitmap=%#X32\n",
13835 VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVmcsInfo->u32XcptBitmap));
13836 NOREF(pVmcsInfo);
13837#endif
13838
13839 /*
13840 * Re-inject the exception into the guest. This cannot be a double-fault condition which
13841 * would have been handled while checking exits due to event delivery.
13842 */
13843 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13844
13845#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13846 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
13847 AssertRCReturn(rc, rc);
13848 Log4Func(("Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
13849#endif
13850
13851#ifdef VBOX_WITH_STATISTICS
13852 switch (uVector)
13853 {
13854 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE); break;
13855 case X86_XCPT_DB: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB); break;
13856 case X86_XCPT_BP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP); break;
13857 case X86_XCPT_OF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
13858 case X86_XCPT_BR: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBR); break;
13859 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD); break;
13860 case X86_XCPT_NM: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
13861 case X86_XCPT_DF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDF); break;
13862 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS); break;
13863 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP); break;
13864 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS); break;
13865 case X86_XCPT_GP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP); break;
13866 case X86_XCPT_PF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF); break;
13867 case X86_XCPT_MF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF); break;
13868 case X86_XCPT_AC: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC); break;
13869 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF); break;
13870 default:
13871 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
13872 break;
13873 }
13874#endif
13875
13876 /* We should never call this function for a page-fault, we'd need to pass on the fault address below otherwise. */
13877 Assert(!VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo));
13878 NOREF(uVector);
13879
13880 /* Re-inject the original exception into the guest. */
13881 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13882 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13883 return VINF_SUCCESS;
13884}
13885
13886
13887/**
13888 * VM-exit exception handler for all exceptions (except NMIs!).
13889 *
13890 * @remarks This may be called for both guests and nested-guests. Take care to not
13891 * make assumptions and avoid doing anything that is not relevant when
13892 * executing a nested-guest (e.g., Mesa driver hacks).
13893 */
13894static VBOXSTRICTRC hmR0VmxExitXcpt(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13895{
13896 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
13897
13898 /*
13899 * If this VM-exit occurred while delivering an event through the guest IDT, take
13900 * action based on the return code and additional hints (e.g. for page-faults)
13901 * that will be updated in the VMX transient structure.
13902 */
13903 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
13904 if (rcStrict == VINF_SUCCESS)
13905 {
13906 /*
13907 * If an exception caused a VM-exit due to delivery of an event, the original
13908 * event may have to be re-injected into the guest. We shall reinject it and
13909 * continue guest execution. However, page-fault is a complicated case and
13910 * needs additional processing done in hmR0VmxExitXcptPF().
13911 */
13912 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
13913 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13914 if ( !pVCpu->hm.s.Event.fPending
13915 || uVector == X86_XCPT_PF)
13916 {
13917 switch (uVector)
13918 {
13919 case X86_XCPT_PF: return hmR0VmxExitXcptPF(pVCpu, pVmxTransient);
13920 case X86_XCPT_GP: return hmR0VmxExitXcptGP(pVCpu, pVmxTransient);
13921 case X86_XCPT_MF: return hmR0VmxExitXcptMF(pVCpu, pVmxTransient);
13922 case X86_XCPT_DB: return hmR0VmxExitXcptDB(pVCpu, pVmxTransient);
13923 case X86_XCPT_BP: return hmR0VmxExitXcptBP(pVCpu, pVmxTransient);
13924 case X86_XCPT_AC: return hmR0VmxExitXcptAC(pVCpu, pVmxTransient);
13925 default:
13926 return hmR0VmxExitXcptOthers(pVCpu, pVmxTransient);
13927 }
13928 }
13929 /* else: inject pending event before resuming guest execution. */
13930 }
13931 else if (rcStrict == VINF_HM_DOUBLE_FAULT)
13932 {
13933 Assert(pVCpu->hm.s.Event.fPending);
13934 rcStrict = VINF_SUCCESS;
13935 }
13936
13937 return rcStrict;
13938}
13939/** @} */
13940
13941
13942/** @name VM-exit handlers.
13943 * @{
13944 */
13945/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13946/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
13947/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13948
13949/**
13950 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
13951 */
13952HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13953{
13954 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13955 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
13956 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
13957 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
13958 return VINF_SUCCESS;
13959 return VINF_EM_RAW_INTERRUPT;
13960}
13961
13962
13963/**
13964 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI). Conditional
13965 * VM-exit.
13966 */
13967HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13968{
13969 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13970 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
13971
13972 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13973
13974 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
13975 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13976 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
13977
13978 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13979 Assert( !(pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT)
13980 && uExitIntType != VMX_EXIT_INT_INFO_TYPE_EXT_INT);
13981 NOREF(pVmcsInfo);
13982
13983 VBOXSTRICTRC rcStrict;
13984 switch (uExitIntType)
13985 {
13986 /*
13987 * Host physical NMIs:
13988 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we
13989 * injected it ourselves and anything we inject is not going to cause a VM-exit directly
13990 * for the event being injected[1]. Go ahead and dispatch the NMI to the host[2].
13991 *
13992 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
13993 * See Intel spec. 27.5.5 "Updating Non-Register State".
13994 */
13995 case VMX_EXIT_INT_INFO_TYPE_NMI:
13996 {
13997 rcStrict = hmR0VmxExitHostNmi(pVCpu, pVmcsInfo);
13998 break;
13999 }
14000
14001 /*
14002 * Privileged software exceptions (#DB from ICEBP),
14003 * Software exceptions (#BP and #OF),
14004 * Hardware exceptions:
14005 * Process the required exceptions and resume guest execution if possible.
14006 */
14007 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
14008 Assert(uVector == X86_XCPT_DB);
14009 RT_FALL_THRU();
14010 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
14011 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uExitIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT);
14012 RT_FALL_THRU();
14013 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
14014 {
14015 NOREF(uVector);
14016 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
14017 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14018 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
14019 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
14020
14021 rcStrict = hmR0VmxExitXcpt(pVCpu, pVmxTransient);
14022 break;
14023 }
14024
14025 default:
14026 {
14027 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
14028 rcStrict = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
14029 AssertMsgFailed(("Invalid/unexpected VM-exit interruption info %#x\n", pVmxTransient->uExitIntInfo));
14030 break;
14031 }
14032 }
14033
14034 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
14035 return rcStrict;
14036}
14037
14038
14039/**
14040 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
14041 */
14042HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14043{
14044 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14045
14046 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
14047 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14048 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
14049
14050 /* Evaluate and deliver pending events and resume guest execution. */
14051 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
14052 return VINF_SUCCESS;
14053}
14054
14055
14056/**
14057 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
14058 */
14059HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14060{
14061 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14062
14063 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14064 if (RT_UNLIKELY(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))) /** @todo NSTVMX: Turn this into an assertion. */
14065 {
14066 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
14067 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14068 }
14069
14070 Assert(!CPUMIsGuestNmiBlocking(pVCpu));
14071
14072 /*
14073 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
14074 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
14075 */
14076 uint32_t fIntrState;
14077 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
14078 AssertRC(rc);
14079 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
14080 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
14081 {
14082 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
14083 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
14084
14085 fIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
14086 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
14087 AssertRC(rc);
14088 }
14089
14090 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
14091 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
14092
14093 /* Evaluate and deliver pending events and resume guest execution. */
14094 return VINF_SUCCESS;
14095}
14096
14097
14098/**
14099 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
14100 */
14101HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14102{
14103 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14104 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14105}
14106
14107
14108/**
14109 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
14110 */
14111HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14112{
14113 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14114 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14115}
14116
14117
14118/**
14119 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
14120 */
14121HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14122{
14123 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14124
14125 /*
14126 * Get the state we need and update the exit history entry.
14127 */
14128 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14129 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14130
14131 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14132 AssertRCReturn(rc, rc);
14133
14134 VBOXSTRICTRC rcStrict;
14135 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
14136 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_CPUID),
14137 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
14138 if (!pExitRec)
14139 {
14140 /*
14141 * Regular CPUID instruction execution.
14142 */
14143 rcStrict = IEMExecDecodedCpuid(pVCpu, pVmxTransient->cbInstr);
14144 if (rcStrict == VINF_SUCCESS)
14145 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14146 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14147 {
14148 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14149 rcStrict = VINF_SUCCESS;
14150 }
14151 }
14152 else
14153 {
14154 /*
14155 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
14156 */
14157 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14158 AssertRCReturn(rc2, rc2);
14159
14160 Log4(("CpuIdExit/%u: %04x:%08RX64: %#x/%#x -> EMHistoryExec\n",
14161 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx));
14162
14163 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
14164 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14165
14166 Log4(("CpuIdExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
14167 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
14168 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
14169 }
14170 return rcStrict;
14171}
14172
14173
14174/**
14175 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
14176 */
14177HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14178{
14179 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14180
14181 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14182 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4);
14183 AssertRCReturn(rc, rc);
14184
14185 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_SMXE)
14186 return VINF_EM_RAW_EMULATE_INSTR;
14187
14188 AssertMsgFailed(("hmR0VmxExitGetsec: Unexpected VM-exit when CR4.SMXE is 0.\n"));
14189 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14190}
14191
14192
14193/**
14194 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
14195 */
14196HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14197{
14198 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14199
14200 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14201 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14202 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14203 AssertRCReturn(rc, rc);
14204
14205 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtsc(pVCpu, pVmxTransient->cbInstr);
14206 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14207 {
14208 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14209 we must reset offsetting on VM-entry. See @bugref{6634}. */
14210 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14211 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14212 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14213 }
14214 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14215 {
14216 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14217 rcStrict = VINF_SUCCESS;
14218 }
14219 return rcStrict;
14220}
14221
14222
14223/**
14224 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
14225 */
14226HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14227{
14228 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14229
14230 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14231 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14232 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_TSC_AUX);
14233 AssertRCReturn(rc, rc);
14234
14235 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtscp(pVCpu, pVmxTransient->cbInstr);
14236 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14237 {
14238 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14239 we must reset offsetting on VM-reentry. See @bugref{6634}. */
14240 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14241 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14242 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14243 }
14244 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14245 {
14246 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14247 rcStrict = VINF_SUCCESS;
14248 }
14249 return rcStrict;
14250}
14251
14252
14253/**
14254 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
14255 */
14256HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14257{
14258 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14259
14260 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14261 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_CR0
14262 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS);
14263 AssertRCReturn(rc, rc);
14264
14265 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14266 rc = EMInterpretRdpmc(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
14267 if (RT_LIKELY(rc == VINF_SUCCESS))
14268 {
14269 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14270 Assert(pVmxTransient->cbInstr == 2);
14271 }
14272 else
14273 {
14274 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
14275 rc = VERR_EM_INTERPRETER;
14276 }
14277 return rc;
14278}
14279
14280
14281/**
14282 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
14283 */
14284HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14285{
14286 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14287
14288 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
14289 if (EMAreHypercallInstructionsEnabled(pVCpu))
14290 {
14291 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14292 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CR0
14293 | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
14294 AssertRCReturn(rc, rc);
14295
14296 /* Perform the hypercall. */
14297 rcStrict = GIMHypercall(pVCpu, &pVCpu->cpum.GstCtx);
14298 if (rcStrict == VINF_SUCCESS)
14299 {
14300 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14301 AssertRCReturn(rc, rc);
14302 }
14303 else
14304 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
14305 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
14306 || RT_FAILURE(rcStrict));
14307
14308 /* If the hypercall changes anything other than guest's general-purpose registers,
14309 we would need to reload the guest changed bits here before VM-entry. */
14310 }
14311 else
14312 Log4Func(("Hypercalls not enabled\n"));
14313
14314 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
14315 if (RT_FAILURE(rcStrict))
14316 {
14317 hmR0VmxSetPendingXcptUD(pVCpu);
14318 rcStrict = VINF_SUCCESS;
14319 }
14320
14321 return rcStrict;
14322}
14323
14324
14325/**
14326 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
14327 */
14328HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14329{
14330 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14331 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging || pVCpu->hm.s.fUsingDebugLoop);
14332
14333 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14334 hmR0VmxReadExitQualVmcs(pVmxTransient);
14335 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14336 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
14337 AssertRCReturn(rc, rc);
14338
14339 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpg(pVCpu, pVmxTransient->cbInstr, pVmxTransient->uExitQual);
14340
14341 if (rcStrict == VINF_SUCCESS || rcStrict == VINF_PGM_SYNC_CR3)
14342 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14343 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14344 {
14345 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14346 rcStrict = VINF_SUCCESS;
14347 }
14348 else
14349 AssertMsgFailed(("Unexpected IEMExecDecodedInvlpg(%#RX64) status: %Rrc\n", pVmxTransient->uExitQual,
14350 VBOXSTRICTRC_VAL(rcStrict)));
14351 return rcStrict;
14352}
14353
14354
14355/**
14356 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
14357 */
14358HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14359{
14360 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14361
14362 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14363 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14364 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_DS);
14365 AssertRCReturn(rc, rc);
14366
14367 VBOXSTRICTRC rcStrict = IEMExecDecodedMonitor(pVCpu, pVmxTransient->cbInstr);
14368 if (rcStrict == VINF_SUCCESS)
14369 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14370 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14371 {
14372 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14373 rcStrict = VINF_SUCCESS;
14374 }
14375
14376 return rcStrict;
14377}
14378
14379
14380/**
14381 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
14382 */
14383HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14384{
14385 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14386
14387 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14388 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14389 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14390 AssertRCReturn(rc, rc);
14391
14392 VBOXSTRICTRC rcStrict = IEMExecDecodedMwait(pVCpu, pVmxTransient->cbInstr);
14393 if (RT_SUCCESS(rcStrict))
14394 {
14395 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14396 if (EMMonitorWaitShouldContinue(pVCpu, &pVCpu->cpum.GstCtx))
14397 rcStrict = VINF_SUCCESS;
14398 }
14399
14400 return rcStrict;
14401}
14402
14403
14404/**
14405 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
14406 * VM-exit.
14407 */
14408HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14409{
14410 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14411 return VINF_EM_RESET;
14412}
14413
14414
14415/**
14416 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
14417 */
14418HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14419{
14420 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14421
14422 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14423 AssertRCReturn(rc, rc);
14424
14425 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS); /* Advancing the RIP above should've imported eflags. */
14426 if (EMShouldContinueAfterHalt(pVCpu, &pVCpu->cpum.GstCtx)) /* Requires eflags. */
14427 rc = VINF_SUCCESS;
14428 else
14429 rc = VINF_EM_HALT;
14430
14431 if (rc != VINF_SUCCESS)
14432 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
14433 return rc;
14434}
14435
14436
14437/**
14438 * VM-exit handler for instructions that result in a \#UD exception delivered to
14439 * the guest.
14440 */
14441HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14442{
14443 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14444 hmR0VmxSetPendingXcptUD(pVCpu);
14445 return VINF_SUCCESS;
14446}
14447
14448
14449/**
14450 * VM-exit handler for expiry of the VMX-preemption timer.
14451 */
14452HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14453{
14454 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14455
14456 /* If the VMX-preemption timer has expired, reinitialize the preemption timer on next VM-entry. */
14457 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14458
14459 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
14460 PVM pVM = pVCpu->CTX_SUFF(pVM);
14461 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
14462 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
14463 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
14464}
14465
14466
14467/**
14468 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
14469 */
14470HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14471{
14472 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14473
14474 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14475 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14476 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_CR4);
14477 AssertRCReturn(rc, rc);
14478
14479 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbInstr);
14480 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
14481 : HM_CHANGED_RAISED_XCPT_MASK);
14482
14483 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14484 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
14485
14486 return rcStrict;
14487}
14488
14489
14490/**
14491 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
14492 */
14493HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14494{
14495 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14496 /** @todo Use VM-exit instruction information. */
14497 return VERR_EM_INTERPRETER;
14498}
14499
14500
14501/**
14502 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error
14503 * VM-exit.
14504 */
14505HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14506{
14507 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14508 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14509 AssertRCReturn(rc, rc);
14510
14511 rc = hmR0VmxCheckVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
14512 if (RT_FAILURE(rc))
14513 return rc;
14514
14515 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
14516 NOREF(uInvalidReason);
14517
14518#ifdef VBOX_STRICT
14519 uint32_t fIntrState;
14520 uint64_t u64Val;
14521 hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
14522 hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
14523 hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
14524
14525 Log4(("uInvalidReason %u\n", uInvalidReason));
14526 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
14527 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
14528 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
14529
14530 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState); AssertRC(rc);
14531 Log4(("VMX_VMCS32_GUEST_INT_STATE %#RX32\n", fIntrState));
14532 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Val); AssertRC(rc);
14533 Log4(("VMX_VMCS_GUEST_CR0 %#RX64\n", u64Val));
14534 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_MASK, &u64Val); AssertRC(rc);
14535 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RX64\n", u64Val));
14536 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Val); AssertRC(rc);
14537 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
14538 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_MASK, &u64Val); AssertRC(rc);
14539 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RX64\n", u64Val));
14540 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Val); AssertRC(rc);
14541 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
14542 if (pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging)
14543 {
14544 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
14545 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
14546 }
14547 hmR0DumpRegs(pVCpu);
14548#endif
14549
14550 return VERR_VMX_INVALID_GUEST_STATE;
14551}
14552
14553/**
14554 * VM-exit handler for all undefined/unexpected reasons. Should never happen.
14555 */
14556HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUnexpected(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14557{
14558 /*
14559 * Cummulative notes of all recognized but unexpected VM-exits.
14560 *
14561 * 1. This does -not- cover scenarios like like a page-fault VM-exit occurring when
14562 * nested-paging is used.
14563 *
14564 * 2. Any instruction that causes a VM-exit unconditionally (for e.g. VMXON) must be
14565 * emulated or a #UD must be raised in the guest. Therefore, we should -not- be using
14566 * this function (and thereby stop VM execution) for handling such instructions.
14567 *
14568 *
14569 * VMX_EXIT_INIT_SIGNAL:
14570 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
14571 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these
14572 * VM-exits. However, we should not receive INIT signals VM-exit while executing a VM.
14573 *
14574 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery"
14575 * See Intel spec. 29.3 "VMX Instructions" for "VMXON".
14576 * See Intel spec. "23.8 Restrictions on VMX operation".
14577 *
14578 * VMX_EXIT_SIPI:
14579 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest
14580 * activity state is used. We don't make use of it as our guests don't have direct
14581 * access to the host local APIC.
14582 *
14583 * See Intel spec. 25.3 "Other Causes of VM-exits".
14584 *
14585 * VMX_EXIT_IO_SMI:
14586 * VMX_EXIT_SMI:
14587 * This can only happen if we support dual-monitor treatment of SMI, which can be
14588 * activated by executing VMCALL in VMX root operation. Only an STM (SMM transfer
14589 * monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL in
14590 * VMX root mode or receive an SMI. If we get here, something funny is going on.
14591 *
14592 * See Intel spec. 33.15.6 "Activating the Dual-Monitor Treatment"
14593 * See Intel spec. 25.3 "Other Causes of VM-Exits"
14594 *
14595 * VMX_EXIT_ERR_MSR_LOAD:
14596 * Failures while loading MSRs are part of the VM-entry MSR-load area are unexpected
14597 * and typically indicates a bug in the hypervisor code. We thus cannot not resume
14598 * execution.
14599 *
14600 * See Intel spec. 26.7 "VM-Entry Failures During Or After Loading Guest State".
14601 *
14602 * VMX_EXIT_ERR_MACHINE_CHECK:
14603 * Machine check exceptions indicates a fatal/unrecoverable hardware condition
14604 * including but not limited to system bus, ECC, parity, cache and TLB errors. A
14605 * #MC exception abort class exception is raised. We thus cannot assume a
14606 * reasonable chance of continuing any sort of execution and we bail.
14607 *
14608 * See Intel spec. 15.1 "Machine-check Architecture".
14609 * See Intel spec. 27.1 "Architectural State Before A VM Exit".
14610 *
14611 * VMX_EXIT_PML_FULL:
14612 * VMX_EXIT_VIRTUALIZED_EOI:
14613 * VMX_EXIT_APIC_WRITE:
14614 * We do not currently support any of these features and thus they are all unexpected
14615 * VM-exits.
14616 *
14617 * VMX_EXIT_GDTR_IDTR_ACCESS:
14618 * VMX_EXIT_LDTR_TR_ACCESS:
14619 * VMX_EXIT_RDRAND:
14620 * VMX_EXIT_RSM:
14621 * VMX_EXIT_VMFUNC:
14622 * VMX_EXIT_ENCLS:
14623 * VMX_EXIT_RDSEED:
14624 * VMX_EXIT_XSAVES:
14625 * VMX_EXIT_XRSTORS:
14626 * VMX_EXIT_UMWAIT:
14627 * VMX_EXIT_TPAUSE:
14628 * These VM-exits are -not- caused unconditionally by execution of the corresponding
14629 * instruction. Any VM-exit for these instructions indicate a hardware problem,
14630 * unsupported CPU modes (like SMM) or potentially corrupt VMCS controls.
14631 *
14632 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
14633 */
14634 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14635 AssertMsgFailed(("Unexpected VM-exit %u\n", pVmxTransient->uExitReason));
14636 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14637}
14638
14639
14640/**
14641 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
14642 */
14643HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14644{
14645 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14646
14647 /** @todo Optimize this: We currently drag in in the whole MSR state
14648 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
14649 * MSRs required. That would require changes to IEM and possibly CPUM too.
14650 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
14651 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14652 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
14653 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
14654 switch (idMsr)
14655 {
14656 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
14657 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
14658 }
14659
14660 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14661 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
14662 AssertRCReturn(rc, rc);
14663
14664 Log4Func(("ecx=%#RX32\n", idMsr));
14665
14666#ifdef VBOX_STRICT
14667 Assert(!pVmxTransient->fIsNestedGuest);
14668 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
14669 {
14670 if ( hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr)
14671 && idMsr != MSR_K6_EFER)
14672 {
14673 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", idMsr));
14674 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14675 }
14676 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14677 {
14678 Assert(pVmcsInfo->pvMsrBitmap);
14679 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
14680 if (fMsrpm & VMXMSRPM_ALLOW_RD)
14681 {
14682 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", idMsr));
14683 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14684 }
14685 }
14686 }
14687#endif
14688
14689 VBOXSTRICTRC rcStrict = IEMExecDecodedRdmsr(pVCpu, pVmxTransient->cbInstr);
14690 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
14691 if (rcStrict == VINF_SUCCESS)
14692 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
14693 | HM_CHANGED_GUEST_RAX | HM_CHANGED_GUEST_RDX);
14694 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14695 {
14696 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14697 rcStrict = VINF_SUCCESS;
14698 }
14699 else
14700 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_READ, ("Unexpected IEMExecDecodedRdmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
14701
14702 return rcStrict;
14703}
14704
14705
14706/**
14707 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
14708 */
14709HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14710{
14711 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14712
14713 /** @todo Optimize this: We currently drag in in the whole MSR state
14714 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
14715 * MSRs required. That would require changes to IEM and possibly CPUM too.
14716 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
14717 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
14718 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
14719
14720 /*
14721 * The FS and GS base MSRs are not part of the above all-MSRs mask.
14722 * Although we don't need to fetch the base as it will be overwritten shortly, while
14723 * loading guest-state we would also load the entire segment register including limit
14724 * and attributes and thus we need to load them here.
14725 */
14726 switch (idMsr)
14727 {
14728 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
14729 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
14730 }
14731
14732 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14733 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14734 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
14735 AssertRCReturn(rc, rc);
14736
14737 Log4Func(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", idMsr, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.eax));
14738
14739 VBOXSTRICTRC rcStrict = IEMExecDecodedWrmsr(pVCpu, pVmxTransient->cbInstr);
14740 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
14741
14742 if (rcStrict == VINF_SUCCESS)
14743 {
14744 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14745
14746 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
14747 if ( idMsr == MSR_IA32_APICBASE
14748 || ( idMsr >= MSR_IA32_X2APIC_START
14749 && idMsr <= MSR_IA32_X2APIC_END))
14750 {
14751 /*
14752 * We've already saved the APIC related guest-state (TPR) in post-run phase.
14753 * When full APIC register virtualization is implemented we'll have to make
14754 * sure APIC state is saved from the VMCS before IEM changes it.
14755 */
14756 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
14757 }
14758 else if (idMsr == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
14759 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14760 else if (idMsr == MSR_K6_EFER)
14761 {
14762 /*
14763 * If the guest touches the EFER MSR we need to update the VM-Entry and VM-Exit controls
14764 * as well, even if it is -not- touching bits that cause paging mode changes (LMA/LME).
14765 * We care about the other bits as well, SCE and NXE. See @bugref{7368}.
14766 */
14767 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
14768 }
14769
14770 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not used. */
14771 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
14772 {
14773 switch (idMsr)
14774 {
14775 case MSR_IA32_SYSENTER_CS: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
14776 case MSR_IA32_SYSENTER_EIP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
14777 case MSR_IA32_SYSENTER_ESP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
14778 case MSR_K8_FS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_FS); break;
14779 case MSR_K8_GS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_GS); break;
14780 case MSR_K6_EFER: /* Nothing to do, already handled above. */ break;
14781 default:
14782 {
14783 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14784 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_LAZY_MSRS);
14785 else if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
14786 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
14787 break;
14788 }
14789 }
14790 }
14791#ifdef VBOX_STRICT
14792 else
14793 {
14794 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
14795 switch (idMsr)
14796 {
14797 case MSR_IA32_SYSENTER_CS:
14798 case MSR_IA32_SYSENTER_EIP:
14799 case MSR_IA32_SYSENTER_ESP:
14800 case MSR_K8_FS_BASE:
14801 case MSR_K8_GS_BASE:
14802 {
14803 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", idMsr));
14804 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14805 }
14806
14807 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
14808 default:
14809 {
14810 if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
14811 {
14812 /* EFER MSR writes are always intercepted. */
14813 if (idMsr != MSR_K6_EFER)
14814 {
14815 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
14816 idMsr));
14817 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14818 }
14819 }
14820
14821 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14822 {
14823 Assert(pVmcsInfo->pvMsrBitmap);
14824 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
14825 if (fMsrpm & VMXMSRPM_ALLOW_WR)
14826 {
14827 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", idMsr));
14828 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14829 }
14830 }
14831 break;
14832 }
14833 }
14834 }
14835#endif /* VBOX_STRICT */
14836 }
14837 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14838 {
14839 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14840 rcStrict = VINF_SUCCESS;
14841 }
14842 else
14843 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_WRITE, ("Unexpected IEMExecDecodedWrmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
14844
14845 return rcStrict;
14846}
14847
14848
14849/**
14850 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
14851 */
14852HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14853{
14854 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14855
14856 /** @todo The guest has likely hit a contended spinlock. We might want to
14857 * poke a schedule different guest VCPU. */
14858 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14859 if (RT_SUCCESS(rc))
14860 return VINF_EM_RAW_INTERRUPT;
14861
14862 AssertMsgFailed(("hmR0VmxExitPause: Failed to increment RIP. rc=%Rrc\n", rc));
14863 return rc;
14864}
14865
14866
14867/**
14868 * VM-exit handler for when the TPR value is lowered below the specified
14869 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
14870 */
14871HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14872{
14873 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14874 Assert(pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
14875
14876 /*
14877 * The TPR shadow would've been synced with the APIC TPR in the post-run phase.
14878 * We'll re-evaluate pending interrupts and inject them before the next VM
14879 * entry so we can just continue execution here.
14880 */
14881 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
14882 return VINF_SUCCESS;
14883}
14884
14885
14886/**
14887 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
14888 * VM-exit.
14889 *
14890 * @retval VINF_SUCCESS when guest execution can continue.
14891 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
14892 * @retval VERR_EM_RESCHEDULE_REM when we need to return to ring-3 due to
14893 * incompatible guest state for VMX execution (real-on-v86 case).
14894 */
14895HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14896{
14897 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14898 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
14899
14900 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14901 hmR0VmxReadExitQualVmcs(pVmxTransient);
14902 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14903
14904 VBOXSTRICTRC rcStrict;
14905 PVM pVM = pVCpu->CTX_SUFF(pVM);
14906 uint64_t const uExitQual = pVmxTransient->uExitQual;
14907 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(uExitQual);
14908 switch (uAccessType)
14909 {
14910 /*
14911 * MOV to CRx.
14912 */
14913 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
14914 {
14915 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14916 AssertRCReturn(rc, rc);
14917
14918 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
14919 uint32_t const uOldCr0 = pVCpu->cpum.GstCtx.cr0;
14920 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
14921 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
14922
14923 /*
14924 * MOV to CR3 only cause a VM-exit when one or more of the following are true:
14925 * - When nested paging isn't used.
14926 * - If the guest doesn't have paging enabled (intercept CR3 to update shadow page tables).
14927 * - We are executing in the VM debug loop.
14928 */
14929 Assert( iCrReg != 3
14930 || !pVM->hm.s.fNestedPaging
14931 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
14932 || pVCpu->hm.s.fUsingDebugLoop);
14933
14934 /* MOV to CR8 writes only cause VM-exits when TPR shadow is not used. */
14935 Assert( iCrReg != 8
14936 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
14937
14938 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmcsInfo, pVmxTransient->cbInstr, iGReg, iCrReg);
14939 AssertMsg( rcStrict == VINF_SUCCESS
14940 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
14941
14942 /*
14943 * This is a kludge for handling switches back to real mode when we try to use
14944 * V86 mode to run real mode code directly. Problem is that V86 mode cannot
14945 * deal with special selector values, so we have to return to ring-3 and run
14946 * there till the selector values are V86 mode compatible.
14947 *
14948 * Note! Using VINF_EM_RESCHEDULE_REM here rather than VINF_EM_RESCHEDULE since the
14949 * latter is an alias for VINF_IEM_RAISED_XCPT which is asserted at the end of
14950 * this function.
14951 */
14952 if ( iCrReg == 0
14953 && rcStrict == VINF_SUCCESS
14954 && !pVM->hm.s.vmx.fUnrestrictedGuest
14955 && CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx)
14956 && (uOldCr0 & X86_CR0_PE)
14957 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
14958 {
14959 /** @todo Check selectors rather than returning all the time. */
14960 Assert(!pVmxTransient->fIsNestedGuest);
14961 Log4Func(("CR0 write, back to real mode -> VINF_EM_RESCHEDULE_REM\n"));
14962 rcStrict = VINF_EM_RESCHEDULE_REM;
14963 }
14964 break;
14965 }
14966
14967 /*
14968 * MOV from CRx.
14969 */
14970 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
14971 {
14972 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
14973 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
14974
14975 /*
14976 * MOV from CR3 only cause a VM-exit when one or more of the following are true:
14977 * - When nested paging isn't used.
14978 * - If the guest doesn't have paging enabled (pass guest's CR3 rather than our identity mapped CR3).
14979 * - We are executing in the VM debug loop.
14980 */
14981 Assert( iCrReg != 3
14982 || !pVM->hm.s.fNestedPaging
14983 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
14984 || pVCpu->hm.s.fUsingDebugLoop);
14985
14986 /* MOV from CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
14987 Assert( iCrReg != 8
14988 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
14989
14990 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmcsInfo, pVmxTransient->cbInstr, iGReg, iCrReg);
14991 break;
14992 }
14993
14994 /*
14995 * CLTS (Clear Task-Switch Flag in CR0).
14996 */
14997 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
14998 {
14999 rcStrict = hmR0VmxExitClts(pVCpu, pVmcsInfo, pVmxTransient->cbInstr);
15000 break;
15001 }
15002
15003 /*
15004 * LMSW (Load Machine-Status Word into CR0).
15005 * LMSW cannot clear CR0.PE, so no fRealOnV86Active kludge needed here.
15006 */
15007 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW:
15008 {
15009 RTGCPTR GCPtrEffDst;
15010 uint8_t const cbInstr = pVmxTransient->cbInstr;
15011 uint16_t const uMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(uExitQual);
15012 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(uExitQual);
15013 if (fMemOperand)
15014 {
15015 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
15016 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
15017 }
15018 else
15019 GCPtrEffDst = NIL_RTGCPTR;
15020 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmcsInfo, cbInstr, uMsw, GCPtrEffDst);
15021 break;
15022 }
15023
15024 default:
15025 {
15026 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
15027 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
15028 }
15029 }
15030
15031 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS))
15032 == (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS));
15033 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15034
15035 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
15036 NOREF(pVM);
15037 return rcStrict;
15038}
15039
15040
15041/**
15042 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
15043 * VM-exit.
15044 */
15045HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15046{
15047 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15048 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
15049
15050 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15051 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15052 hmR0VmxReadExitQualVmcs(pVmxTransient);
15053 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15054 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_SREG_MASK
15055 | CPUMCTX_EXTRN_EFER);
15056 /* EFER MSR also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
15057 AssertRCReturn(rc, rc);
15058
15059 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
15060 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
15061 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
15062 bool const fIOWrite = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
15063 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
15064 bool const fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
15065 bool const fDbgStepping = pVCpu->hm.s.fSingleInstruction;
15066 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
15067
15068 /*
15069 * Update exit history to see if this exit can be optimized.
15070 */
15071 VBOXSTRICTRC rcStrict;
15072 PCEMEXITREC pExitRec = NULL;
15073 if ( !fGstStepping
15074 && !fDbgStepping)
15075 pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15076 !fIOString
15077 ? !fIOWrite
15078 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_READ)
15079 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_WRITE)
15080 : !fIOWrite
15081 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_READ)
15082 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_WRITE),
15083 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15084 if (!pExitRec)
15085 {
15086 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
15087 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving result in AL/AX/EAX. */
15088
15089 uint32_t const cbValue = s_aIOSizes[uIOSize];
15090 uint32_t const cbInstr = pVmxTransient->cbInstr;
15091 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
15092 PVM pVM = pVCpu->CTX_SUFF(pVM);
15093 if (fIOString)
15094 {
15095 /*
15096 * INS/OUTS - I/O String instruction.
15097 *
15098 * Use instruction-information if available, otherwise fall back on
15099 * interpreting the instruction.
15100 */
15101 Log4Func(("cs:rip=%#04x:%#RX64 %#06x/%u %c str\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15102 AssertReturn(pCtx->dx == uIOPort, VERR_VMX_IPE_2);
15103 bool const fInsOutsInfo = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS);
15104 if (fInsOutsInfo)
15105 {
15106 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15107 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
15108 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
15109 IEMMODE const enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
15110 bool const fRep = VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual);
15111 if (fIOWrite)
15112 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
15113 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
15114 else
15115 {
15116 /*
15117 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
15118 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
15119 * See Intel Instruction spec. for "INS".
15120 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
15121 */
15122 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
15123 }
15124 }
15125 else
15126 rcStrict = IEMExecOne(pVCpu);
15127
15128 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15129 fUpdateRipAlready = true;
15130 }
15131 else
15132 {
15133 /*
15134 * IN/OUT - I/O instruction.
15135 */
15136 Log4Func(("cs:rip=%04x:%08RX64 %#06x/%u %c\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15137 uint32_t const uAndVal = s_aIOOpAnd[uIOSize];
15138 Assert(!VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual));
15139 if (fIOWrite)
15140 {
15141 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pCtx->eax & uAndVal, cbValue);
15142 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
15143 if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15144 && !pCtx->eflags.Bits.u1TF)
15145 rcStrict = EMRZSetPendingIoPortWrite(pVCpu, uIOPort, cbInstr, cbValue, pCtx->eax & uAndVal);
15146 }
15147 else
15148 {
15149 uint32_t u32Result = 0;
15150 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
15151 if (IOM_SUCCESS(rcStrict))
15152 {
15153 /* Save result of I/O IN instr. in AL/AX/EAX. */
15154 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Result & uAndVal);
15155 }
15156 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15157 && !pCtx->eflags.Bits.u1TF)
15158 rcStrict = EMRZSetPendingIoPortRead(pVCpu, uIOPort, cbInstr, cbValue);
15159 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
15160 }
15161 }
15162
15163 if (IOM_SUCCESS(rcStrict))
15164 {
15165 if (!fUpdateRipAlready)
15166 {
15167 hmR0VmxAdvanceGuestRipBy(pVCpu, cbInstr);
15168 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15169 }
15170
15171 /*
15172 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru
15173 * while booting Fedora 17 64-bit guest.
15174 *
15175 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
15176 */
15177 if (fIOString)
15178 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RFLAGS);
15179
15180 /*
15181 * If any I/O breakpoints are armed, we need to check if one triggered
15182 * and take appropriate action.
15183 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
15184 */
15185 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_DR7);
15186 AssertRCReturn(rc, rc);
15187
15188 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
15189 * execution engines about whether hyper BPs and such are pending. */
15190 uint32_t const uDr7 = pCtx->dr[7];
15191 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
15192 && X86_DR7_ANY_RW_IO(uDr7)
15193 && (pCtx->cr4 & X86_CR4_DE))
15194 || DBGFBpIsHwIoArmed(pVM)))
15195 {
15196 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
15197
15198 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
15199 VMMRZCallRing3Disable(pVCpu);
15200 HM_DISABLE_PREEMPT(pVCpu);
15201
15202 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
15203
15204 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, uIOPort, cbValue);
15205 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
15206 {
15207 /* Raise #DB. */
15208 if (fIsGuestDbgActive)
15209 ASMSetDR6(pCtx->dr[6]);
15210 if (pCtx->dr[7] != uDr7)
15211 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_DR7;
15212
15213 hmR0VmxSetPendingXcptDB(pVCpu);
15214 }
15215 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
15216 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
15217 else if ( rcStrict2 != VINF_SUCCESS
15218 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
15219 rcStrict = rcStrict2;
15220 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
15221
15222 HM_RESTORE_PREEMPT();
15223 VMMRZCallRing3Enable(pVCpu);
15224 }
15225 }
15226
15227#ifdef VBOX_STRICT
15228 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15229 || rcStrict == VINF_EM_PENDING_R3_IOPORT_READ)
15230 Assert(!fIOWrite);
15231 else if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15232 || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
15233 || rcStrict == VINF_EM_PENDING_R3_IOPORT_WRITE)
15234 Assert(fIOWrite);
15235 else
15236 {
15237# if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
15238 * statuses, that the VMM device and some others may return. See
15239 * IOM_SUCCESS() for guidance. */
15240 AssertMsg( RT_FAILURE(rcStrict)
15241 || rcStrict == VINF_SUCCESS
15242 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
15243 || rcStrict == VINF_EM_DBG_BREAKPOINT
15244 || rcStrict == VINF_EM_RAW_GUEST_TRAP
15245 || rcStrict == VINF_EM_RAW_TO_R3
15246 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15247# endif
15248 }
15249#endif
15250 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
15251 }
15252 else
15253 {
15254 /*
15255 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
15256 */
15257 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15258 AssertRCReturn(rc2, rc2);
15259 STAM_COUNTER_INC(!fIOString ? fIOWrite ? &pVCpu->hm.s.StatExitIOWrite : &pVCpu->hm.s.StatExitIORead
15260 : fIOWrite ? &pVCpu->hm.s.StatExitIOStringWrite : &pVCpu->hm.s.StatExitIOStringRead);
15261 Log4(("IOExit/%u: %04x:%08RX64: %s%s%s %#x LB %u -> EMHistoryExec\n",
15262 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15263 VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual) ? "REP " : "",
15264 fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOSize));
15265
15266 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15267 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15268
15269 Log4(("IOExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15270 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15271 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15272 }
15273 return rcStrict;
15274}
15275
15276
15277/**
15278 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
15279 * VM-exit.
15280 */
15281HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15282{
15283 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15284
15285 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
15286 hmR0VmxReadExitQualVmcs(pVmxTransient);
15287 if (VMX_EXIT_QUAL_TASK_SWITCH_TYPE(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT)
15288 {
15289 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15290 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
15291 {
15292 uint32_t uErrCode;
15293 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uIdtVectoringInfo))
15294 {
15295 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15296 uErrCode = pVmxTransient->uIdtVectoringErrorCode;
15297 }
15298 else
15299 uErrCode = 0;
15300
15301 RTGCUINTPTR GCPtrFaultAddress;
15302 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(pVmxTransient->uIdtVectoringInfo))
15303 GCPtrFaultAddress = pVCpu->cpum.GstCtx.cr2;
15304 else
15305 GCPtrFaultAddress = 0;
15306
15307 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15308
15309 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
15310 pVmxTransient->cbInstr, uErrCode, GCPtrFaultAddress);
15311
15312 Log4Func(("Pending event. uIntType=%#x uVector=%#x\n", VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo),
15313 VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo)));
15314 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15315 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15316 }
15317 }
15318
15319 /* Fall back to the interpreter to emulate the task-switch. */
15320 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15321 return VERR_EM_INTERPRETER;
15322}
15323
15324
15325/**
15326 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
15327 */
15328HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15329{
15330 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15331
15332 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15333 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
15334 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15335 AssertRC(rc);
15336 return VINF_EM_DBG_STEPPED;
15337}
15338
15339
15340/**
15341 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
15342 */
15343HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15344{
15345 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15346 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
15347
15348 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15349 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15350 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15351 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15352 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15353
15354 /*
15355 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15356 */
15357 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15358 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15359 {
15360 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
15361 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
15362 {
15363 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15364 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15365 }
15366 }
15367 else
15368 {
15369 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15370 return rcStrict;
15371 }
15372
15373 /* IOMMIOPhysHandler() below may call into IEM, save the necessary state. */
15374 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15375 hmR0VmxReadExitQualVmcs(pVmxTransient);
15376 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15377 AssertRCReturn(rc, rc);
15378
15379 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
15380 uint32_t const uAccessType = VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual);
15381 switch (uAccessType)
15382 {
15383 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
15384 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
15385 {
15386 AssertMsg( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
15387 || VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual) != XAPIC_OFF_TPR,
15388 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
15389
15390 RTGCPHYS GCPhys = pVCpu->hm.s.vmx.u64GstMsrApicBase; /* Always up-to-date, as it is not part of the VMCS. */
15391 GCPhys &= PAGE_BASE_GC_MASK;
15392 GCPhys += VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual);
15393 Log4Func(("Linear access uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
15394 VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual)));
15395
15396 PVM pVM = pVCpu->CTX_SUFF(pVM);
15397 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15398 rcStrict = IOMMMIOPhysHandler(pVM, pVCpu,
15399 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW,
15400 CPUMCTX2CORE(pCtx), GCPhys);
15401 Log4Func(("IOMMMIOPhysHandler returned %Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15402 if ( rcStrict == VINF_SUCCESS
15403 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15404 || rcStrict == VERR_PAGE_NOT_PRESENT)
15405 {
15406 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15407 | HM_CHANGED_GUEST_APIC_TPR);
15408 rcStrict = VINF_SUCCESS;
15409 }
15410 break;
15411 }
15412
15413 default:
15414 {
15415 Log4Func(("uAccessType=%#x\n", uAccessType));
15416 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
15417 break;
15418 }
15419 }
15420
15421 if (rcStrict != VINF_SUCCESS)
15422 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
15423 return rcStrict;
15424}
15425
15426
15427/**
15428 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
15429 * VM-exit.
15430 */
15431HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15432{
15433 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15434 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15435
15436 /* We might get this VM-exit if the nested-guest is not intercepting MOV DRx accesses. */
15437 if (!pVmxTransient->fIsNestedGuest)
15438 {
15439 /* We should -not- get this VM-exit if the guest's debug registers were active. */
15440 if (pVmxTransient->fWasGuestDebugStateActive)
15441 {
15442 AssertMsgFailed(("Unexpected MOV DRx exit\n"));
15443 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
15444 }
15445
15446 if ( !pVCpu->hm.s.fSingleInstruction
15447 && !pVmxTransient->fWasHyperDebugStateActive)
15448 {
15449 Assert(!DBGFIsStepping(pVCpu));
15450 Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB));
15451
15452 /* Don't intercept MOV DRx any more. */
15453 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
15454 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15455 AssertRC(rc);
15456
15457 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
15458 VMMRZCallRing3Disable(pVCpu);
15459 HM_DISABLE_PREEMPT(pVCpu);
15460
15461 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
15462 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
15463 Assert(CPUMIsGuestDebugStateActive(pVCpu));
15464
15465 HM_RESTORE_PREEMPT();
15466 VMMRZCallRing3Enable(pVCpu);
15467
15468#ifdef VBOX_WITH_STATISTICS
15469 hmR0VmxReadExitQualVmcs(pVmxTransient);
15470 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
15471 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
15472 else
15473 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
15474#endif
15475 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
15476 return VINF_SUCCESS;
15477 }
15478 }
15479
15480 /*
15481 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER MSR, CS.
15482 * The EFER MSR is always up-to-date.
15483 * Update the segment registers and DR7 from the CPU.
15484 */
15485 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15486 hmR0VmxReadExitQualVmcs(pVmxTransient);
15487 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_DR7);
15488 AssertRCReturn(rc, rc);
15489 Log4Func(("cs:rip=%#04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
15490
15491 PVM pVM = pVCpu->CTX_SUFF(pVM);
15492 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
15493 {
15494 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pCtx),
15495 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual),
15496 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual));
15497 if (RT_SUCCESS(rc))
15498 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
15499 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
15500 }
15501 else
15502 {
15503 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pCtx),
15504 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual),
15505 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual));
15506 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
15507 }
15508
15509 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
15510 if (RT_SUCCESS(rc))
15511 {
15512 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15513 AssertRCReturn(rc2, rc2);
15514 return VINF_SUCCESS;
15515 }
15516 return rc;
15517}
15518
15519
15520/**
15521 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
15522 * Conditional VM-exit.
15523 */
15524HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15525{
15526 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15527 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
15528
15529 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15530 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15531 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15532 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15533 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15534
15535 /*
15536 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15537 */
15538 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15539 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15540 {
15541 /*
15542 * In the unlikely case where delivering an event causes an EPT misconfig (MMIO), go back to
15543 * instruction emulation to inject the original event. Otherwise, injecting the original event
15544 * using hardware-assisted VMX would would trigger the same EPT misconfig VM-exit again.
15545 */
15546 if (!pVCpu->hm.s.Event.fPending)
15547 { /* likely */ }
15548 else
15549 {
15550 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15551#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
15552 /** @todo NSTVMX: Think about how this should be handled. */
15553 if (pVmxTransient->fIsNestedGuest)
15554 return VERR_VMX_IPE_3;
15555#endif
15556 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15557 }
15558 }
15559 else
15560 {
15561 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15562 return rcStrict;
15563 }
15564
15565 /*
15566 * Get sufficent state and update the exit history entry.
15567 */
15568 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15569 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
15570 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15571 AssertRCReturn(rc, rc);
15572
15573 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
15574 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15575 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_MMIO),
15576 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15577 if (!pExitRec)
15578 {
15579 /*
15580 * If we succeed, resume guest execution.
15581 * If we fail in interpreting the instruction because we couldn't get the guest physical address
15582 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
15583 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
15584 * weird case. See @bugref{6043}.
15585 */
15586 PVM pVM = pVCpu->CTX_SUFF(pVM);
15587 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15588 rcStrict = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pCtx), GCPhys, UINT32_MAX);
15589 Log4Func(("At %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pCtx->rip, VBOXSTRICTRC_VAL(rcStrict)));
15590 if ( rcStrict == VINF_SUCCESS
15591 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15592 || rcStrict == VERR_PAGE_NOT_PRESENT)
15593 {
15594 /* Successfully handled MMIO operation. */
15595 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15596 | HM_CHANGED_GUEST_APIC_TPR);
15597 rcStrict = VINF_SUCCESS;
15598 }
15599 }
15600 else
15601 {
15602 /*
15603 * Frequent exit or something needing probing. Call EMHistoryExec.
15604 */
15605 Log4(("EptMisscfgExit/%u: %04x:%08RX64: %RGp -> EMHistoryExec\n",
15606 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPhys));
15607
15608 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15609 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15610
15611 Log4(("EptMisscfgExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15612 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15613 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15614 }
15615 return rcStrict;
15616}
15617
15618
15619/**
15620 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
15621 * VM-exit.
15622 */
15623HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15624{
15625 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15626 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
15627
15628 hmR0VmxReadExitQualVmcs(pVmxTransient);
15629 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15630 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15631 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15632 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15633 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15634
15635 /*
15636 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15637 */
15638 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15639 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15640 {
15641 /*
15642 * If delivery of an event causes an EPT violation (true nested #PF and not MMIO),
15643 * we shall resolve the nested #PF and re-inject the original event.
15644 */
15645 if (pVCpu->hm.s.Event.fPending)
15646 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflectNPF);
15647 }
15648 else
15649 {
15650 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15651 return rcStrict;
15652 }
15653
15654 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15655 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
15656 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15657 AssertRCReturn(rc, rc);
15658
15659 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
15660 uint64_t const uExitQual = pVmxTransient->uExitQual;
15661 AssertMsg(((pVmxTransient->uExitQual >> 7) & 3) != 2, ("%#RX64", uExitQual));
15662
15663 RTGCUINT uErrorCode = 0;
15664 if (uExitQual & VMX_EXIT_QUAL_EPT_INSTR_FETCH)
15665 uErrorCode |= X86_TRAP_PF_ID;
15666 if (uExitQual & VMX_EXIT_QUAL_EPT_DATA_WRITE)
15667 uErrorCode |= X86_TRAP_PF_RW;
15668 if (uExitQual & VMX_EXIT_QUAL_EPT_ENTRY_PRESENT)
15669 uErrorCode |= X86_TRAP_PF_P;
15670
15671 PVM pVM = pVCpu->CTX_SUFF(pVM);
15672 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15673 Log4Func(("at %#RX64 (%#RX64 errcode=%#x) cs:rip=%#04x:%#RX64\n", GCPhys, uExitQual, uErrorCode, pCtx->cs.Sel, pCtx->rip));
15674
15675 /*
15676 * Handle the pagefault trap for the nested shadow table.
15677 */
15678 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
15679 rcStrict = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pCtx), GCPhys);
15680 TRPMResetTrap(pVCpu);
15681
15682 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
15683 if ( rcStrict == VINF_SUCCESS
15684 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15685 || rcStrict == VERR_PAGE_NOT_PRESENT)
15686 {
15687 /* Successfully synced our nested page tables. */
15688 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
15689 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS);
15690 return VINF_SUCCESS;
15691 }
15692
15693 Log4Func(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15694 return rcStrict;
15695}
15696
15697
15698#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
15699/**
15700 * VM-exit handler for VMCLEAR (VMX_EXIT_VMCLEAR). Unconditional VM-exit.
15701 */
15702HMVMX_EXIT_DECL hmR0VmxExitVmclear(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15703{
15704 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15705
15706 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15707 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15708 hmR0VmxReadExitQualVmcs(pVmxTransient);
15709 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15710 | CPUMCTX_EXTRN_HWVIRT
15711 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15712 AssertRCReturn(rc, rc);
15713
15714 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15715
15716 VMXVEXITINFO ExitInfo;
15717 RT_ZERO(ExitInfo);
15718 ExitInfo.uReason = pVmxTransient->uExitReason;
15719 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15720 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15721 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15722 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15723
15724 VBOXSTRICTRC rcStrict = IEMExecDecodedVmclear(pVCpu, &ExitInfo);
15725 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15726 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15727 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15728 {
15729 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15730 rcStrict = VINF_SUCCESS;
15731 }
15732 return rcStrict;
15733}
15734
15735
15736/**
15737 * VM-exit handler for VMLAUNCH (VMX_EXIT_VMLAUNCH). Unconditional VM-exit.
15738 */
15739HMVMX_EXIT_DECL hmR0VmxExitVmlaunch(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15740{
15741 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15742
15743 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMLAUNCH,
15744 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
15745 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15746 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15747 AssertRCReturn(rc, rc);
15748
15749 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15750
15751 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
15752 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbInstr, VMXINSTRID_VMLAUNCH);
15753 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
15754 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15755 {
15756 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15757 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
15758 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
15759 }
15760 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15761 return rcStrict;
15762}
15763
15764
15765/**
15766 * VM-exit handler for VMPTRLD (VMX_EXIT_VMPTRLD). Unconditional VM-exit.
15767 */
15768HMVMX_EXIT_DECL hmR0VmxExitVmptrld(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15769{
15770 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15771
15772 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15773 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15774 hmR0VmxReadExitQualVmcs(pVmxTransient);
15775 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15776 | CPUMCTX_EXTRN_HWVIRT
15777 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15778 AssertRCReturn(rc, rc);
15779
15780 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15781
15782 VMXVEXITINFO ExitInfo;
15783 RT_ZERO(ExitInfo);
15784 ExitInfo.uReason = pVmxTransient->uExitReason;
15785 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15786 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15787 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15788 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15789
15790 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrld(pVCpu, &ExitInfo);
15791 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15792 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15793 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15794 {
15795 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15796 rcStrict = VINF_SUCCESS;
15797 }
15798 return rcStrict;
15799}
15800
15801
15802/**
15803 * VM-exit handler for VMPTRST (VMX_EXIT_VMPTRST). Unconditional VM-exit.
15804 */
15805HMVMX_EXIT_DECL hmR0VmxExitVmptrst(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15806{
15807 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15808
15809 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15810 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15811 hmR0VmxReadExitQualVmcs(pVmxTransient);
15812 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15813 | CPUMCTX_EXTRN_HWVIRT
15814 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15815 AssertRCReturn(rc, rc);
15816
15817 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15818
15819 VMXVEXITINFO ExitInfo;
15820 RT_ZERO(ExitInfo);
15821 ExitInfo.uReason = pVmxTransient->uExitReason;
15822 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15823 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15824 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15825 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
15826
15827 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrst(pVCpu, &ExitInfo);
15828 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15829 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15830 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15831 {
15832 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15833 rcStrict = VINF_SUCCESS;
15834 }
15835 return rcStrict;
15836}
15837
15838
15839/**
15840 * VM-exit handler for VMREAD (VMX_EXIT_VMREAD). Conditional VM-exit.
15841 */
15842HMVMX_EXIT_DECL hmR0VmxExitVmread(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15843{
15844 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15845
15846 /*
15847 * Strictly speaking we should not get VMREAD VM-exits for shadow VMCS fields and
15848 * thus might not need to import the shadow VMCS state, it's safer just in case
15849 * code elsewhere dares look at unsynced VMCS fields.
15850 */
15851 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15852 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15853 hmR0VmxReadExitQualVmcs(pVmxTransient);
15854 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15855 | CPUMCTX_EXTRN_HWVIRT
15856 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15857 AssertRCReturn(rc, rc);
15858
15859 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15860
15861 VMXVEXITINFO ExitInfo;
15862 RT_ZERO(ExitInfo);
15863 ExitInfo.uReason = pVmxTransient->uExitReason;
15864 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15865 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15866 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15867 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
15868 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
15869
15870 VBOXSTRICTRC rcStrict = IEMExecDecodedVmread(pVCpu, &ExitInfo);
15871 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15872 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15873 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15874 {
15875 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15876 rcStrict = VINF_SUCCESS;
15877 }
15878 return rcStrict;
15879}
15880
15881
15882/**
15883 * VM-exit handler for VMRESUME (VMX_EXIT_VMRESUME). Unconditional VM-exit.
15884 */
15885HMVMX_EXIT_DECL hmR0VmxExitVmresume(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15886{
15887 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15888
15889 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMRESUME,
15890 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
15891 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15892 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15893 AssertRCReturn(rc, rc);
15894
15895 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15896
15897 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
15898 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbInstr, VMXINSTRID_VMRESUME);
15899 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
15900 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15901 {
15902 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15903 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
15904 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
15905 }
15906 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15907 return rcStrict;
15908}
15909
15910
15911/**
15912 * VM-exit handler for VMWRITE (VMX_EXIT_VMWRITE). Conditional VM-exit.
15913 */
15914HMVMX_EXIT_DECL hmR0VmxExitVmwrite(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15915{
15916 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15917
15918 /*
15919 * Although we should not get VMWRITE VM-exits for shadow VMCS fields, since our HM hook
15920 * gets invoked when IEM's VMWRITE instruction emulation modifies the current VMCS and it
15921 * flags re-loading the entire shadow VMCS, we should save the entire shadow VMCS here.
15922 */
15923 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15924 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15925 hmR0VmxReadExitQualVmcs(pVmxTransient);
15926 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15927 | CPUMCTX_EXTRN_HWVIRT
15928 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15929 AssertRCReturn(rc, rc);
15930
15931 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15932
15933 VMXVEXITINFO ExitInfo;
15934 RT_ZERO(ExitInfo);
15935 ExitInfo.uReason = pVmxTransient->uExitReason;
15936 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15937 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15938 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15939 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
15940 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15941
15942 VBOXSTRICTRC rcStrict = IEMExecDecodedVmwrite(pVCpu, &ExitInfo);
15943 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15944 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15945 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15946 {
15947 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15948 rcStrict = VINF_SUCCESS;
15949 }
15950 return rcStrict;
15951}
15952
15953
15954/**
15955 * VM-exit handler for VMXOFF (VMX_EXIT_VMXOFF). Unconditional VM-exit.
15956 */
15957HMVMX_EXIT_DECL hmR0VmxExitVmxoff(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15958{
15959 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15960
15961 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15962 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR4
15963 | CPUMCTX_EXTRN_HWVIRT
15964 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
15965 AssertRCReturn(rc, rc);
15966
15967 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15968
15969 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxoff(pVCpu, pVmxTransient->cbInstr);
15970 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15971 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_HWVIRT);
15972 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15973 {
15974 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15975 rcStrict = VINF_SUCCESS;
15976 }
15977 return rcStrict;
15978}
15979
15980
15981/**
15982 * VM-exit handler for VMXON (VMX_EXIT_VMXON). Unconditional VM-exit.
15983 */
15984HMVMX_EXIT_DECL hmR0VmxExitVmxon(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15985{
15986 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15987
15988 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15989 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15990 hmR0VmxReadExitQualVmcs(pVmxTransient);
15991 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15992 | CPUMCTX_EXTRN_HWVIRT
15993 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15994 AssertRCReturn(rc, rc);
15995
15996 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15997
15998 VMXVEXITINFO ExitInfo;
15999 RT_ZERO(ExitInfo);
16000 ExitInfo.uReason = pVmxTransient->uExitReason;
16001 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16002 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16003 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16004 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16005
16006 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxon(pVCpu, &ExitInfo);
16007 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16008 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16009 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16010 {
16011 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16012 rcStrict = VINF_SUCCESS;
16013 }
16014 return rcStrict;
16015}
16016
16017
16018/**
16019 * VM-exit handler for INVVPID (VMX_EXIT_INVVPID). Unconditional VM-exit.
16020 */
16021HMVMX_EXIT_DECL hmR0VmxExitInvvpid(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16022{
16023 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16024
16025 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16026 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16027 hmR0VmxReadExitQualVmcs(pVmxTransient);
16028 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16029 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16030 AssertRCReturn(rc, rc);
16031
16032 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16033
16034 VMXVEXITINFO ExitInfo;
16035 RT_ZERO(ExitInfo);
16036 ExitInfo.uReason = pVmxTransient->uExitReason;
16037 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16038 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16039 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16040 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16041
16042 VBOXSTRICTRC rcStrict = IEMExecDecodedInvvpid(pVCpu, &ExitInfo);
16043 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16044 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16045 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16046 {
16047 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16048 rcStrict = VINF_SUCCESS;
16049 }
16050 return rcStrict;
16051}
16052#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16053/** @} */
16054
16055
16056#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16057/** @name Nested-guest VM-exit handlers.
16058 * @{
16059 */
16060/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16061/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Nested-guest VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16062/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16063
16064/**
16065 * Nested-guest VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
16066 * Conditional VM-exit.
16067 */
16068HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmiNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16069{
16070 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16071
16072 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16073
16074 uint64_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
16075 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
16076 Assert(VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo));
16077
16078 switch (uExitIntType)
16079 {
16080 /*
16081 * Physical NMIs:
16082 * We shouldn't direct host physical NMIs to the nested-guest. Dispatch it to the host.
16083 */
16084 case VMX_EXIT_INT_INFO_TYPE_NMI:
16085 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
16086
16087 /*
16088 * Hardware exceptions,
16089 * Software exceptions,
16090 * Privileged software exceptions:
16091 * Figure out if the exception must be delivered to the guest or the nested-guest.
16092 */
16093 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
16094 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
16095 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
16096 {
16097 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16098 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16099 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16100 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16101
16102 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16103 bool const fIntercept = CPUMIsGuestVmxXcptInterceptSet(pVCpu, pCtx, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo),
16104 pVmxTransient->uExitIntErrorCode);
16105 if (fIntercept)
16106 {
16107 /* Exit qualification is required for debug and page-fault exceptions. */
16108 hmR0VmxReadExitQualVmcs(pVmxTransient);
16109
16110 /*
16111 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged
16112 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
16113 * length. However, if delivery of a software interrupt, software exception or privileged
16114 * software exception causes a VM-exit, that too provides the VM-exit instruction length.
16115 */
16116 VMXVEXITINFO ExitInfo;
16117 RT_ZERO(ExitInfo);
16118 ExitInfo.uReason = pVmxTransient->uExitReason;
16119 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16120 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16121
16122 VMXVEXITEVENTINFO ExitEventInfo;
16123 RT_ZERO(ExitEventInfo);
16124 ExitEventInfo.uExitIntInfo = pVmxTransient->uExitIntInfo;
16125 ExitEventInfo.uExitIntErrCode = pVmxTransient->uExitIntErrorCode;
16126 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16127 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16128
16129#ifdef DEBUG_ramshankar
16130 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
16131 Log4Func(("cs:rip=%#04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
16132 Log4Func(("exit_int_info=%#x err_code=%#x exit_qual=%#RX64\n", pVmxTransient->uExitIntInfo,
16133 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual));
16134 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
16135 {
16136 Log4Func(("idt_info=%#RX32 idt_errcode=%#RX32\n", pVmxTransient->uIdtVectoringInfo,
16137 pVmxTransient->uIdtVectoringErrorCode));
16138 }
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 Log4Func(("at offset %#x type=%u\n", VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual),
16729 VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual)));
16730
16731 VMXVEXITINFO ExitInfo;
16732 RT_ZERO(ExitInfo);
16733 ExitInfo.uReason = pVmxTransient->uExitReason;
16734 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16735 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16736
16737 VMXVEXITEVENTINFO ExitEventInfo;
16738 RT_ZERO(ExitEventInfo);
16739 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16740 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16741 return IEMExecVmxVmexitApicAccess(pVCpu, &ExitInfo, &ExitEventInfo);
16742}
16743
16744
16745/**
16746 * Nested-guest VM-exit handler for APIC write emulation (VMX_EXIT_APIC_WRITE).
16747 * Conditional VM-exit.
16748 */
16749HMVMX_EXIT_DECL hmR0VmxExitApicWriteNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16750{
16751 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16752
16753 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_APIC_REG_VIRT));
16754 hmR0VmxReadExitQualVmcs(pVmxTransient);
16755 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
16756}
16757
16758
16759/**
16760 * Nested-guest VM-exit handler for virtualized EOI (VMX_EXIT_VIRTUALIZED_EOI).
16761 * Conditional VM-exit.
16762 */
16763HMVMX_EXIT_DECL hmR0VmxExitVirtEoiNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16764{
16765 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16766
16767 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_INT_DELIVERY));
16768 hmR0VmxReadExitQualVmcs(pVmxTransient);
16769 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
16770}
16771
16772
16773/**
16774 * Nested-guest VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
16775 */
16776HMVMX_EXIT_DECL hmR0VmxExitRdtscpNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16777{
16778 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16779
16780 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16781 {
16782 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_RDTSCP));
16783 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16784 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16785 }
16786 return hmR0VmxExitRdtscp(pVCpu, pVmxTransient);
16787}
16788
16789
16790/**
16791 * Nested-guest VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
16792 */
16793HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvdNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16794{
16795 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16796
16797 if (CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_WBINVD_EXIT))
16798 {
16799 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16800 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16801 }
16802 return hmR0VmxExitWbinvd(pVCpu, pVmxTransient);
16803}
16804
16805
16806/**
16807 * Nested-guest VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
16808 */
16809HMVMX_EXIT_DECL hmR0VmxExitInvpcidNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16810{
16811 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16812
16813 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16814 {
16815 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_INVPCID));
16816 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16817 hmR0VmxReadExitQualVmcs(pVmxTransient);
16818 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16819
16820 VMXVEXITINFO ExitInfo;
16821 RT_ZERO(ExitInfo);
16822 ExitInfo.uReason = pVmxTransient->uExitReason;
16823 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16824 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16825 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16826 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16827 }
16828 return hmR0VmxExitInvpcid(pVCpu, pVmxTransient);
16829}
16830
16831
16832/**
16833 * Nested-guest VM-exit handler for invalid-guest state
16834 * (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error VM-exit.
16835 */
16836HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestStateNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16837{
16838 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16839
16840 /*
16841 * Currently this should never happen because we fully emulate VMLAUNCH/VMRESUME in IEM.
16842 * So if it does happen, it indicates a bug possibly in the hardware-assisted VMX code.
16843 * Handle it like it's in an invalid guest state of the outer guest.
16844 *
16845 * When the fast path is implemented, this should be changed to cause the corresponding
16846 * nested-guest VM-exit.
16847 */
16848 return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
16849}
16850
16851
16852/**
16853 * Nested-guest VM-exit handler for instructions that cause VM-exits uncondtionally
16854 * and only provide the instruction length.
16855 *
16856 * Unconditional VM-exit.
16857 */
16858HMVMX_EXIT_DECL hmR0VmxExitInstrNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16859{
16860 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16861
16862#ifdef VBOX_STRICT
16863 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16864 switch (pVmxTransient->uExitReason)
16865 {
16866 case VMX_EXIT_ENCLS:
16867 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_ENCLS_EXIT));
16868 break;
16869
16870 case VMX_EXIT_VMFUNC:
16871 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_VMFUNC));
16872 break;
16873 }
16874#endif
16875
16876 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16877 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16878}
16879
16880
16881/**
16882 * Nested-guest VM-exit handler for instructions that provide instruction length as
16883 * well as more information.
16884 *
16885 * Unconditional VM-exit.
16886 */
16887HMVMX_EXIT_DECL hmR0VmxExitInstrWithInfoNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16888{
16889 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16890
16891#ifdef VBOX_STRICT
16892 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16893 switch (pVmxTransient->uExitReason)
16894 {
16895 case VMX_EXIT_GDTR_IDTR_ACCESS:
16896 case VMX_EXIT_LDTR_TR_ACCESS:
16897 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_DESC_TABLE_EXIT));
16898 break;
16899
16900 case VMX_EXIT_RDRAND:
16901 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_RDRAND_EXIT));
16902 break;
16903
16904 case VMX_EXIT_RDSEED:
16905 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_RDSEED_EXIT));
16906 break;
16907
16908 case VMX_EXIT_XSAVES:
16909 case VMX_EXIT_XRSTORS:
16910 /** @todo NSTVMX: Verify XSS-bitmap. */
16911 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_XSAVES_XRSTORS));
16912 break;
16913
16914 case VMX_EXIT_UMWAIT:
16915 case VMX_EXIT_TPAUSE:
16916 Assert(CPUMIsGuestVmxProcCtlsSet(pVCpu, pCtx, VMX_PROC_CTLS_RDTSC_EXIT));
16917 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_USER_WAIT_PAUSE));
16918 break;
16919 }
16920#endif
16921
16922 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16923 hmR0VmxReadExitQualVmcs(pVmxTransient);
16924 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16925
16926 VMXVEXITINFO ExitInfo;
16927 RT_ZERO(ExitInfo);
16928 ExitInfo.uReason = pVmxTransient->uExitReason;
16929 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16930 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16931 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16932 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16933}
16934
16935/** @} */
16936#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16937
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette