VirtualBox

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

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

VMM/HMVMXR0: Nested VMX: bugref:9180 APIC-access/virtual-APIC page nits.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 700.3 KB
Line 
1/* $Id: HMVMXR0.cpp 80170 2019-08-07 04:59:59Z 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 = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS);
5003 AssertRC(rc);
5004 }
5005 /** @todo NSTVMX: Handling copying of VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS from
5006 * nested-guest VMCS. */
5007
5008 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RFLAGS);
5009 Log4Func(("eflags=%#RX32\n", fEFlags.u32));
5010 }
5011 return VINF_SUCCESS;
5012}
5013
5014
5015#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5016/**
5017 * Copies the nested-guest VMCS to the shadow VMCS.
5018 *
5019 * @returns VBox status code.
5020 * @param pVCpu The cross context virtual CPU structure.
5021 * @param pVmcsInfo The VMCS info. object.
5022 *
5023 * @remarks No-long-jump zone!!!
5024 */
5025static int hmR0VmxCopyNstGstToShadowVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
5026{
5027 PVM pVM = pVCpu->CTX_SUFF(pVM);
5028 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5029
5030 /*
5031 * Disable interrupts so we don't get preempted while the shadow VMCS is the
5032 * current VMCS, as we may try saving guest lazy MSRs.
5033 *
5034 * Strictly speaking the lazy MSRs are not in the VMCS, but I'd rather not risk
5035 * calling the import VMCS code which is currently performing the guest MSR reads
5036 * (on 64-bit hosts) and accessing the auto-load/store MSR area on 32-bit hosts
5037 * and the rest of the VMX leave session machinery.
5038 */
5039 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
5040
5041 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5042 if (RT_SUCCESS(rc))
5043 {
5044 /*
5045 * Copy all guest read/write VMCS fields.
5046 *
5047 * We don't check for VMWRITE failures here for performance reasons and
5048 * because they are not expected to fail, barring irrecoverable conditions
5049 * like hardware errors.
5050 */
5051 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
5052 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5053 {
5054 uint64_t u64Val;
5055 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
5056 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5057 VMXWriteVmcs64(uVmcsField, u64Val);
5058 }
5059
5060 /*
5061 * If the host CPU supports writing all VMCS fields, copy the guest read-only
5062 * VMCS fields, so the guest can VMREAD them without causing a VM-exit.
5063 */
5064 if (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL)
5065 {
5066 uint32_t const cShadowVmcsRoFields = pVM->hm.s.vmx.cShadowVmcsRoFields;
5067 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
5068 {
5069 uint64_t u64Val;
5070 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsRoFields[i];
5071 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5072 VMXWriteVmcs64(uVmcsField, u64Val);
5073 }
5074 }
5075
5076 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5077 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5078 }
5079
5080 ASMSetFlags(fEFlags);
5081 return rc;
5082}
5083
5084
5085/**
5086 * Copies the shadow VMCS to the nested-guest VMCS.
5087 *
5088 * @returns VBox status code.
5089 * @param pVCpu The cross context virtual CPU structure.
5090 * @param pVmcsInfo The VMCS info. object.
5091 *
5092 * @remarks Called with interrupts disabled.
5093 */
5094static int hmR0VmxCopyShadowToNstGstVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
5095{
5096 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5097 PVM pVM = pVCpu->CTX_SUFF(pVM);
5098 PVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5099
5100 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5101 if (RT_SUCCESS(rc))
5102 {
5103 /*
5104 * Copy guest read/write fields from the shadow VMCS.
5105 * Guest read-only fields cannot be modified, so no need to copy them.
5106 *
5107 * We don't check for VMREAD failures here for performance reasons and
5108 * because they are not expected to fail, barring irrecoverable conditions
5109 * like hardware errors.
5110 */
5111 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
5112 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5113 {
5114 uint64_t u64Val;
5115 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
5116 VMXReadVmcs64(uVmcsField, &u64Val);
5117 IEMWriteVmxVmcsField(pVmcsNstGst, uVmcsField, u64Val);
5118 }
5119
5120 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5121 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5122 }
5123 return rc;
5124}
5125
5126
5127/**
5128 * Enables VMCS shadowing for the given VMCS info. object.
5129 *
5130 * @param pVmcsInfo The VMCS info. object.
5131 *
5132 * @remarks No-long-jump zone!!!
5133 */
5134static void hmR0VmxEnableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5135{
5136 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5137 if (!(uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING))
5138 {
5139 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
5140 uProcCtls2 |= VMX_PROC_CTLS2_VMCS_SHADOWING;
5141 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5142 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, pVmcsInfo->HCPhysShadowVmcs); AssertRC(rc);
5143 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5144 pVmcsInfo->u64VmcsLinkPtr = pVmcsInfo->HCPhysShadowVmcs;
5145 Log4Func(("Enabled\n"));
5146 }
5147}
5148
5149
5150/**
5151 * Disables VMCS shadowing for the given VMCS info. object.
5152 *
5153 * @param pVmcsInfo The VMCS info. object.
5154 *
5155 * @remarks No-long-jump zone!!!
5156 */
5157static void hmR0VmxDisableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5158{
5159 /*
5160 * We want all VMREAD and VMWRITE instructions to cause VM-exits, so we clear the
5161 * VMCS shadowing control. However, VM-entry requires the shadow VMCS indicator bit
5162 * to match the VMCS shadowing control if the VMCS link pointer is not NIL_RTHCPHYS.
5163 * Hence, we must also reset the VMCS link pointer to ensure VM-entry does not fail.
5164 *
5165 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
5166 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5167 */
5168 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5169 if (uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
5170 {
5171 uProcCtls2 &= ~VMX_PROC_CTLS2_VMCS_SHADOWING;
5172 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5173 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS); AssertRC(rc);
5174 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5175 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
5176 Log4Func(("Disabled\n"));
5177 }
5178}
5179#endif
5180
5181
5182/**
5183 * Exports the guest hardware-virtualization state.
5184 *
5185 * @returns VBox status code.
5186 * @param pVCpu The cross context virtual CPU structure.
5187 * @param pVmxTransient The VMX-transient structure.
5188 *
5189 * @remarks No-long-jump zone!!!
5190 */
5191static int hmR0VmxExportGuestHwvirtState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
5192{
5193 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_HWVIRT)
5194 {
5195#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5196 /*
5197 * Check if the VMX feature is exposed to the guest and if the host CPU supports
5198 * VMCS shadowing.
5199 */
5200 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
5201 {
5202 /*
5203 * If the guest hypervisor has loaded a current VMCS and is in VMX root mode,
5204 * copy the guest hypervisor's current VMCS into the shadow VMCS and enable
5205 * VMCS shadowing to skip intercepting some or all VMREAD/VMWRITE VM-exits.
5206 *
5207 * We check for VMX root mode here in case the guest executes VMXOFF without
5208 * clearing the current VMCS pointer and our VMXOFF instruction emulation does
5209 * not clear the current VMCS pointer.
5210 */
5211 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5212 if ( CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx)
5213 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx)
5214 && CPUMIsGuestVmxCurrentVmcsValid(pVCpu, &pVCpu->cpum.GstCtx))
5215 {
5216 /* Paranoia. */
5217 Assert(!pVmxTransient->fIsNestedGuest);
5218
5219 /*
5220 * For performance reasons, also check if the guest hypervisor's current VMCS
5221 * was newly loaded or modified before copying it to the shadow VMCS.
5222 */
5223 if (!pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs)
5224 {
5225 int rc = hmR0VmxCopyNstGstToShadowVmcs(pVCpu, pVmcsInfo);
5226 AssertRCReturn(rc, rc);
5227 pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs = true;
5228 }
5229 hmR0VmxEnableVmcsShadowing(pVmcsInfo);
5230 }
5231 else
5232 hmR0VmxDisableVmcsShadowing(pVmcsInfo);
5233 }
5234#else
5235 NOREF(pVmxTransient);
5236#endif
5237 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_HWVIRT);
5238 }
5239 return VINF_SUCCESS;
5240}
5241
5242
5243/**
5244 * Exports the guest CR0 control register into the guest-state area in the VMCS.
5245 *
5246 * The guest FPU state is always pre-loaded hence we don't need to bother about
5247 * sharing FPU related CR0 bits between the guest and host.
5248 *
5249 * @returns VBox status code.
5250 * @param pVCpu The cross context virtual CPU structure.
5251 * @param pVmxTransient The VMX-transient structure.
5252 *
5253 * @remarks No-long-jump zone!!!
5254 */
5255static int hmR0VmxExportGuestCR0(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
5256{
5257 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR0)
5258 {
5259 PVM pVM = pVCpu->CTX_SUFF(pVM);
5260 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5261
5262 /*
5263 * Figure out fixed CR0 bits in VMX operation.
5264 */
5265 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
5266 uint64_t fSetCr0 = pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1;
5267 uint64_t const fZapCr0 = pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1;
5268 if (pVM->hm.s.vmx.fUnrestrictedGuest)
5269 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
5270 else
5271 Assert((fSetCr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
5272
5273 if (!pVmxTransient->fIsNestedGuest)
5274 {
5275 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5276 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5277 uint64_t const u64ShadowCr0 = u64GuestCr0;
5278 Assert(!RT_HI_U32(u64GuestCr0));
5279
5280 /*
5281 * Setup VT-x's view of the guest CR0.
5282 */
5283 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5284 if (pVM->hm.s.fNestedPaging)
5285 {
5286 if (CPUMIsGuestPagingEnabled(pVCpu))
5287 {
5288 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
5289 uProcCtls &= ~( VMX_PROC_CTLS_CR3_LOAD_EXIT
5290 | VMX_PROC_CTLS_CR3_STORE_EXIT);
5291 }
5292 else
5293 {
5294 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
5295 uProcCtls |= VMX_PROC_CTLS_CR3_LOAD_EXIT
5296 | VMX_PROC_CTLS_CR3_STORE_EXIT;
5297 }
5298
5299 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
5300 if (pVM->hm.s.vmx.fUnrestrictedGuest)
5301 uProcCtls &= ~VMX_PROC_CTLS_CR3_STORE_EXIT;
5302 }
5303 else
5304 {
5305 /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
5306 u64GuestCr0 |= X86_CR0_WP;
5307 }
5308
5309 /*
5310 * Guest FPU bits.
5311 *
5312 * Since we pre-load the guest FPU always before VM-entry there is no need to track lazy state
5313 * using CR0.TS.
5314 *
5315 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be
5316 * set on the first CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
5317 */
5318 u64GuestCr0 |= X86_CR0_NE;
5319
5320 /* If CR0.NE isn't set, we need to intercept #MF exceptions and report them to the guest differently. */
5321 bool const fInterceptMF = !(u64ShadowCr0 & X86_CR0_NE);
5322
5323 /*
5324 * Update exception intercepts.
5325 */
5326 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
5327 if (pVmcsInfo->RealMode.fRealOnV86Active)
5328 {
5329 Assert(PDMVmmDevHeapIsEnabled(pVM));
5330 Assert(pVM->hm.s.vmx.pRealModeTSS);
5331 uXcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
5332 }
5333 else
5334 {
5335 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
5336 uXcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
5337 if (fInterceptMF)
5338 uXcptBitmap |= RT_BIT(X86_XCPT_MF);
5339 }
5340
5341 /* Additional intercepts for debugging, define these yourself explicitly. */
5342#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
5343 uXcptBitmap |= 0
5344 | RT_BIT(X86_XCPT_BP)
5345 | RT_BIT(X86_XCPT_DE)
5346 | RT_BIT(X86_XCPT_NM)
5347 | RT_BIT(X86_XCPT_TS)
5348 | RT_BIT(X86_XCPT_UD)
5349 | RT_BIT(X86_XCPT_NP)
5350 | RT_BIT(X86_XCPT_SS)
5351 | RT_BIT(X86_XCPT_GP)
5352 | RT_BIT(X86_XCPT_PF)
5353 | RT_BIT(X86_XCPT_MF)
5354 ;
5355#elif defined(HMVMX_ALWAYS_TRAP_PF)
5356 uXcptBitmap |= RT_BIT(X86_XCPT_PF);
5357#endif
5358 if (pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv)
5359 uXcptBitmap |= RT_BIT(X86_XCPT_GP);
5360 Assert(pVM->hm.s.fNestedPaging || (uXcptBitmap & RT_BIT(X86_XCPT_PF)));
5361
5362 /* Apply the hardware specified fixed CR0 bits and enable caching. */
5363 u64GuestCr0 |= fSetCr0;
5364 u64GuestCr0 &= fZapCr0;
5365 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5366
5367 /* Commit the CR0 and related fields to the guest VMCS. */
5368 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5369 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5370 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5371 {
5372 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5373 AssertRC(rc);
5374 }
5375 if (uXcptBitmap != pVmcsInfo->u32XcptBitmap)
5376 {
5377 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
5378 AssertRC(rc);
5379 }
5380
5381 /* Update our caches. */
5382 pVmcsInfo->u32ProcCtls = uProcCtls;
5383 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
5384
5385 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5386 }
5387 else
5388 {
5389 /*
5390 * With nested-guests, we may have extended the guest/host mask here since we
5391 * merged in the outer guest's mask. Thus, the merged mask can include more bits
5392 * (to read from the nested-guest CR0 read-shadow) than the guest hypervisor
5393 * originally supplied. We must copy those bits from the nested-guest CR0 into
5394 * the nested-guest CR0 read-shadow.
5395 */
5396 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5397 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5398 uint64_t const u64ShadowCr0 = CPUMGetGuestVmxMaskedCr0(pVCpu, &pVCpu->cpum.GstCtx, pVmcsInfo->u64Cr0Mask);
5399 Assert(!RT_HI_U32(u64GuestCr0));
5400 Assert(u64GuestCr0 & X86_CR0_NE);
5401
5402 /*
5403 * Apply the hardware specified fixed CR0 bits and enable caching.
5404 * Note! We could be altering our VMX emulation's fixed bits. We thus
5405 * need to re-apply them while importing CR0.
5406 */
5407 u64GuestCr0 |= fSetCr0;
5408 u64GuestCr0 &= fZapCr0;
5409 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5410
5411 /* Commit the CR0 and CR0 read-shadow to the nested-guest VMCS. */
5412 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5413 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5414
5415 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5416 }
5417
5418 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR0);
5419 }
5420
5421 return VINF_SUCCESS;
5422}
5423
5424
5425/**
5426 * Exports the guest control registers (CR3, CR4) into the guest-state area
5427 * in the VMCS.
5428 *
5429 * @returns VBox strict status code.
5430 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
5431 * without unrestricted guest access and the VMMDev is not presently
5432 * mapped (e.g. EFI32).
5433 *
5434 * @param pVCpu The cross context virtual CPU structure.
5435 * @param pVmxTransient The VMX-transient structure.
5436 *
5437 * @remarks No-long-jump zone!!!
5438 */
5439static VBOXSTRICTRC hmR0VmxExportGuestCR3AndCR4(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
5440{
5441 int rc = VINF_SUCCESS;
5442 PVM pVM = pVCpu->CTX_SUFF(pVM);
5443
5444 /*
5445 * Guest CR2.
5446 * It's always loaded in the assembler code. Nothing to do here.
5447 */
5448
5449 /*
5450 * Guest CR3.
5451 */
5452 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR3)
5453 {
5454 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
5455
5456 RTGCPHYS GCPhysGuestCr3 = NIL_RTGCPHYS;
5457 if (pVM->hm.s.fNestedPaging)
5458 {
5459 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5460 pVmcsInfo->HCPhysEPTP = PGMGetHyperCR3(pVCpu);
5461
5462 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
5463 Assert(pVmcsInfo->HCPhysEPTP != NIL_RTHCPHYS);
5464 Assert(!(pVmcsInfo->HCPhysEPTP & UINT64_C(0xfff0000000000000)));
5465 Assert(!(pVmcsInfo->HCPhysEPTP & 0xfff));
5466
5467 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
5468 pVmcsInfo->HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
5469 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
5470
5471 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
5472 AssertMsg( ((pVmcsInfo->HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
5473 && ((pVmcsInfo->HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
5474 ("EPTP %#RX64\n", pVmcsInfo->HCPhysEPTP));
5475 AssertMsg( !((pVmcsInfo->HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
5476 || (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
5477 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVmcsInfo->HCPhysEPTP));
5478
5479 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVmcsInfo->HCPhysEPTP);
5480 AssertRC(rc);
5481
5482 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5483 if ( pVM->hm.s.vmx.fUnrestrictedGuest
5484 || CPUMIsGuestPagingEnabledEx(pCtx))
5485 {
5486 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
5487 if (CPUMIsGuestInPAEModeEx(pCtx))
5488 {
5489 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
5490 AssertRC(rc);
5491 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
5492 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
5493 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
5494 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
5495 }
5496
5497 /*
5498 * The guest's view of its CR3 is unblemished with nested paging when the
5499 * guest is using paging or we have unrestricted guest execution to handle
5500 * the guest when it's not using paging.
5501 */
5502 GCPhysGuestCr3 = pCtx->cr3;
5503 }
5504 else
5505 {
5506 /*
5507 * The guest is not using paging, but the CPU (VT-x) has to. While the guest
5508 * thinks it accesses physical memory directly, we use our identity-mapped
5509 * page table to map guest-linear to guest-physical addresses. EPT takes care
5510 * of translating it to host-physical addresses.
5511 */
5512 RTGCPHYS GCPhys;
5513 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
5514
5515 /* We obtain it here every time as the guest could have relocated this PCI region. */
5516 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
5517 if (RT_SUCCESS(rc))
5518 { /* likely */ }
5519 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
5520 {
5521 Log4Func(("VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n"));
5522 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
5523 }
5524 else
5525 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
5526
5527 GCPhysGuestCr3 = GCPhys;
5528 }
5529
5530 Log4Func(("u32GuestCr3=%#RGp (GstN)\n", GCPhysGuestCr3));
5531 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, GCPhysGuestCr3);
5532 AssertRC(rc);
5533 }
5534 else
5535 {
5536 /* Non-nested paging case, just use the hypervisor's CR3. */
5537 RTHCPHYS const HCPhysGuestCr3 = PGMGetHyperCR3(pVCpu);
5538
5539 Log4Func(("u32GuestCr3=%#RHv (HstN)\n", HCPhysGuestCr3));
5540 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, HCPhysGuestCr3);
5541 AssertRC(rc);
5542 }
5543
5544 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR3);
5545 }
5546
5547 /*
5548 * Guest CR4.
5549 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
5550 */
5551 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR4)
5552 {
5553 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5554 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5555
5556 /*
5557 * Figure out fixed CR4 bits in VMX operation.
5558 */
5559 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
5560 uint64_t const fSetCr4 = pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1;
5561 uint64_t const fZapCr4 = pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1;
5562
5563 /*
5564 * With nested-guests, we may have extended the guest/host mask here (since we
5565 * merged in the outer guest's mask, see hmR0VmxMergeVmcsNested). This means, the
5566 * mask can include more bits (to read from the nested-guest CR4 read-shadow) than
5567 * the guest hypervisor originally supplied. Thus, we should, in essence, copy
5568 * those bits from the nested-guest CR4 into the nested-guest CR4 read-shadow.
5569 */
5570 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
5571 uint64_t u64GuestCr4 = pCtx->cr4;
5572 uint64_t const u64ShadowCr4 = !pVmxTransient->fIsNestedGuest
5573 ? pCtx->cr4
5574 : CPUMGetGuestVmxMaskedCr4(pVCpu, pCtx, pVmcsInfo->u64Cr4Mask);
5575 Assert(!RT_HI_U32(u64GuestCr4));
5576
5577 /*
5578 * Setup VT-x's view of the guest CR4.
5579 *
5580 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software
5581 * interrupts to the 8086 program interrupt handler. Clear the VME bit (the interrupt
5582 * redirection bitmap is already all 0, see hmR3InitFinalizeR0())
5583 *
5584 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
5585 */
5586 if (pVmcsInfo->RealMode.fRealOnV86Active)
5587 {
5588 Assert(pVM->hm.s.vmx.pRealModeTSS);
5589 Assert(PDMVmmDevHeapIsEnabled(pVM));
5590 u64GuestCr4 &= ~(uint64_t)X86_CR4_VME;
5591 }
5592
5593 if (pVM->hm.s.fNestedPaging)
5594 {
5595 if ( !CPUMIsGuestPagingEnabledEx(pCtx)
5596 && !pVM->hm.s.vmx.fUnrestrictedGuest)
5597 {
5598 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
5599 u64GuestCr4 |= X86_CR4_PSE;
5600 /* Our identity mapping is a 32-bit page directory. */
5601 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5602 }
5603 /* else use guest CR4.*/
5604 }
5605 else
5606 {
5607 Assert(!pVmxTransient->fIsNestedGuest);
5608
5609 /*
5610 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
5611 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
5612 */
5613 switch (pVCpu->hm.s.enmShadowMode)
5614 {
5615 case PGMMODE_REAL: /* Real-mode. */
5616 case PGMMODE_PROTECTED: /* Protected mode without paging. */
5617 case PGMMODE_32_BIT: /* 32-bit paging. */
5618 {
5619 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5620 break;
5621 }
5622
5623 case PGMMODE_PAE: /* PAE paging. */
5624 case PGMMODE_PAE_NX: /* PAE paging with NX. */
5625 {
5626 u64GuestCr4 |= X86_CR4_PAE;
5627 break;
5628 }
5629
5630 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
5631 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
5632#ifdef VBOX_WITH_64_BITS_GUESTS
5633 break;
5634#endif
5635 default:
5636 AssertFailed();
5637 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
5638 }
5639 }
5640
5641 /*
5642 * Apply the hardware specified fixed CR4 bits (mainly CR4.VMXE).
5643 * Note! For nested-guests, we could be altering our VMX emulation's
5644 * fixed bits. We thus need to re-apply them while importing CR4.
5645 */
5646 u64GuestCr4 |= fSetCr4;
5647 u64GuestCr4 &= fZapCr4;
5648
5649 /* Commit the CR4 and CR4 read-shadow to the guest VMCS. */
5650 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR4, u64GuestCr4); AssertRC(rc);
5651 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, u64ShadowCr4); AssertRC(rc);
5652
5653 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
5654 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
5655
5656 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR4);
5657
5658 Log4Func(("cr4=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64)\n", u64GuestCr4, u64ShadowCr4, fSetCr4, fZapCr4));
5659 }
5660 return rc;
5661}
5662
5663
5664/**
5665 * Exports the guest debug registers into the guest-state area in the VMCS.
5666 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
5667 *
5668 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
5669 *
5670 * @returns VBox status code.
5671 * @param pVCpu The cross context virtual CPU structure.
5672 * @param pVmxTransient The VMX-transient structure.
5673 *
5674 * @remarks No-long-jump zone!!!
5675 */
5676static int hmR0VmxExportSharedDebugState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
5677{
5678 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5679
5680 /** @todo NSTVMX: Figure out what we want to do with nested-guest instruction
5681 * stepping. */
5682 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5683 if (pVmxTransient->fIsNestedGuest)
5684 {
5685 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, CPUMGetGuestDR7(pVCpu));
5686 AssertRC(rc);
5687
5688 /* Always intercept Mov DRx accesses for the nested-guest for now. */
5689 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
5690 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
5691 AssertRC(rc);
5692 return VINF_SUCCESS;
5693 }
5694
5695#ifdef VBOX_STRICT
5696 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
5697 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
5698 {
5699 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
5700 Assert((pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0);
5701 Assert((pVCpu->cpum.GstCtx.dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK);
5702 }
5703#endif
5704
5705 bool fSteppingDB = false;
5706 bool fInterceptMovDRx = false;
5707 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5708 if (pVCpu->hm.s.fSingleInstruction)
5709 {
5710 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
5711 PVM pVM = pVCpu->CTX_SUFF(pVM);
5712 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
5713 {
5714 uProcCtls |= VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
5715 Assert(fSteppingDB == false);
5716 }
5717 else
5718 {
5719 pVCpu->cpum.GstCtx.eflags.u32 |= X86_EFL_TF;
5720 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_RFLAGS;
5721 pVCpu->hm.s.fClearTrapFlag = true;
5722 fSteppingDB = true;
5723 }
5724 }
5725
5726 uint64_t u64GuestDr7;
5727 if ( fSteppingDB
5728 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
5729 {
5730 /*
5731 * Use the combined guest and host DRx values found in the hypervisor register set
5732 * because the hypervisor debugger has breakpoints active or someone is single stepping
5733 * on the host side without a monitor trap flag.
5734 *
5735 * Note! DBGF expects a clean DR6 state before executing guest code.
5736 */
5737 if (!CPUMIsHyperDebugStateActive(pVCpu))
5738 {
5739 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
5740 Assert(CPUMIsHyperDebugStateActive(pVCpu));
5741 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
5742 }
5743
5744 /* Update DR7 with the hypervisor value (other DRx registers are handled by CPUM one way or another). */
5745 u64GuestDr7 = CPUMGetHyperDR7(pVCpu);
5746 pVCpu->hm.s.fUsingHyperDR7 = true;
5747 fInterceptMovDRx = true;
5748 }
5749 else
5750 {
5751 /*
5752 * If the guest has enabled debug registers, we need to load them prior to
5753 * executing guest code so they'll trigger at the right time.
5754 */
5755 if (pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
5756 {
5757 if (!CPUMIsGuestDebugStateActive(pVCpu))
5758 {
5759 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
5760 Assert(CPUMIsGuestDebugStateActive(pVCpu));
5761 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
5762 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
5763 }
5764 Assert(!fInterceptMovDRx);
5765 }
5766 else if (!CPUMIsGuestDebugStateActive(pVCpu))
5767 {
5768 /*
5769 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
5770 * must intercept #DB in order to maintain a correct DR6 guest value, and
5771 * because we need to intercept it to prevent nested #DBs from hanging the
5772 * CPU, we end up always having to intercept it. See hmR0VmxSetupVmcsXcptBitmap().
5773 */
5774 fInterceptMovDRx = true;
5775 }
5776
5777 /* Update DR7 with the actual guest value. */
5778 u64GuestDr7 = pVCpu->cpum.GstCtx.dr[7];
5779 pVCpu->hm.s.fUsingHyperDR7 = false;
5780 }
5781
5782 if (fInterceptMovDRx)
5783 uProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
5784 else
5785 uProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
5786
5787 /*
5788 * Update the processor-based VM-execution controls with the MOV-DRx intercepts and the
5789 * monitor-trap flag and update our cache.
5790 */
5791 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5792 {
5793 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5794 AssertRC(rc);
5795 pVmcsInfo->u32ProcCtls = uProcCtls;
5796 }
5797
5798 /*
5799 * Update guest DR7.
5800 */
5801 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, u64GuestDr7);
5802 AssertRC(rc);
5803
5804 /*
5805 * If we have forced EFLAGS.TF to be set because we're single-stepping in the hypervisor debugger,
5806 * we need to clear interrupt inhibition if any as otherwise it causes a VM-entry failure.
5807 *
5808 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5809 */
5810 if (fSteppingDB)
5811 {
5812 Assert(pVCpu->hm.s.fSingleInstruction);
5813 Assert(pVCpu->cpum.GstCtx.eflags.Bits.u1TF);
5814
5815 uint32_t fIntrState = 0;
5816 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
5817 AssertRC(rc);
5818
5819 if (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
5820 {
5821 fIntrState &= ~(VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
5822 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
5823 AssertRC(rc);
5824 }
5825 }
5826
5827 return VINF_SUCCESS;
5828}
5829
5830
5831#ifdef VBOX_STRICT
5832/**
5833 * Strict function to validate segment registers.
5834 *
5835 * @param pVCpu The cross context virtual CPU structure.
5836 * @param pVmcsInfo The VMCS info. object.
5837 *
5838 * @remarks Will import guest CR0 on strict builds during validation of
5839 * segments.
5840 */
5841static void hmR0VmxValidateSegmentRegs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
5842{
5843 /*
5844 * Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
5845 *
5846 * The reason we check for attribute value 0 in this function and not just the unusable bit is
5847 * because hmR0VmxExportGuestSegReg() only updates the VMCS' copy of the value with the
5848 * unusable bit and doesn't change the guest-context value.
5849 */
5850 PVM pVM = pVCpu->CTX_SUFF(pVM);
5851 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5852 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR0);
5853 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
5854 && ( !CPUMIsGuestInRealModeEx(pCtx)
5855 && !CPUMIsGuestInV86ModeEx(pCtx)))
5856 {
5857 /* Protected mode checks */
5858 /* CS */
5859 Assert(pCtx->cs.Attr.n.u1Present);
5860 Assert(!(pCtx->cs.Attr.u & 0xf00));
5861 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
5862 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
5863 || !(pCtx->cs.Attr.n.u1Granularity));
5864 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
5865 || (pCtx->cs.Attr.n.u1Granularity));
5866 /* CS cannot be loaded with NULL in protected mode. */
5867 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
5868 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
5869 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
5870 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
5871 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
5872 else
5873 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
5874 /* SS */
5875 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
5876 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
5877 if ( !(pCtx->cr0 & X86_CR0_PE)
5878 || pCtx->cs.Attr.n.u4Type == 3)
5879 {
5880 Assert(!pCtx->ss.Attr.n.u2Dpl);
5881 }
5882 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
5883 {
5884 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
5885 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
5886 Assert(pCtx->ss.Attr.n.u1Present);
5887 Assert(!(pCtx->ss.Attr.u & 0xf00));
5888 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
5889 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
5890 || !(pCtx->ss.Attr.n.u1Granularity));
5891 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
5892 || (pCtx->ss.Attr.n.u1Granularity));
5893 }
5894 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSegReg(). */
5895 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
5896 {
5897 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5898 Assert(pCtx->ds.Attr.n.u1Present);
5899 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
5900 Assert(!(pCtx->ds.Attr.u & 0xf00));
5901 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
5902 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
5903 || !(pCtx->ds.Attr.n.u1Granularity));
5904 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
5905 || (pCtx->ds.Attr.n.u1Granularity));
5906 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5907 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
5908 }
5909 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
5910 {
5911 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5912 Assert(pCtx->es.Attr.n.u1Present);
5913 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
5914 Assert(!(pCtx->es.Attr.u & 0xf00));
5915 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
5916 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
5917 || !(pCtx->es.Attr.n.u1Granularity));
5918 Assert( !(pCtx->es.u32Limit & 0xfff00000)
5919 || (pCtx->es.Attr.n.u1Granularity));
5920 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5921 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
5922 }
5923 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
5924 {
5925 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5926 Assert(pCtx->fs.Attr.n.u1Present);
5927 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
5928 Assert(!(pCtx->fs.Attr.u & 0xf00));
5929 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
5930 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
5931 || !(pCtx->fs.Attr.n.u1Granularity));
5932 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
5933 || (pCtx->fs.Attr.n.u1Granularity));
5934 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5935 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
5936 }
5937 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
5938 {
5939 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5940 Assert(pCtx->gs.Attr.n.u1Present);
5941 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
5942 Assert(!(pCtx->gs.Attr.u & 0xf00));
5943 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
5944 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
5945 || !(pCtx->gs.Attr.n.u1Granularity));
5946 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
5947 || (pCtx->gs.Attr.n.u1Granularity));
5948 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5949 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
5950 }
5951 /* 64-bit capable CPUs. */
5952 Assert(!RT_HI_U32(pCtx->cs.u64Base));
5953 Assert(!pCtx->ss.Attr.u || !RT_HI_U32(pCtx->ss.u64Base));
5954 Assert(!pCtx->ds.Attr.u || !RT_HI_U32(pCtx->ds.u64Base));
5955 Assert(!pCtx->es.Attr.u || !RT_HI_U32(pCtx->es.u64Base));
5956 }
5957 else if ( CPUMIsGuestInV86ModeEx(pCtx)
5958 || ( CPUMIsGuestInRealModeEx(pCtx)
5959 && !pVM->hm.s.vmx.fUnrestrictedGuest))
5960 {
5961 /* Real and v86 mode checks. */
5962 /* hmR0VmxExportGuestSegReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
5963 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
5964 if (pVmcsInfo->RealMode.fRealOnV86Active)
5965 {
5966 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3;
5967 u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
5968 }
5969 else
5970 {
5971 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
5972 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
5973 }
5974
5975 /* CS */
5976 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
5977 Assert(pCtx->cs.u32Limit == 0xffff);
5978 Assert(u32CSAttr == 0xf3);
5979 /* SS */
5980 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
5981 Assert(pCtx->ss.u32Limit == 0xffff);
5982 Assert(u32SSAttr == 0xf3);
5983 /* DS */
5984 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
5985 Assert(pCtx->ds.u32Limit == 0xffff);
5986 Assert(u32DSAttr == 0xf3);
5987 /* ES */
5988 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
5989 Assert(pCtx->es.u32Limit == 0xffff);
5990 Assert(u32ESAttr == 0xf3);
5991 /* FS */
5992 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
5993 Assert(pCtx->fs.u32Limit == 0xffff);
5994 Assert(u32FSAttr == 0xf3);
5995 /* GS */
5996 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
5997 Assert(pCtx->gs.u32Limit == 0xffff);
5998 Assert(u32GSAttr == 0xf3);
5999 /* 64-bit capable CPUs. */
6000 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6001 Assert(!u32SSAttr || !RT_HI_U32(pCtx->ss.u64Base));
6002 Assert(!u32DSAttr || !RT_HI_U32(pCtx->ds.u64Base));
6003 Assert(!u32ESAttr || !RT_HI_U32(pCtx->es.u64Base));
6004 }
6005}
6006#endif /* VBOX_STRICT */
6007
6008
6009/**
6010 * Exports a guest segment register into the guest-state area in the VMCS.
6011 *
6012 * @returns VBox status code.
6013 * @param pVCpu The cross context virtual CPU structure.
6014 * @param pVmcsInfo The VMCS info. object.
6015 * @param iSegReg The segment register number (X86_SREG_XXX).
6016 * @param pSelReg Pointer to the segment selector.
6017 *
6018 * @remarks No-long-jump zone!!!
6019 */
6020static int hmR0VmxExportGuestSegReg(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t iSegReg, PCCPUMSELREG pSelReg)
6021{
6022 Assert(iSegReg < X86_SREG_COUNT);
6023 uint32_t const idxSel = g_aVmcsSegSel[iSegReg];
6024 uint32_t const idxLimit = g_aVmcsSegLimit[iSegReg];
6025 uint32_t const idxBase = g_aVmcsSegBase[iSegReg];
6026 uint32_t const idxAttr = g_aVmcsSegAttr[iSegReg];
6027
6028 uint32_t u32Access = pSelReg->Attr.u;
6029 if (pVmcsInfo->RealMode.fRealOnV86Active)
6030 {
6031 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
6032 u32Access = 0xf3;
6033 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6034 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
6035 RT_NOREF_PV(pVCpu);
6036 }
6037 else
6038 {
6039 /*
6040 * The way to differentiate between whether this is really a null selector or was just
6041 * a selector loaded with 0 in real-mode is using the segment attributes. A selector
6042 * loaded in real-mode with the value 0 is valid and usable in protected-mode and we
6043 * should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures
6044 * NULL selectors loaded in protected-mode have their attribute as 0.
6045 */
6046 if (!u32Access)
6047 u32Access = X86DESCATTR_UNUSABLE;
6048 }
6049
6050 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
6051 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
6052 ("Access bit not set for usable segment. idx=%#x sel=%#x attr %#x\n", idxBase, pSelReg, pSelReg->Attr.u));
6053
6054 /*
6055 * Commit it to the VMCS.
6056 */
6057 int rc = VMXWriteVmcs32(idxSel, pSelReg->Sel); AssertRC(rc);
6058 rc = VMXWriteVmcs32(idxLimit, pSelReg->u32Limit); AssertRC(rc);
6059 rc = VMXWriteVmcsNw(idxBase, pSelReg->u64Base); AssertRC(rc);
6060 rc = VMXWriteVmcs32(idxAttr, u32Access); AssertRC(rc);
6061 return VINF_SUCCESS;
6062}
6063
6064
6065/**
6066 * Exports the guest segment registers, GDTR, IDTR, LDTR, TR into the guest-state
6067 * area in the VMCS.
6068 *
6069 * @returns VBox status code.
6070 * @param pVCpu The cross context virtual CPU structure.
6071 * @param pVmxTransient The VMX-transient structure.
6072 *
6073 * @remarks Will import guest CR0 on strict builds during validation of
6074 * segments.
6075 * @remarks No-long-jump zone!!!
6076 */
6077static int hmR0VmxExportGuestSegRegsXdtr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
6078{
6079 int rc = VERR_INTERNAL_ERROR_5;
6080 PVM pVM = pVCpu->CTX_SUFF(pVM);
6081 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6082 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6083
6084 /*
6085 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
6086 */
6087 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SREG_MASK)
6088 {
6089#ifdef VBOX_WITH_REM
6090 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
6091 {
6092 Assert(!pVmxTransient->fIsNestedGuest);
6093 Assert(pVM->hm.s.vmx.pRealModeTSS);
6094 AssertCompile(PGMMODE_REAL < PGMMODE_PROTECTED);
6095 if ( pVmcsInfo->fWasInRealMode
6096 && PGMGetGuestMode(pVCpu) >= PGMMODE_PROTECTED)
6097 {
6098 /*
6099 * Notify the recompiler must flush its code-cache as the guest -may-
6100 * rewrite code it in real-mode (e.g. OpenBSD 4.0).
6101 */
6102 REMFlushTBs(pVM);
6103 Log4Func(("Switch to protected mode detected!\n"));
6104 pVmcsInfo->fWasInRealMode = false;
6105 }
6106 }
6107#endif
6108 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CS)
6109 {
6110 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CS);
6111 if (pVmcsInfo->RealMode.fRealOnV86Active)
6112 pVmcsInfo->RealMode.AttrCS.u = pCtx->cs.Attr.u;
6113 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_CS, &pCtx->cs);
6114 AssertRC(rc);
6115 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CS);
6116 }
6117
6118 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SS)
6119 {
6120 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SS);
6121 if (pVmcsInfo->RealMode.fRealOnV86Active)
6122 pVmcsInfo->RealMode.AttrSS.u = pCtx->ss.Attr.u;
6123 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_SS, &pCtx->ss);
6124 AssertRC(rc);
6125 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SS);
6126 }
6127
6128 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_DS)
6129 {
6130 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DS);
6131 if (pVmcsInfo->RealMode.fRealOnV86Active)
6132 pVmcsInfo->RealMode.AttrDS.u = pCtx->ds.Attr.u;
6133 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_DS, &pCtx->ds);
6134 AssertRC(rc);
6135 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_DS);
6136 }
6137
6138 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_ES)
6139 {
6140 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_ES);
6141 if (pVmcsInfo->RealMode.fRealOnV86Active)
6142 pVmcsInfo->RealMode.AttrES.u = pCtx->es.Attr.u;
6143 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_ES, &pCtx->es);
6144 AssertRC(rc);
6145 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_ES);
6146 }
6147
6148 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_FS)
6149 {
6150 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_FS);
6151 if (pVmcsInfo->RealMode.fRealOnV86Active)
6152 pVmcsInfo->RealMode.AttrFS.u = pCtx->fs.Attr.u;
6153 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_FS, &pCtx->fs);
6154 AssertRC(rc);
6155 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_FS);
6156 }
6157
6158 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GS)
6159 {
6160 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GS);
6161 if (pVmcsInfo->RealMode.fRealOnV86Active)
6162 pVmcsInfo->RealMode.AttrGS.u = pCtx->gs.Attr.u;
6163 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_GS, &pCtx->gs);
6164 AssertRC(rc);
6165 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GS);
6166 }
6167
6168#ifdef VBOX_STRICT
6169 hmR0VmxValidateSegmentRegs(pVCpu, pVmcsInfo);
6170#endif
6171 Log4Func(("cs={%#04x base=%#RX64 limit=%#RX32 attr=%#RX32}\n", pCtx->cs.Sel, pCtx->cs.u64Base, pCtx->cs.u32Limit,
6172 pCtx->cs.Attr.u));
6173 }
6174
6175 /*
6176 * Guest TR.
6177 */
6178 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_TR)
6179 {
6180 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_TR);
6181
6182 /*
6183 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is
6184 * achieved using the interrupt redirection bitmap (all bits cleared to let the guest
6185 * handle INT-n's) in the TSS. See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
6186 */
6187 uint16_t u16Sel;
6188 uint32_t u32Limit;
6189 uint64_t u64Base;
6190 uint32_t u32AccessRights;
6191 if (!pVmcsInfo->RealMode.fRealOnV86Active)
6192 {
6193 u16Sel = pCtx->tr.Sel;
6194 u32Limit = pCtx->tr.u32Limit;
6195 u64Base = pCtx->tr.u64Base;
6196 u32AccessRights = pCtx->tr.Attr.u;
6197 }
6198 else
6199 {
6200 Assert(!pVmxTransient->fIsNestedGuest);
6201 Assert(pVM->hm.s.vmx.pRealModeTSS);
6202 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMCanExecuteGuest() -XXX- what about inner loop changes? */
6203
6204 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
6205 RTGCPHYS GCPhys;
6206 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
6207 AssertRCReturn(rc, rc);
6208
6209 X86DESCATTR DescAttr;
6210 DescAttr.u = 0;
6211 DescAttr.n.u1Present = 1;
6212 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
6213
6214 u16Sel = 0;
6215 u32Limit = HM_VTX_TSS_SIZE;
6216 u64Base = GCPhys;
6217 u32AccessRights = DescAttr.u;
6218 }
6219
6220 /* Validate. */
6221 Assert(!(u16Sel & RT_BIT(2)));
6222 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
6223 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
6224 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
6225 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
6226 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
6227 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
6228 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
6229 Assert( (u32Limit & 0xfff) == 0xfff
6230 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
6231 Assert( !(pCtx->tr.u32Limit & 0xfff00000)
6232 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
6233
6234 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_TR_SEL, u16Sel); AssertRC(rc);
6235 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit); AssertRC(rc);
6236 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights); AssertRC(rc);
6237 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_TR_BASE, u64Base); AssertRC(rc);
6238
6239 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_TR);
6240 Log4Func(("tr base=%#RX64 limit=%#RX32\n", pCtx->tr.u64Base, pCtx->tr.u32Limit));
6241 }
6242
6243 /*
6244 * Guest GDTR.
6245 */
6246 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GDTR)
6247 {
6248 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GDTR);
6249
6250 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt); AssertRC(rc);
6251 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, pCtx->gdtr.pGdt); AssertRC(rc);
6252
6253 /* Validate. */
6254 Assert(!(pCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6255
6256 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GDTR);
6257 Log4Func(("gdtr base=%#RX64 limit=%#RX32\n", pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt));
6258 }
6259
6260 /*
6261 * Guest LDTR.
6262 */
6263 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_LDTR)
6264 {
6265 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_LDTR);
6266
6267 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
6268 uint32_t u32Access;
6269 if ( !pVmxTransient->fIsNestedGuest
6270 && !pCtx->ldtr.Attr.u)
6271 u32Access = X86DESCATTR_UNUSABLE;
6272 else
6273 u32Access = pCtx->ldtr.Attr.u;
6274
6275 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, pCtx->ldtr.Sel); AssertRC(rc);
6276 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtr.u32Limit); AssertRC(rc);
6277 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access); AssertRC(rc);
6278 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, pCtx->ldtr.u64Base); AssertRC(rc);
6279
6280 /* Validate. */
6281 if (!(u32Access & X86DESCATTR_UNUSABLE))
6282 {
6283 Assert(!(pCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
6284 Assert(pCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
6285 Assert(!pCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
6286 Assert(pCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
6287 Assert(!pCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
6288 Assert(!(pCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
6289 Assert( (pCtx->ldtr.u32Limit & 0xfff) == 0xfff
6290 || !pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
6291 Assert( !(pCtx->ldtr.u32Limit & 0xfff00000)
6292 || pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
6293 }
6294
6295 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_LDTR);
6296 Log4Func(("ldtr base=%#RX64 limit=%#RX32\n", pCtx->ldtr.u64Base, pCtx->ldtr.u32Limit));
6297 }
6298
6299 /*
6300 * Guest IDTR.
6301 */
6302 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_IDTR)
6303 {
6304 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_IDTR);
6305
6306 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt); AssertRC(rc);
6307 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, pCtx->idtr.pIdt); AssertRC(rc);
6308
6309 /* Validate. */
6310 Assert(!(pCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6311
6312 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_IDTR);
6313 Log4Func(("idtr base=%#RX64 limit=%#RX32\n", pCtx->idtr.pIdt, pCtx->idtr.cbIdt));
6314 }
6315
6316 return VINF_SUCCESS;
6317}
6318
6319
6320/**
6321 * Exports certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
6322 * areas.
6323 *
6324 * These MSRs will automatically be loaded to the host CPU on every successful
6325 * VM-entry and stored from the host CPU on every successful VM-exit.
6326 *
6327 * We creates/updates MSR slots for the host MSRs in the VM-exit MSR-load area. The
6328 * actual host MSR values are not- updated here for performance reasons. See
6329 * hmR0VmxExportHostMsrs().
6330 *
6331 * We also exports the guest sysenter MSRs into the guest-state area in the VMCS.
6332 *
6333 * @returns VBox status code.
6334 * @param pVCpu The cross context virtual CPU structure.
6335 * @param pVmxTransient The VMX-transient structure.
6336 *
6337 * @remarks No-long-jump zone!!!
6338 */
6339static int hmR0VmxExportGuestMsrs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
6340{
6341 AssertPtr(pVCpu);
6342 AssertPtr(pVmxTransient);
6343
6344 PVM pVM = pVCpu->CTX_SUFF(pVM);
6345 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6346
6347 /*
6348 * MSRs that we use the auto-load/store MSR area in the VMCS.
6349 * For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(),
6350 * nothing to do here. The host MSR values are updated when it's safe in
6351 * hmR0VmxLazySaveHostMsrs().
6352 *
6353 * For nested-guests, the guests MSRs from the VM-entry MSR-load area are already
6354 * loaded (into the guest-CPU context) by the VMLAUNCH/VMRESUME instruction
6355 * emulation, nothing to do here.
6356 */
6357 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_GUEST_AUTO_MSRS)
6358 {
6359 /* No auto-load/store MSRs currently. */
6360 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_GUEST_AUTO_MSRS);
6361 }
6362
6363 /*
6364 * Guest Sysenter MSRs.
6365 */
6366 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_MSR_MASK)
6367 {
6368 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SYSENTER_MSRS);
6369
6370 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_CS_MSR)
6371 {
6372 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pCtx->SysEnter.cs);
6373 AssertRC(rc);
6374 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_CS_MSR);
6375 }
6376
6377 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_EIP_MSR)
6378 {
6379 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, pCtx->SysEnter.eip);
6380 AssertRC(rc);
6381 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
6382 }
6383
6384 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_ESP_MSR)
6385 {
6386 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, pCtx->SysEnter.esp);
6387 AssertRC(rc);
6388 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
6389 }
6390 }
6391
6392 /*
6393 * Guest/host EFER MSR.
6394 */
6395 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_EFER_MSR)
6396 {
6397 /* Whether we are using the VMCS to swap the EFER MSR must have been
6398 determined earlier while exporting VM-entry/VM-exit controls. */
6399 Assert(!(ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS));
6400 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
6401
6402 if (hmR0VmxShouldSwapEferMsr(pVCpu))
6403 {
6404 /*
6405 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
6406 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
6407 */
6408 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
6409 {
6410 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, pCtx->msrEFER);
6411 AssertRC(rc);
6412 }
6413 else
6414 {
6415 /*
6416 * We shall use the auto-load/store MSR area only for loading the EFER MSR but we must
6417 * continue to intercept guest read and write accesses to it, see @bugref{7386#c16}.
6418 */
6419 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER, pCtx->msrEFER,
6420 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6421 AssertRCReturn(rc, rc);
6422 }
6423 }
6424 else if (!pVM->hm.s.vmx.fSupportsVmcsEfer)
6425 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER);
6426
6427 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_EFER_MSR);
6428 }
6429
6430 /*
6431 * Other MSRs.
6432 * Speculation Control (R/W).
6433 */
6434 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_OTHER_MSRS)
6435 {
6436 HMVMX_CPUMCTX_ASSERT(pVCpu, HM_CHANGED_GUEST_OTHER_MSRS);
6437 if (pVM->cpum.ro.GuestFeatures.fIbrs)
6438 {
6439 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_IA32_SPEC_CTRL, CPUMGetGuestSpecCtrl(pVCpu),
6440 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6441 AssertRCReturn(rc, rc);
6442 }
6443 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
6444 }
6445
6446 return VINF_SUCCESS;
6447}
6448
6449
6450/**
6451 * Selects up the appropriate function to run guest code.
6452 *
6453 * @returns VBox status code.
6454 * @param pVCpu The cross context virtual CPU structure.
6455 * @param pVmxTransient The VMX-transient structure.
6456 *
6457 * @remarks No-long-jump zone!!!
6458 */
6459static int hmR0VmxSelectVMRunHandler(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
6460{
6461 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6462 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6463
6464 if (CPUMIsGuestInLongModeEx(pCtx))
6465 {
6466#ifndef VBOX_WITH_64_BITS_GUESTS
6467 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
6468#else
6469 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
6470 /* Guest is in long mode, use the 64-bit handler (host is 64-bit). */
6471 pVmcsInfo->pfnStartVM = VMXR0StartVM64;
6472#endif
6473 }
6474 else
6475 {
6476 /* Guest is not in long mode, use the 32-bit handler. */
6477 pVmcsInfo->pfnStartVM = VMXR0StartVM32;
6478 }
6479 Assert(pVmcsInfo->pfnStartVM);
6480 return VINF_SUCCESS;
6481}
6482
6483
6484/**
6485 * Wrapper for running the guest code in VT-x.
6486 *
6487 * @returns VBox status code, no informational status codes.
6488 * @param pVCpu The cross context virtual CPU structure.
6489 * @param pVmxTransient The VMX-transient structure.
6490 *
6491 * @remarks No-long-jump zone!!!
6492 */
6493DECLINLINE(int) hmR0VmxRunGuest(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient)
6494{
6495 /* Mark that HM is the keeper of all guest-CPU registers now that we're going to execute guest code. */
6496 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6497 pCtx->fExtrn |= HMVMX_CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_KEEPER_HM;
6498
6499 /** @todo Add stats for VMRESUME vs VMLAUNCH. */
6500
6501 /*
6502 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses
6503 * floating-point operations using SSE instructions. Some XMM registers (XMM6-XMM15) are
6504 * callee-saved and thus the need for this XMM wrapper.
6505 *
6506 * See MSDN "Configuring Programs for 64-bit/x64 Software Conventions / Register Usage".
6507 */
6508 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6509 bool const fResumeVM = RT_BOOL(pVmcsInfo->fVmcsState & VMX_V_VMCS_LAUNCH_STATE_LAUNCHED);
6510 PVM pVM = pVCpu->CTX_SUFF(pVM);
6511#ifdef VBOX_WITH_KERNEL_USING_XMM
6512 int rc = hmR0VMXStartVMWrapXMM(fResumeVM, pCtx, NULL /*pvUnused*/, pVM, pVCpu, pVmcsInfo->pfnStartVM);
6513#else
6514 int rc = pVmcsInfo->pfnStartVM(fResumeVM, pCtx, NULL /*pvUnused*/, pVM, pVCpu);
6515#endif
6516 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
6517 return rc;
6518}
6519
6520
6521/**
6522 * Reports world-switch error and dumps some useful debug info.
6523 *
6524 * @param pVCpu The cross context virtual CPU structure.
6525 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
6526 * @param pVmxTransient The VMX-transient structure (only
6527 * exitReason updated).
6528 */
6529static void hmR0VmxReportWorldSwitchError(PVMCPU pVCpu, int rcVMRun, PVMXTRANSIENT pVmxTransient)
6530{
6531 Assert(pVCpu);
6532 Assert(pVmxTransient);
6533 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
6534
6535 Log4Func(("VM-entry failure: %Rrc\n", rcVMRun));
6536 switch (rcVMRun)
6537 {
6538 case VERR_VMX_INVALID_VMXON_PTR:
6539 AssertFailed();
6540 break;
6541 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
6542 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
6543 {
6544 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
6545 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
6546 AssertRC(rc);
6547 hmR0VmxReadExitQualVmcs(pVmxTransient);
6548
6549 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
6550 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
6551 Cannot do it here as we may have been long preempted. */
6552
6553#ifdef VBOX_STRICT
6554 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6555 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
6556 pVmxTransient->uExitReason));
6557 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQual));
6558 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
6559 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
6560 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
6561 else
6562 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
6563 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
6564 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
6565
6566 static struct
6567 {
6568 /** Name of the field to log. */
6569 const char *pszName;
6570 /** The VMCS field. */
6571 uint32_t uVmcsField;
6572 /** Whether host support of this field needs to be checked. */
6573 bool fCheckSupport;
6574 } const s_aVmcsFields[] =
6575 {
6576 { "VMX_VMCS32_CTRL_PIN_EXEC", VMX_VMCS32_CTRL_PIN_EXEC, false },
6577 { "VMX_VMCS32_CTRL_PROC_EXEC", VMX_VMCS32_CTRL_PROC_EXEC, false },
6578 { "VMX_VMCS32_CTRL_PROC_EXEC2", VMX_VMCS32_CTRL_PROC_EXEC2, true },
6579 { "VMX_VMCS32_CTRL_ENTRY", VMX_VMCS32_CTRL_ENTRY, false },
6580 { "VMX_VMCS32_CTRL_EXIT", VMX_VMCS32_CTRL_EXIT, false },
6581 { "VMX_VMCS32_CTRL_CR3_TARGET_COUNT", VMX_VMCS32_CTRL_CR3_TARGET_COUNT, false },
6582 { "VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO", VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, false },
6583 { "VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE", VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, false },
6584 { "VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH", VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, false },
6585 { "VMX_VMCS32_CTRL_TPR_THRESHOLD", VMX_VMCS32_CTRL_TPR_THRESHOLD, false },
6586 { "VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, false },
6587 { "VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, false },
6588 { "VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, false },
6589 { "VMX_VMCS32_CTRL_EXCEPTION_BITMAP", VMX_VMCS32_CTRL_EXCEPTION_BITMAP, false },
6590 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, false },
6591 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, false },
6592 { "VMX_VMCS_CTRL_CR0_MASK", VMX_VMCS_CTRL_CR0_MASK, false },
6593 { "VMX_VMCS_CTRL_CR0_READ_SHADOW", VMX_VMCS_CTRL_CR0_READ_SHADOW, false },
6594 { "VMX_VMCS_CTRL_CR4_MASK", VMX_VMCS_CTRL_CR4_MASK, false },
6595 { "VMX_VMCS_CTRL_CR4_READ_SHADOW", VMX_VMCS_CTRL_CR4_READ_SHADOW, false },
6596 { "VMX_VMCS64_CTRL_EPTP_FULL", VMX_VMCS64_CTRL_EPTP_FULL, true },
6597 { "VMX_VMCS_GUEST_RIP", VMX_VMCS_GUEST_RIP, false },
6598 { "VMX_VMCS_GUEST_RSP", VMX_VMCS_GUEST_RSP, false },
6599 { "VMX_VMCS_GUEST_RFLAGS", VMX_VMCS_GUEST_RFLAGS, false },
6600 { "VMX_VMCS16_VPID", VMX_VMCS16_VPID, true, },
6601 { "VMX_VMCS_HOST_CR0", VMX_VMCS_HOST_CR0, false },
6602 { "VMX_VMCS_HOST_CR3", VMX_VMCS_HOST_CR3, false },
6603 { "VMX_VMCS_HOST_CR4", VMX_VMCS_HOST_CR4, false },
6604 /* The order of selector fields below are fixed! */
6605 { "VMX_VMCS16_HOST_ES_SEL", VMX_VMCS16_HOST_ES_SEL, false },
6606 { "VMX_VMCS16_HOST_CS_SEL", VMX_VMCS16_HOST_CS_SEL, false },
6607 { "VMX_VMCS16_HOST_SS_SEL", VMX_VMCS16_HOST_SS_SEL, false },
6608 { "VMX_VMCS16_HOST_DS_SEL", VMX_VMCS16_HOST_DS_SEL, false },
6609 { "VMX_VMCS16_HOST_FS_SEL", VMX_VMCS16_HOST_FS_SEL, false },
6610 { "VMX_VMCS16_HOST_GS_SEL", VMX_VMCS16_HOST_GS_SEL, false },
6611 { "VMX_VMCS16_HOST_TR_SEL", VMX_VMCS16_HOST_TR_SEL, false },
6612 /* End of ordered selector fields. */
6613 { "VMX_VMCS_HOST_TR_BASE", VMX_VMCS_HOST_TR_BASE, false },
6614 { "VMX_VMCS_HOST_GDTR_BASE", VMX_VMCS_HOST_GDTR_BASE, false },
6615 { "VMX_VMCS_HOST_IDTR_BASE", VMX_VMCS_HOST_IDTR_BASE, false },
6616 { "VMX_VMCS32_HOST_SYSENTER_CS", VMX_VMCS32_HOST_SYSENTER_CS, false },
6617 { "VMX_VMCS_HOST_SYSENTER_EIP", VMX_VMCS_HOST_SYSENTER_EIP, false },
6618 { "VMX_VMCS_HOST_SYSENTER_ESP", VMX_VMCS_HOST_SYSENTER_ESP, false },
6619 { "VMX_VMCS_HOST_RSP", VMX_VMCS_HOST_RSP, false },
6620 { "VMX_VMCS_HOST_RIP", VMX_VMCS_HOST_RIP, false }
6621 };
6622
6623 RTGDTR HostGdtr;
6624 ASMGetGDTR(&HostGdtr);
6625
6626 uint32_t const cVmcsFields = RT_ELEMENTS(s_aVmcsFields);
6627 for (uint32_t i = 0; i < cVmcsFields; i++)
6628 {
6629 uint32_t const uVmcsField = s_aVmcsFields[i].uVmcsField;
6630
6631 bool fSupported;
6632 if (!s_aVmcsFields[i].fCheckSupport)
6633 fSupported = true;
6634 else
6635 {
6636 PVM pVM = pVCpu->CTX_SUFF(pVM);
6637 switch (uVmcsField)
6638 {
6639 case VMX_VMCS64_CTRL_EPTP_FULL: fSupported = pVM->hm.s.fNestedPaging; break;
6640 case VMX_VMCS16_VPID: fSupported = pVM->hm.s.vmx.fVpid; break;
6641 case VMX_VMCS32_CTRL_PROC_EXEC2:
6642 fSupported = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
6643 break;
6644 default:
6645 AssertMsgFailedReturnVoid(("Failed to provide VMCS field support for %#RX32\n", uVmcsField));
6646 }
6647 }
6648
6649 if (fSupported)
6650 {
6651 uint8_t const uWidth = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH);
6652 switch (uWidth)
6653 {
6654 case VMX_VMCSFIELD_WIDTH_16BIT:
6655 {
6656 uint16_t u16Val;
6657 rc = VMXReadVmcs16(uVmcsField, &u16Val);
6658 AssertRC(rc);
6659 Log4(("%-40s = %#RX16\n", s_aVmcsFields[i].pszName, u16Val));
6660
6661 if ( uVmcsField >= VMX_VMCS16_HOST_ES_SEL
6662 && uVmcsField <= VMX_VMCS16_HOST_TR_SEL)
6663 {
6664 if (u16Val < HostGdtr.cbGdt)
6665 {
6666 /* Order of selectors in s_apszSel is fixed and matches the order in s_aVmcsFields. */
6667 static const char * const s_apszSel[] = { "Host ES", "Host CS", "Host SS", "Host DS",
6668 "Host FS", "Host GS", "Host TR" };
6669 uint8_t const idxSel = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_INDEX);
6670 Assert(idxSel < RT_ELEMENTS(s_apszSel));
6671 PCX86DESCHC pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u16Val & X86_SEL_MASK));
6672 hmR0DumpDescriptor(pDesc, u16Val, s_apszSel[idxSel]);
6673 }
6674 else
6675 Log4((" Selector value exceeds GDT limit!\n"));
6676 }
6677 break;
6678 }
6679
6680 case VMX_VMCSFIELD_WIDTH_32BIT:
6681 {
6682 uint32_t u32Val;
6683 rc = VMXReadVmcs32(uVmcsField, &u32Val);
6684 AssertRC(rc);
6685 Log4(("%-40s = %#RX32\n", s_aVmcsFields[i].pszName, u32Val));
6686 break;
6687 }
6688
6689 case VMX_VMCSFIELD_WIDTH_64BIT:
6690 case VMX_VMCSFIELD_WIDTH_NATURAL:
6691 {
6692 uint64_t u64Val;
6693 rc = VMXReadVmcs64(uVmcsField, &u64Val);
6694 AssertRC(rc);
6695 Log4(("%-40s = %#RX64\n", s_aVmcsFields[i].pszName, u64Val));
6696 break;
6697 }
6698 }
6699 }
6700 }
6701
6702 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
6703 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
6704 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
6705 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
6706 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
6707 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
6708#endif /* VBOX_STRICT */
6709 break;
6710 }
6711
6712 default:
6713 /* Impossible */
6714 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
6715 break;
6716 }
6717}
6718
6719
6720/**
6721 * Sets up the usage of TSC-offsetting and updates the VMCS.
6722 *
6723 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
6724 * VMX-preemption timer.
6725 *
6726 * @returns VBox status code.
6727 * @param pVCpu The cross context virtual CPU structure.
6728 * @param pVmxTransient The VMX-transient structure.
6729 *
6730 * @remarks No-long-jump zone!!!
6731 */
6732static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
6733{
6734 bool fOffsettedTsc;
6735 bool fParavirtTsc;
6736 uint64_t uTscOffset;
6737 PVM pVM = pVCpu->CTX_SUFF(pVM);
6738 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6739
6740 if (pVM->hm.s.vmx.fUsePreemptTimer)
6741 {
6742 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &uTscOffset, &fOffsettedTsc, &fParavirtTsc);
6743
6744 /* Make sure the returned values have sane upper and lower boundaries. */
6745 uint64_t u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
6746 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second */
6747 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
6748 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
6749
6750 /** @todo r=ramshankar: We need to find a way to integrate nested-guest
6751 * preemption timers here. We probably need to clamp the preemption timer,
6752 * after converting the timer value to the host. */
6753 uint32_t cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
6754 int rc = VMXWriteVmcs32(VMX_VMCS32_PREEMPT_TIMER_VALUE, cPreemptionTickCount);
6755 AssertRC(rc);
6756 }
6757 else
6758 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
6759
6760 if (fParavirtTsc)
6761 {
6762 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
6763 information before every VM-entry, hence disable it for performance sake. */
6764#if 0
6765 int rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
6766 AssertRC(rc);
6767#endif
6768 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
6769 }
6770
6771 if ( fOffsettedTsc
6772 && RT_LIKELY(!pVCpu->hm.s.fDebugWantRdTscExit))
6773 {
6774 if (pVmxTransient->fIsNestedGuest)
6775 uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
6776 hmR0VmxSetTscOffsetVmcs(pVmcsInfo, uTscOffset);
6777 hmR0VmxRemoveProcCtlsVmcs(pVCpu, pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
6778 }
6779 else
6780 {
6781 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
6782 hmR0VmxSetProcCtlsVmcs(pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
6783 }
6784}
6785
6786
6787/**
6788 * Gets the IEM exception flags for the specified vector and IDT vectoring /
6789 * VM-exit interruption info type.
6790 *
6791 * @returns The IEM exception flags.
6792 * @param uVector The event vector.
6793 * @param uVmxEventType The VMX event type.
6794 *
6795 * @remarks This function currently only constructs flags required for
6796 * IEMEvaluateRecursiveXcpt and not the complete flags (e.g, error-code
6797 * and CR2 aspects of an exception are not included).
6798 */
6799static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxEventType)
6800{
6801 uint32_t fIemXcptFlags;
6802 switch (uVmxEventType)
6803 {
6804 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
6805 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
6806 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
6807 break;
6808
6809 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
6810 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
6811 break;
6812
6813 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
6814 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
6815 break;
6816
6817 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
6818 {
6819 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6820 if (uVector == X86_XCPT_BP)
6821 fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
6822 else if (uVector == X86_XCPT_OF)
6823 fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
6824 else
6825 {
6826 fIemXcptFlags = 0;
6827 AssertMsgFailed(("Unexpected vector for software exception. uVector=%#x", uVector));
6828 }
6829 break;
6830 }
6831
6832 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
6833 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6834 break;
6835
6836 default:
6837 fIemXcptFlags = 0;
6838 AssertMsgFailed(("Unexpected vector type! uVmxEventType=%#x uVector=%#x", uVmxEventType, uVector));
6839 break;
6840 }
6841 return fIemXcptFlags;
6842}
6843
6844
6845/**
6846 * Sets an event as a pending event to be injected into the guest.
6847 *
6848 * @param pVCpu The cross context virtual CPU structure.
6849 * @param u32IntInfo The VM-entry interruption-information field.
6850 * @param cbInstr The VM-entry instruction length in bytes (for software
6851 * interrupts, exceptions and privileged software
6852 * exceptions).
6853 * @param u32ErrCode The VM-entry exception error code.
6854 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
6855 * page-fault.
6856 */
6857DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPU pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
6858 RTGCUINTPTR GCPtrFaultAddress)
6859{
6860 Assert(!pVCpu->hm.s.Event.fPending);
6861 pVCpu->hm.s.Event.fPending = true;
6862 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
6863 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
6864 pVCpu->hm.s.Event.cbInstr = cbInstr;
6865 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
6866}
6867
6868
6869/**
6870 * Sets an external interrupt as pending-for-injection into the VM.
6871 *
6872 * @param pVCpu The cross context virtual CPU structure.
6873 * @param u8Interrupt The external interrupt vector.
6874 */
6875DECLINLINE(void) hmR0VmxSetPendingExtInt(PVMCPU pVCpu, uint8_t u8Interrupt)
6876{
6877 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, u8Interrupt)
6878 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
6879 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6880 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6881 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6882}
6883
6884
6885/**
6886 * Sets an NMI (\#NMI) exception as pending-for-injection into the VM.
6887 *
6888 * @param pVCpu The cross context virtual CPU structure.
6889 */
6890DECLINLINE(void) hmR0VmxSetPendingXcptNmi(PVMCPU pVCpu)
6891{
6892 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI)
6893 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI)
6894 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6895 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6896 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6897}
6898
6899
6900/**
6901 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
6902 *
6903 * @param pVCpu The cross context virtual CPU structure.
6904 */
6905DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu)
6906{
6907 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
6908 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6909 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6910 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6911 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6912}
6913
6914
6915/**
6916 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
6917 *
6918 * @param pVCpu The cross context virtual CPU structure.
6919 */
6920DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPU pVCpu)
6921{
6922 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_UD)
6923 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6924 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6925 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6926 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6927}
6928
6929
6930/**
6931 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
6932 *
6933 * @param pVCpu The cross context virtual CPU structure.
6934 */
6935DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPU pVCpu)
6936{
6937 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
6938 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6939 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6940 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6941 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6942}
6943
6944
6945#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6946/**
6947 * Sets a general-protection (\#GP) exception as pending-for-injection into the VM.
6948 *
6949 * @param pVCpu The cross context virtual CPU structure.
6950 * @param u32ErrCode The error code for the general-protection exception.
6951 */
6952DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPU pVCpu, uint32_t u32ErrCode)
6953{
6954 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
6955 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6956 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6957 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6958 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
6959}
6960
6961
6962/**
6963 * Sets a stack (\#SS) exception as pending-for-injection into the VM.
6964 *
6965 * @param pVCpu The cross context virtual CPU structure.
6966 * @param u32ErrCode The error code for the stack exception.
6967 */
6968DECLINLINE(void) hmR0VmxSetPendingXcptSS(PVMCPU pVCpu, uint32_t u32ErrCode)
6969{
6970 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_SS)
6971 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6972 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6973 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6974 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
6975}
6976#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
6977
6978
6979/**
6980 * Fixes up attributes for the specified segment register.
6981 *
6982 * @param pVCpu The cross context virtual CPU structure.
6983 * @param pSelReg The segment register that needs fixing.
6984 * @param idxSel The VMCS field for the corresponding segment register.
6985 */
6986static void hmR0VmxFixUnusableSegRegAttr(PVMCPU pVCpu, PCPUMSELREG pSelReg, uint32_t idxSel)
6987{
6988 Assert(pSelReg->Attr.u & X86DESCATTR_UNUSABLE);
6989
6990 /*
6991 * If VT-x marks the segment as unusable, most other bits remain undefined:
6992 * - For CS the L, D and G bits have meaning.
6993 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
6994 * - For the remaining data segments no bits are defined.
6995 *
6996 * The present bit and the unusable bit has been observed to be set at the
6997 * same time (the selector was supposed to be invalid as we started executing
6998 * a V8086 interrupt in ring-0).
6999 *
7000 * What should be important for the rest of the VBox code, is that the P bit is
7001 * cleared. Some of the other VBox code recognizes the unusable bit, but
7002 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
7003 * safe side here, we'll strip off P and other bits we don't care about. If
7004 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
7005 *
7006 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
7007 */
7008#ifdef VBOX_STRICT
7009 uint32_t const uAttr = pSelReg->Attr.u;
7010#endif
7011
7012 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
7013 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
7014 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
7015
7016#ifdef VBOX_STRICT
7017 VMMRZCallRing3Disable(pVCpu);
7018 Log4Func(("Unusable %#x: sel=%#x attr=%#x -> %#x\n", idxSel, pSelReg->Sel, uAttr, pSelReg->Attr.u));
7019# ifdef DEBUG_bird
7020 AssertMsg((uAttr & ~X86DESCATTR_P) == pSelReg->Attr.u,
7021 ("%#x: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
7022 idxSel, uAttr, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
7023# endif
7024 VMMRZCallRing3Enable(pVCpu);
7025 NOREF(uAttr);
7026#endif
7027 RT_NOREF2(pVCpu, idxSel);
7028}
7029
7030
7031/**
7032 * Imports a guest segment register from the current VMCS into the guest-CPU
7033 * context.
7034 *
7035 * @param pVCpu The cross context virtual CPU structure.
7036 * @param iSegReg The segment register number (X86_SREG_XXX).
7037 *
7038 * @remarks Called with interrupts and/or preemption disabled.
7039 */
7040static void hmR0VmxImportGuestSegReg(PVMCPU pVCpu, uint8_t iSegReg)
7041{
7042 Assert(iSegReg < X86_SREG_COUNT);
7043
7044 uint32_t const idxSel = g_aVmcsSegSel[iSegReg];
7045 uint32_t const idxLimit = g_aVmcsSegLimit[iSegReg];
7046 uint32_t const idxAttr = g_aVmcsSegAttr[iSegReg];
7047 uint32_t const idxBase = g_aVmcsSegBase[iSegReg];
7048
7049 uint16_t u16Sel;
7050 uint64_t u64Base;
7051 uint32_t u32Limit, u32Attr;
7052 int rc = VMXReadVmcs16(idxSel, &u16Sel); AssertRC(rc);
7053 rc = VMXReadVmcs32(idxLimit, &u32Limit); AssertRC(rc);
7054 rc = VMXReadVmcs32(idxAttr, &u32Attr); AssertRC(rc);
7055 rc = VMXReadVmcsNw(idxBase, &u64Base); AssertRC(rc);
7056
7057 PCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
7058 pSelReg->Sel = u16Sel;
7059 pSelReg->ValidSel = u16Sel;
7060 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
7061 pSelReg->u32Limit = u32Limit;
7062 pSelReg->u64Base = u64Base;
7063 pSelReg->Attr.u = u32Attr;
7064 if (u32Attr & X86DESCATTR_UNUSABLE)
7065 hmR0VmxFixUnusableSegRegAttr(pVCpu, pSelReg, idxSel);
7066}
7067
7068
7069/**
7070 * Imports the guest LDTR from the current VMCS into the guest-CPU context.
7071 *
7072 * @param pVCpu The cross context virtual CPU structure.
7073 *
7074 * @remarks Called with interrupts and/or preemption disabled.
7075 */
7076static void hmR0VmxImportGuestLdtr(PVMCPU pVCpu)
7077{
7078 uint16_t u16Sel;
7079 uint64_t u64Base;
7080 uint32_t u32Limit, u32Attr;
7081 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, &u16Sel); AssertRC(rc);
7082 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, &u32Limit); AssertRC(rc);
7083 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7084 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, &u64Base); AssertRC(rc);
7085
7086 pVCpu->cpum.GstCtx.ldtr.Sel = u16Sel;
7087 pVCpu->cpum.GstCtx.ldtr.ValidSel = u16Sel;
7088 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
7089 pVCpu->cpum.GstCtx.ldtr.u32Limit = u32Limit;
7090 pVCpu->cpum.GstCtx.ldtr.u64Base = u64Base;
7091 pVCpu->cpum.GstCtx.ldtr.Attr.u = u32Attr;
7092 if (u32Attr & X86DESCATTR_UNUSABLE)
7093 hmR0VmxFixUnusableSegRegAttr(pVCpu, &pVCpu->cpum.GstCtx.ldtr, VMX_VMCS16_GUEST_LDTR_SEL);
7094}
7095
7096
7097/**
7098 * Imports the guest TR from the current VMCS into the guest-CPU context.
7099 *
7100 * @param pVCpu The cross context virtual CPU structure.
7101 *
7102 * @remarks Called with interrupts and/or preemption disabled.
7103 */
7104static void hmR0VmxImportGuestTr(PVMCPU pVCpu)
7105{
7106 uint16_t u16Sel;
7107 uint64_t u64Base;
7108 uint32_t u32Limit, u32Attr;
7109 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_TR_SEL, &u16Sel); AssertRC(rc);
7110 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, &u32Limit); AssertRC(rc);
7111 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7112 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_TR_BASE, &u64Base); AssertRC(rc);
7113
7114 pVCpu->cpum.GstCtx.tr.Sel = u16Sel;
7115 pVCpu->cpum.GstCtx.tr.ValidSel = u16Sel;
7116 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
7117 pVCpu->cpum.GstCtx.tr.u32Limit = u32Limit;
7118 pVCpu->cpum.GstCtx.tr.u64Base = u64Base;
7119 pVCpu->cpum.GstCtx.tr.Attr.u = u32Attr;
7120 /* TR is the only selector that can never be unusable. */
7121 Assert(!(u32Attr & X86DESCATTR_UNUSABLE));
7122}
7123
7124
7125/**
7126 * Imports the guest RIP from the VMCS back into the guest-CPU context.
7127 *
7128 * @param pVCpu The cross context virtual CPU structure.
7129 *
7130 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7131 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7132 * instead!!!
7133 */
7134static void hmR0VmxImportGuestRip(PVMCPU pVCpu)
7135{
7136 uint64_t u64Val;
7137 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7138 if (pCtx->fExtrn & CPUMCTX_EXTRN_RIP)
7139 {
7140 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
7141 AssertRC(rc);
7142
7143 pCtx->rip = u64Val;
7144 EMR0HistoryUpdatePC(pVCpu, pCtx->rip, false);
7145 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RIP;
7146 }
7147}
7148
7149
7150/**
7151 * Imports the guest RFLAGS from the VMCS back into the guest-CPU context.
7152 *
7153 * @param pVCpu The cross context virtual CPU structure.
7154 * @param pVmcsInfo The VMCS info. object.
7155 *
7156 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7157 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7158 * instead!!!
7159 */
7160static void hmR0VmxImportGuestRFlags(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
7161{
7162 RTHCUINTREG HCRegVal;
7163 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7164 if (pCtx->fExtrn & CPUMCTX_EXTRN_RFLAGS)
7165 {
7166 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &HCRegVal);
7167 AssertRC(rc);
7168
7169 pCtx->rflags.u64 = HCRegVal;
7170 if (pVmcsInfo->RealMode.fRealOnV86Active)
7171 {
7172 pCtx->eflags.Bits.u1VM = 0;
7173 pCtx->eflags.Bits.u2IOPL = pVmcsInfo->RealMode.Eflags.Bits.u2IOPL;
7174 }
7175 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RFLAGS;
7176 }
7177}
7178
7179
7180/**
7181 * Imports the guest interruptibility-state from the VMCS back into the guest-CPU
7182 * context.
7183 *
7184 * @param pVCpu The cross context virtual CPU structure.
7185 * @param pVmcsInfo The VMCS info. object.
7186 *
7187 * @remarks Called with interrupts and/or preemption disabled, try not to assert and
7188 * do not log!
7189 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7190 * instead!!!
7191 */
7192static void hmR0VmxImportGuestIntrState(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
7193{
7194 uint32_t u32Val;
7195 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32Val); AssertRC(rc);
7196 if (!u32Val)
7197 {
7198 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7199 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7200 CPUMSetGuestNmiBlocking(pVCpu, false);
7201 }
7202 else
7203 {
7204 /*
7205 * We must import RIP here to set our EM interrupt-inhibited state.
7206 * We also import RFLAGS as our code that evaluates pending interrupts
7207 * before VM-entry requires it.
7208 */
7209 hmR0VmxImportGuestRip(pVCpu);
7210 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7211
7212 if (u32Val & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
7213 EMSetInhibitInterruptsPC(pVCpu, pVCpu->cpum.GstCtx.rip);
7214 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7215 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7216
7217 bool const fNmiBlocking = RT_BOOL(u32Val & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
7218 CPUMSetGuestNmiBlocking(pVCpu, fNmiBlocking);
7219 }
7220}
7221
7222
7223/**
7224 * Worker for VMXR0ImportStateOnDemand.
7225 *
7226 * @returns VBox status code.
7227 * @param pVCpu The cross context virtual CPU structure.
7228 * @param pVmcsInfo The VMCS info. object.
7229 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7230 */
7231static int hmR0VmxImportGuestState(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
7232{
7233 int rc = VINF_SUCCESS;
7234 PVM pVM = pVCpu->CTX_SUFF(pVM);
7235 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7236 uint32_t u32Val;
7237 RTHCUINTREG HCRegVal;
7238
7239 /*
7240 * Note! This is hack to workaround a mysterious BSOD observed with release builds
7241 * on Windows 10 64-bit hosts. Profile and debug builds are not affected and
7242 * neither are other host platforms.
7243 *
7244 * Committing this temporarily as it prevents BSOD.
7245 *
7246 * Update: This is very likely a compiler optimization bug, see @bugref{9180}.
7247 */
7248#ifdef RT_OS_WINDOWS
7249 if (pVM == 0 || pVM == (void *)(uintptr_t)-1)
7250 return VERR_HM_IPE_1;
7251#endif
7252
7253 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatImportGuestState, x);
7254
7255 /*
7256 * We disable interrupts to make the updating of the state and in particular
7257 * the fExtrn modification atomic wrt to preemption hooks.
7258 */
7259 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
7260
7261 fWhat &= pCtx->fExtrn;
7262 if (fWhat)
7263 {
7264 do
7265 {
7266 if (fWhat & CPUMCTX_EXTRN_RIP)
7267 hmR0VmxImportGuestRip(pVCpu);
7268
7269 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
7270 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7271
7272 if (fWhat & CPUMCTX_EXTRN_HM_VMX_INT_STATE)
7273 hmR0VmxImportGuestIntrState(pVCpu, pVmcsInfo);
7274
7275 if (fWhat & CPUMCTX_EXTRN_RSP)
7276 {
7277 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RSP, &HCRegVal);
7278 AssertRC(rc);
7279 pCtx->rsp = HCRegVal;
7280 }
7281
7282 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
7283 {
7284 bool const fRealOnV86Active = pVmcsInfo->RealMode.fRealOnV86Active;
7285 if (fWhat & CPUMCTX_EXTRN_CS)
7286 {
7287 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_CS);
7288 hmR0VmxImportGuestRip(pVCpu);
7289 if (fRealOnV86Active)
7290 pCtx->cs.Attr.u = pVmcsInfo->RealMode.AttrCS.u;
7291 EMR0HistoryUpdatePC(pVCpu, pCtx->cs.u64Base + pCtx->rip, true /* fFlattened */);
7292 }
7293 if (fWhat & CPUMCTX_EXTRN_SS)
7294 {
7295 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_SS);
7296 if (fRealOnV86Active)
7297 pCtx->ss.Attr.u = pVmcsInfo->RealMode.AttrSS.u;
7298 }
7299 if (fWhat & CPUMCTX_EXTRN_DS)
7300 {
7301 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_DS);
7302 if (fRealOnV86Active)
7303 pCtx->ds.Attr.u = pVmcsInfo->RealMode.AttrDS.u;
7304 }
7305 if (fWhat & CPUMCTX_EXTRN_ES)
7306 {
7307 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_ES);
7308 if (fRealOnV86Active)
7309 pCtx->es.Attr.u = pVmcsInfo->RealMode.AttrES.u;
7310 }
7311 if (fWhat & CPUMCTX_EXTRN_FS)
7312 {
7313 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_FS);
7314 if (fRealOnV86Active)
7315 pCtx->fs.Attr.u = pVmcsInfo->RealMode.AttrFS.u;
7316 }
7317 if (fWhat & CPUMCTX_EXTRN_GS)
7318 {
7319 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_GS);
7320 if (fRealOnV86Active)
7321 pCtx->gs.Attr.u = pVmcsInfo->RealMode.AttrGS.u;
7322 }
7323 }
7324
7325 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
7326 {
7327 if (fWhat & CPUMCTX_EXTRN_LDTR)
7328 hmR0VmxImportGuestLdtr(pVCpu);
7329
7330 if (fWhat & CPUMCTX_EXTRN_GDTR)
7331 {
7332 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &HCRegVal); AssertRC(rc);
7333 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRC(rc);
7334 pCtx->gdtr.pGdt = HCRegVal;
7335 pCtx->gdtr.cbGdt = u32Val;
7336 }
7337
7338 /* Guest IDTR. */
7339 if (fWhat & CPUMCTX_EXTRN_IDTR)
7340 {
7341 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &HCRegVal); AssertRC(rc);
7342 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRC(rc);
7343 pCtx->idtr.pIdt = HCRegVal;
7344 pCtx->idtr.cbIdt = u32Val;
7345 }
7346
7347 /* Guest TR. */
7348 if (fWhat & CPUMCTX_EXTRN_TR)
7349 {
7350 /* Real-mode emulation using virtual-8086 mode has the fake TSS (pRealModeTSS) in TR,
7351 don't need to import that one. */
7352 if (!pVmcsInfo->RealMode.fRealOnV86Active)
7353 hmR0VmxImportGuestTr(pVCpu);
7354 }
7355 }
7356
7357 if (fWhat & CPUMCTX_EXTRN_DR7)
7358 {
7359 if (!pVCpu->hm.s.fUsingHyperDR7)
7360 {
7361 /* Upper 32-bits are always zero. See Intel spec. 2.7.3 "Loading and Storing Debug Registers". */
7362 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_DR7, &HCRegVal); AssertRC(rc);
7363 pCtx->dr[7] = HCRegVal;
7364 }
7365 }
7366
7367 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
7368 {
7369 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, &HCRegVal); AssertRC(rc);
7370 pCtx->SysEnter.eip = HCRegVal;
7371 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, &HCRegVal); AssertRC(rc);
7372 pCtx->SysEnter.esp = HCRegVal;
7373 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRC(rc);
7374 pCtx->SysEnter.cs = u32Val;
7375 }
7376
7377 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
7378 {
7379 if ( pVM->hm.s.fAllow64BitGuests
7380 && (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7381 pCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
7382 }
7383
7384 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
7385 {
7386 if ( pVM->hm.s.fAllow64BitGuests
7387 && (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7388 {
7389 pCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
7390 pCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
7391 pCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
7392 }
7393 }
7394
7395 if (fWhat & (CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS))
7396 {
7397 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
7398 uint32_t const cMsrs = pVmcsInfo->cExitMsrStore;
7399 Assert(pMsrs);
7400 Assert(cMsrs <= VMX_MISC_MAX_MSRS(pVM->hm.s.vmx.Msrs.u64Misc));
7401 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
7402 for (uint32_t i = 0; i < cMsrs; i++)
7403 {
7404 uint32_t const idMsr = pMsrs[i].u32Msr;
7405 switch (idMsr)
7406 {
7407 case MSR_K8_TSC_AUX: CPUMSetGuestTscAux(pVCpu, pMsrs[i].u64Value); break;
7408 case MSR_IA32_SPEC_CTRL: CPUMSetGuestSpecCtrl(pVCpu, pMsrs[i].u64Value); break;
7409 case MSR_K6_EFER: /* Can't be changed without causing a VM-exit */ break;
7410 default:
7411 {
7412 pCtx->fExtrn = 0;
7413 pVCpu->hm.s.u32HMError = pMsrs->u32Msr;
7414 ASMSetFlags(fEFlags);
7415 AssertMsgFailed(("Unexpected MSR in auto-load/store area. idMsr=%#RX32 cMsrs=%u\n", idMsr, cMsrs));
7416 return VERR_HM_UNEXPECTED_LD_ST_MSR;
7417 }
7418 }
7419 }
7420 }
7421
7422 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
7423 {
7424 if (fWhat & CPUMCTX_EXTRN_CR0)
7425 {
7426 RTHCUINTREG HCRegShadow;
7427 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &HCRegVal); AssertRC(rc);
7428 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &HCRegShadow); AssertRC(rc);
7429 HCRegVal = (HCRegVal & ~pVmcsInfo->u64Cr0Mask)
7430 | (HCRegShadow & pVmcsInfo->u64Cr0Mask);
7431#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7432 /*
7433 * Reapply the nested-guest's CR0 fixed bits that might have been altered while
7434 * exporting the nested-guest CR0 for executing using hardware-assisted VMX.
7435 */
7436 if (CPUMIsGuestInVmxNonRootMode(pCtx))
7437 {
7438 HCRegVal |= pCtx->hwvirt.vmx.Msrs.u64Cr0Fixed0;
7439 HCRegVal &= pCtx->hwvirt.vmx.Msrs.u64Cr0Fixed1;
7440 }
7441#endif
7442 VMMRZCallRing3Disable(pVCpu); /* May call into PGM which has Log statements. */
7443 CPUMSetGuestCR0(pVCpu, HCRegVal);
7444 VMMRZCallRing3Enable(pVCpu);
7445 }
7446
7447 if (fWhat & CPUMCTX_EXTRN_CR4)
7448 {
7449 RTHCUINTREG HCRegShadow;
7450 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &HCRegVal); AssertRC(rc);
7451 rc |= VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &HCRegShadow); AssertRC(rc);
7452 HCRegVal = (HCRegVal & ~pVmcsInfo->u64Cr4Mask)
7453 | (HCRegShadow & pVmcsInfo->u64Cr4Mask);
7454#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7455 /*
7456 * Reapply the nested-guest's CR4 fixed bits that might have been altered while
7457 * exporting the nested-guest CR4 for executing using hardware-assisted VMX.
7458 */
7459 if (CPUMIsGuestInVmxNonRootMode(pCtx))
7460 {
7461 HCRegVal |= pCtx->hwvirt.vmx.Msrs.u64Cr4Fixed0;
7462 HCRegVal &= pCtx->hwvirt.vmx.Msrs.u64Cr4Fixed1;
7463 }
7464#endif
7465 pCtx->cr4 = HCRegVal;
7466 }
7467
7468 if (fWhat & CPUMCTX_EXTRN_CR3)
7469 {
7470 /* CR0.PG bit changes are always intercepted, so it's up to date. */
7471 if ( pVM->hm.s.vmx.fUnrestrictedGuest
7472 || ( pVM->hm.s.fNestedPaging
7473 && CPUMIsGuestPagingEnabledEx(pCtx)))
7474 {
7475 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR3, &HCRegVal); AssertRC(rc);
7476 if (pCtx->cr3 != HCRegVal)
7477 {
7478 pCtx->cr3 = HCRegVal;
7479 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
7480 }
7481
7482 /* If the guest is in PAE mode, sync back the PDPE's into the guest state.
7483 Note: CR4.PAE, CR0.PG, EFER MSR changes are always intercepted, so they're up to date. */
7484 if (CPUMIsGuestInPAEModeEx(pCtx))
7485 {
7486 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
7487 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
7488 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
7489 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
7490 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
7491 }
7492 }
7493 }
7494 }
7495
7496#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7497 if (fWhat & CPUMCTX_EXTRN_HWVIRT)
7498 {
7499 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
7500 && !CPUMIsGuestInVmxNonRootMode(pCtx))
7501 {
7502 Assert(CPUMIsGuestInVmxRootMode(pCtx));
7503 rc = hmR0VmxCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
7504 if (RT_SUCCESS(rc))
7505 { /* likely */ }
7506 else
7507 break;
7508 }
7509 }
7510#endif
7511 } while (0);
7512
7513 if (RT_SUCCESS(rc))
7514 {
7515 /* Update fExtrn. */
7516 pCtx->fExtrn &= ~fWhat;
7517
7518 /* If everything has been imported, clear the HM keeper bit. */
7519 if (!(pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL))
7520 {
7521 pCtx->fExtrn &= ~CPUMCTX_EXTRN_KEEPER_HM;
7522 Assert(!pCtx->fExtrn);
7523 }
7524 }
7525 }
7526 else
7527 AssertMsg(!pCtx->fExtrn || (pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL), ("%#RX64\n", pCtx->fExtrn));
7528
7529 /*
7530 * Restore interrupts.
7531 */
7532 ASMSetFlags(fEFlags);
7533
7534 STAM_PROFILE_ADV_STOP(& pVCpu->hm.s.StatImportGuestState, x);
7535
7536 if (RT_SUCCESS(rc))
7537 { /* likely */ }
7538 else
7539 return rc;
7540
7541 /*
7542 * Honor any pending CR3 updates.
7543 *
7544 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> hmR0VmxCallRing3Callback()
7545 * -> VMMRZCallRing3Disable() -> hmR0VmxImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
7546 * -> continue with VM-exit handling -> hmR0VmxImportGuestState() and here we are.
7547 *
7548 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
7549 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
7550 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
7551 * -NOT- check if CPUMCTX_EXTRN_CR3 is set!
7552 *
7553 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
7554 */
7555 if (VMMRZCallRing3IsEnabled(pVCpu))
7556 {
7557 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
7558 {
7559 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & CPUMCTX_EXTRN_CR3));
7560 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
7561 }
7562
7563 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
7564 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
7565
7566 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
7567 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
7568 }
7569
7570 return VINF_SUCCESS;
7571}
7572
7573
7574/**
7575 * Saves the guest state from the VMCS into the guest-CPU context.
7576 *
7577 * @returns VBox status code.
7578 * @param pVCpu The cross context virtual CPU structure.
7579 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7580 */
7581VMMR0DECL(int) VMXR0ImportStateOnDemand(PVMCPU pVCpu, uint64_t fWhat)
7582{
7583 AssertPtr(pVCpu);
7584 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7585 return hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fWhat);
7586}
7587
7588
7589/**
7590 * Check per-VM and per-VCPU force flag actions that require us to go back to
7591 * ring-3 for one reason or another.
7592 *
7593 * @returns Strict VBox status code (i.e. informational status codes too)
7594 * @retval VINF_SUCCESS if we don't have any actions that require going back to
7595 * ring-3.
7596 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
7597 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
7598 * interrupts)
7599 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
7600 * all EMTs to be in ring-3.
7601 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
7602 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
7603 * to the EM loop.
7604 *
7605 * @param pVCpu The cross context virtual CPU structure.
7606 * @param fStepping Whether we are single-stepping the guest using the
7607 * hypervisor debugger.
7608 *
7609 * @remarks This might cause nested-guest VM-exits, caller must check if the guest
7610 * is no longer in VMX non-root mode.
7611 */
7612static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVMCPU pVCpu, bool fStepping)
7613{
7614 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7615
7616 /*
7617 * Update pending interrupts into the APIC's IRR.
7618 */
7619 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
7620 APICUpdatePendingInterrupts(pVCpu);
7621
7622 /*
7623 * Anything pending? Should be more likely than not if we're doing a good job.
7624 */
7625 PVM pVM = pVCpu->CTX_SUFF(pVM);
7626 if ( !fStepping
7627 ? !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_MASK)
7628 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
7629 : !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
7630 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
7631 return VINF_SUCCESS;
7632
7633 /* Pending PGM C3 sync. */
7634 if (VMCPU_FF_IS_ANY_SET(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
7635 {
7636 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7637 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & (CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4)));
7638 VBOXSTRICTRC rcStrict = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4,
7639 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
7640 if (rcStrict != VINF_SUCCESS)
7641 {
7642 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
7643 Log4Func(("PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
7644 return rcStrict;
7645 }
7646 }
7647
7648 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
7649 if ( VM_FF_IS_ANY_SET(pVM, VM_FF_HM_TO_R3_MASK)
7650 || VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
7651 {
7652 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
7653 int rc = RT_LIKELY(!VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_RAW_TO_R3 : VINF_EM_NO_MEMORY;
7654 Log4Func(("HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc));
7655 return rc;
7656 }
7657
7658 /* Pending VM request packets, such as hardware interrupts. */
7659 if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
7660 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
7661 {
7662 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchVmReq);
7663 Log4Func(("Pending VM request forcing us back to ring-3\n"));
7664 return VINF_EM_PENDING_REQUEST;
7665 }
7666
7667 /* Pending PGM pool flushes. */
7668 if (VM_FF_IS_SET(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
7669 {
7670 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPgmPoolFlush);
7671 Log4Func(("PGM pool flush pending forcing us back to ring-3\n"));
7672 return VINF_PGM_POOL_FLUSH_PENDING;
7673 }
7674
7675 /* Pending DMA requests. */
7676 if (VM_FF_IS_SET(pVM, VM_FF_PDM_DMA))
7677 {
7678 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchDma);
7679 Log4Func(("Pending DMA request forcing us back to ring-3\n"));
7680 return VINF_EM_RAW_TO_R3;
7681 }
7682
7683#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7684 /* Pending nested-guest APIC-write (has highest priority among nested-guest FFs). */
7685 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
7686 {
7687 Log4Func(("Pending nested-guest APIC-write\n"));
7688 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitApicWrite(pVCpu);
7689 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
7690 return rcStrict;
7691 }
7692 /** @todo VMCPU_FF_VMX_MTF, VMCPU_FF_VMX_PREEMPT_TIMER */
7693#endif
7694
7695 return VINF_SUCCESS;
7696}
7697
7698
7699/**
7700 * Converts any TRPM trap into a pending HM event. This is typically used when
7701 * entering from ring-3 (not longjmp returns).
7702 *
7703 * @param pVCpu The cross context virtual CPU structure.
7704 */
7705static void hmR0VmxTrpmTrapToPendingEvent(PVMCPU pVCpu)
7706{
7707 Assert(TRPMHasTrap(pVCpu));
7708 Assert(!pVCpu->hm.s.Event.fPending);
7709
7710 uint8_t uVector;
7711 TRPMEVENT enmTrpmEvent;
7712 RTGCUINT uErrCode;
7713 RTGCUINTPTR GCPtrFaultAddress;
7714 uint8_t cbInstr;
7715
7716 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr);
7717 AssertRC(rc);
7718
7719 uint32_t u32IntInfo;
7720 u32IntInfo = uVector | VMX_IDT_VECTORING_INFO_VALID;
7721 u32IntInfo |= HMTrpmEventTypeToVmxEventType(uVector, enmTrpmEvent);
7722
7723 rc = TRPMResetTrap(pVCpu);
7724 AssertRC(rc);
7725 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
7726 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
7727
7728 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
7729}
7730
7731
7732/**
7733 * Converts the pending HM event into a TRPM trap.
7734 *
7735 * @param pVCpu The cross context virtual CPU structure.
7736 */
7737static void hmR0VmxPendingEventToTrpmTrap(PVMCPU pVCpu)
7738{
7739 Assert(pVCpu->hm.s.Event.fPending);
7740
7741 /* If a trap was already pending, we did something wrong! */
7742 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
7743
7744 uint32_t const u32IntInfo = pVCpu->hm.s.Event.u64IntInfo;
7745 uint32_t const uVector = VMX_IDT_VECTORING_INFO_VECTOR(u32IntInfo);
7746 TRPMEVENT const enmTrapType = HMVmxEventTypeToTrpmEventType(u32IntInfo);
7747
7748 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
7749
7750 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
7751 AssertRC(rc);
7752
7753 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
7754 TRPMSetErrorCode(pVCpu, pVCpu->hm.s.Event.u32ErrCode);
7755
7756 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(u32IntInfo))
7757 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
7758 else if (VMX_IDT_VECTORING_INFO_TYPE(u32IntInfo) == VMX_IDT_VECTORING_INFO_TYPE_SW_INT)
7759 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
7760
7761 /* We're now done converting the pending event. */
7762 pVCpu->hm.s.Event.fPending = false;
7763}
7764
7765
7766/**
7767 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
7768 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
7769 *
7770 * @param pVCpu The cross context virtual CPU structure.
7771 * @param pVmcsInfo The VMCS info. object.
7772 */
7773static void hmR0VmxSetIntWindowExitVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
7774{
7775 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7776 {
7777 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
7778 {
7779 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_INT_WINDOW_EXIT;
7780 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7781 AssertRC(rc);
7782 }
7783 } /* else we will deliver interrupts whenever the guest Vm-exits next and is in a state to receive the interrupt. */
7784}
7785
7786
7787/**
7788 * Clears the interrupt-window exiting control in the VMCS.
7789 *
7790 * @param pVmcsInfo The VMCS info. object.
7791 */
7792DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
7793{
7794 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7795 {
7796 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_INT_WINDOW_EXIT;
7797 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7798 AssertRC(rc);
7799 }
7800}
7801
7802
7803/**
7804 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
7805 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
7806 *
7807 * @param pVCpu The cross context virtual CPU structure.
7808 * @param pVmcsInfo The VMCS info. object.
7809 */
7810static void hmR0VmxSetNmiWindowExitVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
7811{
7812 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7813 {
7814 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
7815 {
7816 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_NMI_WINDOW_EXIT;
7817 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7818 AssertRC(rc);
7819 Log4Func(("Setup NMI-window exiting\n"));
7820 }
7821 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
7822}
7823
7824
7825/**
7826 * Clears the NMI-window exiting control in the VMCS.
7827 *
7828 * @param pVmcsInfo The VMCS info. object.
7829 */
7830DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
7831{
7832 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7833 {
7834 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_NMI_WINDOW_EXIT;
7835 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7836 AssertRC(rc);
7837 }
7838}
7839
7840
7841/**
7842 * Does the necessary state syncing before returning to ring-3 for any reason
7843 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
7844 *
7845 * @returns VBox status code.
7846 * @param pVCpu The cross context virtual CPU structure.
7847 * @param fImportState Whether to import the guest state from the VMCS back
7848 * to the guest-CPU context.
7849 *
7850 * @remarks No-long-jmp zone!!!
7851 */
7852static int hmR0VmxLeave(PVMCPU pVCpu, bool fImportState)
7853{
7854 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7855 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7856
7857 RTCPUID const idCpu = RTMpCpuId();
7858 Log4Func(("HostCpuId=%u\n", idCpu));
7859
7860 /*
7861 * !!! IMPORTANT !!!
7862 * If you modify code here, check whether hmR0VmxCallRing3Callback() needs to be updated too.
7863 */
7864
7865 /* Save the guest state if necessary. */
7866 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7867 if (fImportState)
7868 {
7869 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
7870 AssertRCReturn(rc, rc);
7871 }
7872
7873 /* Restore host FPU state if necessary. We will resync on next R0 reentry. */
7874 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
7875 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
7876
7877 /* Restore host debug registers if necessary. We will resync on next R0 reentry. */
7878#ifdef VBOX_STRICT
7879 if (CPUMIsHyperDebugStateActive(pVCpu))
7880 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT);
7881#endif
7882 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
7883 Assert(!CPUMIsGuestDebugStateActive(pVCpu) && !CPUMIsGuestDebugStateActivePending(pVCpu));
7884 Assert(!CPUMIsHyperDebugStateActive(pVCpu) && !CPUMIsHyperDebugStateActivePending(pVCpu));
7885
7886 /* Restore host-state bits that VT-x only restores partially. */
7887 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7888 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7889 {
7890 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags, idCpu));
7891 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7892 }
7893 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7894
7895 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7896 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
7897 {
7898 /* We shouldn't restore the host MSRs without saving the guest MSRs first. */
7899 if (!fImportState)
7900 {
7901 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS);
7902 AssertRCReturn(rc, rc);
7903 }
7904 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7905 Assert(!pVCpu->hm.s.vmx.fLazyMsrs);
7906 }
7907 else
7908 pVCpu->hm.s.vmx.fLazyMsrs = 0;
7909
7910 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7911 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
7912
7913 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
7914 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatImportGuestState);
7915 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExportGuestState);
7916 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatPreExit);
7917 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitHandling);
7918 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
7919 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
7920 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
7921 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitVmentry);
7922 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7923
7924 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7925
7926 /** @todo This partially defeats the purpose of having preemption hooks.
7927 * The problem is, deregistering the hooks should be moved to a place that
7928 * lasts until the EMT is about to be destroyed not everytime while leaving HM
7929 * context.
7930 */
7931 int rc = hmR0VmxClearVmcs(pVmcsInfo);
7932 AssertRCReturn(rc, rc);
7933
7934#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7935 /*
7936 * A valid shadow VMCS is made active as part of VM-entry. It is necessary to
7937 * clear a shadow VMCS before allowing that VMCS to become active on another
7938 * logical processor. We may or may not be importing guest state which clears
7939 * it, so cover for it here.
7940 *
7941 * See Intel spec. 24.11.1 "Software Use of Virtual-Machine Control Structures".
7942 */
7943 if ( pVmcsInfo->pvShadowVmcs
7944 && pVmcsInfo->fShadowVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
7945 {
7946 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
7947 AssertRCReturn(rc, rc);
7948 }
7949
7950 /*
7951 * Flag that we need to re-import the host state if we switch to this VMCS before
7952 * executing guest or nested-guest code.
7953 */
7954 pVmcsInfo->idHostCpu = NIL_RTCPUID;
7955#endif
7956
7957 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
7958 NOREF(idCpu);
7959 return VINF_SUCCESS;
7960}
7961
7962
7963/**
7964 * Leaves the VT-x session.
7965 *
7966 * @returns VBox status code.
7967 * @param pVCpu The cross context virtual CPU structure.
7968 *
7969 * @remarks No-long-jmp zone!!!
7970 */
7971static int hmR0VmxLeaveSession(PVMCPU pVCpu)
7972{
7973 HM_DISABLE_PREEMPT(pVCpu);
7974 HMVMX_ASSERT_CPU_SAFE(pVCpu);
7975 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7976 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7977
7978 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
7979 and done this from the VMXR0ThreadCtxCallback(). */
7980 if (!pVCpu->hm.s.fLeaveDone)
7981 {
7982 int rc2 = hmR0VmxLeave(pVCpu, true /* fImportState */);
7983 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
7984 pVCpu->hm.s.fLeaveDone = true;
7985 }
7986 Assert(!pVCpu->cpum.GstCtx.fExtrn);
7987
7988 /*
7989 * !!! IMPORTANT !!!
7990 * If you modify code here, make sure to check whether hmR0VmxCallRing3Callback() needs to be updated too.
7991 */
7992
7993 /* Deregister hook now that we've left HM context before re-enabling preemption. */
7994 /** @todo Deregistering here means we need to VMCLEAR always
7995 * (longjmp/exit-to-r3) in VT-x which is not efficient, eliminate need
7996 * for calling VMMR0ThreadCtxHookDisable here! */
7997 VMMR0ThreadCtxHookDisable(pVCpu);
7998
7999 /* Leave HM context. This takes care of local init (term). */
8000 int rc = HMR0LeaveCpu(pVCpu);
8001
8002 HM_RESTORE_PREEMPT();
8003 return rc;
8004}
8005
8006
8007/**
8008 * Does the necessary state syncing before doing a longjmp to ring-3.
8009 *
8010 * @returns VBox status code.
8011 * @param pVCpu The cross context virtual CPU structure.
8012 *
8013 * @remarks No-long-jmp zone!!!
8014 */
8015DECLINLINE(int) hmR0VmxLongJmpToRing3(PVMCPU pVCpu)
8016{
8017 return hmR0VmxLeaveSession(pVCpu);
8018}
8019
8020
8021/**
8022 * Take necessary actions before going back to ring-3.
8023 *
8024 * An action requires us to go back to ring-3. This function does the necessary
8025 * steps before we can safely return to ring-3. This is not the same as longjmps
8026 * to ring-3, this is voluntary and prepares the guest so it may continue
8027 * executing outside HM (recompiler/IEM).
8028 *
8029 * @returns VBox status code.
8030 * @param pVCpu The cross context virtual CPU structure.
8031 * @param rcExit The reason for exiting to ring-3. Can be
8032 * VINF_VMM_UNKNOWN_RING3_CALL.
8033 */
8034static int hmR0VmxExitToRing3(PVMCPU pVCpu, VBOXSTRICTRC rcExit)
8035{
8036 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8037
8038 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8039 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
8040 {
8041 VMXGetCurrentVmcs(&pVCpu->hm.s.vmx.LastError.HCPhysCurrentVmcs);
8042 pVCpu->hm.s.vmx.LastError.u32VmcsRev = *(uint32_t *)pVmcsInfo->pvVmcs;
8043 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
8044 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
8045 }
8046
8047 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
8048 VMMRZCallRing3Disable(pVCpu);
8049 Log4Func(("rcExit=%d\n", VBOXSTRICTRC_VAL(rcExit)));
8050
8051 /*
8052 * Convert any pending HM events back to TRPM due to premature exits to ring-3.
8053 * We need to do this only on returns to ring-3 and not for longjmps to ring3.
8054 *
8055 * This is because execution may continue from ring-3 and we would need to inject
8056 * the event from there (hence place it back in TRPM).
8057 */
8058 if (pVCpu->hm.s.Event.fPending)
8059 {
8060 hmR0VmxPendingEventToTrpmTrap(pVCpu);
8061 Assert(!pVCpu->hm.s.Event.fPending);
8062
8063 /* Clear the events from the VMCS. */
8064 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0);
8065 AssertRC(rc);
8066 }
8067#ifdef VBOX_STRICT
8068 else
8069 {
8070 /*
8071 * Ensure we don't accidentally clear a pending HM event without clearing the VMCS.
8072 * This can be pretty hard to debug otherwise, interrupts might get injected twice
8073 * occasionally, see @bugref{9180#c42}.
8074 *
8075 * However, if the VM-entry failed, any VM entry-interruption info. field would
8076 * be left unmodified as the event would not have been injected to the guest. In
8077 * such cases, don't assert, we're not going to continue guest execution anyway.
8078 */
8079 uint32_t uExitReason;
8080 uint32_t uEntryIntInfo;
8081 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8082 rc |= VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &uEntryIntInfo);
8083 AssertRC(rc);
8084 Assert(VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason) || !VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo));
8085 }
8086#endif
8087
8088 /*
8089 * Clear the interrupt-window and NMI-window VMCS controls as we could have got
8090 * a VM-exit with higher priority than interrupt-window or NMI-window VM-exits
8091 * (e.g. TPR below threshold).
8092 */
8093 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8094 {
8095 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
8096 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
8097 }
8098
8099 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
8100 and if we're injecting an event we should have a TRPM trap pending. */
8101 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8102#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a triple fault in progress. */
8103 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8104#endif
8105
8106 /* Save guest state and restore host state bits. */
8107 int rc = hmR0VmxLeaveSession(pVCpu);
8108 AssertRCReturn(rc, rc);
8109 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8110
8111 /* Thread-context hooks are unregistered at this point!!! */
8112
8113 /* Sync recompiler state. */
8114 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
8115 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
8116 | CPUM_CHANGED_LDTR
8117 | CPUM_CHANGED_GDTR
8118 | CPUM_CHANGED_IDTR
8119 | CPUM_CHANGED_TR
8120 | CPUM_CHANGED_HIDDEN_SEL_REGS);
8121 if ( pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging
8122 && CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx))
8123 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
8124
8125 Assert(!pVCpu->hm.s.fClearTrapFlag);
8126
8127 /* Update the exit-to-ring 3 reason. */
8128 pVCpu->hm.s.rcLastExitToR3 = VBOXSTRICTRC_VAL(rcExit);
8129
8130 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
8131 if ( rcExit != VINF_EM_RAW_INTERRUPT
8132 || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8133 {
8134 Assert(!(pVCpu->cpum.GstCtx.fExtrn & HMVMX_CPUMCTX_EXTRN_ALL));
8135 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
8136 }
8137
8138 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
8139
8140 /* We do -not- want any longjmp notifications after this! We must return to ring-3 ASAP. */
8141 VMMRZCallRing3RemoveNotification(pVCpu);
8142 VMMRZCallRing3Enable(pVCpu);
8143
8144 return rc;
8145}
8146
8147
8148/**
8149 * VMMRZCallRing3() callback wrapper which saves the guest state before we
8150 * longjump to ring-3 and possibly get preempted.
8151 *
8152 * @returns VBox status code.
8153 * @param pVCpu The cross context virtual CPU structure.
8154 * @param enmOperation The operation causing the ring-3 longjump.
8155 * @param pvUser User argument, currently unused, NULL.
8156 */
8157static DECLCALLBACK(int) hmR0VmxCallRing3Callback(PVMCPU pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
8158{
8159 RT_NOREF(pvUser);
8160 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
8161 {
8162 /*
8163 * !!! IMPORTANT !!!
8164 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
8165 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
8166 */
8167 VMMRZCallRing3RemoveNotification(pVCpu);
8168 VMMRZCallRing3Disable(pVCpu);
8169 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
8170 RTThreadPreemptDisable(&PreemptState);
8171
8172 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8173 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8174 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8175 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8176
8177 /* Restore host-state bits that VT-x only restores partially. */
8178 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
8179 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
8180 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
8181 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
8182
8183 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8184 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8185 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8186
8187 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8188 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
8189 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8190
8191 /* Clear the current VMCS data back to memory (shadow VMCS if any would have been
8192 cleared as part of importing the guest state above. */
8193 hmR0VmxClearVmcs(pVmcsInfo);
8194
8195 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
8196 VMMR0ThreadCtxHookDisable(pVCpu);
8197 HMR0LeaveCpu(pVCpu);
8198 RTThreadPreemptRestore(&PreemptState);
8199 return VINF_SUCCESS;
8200 }
8201
8202 Assert(pVCpu);
8203 Assert(pvUser);
8204 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8205 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8206
8207 VMMRZCallRing3Disable(pVCpu);
8208 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8209
8210 Log4Func((" -> hmR0VmxLongJmpToRing3 enmOperation=%d\n", enmOperation));
8211
8212 int rc = hmR0VmxLongJmpToRing3(pVCpu);
8213 AssertRCReturn(rc, rc);
8214
8215 VMMRZCallRing3Enable(pVCpu);
8216 return VINF_SUCCESS;
8217}
8218
8219
8220/**
8221 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
8222 * stack.
8223 *
8224 * @returns Strict VBox status code (i.e. informational status codes too).
8225 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
8226 * @param pVCpu The cross context virtual CPU structure.
8227 * @param uValue The value to push to the guest stack.
8228 */
8229static VBOXSTRICTRC hmR0VmxRealModeGuestStackPush(PVMCPU pVCpu, uint16_t uValue)
8230{
8231 /*
8232 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
8233 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
8234 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
8235 */
8236 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8237 if (pCtx->sp == 1)
8238 return VINF_EM_RESET;
8239 pCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
8240 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), pCtx->ss.u64Base + pCtx->sp, &uValue, sizeof(uint16_t));
8241 AssertRC(rc);
8242 return rc;
8243}
8244
8245
8246/**
8247 * Injects an event into the guest upon VM-entry by updating the relevant fields
8248 * in the VM-entry area in the VMCS.
8249 *
8250 * @returns Strict VBox status code (i.e. informational status codes too).
8251 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
8252 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
8253 *
8254 * @param pVCpu The cross context virtual CPU structure.
8255 * @param pVmxTransient The VMX-transient structure.
8256 * @param pEvent The event being injected.
8257 * @param pfIntrState Pointer to the VT-x guest-interruptibility-state. This
8258 * will be updated if necessary. This cannot not be NULL.
8259 * @param fStepping Whether we're single-stepping guest execution and should
8260 * return VINF_EM_DBG_STEPPED if the event is injected
8261 * directly (registers modified by us, not by hardware on
8262 * VM-entry).
8263 */
8264static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PCHMEVENT pEvent, bool fStepping,
8265 uint32_t *pfIntrState)
8266{
8267 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
8268 AssertMsg(!RT_HI_U32(pEvent->u64IntInfo), ("%#RX64\n", pEvent->u64IntInfo));
8269 Assert(pfIntrState);
8270
8271 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8272 uint32_t u32IntInfo = pEvent->u64IntInfo;
8273 uint32_t const u32ErrCode = pEvent->u32ErrCode;
8274 uint32_t const cbInstr = pEvent->cbInstr;
8275 RTGCUINTPTR const GCPtrFault = pEvent->GCPtrFaultAddress;
8276 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(u32IntInfo);
8277 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(u32IntInfo);
8278
8279#ifdef VBOX_STRICT
8280 /*
8281 * Validate the error-code-valid bit for hardware exceptions.
8282 * No error codes for exceptions in real-mode.
8283 *
8284 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8285 */
8286 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8287 && !CPUMIsGuestInRealModeEx(pCtx))
8288 {
8289 switch (uVector)
8290 {
8291 case X86_XCPT_PF:
8292 case X86_XCPT_DF:
8293 case X86_XCPT_TS:
8294 case X86_XCPT_NP:
8295 case X86_XCPT_SS:
8296 case X86_XCPT_GP:
8297 case X86_XCPT_AC:
8298 AssertMsg(VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo),
8299 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
8300 RT_FALL_THRU();
8301 default:
8302 break;
8303 }
8304 }
8305
8306 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
8307 Assert( uIntType != VMX_EXIT_INT_INFO_TYPE_NMI
8308 || !(*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
8309#endif
8310
8311 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
8312
8313 /*
8314 * Hardware interrupts & exceptions cannot be delivered through the software interrupt
8315 * redirection bitmap to the real mode task in virtual-8086 mode. We must jump to the
8316 * interrupt handler in the (real-mode) guest.
8317 *
8318 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode".
8319 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
8320 */
8321 if (CPUMIsGuestInRealModeEx(pCtx)) /* CR0.PE bit changes are always intercepted, so it's up to date. */
8322 {
8323 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest)
8324 {
8325 /*
8326 * For CPUs with unrestricted guest execution enabled and with the guest
8327 * in real-mode, we must not set the deliver-error-code bit.
8328 *
8329 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8330 */
8331 u32IntInfo &= ~VMX_ENTRY_INT_INFO_ERROR_CODE_VALID;
8332 }
8333 else
8334 {
8335 PVM pVM = pVCpu->CTX_SUFF(pVM);
8336 Assert(PDMVmmDevHeapIsEnabled(pVM));
8337 Assert(pVM->hm.s.vmx.pRealModeTSS);
8338 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
8339
8340 /* We require RIP, RSP, RFLAGS, CS, IDTR, import them. */
8341 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8342 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TABLE_MASK
8343 | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS);
8344 AssertRCReturn(rc2, rc2);
8345
8346 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8347 size_t const cbIdtEntry = sizeof(X86IDTR16);
8348 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pCtx->idtr.cbIdt)
8349 {
8350 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8351 if (uVector == X86_XCPT_DF)
8352 return VINF_EM_RESET;
8353
8354 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault.
8355 No error codes for exceptions in real-mode. */
8356 if (uVector == X86_XCPT_GP)
8357 {
8358 uint32_t const uXcptDfInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
8359 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8360 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8361 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8362 HMEVENT EventXcptDf;
8363 RT_ZERO(EventXcptDf);
8364 EventXcptDf.u64IntInfo = uXcptDfInfo;
8365 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptDf, fStepping, pfIntrState);
8366 }
8367
8368 /*
8369 * If we're injecting an event with no valid IDT entry, inject a #GP.
8370 * No error codes for exceptions in real-mode.
8371 *
8372 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8373 */
8374 uint32_t const uXcptGpInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
8375 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8376 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8377 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8378 HMEVENT EventXcptGp;
8379 RT_ZERO(EventXcptGp);
8380 EventXcptGp.u64IntInfo = uXcptGpInfo;
8381 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptGp, fStepping, pfIntrState);
8382 }
8383
8384 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8385 uint16_t uGuestIp = pCtx->ip;
8386 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT)
8387 {
8388 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8389 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8390 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8391 }
8392 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_INT)
8393 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8394
8395 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8396 X86IDTR16 IdtEntry;
8397 RTGCPHYS const GCPhysIdtEntry = (RTGCPHYS)pCtx->idtr.pIdt + uVector * cbIdtEntry;
8398 rc2 = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8399 AssertRCReturn(rc2, rc2);
8400
8401 /* Construct the stack frame for the interrupt/exception handler. */
8402 VBOXSTRICTRC rcStrict;
8403 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->eflags.u32);
8404 if (rcStrict == VINF_SUCCESS)
8405 {
8406 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->cs.Sel);
8407 if (rcStrict == VINF_SUCCESS)
8408 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, uGuestIp);
8409 }
8410
8411 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8412 if (rcStrict == VINF_SUCCESS)
8413 {
8414 pCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8415 pCtx->rip = IdtEntry.offSel;
8416 pCtx->cs.Sel = IdtEntry.uSel;
8417 pCtx->cs.ValidSel = IdtEntry.uSel;
8418 pCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8419 if ( uIntType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
8420 && uVector == X86_XCPT_PF)
8421 pCtx->cr2 = GCPtrFault;
8422
8423 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CS | HM_CHANGED_GUEST_CR2
8424 | HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
8425 | HM_CHANGED_GUEST_RSP);
8426
8427 /*
8428 * If we delivered a hardware exception (other than an NMI) and if there was
8429 * block-by-STI in effect, we should clear it.
8430 */
8431 if (*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
8432 {
8433 Assert( uIntType != VMX_ENTRY_INT_INFO_TYPE_NMI
8434 && uIntType != VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
8435 Log4Func(("Clearing inhibition due to STI\n"));
8436 *pfIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
8437 }
8438
8439 Log4(("Injected real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8440 u32IntInfo, u32ErrCode, cbInstr, pCtx->eflags.u, pCtx->cs.Sel, pCtx->eip));
8441
8442 /*
8443 * The event has been truly dispatched to the guest. Mark it as no longer pending so
8444 * we don't attempt to undo it if we are returning to ring-3 before executing guest code.
8445 */
8446 pVCpu->hm.s.Event.fPending = false;
8447
8448 /*
8449 * If we eventually support nested-guest execution without unrestricted guest execution,
8450 * we should set fInterceptEvents here.
8451 */
8452 Assert(!pVmxTransient->fIsNestedGuest);
8453
8454 /* If we're stepping and we've changed cs:rip above, bail out of the VMX R0 execution loop. */
8455 if (fStepping)
8456 rcStrict = VINF_EM_DBG_STEPPED;
8457 }
8458 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8459 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8460 return rcStrict;
8461 }
8462 }
8463
8464 /*
8465 * Validate.
8466 */
8467 Assert(VMX_ENTRY_INT_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
8468 Assert(!(u32IntInfo & VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK)); /* Bits 30:12 MBZ. */
8469
8470 /*
8471 * Inject the event into the VMCS.
8472 */
8473 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8474 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8475 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8476 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8477 AssertRC(rc);
8478
8479 /*
8480 * Update guest CR2 if this is a page-fault.
8481 */
8482 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
8483 pCtx->cr2 = GCPtrFault;
8484
8485 Log4(("Injecting u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x CR2=%#RX64\n", u32IntInfo, u32ErrCode, cbInstr, pCtx->cr2));
8486 return VINF_SUCCESS;
8487}
8488
8489
8490/**
8491 * Evaluates the event to be delivered to the guest and sets it as the pending
8492 * event.
8493 *
8494 * @returns Strict VBox status code (i.e. informational status codes too).
8495 * @param pVCpu The cross context virtual CPU structure.
8496 * @param pVmxTransient The VMX-transient structure.
8497 * @param pfIntrState Where to store the VT-x guest-interruptibility state.
8498 */
8499static VBOXSTRICTRC hmR0VmxEvaluatePendingEvent(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t *pfIntrState)
8500{
8501 Assert(pfIntrState);
8502 Assert(!TRPMHasTrap(pVCpu));
8503
8504 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8505 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8506 bool const fIsNestedGuest = pVmxTransient->fIsNestedGuest;
8507
8508 /*
8509 * Get the current interruptibility-state of the guest or nested-guest and
8510 * then figure out what needs to be injected.
8511 */
8512 uint32_t const fIntrState = hmR0VmxGetGuestIntrState(pVCpu, pVmxTransient);
8513 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
8514 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
8515 bool const fBlockNmi = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
8516
8517 /* We don't support block-by-SMI yet.*/
8518 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI));
8519
8520 /* Block-by-STI must not be set when interrupts are disabled. */
8521 if (fBlockSti)
8522 {
8523 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
8524 Assert(pCtx->eflags.Bits.u1IF);
8525 }
8526
8527 /* Update interruptibility state to the caller. */
8528 *pfIntrState = fIntrState;
8529
8530 /*
8531 * Toggling of interrupt force-flags here is safe since we update TRPM on
8532 * premature exits to ring-3 before executing guest code, see hmR0VmxExitToRing3().
8533 * We must NOT restore these force-flags.
8534 */
8535
8536 /** @todo SMI. SMIs take priority over NMIs. */
8537
8538 /*
8539 * Check if an NMI is pending and if the guest or nested-guest can receive them.
8540 * NMIs take priority over external interrupts.
8541 */
8542 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
8543 {
8544 /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
8545 if ( !pVCpu->hm.s.Event.fPending
8546 && !fBlockNmi
8547 && !fBlockSti
8548 && !fBlockMovSS)
8549 {
8550#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8551 if ( fIsNestedGuest
8552 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_NMI_EXIT))
8553 return IEMExecVmxVmexitXcptNmi(pVCpu);
8554#endif
8555 hmR0VmxSetPendingXcptNmi(pVCpu);
8556 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
8557 Log4Func(("Pending NMI\n"));
8558 }
8559 else if (!fIsNestedGuest)
8560 hmR0VmxSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
8561 /* else: for nested-guests, NMI-window exiting will be picked up when merging VMCS controls. */
8562 }
8563 /*
8564 * Check if an external interrupt (PIC/APIC) is pending and if the guest or nested-guest
8565 * can receive them. Once PDMGetInterrupt() returns a valid interrupt we -must- deliver
8566 * the interrupt. We can no longer re-request it from the APIC.
8567 */
8568 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
8569 && !pVCpu->hm.s.fSingleInstruction)
8570 {
8571 Assert(!DBGFIsStepping(pVCpu));
8572 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
8573 AssertRCReturn(rc, rc);
8574
8575 bool const fBlockInt = !(pCtx->eflags.u32 & X86_EFL_IF);
8576 if ( !pVCpu->hm.s.Event.fPending
8577 && !fBlockInt
8578 && !fBlockSti
8579 && !fBlockMovSS)
8580 {
8581#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8582 if ( fIsNestedGuest
8583 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
8584 && !CPUMIsGuestVmxExitCtlsSet(pVCpu, pCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
8585 {
8586 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
8587 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8588 return rcStrict;
8589 }
8590#endif
8591 uint8_t u8Interrupt;
8592 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
8593 if (RT_SUCCESS(rc))
8594 {
8595#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8596 if ( fIsNestedGuest
8597 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
8598 && CPUMIsGuestVmxExitCtlsSet(pVCpu, pCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
8599 {
8600 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, u8Interrupt, false /* fIntPending */);
8601 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8602 return rcStrict;
8603 }
8604#endif
8605 hmR0VmxSetPendingExtInt(pVCpu, u8Interrupt);
8606 Log4Func(("Pending external interrupt vector %#x\n", u8Interrupt));
8607 }
8608 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
8609 {
8610 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
8611
8612 if ( !fIsNestedGuest
8613 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
8614 hmR0VmxApicSetTprThreshold(pVmcsInfo, u8Interrupt >> 4);
8615 /* else: for nested-guests, TPR threshold is picked up while merging VMCS controls. */
8616
8617 /*
8618 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
8619 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
8620 * need to re-set this force-flag here.
8621 */
8622 }
8623 else
8624 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
8625 }
8626 else if (!fIsNestedGuest)
8627 hmR0VmxSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
8628 /* else: for nested-guests, interrupt-window exiting will be picked up when merging VMCS controls. */
8629 }
8630
8631 return VINF_SUCCESS;
8632}
8633
8634
8635/**
8636 * Injects any pending events into the guest if the guest is in a state to
8637 * receive them.
8638 *
8639 * @returns Strict VBox status code (i.e. informational status codes too).
8640 * @param pVCpu The cross context virtual CPU structure.
8641 * @param pVmxTransient The VMX-transient structure.
8642 * @param fIntrState The VT-x guest-interruptibility state.
8643 * @param fStepping Whether we are single-stepping the guest using the
8644 * hypervisor debugger and should return
8645 * VINF_EM_DBG_STEPPED if the event was dispatched
8646 * directly.
8647 */
8648static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t fIntrState, bool fStepping)
8649{
8650 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8651 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8652
8653 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
8654 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
8655
8656 Assert(!fBlockSti || !(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_RFLAGS));
8657 Assert(!fBlockSti || pVCpu->cpum.GstCtx.eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
8658 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
8659 Assert(!TRPMHasTrap(pVCpu));
8660
8661 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
8662 if (pVCpu->hm.s.Event.fPending)
8663 {
8664 /*
8665 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
8666 * pending even while injecting an event and in this case, we want a VM-exit as soon as
8667 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
8668 *
8669 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
8670 */
8671 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
8672#ifdef VBOX_STRICT
8673 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
8674 {
8675 bool const fBlockInt = !(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_IF);
8676 Assert(!fBlockInt);
8677 Assert(!fBlockSti);
8678 Assert(!fBlockMovSS);
8679 }
8680 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_NMI)
8681 {
8682 bool const fBlockNmi = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
8683 Assert(!fBlockSti);
8684 Assert(!fBlockMovSS);
8685 Assert(!fBlockNmi);
8686 }
8687#endif
8688 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
8689 uIntType));
8690
8691 /*
8692 * Inject the event and get any changes to the guest-interruptibility state.
8693 *
8694 * The guest-interruptibility state may need to be updated if we inject the event
8695 * into the guest IDT ourselves (for real-on-v86 guest injecting software interrupts).
8696 */
8697 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &pVCpu->hm.s.Event, fStepping, &fIntrState);
8698 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
8699
8700 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
8701 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
8702 else
8703 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
8704 }
8705
8706 /*
8707 * Update the guest-interruptibility state.
8708 *
8709 * This is required for the real-on-v86 software interrupt injection case above, as well as
8710 * updates to the guest state from ring-3 or IEM/REM.
8711 */
8712 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
8713 AssertRC(rc);
8714
8715 /*
8716 * There's no need to clear the VM-entry interruption-information field here if we're not
8717 * injecting anything. VT-x clears the valid bit on every VM-exit.
8718 *
8719 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
8720 */
8721
8722 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
8723 NOREF(fBlockMovSS); NOREF(fBlockSti);
8724 return rcStrict;
8725}
8726
8727
8728/**
8729 * Enters the VT-x session.
8730 *
8731 * @returns VBox status code.
8732 * @param pVCpu The cross context virtual CPU structure.
8733 */
8734VMMR0DECL(int) VMXR0Enter(PVMCPU pVCpu)
8735{
8736 AssertPtr(pVCpu);
8737 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported);
8738 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8739
8740 LogFlowFunc(("pVCpu=%p\n", pVCpu));
8741 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
8742 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
8743
8744#ifdef VBOX_STRICT
8745 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
8746 RTCCUINTREG uHostCr4 = ASMGetCR4();
8747 if (!(uHostCr4 & X86_CR4_VMXE))
8748 {
8749 LogRelFunc(("X86_CR4_VMXE bit in CR4 is not set!\n"));
8750 return VERR_VMX_X86_CR4_VMXE_CLEARED;
8751 }
8752#endif
8753
8754 /*
8755 * Load the appropriate VMCS as the current and active one.
8756 */
8757 PVMXVMCSINFO pVmcsInfo;
8758 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx);
8759 if (!fInNestedGuestMode)
8760 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfo;
8761 else
8762 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
8763 int rc = hmR0VmxLoadVmcs(pVmcsInfo);
8764 if (RT_SUCCESS(rc))
8765 {
8766 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs = fInNestedGuestMode;
8767 pVCpu->hm.s.fLeaveDone = false;
8768 Log4Func(("Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8769
8770 /*
8771 * Do the EMT scheduled L1D flush here if needed.
8772 */
8773 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
8774 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
8775 else if (pVCpu->CTX_SUFF(pVM)->hm.s.fMdsClearOnSched)
8776 hmR0MdsClear();
8777 }
8778 return rc;
8779}
8780
8781
8782/**
8783 * The thread-context callback (only on platforms which support it).
8784 *
8785 * @param enmEvent The thread-context event.
8786 * @param pVCpu The cross context virtual CPU structure.
8787 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
8788 * @thread EMT(pVCpu)
8789 */
8790VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPU pVCpu, bool fGlobalInit)
8791{
8792 AssertPtr(pVCpu);
8793 RT_NOREF1(fGlobalInit);
8794
8795 switch (enmEvent)
8796 {
8797 case RTTHREADCTXEVENT_OUT:
8798 {
8799 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8800 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8801 VMCPU_ASSERT_EMT(pVCpu);
8802
8803 /* No longjmps (logger flushes, locks) in this fragile context. */
8804 VMMRZCallRing3Disable(pVCpu);
8805 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
8806
8807 /* Restore host-state (FPU, debug etc.) */
8808 if (!pVCpu->hm.s.fLeaveDone)
8809 {
8810 /*
8811 * Do -not- import the guest-state here as we might already be in the middle of importing
8812 * it, esp. bad if we're holding the PGM lock, see comment in hmR0VmxImportGuestState().
8813 */
8814 hmR0VmxLeave(pVCpu, false /* fImportState */);
8815 pVCpu->hm.s.fLeaveDone = true;
8816 }
8817
8818 /* Leave HM context, takes care of local init (term). */
8819 int rc = HMR0LeaveCpu(pVCpu);
8820 AssertRC(rc);
8821
8822 /* Restore longjmp state. */
8823 VMMRZCallRing3Enable(pVCpu);
8824 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
8825 break;
8826 }
8827
8828 case RTTHREADCTXEVENT_IN:
8829 {
8830 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8831 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8832 VMCPU_ASSERT_EMT(pVCpu);
8833
8834 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
8835 VMMRZCallRing3Disable(pVCpu);
8836 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
8837
8838 /* Initialize the bare minimum state required for HM. This takes care of
8839 initializing VT-x if necessary (onlined CPUs, local init etc.) */
8840 int rc = hmR0EnterCpu(pVCpu);
8841 AssertRC(rc);
8842 Assert( (pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
8843 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
8844
8845 /* Load the active VMCS as the current one. */
8846 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8847 rc = hmR0VmxLoadVmcs(pVmcsInfo);
8848 AssertRC(rc);
8849 Log4Func(("Resumed: Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8850 pVCpu->hm.s.fLeaveDone = false;
8851
8852 /* Do the EMT scheduled L1D flush if needed. */
8853 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
8854 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
8855
8856 /* Restore longjmp state. */
8857 VMMRZCallRing3Enable(pVCpu);
8858 break;
8859 }
8860
8861 default:
8862 break;
8863 }
8864}
8865
8866
8867/**
8868 * Exports the host state into the VMCS host-state area.
8869 * Sets up the VM-exit MSR-load area.
8870 *
8871 * The CPU state will be loaded from these fields on every successful VM-exit.
8872 *
8873 * @returns VBox status code.
8874 * @param pVCpu The cross context virtual CPU structure.
8875 *
8876 * @remarks No-long-jump zone!!!
8877 */
8878static int hmR0VmxExportHostState(PVMCPU pVCpu)
8879{
8880 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8881
8882 int rc = VINF_SUCCESS;
8883 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
8884 {
8885 hmR0VmxExportHostControlRegs();
8886
8887 rc = hmR0VmxExportHostSegmentRegs(pVCpu);
8888 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8889
8890 hmR0VmxExportHostMsrs(pVCpu);
8891
8892 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_HOST_CONTEXT;
8893 }
8894 return rc;
8895}
8896
8897
8898/**
8899 * Saves the host state in the VMCS host-state.
8900 *
8901 * @returns VBox status code.
8902 * @param pVCpu The cross context virtual CPU structure.
8903 *
8904 * @remarks No-long-jump zone!!!
8905 */
8906VMMR0DECL(int) VMXR0ExportHostState(PVMCPU pVCpu)
8907{
8908 AssertPtr(pVCpu);
8909 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8910
8911 /*
8912 * Export the host state here while entering HM context.
8913 * When thread-context hooks are used, we might get preempted and have to re-save the host
8914 * state but most of the time we won't be, so do it here before we disable interrupts.
8915 */
8916 return hmR0VmxExportHostState(pVCpu);
8917}
8918
8919
8920/**
8921 * Exports the guest state into the VMCS guest-state area.
8922 *
8923 * The will typically be done before VM-entry when the guest-CPU state and the
8924 * VMCS state may potentially be out of sync.
8925 *
8926 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
8927 * VM-entry controls.
8928 * Sets up the appropriate VMX non-root function to execute guest code based on
8929 * the guest CPU mode.
8930 *
8931 * @returns VBox strict status code.
8932 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8933 * without unrestricted guest execution and the VMMDev is not presently
8934 * mapped (e.g. EFI32).
8935 *
8936 * @param pVCpu The cross context virtual CPU structure.
8937 * @param pVmxTransient The VMX-transient structure.
8938 *
8939 * @remarks No-long-jump zone!!!
8940 */
8941static VBOXSTRICTRC hmR0VmxExportGuestState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
8942{
8943 AssertPtr(pVCpu);
8944 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8945 LogFlowFunc(("pVCpu=%p\n", pVCpu));
8946
8947 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExportGuestState, x);
8948
8949 /*
8950 * Determine real-on-v86 mode.
8951 * Used when the guest is in real-mode and unrestricted guest execution is not used.
8952 */
8953 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8954 if ( pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest
8955 || !CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx))
8956 pVmcsInfo->RealMode. fRealOnV86Active = false;
8957 else
8958 {
8959 Assert(!pVmxTransient->fIsNestedGuest);
8960 pVmcsInfo->RealMode.fRealOnV86Active = true;
8961 }
8962
8963 /*
8964 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
8965 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
8966 */
8967 /** @todo r=ramshankar: Move hmR0VmxSelectVMRunHandler inside
8968 * hmR0VmxExportGuestEntryExitCtls and do it conditionally. There shouldn't
8969 * be a need to evaluate this everytime since I'm pretty sure we intercept
8970 * all guest paging mode changes. */
8971 int rc = hmR0VmxSelectVMRunHandler(pVCpu, pVmxTransient);
8972 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8973
8974 rc = hmR0VmxExportGuestEntryExitCtls(pVCpu, pVmxTransient);
8975 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8976
8977 rc = hmR0VmxExportGuestCR0(pVCpu, pVmxTransient);
8978 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8979
8980 VBOXSTRICTRC rcStrict = hmR0VmxExportGuestCR3AndCR4(pVCpu, pVmxTransient);
8981 if (rcStrict == VINF_SUCCESS)
8982 { /* likely */ }
8983 else
8984 {
8985 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
8986 return rcStrict;
8987 }
8988
8989 rc = hmR0VmxExportGuestSegRegsXdtr(pVCpu, pVmxTransient);
8990 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8991
8992 rc = hmR0VmxExportGuestMsrs(pVCpu, pVmxTransient);
8993 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8994
8995 rc = hmR0VmxExportGuestApicTpr(pVCpu, pVmxTransient);
8996 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8997
8998 rc = hmR0VmxExportGuestXcptIntercepts(pVCpu, pVmxTransient);
8999 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9000
9001 rc = hmR0VmxExportGuestRip(pVCpu);
9002 rc |= hmR0VmxExportGuestRsp(pVCpu);
9003 rc |= hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9004 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9005
9006 rc = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9007 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9008
9009 /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
9010 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~( (HM_CHANGED_GUEST_GPRS_MASK & ~HM_CHANGED_GUEST_RSP)
9011 | HM_CHANGED_GUEST_CR2
9012 | (HM_CHANGED_GUEST_DR_MASK & ~HM_CHANGED_GUEST_DR7)
9013 | HM_CHANGED_GUEST_X87
9014 | HM_CHANGED_GUEST_SSE_AVX
9015 | HM_CHANGED_GUEST_OTHER_XSAVE
9016 | HM_CHANGED_GUEST_XCRx
9017 | HM_CHANGED_GUEST_KERNEL_GS_BASE /* Part of lazy or auto load-store MSRs. */
9018 | HM_CHANGED_GUEST_SYSCALL_MSRS /* Part of lazy or auto load-store MSRs. */
9019 | HM_CHANGED_GUEST_TSC_AUX
9020 | HM_CHANGED_GUEST_OTHER_MSRS
9021 | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
9022
9023 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExportGuestState, x);
9024 return rc;
9025}
9026
9027
9028/**
9029 * Exports the state shared between the host and guest into the VMCS.
9030 *
9031 * @param pVCpu The cross context virtual CPU structure.
9032 * @param pVmxTransient The VMX-transient structure.
9033 *
9034 * @remarks No-long-jump zone!!!
9035 */
9036static void hmR0VmxExportSharedState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
9037{
9038 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9039 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9040
9041 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_DR_MASK)
9042 {
9043 int rc = hmR0VmxExportSharedDebugState(pVCpu, pVmxTransient);
9044 AssertRC(rc);
9045 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_GUEST_DR_MASK;
9046
9047 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
9048 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_RFLAGS)
9049 {
9050 rc = hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9051 AssertRC(rc);
9052 }
9053 }
9054
9055 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_GUEST_LAZY_MSRS)
9056 {
9057 hmR0VmxLazyLoadGuestMsrs(pVCpu);
9058 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_VMX_GUEST_LAZY_MSRS;
9059 }
9060
9061 AssertMsg(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE),
9062 ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
9063}
9064
9065
9066/**
9067 * Worker for loading the guest-state bits in the inner VT-x execution loop.
9068 *
9069 * @returns Strict VBox status code (i.e. informational status codes too).
9070 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9071 * without unrestricted guest execution and the VMMDev is not presently
9072 * mapped (e.g. EFI32).
9073 *
9074 * @param pVCpu The cross context virtual CPU structure.
9075 * @param pVmxTransient The VMX-transient structure.
9076 *
9077 * @remarks No-long-jump zone!!!
9078 */
9079static VBOXSTRICTRC hmR0VmxExportGuestStateOptimal(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
9080{
9081 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9082 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9083 Assert(VMMR0IsLogFlushDisabled(pVCpu));
9084
9085#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
9086 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
9087#endif
9088
9089 /*
9090 * For many exits it's only RIP that changes and hence try to export it first
9091 * without going through a lot of change flag checks.
9092 */
9093 VBOXSTRICTRC rcStrict;
9094 uint64_t fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9095 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
9096 if ((fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)) == HM_CHANGED_GUEST_RIP)
9097 {
9098 rcStrict = hmR0VmxExportGuestRip(pVCpu);
9099 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9100 { /* likely */}
9101 else
9102 AssertMsgFailedReturn(("Failed to export guest RIP! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)), rcStrict);
9103 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportMinimal);
9104 }
9105 else if (fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9106 {
9107 rcStrict = hmR0VmxExportGuestState(pVCpu, pVmxTransient);
9108 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9109 { /* likely */}
9110 else
9111 {
9112 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM, ("Failed to export guest state! rc=%Rrc\n",
9113 VBOXSTRICTRC_VAL(rcStrict)));
9114 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9115 return rcStrict;
9116 }
9117 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportFull);
9118 }
9119 else
9120 rcStrict = VINF_SUCCESS;
9121
9122#ifdef VBOX_STRICT
9123 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
9124 fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9125 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
9126 AssertMsg(!(fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)),
9127 ("fCtxChanged=%#RX64\n", fCtxChanged));
9128#endif
9129 return rcStrict;
9130}
9131
9132
9133/**
9134 * Tries to determine what part of the guest-state VT-x has deemed as invalid
9135 * and update error record fields accordingly.
9136 *
9137 * @returns VMX_IGS_* error codes.
9138 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
9139 * wrong with the guest state.
9140 *
9141 * @param pVCpu The cross context virtual CPU structure.
9142 * @param pVmcsInfo The VMCS info. object.
9143 *
9144 * @remarks This function assumes our cache of the VMCS controls
9145 * are valid, i.e. hmR0VmxCheckVmcsCtls() succeeded.
9146 */
9147static uint32_t hmR0VmxCheckGuestState(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
9148{
9149#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
9150#define HMVMX_CHECK_BREAK(expr, err) do { \
9151 if (!(expr)) { uError = (err); break; } \
9152 } while (0)
9153
9154 int rc;
9155 PVM pVM = pVCpu->CTX_SUFF(pVM);
9156 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9157 uint32_t uError = VMX_IGS_ERROR;
9158 uint32_t u32Val;
9159 bool const fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuest;
9160
9161 do
9162 {
9163 /*
9164 * CR0.
9165 */
9166 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9167 uint32_t fSetCr0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
9168 uint32_t const fZapCr0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
9169 /* Exceptions for unrestricted guest execution for fixed CR0 bits (PE, PG).
9170 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
9171 if (fUnrestrictedGuest)
9172 fSetCr0 &= ~(X86_CR0_PE | X86_CR0_PG);
9173
9174 uint32_t u32GuestCr0;
9175 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32GuestCr0);
9176 AssertRCBreak(rc);
9177 HMVMX_CHECK_BREAK((u32GuestCr0 & fSetCr0) == fSetCr0, VMX_IGS_CR0_FIXED1);
9178 HMVMX_CHECK_BREAK(!(u32GuestCr0 & ~fZapCr0), VMX_IGS_CR0_FIXED0);
9179 if ( !fUnrestrictedGuest
9180 && (u32GuestCr0 & X86_CR0_PG)
9181 && !(u32GuestCr0 & X86_CR0_PE))
9182 {
9183 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
9184 }
9185
9186 /*
9187 * CR4.
9188 */
9189 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9190 uint64_t const fSetCr4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
9191 uint64_t const fZapCr4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
9192
9193 uint32_t u32GuestCr4;
9194 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR4, &u32GuestCr4);
9195 AssertRCBreak(rc);
9196 HMVMX_CHECK_BREAK((u32GuestCr4 & fSetCr4) == fSetCr4, VMX_IGS_CR4_FIXED1);
9197 HMVMX_CHECK_BREAK(!(u32GuestCr4 & ~fZapCr4), VMX_IGS_CR4_FIXED0);
9198
9199 /*
9200 * IA32_DEBUGCTL MSR.
9201 */
9202 uint64_t u64Val;
9203 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
9204 AssertRCBreak(rc);
9205 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9206 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
9207 {
9208 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
9209 }
9210 uint64_t u64DebugCtlMsr = u64Val;
9211
9212#ifdef VBOX_STRICT
9213 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
9214 AssertRCBreak(rc);
9215 Assert(u32Val == pVmcsInfo->u32EntryCtls);
9216#endif
9217 bool const fLongModeGuest = RT_BOOL(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
9218
9219 /*
9220 * RIP and RFLAGS.
9221 */
9222 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
9223 AssertRCBreak(rc);
9224 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
9225 if ( !fLongModeGuest
9226 || !pCtx->cs.Attr.n.u1Long)
9227 {
9228 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
9229 }
9230 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
9231 * must be identical if the "IA-32e mode guest" VM-entry
9232 * control is 1 and CS.L is 1. No check applies if the
9233 * CPU supports 64 linear-address bits. */
9234
9235 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
9236 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
9237 AssertRCBreak(rc);
9238 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
9239 VMX_IGS_RFLAGS_RESERVED);
9240 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
9241 uint32_t const u32Eflags = u64Val;
9242
9243 if ( fLongModeGuest
9244 || ( fUnrestrictedGuest
9245 && !(u32GuestCr0 & X86_CR0_PE)))
9246 {
9247 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
9248 }
9249
9250 uint32_t u32EntryInfo;
9251 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
9252 AssertRCBreak(rc);
9253 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9254 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
9255
9256 /*
9257 * 64-bit checks.
9258 */
9259 if (fLongModeGuest)
9260 {
9261 HMVMX_CHECK_BREAK(u32GuestCr0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
9262 HMVMX_CHECK_BREAK(u32GuestCr4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
9263 }
9264
9265 if ( !fLongModeGuest
9266 && (u32GuestCr4 & X86_CR4_PCIDE))
9267 {
9268 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
9269 }
9270
9271 /** @todo CR3 field must be such that bits 63:52 and bits in the range
9272 * 51:32 beyond the processor's physical-address width are 0. */
9273
9274 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9275 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
9276 {
9277 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
9278 }
9279
9280 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
9281 AssertRCBreak(rc);
9282 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
9283
9284 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
9285 AssertRCBreak(rc);
9286 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
9287
9288 /*
9289 * PERF_GLOBAL MSR.
9290 */
9291 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR)
9292 {
9293 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
9294 AssertRCBreak(rc);
9295 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
9296 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
9297 }
9298
9299 /*
9300 * PAT MSR.
9301 */
9302 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
9303 {
9304 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
9305 AssertRCBreak(rc);
9306 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
9307 for (unsigned i = 0; i < 8; i++)
9308 {
9309 uint8_t u8Val = (u64Val & 0xff);
9310 if ( u8Val != 0 /* UC */
9311 && u8Val != 1 /* WC */
9312 && u8Val != 4 /* WT */
9313 && u8Val != 5 /* WP */
9314 && u8Val != 6 /* WB */
9315 && u8Val != 7 /* UC- */)
9316 {
9317 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
9318 }
9319 u64Val >>= 8;
9320 }
9321 }
9322
9323 /*
9324 * EFER MSR.
9325 */
9326 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
9327 {
9328 Assert(pVM->hm.s.vmx.fSupportsVmcsEfer);
9329 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
9330 AssertRCBreak(rc);
9331 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
9332 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
9333 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVmcsInfo->u32EntryCtls
9334 & VMX_ENTRY_CTLS_IA32E_MODE_GUEST),
9335 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
9336 /** @todo r=ramshankar: Unrestricted check here is probably wrong, see
9337 * iemVmxVmentryCheckGuestState(). */
9338 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9339 || !(u32GuestCr0 & X86_CR0_PG)
9340 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
9341 VMX_IGS_EFER_LMA_LME_MISMATCH);
9342 }
9343
9344 /*
9345 * Segment registers.
9346 */
9347 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9348 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
9349 if (!(u32Eflags & X86_EFL_VM))
9350 {
9351 /* CS */
9352 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
9353 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
9354 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
9355 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
9356 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9357 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
9358 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9359 /* CS cannot be loaded with NULL in protected mode. */
9360 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
9361 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
9362 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
9363 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
9364 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
9365 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
9366 else if (pVM->hm.s.vmx.fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
9367 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
9368 else
9369 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
9370
9371 /* SS */
9372 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9373 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
9374 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
9375 if ( !(pCtx->cr0 & X86_CR0_PE)
9376 || pCtx->cs.Attr.n.u4Type == 3)
9377 {
9378 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
9379 }
9380 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
9381 {
9382 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
9383 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
9384 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
9385 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
9386 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
9387 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9388 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
9389 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9390 }
9391
9392 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSReg(). */
9393 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
9394 {
9395 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
9396 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
9397 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9398 || pCtx->ds.Attr.n.u4Type > 11
9399 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9400 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
9401 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
9402 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
9403 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9404 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
9405 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9406 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9407 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
9408 }
9409 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
9410 {
9411 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
9412 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
9413 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9414 || pCtx->es.Attr.n.u4Type > 11
9415 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9416 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
9417 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
9418 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
9419 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9420 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
9421 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9422 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9423 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
9424 }
9425 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
9426 {
9427 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
9428 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
9429 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9430 || pCtx->fs.Attr.n.u4Type > 11
9431 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
9432 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
9433 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
9434 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
9435 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9436 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
9437 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9438 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9439 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
9440 }
9441 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
9442 {
9443 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
9444 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
9445 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9446 || pCtx->gs.Attr.n.u4Type > 11
9447 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
9448 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
9449 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
9450 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
9451 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9452 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
9453 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9454 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9455 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
9456 }
9457 /* 64-bit capable CPUs. */
9458 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9459 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9460 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9461 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9462 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9463 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9464 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9465 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9466 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9467 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9468 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9469 }
9470 else
9471 {
9472 /* V86 mode checks. */
9473 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
9474 if (pVmcsInfo->RealMode.fRealOnV86Active)
9475 {
9476 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
9477 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
9478 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
9479 }
9480 else
9481 {
9482 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
9483 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
9484 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
9485 }
9486
9487 /* CS */
9488 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
9489 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
9490 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
9491 /* SS */
9492 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
9493 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
9494 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
9495 /* DS */
9496 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
9497 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
9498 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
9499 /* ES */
9500 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
9501 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
9502 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
9503 /* FS */
9504 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
9505 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
9506 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
9507 /* GS */
9508 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
9509 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
9510 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
9511 /* 64-bit capable CPUs. */
9512 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9513 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9514 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9515 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9516 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9517 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9518 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9519 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9520 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9521 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9522 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9523 }
9524
9525 /*
9526 * TR.
9527 */
9528 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
9529 /* 64-bit capable CPUs. */
9530 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
9531 if (fLongModeGuest)
9532 {
9533 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
9534 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
9535 }
9536 else
9537 {
9538 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
9539 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
9540 VMX_IGS_TR_ATTR_TYPE_INVALID);
9541 }
9542 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
9543 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
9544 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
9545 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
9546 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
9547 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
9548 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
9549 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
9550
9551 /*
9552 * GDTR and IDTR (64-bit capable checks).
9553 */
9554 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
9555 AssertRCBreak(rc);
9556 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
9557
9558 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
9559 AssertRCBreak(rc);
9560 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
9561
9562 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
9563 AssertRCBreak(rc);
9564 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
9565
9566 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
9567 AssertRCBreak(rc);
9568 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
9569
9570 /*
9571 * Guest Non-Register State.
9572 */
9573 /* Activity State. */
9574 uint32_t u32ActivityState;
9575 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
9576 AssertRCBreak(rc);
9577 HMVMX_CHECK_BREAK( !u32ActivityState
9578 || (u32ActivityState & RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Misc, VMX_BF_MISC_ACTIVITY_STATES)),
9579 VMX_IGS_ACTIVITY_STATE_INVALID);
9580 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
9581 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
9582 uint32_t u32IntrState;
9583 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32IntrState);
9584 AssertRCBreak(rc);
9585 if ( u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS
9586 || u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9587 {
9588 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
9589 }
9590
9591 /** @todo Activity state and injecting interrupts. Left as a todo since we
9592 * currently don't use activity states but ACTIVE. */
9593
9594 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
9595 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
9596
9597 /* Guest interruptibility-state. */
9598 HMVMX_CHECK_BREAK(!(u32IntrState & 0xffffffe0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
9599 HMVMX_CHECK_BREAK((u32IntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
9600 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9601 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
9602 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
9603 || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
9604 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
9605 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9606 {
9607 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9608 && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9609 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
9610 }
9611 else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
9612 {
9613 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9614 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
9615 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
9616 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
9617 }
9618 /** @todo Assumes the processor is not in SMM. */
9619 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
9620 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
9621 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
9622 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
9623 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
9624 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
9625 && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
9626 {
9627 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI),
9628 VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
9629 }
9630
9631 /* Pending debug exceptions. */
9632 rc = VMXReadVmcs64(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &u64Val);
9633 AssertRCBreak(rc);
9634 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
9635 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
9636 u32Val = u64Val; /* For pending debug exceptions checks below. */
9637
9638 if ( (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9639 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
9640 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
9641 {
9642 if ( (u32Eflags & X86_EFL_TF)
9643 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
9644 {
9645 /* Bit 14 is PendingDebug.BS. */
9646 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
9647 }
9648 if ( !(u32Eflags & X86_EFL_TF)
9649 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
9650 {
9651 /* Bit 14 is PendingDebug.BS. */
9652 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
9653 }
9654 }
9655
9656 /* VMCS link pointer. */
9657 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
9658 AssertRCBreak(rc);
9659 if (u64Val != UINT64_C(0xffffffffffffffff))
9660 {
9661 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
9662 /** @todo Bits beyond the processor's physical-address width MBZ. */
9663 /** @todo SMM checks. */
9664 Assert(pVmcsInfo->HCPhysShadowVmcs == u64Val);
9665 Assert(pVmcsInfo->pvShadowVmcs);
9666 VMXVMCSREVID VmcsRevId;
9667 VmcsRevId.u = *(uint32_t *)pVmcsInfo->pvShadowVmcs;
9668 HMVMX_CHECK_BREAK(VmcsRevId.n.u31RevisionId == RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID),
9669 VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID);
9670 HMVMX_CHECK_BREAK(VmcsRevId.n.fIsShadowVmcs == (uint32_t)!!(pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING),
9671 VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW);
9672 }
9673
9674 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
9675 * not using nested paging? */
9676 if ( pVM->hm.s.fNestedPaging
9677 && !fLongModeGuest
9678 && CPUMIsGuestInPAEModeEx(pCtx))
9679 {
9680 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
9681 AssertRCBreak(rc);
9682 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9683
9684 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
9685 AssertRCBreak(rc);
9686 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9687
9688 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
9689 AssertRCBreak(rc);
9690 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9691
9692 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
9693 AssertRCBreak(rc);
9694 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9695 }
9696
9697 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
9698 if (uError == VMX_IGS_ERROR)
9699 uError = VMX_IGS_REASON_NOT_FOUND;
9700 } while (0);
9701
9702 pVCpu->hm.s.u32HMError = uError;
9703 return uError;
9704
9705#undef HMVMX_ERROR_BREAK
9706#undef HMVMX_CHECK_BREAK
9707}
9708
9709
9710/**
9711 * Map the APIC-access page for virtualizing APIC accesses.
9712 *
9713 * This can cause a longjumps to R3 due to the acquisition of the PGM lock. Hence,
9714 * this not done as part of exporting guest state, see @bugref{8721}.
9715 *
9716 * @returns VBox status code.
9717 * @param pVCpu The cross context virtual CPU structure.
9718 */
9719static int hmR0VmxMapHCApicAccessPage(PVMCPU pVCpu)
9720{
9721 PVM pVM = pVCpu->CTX_SUFF(pVM);
9722 uint64_t const u64MsrApicBase = APICGetBaseMsrNoCheck(pVCpu);
9723
9724 Assert(PDMHasApic(pVM));
9725 Assert(u64MsrApicBase);
9726
9727 RTGCPHYS const GCPhysApicBase = u64MsrApicBase & PAGE_BASE_GC_MASK;
9728 Log4Func(("Mappping HC APIC-access page at %#RGp\n", GCPhysApicBase));
9729
9730 /* Unalias the existing mapping. */
9731 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
9732 AssertRCReturn(rc, rc);
9733
9734 /* Map the HC APIC-access page in place of the MMIO page, also updates the shadow page tables if necessary. */
9735 Assert(pVM->hm.s.vmx.HCPhysApicAccess != NIL_RTHCPHYS);
9736 rc = IOMMMIOMapMMIOHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hm.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
9737 AssertRCReturn(rc, rc);
9738
9739 /* Update the per-VCPU cache of the APIC base MSR. */
9740 pVCpu->hm.s.vmx.u64GstMsrApicBase = u64MsrApicBase;
9741 return VINF_SUCCESS;
9742}
9743
9744
9745/**
9746 * Worker function passed to RTMpOnSpecific() that is to be called on the target
9747 * CPU.
9748 *
9749 * @param idCpu The ID for the CPU the function is called on.
9750 * @param pvUser1 Null, not used.
9751 * @param pvUser2 Null, not used.
9752 */
9753static DECLCALLBACK(void) hmR0DispatchHostNmi(RTCPUID idCpu, void *pvUser1, void *pvUser2)
9754{
9755 RT_NOREF3(idCpu, pvUser1, pvUser2);
9756 VMXDispatchHostNmi();
9757}
9758
9759
9760/**
9761 * Dispatching an NMI on the host CPU that received it.
9762 *
9763 * @returns VBox status code.
9764 * @param pVCpu The cross context virtual CPU structure.
9765 * @param pVmcsInfo The VMCS info. object corresponding to the VMCS that was
9766 * executing when receiving the host NMI in VMX non-root
9767 * operation.
9768 */
9769static int hmR0VmxExitHostNmi(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
9770{
9771 RTCPUID const idCpu = pVmcsInfo->idHostCpu;
9772
9773 /*
9774 * We don't want to delay dispatching the NMI any more than we have to. However,
9775 * we have already chosen -not- to dispatch NMIs when interrupts were still disabled
9776 * after executing guest or nested-guest code for the following reasons:
9777 *
9778 * - We would need to perform VMREADs with interrupts disabled and is orders of
9779 * magnitude worse when we run as a guest hypervisor without VMCS shadowing
9780 * supported by the host hypervisor.
9781 *
9782 * - It affects the common VM-exit scenario and keeps interrupts disabled for a
9783 * longer period of time just for handling an edge case like host NMIs which do
9784 * not occur nearly as frequently as other VM-exits.
9785 *
9786 * Let's cover the most likely scenario first. Check if we are on the target CPU
9787 * and dispatch the NMI right away. This should be much faster than calling into
9788 * RTMpOnSpecific() machinery.
9789 */
9790 bool fDispatched = false;
9791 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
9792 if (idCpu == RTMpCpuId())
9793 {
9794 VMXDispatchHostNmi();
9795 fDispatched = true;
9796 }
9797 ASMSetFlags(fEFlags);
9798 if (fDispatched)
9799 {
9800 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
9801 return VINF_SUCCESS;
9802 }
9803
9804 /*
9805 * RTMpOnSpecific() waits until the worker function has run on the target CPU. So
9806 * there should be no race or recursion even if we are unlucky enough to be preempted
9807 * (to the target CPU) without dispatching the host NMI above.
9808 */
9809 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGCIpi);
9810 return RTMpOnSpecific(idCpu, &hmR0DispatchHostNmi, NULL /* pvUser1 */, NULL /* pvUser2 */);
9811}
9812
9813
9814#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9815/**
9816 * Merges the guest with the nested-guest MSR bitmap in preparation of executing the
9817 * nested-guest using hardware-assisted VMX.
9818 *
9819 * @param pVCpu The cross context virtual CPU structure.
9820 * @param pVmcsInfoNstGst The nested-guest VMCS info. object.
9821 * @param pVmcsInfoGst The guest VMCS info. object.
9822 */
9823static void hmR0VmxMergeMsrBitmapNested(PCVMCPU pVCpu, PVMXVMCSINFO pVmcsInfoNstGst, PCVMXVMCSINFO pVmcsInfoGst)
9824{
9825 uint32_t const cbMsrBitmap = X86_PAGE_4K_SIZE;
9826 uint64_t *pu64MsrBitmap = (uint64_t *)pVmcsInfoNstGst->pvMsrBitmap;
9827 Assert(pu64MsrBitmap);
9828
9829 /*
9830 * We merge the guest MSR bitmap with the nested-guest MSR bitmap such that any
9831 * MSR that is intercepted by the guest is also intercepted while executing the
9832 * nested-guest using hardware-assisted VMX.
9833 *
9834 * Note! If the nested-guest is not using an MSR bitmap, ever MSR must cause a
9835 * nested-guest VM-exit even if the outer guest is not intercepting some
9836 * MSRs. We cannot assume the caller has initialized the nested-guest
9837 * MSR bitmap in this case.
9838 *
9839 * The guest hypervisor may also switch whether it uses MSR bitmaps for
9840 * each VM-entry, hence initializing it once per-VM while setting up the
9841 * nested-guest VMCS is not sufficient.
9842 */
9843 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
9844 if (pVmcsNstGst->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
9845 {
9846 uint64_t const *pu64MsrBitmapNstGst = (uint64_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
9847 uint64_t const *pu64MsrBitmapGst = (uint64_t const *)pVmcsInfoGst->pvMsrBitmap;
9848 Assert(pu64MsrBitmapNstGst);
9849 Assert(pu64MsrBitmapGst);
9850
9851 uint32_t const cFrags = cbMsrBitmap / sizeof(uint64_t);
9852 for (uint32_t i = 0; i < cFrags; i++)
9853 pu64MsrBitmap[i] = pu64MsrBitmapNstGst[i] | pu64MsrBitmapGst[i];
9854 }
9855 else
9856 ASMMemFill32(pu64MsrBitmap, cbMsrBitmap, UINT32_C(0xffffffff));
9857}
9858
9859
9860/**
9861 * Merges the guest VMCS in to the nested-guest VMCS controls in preparation of
9862 * hardware-assisted VMX execution of the nested-guest.
9863 *
9864 * For a guest, we don't modify these controls once we set up the VMCS and hence
9865 * this function is never called.
9866 *
9867 * For nested-guests since the guest hypervisor provides these controls on every
9868 * nested-guest VM-entry and could potentially change them everytime we need to
9869 * merge them before every nested-guest VM-entry.
9870 *
9871 * @returns VBox status code.
9872 * @param pVCpu The cross context virtual CPU structure.
9873 */
9874static int hmR0VmxMergeVmcsNested(PVMCPU pVCpu)
9875{
9876 PVM pVM = pVCpu->CTX_SUFF(pVM);
9877 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hm.s.vmx.VmcsInfo;
9878 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
9879 Assert(pVmcsNstGst);
9880
9881 /*
9882 * Merge the controls with the requirements of the guest VMCS.
9883 *
9884 * We do not need to validate the nested-guest VMX features specified in the nested-guest
9885 * VMCS with the features supported by the physical CPU as it's already done by the
9886 * VMLAUNCH/VMRESUME instruction emulation.
9887 *
9888 * This is because the VMX features exposed by CPUM (through CPUID/MSRs) to the guest are
9889 * derived from the VMX features supported by the physical CPU.
9890 */
9891
9892 /* Pin-based VM-execution controls. */
9893 uint32_t const u32PinCtls = pVmcsNstGst->u32PinCtls | pVmcsInfoGst->u32PinCtls;
9894
9895 /* Processor-based VM-execution controls. */
9896 uint32_t u32ProcCtls = (pVmcsNstGst->u32ProcCtls & ~VMX_PROC_CTLS_USE_IO_BITMAPS)
9897 | (pVmcsInfoGst->u32ProcCtls & ~( VMX_PROC_CTLS_INT_WINDOW_EXIT
9898 | VMX_PROC_CTLS_NMI_WINDOW_EXIT
9899 | VMX_PROC_CTLS_USE_TPR_SHADOW
9900 | VMX_PROC_CTLS_MONITOR_TRAP_FLAG));
9901
9902 /* Secondary processor-based VM-execution controls. */
9903 uint32_t const u32ProcCtls2 = (pVmcsNstGst->u32ProcCtls2 & ~VMX_PROC_CTLS2_VPID)
9904 | (pVmcsInfoGst->u32ProcCtls2 & ~( VMX_PROC_CTLS2_VIRT_APIC_ACCESS
9905 | VMX_PROC_CTLS2_INVPCID
9906 | VMX_PROC_CTLS2_VMCS_SHADOWING
9907 | VMX_PROC_CTLS2_RDTSCP
9908 | VMX_PROC_CTLS2_XSAVES_XRSTORS
9909 | VMX_PROC_CTLS2_APIC_REG_VIRT
9910 | VMX_PROC_CTLS2_VIRT_INT_DELIVERY
9911 | VMX_PROC_CTLS2_VMFUNC));
9912
9913 /*
9914 * VM-entry controls:
9915 * These controls contains state that depends on the nested-guest state (primarily
9916 * EFER MSR) and is thus not constant between VMLAUNCH/VMRESUME and the nested-guest
9917 * VM-exit. Although the guest hypervisor cannot change it, we need to in order to
9918 * properly continue executing the nested-guest if the EFER MSR changes but does not
9919 * cause a nested-guest VM-exits.
9920 *
9921 * VM-exit controls:
9922 * These controls specify the host state on return. We cannot use the controls from
9923 * the guest hypervisor state as is as it would contain the guest state rather than
9924 * the host state. Since the host state is subject to change (e.g. preemption, trips
9925 * to ring-3, longjmp and rescheduling to a different host CPU) they are not constant
9926 * through VMLAUNCH/VMRESUME and the nested-guest VM-exit.
9927 *
9928 * VM-entry MSR-load:
9929 * The guest MSRs from the VM-entry MSR-load area are already loaded into the guest-CPU
9930 * context by the VMLAUNCH/VMRESUME instruction emulation.
9931 *
9932 * VM-exit MSR-store:
9933 * The VM-exit emulation will take care of populating the MSRs from the guest-CPU context
9934 * back into the VM-exit MSR-store area.
9935 *
9936 * VM-exit MSR-load areas:
9937 * This must contain the real host MSRs with hardware-assisted VMX execution. Hence, we
9938 * can entirely ignore what the guest hypervisor wants to load here.
9939 */
9940
9941 /*
9942 * Exception bitmap.
9943 *
9944 * We could remove #UD from the guest bitmap and merge it with the nested-guest bitmap
9945 * here (and avoid doing anything while exporting nested-guest state), but to keep the
9946 * code more flexible if intercepting exceptions become more dynamic in the future we do
9947 * it as part of exporting the nested-guest state.
9948 */
9949 uint32_t const u32XcptBitmap = pVmcsNstGst->u32XcptBitmap | pVmcsInfoGst->u32XcptBitmap;
9950
9951 /*
9952 * CR0/CR4 guest/host mask.
9953 *
9954 * Modifications by the nested-guest to CR0/CR4 bits owned by the host and the guest must
9955 * cause VM-exits, so we need to merge them here.
9956 */
9957 uint64_t const u64Cr0Mask = pVmcsNstGst->u64Cr0Mask.u | pVmcsInfoGst->u64Cr0Mask;
9958 uint64_t const u64Cr4Mask = pVmcsNstGst->u64Cr4Mask.u | pVmcsInfoGst->u64Cr4Mask;
9959
9960 /*
9961 * Page-fault error-code mask and match.
9962 *
9963 * Although we require unrestricted guest execution (and thereby nested-paging) for
9964 * hardware-assisted VMX execution of nested-guests and thus the outer guest doesn't
9965 * normally intercept #PFs, it might intercept them for debugging purposes.
9966 *
9967 * If the outer guest is not intercepting #PFs, we can use the nested-guest #PF filters.
9968 * If the outer guest is intercepting #PFs, we must intercept all #PFs.
9969 */
9970 uint32_t u32XcptPFMask;
9971 uint32_t u32XcptPFMatch;
9972 if (!(pVmcsInfoGst->u32XcptBitmap & RT_BIT(X86_XCPT_PF)))
9973 {
9974 u32XcptPFMask = pVmcsNstGst->u32XcptPFMask;
9975 u32XcptPFMatch = pVmcsNstGst->u32XcptPFMatch;
9976 }
9977 else
9978 {
9979 u32XcptPFMask = 0;
9980 u32XcptPFMatch = 0;
9981 }
9982
9983 /*
9984 * Pause-Loop exiting.
9985 */
9986 uint32_t const cPleGapTicks = RT_MIN(pVM->hm.s.vmx.cPleGapTicks, pVmcsNstGst->u32PleGap);
9987 uint32_t const cPleWindowTicks = RT_MIN(pVM->hm.s.vmx.cPleWindowTicks, pVmcsNstGst->u32PleWindow);
9988
9989 /*
9990 * I/O Bitmap.
9991 *
9992 * We do not use the I/O bitmap that may be provided by the guest hypervisor as we always
9993 * intercept all I/O port accesses.
9994 */
9995 Assert(u32ProcCtls & VMX_PROC_CTLS_UNCOND_IO_EXIT);
9996
9997 /*
9998 * VMCS shadowing.
9999 *
10000 * We do not yet expose VMCS shadowing to the guest and thus VMCS shadowing should not be
10001 * enabled while executing the nested-guest.
10002 */
10003 Assert(!(u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING));
10004
10005 /*
10006 * APIC-access page.
10007 */
10008 RTHCPHYS HCPhysApicAccess;
10009 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10010 {
10011 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
10012 RTGCPHYS const GCPhysApicAccess = pVmcsNstGst->u64AddrApicAccess.u;
10013
10014 /** @todo NSTVMX: This is not really correct but currently is required to make
10015 * things work. We need to re-enable the page handler when we fallback to
10016 * IEM execution of the nested-guest! */
10017 PGMHandlerPhysicalPageTempOff(pVM, GCPhysApicAccess, GCPhysApicAccess);
10018
10019 void *pvPage;
10020 PGMPAGEMAPLOCK PgLockApicAccess;
10021 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysApicAccess, &pvPage, &PgLockApicAccess);
10022 if (RT_SUCCESS(rc))
10023 {
10024 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysApicAccess, &HCPhysApicAccess);
10025 AssertMsgRCReturn(rc, ("Failed to get host-physical address for APIC-access page at %#RGp\n", GCPhysApicAccess), rc);
10026
10027 /** @todo Handle proper releasing of page-mapping lock later. */
10028 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockApicAccess);
10029 }
10030 else
10031 return rc;
10032 }
10033 else
10034 HCPhysApicAccess = 0;
10035
10036 /*
10037 * Virtual-APIC page and TPR threshold.
10038 */
10039 PVMXVMCSINFO pVmcsInfoNstGst = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
10040 RTHCPHYS HCPhysVirtApic;
10041 uint32_t u32TprThreshold;
10042 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10043 {
10044 Assert(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW);
10045 RTGCPHYS const GCPhysVirtApic = pVmcsNstGst->u64AddrVirtApic.u;
10046
10047 void *pvPage;
10048 PGMPAGEMAPLOCK PgLockVirtApic;
10049 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysVirtApic, &pvPage, &PgLockVirtApic);
10050 if (RT_SUCCESS(rc))
10051 {
10052 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysVirtApic, &HCPhysVirtApic);
10053 AssertMsgRCReturn(rc, ("Failed to get host-physical address for virtual-APIC page at %#RGp\n", GCPhysVirtApic), rc);
10054
10055 /** @todo Handle proper releasing of page-mapping lock later. */
10056 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockVirtApic);
10057 }
10058 else
10059 return rc;
10060
10061 u32TprThreshold = pVmcsNstGst->u32TprThreshold;
10062 }
10063 else
10064 {
10065 HCPhysVirtApic = 0;
10066 u32TprThreshold = 0;
10067
10068 /*
10069 * We must make sure CR8 reads/write must cause VM-exits when TPR shadowing is not
10070 * used by the guest hypervisor. Preventing MMIO accesses to the physical APIC will
10071 * be taken care of by EPT/shadow paging.
10072 */
10073 if (pVM->hm.s.fAllow64BitGuests)
10074 {
10075 u32ProcCtls |= VMX_PROC_CTLS_CR8_STORE_EXIT
10076 | VMX_PROC_CTLS_CR8_LOAD_EXIT;
10077 }
10078 }
10079
10080 /*
10081 * Validate basic assumptions.
10082 */
10083 Assert(pVM->hm.s.vmx.fAllowUnrestricted);
10084 Assert(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
10085 Assert(hmGetVmxActiveVmcsInfo(pVCpu) == pVmcsInfoNstGst);
10086
10087 /*
10088 * Commit it to the nested-guest VMCS.
10089 */
10090 int rc = VINF_SUCCESS;
10091 if (pVmcsInfoNstGst->u32PinCtls != u32PinCtls)
10092 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, u32PinCtls);
10093 if (pVmcsInfoNstGst->u32ProcCtls != u32ProcCtls)
10094 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, u32ProcCtls);
10095 if (pVmcsInfoNstGst->u32ProcCtls2 != u32ProcCtls2)
10096 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, u32ProcCtls2);
10097 if (pVmcsInfoNstGst->u32XcptBitmap != u32XcptBitmap)
10098 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
10099 if (pVmcsInfoNstGst->u64Cr0Mask != u64Cr0Mask)
10100 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask);
10101 if (pVmcsInfoNstGst->u64Cr4Mask != u64Cr4Mask)
10102 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask);
10103 if (pVmcsInfoNstGst->u32XcptPFMask != u32XcptPFMask)
10104 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, u32XcptPFMask);
10105 if (pVmcsInfoNstGst->u32XcptPFMatch != u32XcptPFMatch)
10106 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, u32XcptPFMatch);
10107 if ( !(u32ProcCtls & VMX_PROC_CTLS_PAUSE_EXIT)
10108 && (u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
10109 {
10110 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT);
10111 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, cPleGapTicks);
10112 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, cPleWindowTicks);
10113 }
10114 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10115 {
10116 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
10117 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
10118 }
10119 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10120 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
10121 AssertRC(rc);
10122
10123 /*
10124 * Update the nested-guest VMCS cache.
10125 */
10126 pVmcsInfoNstGst->u32PinCtls = u32PinCtls;
10127 pVmcsInfoNstGst->u32ProcCtls = u32ProcCtls;
10128 pVmcsInfoNstGst->u32ProcCtls2 = u32ProcCtls2;
10129 pVmcsInfoNstGst->u32XcptBitmap = u32XcptBitmap;
10130 pVmcsInfoNstGst->u64Cr0Mask = u64Cr0Mask;
10131 pVmcsInfoNstGst->u64Cr4Mask = u64Cr4Mask;
10132 pVmcsInfoNstGst->u32XcptPFMask = u32XcptPFMask;
10133 pVmcsInfoNstGst->u32XcptPFMatch = u32XcptPFMatch;
10134 pVmcsInfoNstGst->HCPhysVirtApic = HCPhysVirtApic;
10135
10136 /*
10137 * We need to flush the TLB if we are switching the APIC-access page address.
10138 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
10139 */
10140 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10141 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = true;
10142
10143 /*
10144 * MSR bitmap.
10145 *
10146 * The MSR bitmap address has already been initialized while setting up the nested-guest
10147 * VMCS, here we need to merge the MSR bitmaps.
10148 */
10149 if (u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10150 hmR0VmxMergeMsrBitmapNested(pVCpu, pVmcsInfoNstGst, pVmcsInfoGst);
10151
10152 return VINF_SUCCESS;
10153}
10154#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10155
10156
10157/**
10158 * Does the preparations before executing guest code in VT-x.
10159 *
10160 * This may cause longjmps to ring-3 and may even result in rescheduling to the
10161 * recompiler/IEM. We must be cautious what we do here regarding committing
10162 * guest-state information into the VMCS assuming we assuredly execute the
10163 * guest in VT-x mode.
10164 *
10165 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
10166 * the common-state (TRPM/forceflags), we must undo those changes so that the
10167 * recompiler/IEM can (and should) use them when it resumes guest execution.
10168 * Otherwise such operations must be done when we can no longer exit to ring-3.
10169 *
10170 * @returns Strict VBox status code (i.e. informational status codes too).
10171 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
10172 * have been disabled.
10173 * @retval VINF_VMX_VMEXIT if a nested-guest VM-exit occurs (e.g., while evaluating
10174 * pending events).
10175 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
10176 * double-fault into the guest.
10177 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
10178 * dispatched directly.
10179 * @retval VINF_* scheduling changes, we have to go back to ring-3.
10180 *
10181 * @param pVCpu The cross context virtual CPU structure.
10182 * @param pVmxTransient The VMX-transient structure.
10183 * @param fStepping Whether we are single-stepping the guest in the
10184 * hypervisor debugger. Makes us ignore some of the reasons
10185 * for returning to ring-3, and return VINF_EM_DBG_STEPPED
10186 * if event dispatching took place.
10187 */
10188static VBOXSTRICTRC hmR0VmxPreRunGuest(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, bool fStepping)
10189{
10190 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10191
10192#ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
10193 if (pVmxTransient->fIsNestedGuest)
10194 {
10195 RT_NOREF2(pVCpu, fStepping);
10196 Log2Func(("Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
10197 return VINF_EM_RESCHEDULE_REM;
10198 }
10199#endif
10200
10201#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
10202 PGMRZDynMapFlushAutoSet(pVCpu);
10203#endif
10204
10205 /*
10206 * Check and process force flag actions, some of which might require us to go back to ring-3.
10207 */
10208 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVCpu, fStepping);
10209 if (rcStrict == VINF_SUCCESS)
10210 {
10211 /* FFs don't get set all the time. */
10212#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10213 if ( pVmxTransient->fIsNestedGuest
10214 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10215 {
10216 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10217 return VINF_VMX_VMEXIT;
10218 }
10219#endif
10220 }
10221 else
10222 return rcStrict;
10223
10224 /*
10225 * Virtualize memory-mapped accesses to the physical APIC (may take locks).
10226 */
10227 /** @todo Doing this from ring-3 after VM setup phase causes a
10228 * VERR_IOM_MMIO_RANGE_NOT_FOUND guru while booting Visa 64 SMP VM. No
10229 * idea why atm. */
10230 PVM pVM = pVCpu->CTX_SUFF(pVM);
10231 if ( !pVCpu->hm.s.vmx.u64GstMsrApicBase
10232 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10233 && PDMHasApic(pVM))
10234 {
10235 int rc = hmR0VmxMapHCApicAccessPage(pVCpu);
10236 AssertRCReturn(rc, rc);
10237 }
10238
10239#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10240 /*
10241 * Merge guest VMCS controls with the nested-guest VMCS controls.
10242 *
10243 * Even if we have not executed the guest prior to this (e.g. when resuming from a
10244 * saved state), we should be okay with merging controls as we initialize the
10245 * guest VMCS controls as part of VM setup phase.
10246 */
10247 if ( pVmxTransient->fIsNestedGuest
10248 && !pVCpu->hm.s.vmx.fMergedNstGstCtls)
10249 {
10250 int rc = hmR0VmxMergeVmcsNested(pVCpu);
10251 AssertRCReturn(rc, rc);
10252 pVCpu->hm.s.vmx.fMergedNstGstCtls = true;
10253 }
10254#endif
10255
10256 /*
10257 * Evaluate events to be injected into the guest.
10258 *
10259 * Events in TRPM can be injected without inspecting the guest state.
10260 * If any new events (interrupts/NMI) are pending currently, we try to set up the
10261 * guest to cause a VM-exit the next time they are ready to receive the event.
10262 *
10263 * With nested-guests, evaluating pending events may cause VM-exits.
10264 */
10265 if (TRPMHasTrap(pVCpu))
10266 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
10267
10268 uint32_t fIntrState;
10269 rcStrict = hmR0VmxEvaluatePendingEvent(pVCpu, pVmxTransient, &fIntrState);
10270
10271#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10272 /*
10273 * While evaluating pending events if something failed (unlikely) or if we were
10274 * preparing to run a nested-guest but performed a nested-guest VM-exit, we should bail.
10275 */
10276 if (rcStrict != VINF_SUCCESS)
10277 return rcStrict;
10278 if ( pVmxTransient->fIsNestedGuest
10279 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10280 {
10281 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10282 return VINF_VMX_VMEXIT;
10283 }
10284#else
10285 Assert(rcStrict == VINF_SUCCESS);
10286#endif
10287
10288 /*
10289 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus
10290 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might
10291 * also result in triple-faulting the VM.
10292 *
10293 * With nested-guests, the above does not apply since unrestricted guest execution is a
10294 * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
10295 */
10296 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pVmxTransient, fIntrState, fStepping);
10297 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10298 { /* likely */ }
10299 else
10300 {
10301 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
10302 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
10303 return rcStrict;
10304 }
10305
10306 /*
10307 * A longjump might result in importing CR3 even for VM-exits that don't necessarily
10308 * import CR3 themselves. We will need to update them here, as even as late as the above
10309 * hmR0VmxInjectPendingEvent() call may lazily import guest-CPU state on demand causing
10310 * the below force flags to be set.
10311 */
10312 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
10313 {
10314 Assert(!(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_CR3));
10315 int rc2 = PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
10316 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
10317 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
10318 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10319 }
10320 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
10321 {
10322 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
10323 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10324 }
10325
10326#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10327 /* Paranoia. */
10328 Assert(!pVmxTransient->fIsNestedGuest || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10329#endif
10330
10331 /*
10332 * No longjmps to ring-3 from this point on!!!
10333 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
10334 * This also disables flushing of the R0-logger instance (if any).
10335 */
10336 VMMRZCallRing3Disable(pVCpu);
10337
10338 /*
10339 * Export the guest state bits.
10340 *
10341 * We cannot perform longjmps while loading the guest state because we do not preserve the
10342 * host/guest state (although the VMCS will be preserved) across longjmps which can cause
10343 * CPU migration.
10344 *
10345 * If we are injecting events to a real-on-v86 mode guest, we would have updated RIP and some segment
10346 * registers. Hence, exporting of the guest state needs to be done -after- injection of events.
10347 */
10348 rcStrict = hmR0VmxExportGuestStateOptimal(pVCpu, pVmxTransient);
10349 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10350 { /* likely */ }
10351 else
10352 {
10353 VMMRZCallRing3Enable(pVCpu);
10354 return rcStrict;
10355 }
10356
10357 /*
10358 * We disable interrupts so that we don't miss any interrupts that would flag preemption
10359 * (IPI/timers etc.) when thread-context hooks aren't used and we've been running with
10360 * preemption disabled for a while. Since this is purely to aid the
10361 * RTThreadPreemptIsPending() code, it doesn't matter that it may temporarily reenable and
10362 * disable interrupt on NT.
10363 *
10364 * We need to check for force-flags that could've possible been altered since we last
10365 * checked them (e.g. by PDMGetInterrupt() leaving the PDM critical section,
10366 * see @bugref{6398}).
10367 *
10368 * We also check a couple of other force-flags as a last opportunity to get the EMT back
10369 * to ring-3 before executing guest code.
10370 */
10371 pVmxTransient->fEFlags = ASMIntDisableFlags();
10372
10373 if ( ( !VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
10374 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
10375 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
10376 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
10377 {
10378 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
10379 {
10380#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10381 /*
10382 * If we are executing a nested-guest make sure that we should intercept subsequent
10383 * events. The one we are injecting might be part of VM-entry. This is mainly to keep
10384 * the VM-exit instruction emulation happy.
10385 */
10386 if (pVmxTransient->fIsNestedGuest)
10387 pVCpu->cpum.GstCtx.hwvirt.vmx.fInterceptEvents = true;
10388#endif
10389
10390 /*
10391 * We've injected any pending events. This is really the point of no return (to ring-3).
10392 *
10393 * Note! The caller expects to continue with interrupts & longjmps disabled on successful
10394 * returns from this function, so do -not- enable them here.
10395 */
10396 pVCpu->hm.s.Event.fPending = false;
10397 return VINF_SUCCESS;
10398 }
10399
10400 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPendingHostIrq);
10401 rcStrict = VINF_EM_RAW_INTERRUPT;
10402 }
10403 else
10404 {
10405 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
10406 rcStrict = VINF_EM_RAW_TO_R3;
10407 }
10408
10409 ASMSetFlags(pVmxTransient->fEFlags);
10410 VMMRZCallRing3Enable(pVCpu);
10411
10412 return rcStrict;
10413}
10414
10415
10416/**
10417 * Final preparations before executing guest code using hardware-assisted VMX.
10418 *
10419 * We can no longer get preempted to a different host CPU and there are no returns
10420 * to ring-3. We ignore any errors that may happen from this point (e.g. VMWRITE
10421 * failures), this function is not intended to fail sans unrecoverable hardware
10422 * errors.
10423 *
10424 * @param pVCpu The cross context virtual CPU structure.
10425 * @param pVmxTransient The VMX-transient structure.
10426 *
10427 * @remarks Called with preemption disabled.
10428 * @remarks No-long-jump zone!!!
10429 */
10430static void hmR0VmxPreRunGuestCommitted(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
10431{
10432 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10433 Assert(VMMR0IsLogFlushDisabled(pVCpu));
10434 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
10435 Assert(!pVCpu->hm.s.Event.fPending);
10436
10437 /*
10438 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
10439 */
10440 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10441 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
10442
10443 PVM pVM = pVCpu->CTX_SUFF(pVM);
10444 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10445 PHMPHYSCPU pHostCpu = hmR0GetCurrentCpu();
10446 RTCPUID const idCurrentCpu = pHostCpu->idCpu;
10447
10448 if (!CPUMIsGuestFPUStateActive(pVCpu))
10449 {
10450 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10451 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
10452 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_HOST_CONTEXT;
10453 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10454 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadGuestFpu);
10455 }
10456
10457 /*
10458 * Re-export the host state bits as we may've been preempted (only happens when
10459 * thread-context hooks are used or when the VM start function changes) or if
10460 * the host CR0 is modified while loading the guest FPU state above.
10461 *
10462 * The 64-on-32 switcher saves the (64-bit) host state into the VMCS and if we
10463 * changed the switcher back to 32-bit, we *must* save the 32-bit host state here,
10464 * see @bugref{8432}.
10465 *
10466 * This may also happen when switching to/from a nested-guest VMCS without leaving
10467 * ring-0.
10468 */
10469 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
10470 {
10471 hmR0VmxExportHostState(pVCpu);
10472 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportHostState);
10473 }
10474 Assert(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT));
10475
10476 /*
10477 * Export the state shared between host and guest (FPU, debug, lazy MSRs).
10478 */
10479 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)
10480 hmR0VmxExportSharedState(pVCpu, pVmxTransient);
10481 AssertMsg(!pVCpu->hm.s.fCtxChanged, ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
10482
10483 /*
10484 * Store status of the shared guest/host debug state at the time of VM-entry.
10485 */
10486 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
10487 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
10488
10489 /*
10490 * Always cache the TPR-shadow if the virtual-APIC page exists, thereby skipping
10491 * more than one conditional check. The post-run side of our code shall determine
10492 * if it needs to sync. the virtual APIC TPR with the TPR-shadow.
10493 */
10494 if (pVmcsInfo->pbVirtApic)
10495 pVmxTransient->u8GuestTpr = pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR];
10496
10497 /*
10498 * Update the host MSRs values in the VM-exit MSR-load area.
10499 */
10500 if (!pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs)
10501 {
10502 if (pVmcsInfo->cExitMsrLoad > 0)
10503 hmR0VmxUpdateAutoLoadHostMsrs(pVCpu, pVmcsInfo);
10504 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = true;
10505 }
10506
10507 /*
10508 * Evaluate if we need to intercept guest RDTSC/P accesses. Set up the
10509 * VMX-preemption timer based on the next virtual sync clock deadline.
10510 */
10511 if ( !pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer
10512 || idCurrentCpu != pVCpu->hm.s.idLastCpu)
10513 {
10514 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVCpu, pVmxTransient);
10515 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = true;
10516 }
10517
10518 /* Record statistics of how often we use TSC offsetting as opposed to intercepting RDTSC/P. */
10519 bool const fIsRdtscIntercepted = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT);
10520 if (!fIsRdtscIntercepted)
10521 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
10522 else
10523 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
10524
10525 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
10526 hmR0VmxFlushTaggedTlb(pHostCpu, pVCpu, pVmcsInfo); /* Invalidate the appropriate guest entries from the TLB. */
10527 Assert(idCurrentCpu == pVCpu->hm.s.idLastCpu);
10528 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Update the error reporting info. with the current host CPU. */
10529 pVmcsInfo->idHostCpu = idCurrentCpu; /* Update the CPU for which we updated host-state in this VMCS. */
10530
10531 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
10532
10533 TMNotifyStartOfExecution(pVCpu); /* Notify TM to resume its clocks when TSC is tied to execution,
10534 as we're about to start executing the guest . */
10535
10536 /*
10537 * Load the guest TSC_AUX MSR when we are not intercepting RDTSCP.
10538 *
10539 * This is done this late as updating the TSC offsetting/preemption timer above
10540 * figures out if we can skip intercepting RDTSCP by calculating the number of
10541 * host CPU ticks till the next virtual sync deadline (for the dynamic case).
10542 */
10543 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_RDTSCP)
10544 && !fIsRdtscIntercepted)
10545 {
10546 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_TSC_AUX);
10547
10548 /* NB: Because we call hmR0VmxAddAutoLoadStoreMsr with fUpdateHostMsr=true,
10549 it's safe even after hmR0VmxUpdateAutoLoadHostMsrs has already been done. */
10550 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX, CPUMGetGuestTscAux(pVCpu),
10551 true /* fSetReadWrite */, true /* fUpdateHostMsr */);
10552 AssertRC(rc);
10553 Assert(!pVmxTransient->fRemoveTscAuxMsr);
10554 pVmxTransient->fRemoveTscAuxMsr = true;
10555 }
10556
10557#ifdef VBOX_STRICT
10558 Assert(pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs);
10559 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
10560 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo);
10561 AssertRC(hmR0VmxCheckVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest));
10562#endif
10563
10564#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
10565 /** @todo r=ramshankar: We can now probably use iemVmxVmentryCheckGuestState here.
10566 * Add a PVMXMSRS parameter to it, so that IEM can look at the host MSRs,
10567 * see @bugref{9180#c54}. */
10568 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
10569 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
10570 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
10571#endif
10572}
10573
10574
10575/**
10576 * First C routine invoked after running guest code using hardware-assisted VMX.
10577 *
10578 * @param pVCpu The cross context virtual CPU structure.
10579 * @param pVmxTransient The VMX-transient structure.
10580 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
10581 *
10582 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
10583 *
10584 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
10585 * unconditionally when it is safe to do so.
10586 */
10587static void hmR0VmxPostRunGuest(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, int rcVMRun)
10588{
10589 uint64_t const uHostTsc = ASMReadTSC(); /** @todo We can do a lot better here, see @bugref{9180#c38}. */
10590
10591 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
10592 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
10593 pVCpu->hm.s.fCtxChanged = 0; /* Exits/longjmps to ring-3 requires saving the guest state. */
10594 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
10595 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
10596 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
10597
10598 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10599 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
10600 {
10601 uint64_t uGstTsc;
10602 if (!pVmxTransient->fIsNestedGuest)
10603 uGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
10604 else
10605 {
10606 uint64_t const uNstGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
10607 uGstTsc = CPUMRemoveNestedGuestTscOffset(pVCpu, uNstGstTsc);
10608 }
10609 TMCpuTickSetLastSeen(pVCpu, uGstTsc); /* Update TM with the guest TSC. */
10610 }
10611
10612 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatPreExit, x);
10613 TMNotifyEndOfExecution(pVCpu); /* Notify TM that the guest is no longer running. */
10614 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10615
10616 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Some host state messed up by VMX needs restoring. */
10617 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
10618#ifdef VBOX_STRICT
10619 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo); /* Verify that the host EFER MSR wasn't modified. */
10620#endif
10621 Assert(!ASMIntAreEnabled());
10622 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
10623 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10624
10625#ifdef HMVMX_ALWAYS_CLEAN_TRANSIENT
10626 /*
10627 * Clean all the VMCS fields in the transient structure before reading
10628 * anything from the VMCS.
10629 */
10630 pVmxTransient->uExitReason = 0;
10631 pVmxTransient->uExitIntErrorCode = 0;
10632 pVmxTransient->uExitQual = 0;
10633 pVmxTransient->uGuestLinearAddr = 0;
10634 pVmxTransient->uExitIntInfo = 0;
10635 pVmxTransient->cbInstr = 0;
10636 pVmxTransient->ExitInstrInfo.u = 0;
10637 pVmxTransient->uEntryIntInfo = 0;
10638 pVmxTransient->uEntryXcptErrorCode = 0;
10639 pVmxTransient->cbEntryInstr = 0;
10640 pVmxTransient->uIdtVectoringInfo = 0;
10641 pVmxTransient->uIdtVectoringErrorCode = 0;
10642#endif
10643
10644 /*
10645 * Save the basic VM-exit reason and check if the VM-entry failed.
10646 * See Intel spec. 24.9.1 "Basic VM-exit Information".
10647 */
10648 uint32_t uExitReason;
10649 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
10650 AssertRC(rc);
10651 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason);
10652 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
10653
10654 /*
10655 * Log the VM-exit before logging anything else as otherwise it might be a
10656 * tad confusing what happens before and after the world-switch.
10657 */
10658 HMVMX_LOG_EXIT(pVCpu, uExitReason);
10659
10660 /*
10661 * Remove the TSC_AUX MSR from the auto-load/store MSR area and reset any MSR
10662 * bitmap permissions, if it was added before VM-entry.
10663 */
10664 if (pVmxTransient->fRemoveTscAuxMsr)
10665 {
10666 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX);
10667 pVmxTransient->fRemoveTscAuxMsr = false;
10668 }
10669
10670 /*
10671 * Check if VMLAUNCH/VMRESUME succeeded.
10672 * If this failed, we cause a guru meditation and cease further execution.
10673 *
10674 * However, if we are executing a nested-guest we might fail if we use the
10675 * fast path rather than fully emulating VMLAUNCH/VMRESUME instruction in IEM.
10676 */
10677 if (RT_LIKELY(rcVMRun == VINF_SUCCESS))
10678 {
10679 /*
10680 * Update the VM-exit history array here even if the VM-entry failed due to:
10681 * - Invalid guest state.
10682 * - MSR loading.
10683 * - Machine-check event.
10684 *
10685 * In any of the above cases we will still have a "valid" VM-exit reason
10686 * despite @a fVMEntryFailed being false.
10687 *
10688 * See Intel spec. 26.7 "VM-Entry failures during or after loading guest state".
10689 *
10690 * Note! We don't have CS or RIP at this point. Will probably address that later
10691 * by amending the history entry added here.
10692 */
10693 EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_VMX, pVmxTransient->uExitReason & EMEXIT_F_TYPE_MASK),
10694 UINT64_MAX, uHostTsc);
10695
10696 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
10697 {
10698 VMMRZCallRing3Enable(pVCpu);
10699
10700 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10701 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10702
10703#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
10704 hmR0VmxReadAllRoFieldsVmcs(pVmxTransient);
10705#endif
10706#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
10707 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
10708 AssertRC(rc);
10709#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
10710 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_RFLAGS);
10711 AssertRC(rc);
10712#else
10713 /*
10714 * Import the guest-interruptibility state always as we need it while evaluating
10715 * injecting events on re-entry.
10716 *
10717 * We don't import CR0 (when unrestricted guest execution is unavailable) despite
10718 * checking for real-mode while exporting the state because all bits that cause
10719 * mode changes wrt CR0 are intercepted.
10720 */
10721 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_HM_VMX_INT_STATE);
10722 AssertRC(rc);
10723#endif
10724
10725 /*
10726 * Sync the TPR shadow with our APIC state.
10727 */
10728 if ( !pVmxTransient->fIsNestedGuest
10729 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
10730 {
10731 Assert(pVmcsInfo->pbVirtApic);
10732 if (pVmxTransient->u8GuestTpr != pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR])
10733 {
10734 rc = APICSetTpr(pVCpu, pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR]);
10735 AssertRC(rc);
10736 ASMAtomicOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
10737 }
10738 }
10739
10740 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10741 return;
10742 }
10743 }
10744#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10745 else if (pVmxTransient->fIsNestedGuest)
10746 AssertMsgFailed(("VMLAUNCH/VMRESUME failed but shouldn't happen when VMLAUNCH/VMRESUME was emulated in IEM!\n"));
10747#endif
10748 else
10749 Log4Func(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
10750
10751 VMMRZCallRing3Enable(pVCpu);
10752}
10753
10754
10755/**
10756 * Runs the guest code using hardware-assisted VMX the normal way.
10757 *
10758 * @returns VBox status code.
10759 * @param pVCpu The cross context virtual CPU structure.
10760 * @param pcLoops Pointer to the number of executed loops.
10761 */
10762static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVMCPU pVCpu, uint32_t *pcLoops)
10763{
10764 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
10765 Assert(pcLoops);
10766 Assert(*pcLoops <= cMaxResumeLoops);
10767 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10768
10769#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10770 /*
10771 * Switch to the guest VMCS as we may have transitioned from executing the nested-guest
10772 * without leaving ring-0. Otherwise, if we came from ring-3 we would have loaded the
10773 * guest VMCS while entering the VMX ring-0 session.
10774 */
10775 if (pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs)
10776 {
10777 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, false /* fSwitchToNstGstVmcs */);
10778 if (RT_SUCCESS(rc))
10779 { /* likely */ }
10780 else
10781 {
10782 LogRelFunc(("Failed to switch to the guest VMCS. rc=%Rrc\n", rc));
10783 return rc;
10784 }
10785 }
10786#endif
10787
10788 VMXTRANSIENT VmxTransient;
10789 RT_ZERO(VmxTransient);
10790 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
10791
10792 /* Paranoia. */
10793 Assert(VmxTransient.pVmcsInfo == &pVCpu->hm.s.vmx.VmcsInfo);
10794
10795 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10796 for (;;)
10797 {
10798 Assert(!HMR0SuspendPending());
10799 HMVMX_ASSERT_CPU_SAFE(pVCpu);
10800 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10801
10802 /*
10803 * Preparatory work for running nested-guest code, this may force us to
10804 * return to ring-3.
10805 *
10806 * Warning! This bugger disables interrupts on VINF_SUCCESS!
10807 */
10808 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
10809 if (rcStrict != VINF_SUCCESS)
10810 break;
10811
10812 /* Interrupts are disabled at this point! */
10813 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
10814 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
10815 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
10816 /* Interrupts are re-enabled at this point! */
10817
10818 /*
10819 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
10820 */
10821 if (RT_SUCCESS(rcRun))
10822 { /* very likely */ }
10823 else
10824 {
10825 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
10826 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
10827 return rcRun;
10828 }
10829
10830 /*
10831 * Profile the VM-exit.
10832 */
10833 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10834 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10835 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10836 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
10837 HMVMX_START_EXIT_DISPATCH_PROF();
10838
10839 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
10840
10841 /*
10842 * Handle the VM-exit.
10843 */
10844#ifdef HMVMX_USE_FUNCTION_TABLE
10845 rcStrict = g_apfnVMExitHandlers[VmxTransient.uExitReason](pVCpu, &VmxTransient);
10846#else
10847 rcStrict = hmR0VmxHandleExit(pVCpu, &VmxTransient);
10848#endif
10849 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
10850 if (rcStrict == VINF_SUCCESS)
10851 {
10852 if (++(*pcLoops) <= cMaxResumeLoops)
10853 continue;
10854 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10855 rcStrict = VINF_EM_RAW_INTERRUPT;
10856 }
10857 break;
10858 }
10859
10860 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10861 return rcStrict;
10862}
10863
10864
10865#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10866/**
10867 * Runs the nested-guest code using hardware-assisted VMX.
10868 *
10869 * @returns VBox status code.
10870 * @param pVCpu The cross context virtual CPU structure.
10871 * @param pcLoops Pointer to the number of executed loops.
10872 *
10873 * @sa hmR0VmxRunGuestCodeNormal.
10874 */
10875static VBOXSTRICTRC hmR0VmxRunGuestCodeNested(PVMCPU pVCpu, uint32_t *pcLoops)
10876{
10877 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
10878 Assert(pcLoops);
10879 Assert(*pcLoops <= cMaxResumeLoops);
10880 Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10881
10882 /*
10883 * Switch to the nested-guest VMCS as we may have transitioned from executing the
10884 * guest without leaving ring-0. Otherwise, if we came from ring-3 we would have
10885 * loaded the nested-guest VMCS while entering the VMX ring-0 session.
10886 */
10887 if (!pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs)
10888 {
10889 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, true /* fSwitchToNstGstVmcs */);
10890 if (RT_SUCCESS(rc))
10891 { /* likely */ }
10892 else
10893 {
10894 LogRelFunc(("Failed to switch to the nested-guest VMCS. rc=%Rrc\n", rc));
10895 return rc;
10896 }
10897 }
10898
10899 VMXTRANSIENT VmxTransient;
10900 RT_ZERO(VmxTransient);
10901 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
10902 VmxTransient.fIsNestedGuest = true;
10903
10904 /* Paranoia. */
10905 Assert(VmxTransient.pVmcsInfo == &pVCpu->hm.s.vmx.VmcsInfoNstGst);
10906
10907 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10908 for (;;)
10909 {
10910 Assert(!HMR0SuspendPending());
10911 HMVMX_ASSERT_CPU_SAFE(pVCpu);
10912 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10913
10914 /*
10915 * Preparatory work for running guest code, this may force us to
10916 * return to ring-3.
10917 *
10918 * Warning! This bugger disables interrupts on VINF_SUCCESS!
10919 */
10920 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
10921 if (rcStrict != VINF_SUCCESS)
10922 break;
10923
10924 /* Interrupts are disabled at this point! */
10925 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
10926 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
10927 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
10928 /* Interrupts are re-enabled at this point! */
10929
10930 /*
10931 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
10932 */
10933 if (RT_SUCCESS(rcRun))
10934 { /* very likely */ }
10935 else
10936 {
10937 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
10938 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
10939 return rcRun;
10940 }
10941
10942 /*
10943 * Profile the VM-exit.
10944 */
10945 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10946 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10947 STAM_COUNTER_INC(&pVCpu->hm.s.StatNestedExitAll);
10948 STAM_COUNTER_INC(&pVCpu->hm.s.paStatNestedExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10949 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
10950 HMVMX_START_EXIT_DISPATCH_PROF();
10951
10952 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
10953
10954 /*
10955 * Handle the VM-exit.
10956 */
10957 rcStrict = hmR0VmxHandleExitNested(pVCpu, &VmxTransient);
10958 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
10959 if (rcStrict == VINF_SUCCESS)
10960 {
10961 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10962 {
10963 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10964 rcStrict = VINF_VMX_VMEXIT;
10965 }
10966 else
10967 {
10968 if (++(*pcLoops) <= cMaxResumeLoops)
10969 continue;
10970 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10971 rcStrict = VINF_EM_RAW_INTERRUPT;
10972 }
10973 }
10974 else
10975 Assert(rcStrict != VINF_VMX_VMEXIT);
10976 break;
10977 }
10978
10979 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10980 return rcStrict;
10981}
10982#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10983
10984
10985/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
10986 * probes.
10987 *
10988 * The following few functions and associated structure contains the bloat
10989 * necessary for providing detailed debug events and dtrace probes as well as
10990 * reliable host side single stepping. This works on the principle of
10991 * "subclassing" the normal execution loop and workers. We replace the loop
10992 * method completely and override selected helpers to add necessary adjustments
10993 * to their core operation.
10994 *
10995 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
10996 * any performance for debug and analysis features.
10997 *
10998 * @{
10999 */
11000
11001/**
11002 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
11003 * the debug run loop.
11004 */
11005typedef struct VMXRUNDBGSTATE
11006{
11007 /** The RIP we started executing at. This is for detecting that we stepped. */
11008 uint64_t uRipStart;
11009 /** The CS we started executing with. */
11010 uint16_t uCsStart;
11011
11012 /** Whether we've actually modified the 1st execution control field. */
11013 bool fModifiedProcCtls : 1;
11014 /** Whether we've actually modified the 2nd execution control field. */
11015 bool fModifiedProcCtls2 : 1;
11016 /** Whether we've actually modified the exception bitmap. */
11017 bool fModifiedXcptBitmap : 1;
11018
11019 /** We desire the modified the CR0 mask to be cleared. */
11020 bool fClearCr0Mask : 1;
11021 /** We desire the modified the CR4 mask to be cleared. */
11022 bool fClearCr4Mask : 1;
11023 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
11024 uint32_t fCpe1Extra;
11025 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
11026 uint32_t fCpe1Unwanted;
11027 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
11028 uint32_t fCpe2Extra;
11029 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
11030 uint32_t bmXcptExtra;
11031 /** The sequence number of the Dtrace provider settings the state was
11032 * configured against. */
11033 uint32_t uDtraceSettingsSeqNo;
11034 /** VM-exits to check (one bit per VM-exit). */
11035 uint32_t bmExitsToCheck[3];
11036
11037 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
11038 uint32_t fProcCtlsInitial;
11039 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
11040 uint32_t fProcCtls2Initial;
11041 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
11042 uint32_t bmXcptInitial;
11043} VMXRUNDBGSTATE;
11044AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
11045typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
11046
11047
11048/**
11049 * Initializes the VMXRUNDBGSTATE structure.
11050 *
11051 * @param pVCpu The cross context virtual CPU structure of the
11052 * calling EMT.
11053 * @param pVmxTransient The VMX-transient structure.
11054 * @param pDbgState The debug state to initialize.
11055 */
11056static void hmR0VmxRunDebugStateInit(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11057{
11058 pDbgState->uRipStart = pVCpu->cpum.GstCtx.rip;
11059 pDbgState->uCsStart = pVCpu->cpum.GstCtx.cs.Sel;
11060
11061 pDbgState->fModifiedProcCtls = false;
11062 pDbgState->fModifiedProcCtls2 = false;
11063 pDbgState->fModifiedXcptBitmap = false;
11064 pDbgState->fClearCr0Mask = false;
11065 pDbgState->fClearCr4Mask = false;
11066 pDbgState->fCpe1Extra = 0;
11067 pDbgState->fCpe1Unwanted = 0;
11068 pDbgState->fCpe2Extra = 0;
11069 pDbgState->bmXcptExtra = 0;
11070 pDbgState->fProcCtlsInitial = pVmxTransient->pVmcsInfo->u32ProcCtls;
11071 pDbgState->fProcCtls2Initial = pVmxTransient->pVmcsInfo->u32ProcCtls2;
11072 pDbgState->bmXcptInitial = pVmxTransient->pVmcsInfo->u32XcptBitmap;
11073}
11074
11075
11076/**
11077 * Updates the VMSC fields with changes requested by @a pDbgState.
11078 *
11079 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
11080 * immediately before executing guest code, i.e. when interrupts are disabled.
11081 * We don't check status codes here as we cannot easily assert or return in the
11082 * latter case.
11083 *
11084 * @param pVCpu The cross context virtual CPU structure.
11085 * @param pVmxTransient The VMX-transient structure.
11086 * @param pDbgState The debug state.
11087 */
11088static void hmR0VmxPreRunGuestDebugStateApply(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11089{
11090 /*
11091 * Ensure desired flags in VMCS control fields are set.
11092 * (Ignoring write failure here, as we're committed and it's just debug extras.)
11093 *
11094 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
11095 * there should be no stale data in pCtx at this point.
11096 */
11097 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11098 if ( (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
11099 || (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Unwanted))
11100 {
11101 pVmcsInfo->u32ProcCtls |= pDbgState->fCpe1Extra;
11102 pVmcsInfo->u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
11103 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
11104 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVmcsInfo->u32ProcCtls));
11105 pDbgState->fModifiedProcCtls = true;
11106 }
11107
11108 if ((pVmcsInfo->u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
11109 {
11110 pVmcsInfo->u32ProcCtls2 |= pDbgState->fCpe2Extra;
11111 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVmcsInfo->u32ProcCtls2);
11112 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVmcsInfo->u32ProcCtls2));
11113 pDbgState->fModifiedProcCtls2 = true;
11114 }
11115
11116 if ((pVmcsInfo->u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
11117 {
11118 pVmcsInfo->u32XcptBitmap |= pDbgState->bmXcptExtra;
11119 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVmcsInfo->u32XcptBitmap);
11120 Log6Func(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVmcsInfo->u32XcptBitmap));
11121 pDbgState->fModifiedXcptBitmap = true;
11122 }
11123
11124 if (pDbgState->fClearCr0Mask && pVmcsInfo->u64Cr0Mask != 0)
11125 {
11126 pVmcsInfo->u64Cr0Mask = 0;
11127 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, 0);
11128 Log6Func(("VMX_VMCS_CTRL_CR0_MASK: 0\n"));
11129 }
11130
11131 if (pDbgState->fClearCr4Mask && pVmcsInfo->u64Cr4Mask != 0)
11132 {
11133 pVmcsInfo->u64Cr4Mask = 0;
11134 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, 0);
11135 Log6Func(("VMX_VMCS_CTRL_CR4_MASK: 0\n"));
11136 }
11137
11138 NOREF(pVCpu);
11139}
11140
11141
11142/**
11143 * Restores VMCS fields that were changed by hmR0VmxPreRunGuestDebugStateApply for
11144 * re-entry next time around.
11145 *
11146 * @returns Strict VBox status code (i.e. informational status codes too).
11147 * @param pVCpu The cross context virtual CPU structure.
11148 * @param pVmxTransient The VMX-transient structure.
11149 * @param pDbgState The debug state.
11150 * @param rcStrict The return code from executing the guest using single
11151 * stepping.
11152 */
11153static VBOXSTRICTRC hmR0VmxRunDebugStateRevert(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState,
11154 VBOXSTRICTRC rcStrict)
11155{
11156 /*
11157 * Restore VM-exit control settings as we may not reenter this function the
11158 * next time around.
11159 */
11160 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11161
11162 /* We reload the initial value, trigger what we can of recalculations the
11163 next time around. From the looks of things, that's all that's required atm. */
11164 if (pDbgState->fModifiedProcCtls)
11165 {
11166 if (!(pDbgState->fProcCtlsInitial & VMX_PROC_CTLS_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
11167 pDbgState->fProcCtlsInitial |= VMX_PROC_CTLS_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
11168 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
11169 AssertRC(rc2);
11170 pVmcsInfo->u32ProcCtls = pDbgState->fProcCtlsInitial;
11171 }
11172
11173 /* We're currently the only ones messing with this one, so just restore the
11174 cached value and reload the field. */
11175 if ( pDbgState->fModifiedProcCtls2
11176 && pVmcsInfo->u32ProcCtls2 != pDbgState->fProcCtls2Initial)
11177 {
11178 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
11179 AssertRC(rc2);
11180 pVmcsInfo->u32ProcCtls2 = pDbgState->fProcCtls2Initial;
11181 }
11182
11183 /* If we've modified the exception bitmap, we restore it and trigger
11184 reloading and partial recalculation the next time around. */
11185 if (pDbgState->fModifiedXcptBitmap)
11186 pVmcsInfo->u32XcptBitmap = pDbgState->bmXcptInitial;
11187
11188 return rcStrict;
11189}
11190
11191
11192/**
11193 * Configures VM-exit controls for current DBGF and DTrace settings.
11194 *
11195 * This updates @a pDbgState and the VMCS execution control fields to reflect
11196 * the necessary VM-exits demanded by DBGF and DTrace.
11197 *
11198 * @param pVCpu The cross context virtual CPU structure.
11199 * @param pVmxTransient The VMX-transient structure. May update
11200 * fUpdatedTscOffsettingAndPreemptTimer.
11201 * @param pDbgState The debug state.
11202 */
11203static void hmR0VmxPreRunGuestDebugStateUpdate(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11204{
11205 /*
11206 * Take down the dtrace serial number so we can spot changes.
11207 */
11208 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
11209 ASMCompilerBarrier();
11210
11211 /*
11212 * We'll rebuild most of the middle block of data members (holding the
11213 * current settings) as we go along here, so start by clearing it all.
11214 */
11215 pDbgState->bmXcptExtra = 0;
11216 pDbgState->fCpe1Extra = 0;
11217 pDbgState->fCpe1Unwanted = 0;
11218 pDbgState->fCpe2Extra = 0;
11219 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
11220 pDbgState->bmExitsToCheck[i] = 0;
11221
11222 /*
11223 * Software interrupts (INT XXh) - no idea how to trigger these...
11224 */
11225 PVM pVM = pVCpu->CTX_SUFF(pVM);
11226 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
11227 || VBOXVMM_INT_SOFTWARE_ENABLED())
11228 {
11229 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11230 }
11231
11232 /*
11233 * INT3 breakpoints - triggered by #BP exceptions.
11234 */
11235 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
11236 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11237
11238 /*
11239 * Exception bitmap and XCPT events+probes.
11240 */
11241 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
11242 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
11243 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
11244
11245 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
11246 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
11247 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11248 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
11249 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
11250 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
11251 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
11252 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
11253 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
11254 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
11255 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
11256 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
11257 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
11258 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
11259 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
11260 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
11261 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
11262 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
11263
11264 if (pDbgState->bmXcptExtra)
11265 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11266
11267 /*
11268 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
11269 *
11270 * Note! This is the reverse of what hmR0VmxHandleExitDtraceEvents does.
11271 * So, when adding/changing/removing please don't forget to update it.
11272 *
11273 * Some of the macros are picking up local variables to save horizontal space,
11274 * (being able to see it in a table is the lesser evil here).
11275 */
11276#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
11277 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
11278 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
11279#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
11280 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11281 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11282 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11283 } else do { } while (0)
11284#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
11285 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11286 { \
11287 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
11288 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11289 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11290 } else do { } while (0)
11291#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
11292 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11293 { \
11294 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
11295 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11296 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11297 } else do { } while (0)
11298#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
11299 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11300 { \
11301 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
11302 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11303 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11304 } else do { } while (0)
11305
11306 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
11307 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
11308 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
11309 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
11310 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
11311
11312 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
11313 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
11314 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
11315 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
11316 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_PROC_CTLS_HLT_EXIT); /* paranoia */
11317 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
11318 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
11319 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
11320 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_PROC_CTLS_INVLPG_EXIT);
11321 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
11322 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_PROC_CTLS_RDPMC_EXIT);
11323 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
11324 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_PROC_CTLS_RDTSC_EXIT);
11325 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
11326 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
11327 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
11328 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
11329 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
11330 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
11331 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
11332 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
11333 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
11334 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
11335 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
11336 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
11337 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
11338 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
11339 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
11340 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
11341 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
11342 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
11343 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
11344 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
11345 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
11346 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
11347 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
11348
11349 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
11350 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11351 {
11352 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4
11353 | CPUMCTX_EXTRN_APIC_TPR);
11354 AssertRC(rc);
11355
11356#if 0 /** @todo fix me */
11357 pDbgState->fClearCr0Mask = true;
11358 pDbgState->fClearCr4Mask = true;
11359#endif
11360 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
11361 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_STORE_EXIT | VMX_PROC_CTLS_CR8_STORE_EXIT;
11362 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11363 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_LOAD_EXIT | VMX_PROC_CTLS_CR8_LOAD_EXIT;
11364 pDbgState->fCpe1Unwanted |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* risky? */
11365 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
11366 require clearing here and in the loop if we start using it. */
11367 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
11368 }
11369 else
11370 {
11371 if (pDbgState->fClearCr0Mask)
11372 {
11373 pDbgState->fClearCr0Mask = false;
11374 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR0);
11375 }
11376 if (pDbgState->fClearCr4Mask)
11377 {
11378 pDbgState->fClearCr4Mask = false;
11379 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR4);
11380 }
11381 }
11382 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
11383 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
11384
11385 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
11386 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
11387 {
11388 /** @todo later, need to fix handler as it assumes this won't usually happen. */
11389 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
11390 }
11391 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
11392 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
11393
11394 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS); /* risky clearing this? */
11395 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
11396 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS);
11397 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
11398 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_PROC_CTLS_MWAIT_EXIT); /* paranoia */
11399 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
11400 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_PROC_CTLS_MONITOR_EXIT); /* paranoia */
11401 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
11402#if 0 /** @todo too slow, fix handler. */
11403 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_PROC_CTLS_PAUSE_EXIT);
11404#endif
11405 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
11406
11407 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
11408 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
11409 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
11410 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
11411 {
11412 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11413 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_GDTR_IDTR_ACCESS);
11414 }
11415 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11416 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11417 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11418 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11419
11420 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
11421 || IS_EITHER_ENABLED(pVM, INSTR_STR)
11422 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
11423 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
11424 {
11425 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11426 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_LDTR_TR_ACCESS);
11427 }
11428 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_LDTR_TR_ACCESS);
11429 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_LDTR_TR_ACCESS);
11430 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_LDTR_TR_ACCESS);
11431 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_LDTR_TR_ACCESS);
11432
11433 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
11434 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
11435 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_PROC_CTLS_RDTSC_EXIT);
11436 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
11437 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
11438 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
11439 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_PROC_CTLS2_WBINVD_EXIT);
11440 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
11441 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
11442 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
11443 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_PROC_CTLS2_RDRAND_EXIT);
11444 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
11445 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_PROC_CTLS_INVLPG_EXIT);
11446 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
11447 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
11448 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
11449 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_PROC_CTLS2_RDSEED_EXIT);
11450 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
11451 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
11452 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
11453 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
11454 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
11455
11456#undef IS_EITHER_ENABLED
11457#undef SET_ONLY_XBM_IF_EITHER_EN
11458#undef SET_CPE1_XBM_IF_EITHER_EN
11459#undef SET_CPEU_XBM_IF_EITHER_EN
11460#undef SET_CPE2_XBM_IF_EITHER_EN
11461
11462 /*
11463 * Sanitize the control stuff.
11464 */
11465 pDbgState->fCpe2Extra &= pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1;
11466 if (pDbgState->fCpe2Extra)
11467 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
11468 pDbgState->fCpe1Extra &= pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1;
11469 pDbgState->fCpe1Unwanted &= ~pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0;
11470 if (pVCpu->hm.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_PROC_CTLS_RDTSC_EXIT))
11471 {
11472 pVCpu->hm.s.fDebugWantRdTscExit ^= true;
11473 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
11474 }
11475
11476 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
11477 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
11478 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
11479 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
11480}
11481
11482
11483/**
11484 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
11485 * appropriate.
11486 *
11487 * The caller has checked the VM-exit against the
11488 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
11489 * already, so we don't have to do that either.
11490 *
11491 * @returns Strict VBox status code (i.e. informational status codes too).
11492 * @param pVCpu The cross context virtual CPU structure.
11493 * @param pVmxTransient The VMX-transient structure.
11494 * @param uExitReason The VM-exit reason.
11495 *
11496 * @remarks The name of this function is displayed by dtrace, so keep it short
11497 * and to the point. No longer than 33 chars long, please.
11498 */
11499static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
11500{
11501 /*
11502 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
11503 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
11504 *
11505 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
11506 * does. Must add/change/remove both places. Same ordering, please.
11507 *
11508 * Added/removed events must also be reflected in the next section
11509 * where we dispatch dtrace events.
11510 */
11511 bool fDtrace1 = false;
11512 bool fDtrace2 = false;
11513 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
11514 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
11515 uint32_t uEventArg = 0;
11516#define SET_EXIT(a_EventSubName) \
11517 do { \
11518 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11519 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11520 } while (0)
11521#define SET_BOTH(a_EventSubName) \
11522 do { \
11523 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
11524 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11525 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
11526 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11527 } while (0)
11528 switch (uExitReason)
11529 {
11530 case VMX_EXIT_MTF:
11531 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
11532
11533 case VMX_EXIT_XCPT_OR_NMI:
11534 {
11535 uint8_t const idxVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
11536 switch (VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo))
11537 {
11538 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
11539 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
11540 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
11541 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
11542 {
11543 if (VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uExitIntInfo))
11544 {
11545 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
11546 uEventArg = pVmxTransient->uExitIntErrorCode;
11547 }
11548 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
11549 switch (enmEvent1)
11550 {
11551 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
11552 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
11553 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
11554 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
11555 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
11556 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
11557 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
11558 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
11559 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
11560 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
11561 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
11562 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
11563 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
11564 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
11565 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
11566 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
11567 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
11568 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
11569 default: break;
11570 }
11571 }
11572 else
11573 AssertFailed();
11574 break;
11575
11576 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
11577 uEventArg = idxVector;
11578 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
11579 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
11580 break;
11581 }
11582 break;
11583 }
11584
11585 case VMX_EXIT_TRIPLE_FAULT:
11586 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
11587 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
11588 break;
11589 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
11590 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
11591 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
11592 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
11593 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
11594
11595 /* Instruction specific VM-exits: */
11596 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
11597 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
11598 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
11599 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
11600 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
11601 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
11602 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
11603 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
11604 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
11605 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
11606 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
11607 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
11608 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
11609 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
11610 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
11611 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
11612 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
11613 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
11614 case VMX_EXIT_MOV_CRX:
11615 hmR0VmxReadExitQualVmcs(pVmxTransient);
11616 if (VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_CRX_ACCESS_READ)
11617 SET_BOTH(CRX_READ);
11618 else
11619 SET_BOTH(CRX_WRITE);
11620 uEventArg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
11621 break;
11622 case VMX_EXIT_MOV_DRX:
11623 hmR0VmxReadExitQualVmcs(pVmxTransient);
11624 if ( VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual)
11625 == VMX_EXIT_QUAL_DRX_DIRECTION_READ)
11626 SET_BOTH(DRX_READ);
11627 else
11628 SET_BOTH(DRX_WRITE);
11629 uEventArg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
11630 break;
11631 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
11632 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
11633 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
11634 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
11635 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
11636 case VMX_EXIT_GDTR_IDTR_ACCESS:
11637 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
11638 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_XDTR_INSINFO_INSTR_ID))
11639 {
11640 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
11641 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
11642 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
11643 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
11644 }
11645 break;
11646
11647 case VMX_EXIT_LDTR_TR_ACCESS:
11648 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
11649 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_YYTR_INSINFO_INSTR_ID))
11650 {
11651 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
11652 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
11653 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
11654 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
11655 }
11656 break;
11657
11658 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
11659 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
11660 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
11661 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
11662 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
11663 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
11664 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
11665 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
11666 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
11667 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
11668 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
11669
11670 /* Events that aren't relevant at this point. */
11671 case VMX_EXIT_EXT_INT:
11672 case VMX_EXIT_INT_WINDOW:
11673 case VMX_EXIT_NMI_WINDOW:
11674 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11675 case VMX_EXIT_PREEMPT_TIMER:
11676 case VMX_EXIT_IO_INSTR:
11677 break;
11678
11679 /* Errors and unexpected events. */
11680 case VMX_EXIT_INIT_SIGNAL:
11681 case VMX_EXIT_SIPI:
11682 case VMX_EXIT_IO_SMI:
11683 case VMX_EXIT_SMI:
11684 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
11685 case VMX_EXIT_ERR_MSR_LOAD:
11686 case VMX_EXIT_ERR_MACHINE_CHECK:
11687 case VMX_EXIT_PML_FULL:
11688 case VMX_EXIT_VIRTUALIZED_EOI:
11689 break;
11690
11691 default:
11692 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
11693 break;
11694 }
11695#undef SET_BOTH
11696#undef SET_EXIT
11697
11698 /*
11699 * Dtrace tracepoints go first. We do them here at once so we don't
11700 * have to copy the guest state saving and stuff a few dozen times.
11701 * Down side is that we've got to repeat the switch, though this time
11702 * we use enmEvent since the probes are a subset of what DBGF does.
11703 */
11704 if (fDtrace1 || fDtrace2)
11705 {
11706 hmR0VmxReadExitQualVmcs(pVmxTransient);
11707 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
11708 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
11709 switch (enmEvent1)
11710 {
11711 /** @todo consider which extra parameters would be helpful for each probe. */
11712 case DBGFEVENT_END: break;
11713 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pCtx); break;
11714 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pCtx, pCtx->dr[6]); break;
11715 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pCtx); break;
11716 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pCtx); break;
11717 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pCtx); break;
11718 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pCtx); break;
11719 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pCtx); break;
11720 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pCtx); break;
11721 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pCtx, uEventArg); break;
11722 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pCtx, uEventArg); break;
11723 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pCtx, uEventArg); break;
11724 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pCtx, uEventArg); break;
11725 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pCtx, uEventArg, pCtx->cr2); break;
11726 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pCtx); break;
11727 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pCtx); break;
11728 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pCtx); break;
11729 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pCtx); break;
11730 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pCtx, uEventArg); break;
11731 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11732 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11733 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pCtx); break;
11734 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pCtx); break;
11735 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pCtx); break;
11736 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pCtx); break;
11737 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pCtx); break;
11738 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pCtx); break;
11739 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pCtx); break;
11740 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11741 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11742 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11743 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11744 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11745 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pCtx, pCtx->ecx,
11746 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11747 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pCtx); break;
11748 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pCtx); break;
11749 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pCtx); break;
11750 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pCtx); break;
11751 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pCtx); break;
11752 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pCtx); break;
11753 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pCtx); break;
11754 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pCtx); break;
11755 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pCtx); break;
11756 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pCtx); break;
11757 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pCtx); break;
11758 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pCtx); break;
11759 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pCtx); break;
11760 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pCtx); break;
11761 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pCtx); break;
11762 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pCtx); break;
11763 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pCtx); break;
11764 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pCtx); break;
11765 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pCtx); break;
11766 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pCtx); break;
11767 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pCtx); break;
11768 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pCtx); break;
11769 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pCtx); break;
11770 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pCtx); break;
11771 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pCtx); break;
11772 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pCtx); break;
11773 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pCtx); break;
11774 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pCtx); break;
11775 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pCtx); break;
11776 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pCtx); break;
11777 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pCtx); break;
11778 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pCtx); break;
11779 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
11780 }
11781 switch (enmEvent2)
11782 {
11783 /** @todo consider which extra parameters would be helpful for each probe. */
11784 case DBGFEVENT_END: break;
11785 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pCtx); break;
11786 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11787 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pCtx); break;
11788 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pCtx); break;
11789 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pCtx); break;
11790 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pCtx); break;
11791 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pCtx); break;
11792 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pCtx); break;
11793 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pCtx); break;
11794 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11795 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11796 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11797 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11798 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11799 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pCtx, pCtx->ecx,
11800 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11801 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pCtx); break;
11802 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pCtx); break;
11803 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pCtx); break;
11804 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pCtx); break;
11805 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pCtx); break;
11806 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pCtx); break;
11807 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pCtx); break;
11808 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pCtx); break;
11809 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pCtx); break;
11810 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pCtx); break;
11811 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pCtx); break;
11812 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pCtx); break;
11813 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pCtx); break;
11814 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pCtx); break;
11815 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pCtx); break;
11816 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pCtx); break;
11817 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pCtx); break;
11818 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pCtx); break;
11819 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pCtx); break;
11820 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pCtx); break;
11821 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pCtx); break;
11822 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pCtx); break;
11823 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pCtx); break;
11824 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pCtx); break;
11825 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pCtx); break;
11826 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pCtx); break;
11827 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pCtx); break;
11828 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pCtx); break;
11829 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pCtx); break;
11830 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pCtx); break;
11831 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pCtx); break;
11832 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pCtx); break;
11833 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pCtx); break;
11834 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pCtx); break;
11835 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pCtx); break;
11836 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pCtx); break;
11837 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
11838 }
11839 }
11840
11841 /*
11842 * Fire of the DBGF event, if enabled (our check here is just a quick one,
11843 * the DBGF call will do a full check).
11844 *
11845 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
11846 * Note! If we have to events, we prioritize the first, i.e. the instruction
11847 * one, in order to avoid event nesting.
11848 */
11849 PVM pVM = pVCpu->CTX_SUFF(pVM);
11850 if ( enmEvent1 != DBGFEVENT_END
11851 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
11852 {
11853 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11854 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent1, DBGFEVENTCTX_HM, 1, uEventArg);
11855 if (rcStrict != VINF_SUCCESS)
11856 return rcStrict;
11857 }
11858 else if ( enmEvent2 != DBGFEVENT_END
11859 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
11860 {
11861 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11862 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent2, DBGFEVENTCTX_HM, 1, uEventArg);
11863 if (rcStrict != VINF_SUCCESS)
11864 return rcStrict;
11865 }
11866
11867 return VINF_SUCCESS;
11868}
11869
11870
11871/**
11872 * Single-stepping VM-exit filtering.
11873 *
11874 * This is preprocessing the VM-exits and deciding whether we've gotten far
11875 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
11876 * handling is performed.
11877 *
11878 * @returns Strict VBox status code (i.e. informational status codes too).
11879 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
11880 * @param pVmxTransient The VMX-transient structure.
11881 * @param pDbgState The debug state.
11882 */
11883DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11884{
11885 /*
11886 * Expensive (saves context) generic dtrace VM-exit probe.
11887 */
11888 uint32_t const uExitReason = pVmxTransient->uExitReason;
11889 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
11890 { /* more likely */ }
11891 else
11892 {
11893 hmR0VmxReadExitQualVmcs(pVmxTransient);
11894 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
11895 AssertRC(rc);
11896 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, &pVCpu->cpum.GstCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
11897 }
11898
11899 /*
11900 * Check for host NMI, just to get that out of the way.
11901 */
11902 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
11903 { /* normally likely */ }
11904 else
11905 {
11906 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
11907 uint32_t const uIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
11908 if (uIntType == VMX_EXIT_INT_INFO_TYPE_NMI)
11909 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
11910 }
11911
11912 /*
11913 * Check for single stepping event if we're stepping.
11914 */
11915 if (pVCpu->hm.s.fSingleInstruction)
11916 {
11917 switch (uExitReason)
11918 {
11919 case VMX_EXIT_MTF:
11920 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
11921
11922 /* Various events: */
11923 case VMX_EXIT_XCPT_OR_NMI:
11924 case VMX_EXIT_EXT_INT:
11925 case VMX_EXIT_TRIPLE_FAULT:
11926 case VMX_EXIT_INT_WINDOW:
11927 case VMX_EXIT_NMI_WINDOW:
11928 case VMX_EXIT_TASK_SWITCH:
11929 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11930 case VMX_EXIT_APIC_ACCESS:
11931 case VMX_EXIT_EPT_VIOLATION:
11932 case VMX_EXIT_EPT_MISCONFIG:
11933 case VMX_EXIT_PREEMPT_TIMER:
11934
11935 /* Instruction specific VM-exits: */
11936 case VMX_EXIT_CPUID:
11937 case VMX_EXIT_GETSEC:
11938 case VMX_EXIT_HLT:
11939 case VMX_EXIT_INVD:
11940 case VMX_EXIT_INVLPG:
11941 case VMX_EXIT_RDPMC:
11942 case VMX_EXIT_RDTSC:
11943 case VMX_EXIT_RSM:
11944 case VMX_EXIT_VMCALL:
11945 case VMX_EXIT_VMCLEAR:
11946 case VMX_EXIT_VMLAUNCH:
11947 case VMX_EXIT_VMPTRLD:
11948 case VMX_EXIT_VMPTRST:
11949 case VMX_EXIT_VMREAD:
11950 case VMX_EXIT_VMRESUME:
11951 case VMX_EXIT_VMWRITE:
11952 case VMX_EXIT_VMXOFF:
11953 case VMX_EXIT_VMXON:
11954 case VMX_EXIT_MOV_CRX:
11955 case VMX_EXIT_MOV_DRX:
11956 case VMX_EXIT_IO_INSTR:
11957 case VMX_EXIT_RDMSR:
11958 case VMX_EXIT_WRMSR:
11959 case VMX_EXIT_MWAIT:
11960 case VMX_EXIT_MONITOR:
11961 case VMX_EXIT_PAUSE:
11962 case VMX_EXIT_GDTR_IDTR_ACCESS:
11963 case VMX_EXIT_LDTR_TR_ACCESS:
11964 case VMX_EXIT_INVEPT:
11965 case VMX_EXIT_RDTSCP:
11966 case VMX_EXIT_INVVPID:
11967 case VMX_EXIT_WBINVD:
11968 case VMX_EXIT_XSETBV:
11969 case VMX_EXIT_RDRAND:
11970 case VMX_EXIT_INVPCID:
11971 case VMX_EXIT_VMFUNC:
11972 case VMX_EXIT_RDSEED:
11973 case VMX_EXIT_XSAVES:
11974 case VMX_EXIT_XRSTORS:
11975 {
11976 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11977 AssertRCReturn(rc, rc);
11978 if ( pVCpu->cpum.GstCtx.rip != pDbgState->uRipStart
11979 || pVCpu->cpum.GstCtx.cs.Sel != pDbgState->uCsStart)
11980 return VINF_EM_DBG_STEPPED;
11981 break;
11982 }
11983
11984 /* Errors and unexpected events: */
11985 case VMX_EXIT_INIT_SIGNAL:
11986 case VMX_EXIT_SIPI:
11987 case VMX_EXIT_IO_SMI:
11988 case VMX_EXIT_SMI:
11989 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
11990 case VMX_EXIT_ERR_MSR_LOAD:
11991 case VMX_EXIT_ERR_MACHINE_CHECK:
11992 case VMX_EXIT_PML_FULL:
11993 case VMX_EXIT_VIRTUALIZED_EOI:
11994 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
11995 break;
11996
11997 default:
11998 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
11999 break;
12000 }
12001 }
12002
12003 /*
12004 * Check for debugger event breakpoints and dtrace probes.
12005 */
12006 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
12007 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
12008 {
12009 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVCpu, pVmxTransient, uExitReason);
12010 if (rcStrict != VINF_SUCCESS)
12011 return rcStrict;
12012 }
12013
12014 /*
12015 * Normal processing.
12016 */
12017#ifdef HMVMX_USE_FUNCTION_TABLE
12018 return g_apfnVMExitHandlers[uExitReason](pVCpu, pVmxTransient);
12019#else
12020 return hmR0VmxHandleExit(pVCpu, pVmxTransient, uExitReason);
12021#endif
12022}
12023
12024
12025/**
12026 * Single steps guest code using hardware-assisted VMX.
12027 *
12028 * This is -not- the same as the guest single-stepping itself (say using EFLAGS.TF)
12029 * but single-stepping through the hypervisor debugger.
12030 *
12031 * @returns Strict VBox status code (i.e. informational status codes too).
12032 * @param pVCpu The cross context virtual CPU structure.
12033 * @param pcLoops Pointer to the number of executed loops.
12034 *
12035 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
12036 */
12037static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVMCPU pVCpu, uint32_t *pcLoops)
12038{
12039 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
12040 Assert(pcLoops);
12041 Assert(*pcLoops <= cMaxResumeLoops);
12042
12043 VMXTRANSIENT VmxTransient;
12044 RT_ZERO(VmxTransient);
12045 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
12046
12047 /* Set HMCPU indicators. */
12048 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
12049 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
12050 pVCpu->hm.s.fDebugWantRdTscExit = false;
12051 pVCpu->hm.s.fUsingDebugLoop = true;
12052
12053 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
12054 VMXRUNDBGSTATE DbgState;
12055 hmR0VmxRunDebugStateInit(pVCpu, &VmxTransient, &DbgState);
12056 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12057
12058 /*
12059 * The loop.
12060 */
12061 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
12062 for (;;)
12063 {
12064 Assert(!HMR0SuspendPending());
12065 HMVMX_ASSERT_CPU_SAFE(pVCpu);
12066 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
12067 bool fStepping = pVCpu->hm.s.fSingleInstruction;
12068
12069 /* Set up VM-execution controls the next two can respond to. */
12070 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12071
12072 /*
12073 * Preparatory work for running guest code, this may force us to
12074 * return to ring-3.
12075 *
12076 * Warning! This bugger disables interrupts on VINF_SUCCESS!
12077 */
12078 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, fStepping);
12079 if (rcStrict != VINF_SUCCESS)
12080 break;
12081
12082 /* Interrupts are disabled at this point! */
12083 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
12084
12085 /* Override any obnoxious code in the above two calls. */
12086 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12087
12088 /*
12089 * Finally execute the guest.
12090 */
12091 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
12092
12093 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
12094 /* Interrupts are re-enabled at this point! */
12095
12096 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
12097 if (RT_SUCCESS(rcRun))
12098 { /* very likely */ }
12099 else
12100 {
12101 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
12102 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
12103 return rcRun;
12104 }
12105
12106 /* Profile the VM-exit. */
12107 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
12108 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
12109 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
12110 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
12111 HMVMX_START_EXIT_DISPATCH_PROF();
12112
12113 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
12114
12115 /*
12116 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
12117 */
12118 rcStrict = hmR0VmxRunDebugHandleExit(pVCpu, &VmxTransient, &DbgState);
12119 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
12120 if (rcStrict != VINF_SUCCESS)
12121 break;
12122 if (++(*pcLoops) > cMaxResumeLoops)
12123 {
12124 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
12125 rcStrict = VINF_EM_RAW_INTERRUPT;
12126 break;
12127 }
12128
12129 /*
12130 * Stepping: Did the RIP change, if so, consider it a single step.
12131 * Otherwise, make sure one of the TFs gets set.
12132 */
12133 if (fStepping)
12134 {
12135 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12136 AssertRC(rc);
12137 if ( pVCpu->cpum.GstCtx.rip != DbgState.uRipStart
12138 || pVCpu->cpum.GstCtx.cs.Sel != DbgState.uCsStart)
12139 {
12140 rcStrict = VINF_EM_DBG_STEPPED;
12141 break;
12142 }
12143 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
12144 }
12145
12146 /*
12147 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
12148 */
12149 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
12150 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12151 }
12152
12153 /*
12154 * Clear the X86_EFL_TF if necessary.
12155 */
12156 if (pVCpu->hm.s.fClearTrapFlag)
12157 {
12158 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
12159 AssertRC(rc);
12160 pVCpu->hm.s.fClearTrapFlag = false;
12161 pVCpu->cpum.GstCtx.eflags.Bits.u1TF = 0;
12162 }
12163 /** @todo there seems to be issues with the resume flag when the monitor trap
12164 * flag is pending without being used. Seen early in bios init when
12165 * accessing APIC page in protected mode. */
12166
12167 /*
12168 * Restore VM-exit control settings as we may not re-enter this function the
12169 * next time around.
12170 */
12171 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &VmxTransient, &DbgState, rcStrict);
12172
12173 /* Restore HMCPU indicators. */
12174 pVCpu->hm.s.fUsingDebugLoop = false;
12175 pVCpu->hm.s.fDebugWantRdTscExit = false;
12176 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
12177
12178 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
12179 return rcStrict;
12180}
12181
12182
12183/** @} */
12184
12185
12186/**
12187 * Checks if any expensive dtrace probes are enabled and we should go to the
12188 * debug loop.
12189 *
12190 * @returns true if we should use debug loop, false if not.
12191 */
12192static bool hmR0VmxAnyExpensiveProbesEnabled(void)
12193{
12194 /* It's probably faster to OR the raw 32-bit counter variables together.
12195 Since the variables are in an array and the probes are next to one
12196 another (more or less), we have good locality. So, better read
12197 eight-nine cache lines ever time and only have one conditional, than
12198 128+ conditionals, right? */
12199 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
12200 | VBOXVMM_XCPT_DE_ENABLED_RAW()
12201 | VBOXVMM_XCPT_DB_ENABLED_RAW()
12202 | VBOXVMM_XCPT_BP_ENABLED_RAW()
12203 | VBOXVMM_XCPT_OF_ENABLED_RAW()
12204 | VBOXVMM_XCPT_BR_ENABLED_RAW()
12205 | VBOXVMM_XCPT_UD_ENABLED_RAW()
12206 | VBOXVMM_XCPT_NM_ENABLED_RAW()
12207 | VBOXVMM_XCPT_DF_ENABLED_RAW()
12208 | VBOXVMM_XCPT_TS_ENABLED_RAW()
12209 | VBOXVMM_XCPT_NP_ENABLED_RAW()
12210 | VBOXVMM_XCPT_SS_ENABLED_RAW()
12211 | VBOXVMM_XCPT_GP_ENABLED_RAW()
12212 | VBOXVMM_XCPT_PF_ENABLED_RAW()
12213 | VBOXVMM_XCPT_MF_ENABLED_RAW()
12214 | VBOXVMM_XCPT_AC_ENABLED_RAW()
12215 | VBOXVMM_XCPT_XF_ENABLED_RAW()
12216 | VBOXVMM_XCPT_VE_ENABLED_RAW()
12217 | VBOXVMM_XCPT_SX_ENABLED_RAW()
12218 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
12219 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
12220 ) != 0
12221 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
12222 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
12223 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
12224 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
12225 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
12226 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
12227 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
12228 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
12229 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
12230 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
12231 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
12232 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
12233 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
12234 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
12235 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
12236 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
12237 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
12238 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
12239 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
12240 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
12241 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
12242 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
12243 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
12244 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
12245 | VBOXVMM_INSTR_STR_ENABLED_RAW()
12246 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
12247 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
12248 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
12249 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
12250 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
12251 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
12252 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
12253 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
12254 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
12255 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
12256 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
12257 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
12258 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
12259 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
12260 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
12261 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
12262 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
12263 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
12264 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
12265 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
12266 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
12267 ) != 0
12268 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
12269 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
12270 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
12271 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
12272 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
12273 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
12274 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
12275 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
12276 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
12277 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
12278 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
12279 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
12280 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
12281 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
12282 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
12283 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
12284 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
12285 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
12286 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
12287 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
12288 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
12289 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
12290 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
12291 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
12292 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
12293 | VBOXVMM_EXIT_STR_ENABLED_RAW()
12294 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
12295 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
12296 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
12297 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
12298 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
12299 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
12300 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
12301 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
12302 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
12303 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
12304 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
12305 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
12306 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
12307 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
12308 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
12309 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
12310 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
12311 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
12312 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
12313 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
12314 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
12315 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
12316 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
12317 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
12318 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
12319 ) != 0;
12320}
12321
12322
12323/**
12324 * Runs the guest using hardware-assisted VMX.
12325 *
12326 * @returns Strict VBox status code (i.e. informational status codes too).
12327 * @param pVCpu The cross context virtual CPU structure.
12328 */
12329VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVMCPU pVCpu)
12330{
12331 AssertPtr(pVCpu);
12332 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12333 Assert(VMMRZCallRing3IsEnabled(pVCpu));
12334 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12335 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
12336
12337 VMMRZCallRing3SetNotification(pVCpu, hmR0VmxCallRing3Callback, pCtx);
12338
12339 VBOXSTRICTRC rcStrict;
12340 uint32_t cLoops = 0;
12341 for (;;)
12342 {
12343#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12344 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(pCtx);
12345#else
12346 bool const fInNestedGuestMode = false;
12347#endif
12348 if (!fInNestedGuestMode)
12349 {
12350 if ( !pVCpu->hm.s.fUseDebugLoop
12351 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
12352 && !DBGFIsStepping(pVCpu)
12353 && !pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
12354 rcStrict = hmR0VmxRunGuestCodeNormal(pVCpu, &cLoops);
12355 else
12356 rcStrict = hmR0VmxRunGuestCodeDebug(pVCpu, &cLoops);
12357 }
12358#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12359 else
12360 rcStrict = hmR0VmxRunGuestCodeNested(pVCpu, &cLoops);
12361
12362 if (rcStrict == VINF_VMX_VMLAUNCH_VMRESUME)
12363 {
12364 Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
12365 continue;
12366 }
12367 if (rcStrict == VINF_VMX_VMEXIT)
12368 {
12369 Assert(!CPUMIsGuestInVmxNonRootMode(pCtx));
12370 continue;
12371 }
12372#endif
12373 break;
12374 }
12375
12376 int const rcLoop = VBOXSTRICTRC_VAL(rcStrict);
12377 switch (rcLoop)
12378 {
12379 case VERR_EM_INTERPRETER: rcStrict = VINF_EM_RAW_EMULATE_INSTR; break;
12380 case VINF_EM_RESET: rcStrict = VINF_EM_TRIPLE_FAULT; break;
12381 }
12382
12383 int rc2 = hmR0VmxExitToRing3(pVCpu, rcStrict);
12384 if (RT_FAILURE(rc2))
12385 {
12386 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
12387 rcStrict = rc2;
12388 }
12389 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12390 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
12391 return rcStrict;
12392}
12393
12394
12395#ifndef HMVMX_USE_FUNCTION_TABLE
12396/**
12397 * Handles a guest VM-exit from hardware-assisted VMX execution.
12398 *
12399 * @returns Strict VBox status code (i.e. informational status codes too).
12400 * @param pVCpu The cross context virtual CPU structure.
12401 * @param pVmxTransient The VMX-transient structure.
12402 */
12403DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
12404{
12405#ifdef DEBUG_ramshankar
12406#define VMEXIT_CALL_RET(a_fSave, a_CallExpr) \
12407 do { \
12408 if (a_fSave != 0) \
12409 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL); \
12410 VBOXSTRICTRC rcStrict = a_CallExpr; \
12411 if (a_fSave != 0) \
12412 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST); \
12413 return rcStrict; \
12414 } while (0)
12415#else
12416# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) return a_CallExpr
12417#endif
12418 uint32_t const uExitReason = pVmxTransient->uExitReason;
12419 switch (uExitReason)
12420 {
12421 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient));
12422 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, hmR0VmxExitEptViolation(pVCpu, pVmxTransient));
12423 case VMX_EXIT_IO_INSTR: VMEXIT_CALL_RET(0, hmR0VmxExitIoInstr(pVCpu, pVmxTransient));
12424 case VMX_EXIT_CPUID: VMEXIT_CALL_RET(0, hmR0VmxExitCpuid(pVCpu, pVmxTransient));
12425 case VMX_EXIT_RDTSC: VMEXIT_CALL_RET(0, hmR0VmxExitRdtsc(pVCpu, pVmxTransient));
12426 case VMX_EXIT_RDTSCP: VMEXIT_CALL_RET(0, hmR0VmxExitRdtscp(pVCpu, pVmxTransient));
12427 case VMX_EXIT_APIC_ACCESS: VMEXIT_CALL_RET(0, hmR0VmxExitApicAccess(pVCpu, pVmxTransient));
12428 case VMX_EXIT_XCPT_OR_NMI: VMEXIT_CALL_RET(0, hmR0VmxExitXcptOrNmi(pVCpu, pVmxTransient));
12429 case VMX_EXIT_MOV_CRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovCRx(pVCpu, pVmxTransient));
12430 case VMX_EXIT_EXT_INT: VMEXIT_CALL_RET(0, hmR0VmxExitExtInt(pVCpu, pVmxTransient));
12431 case VMX_EXIT_INT_WINDOW: VMEXIT_CALL_RET(0, hmR0VmxExitIntWindow(pVCpu, pVmxTransient));
12432 case VMX_EXIT_TPR_BELOW_THRESHOLD: VMEXIT_CALL_RET(0, hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient));
12433 case VMX_EXIT_MWAIT: VMEXIT_CALL_RET(0, hmR0VmxExitMwait(pVCpu, pVmxTransient));
12434 case VMX_EXIT_MONITOR: VMEXIT_CALL_RET(0, hmR0VmxExitMonitor(pVCpu, pVmxTransient));
12435 case VMX_EXIT_TASK_SWITCH: VMEXIT_CALL_RET(0, hmR0VmxExitTaskSwitch(pVCpu, pVmxTransient));
12436 case VMX_EXIT_PREEMPT_TIMER: VMEXIT_CALL_RET(0, hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient));
12437 case VMX_EXIT_RDMSR: VMEXIT_CALL_RET(0, hmR0VmxExitRdmsr(pVCpu, pVmxTransient));
12438 case VMX_EXIT_WRMSR: VMEXIT_CALL_RET(0, hmR0VmxExitWrmsr(pVCpu, pVmxTransient));
12439 case VMX_EXIT_VMCALL: VMEXIT_CALL_RET(0, hmR0VmxExitVmcall(pVCpu, pVmxTransient));
12440 case VMX_EXIT_MOV_DRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovDRx(pVCpu, pVmxTransient));
12441 case VMX_EXIT_HLT: VMEXIT_CALL_RET(0, hmR0VmxExitHlt(pVCpu, pVmxTransient));
12442 case VMX_EXIT_INVD: VMEXIT_CALL_RET(0, hmR0VmxExitInvd(pVCpu, pVmxTransient));
12443 case VMX_EXIT_INVLPG: VMEXIT_CALL_RET(0, hmR0VmxExitInvlpg(pVCpu, pVmxTransient));
12444 case VMX_EXIT_MTF: VMEXIT_CALL_RET(0, hmR0VmxExitMtf(pVCpu, pVmxTransient));
12445 case VMX_EXIT_PAUSE: VMEXIT_CALL_RET(0, hmR0VmxExitPause(pVCpu, pVmxTransient));
12446 case VMX_EXIT_WBINVD: VMEXIT_CALL_RET(0, hmR0VmxExitWbinvd(pVCpu, pVmxTransient));
12447 case VMX_EXIT_XSETBV: VMEXIT_CALL_RET(0, hmR0VmxExitXsetbv(pVCpu, pVmxTransient));
12448 case VMX_EXIT_INVPCID: VMEXIT_CALL_RET(0, hmR0VmxExitInvpcid(pVCpu, pVmxTransient));
12449 case VMX_EXIT_GETSEC: VMEXIT_CALL_RET(0, hmR0VmxExitGetsec(pVCpu, pVmxTransient));
12450 case VMX_EXIT_RDPMC: VMEXIT_CALL_RET(0, hmR0VmxExitRdpmc(pVCpu, pVmxTransient));
12451#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12452 case VMX_EXIT_VMCLEAR: VMEXIT_CALL_RET(0, hmR0VmxExitVmclear(pVCpu, pVmxTransient));
12453 case VMX_EXIT_VMLAUNCH: VMEXIT_CALL_RET(0, hmR0VmxExitVmlaunch(pVCpu, pVmxTransient));
12454 case VMX_EXIT_VMPTRLD: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrld(pVCpu, pVmxTransient));
12455 case VMX_EXIT_VMPTRST: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrst(pVCpu, pVmxTransient));
12456 case VMX_EXIT_VMREAD: VMEXIT_CALL_RET(0, hmR0VmxExitVmread(pVCpu, pVmxTransient));
12457 case VMX_EXIT_VMRESUME: VMEXIT_CALL_RET(0, hmR0VmxExitVmwrite(pVCpu, pVmxTransient));
12458 case VMX_EXIT_VMWRITE: VMEXIT_CALL_RET(0, hmR0VmxExitVmresume(pVCpu, pVmxTransient));
12459 case VMX_EXIT_VMXOFF: VMEXIT_CALL_RET(0, hmR0VmxExitVmxoff(pVCpu, pVmxTransient));
12460 case VMX_EXIT_VMXON: VMEXIT_CALL_RET(0, hmR0VmxExitVmxon(pVCpu, pVmxTransient));
12461 case VMX_EXIT_INVVPID: VMEXIT_CALL_RET(0, hmR0VmxExitInvvpid(pVCpu, pVmxTransient));
12462 case VMX_EXIT_INVEPT: VMEXIT_CALL_RET(0, hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient));
12463#else
12464 case VMX_EXIT_VMCLEAR:
12465 case VMX_EXIT_VMLAUNCH:
12466 case VMX_EXIT_VMPTRLD:
12467 case VMX_EXIT_VMPTRST:
12468 case VMX_EXIT_VMREAD:
12469 case VMX_EXIT_VMRESUME:
12470 case VMX_EXIT_VMWRITE:
12471 case VMX_EXIT_VMXOFF:
12472 case VMX_EXIT_VMXON:
12473 case VMX_EXIT_INVVPID:
12474 case VMX_EXIT_INVEPT:
12475 return hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient);
12476#endif
12477
12478 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pVmxTransient);
12479 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pVmxTransient);
12480 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
12481
12482 case VMX_EXIT_INIT_SIGNAL:
12483 case VMX_EXIT_SIPI:
12484 case VMX_EXIT_IO_SMI:
12485 case VMX_EXIT_SMI:
12486 case VMX_EXIT_ERR_MSR_LOAD:
12487 case VMX_EXIT_ERR_MACHINE_CHECK:
12488 case VMX_EXIT_PML_FULL:
12489 case VMX_EXIT_VIRTUALIZED_EOI:
12490 case VMX_EXIT_GDTR_IDTR_ACCESS:
12491 case VMX_EXIT_LDTR_TR_ACCESS:
12492 case VMX_EXIT_APIC_WRITE:
12493 case VMX_EXIT_RDRAND:
12494 case VMX_EXIT_RSM:
12495 case VMX_EXIT_VMFUNC:
12496 case VMX_EXIT_ENCLS:
12497 case VMX_EXIT_RDSEED:
12498 case VMX_EXIT_XSAVES:
12499 case VMX_EXIT_XRSTORS:
12500 case VMX_EXIT_UMWAIT:
12501 case VMX_EXIT_TPAUSE:
12502 default:
12503 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
12504 }
12505#undef VMEXIT_CALL_RET
12506}
12507#endif /* !HMVMX_USE_FUNCTION_TABLE */
12508
12509
12510#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12511/**
12512 * Handles a nested-guest VM-exit from hardware-assisted VMX execution.
12513 *
12514 * @returns Strict VBox status code (i.e. informational status codes too).
12515 * @param pVCpu The cross context virtual CPU structure.
12516 * @param pVmxTransient The VMX-transient structure.
12517 */
12518DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
12519{
12520 uint32_t const uExitReason = pVmxTransient->uExitReason;
12521 switch (uExitReason)
12522 {
12523 case VMX_EXIT_EPT_MISCONFIG: return hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient);
12524 case VMX_EXIT_EPT_VIOLATION: return hmR0VmxExitEptViolation(pVCpu, pVmxTransient);
12525 case VMX_EXIT_XCPT_OR_NMI: return hmR0VmxExitXcptOrNmiNested(pVCpu, pVmxTransient);
12526 case VMX_EXIT_IO_INSTR: return hmR0VmxExitIoInstrNested(pVCpu, pVmxTransient);
12527 case VMX_EXIT_HLT: return hmR0VmxExitHltNested(pVCpu, pVmxTransient);
12528
12529 /*
12530 * We shouldn't direct host physical interrupts to the nested-guest.
12531 */
12532 case VMX_EXIT_EXT_INT:
12533 return hmR0VmxExitExtInt(pVCpu, pVmxTransient);
12534
12535 /*
12536 * Instructions that cause VM-exits unconditionally or the condition is
12537 * always is taken solely from the guest hypervisor (meaning if the VM-exit
12538 * happens, it's guaranteed to be a nested-guest VM-exit).
12539 *
12540 * - Provides VM-exit instruction length ONLY.
12541 */
12542 case VMX_EXIT_CPUID: /* Unconditional. */
12543 case VMX_EXIT_VMCALL:
12544 case VMX_EXIT_GETSEC:
12545 case VMX_EXIT_INVD:
12546 case VMX_EXIT_XSETBV:
12547 case VMX_EXIT_VMLAUNCH:
12548 case VMX_EXIT_VMRESUME:
12549 case VMX_EXIT_VMXOFF:
12550 case VMX_EXIT_ENCLS: /* Condition specified solely by guest hypervisor. */
12551 case VMX_EXIT_VMFUNC:
12552 return hmR0VmxExitInstrNested(pVCpu, pVmxTransient);
12553
12554 /*
12555 * Instructions that cause VM-exits unconditionally or the condition is
12556 * always is taken solely from the guest hypervisor (meaning if the VM-exit
12557 * happens, it's guaranteed to be a nested-guest VM-exit).
12558 *
12559 * - Provides VM-exit instruction length.
12560 * - Provides VM-exit information.
12561 * - Optionally provides Exit qualification.
12562 *
12563 * Since Exit qualification is 0 for all VM-exits where it is not
12564 * applicable, reading and passing it to the guest should produce
12565 * defined behavior.
12566 *
12567 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
12568 */
12569 case VMX_EXIT_INVEPT: /* Unconditional. */
12570 case VMX_EXIT_INVVPID:
12571 case VMX_EXIT_VMCLEAR:
12572 case VMX_EXIT_VMPTRLD:
12573 case VMX_EXIT_VMPTRST:
12574 case VMX_EXIT_VMXON:
12575 case VMX_EXIT_GDTR_IDTR_ACCESS: /* Condition specified solely by guest hypervisor. */
12576 case VMX_EXIT_LDTR_TR_ACCESS:
12577 case VMX_EXIT_RDRAND:
12578 case VMX_EXIT_RDSEED:
12579 case VMX_EXIT_XSAVES:
12580 case VMX_EXIT_XRSTORS:
12581 case VMX_EXIT_UMWAIT:
12582 case VMX_EXIT_TPAUSE:
12583 return hmR0VmxExitInstrWithInfoNested(pVCpu, pVmxTransient);
12584
12585 case VMX_EXIT_RDTSC: return hmR0VmxExitRdtscNested(pVCpu, pVmxTransient);
12586 case VMX_EXIT_RDTSCP: return hmR0VmxExitRdtscpNested(pVCpu, pVmxTransient);
12587 case VMX_EXIT_RDMSR: return hmR0VmxExitRdmsrNested(pVCpu, pVmxTransient);
12588 case VMX_EXIT_WRMSR: return hmR0VmxExitWrmsrNested(pVCpu, pVmxTransient);
12589 case VMX_EXIT_INVLPG: return hmR0VmxExitInvlpgNested(pVCpu, pVmxTransient);
12590 case VMX_EXIT_INVPCID: return hmR0VmxExitInvpcidNested(pVCpu, pVmxTransient);
12591 case VMX_EXIT_TASK_SWITCH: return hmR0VmxExitTaskSwitchNested(pVCpu, pVmxTransient);
12592 case VMX_EXIT_WBINVD: return hmR0VmxExitWbinvdNested(pVCpu, pVmxTransient);
12593 case VMX_EXIT_MTF: return hmR0VmxExitMtfNested(pVCpu, pVmxTransient);
12594 case VMX_EXIT_APIC_ACCESS: return hmR0VmxExitApicAccessNested(pVCpu, pVmxTransient);
12595 case VMX_EXIT_APIC_WRITE: return hmR0VmxExitApicWriteNested(pVCpu, pVmxTransient);
12596 case VMX_EXIT_VIRTUALIZED_EOI: return hmR0VmxExitVirtEoiNested(pVCpu, pVmxTransient);
12597 case VMX_EXIT_MOV_CRX: return hmR0VmxExitMovCRxNested(pVCpu, pVmxTransient);
12598 case VMX_EXIT_INT_WINDOW: return hmR0VmxExitIntWindowNested(pVCpu, pVmxTransient);
12599 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindowNested(pVCpu, pVmxTransient);
12600 case VMX_EXIT_TPR_BELOW_THRESHOLD: return hmR0VmxExitTprBelowThresholdNested(pVCpu, pVmxTransient);
12601 case VMX_EXIT_MWAIT: return hmR0VmxExitMwaitNested(pVCpu, pVmxTransient);
12602 case VMX_EXIT_MONITOR: return hmR0VmxExitMonitorNested(pVCpu, pVmxTransient);
12603 case VMX_EXIT_PAUSE: return hmR0VmxExitPauseNested(pVCpu, pVmxTransient);
12604
12605 case VMX_EXIT_PREEMPT_TIMER:
12606 {
12607 /** @todo NSTVMX: Preempt timer. */
12608 return hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient);
12609 }
12610
12611 case VMX_EXIT_MOV_DRX: return hmR0VmxExitMovDRxNested(pVCpu, pVmxTransient);
12612 case VMX_EXIT_RDPMC: return hmR0VmxExitRdpmcNested(pVCpu, pVmxTransient);
12613
12614 case VMX_EXIT_VMREAD:
12615 case VMX_EXIT_VMWRITE: return hmR0VmxExitVmreadVmwriteNested(pVCpu, pVmxTransient);
12616
12617 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFaultNested(pVCpu, pVmxTransient);
12618 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestStateNested(pVCpu, pVmxTransient);
12619
12620 case VMX_EXIT_INIT_SIGNAL:
12621 case VMX_EXIT_SIPI:
12622 case VMX_EXIT_IO_SMI:
12623 case VMX_EXIT_SMI:
12624 case VMX_EXIT_ERR_MSR_LOAD:
12625 case VMX_EXIT_ERR_MACHINE_CHECK:
12626 case VMX_EXIT_PML_FULL:
12627 case VMX_EXIT_RSM:
12628 default:
12629 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
12630 }
12631}
12632#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
12633
12634
12635/** @name VM-exit helpers.
12636 * @{
12637 */
12638/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12639/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= VM-exit helpers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
12640/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12641
12642/** Macro for VM-exits called unexpectedly. */
12643#define HMVMX_UNEXPECTED_EXIT_RET(a_pVCpu, a_HmError) \
12644 do { \
12645 (a_pVCpu)->hm.s.u32HMError = (a_HmError); \
12646 return VERR_VMX_UNEXPECTED_EXIT; \
12647 } while (0)
12648
12649#ifdef VBOX_STRICT
12650/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
12651# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
12652 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
12653
12654# define HMVMX_ASSERT_PREEMPT_CPUID() \
12655 do { \
12656 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
12657 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
12658 } while (0)
12659
12660# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12661 do { \
12662 AssertPtr((a_pVCpu)); \
12663 AssertPtr((a_pVmxTransient)); \
12664 Assert((a_pVmxTransient)->fVMEntryFailed == false); \
12665 Assert((a_pVmxTransient)->pVmcsInfo); \
12666 Assert(ASMIntAreEnabled()); \
12667 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
12668 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
12669 Log4Func(("vcpu[%RU32]\n", (a_pVCpu)->idCpu)); \
12670 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
12671 if (VMMR0IsLogFlushDisabled((a_pVCpu))) \
12672 HMVMX_ASSERT_PREEMPT_CPUID(); \
12673 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
12674 } while (0)
12675
12676# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12677 do { \
12678 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); \
12679 Assert((a_pVmxTransient)->fIsNestedGuest); \
12680 } while (0)
12681
12682# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12683 do { \
12684 Log4Func(("\n")); \
12685 } while (0)
12686#else
12687# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12688 do { \
12689 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
12690 NOREF((a_pVCpu)); NOREF((a_pVmxTransient)); \
12691 } while (0)
12692
12693# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12694 do { HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); } while (0)
12695
12696# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) do { } while (0)
12697#endif
12698
12699#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12700/** Macro that does the necessary privilege checks and intercepted VM-exits for
12701 * guests that attempted to execute a VMX instruction. */
12702# define HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(a_pVCpu, a_uExitReason) \
12703 do \
12704 { \
12705 VBOXSTRICTRC rcStrictTmp = hmR0VmxCheckExitDueToVmxInstr((a_pVCpu), (a_uExitReason)); \
12706 if (rcStrictTmp == VINF_SUCCESS) \
12707 { /* likely */ } \
12708 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
12709 { \
12710 Assert((a_pVCpu)->hm.s.Event.fPending); \
12711 Log4Func(("Privilege checks failed -> %#x\n", VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo))); \
12712 return VINF_SUCCESS; \
12713 } \
12714 else \
12715 { \
12716 int rcTmp = VBOXSTRICTRC_VAL(rcStrictTmp); \
12717 AssertMsgFailedReturn(("Unexpected failure. rc=%Rrc", rcTmp), rcTmp); \
12718 } \
12719 } while (0)
12720
12721/** Macro that decodes a memory operand for an VM-exit caused by an instruction. */
12722# define HMVMX_DECODE_MEM_OPERAND(a_pVCpu, a_uExitInstrInfo, a_uExitQual, a_enmMemAccess, a_pGCPtrEffAddr) \
12723 do \
12724 { \
12725 VBOXSTRICTRC rcStrictTmp = hmR0VmxDecodeMemOperand((a_pVCpu), (a_uExitInstrInfo), (a_uExitQual), (a_enmMemAccess), \
12726 (a_pGCPtrEffAddr)); \
12727 if (rcStrictTmp == VINF_SUCCESS) \
12728 { /* likely */ } \
12729 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
12730 { \
12731 uint8_t const uXcptTmp = VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo); \
12732 Log4Func(("Memory operand decoding failed, raising xcpt %#x\n", uXcptTmp)); \
12733 NOREF(uXcptTmp); \
12734 return VINF_SUCCESS; \
12735 } \
12736 else \
12737 { \
12738 Log4Func(("hmR0VmxDecodeMemOperand failed. rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrictTmp))); \
12739 return rcStrictTmp; \
12740 } \
12741 } while (0)
12742#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
12743
12744
12745/**
12746 * Advances the guest RIP by the specified number of bytes.
12747 *
12748 * @param pVCpu The cross context virtual CPU structure.
12749 * @param cbInstr Number of bytes to advance the RIP by.
12750 *
12751 * @remarks No-long-jump zone!!!
12752 */
12753DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPU pVCpu, uint32_t cbInstr)
12754{
12755 /* Advance the RIP. */
12756 pVCpu->cpum.GstCtx.rip += cbInstr;
12757 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
12758
12759 /* Update interrupt inhibition. */
12760 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
12761 && pVCpu->cpum.GstCtx.rip != EMGetInhibitInterruptsPC(pVCpu))
12762 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
12763}
12764
12765
12766/**
12767 * Advances the guest RIP after reading it from the VMCS.
12768 *
12769 * @returns VBox status code, no informational status codes.
12770 * @param pVCpu The cross context virtual CPU structure.
12771 * @param pVmxTransient The VMX-transient structure.
12772 *
12773 * @remarks No-long-jump zone!!!
12774 */
12775static int hmR0VmxAdvanceGuestRip(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
12776{
12777 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12778 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
12779 AssertRCReturn(rc, rc);
12780
12781 hmR0VmxAdvanceGuestRipBy(pVCpu, pVmxTransient->cbInstr);
12782 return VINF_SUCCESS;
12783}
12784
12785
12786/**
12787 * Handle a condition that occurred while delivering an event through the guest or
12788 * nested-guest IDT.
12789 *
12790 * @returns Strict VBox status code (i.e. informational status codes too).
12791 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
12792 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
12793 * to continue execution of the guest which will delivery the \#DF.
12794 * @retval VINF_EM_RESET if we detected a triple-fault condition.
12795 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
12796 *
12797 * @param pVCpu The cross context virtual CPU structure.
12798 * @param pVmxTransient The VMX-transient structure.
12799 *
12800 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
12801 * Additionally, HMVMX_READ_EXIT_QUALIFICATION is required if the VM-exit
12802 * is due to an EPT violation, PML full or SPP-related event.
12803 *
12804 * @remarks No-long-jump zone!!!
12805 */
12806static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
12807{
12808 Assert(!pVCpu->hm.s.Event.fPending);
12809 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
12810 if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
12811 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
12812 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
12813 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_EXIT_QUALIFICATION);
12814
12815 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
12816 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
12817 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo;
12818 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
12819 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo))
12820 {
12821 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo);
12822 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo);
12823
12824 /*
12825 * If the event was a software interrupt (generated with INT n) or a software exception
12826 * (generated by INT3/INTO) or a privileged software exception (generated by INT1), we
12827 * can handle the VM-exit and continue guest execution which will re-execute the
12828 * instruction rather than re-injecting the exception, as that can cause premature
12829 * trips to ring-3 before injection and involve TRPM which currently has no way of
12830 * storing that these exceptions were caused by these instructions (ICEBP's #DB poses
12831 * the problem).
12832 */
12833 IEMXCPTRAISE enmRaise;
12834 IEMXCPTRAISEINFO fRaiseInfo;
12835 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
12836 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
12837 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
12838 {
12839 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
12840 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
12841 }
12842 else if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo))
12843 {
12844 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
12845 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo);
12846 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT);
12847
12848 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
12849 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
12850
12851 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo);
12852
12853 /* Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF(). */
12854 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
12855 {
12856 pVmxTransient->fVectoringPF = true;
12857 enmRaise = IEMXCPTRAISE_PREV_EVENT;
12858 }
12859 }
12860 else
12861 {
12862 /*
12863 * If an exception or hardware interrupt delivery caused an EPT violation/misconfig or APIC access
12864 * VM-exit, then the VM-exit interruption-information will not be valid and we end up here.
12865 * It is sufficient to reflect the original event to the guest after handling the VM-exit.
12866 */
12867 Assert( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
12868 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
12869 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
12870 enmRaise = IEMXCPTRAISE_PREV_EVENT;
12871 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
12872 }
12873
12874 /*
12875 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
12876 * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
12877 * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
12878 * subsequent VM-entry would fail, see @bugref{7445}.
12879 *
12880 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception".
12881 */
12882 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
12883 && enmRaise == IEMXCPTRAISE_PREV_EVENT
12884 && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
12885 && CPUMIsGuestNmiBlocking(pVCpu))
12886 {
12887 CPUMSetGuestNmiBlocking(pVCpu, false);
12888 }
12889
12890 switch (enmRaise)
12891 {
12892 case IEMXCPTRAISE_CURRENT_XCPT:
12893 {
12894 Log4Func(("IDT: Pending secondary Xcpt: idtinfo=%#RX64 exitinfo=%#RX64\n", uIdtVectorInfo, uExitIntInfo));
12895 Assert(rcStrict == VINF_SUCCESS);
12896 break;
12897 }
12898
12899 case IEMXCPTRAISE_PREV_EVENT:
12900 {
12901 uint32_t u32ErrCode;
12902 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo))
12903 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
12904 else
12905 u32ErrCode = 0;
12906
12907 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
12908 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflect);
12909 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(uIdtVectorInfo), 0 /* cbInstr */,
12910 u32ErrCode, pVCpu->cpum.GstCtx.cr2);
12911
12912 Log4Func(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntInfo,
12913 pVCpu->hm.s.Event.u32ErrCode));
12914 Assert(rcStrict == VINF_SUCCESS);
12915 break;
12916 }
12917
12918 case IEMXCPTRAISE_REEXEC_INSTR:
12919 Assert(rcStrict == VINF_SUCCESS);
12920 break;
12921
12922 case IEMXCPTRAISE_DOUBLE_FAULT:
12923 {
12924 /*
12925 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
12926 * second #PF as a guest #PF (and not a shadow #PF) and needs to be converted into a #DF.
12927 */
12928 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
12929 {
12930 pVmxTransient->fVectoringDoublePF = true;
12931 Log4Func(("IDT: Vectoring double #PF %#RX64 cr2=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo,
12932 pVCpu->cpum.GstCtx.cr2));
12933 rcStrict = VINF_SUCCESS;
12934 }
12935 else
12936 {
12937 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectConvertDF);
12938 hmR0VmxSetPendingXcptDF(pVCpu);
12939 Log4Func(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntInfo,
12940 uIdtVector, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
12941 rcStrict = VINF_HM_DOUBLE_FAULT;
12942 }
12943 break;
12944 }
12945
12946 case IEMXCPTRAISE_TRIPLE_FAULT:
12947 {
12948 Log4Func(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector,
12949 VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
12950 rcStrict = VINF_EM_RESET;
12951 break;
12952 }
12953
12954 case IEMXCPTRAISE_CPU_HANG:
12955 {
12956 Log4Func(("IDT: Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", fRaiseInfo));
12957 rcStrict = VERR_EM_GUEST_CPU_HANG;
12958 break;
12959 }
12960
12961 default:
12962 {
12963 AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
12964 rcStrict = VERR_VMX_IPE_2;
12965 break;
12966 }
12967 }
12968 }
12969 else if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
12970 && !CPUMIsGuestNmiBlocking(pVCpu))
12971 {
12972 if ( VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)
12973 && VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo) != X86_XCPT_DF
12974 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(uExitIntInfo))
12975 {
12976 /*
12977 * Execution of IRET caused a fault when NMI blocking was in effect (i.e we're in
12978 * the guest or nested-guest NMI handler). We need to set the block-by-NMI field so
12979 * that NMIs remain blocked until the IRET execution is completed.
12980 *
12981 * See Intel spec. 31.7.1.2 "Resuming Guest Software After Handling An Exception".
12982 */
12983 CPUMSetGuestNmiBlocking(pVCpu, true);
12984 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
12985 }
12986 else if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
12987 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
12988 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
12989 {
12990 /*
12991 * Execution of IRET caused an EPT violation, page-modification log-full event or
12992 * SPP-related event VM-exit when NMI blocking was in effect (i.e. we're in the
12993 * guest or nested-guest NMI handler). We need to set the block-by-NMI field so
12994 * that NMIs remain blocked until the IRET execution is completed.
12995 *
12996 * See Intel spec. 27.2.3 "Information about NMI unblocking due to IRET"
12997 */
12998 if (VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(pVmxTransient->uExitQual))
12999 {
13000 CPUMSetGuestNmiBlocking(pVCpu, true);
13001 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13002 }
13003 }
13004 }
13005
13006 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
13007 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
13008 return rcStrict;
13009}
13010
13011
13012#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13013/**
13014 * Perform the relevant VMX instruction checks for VM-exits that occurred due to the
13015 * guest attempting to execute a VMX instruction.
13016 *
13017 * @returns Strict VBox status code (i.e. informational status codes too).
13018 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13019 * @retval VINF_HM_PENDING_XCPT if an exception was raised.
13020 *
13021 * @param pVCpu The cross context virtual CPU structure.
13022 * @param uExitReason The VM-exit reason.
13023 *
13024 * @todo NSTVMX: Document other error codes when VM-exit is implemented.
13025 * @remarks No-long-jump zone!!!
13026 */
13027static VBOXSTRICTRC hmR0VmxCheckExitDueToVmxInstr(PVMCPU pVCpu, uint32_t uExitReason)
13028{
13029 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS
13030 | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
13031
13032 /*
13033 * The physical CPU would have already checked the CPU mode/code segment.
13034 * We shall just assert here for paranoia.
13035 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
13036 */
13037 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13038 Assert( !CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx)
13039 || CPUMIsGuestIn64BitCodeEx(&pVCpu->cpum.GstCtx));
13040
13041 if (uExitReason == VMX_EXIT_VMXON)
13042 {
13043 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
13044
13045 /*
13046 * We check CR4.VMXE because it is required to be always set while in VMX operation
13047 * by physical CPUs and our CR4 read-shadow is only consulted when executing specific
13048 * instructions (CLTS, LMSW, MOV CR, and SMSW) and thus doesn't affect CPU operation
13049 * otherwise (i.e. physical CPU won't automatically #UD if Cr4Shadow.VMXE is 0).
13050 */
13051 if (!CPUMIsGuestVmxEnabled(&pVCpu->cpum.GstCtx))
13052 {
13053 Log4Func(("CR4.VMXE is not set -> #UD\n"));
13054 hmR0VmxSetPendingXcptUD(pVCpu);
13055 return VINF_HM_PENDING_XCPT;
13056 }
13057 }
13058 else if (!CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx))
13059 {
13060 /*
13061 * The guest has not entered VMX operation but attempted to execute a VMX instruction
13062 * (other than VMXON), we need to raise a #UD.
13063 */
13064 Log4Func(("Not in VMX root mode -> #UD\n"));
13065 hmR0VmxSetPendingXcptUD(pVCpu);
13066 return VINF_HM_PENDING_XCPT;
13067 }
13068
13069 /* All other checks (including VM-exit intercepts) are handled by IEM instruction emulation. */
13070 return VINF_SUCCESS;
13071}
13072
13073
13074/**
13075 * Decodes the memory operand of an instruction that caused a VM-exit.
13076 *
13077 * The Exit qualification field provides the displacement field for memory
13078 * operand instructions, if any.
13079 *
13080 * @returns Strict VBox status code (i.e. informational status codes too).
13081 * @retval VINF_SUCCESS if the operand was successfully decoded.
13082 * @retval VINF_HM_PENDING_XCPT if an exception was raised while decoding the
13083 * operand.
13084 * @param pVCpu The cross context virtual CPU structure.
13085 * @param uExitInstrInfo The VM-exit instruction information field.
13086 * @param enmMemAccess The memory operand's access type (read or write).
13087 * @param GCPtrDisp The instruction displacement field, if any. For
13088 * RIP-relative addressing pass RIP + displacement here.
13089 * @param pGCPtrMem Where to store the effective destination memory address.
13090 *
13091 * @remarks Warning! This function ASSUMES the instruction cannot be used in real or
13092 * virtual-8086 mode hence skips those checks while verifying if the
13093 * segment is valid.
13094 */
13095static VBOXSTRICTRC hmR0VmxDecodeMemOperand(PVMCPU pVCpu, uint32_t uExitInstrInfo, RTGCPTR GCPtrDisp, VMXMEMACCESS enmMemAccess,
13096 PRTGCPTR pGCPtrMem)
13097{
13098 Assert(pGCPtrMem);
13099 Assert(!CPUMIsGuestInRealOrV86Mode(pVCpu));
13100 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_EFER
13101 | CPUMCTX_EXTRN_CR0);
13102
13103 static uint64_t const s_auAddrSizeMasks[] = { UINT64_C(0xffff), UINT64_C(0xffffffff), UINT64_C(0xffffffffffffffff) };
13104 static uint64_t const s_auAccessSizeMasks[] = { sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t) };
13105 AssertCompile(RT_ELEMENTS(s_auAccessSizeMasks) == RT_ELEMENTS(s_auAddrSizeMasks));
13106
13107 VMXEXITINSTRINFO ExitInstrInfo;
13108 ExitInstrInfo.u = uExitInstrInfo;
13109 uint8_t const uAddrSize = ExitInstrInfo.All.u3AddrSize;
13110 uint8_t const iSegReg = ExitInstrInfo.All.iSegReg;
13111 bool const fIdxRegValid = !ExitInstrInfo.All.fIdxRegInvalid;
13112 uint8_t const iIdxReg = ExitInstrInfo.All.iIdxReg;
13113 uint8_t const uScale = ExitInstrInfo.All.u2Scaling;
13114 bool const fBaseRegValid = !ExitInstrInfo.All.fBaseRegInvalid;
13115 uint8_t const iBaseReg = ExitInstrInfo.All.iBaseReg;
13116 bool const fIsMemOperand = !ExitInstrInfo.All.fIsRegOperand;
13117 bool const fIsLongMode = CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx);
13118
13119 /*
13120 * Validate instruction information.
13121 * This shouldn't happen on real hardware but useful while testing our nested hardware-virtualization code.
13122 */
13123 AssertLogRelMsgReturn(uAddrSize < RT_ELEMENTS(s_auAddrSizeMasks),
13124 ("Invalid address size. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_1);
13125 AssertLogRelMsgReturn(iSegReg < X86_SREG_COUNT,
13126 ("Invalid segment register. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_2);
13127 AssertLogRelMsgReturn(fIsMemOperand,
13128 ("Expected memory operand. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_3);
13129
13130 /*
13131 * Compute the complete effective address.
13132 *
13133 * See AMD instruction spec. 1.4.2 "SIB Byte Format"
13134 * See AMD spec. 4.5.2 "Segment Registers".
13135 */
13136 RTGCPTR GCPtrMem = GCPtrDisp;
13137 if (fBaseRegValid)
13138 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iBaseReg].u64;
13139 if (fIdxRegValid)
13140 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iIdxReg].u64 << uScale;
13141
13142 RTGCPTR const GCPtrOff = GCPtrMem;
13143 if ( !fIsLongMode
13144 || iSegReg >= X86_SREG_FS)
13145 GCPtrMem += pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
13146 GCPtrMem &= s_auAddrSizeMasks[uAddrSize];
13147
13148 /*
13149 * Validate effective address.
13150 * See AMD spec. 4.5.3 "Segment Registers in 64-Bit Mode".
13151 */
13152 uint8_t const cbAccess = s_auAccessSizeMasks[uAddrSize];
13153 Assert(cbAccess > 0);
13154 if (fIsLongMode)
13155 {
13156 if (X86_IS_CANONICAL(GCPtrMem))
13157 {
13158 *pGCPtrMem = GCPtrMem;
13159 return VINF_SUCCESS;
13160 }
13161
13162 /** @todo r=ramshankar: We should probably raise \#SS or \#GP. See AMD spec. 4.12.2
13163 * "Data Limit Checks in 64-bit Mode". */
13164 Log4Func(("Long mode effective address is not canonical GCPtrMem=%#RX64\n", GCPtrMem));
13165 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13166 return VINF_HM_PENDING_XCPT;
13167 }
13168
13169 /*
13170 * This is a watered down version of iemMemApplySegment().
13171 * Parts that are not applicable for VMX instructions like real-or-v8086 mode
13172 * and segment CPL/DPL checks are skipped.
13173 */
13174 RTGCPTR32 const GCPtrFirst32 = (RTGCPTR32)GCPtrOff;
13175 RTGCPTR32 const GCPtrLast32 = GCPtrFirst32 + cbAccess - 1;
13176 PCCPUMSELREG pSel = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
13177
13178 /* Check if the segment is present and usable. */
13179 if ( pSel->Attr.n.u1Present
13180 && !pSel->Attr.n.u1Unusable)
13181 {
13182 Assert(pSel->Attr.n.u1DescType);
13183 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
13184 {
13185 /* Check permissions for the data segment. */
13186 if ( enmMemAccess == VMXMEMACCESS_WRITE
13187 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE))
13188 {
13189 Log4Func(("Data segment access invalid. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13190 hmR0VmxSetPendingXcptGP(pVCpu, iSegReg);
13191 return VINF_HM_PENDING_XCPT;
13192 }
13193
13194 /* Check limits if it's a normal data segment. */
13195 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
13196 {
13197 if ( GCPtrFirst32 > pSel->u32Limit
13198 || GCPtrLast32 > pSel->u32Limit)
13199 {
13200 Log4Func(("Data segment limit exceeded. "
13201 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13202 GCPtrLast32, pSel->u32Limit));
13203 if (iSegReg == X86_SREG_SS)
13204 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13205 else
13206 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13207 return VINF_HM_PENDING_XCPT;
13208 }
13209 }
13210 else
13211 {
13212 /* Check limits if it's an expand-down data segment.
13213 Note! The upper boundary is defined by the B bit, not the G bit! */
13214 if ( GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
13215 || GCPtrLast32 > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
13216 {
13217 Log4Func(("Expand-down data segment limit exceeded. "
13218 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13219 GCPtrLast32, pSel->u32Limit));
13220 if (iSegReg == X86_SREG_SS)
13221 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13222 else
13223 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13224 return VINF_HM_PENDING_XCPT;
13225 }
13226 }
13227 }
13228 else
13229 {
13230 /* Check permissions for the code segment. */
13231 if ( enmMemAccess == VMXMEMACCESS_WRITE
13232 || ( enmMemAccess == VMXMEMACCESS_READ
13233 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)))
13234 {
13235 Log4Func(("Code segment access invalid. Attr=%#RX32\n", pSel->Attr.u));
13236 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13237 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13238 return VINF_HM_PENDING_XCPT;
13239 }
13240
13241 /* Check limits for the code segment (normal/expand-down not applicable for code segments). */
13242 if ( GCPtrFirst32 > pSel->u32Limit
13243 || GCPtrLast32 > pSel->u32Limit)
13244 {
13245 Log4Func(("Code segment limit exceeded. GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n",
13246 GCPtrFirst32, GCPtrLast32, pSel->u32Limit));
13247 if (iSegReg == X86_SREG_SS)
13248 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13249 else
13250 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13251 return VINF_HM_PENDING_XCPT;
13252 }
13253 }
13254 }
13255 else
13256 {
13257 Log4Func(("Not present or unusable segment. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13258 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13259 return VINF_HM_PENDING_XCPT;
13260 }
13261
13262 *pGCPtrMem = GCPtrMem;
13263 return VINF_SUCCESS;
13264}
13265#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13266
13267
13268/**
13269 * VM-exit helper for LMSW.
13270 */
13271static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst)
13272{
13273 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13274 AssertRCReturn(rc, rc);
13275
13276 VBOXSTRICTRC rcStrict = IEMExecDecodedLmsw(pVCpu, cbInstr, uMsw, GCPtrEffDst);
13277 AssertMsg( rcStrict == VINF_SUCCESS
13278 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13279
13280 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13281 if (rcStrict == VINF_IEM_RAISED_XCPT)
13282 {
13283 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13284 rcStrict = VINF_SUCCESS;
13285 }
13286
13287 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
13288 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13289 return rcStrict;
13290}
13291
13292
13293/**
13294 * VM-exit helper for CLTS.
13295 */
13296static VBOXSTRICTRC hmR0VmxExitClts(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
13297{
13298 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13299 AssertRCReturn(rc, rc);
13300
13301 VBOXSTRICTRC rcStrict = IEMExecDecodedClts(pVCpu, cbInstr);
13302 AssertMsg( rcStrict == VINF_SUCCESS
13303 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13304
13305 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13306 if (rcStrict == VINF_IEM_RAISED_XCPT)
13307 {
13308 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13309 rcStrict = VINF_SUCCESS;
13310 }
13311
13312 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
13313 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13314 return rcStrict;
13315}
13316
13317
13318/**
13319 * VM-exit helper for MOV from CRx (CRx read).
13320 */
13321static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13322{
13323 Assert(iCrReg < 16);
13324 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
13325
13326 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13327 AssertRCReturn(rc, rc);
13328
13329 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxRead(pVCpu, cbInstr, iGReg, iCrReg);
13330 AssertMsg( rcStrict == VINF_SUCCESS
13331 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13332
13333 if (iGReg == X86_GREG_xSP)
13334 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_RSP);
13335 else
13336 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13337#ifdef VBOX_WITH_STATISTICS
13338 switch (iCrReg)
13339 {
13340 case 0: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Read); break;
13341 case 2: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Read); break;
13342 case 3: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Read); break;
13343 case 4: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Read); break;
13344 case 8: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Read); break;
13345 }
13346#endif
13347 Log4Func(("CR%d Read access rcStrict=%Rrc\n", iCrReg, VBOXSTRICTRC_VAL(rcStrict)));
13348 return rcStrict;
13349}
13350
13351
13352/**
13353 * VM-exit helper for MOV to CRx (CRx write).
13354 */
13355static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13356{
13357 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13358 AssertRCReturn(rc, rc);
13359
13360 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, cbInstr, iCrReg, iGReg);
13361 AssertMsg( rcStrict == VINF_SUCCESS
13362 || rcStrict == VINF_IEM_RAISED_XCPT
13363 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13364
13365 switch (iCrReg)
13366 {
13367 case 0:
13368 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13369 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Write);
13370 Log4Func(("CR0 write. rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr0));
13371 break;
13372
13373 case 2:
13374 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Write);
13375 /* Nothing to do here, CR2 it's not part of the VMCS. */
13376 break;
13377
13378 case 3:
13379 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR3);
13380 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Write);
13381 Log4Func(("CR3 write. rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr3));
13382 break;
13383
13384 case 4:
13385 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR4);
13386 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Write);
13387 Log4Func(("CR4 write. rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n", VBOXSTRICTRC_VAL(rcStrict),
13388 pVCpu->cpum.GstCtx.cr4, pVCpu->hm.s.fLoadSaveGuestXcr0));
13389 break;
13390
13391 case 8:
13392 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged,
13393 HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_APIC_TPR);
13394 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Write);
13395 break;
13396
13397 default:
13398 AssertMsgFailed(("Invalid CRx register %#x\n", iCrReg));
13399 break;
13400 }
13401
13402 if (rcStrict == VINF_IEM_RAISED_XCPT)
13403 {
13404 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13405 rcStrict = VINF_SUCCESS;
13406 }
13407 return rcStrict;
13408}
13409
13410
13411/**
13412 * VM-exit exception handler for \#PF (Page-fault exception).
13413 *
13414 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13415 */
13416static VBOXSTRICTRC hmR0VmxExitXcptPF(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13417{
13418 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13419 PVM pVM = pVCpu->CTX_SUFF(pVM);
13420 hmR0VmxReadExitQualVmcs(pVmxTransient);
13421
13422 if (!pVM->hm.s.fNestedPaging)
13423 { /* likely */ }
13424 else
13425 {
13426#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13427 Assert(pVmxTransient->fIsNestedGuest || pVCpu->hm.s.fUsingDebugLoop);
13428#endif
13429 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13430 if (!pVmxTransient->fVectoringDoublePF)
13431 {
13432 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13433 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual);
13434 }
13435 else
13436 {
13437 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13438 Assert(!pVmxTransient->fIsNestedGuest);
13439 hmR0VmxSetPendingXcptDF(pVCpu);
13440 Log4Func(("Pending #DF due to vectoring #PF w/ NestedPaging\n"));
13441 }
13442 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13443 return VINF_SUCCESS;
13444 }
13445
13446 Assert(!pVmxTransient->fIsNestedGuest);
13447
13448 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
13449 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
13450 if (pVmxTransient->fVectoringPF)
13451 {
13452 Assert(pVCpu->hm.s.Event.fPending);
13453 return VINF_EM_RAW_INJECT_TRPM_EVENT;
13454 }
13455
13456 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13457 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13458 AssertRCReturn(rc, rc);
13459
13460 Log4Func(("#PF: cr2=%#RX64 cs:rip=%#04x:%#RX64 uErrCode %#RX32 cr3=%#RX64\n", pVmxTransient->uExitQual, pCtx->cs.Sel,
13461 pCtx->rip, pVmxTransient->uExitIntErrorCode, pCtx->cr3));
13462
13463 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQual, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
13464 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pCtx), (RTGCPTR)pVmxTransient->uExitQual);
13465
13466 Log4Func(("#PF: rc=%Rrc\n", rc));
13467 if (rc == VINF_SUCCESS)
13468 {
13469 /*
13470 * This is typically a shadow page table sync or a MMIO instruction. But we may have
13471 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
13472 */
13473 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13474 TRPMResetTrap(pVCpu);
13475 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
13476 return rc;
13477 }
13478
13479 if (rc == VINF_EM_RAW_GUEST_TRAP)
13480 {
13481 if (!pVmxTransient->fVectoringDoublePF)
13482 {
13483 /* It's a guest page fault and needs to be reflected to the guest. */
13484 uint32_t uGstErrorCode = TRPMGetErrorCode(pVCpu);
13485 TRPMResetTrap(pVCpu);
13486 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
13487 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13488 uGstErrorCode, pVmxTransient->uExitQual);
13489 }
13490 else
13491 {
13492 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13493 TRPMResetTrap(pVCpu);
13494 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
13495 hmR0VmxSetPendingXcptDF(pVCpu);
13496 Log4Func(("#PF: Pending #DF due to vectoring #PF\n"));
13497 }
13498
13499 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13500 return VINF_SUCCESS;
13501 }
13502
13503 TRPMResetTrap(pVCpu);
13504 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
13505 return rc;
13506}
13507
13508
13509/**
13510 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
13511 *
13512 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13513 */
13514static VBOXSTRICTRC hmR0VmxExitXcptMF(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13515{
13516 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13517 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
13518
13519 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0);
13520 AssertRCReturn(rc, rc);
13521
13522 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_NE))
13523 {
13524 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
13525 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
13526
13527 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
13528 * provides VM-exit instruction length. If this causes problem later,
13529 * disassemble the instruction like it's done on AMD-V. */
13530 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
13531 AssertRCReturn(rc2, rc2);
13532 return rc;
13533 }
13534
13535 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13536 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13537 return VINF_SUCCESS;
13538}
13539
13540
13541/**
13542 * VM-exit exception handler for \#BP (Breakpoint exception).
13543 *
13544 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13545 */
13546static VBOXSTRICTRC hmR0VmxExitXcptBP(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13547{
13548 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13549 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
13550
13551 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13552 AssertRCReturn(rc, rc);
13553
13554 if (!pVmxTransient->fIsNestedGuest)
13555 rc = DBGFRZTrap03Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(&pVCpu->cpum.GstCtx));
13556 else
13557 rc = VINF_EM_RAW_GUEST_TRAP;
13558 if (rc == VINF_EM_RAW_GUEST_TRAP)
13559 {
13560 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13561 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13562 }
13563
13564 Assert(rc == VINF_SUCCESS || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_EM_DBG_BREAKPOINT);
13565 return rc;
13566}
13567
13568
13569/**
13570 * VM-exit exception handler for \#AC (Alignment-check exception).
13571 *
13572 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13573 */
13574static VBOXSTRICTRC hmR0VmxExitXcptAC(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13575{
13576 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13577 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC);
13578
13579 /* Re-inject it. We'll detect any nesting before getting here. */
13580 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13581 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13582 return VINF_SUCCESS;
13583}
13584
13585
13586/**
13587 * VM-exit exception handler for \#DB (Debug exception).
13588 *
13589 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13590 */
13591static VBOXSTRICTRC hmR0VmxExitXcptDB(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13592{
13593 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13594 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
13595
13596 /*
13597 * Get the DR6-like values from the Exit qualification and pass it to DBGF for processing.
13598 */
13599 hmR0VmxReadExitQualVmcs(pVmxTransient);
13600
13601 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
13602 uint64_t const uDR6 = X86_DR6_INIT_VAL
13603 | (pVmxTransient->uExitQual & ( X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3
13604 | X86_DR6_BD | X86_DR6_BS));
13605
13606 int rc;
13607 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13608 if (!pVmxTransient->fIsNestedGuest)
13609 rc = DBGFRZTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
13610 else
13611 rc = VINF_EM_RAW_GUEST_TRAP;
13612 Log6Func(("rc=%Rrc\n", rc));
13613 if (rc == VINF_EM_RAW_GUEST_TRAP)
13614 {
13615 /*
13616 * The exception was for the guest. Update DR6, DR7.GD and
13617 * IA32_DEBUGCTL.LBR before forwarding it.
13618 * See Intel spec. 27.1 "Architectural State before a VM-Exit".
13619 */
13620 VMMRZCallRing3Disable(pVCpu);
13621 HM_DISABLE_PREEMPT(pVCpu);
13622
13623 pCtx->dr[6] &= ~X86_DR6_B_MASK;
13624 pCtx->dr[6] |= uDR6;
13625 if (CPUMIsGuestDebugStateActive(pVCpu))
13626 ASMSetDR6(pCtx->dr[6]);
13627
13628 HM_RESTORE_PREEMPT();
13629 VMMRZCallRing3Enable(pVCpu);
13630
13631 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_DR7);
13632 AssertRCReturn(rc, rc);
13633
13634 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
13635 pCtx->dr[7] &= ~(uint64_t)X86_DR7_GD;
13636
13637 /* Paranoia. */
13638 pCtx->dr[7] &= ~(uint64_t)X86_DR7_RAZ_MASK;
13639 pCtx->dr[7] |= X86_DR7_RA1_MASK;
13640
13641 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, pCtx->dr[7]);
13642 AssertRC(rc);
13643
13644 /*
13645 * Raise #DB in the guest.
13646 *
13647 * It is important to reflect exactly what the VM-exit gave us (preserving the
13648 * interruption-type) rather than use hmR0VmxSetPendingXcptDB() as the #DB could've
13649 * been raised while executing ICEBP (INT1) and not the regular #DB. Thus it may
13650 * trigger different handling in the CPU (like skipping DPL checks), see @bugref{6398}.
13651 *
13652 * Intel re-documented ICEBP/INT1 on May 2018 previously documented as part of
13653 * Intel 386, see Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
13654 */
13655 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13656 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13657 return VINF_SUCCESS;
13658 }
13659
13660 /*
13661 * Not a guest trap, must be a hypervisor related debug event then.
13662 * Update DR6 in case someone is interested in it.
13663 */
13664 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
13665 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
13666 CPUMSetHyperDR6(pVCpu, uDR6);
13667
13668 return rc;
13669}
13670
13671
13672/**
13673 * Hacks its way around the lovely mesa driver's backdoor accesses.
13674 *
13675 * @sa hmR0SvmHandleMesaDrvGp.
13676 */
13677static int hmR0VmxHandleMesaDrvGp(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
13678{
13679 LogFunc(("cs:rip=%#04x:%#RX64 rcx=%#RX64 rbx=%#RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->rcx, pCtx->rbx));
13680 RT_NOREF(pCtx);
13681
13682 /* For now we'll just skip the instruction. */
13683 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
13684}
13685
13686
13687/**
13688 * Checks if the \#GP'ing instruction is the mesa driver doing it's lovely
13689 * backdoor logging w/o checking what it is running inside.
13690 *
13691 * This recognizes an "IN EAX,DX" instruction executed in flat ring-3, with the
13692 * backdoor port and magic numbers loaded in registers.
13693 *
13694 * @returns true if it is, false if it isn't.
13695 * @sa hmR0SvmIsMesaDrvGp.
13696 */
13697DECLINLINE(bool) hmR0VmxIsMesaDrvGp(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
13698{
13699 /* 0xed: IN eAX,dx */
13700 uint8_t abInstr[1];
13701 if (pVmxTransient->cbInstr != sizeof(abInstr))
13702 return false;
13703
13704 /* Check that it is #GP(0). */
13705 if (pVmxTransient->uExitIntErrorCode != 0)
13706 return false;
13707
13708 /* Check magic and port. */
13709 Assert(!(pCtx->fExtrn & (CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX)));
13710 /*Log(("hmR0VmxIsMesaDrvGp: rax=%RX64 rdx=%RX64\n", pCtx->rax, pCtx->rdx));*/
13711 if (pCtx->rax != UINT32_C(0x564d5868))
13712 return false;
13713 if (pCtx->dx != UINT32_C(0x5658))
13714 return false;
13715
13716 /* Flat ring-3 CS. */
13717 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_CS);
13718 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_CS));
13719 /*Log(("hmR0VmxIsMesaDrvGp: cs.Attr.n.u2Dpl=%d base=%Rx64\n", pCtx->cs.Attr.n.u2Dpl, pCtx->cs.u64Base));*/
13720 if (pCtx->cs.Attr.n.u2Dpl != 3)
13721 return false;
13722 if (pCtx->cs.u64Base != 0)
13723 return false;
13724
13725 /* Check opcode. */
13726 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_RIP);
13727 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_RIP));
13728 int rc = PGMPhysSimpleReadGCPtr(pVCpu, abInstr, pCtx->rip, sizeof(abInstr));
13729 /*Log(("hmR0VmxIsMesaDrvGp: PGMPhysSimpleReadGCPtr -> %Rrc %#x\n", rc, abInstr[0]));*/
13730 if (RT_FAILURE(rc))
13731 return false;
13732 if (abInstr[0] != 0xed)
13733 return false;
13734
13735 return true;
13736}
13737
13738
13739/**
13740 * VM-exit exception handler for \#GP (General-protection exception).
13741 *
13742 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13743 */
13744static VBOXSTRICTRC hmR0VmxExitXcptGP(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13745{
13746 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13747 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
13748
13749 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13750 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13751 if (pVmcsInfo->RealMode.fRealOnV86Active)
13752 { /* likely */ }
13753 else
13754 {
13755#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13756 Assert(pVCpu->hm.s.fUsingDebugLoop || pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
13757#endif
13758 /*
13759 * If the guest is not in real-mode or we have unrestricted guest execution support, or if we are
13760 * executing a nested-guest, reflect #GP to the guest or nested-guest.
13761 */
13762 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13763 AssertRCReturn(rc, rc);
13764 Log4Func(("Gst: cs:rip=%#04x:%#RX64 ErrorCode=%#x cr0=%#RX64 cpl=%u tr=%#04x\n", pCtx->cs.Sel, pCtx->rip,
13765 pVmxTransient->uExitIntErrorCode, pCtx->cr0, CPUMGetGuestCPL(pVCpu), pCtx->tr.Sel));
13766
13767 if ( pVmxTransient->fIsNestedGuest
13768 || !pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv
13769 || !hmR0VmxIsMesaDrvGp(pVCpu, pVmxTransient, pCtx))
13770 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13771 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13772 else
13773 rc = hmR0VmxHandleMesaDrvGp(pVCpu, pVmxTransient, pCtx);
13774 return rc;
13775 }
13776
13777 Assert(CPUMIsGuestInRealModeEx(pCtx));
13778 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest);
13779 Assert(!pVmxTransient->fIsNestedGuest);
13780
13781 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13782 AssertRCReturn(rc, rc);
13783
13784 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
13785 if (rcStrict == VINF_SUCCESS)
13786 {
13787 if (!CPUMIsGuestInRealModeEx(pCtx))
13788 {
13789 /*
13790 * The guest is no longer in real-mode, check if we can continue executing the
13791 * guest using hardware-assisted VMX. Otherwise, fall back to emulation.
13792 */
13793 pVmcsInfo->RealMode.fRealOnV86Active = false;
13794 if (HMCanExecuteVmxGuest(pVCpu, pCtx))
13795 {
13796 Log4Func(("Mode changed but guest still suitable for executing using hardware-assisted VMX\n"));
13797 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13798 }
13799 else
13800 {
13801 Log4Func(("Mode changed -> VINF_EM_RESCHEDULE\n"));
13802 rcStrict = VINF_EM_RESCHEDULE;
13803 }
13804 }
13805 else
13806 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13807 }
13808 else if (rcStrict == VINF_IEM_RAISED_XCPT)
13809 {
13810 rcStrict = VINF_SUCCESS;
13811 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13812 }
13813 return VBOXSTRICTRC_VAL(rcStrict);
13814}
13815
13816
13817/**
13818 * VM-exit exception handler wrapper for all other exceptions that are not handled
13819 * by a specific handler.
13820 *
13821 * This simply re-injects the exception back into the VM without any special
13822 * processing.
13823 *
13824 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13825 */
13826static VBOXSTRICTRC hmR0VmxExitXcptOthers(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13827{
13828 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13829
13830#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13831 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13832 AssertMsg(pVCpu->hm.s.fUsingDebugLoop || pVmcsInfo->RealMode.fRealOnV86Active || pVmxTransient->fIsNestedGuest,
13833 ("uVector=%#x u32XcptBitmap=%#X32\n",
13834 VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVmcsInfo->u32XcptBitmap));
13835 NOREF(pVmcsInfo);
13836#endif
13837
13838 /*
13839 * Re-inject the exception into the guest. This cannot be a double-fault condition which
13840 * would have been handled while checking exits due to event delivery.
13841 */
13842 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13843
13844#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13845 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
13846 AssertRCReturn(rc, rc);
13847 Log4Func(("Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
13848#endif
13849
13850#ifdef VBOX_WITH_STATISTICS
13851 switch (uVector)
13852 {
13853 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE); break;
13854 case X86_XCPT_DB: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB); break;
13855 case X86_XCPT_BP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP); break;
13856 case X86_XCPT_OF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
13857 case X86_XCPT_BR: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBR); break;
13858 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD); break;
13859 case X86_XCPT_NM: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
13860 case X86_XCPT_DF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDF); break;
13861 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS); break;
13862 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP); break;
13863 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS); break;
13864 case X86_XCPT_GP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP); break;
13865 case X86_XCPT_PF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF); break;
13866 case X86_XCPT_MF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF); break;
13867 case X86_XCPT_AC: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC); break;
13868 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF); break;
13869 default:
13870 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
13871 break;
13872 }
13873#endif
13874
13875 /* We should never call this function for a page-fault, we'd need to pass on the fault address below otherwise. */
13876 Assert(!VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo));
13877 NOREF(uVector);
13878
13879 /* Re-inject the original exception into the guest. */
13880 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbInstr,
13881 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13882 return VINF_SUCCESS;
13883}
13884
13885
13886/**
13887 * VM-exit exception handler for all exceptions (except NMIs!).
13888 *
13889 * @remarks This may be called for both guests and nested-guests. Take care to not
13890 * make assumptions and avoid doing anything that is not relevant when
13891 * executing a nested-guest (e.g., Mesa driver hacks).
13892 */
13893static VBOXSTRICTRC hmR0VmxExitXcpt(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13894{
13895 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
13896
13897 /*
13898 * If this VM-exit occurred while delivering an event through the guest IDT, take
13899 * action based on the return code and additional hints (e.g. for page-faults)
13900 * that will be updated in the VMX transient structure.
13901 */
13902 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
13903 if (rcStrict == VINF_SUCCESS)
13904 {
13905 /*
13906 * If an exception caused a VM-exit due to delivery of an event, the original
13907 * event may have to be re-injected into the guest. We shall reinject it and
13908 * continue guest execution. However, page-fault is a complicated case and
13909 * needs additional processing done in hmR0VmxExitXcptPF().
13910 */
13911 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
13912 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13913 if ( !pVCpu->hm.s.Event.fPending
13914 || uVector == X86_XCPT_PF)
13915 {
13916 switch (uVector)
13917 {
13918 case X86_XCPT_PF: return hmR0VmxExitXcptPF(pVCpu, pVmxTransient);
13919 case X86_XCPT_GP: return hmR0VmxExitXcptGP(pVCpu, pVmxTransient);
13920 case X86_XCPT_MF: return hmR0VmxExitXcptMF(pVCpu, pVmxTransient);
13921 case X86_XCPT_DB: return hmR0VmxExitXcptDB(pVCpu, pVmxTransient);
13922 case X86_XCPT_BP: return hmR0VmxExitXcptBP(pVCpu, pVmxTransient);
13923 case X86_XCPT_AC: return hmR0VmxExitXcptAC(pVCpu, pVmxTransient);
13924 default:
13925 return hmR0VmxExitXcptOthers(pVCpu, pVmxTransient);
13926 }
13927 }
13928 /* else: inject pending event before resuming guest execution. */
13929 }
13930 else if (rcStrict == VINF_HM_DOUBLE_FAULT)
13931 {
13932 Assert(pVCpu->hm.s.Event.fPending);
13933 rcStrict = VINF_SUCCESS;
13934 }
13935
13936 return rcStrict;
13937}
13938/** @} */
13939
13940
13941/** @name VM-exit handlers.
13942 * @{
13943 */
13944/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13945/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
13946/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13947
13948/**
13949 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
13950 */
13951HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13952{
13953 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13954 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
13955 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
13956 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
13957 return VINF_SUCCESS;
13958 return VINF_EM_RAW_INTERRUPT;
13959}
13960
13961
13962/**
13963 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI). Conditional
13964 * VM-exit.
13965 */
13966HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
13967{
13968 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13969 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
13970
13971 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13972
13973 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
13974 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13975 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
13976
13977 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13978 Assert( !(pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT)
13979 && uExitIntType != VMX_EXIT_INT_INFO_TYPE_EXT_INT);
13980 NOREF(pVmcsInfo);
13981
13982 VBOXSTRICTRC rcStrict;
13983 switch (uExitIntType)
13984 {
13985 /*
13986 * Host physical NMIs:
13987 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we
13988 * injected it ourselves and anything we inject is not going to cause a VM-exit directly
13989 * for the event being injected[1]. Go ahead and dispatch the NMI to the host[2].
13990 *
13991 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
13992 * See Intel spec. 27.5.5 "Updating Non-Register State".
13993 */
13994 case VMX_EXIT_INT_INFO_TYPE_NMI:
13995 {
13996 rcStrict = hmR0VmxExitHostNmi(pVCpu, pVmcsInfo);
13997 break;
13998 }
13999
14000 /*
14001 * Privileged software exceptions (#DB from ICEBP),
14002 * Software exceptions (#BP and #OF),
14003 * Hardware exceptions:
14004 * Process the required exceptions and resume guest execution if possible.
14005 */
14006 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
14007 Assert(uVector == X86_XCPT_DB);
14008 RT_FALL_THRU();
14009 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
14010 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uExitIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT);
14011 RT_FALL_THRU();
14012 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
14013 {
14014 NOREF(uVector);
14015 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
14016 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14017 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
14018 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
14019
14020 rcStrict = hmR0VmxExitXcpt(pVCpu, pVmxTransient);
14021 break;
14022 }
14023
14024 default:
14025 {
14026 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
14027 rcStrict = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
14028 AssertMsgFailed(("Invalid/unexpected VM-exit interruption info %#x\n", pVmxTransient->uExitIntInfo));
14029 break;
14030 }
14031 }
14032
14033 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
14034 return rcStrict;
14035}
14036
14037
14038/**
14039 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
14040 */
14041HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14042{
14043 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14044
14045 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
14046 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14047 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
14048
14049 /* Evaluate and deliver pending events and resume guest execution. */
14050 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
14051 return VINF_SUCCESS;
14052}
14053
14054
14055/**
14056 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
14057 */
14058HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14059{
14060 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14061
14062 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14063 if (RT_UNLIKELY(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))) /** @todo NSTVMX: Turn this into an assertion. */
14064 {
14065 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
14066 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14067 }
14068
14069 Assert(!CPUMIsGuestNmiBlocking(pVCpu));
14070
14071 /*
14072 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
14073 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
14074 */
14075 uint32_t fIntrState;
14076 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
14077 AssertRC(rc);
14078 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
14079 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
14080 {
14081 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
14082 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
14083
14084 fIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
14085 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
14086 AssertRC(rc);
14087 }
14088
14089 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
14090 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
14091
14092 /* Evaluate and deliver pending events and resume guest execution. */
14093 return VINF_SUCCESS;
14094}
14095
14096
14097/**
14098 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
14099 */
14100HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14101{
14102 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14103 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14104}
14105
14106
14107/**
14108 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
14109 */
14110HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14111{
14112 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14113 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14114}
14115
14116
14117/**
14118 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
14119 */
14120HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14121{
14122 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14123
14124 /*
14125 * Get the state we need and update the exit history entry.
14126 */
14127 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14128 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14129
14130 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14131 AssertRCReturn(rc, rc);
14132
14133 VBOXSTRICTRC rcStrict;
14134 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
14135 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_CPUID),
14136 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
14137 if (!pExitRec)
14138 {
14139 /*
14140 * Regular CPUID instruction execution.
14141 */
14142 rcStrict = IEMExecDecodedCpuid(pVCpu, pVmxTransient->cbInstr);
14143 if (rcStrict == VINF_SUCCESS)
14144 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14145 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14146 {
14147 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14148 rcStrict = VINF_SUCCESS;
14149 }
14150 }
14151 else
14152 {
14153 /*
14154 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
14155 */
14156 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14157 AssertRCReturn(rc2, rc2);
14158
14159 Log4(("CpuIdExit/%u: %04x:%08RX64: %#x/%#x -> EMHistoryExec\n",
14160 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx));
14161
14162 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
14163 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14164
14165 Log4(("CpuIdExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
14166 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
14167 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
14168 }
14169 return rcStrict;
14170}
14171
14172
14173/**
14174 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
14175 */
14176HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14177{
14178 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14179
14180 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14181 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4);
14182 AssertRCReturn(rc, rc);
14183
14184 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_SMXE)
14185 return VINF_EM_RAW_EMULATE_INSTR;
14186
14187 AssertMsgFailed(("hmR0VmxExitGetsec: Unexpected VM-exit when CR4.SMXE is 0.\n"));
14188 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14189}
14190
14191
14192/**
14193 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
14194 */
14195HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14196{
14197 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14198
14199 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14200 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14201 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14202 AssertRCReturn(rc, rc);
14203
14204 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtsc(pVCpu, pVmxTransient->cbInstr);
14205 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14206 {
14207 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14208 we must reset offsetting on VM-entry. See @bugref{6634}. */
14209 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14210 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14211 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14212 }
14213 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14214 {
14215 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14216 rcStrict = VINF_SUCCESS;
14217 }
14218 return rcStrict;
14219}
14220
14221
14222/**
14223 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
14224 */
14225HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14226{
14227 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14228
14229 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14230 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14231 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_TSC_AUX);
14232 AssertRCReturn(rc, rc);
14233
14234 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtscp(pVCpu, pVmxTransient->cbInstr);
14235 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14236 {
14237 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14238 we must reset offsetting on VM-reentry. See @bugref{6634}. */
14239 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14240 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14241 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14242 }
14243 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14244 {
14245 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14246 rcStrict = VINF_SUCCESS;
14247 }
14248 return rcStrict;
14249}
14250
14251
14252/**
14253 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
14254 */
14255HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14256{
14257 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14258
14259 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14260 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_CR0
14261 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS);
14262 AssertRCReturn(rc, rc);
14263
14264 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14265 rc = EMInterpretRdpmc(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
14266 if (RT_LIKELY(rc == VINF_SUCCESS))
14267 {
14268 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14269 Assert(pVmxTransient->cbInstr == 2);
14270 }
14271 else
14272 {
14273 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
14274 rc = VERR_EM_INTERPRETER;
14275 }
14276 return rc;
14277}
14278
14279
14280/**
14281 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
14282 */
14283HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14284{
14285 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14286
14287 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
14288 if (EMAreHypercallInstructionsEnabled(pVCpu))
14289 {
14290 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14291 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CR0
14292 | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
14293 AssertRCReturn(rc, rc);
14294
14295 /* Perform the hypercall. */
14296 rcStrict = GIMHypercall(pVCpu, &pVCpu->cpum.GstCtx);
14297 if (rcStrict == VINF_SUCCESS)
14298 {
14299 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14300 AssertRCReturn(rc, rc);
14301 }
14302 else
14303 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
14304 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
14305 || RT_FAILURE(rcStrict));
14306
14307 /* If the hypercall changes anything other than guest's general-purpose registers,
14308 we would need to reload the guest changed bits here before VM-entry. */
14309 }
14310 else
14311 Log4Func(("Hypercalls not enabled\n"));
14312
14313 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
14314 if (RT_FAILURE(rcStrict))
14315 {
14316 hmR0VmxSetPendingXcptUD(pVCpu);
14317 rcStrict = VINF_SUCCESS;
14318 }
14319
14320 return rcStrict;
14321}
14322
14323
14324/**
14325 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
14326 */
14327HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14328{
14329 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14330 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging || pVCpu->hm.s.fUsingDebugLoop);
14331
14332 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14333 hmR0VmxReadExitQualVmcs(pVmxTransient);
14334 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14335 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
14336 AssertRCReturn(rc, rc);
14337
14338 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpg(pVCpu, pVmxTransient->cbInstr, pVmxTransient->uExitQual);
14339
14340 if (rcStrict == VINF_SUCCESS || rcStrict == VINF_PGM_SYNC_CR3)
14341 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14342 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14343 {
14344 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14345 rcStrict = VINF_SUCCESS;
14346 }
14347 else
14348 AssertMsgFailed(("Unexpected IEMExecDecodedInvlpg(%#RX64) status: %Rrc\n", pVmxTransient->uExitQual,
14349 VBOXSTRICTRC_VAL(rcStrict)));
14350 return rcStrict;
14351}
14352
14353
14354/**
14355 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
14356 */
14357HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14358{
14359 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14360
14361 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14362 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14363 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_DS);
14364 AssertRCReturn(rc, rc);
14365
14366 VBOXSTRICTRC rcStrict = IEMExecDecodedMonitor(pVCpu, pVmxTransient->cbInstr);
14367 if (rcStrict == VINF_SUCCESS)
14368 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14369 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14370 {
14371 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14372 rcStrict = VINF_SUCCESS;
14373 }
14374
14375 return rcStrict;
14376}
14377
14378
14379/**
14380 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
14381 */
14382HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14383{
14384 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14385
14386 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14387 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14388 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14389 AssertRCReturn(rc, rc);
14390
14391 VBOXSTRICTRC rcStrict = IEMExecDecodedMwait(pVCpu, pVmxTransient->cbInstr);
14392 if (RT_SUCCESS(rcStrict))
14393 {
14394 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14395 if (EMMonitorWaitShouldContinue(pVCpu, &pVCpu->cpum.GstCtx))
14396 rcStrict = VINF_SUCCESS;
14397 }
14398
14399 return rcStrict;
14400}
14401
14402
14403/**
14404 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
14405 * VM-exit.
14406 */
14407HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14408{
14409 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14410 return VINF_EM_RESET;
14411}
14412
14413
14414/**
14415 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
14416 */
14417HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14418{
14419 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14420
14421 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14422 AssertRCReturn(rc, rc);
14423
14424 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS); /* Advancing the RIP above should've imported eflags. */
14425 if (EMShouldContinueAfterHalt(pVCpu, &pVCpu->cpum.GstCtx)) /* Requires eflags. */
14426 rc = VINF_SUCCESS;
14427 else
14428 rc = VINF_EM_HALT;
14429
14430 if (rc != VINF_SUCCESS)
14431 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
14432 return rc;
14433}
14434
14435
14436/**
14437 * VM-exit handler for instructions that result in a \#UD exception delivered to
14438 * the guest.
14439 */
14440HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14441{
14442 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14443 hmR0VmxSetPendingXcptUD(pVCpu);
14444 return VINF_SUCCESS;
14445}
14446
14447
14448/**
14449 * VM-exit handler for expiry of the VMX-preemption timer.
14450 */
14451HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14452{
14453 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14454
14455 /* If the VMX-preemption timer has expired, reinitialize the preemption timer on next VM-entry. */
14456 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14457
14458 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
14459 PVM pVM = pVCpu->CTX_SUFF(pVM);
14460 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
14461 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
14462 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
14463}
14464
14465
14466/**
14467 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
14468 */
14469HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14470{
14471 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14472
14473 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14474 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14475 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_CR4);
14476 AssertRCReturn(rc, rc);
14477
14478 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbInstr);
14479 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
14480 : HM_CHANGED_RAISED_XCPT_MASK);
14481
14482 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14483 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
14484
14485 return rcStrict;
14486}
14487
14488
14489/**
14490 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
14491 */
14492HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14493{
14494 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14495 /** @todo Use VM-exit instruction information. */
14496 return VERR_EM_INTERPRETER;
14497}
14498
14499
14500/**
14501 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error
14502 * VM-exit.
14503 */
14504HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14505{
14506 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14507 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14508 AssertRCReturn(rc, rc);
14509
14510 rc = hmR0VmxCheckVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
14511 if (RT_FAILURE(rc))
14512 return rc;
14513
14514 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
14515 NOREF(uInvalidReason);
14516
14517#ifdef VBOX_STRICT
14518 uint32_t fIntrState;
14519 RTHCUINTREG uHCReg;
14520 uint64_t u64Val;
14521 uint32_t u32Val;
14522 hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
14523 hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
14524 hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
14525 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
14526 AssertRC(rc);
14527
14528 Log4(("uInvalidReason %u\n", uInvalidReason));
14529 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
14530 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
14531 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
14532 Log4(("VMX_VMCS32_GUEST_INT_STATE %#RX32\n", fIntrState));
14533
14534 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32Val); AssertRC(rc);
14535 Log4(("VMX_VMCS_GUEST_CR0 %#RX32\n", u32Val));
14536 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_MASK, &uHCReg); AssertRC(rc);
14537 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RHr\n", uHCReg));
14538 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uHCReg); AssertRC(rc);
14539 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
14540 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_MASK, &uHCReg); AssertRC(rc);
14541 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RHr\n", uHCReg));
14542 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uHCReg); AssertRC(rc);
14543 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
14544 if (pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging)
14545 {
14546 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
14547 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
14548 }
14549
14550 hmR0DumpRegs(pVCpu);
14551#endif
14552
14553 return VERR_VMX_INVALID_GUEST_STATE;
14554}
14555
14556/**
14557 * VM-exit handler for all undefined/unexpected reasons. Should never happen.
14558 */
14559HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUnexpected(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14560{
14561 /*
14562 * Cummulative notes of all recognized but unexpected VM-exits.
14563 *
14564 * 1. This does -not- cover scenarios like like a page-fault VM-exit occurring when
14565 * nested-paging is used.
14566 *
14567 * 2. Any instruction that causes a VM-exit unconditionally (for e.g. VMXON) must be
14568 * emulated or a #UD must be raised in the guest. Therefore, we should -not- be using
14569 * this function (and thereby stop VM execution) for handling such instructions.
14570 *
14571 *
14572 * VMX_EXIT_INIT_SIGNAL:
14573 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
14574 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these
14575 * VM-exits. However, we should not receive INIT signals VM-exit while executing a VM.
14576 *
14577 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery"
14578 * See Intel spec. 29.3 "VMX Instructions" for "VMXON".
14579 * See Intel spec. "23.8 Restrictions on VMX operation".
14580 *
14581 * VMX_EXIT_SIPI:
14582 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest
14583 * activity state is used. We don't make use of it as our guests don't have direct
14584 * access to the host local APIC.
14585 *
14586 * See Intel spec. 25.3 "Other Causes of VM-exits".
14587 *
14588 * VMX_EXIT_IO_SMI:
14589 * VMX_EXIT_SMI:
14590 * This can only happen if we support dual-monitor treatment of SMI, which can be
14591 * activated by executing VMCALL in VMX root operation. Only an STM (SMM transfer
14592 * monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL in
14593 * VMX root mode or receive an SMI. If we get here, something funny is going on.
14594 *
14595 * See Intel spec. 33.15.6 "Activating the Dual-Monitor Treatment"
14596 * See Intel spec. 25.3 "Other Causes of VM-Exits"
14597 *
14598 * VMX_EXIT_ERR_MSR_LOAD:
14599 * Failures while loading MSRs are part of the VM-entry MSR-load area are unexpected
14600 * and typically indicates a bug in the hypervisor code. We thus cannot not resume
14601 * execution.
14602 *
14603 * See Intel spec. 26.7 "VM-Entry Failures During Or After Loading Guest State".
14604 *
14605 * VMX_EXIT_ERR_MACHINE_CHECK:
14606 * Machine check exceptions indicates a fatal/unrecoverable hardware condition
14607 * including but not limited to system bus, ECC, parity, cache and TLB errors. A
14608 * #MC exception abort class exception is raised. We thus cannot assume a
14609 * reasonable chance of continuing any sort of execution and we bail.
14610 *
14611 * See Intel spec. 15.1 "Machine-check Architecture".
14612 * See Intel spec. 27.1 "Architectural State Before A VM Exit".
14613 *
14614 * VMX_EXIT_PML_FULL:
14615 * VMX_EXIT_VIRTUALIZED_EOI:
14616 * VMX_EXIT_APIC_WRITE:
14617 * We do not currently support any of these features and thus they are all unexpected
14618 * VM-exits.
14619 *
14620 * VMX_EXIT_GDTR_IDTR_ACCESS:
14621 * VMX_EXIT_LDTR_TR_ACCESS:
14622 * VMX_EXIT_RDRAND:
14623 * VMX_EXIT_RSM:
14624 * VMX_EXIT_VMFUNC:
14625 * VMX_EXIT_ENCLS:
14626 * VMX_EXIT_RDSEED:
14627 * VMX_EXIT_XSAVES:
14628 * VMX_EXIT_XRSTORS:
14629 * VMX_EXIT_UMWAIT:
14630 * VMX_EXIT_TPAUSE:
14631 * These VM-exits are -not- caused unconditionally by execution of the corresponding
14632 * instruction. Any VM-exit for these instructions indicate a hardware problem,
14633 * unsupported CPU modes (like SMM) or potentially corrupt VMCS controls.
14634 *
14635 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
14636 */
14637 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14638 AssertMsgFailed(("Unexpected VM-exit %u\n", pVmxTransient->uExitReason));
14639 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14640}
14641
14642
14643/**
14644 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
14645 */
14646HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14647{
14648 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14649
14650 /** @todo Optimize this: We currently drag in in the whole MSR state
14651 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
14652 * MSRs required. That would require changes to IEM and possibly CPUM too.
14653 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
14654 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14655 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
14656 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
14657 switch (idMsr)
14658 {
14659 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
14660 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
14661 }
14662
14663 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14664 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
14665 AssertRCReturn(rc, rc);
14666
14667 Log4Func(("ecx=%#RX32\n", idMsr));
14668
14669#ifdef VBOX_STRICT
14670 Assert(!pVmxTransient->fIsNestedGuest);
14671 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
14672 {
14673 if ( hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr)
14674 && idMsr != MSR_K6_EFER)
14675 {
14676 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", idMsr));
14677 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14678 }
14679 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14680 {
14681 Assert(pVmcsInfo->pvMsrBitmap);
14682 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
14683 if (fMsrpm & VMXMSRPM_ALLOW_RD)
14684 {
14685 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", idMsr));
14686 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14687 }
14688 }
14689 }
14690#endif
14691
14692 VBOXSTRICTRC rcStrict = IEMExecDecodedRdmsr(pVCpu, pVmxTransient->cbInstr);
14693 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
14694 if (rcStrict == VINF_SUCCESS)
14695 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
14696 | HM_CHANGED_GUEST_RAX | HM_CHANGED_GUEST_RDX);
14697 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14698 {
14699 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14700 rcStrict = VINF_SUCCESS;
14701 }
14702 else
14703 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_READ, ("Unexpected IEMExecDecodedRdmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
14704
14705 return rcStrict;
14706}
14707
14708
14709/**
14710 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
14711 */
14712HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14713{
14714 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14715
14716 /** @todo Optimize this: We currently drag in in the whole MSR state
14717 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
14718 * MSRs required. That would require changes to IEM and possibly CPUM too.
14719 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
14720 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
14721 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
14722
14723 /*
14724 * The FS and GS base MSRs are not part of the above all-MSRs mask.
14725 * Although we don't need to fetch the base as it will be overwritten shortly, while
14726 * loading guest-state we would also load the entire segment register including limit
14727 * and attributes and thus we need to load them here.
14728 */
14729 switch (idMsr)
14730 {
14731 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
14732 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
14733 }
14734
14735 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14736 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14737 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
14738 AssertRCReturn(rc, rc);
14739
14740 Log4Func(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", idMsr, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.eax));
14741
14742 VBOXSTRICTRC rcStrict = IEMExecDecodedWrmsr(pVCpu, pVmxTransient->cbInstr);
14743 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
14744
14745 if (rcStrict == VINF_SUCCESS)
14746 {
14747 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14748
14749 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
14750 if ( idMsr == MSR_IA32_APICBASE
14751 || ( idMsr >= MSR_IA32_X2APIC_START
14752 && idMsr <= MSR_IA32_X2APIC_END))
14753 {
14754 /*
14755 * We've already saved the APIC related guest-state (TPR) in post-run phase.
14756 * When full APIC register virtualization is implemented we'll have to make
14757 * sure APIC state is saved from the VMCS before IEM changes it.
14758 */
14759 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
14760 }
14761 else if (idMsr == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
14762 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14763 else if (idMsr == MSR_K6_EFER)
14764 {
14765 /*
14766 * If the guest touches the EFER MSR we need to update the VM-Entry and VM-Exit controls
14767 * as well, even if it is -not- touching bits that cause paging mode changes (LMA/LME).
14768 * We care about the other bits as well, SCE and NXE. See @bugref{7368}.
14769 */
14770 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
14771 }
14772
14773 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not used. */
14774 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
14775 {
14776 switch (idMsr)
14777 {
14778 case MSR_IA32_SYSENTER_CS: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
14779 case MSR_IA32_SYSENTER_EIP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
14780 case MSR_IA32_SYSENTER_ESP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
14781 case MSR_K8_FS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_FS); break;
14782 case MSR_K8_GS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_GS); break;
14783 case MSR_K6_EFER: /* Nothing to do, already handled above. */ break;
14784 default:
14785 {
14786 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14787 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_LAZY_MSRS);
14788 else if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
14789 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
14790 break;
14791 }
14792 }
14793 }
14794#ifdef VBOX_STRICT
14795 else
14796 {
14797 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
14798 switch (idMsr)
14799 {
14800 case MSR_IA32_SYSENTER_CS:
14801 case MSR_IA32_SYSENTER_EIP:
14802 case MSR_IA32_SYSENTER_ESP:
14803 case MSR_K8_FS_BASE:
14804 case MSR_K8_GS_BASE:
14805 {
14806 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", idMsr));
14807 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14808 }
14809
14810 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
14811 default:
14812 {
14813 if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
14814 {
14815 /* EFER MSR writes are always intercepted. */
14816 if (idMsr != MSR_K6_EFER)
14817 {
14818 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
14819 idMsr));
14820 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14821 }
14822 }
14823
14824 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14825 {
14826 Assert(pVmcsInfo->pvMsrBitmap);
14827 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
14828 if (fMsrpm & VMXMSRPM_ALLOW_WR)
14829 {
14830 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", idMsr));
14831 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14832 }
14833 }
14834 break;
14835 }
14836 }
14837 }
14838#endif /* VBOX_STRICT */
14839 }
14840 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14841 {
14842 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14843 rcStrict = VINF_SUCCESS;
14844 }
14845 else
14846 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_WRITE, ("Unexpected IEMExecDecodedWrmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
14847
14848 return rcStrict;
14849}
14850
14851
14852/**
14853 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
14854 */
14855HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14856{
14857 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14858
14859 /** @todo The guest has likely hit a contended spinlock. We might want to
14860 * poke a schedule different guest VCPU. */
14861 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14862 if (RT_SUCCESS(rc))
14863 return VINF_EM_RAW_INTERRUPT;
14864
14865 AssertMsgFailed(("hmR0VmxExitPause: Failed to increment RIP. rc=%Rrc\n", rc));
14866 return rc;
14867}
14868
14869
14870/**
14871 * VM-exit handler for when the TPR value is lowered below the specified
14872 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
14873 */
14874HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14875{
14876 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14877 Assert(pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
14878
14879 /*
14880 * The TPR shadow would've been synced with the APIC TPR in the post-run phase.
14881 * We'll re-evaluate pending interrupts and inject them before the next VM
14882 * entry so we can just continue execution here.
14883 */
14884 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
14885 return VINF_SUCCESS;
14886}
14887
14888
14889/**
14890 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
14891 * VM-exit.
14892 *
14893 * @retval VINF_SUCCESS when guest execution can continue.
14894 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
14895 * @retval VERR_EM_RESCHEDULE_REM when we need to return to ring-3 due to
14896 * incompatible guest state for VMX execution (real-on-v86 case).
14897 */
14898HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
14899{
14900 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14901 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
14902
14903 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14904 hmR0VmxReadExitQualVmcs(pVmxTransient);
14905 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14906
14907 VBOXSTRICTRC rcStrict;
14908 PVM pVM = pVCpu->CTX_SUFF(pVM);
14909 uint64_t const uExitQual = pVmxTransient->uExitQual;
14910 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(uExitQual);
14911 switch (uAccessType)
14912 {
14913 /*
14914 * MOV to CRx.
14915 */
14916 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
14917 {
14918 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14919 AssertRCReturn(rc, rc);
14920
14921 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
14922 uint32_t const uOldCr0 = pVCpu->cpum.GstCtx.cr0;
14923 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
14924 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
14925
14926 /*
14927 * MOV to CR3 only cause a VM-exit when one or more of the following are true:
14928 * - When nested paging isn't used.
14929 * - If the guest doesn't have paging enabled (intercept CR3 to update shadow page tables).
14930 * - We are executing in the VM debug loop.
14931 */
14932 Assert( iCrReg != 3
14933 || !pVM->hm.s.fNestedPaging
14934 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
14935 || pVCpu->hm.s.fUsingDebugLoop);
14936
14937 /* MOV to CR8 writes only cause VM-exits when TPR shadow is not used. */
14938 Assert( iCrReg != 8
14939 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
14940
14941 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmcsInfo, pVmxTransient->cbInstr, iGReg, iCrReg);
14942 AssertMsg( rcStrict == VINF_SUCCESS
14943 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
14944
14945 /*
14946 * This is a kludge for handling switches back to real mode when we try to use
14947 * V86 mode to run real mode code directly. Problem is that V86 mode cannot
14948 * deal with special selector values, so we have to return to ring-3 and run
14949 * there till the selector values are V86 mode compatible.
14950 *
14951 * Note! Using VINF_EM_RESCHEDULE_REM here rather than VINF_EM_RESCHEDULE since the
14952 * latter is an alias for VINF_IEM_RAISED_XCPT which is asserted at the end of
14953 * this function.
14954 */
14955 if ( iCrReg == 0
14956 && rcStrict == VINF_SUCCESS
14957 && !pVM->hm.s.vmx.fUnrestrictedGuest
14958 && CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx)
14959 && (uOldCr0 & X86_CR0_PE)
14960 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
14961 {
14962 /** @todo Check selectors rather than returning all the time. */
14963 Assert(!pVmxTransient->fIsNestedGuest);
14964 Log4Func(("CR0 write, back to real mode -> VINF_EM_RESCHEDULE_REM\n"));
14965 rcStrict = VINF_EM_RESCHEDULE_REM;
14966 }
14967 break;
14968 }
14969
14970 /*
14971 * MOV from CRx.
14972 */
14973 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
14974 {
14975 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
14976 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
14977
14978 /*
14979 * MOV from CR3 only cause a VM-exit when one or more of the following are true:
14980 * - When nested paging isn't used.
14981 * - If the guest doesn't have paging enabled (pass guest's CR3 rather than our identity mapped CR3).
14982 * - We are executing in the VM debug loop.
14983 */
14984 Assert( iCrReg != 3
14985 || !pVM->hm.s.fNestedPaging
14986 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
14987 || pVCpu->hm.s.fUsingDebugLoop);
14988
14989 /* MOV from CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
14990 Assert( iCrReg != 8
14991 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
14992
14993 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmcsInfo, pVmxTransient->cbInstr, iGReg, iCrReg);
14994 break;
14995 }
14996
14997 /*
14998 * CLTS (Clear Task-Switch Flag in CR0).
14999 */
15000 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
15001 {
15002 rcStrict = hmR0VmxExitClts(pVCpu, pVmcsInfo, pVmxTransient->cbInstr);
15003 break;
15004 }
15005
15006 /*
15007 * LMSW (Load Machine-Status Word into CR0).
15008 * LMSW cannot clear CR0.PE, so no fRealOnV86Active kludge needed here.
15009 */
15010 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW:
15011 {
15012 RTGCPTR GCPtrEffDst;
15013 uint8_t const cbInstr = pVmxTransient->cbInstr;
15014 uint16_t const uMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(uExitQual);
15015 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(uExitQual);
15016 if (fMemOperand)
15017 {
15018 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
15019 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
15020 }
15021 else
15022 GCPtrEffDst = NIL_RTGCPTR;
15023 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmcsInfo, cbInstr, uMsw, GCPtrEffDst);
15024 break;
15025 }
15026
15027 default:
15028 {
15029 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
15030 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
15031 }
15032 }
15033
15034 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS))
15035 == (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS));
15036 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15037
15038 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
15039 NOREF(pVM);
15040 return rcStrict;
15041}
15042
15043
15044/**
15045 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
15046 * VM-exit.
15047 */
15048HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15049{
15050 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15051 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
15052
15053 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15054 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15055 hmR0VmxReadExitQualVmcs(pVmxTransient);
15056 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15057 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_SREG_MASK
15058 | CPUMCTX_EXTRN_EFER);
15059 /* EFER MSR also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
15060 AssertRCReturn(rc, rc);
15061
15062 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
15063 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
15064 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
15065 bool const fIOWrite = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
15066 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
15067 bool const fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
15068 bool const fDbgStepping = pVCpu->hm.s.fSingleInstruction;
15069 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
15070
15071 /*
15072 * Update exit history to see if this exit can be optimized.
15073 */
15074 VBOXSTRICTRC rcStrict;
15075 PCEMEXITREC pExitRec = NULL;
15076 if ( !fGstStepping
15077 && !fDbgStepping)
15078 pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15079 !fIOString
15080 ? !fIOWrite
15081 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_READ)
15082 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_WRITE)
15083 : !fIOWrite
15084 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_READ)
15085 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_WRITE),
15086 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15087 if (!pExitRec)
15088 {
15089 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
15090 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving result in AL/AX/EAX. */
15091
15092 uint32_t const cbValue = s_aIOSizes[uIOSize];
15093 uint32_t const cbInstr = pVmxTransient->cbInstr;
15094 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
15095 PVM pVM = pVCpu->CTX_SUFF(pVM);
15096 if (fIOString)
15097 {
15098 /*
15099 * INS/OUTS - I/O String instruction.
15100 *
15101 * Use instruction-information if available, otherwise fall back on
15102 * interpreting the instruction.
15103 */
15104 Log4Func(("cs:rip=%#04x:%#RX64 %#06x/%u %c str\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15105 AssertReturn(pCtx->dx == uIOPort, VERR_VMX_IPE_2);
15106 bool const fInsOutsInfo = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS);
15107 if (fInsOutsInfo)
15108 {
15109 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15110 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
15111 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
15112 IEMMODE const enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
15113 bool const fRep = VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual);
15114 if (fIOWrite)
15115 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
15116 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
15117 else
15118 {
15119 /*
15120 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
15121 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
15122 * See Intel Instruction spec. for "INS".
15123 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
15124 */
15125 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
15126 }
15127 }
15128 else
15129 rcStrict = IEMExecOne(pVCpu);
15130
15131 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15132 fUpdateRipAlready = true;
15133 }
15134 else
15135 {
15136 /*
15137 * IN/OUT - I/O instruction.
15138 */
15139 Log4Func(("cs:rip=%04x:%08RX64 %#06x/%u %c\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15140 uint32_t const uAndVal = s_aIOOpAnd[uIOSize];
15141 Assert(!VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual));
15142 if (fIOWrite)
15143 {
15144 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pCtx->eax & uAndVal, cbValue);
15145 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
15146 if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15147 && !pCtx->eflags.Bits.u1TF)
15148 rcStrict = EMRZSetPendingIoPortWrite(pVCpu, uIOPort, cbInstr, cbValue, pCtx->eax & uAndVal);
15149 }
15150 else
15151 {
15152 uint32_t u32Result = 0;
15153 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
15154 if (IOM_SUCCESS(rcStrict))
15155 {
15156 /* Save result of I/O IN instr. in AL/AX/EAX. */
15157 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Result & uAndVal);
15158 }
15159 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15160 && !pCtx->eflags.Bits.u1TF)
15161 rcStrict = EMRZSetPendingIoPortRead(pVCpu, uIOPort, cbInstr, cbValue);
15162 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
15163 }
15164 }
15165
15166 if (IOM_SUCCESS(rcStrict))
15167 {
15168 if (!fUpdateRipAlready)
15169 {
15170 hmR0VmxAdvanceGuestRipBy(pVCpu, cbInstr);
15171 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15172 }
15173
15174 /*
15175 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru
15176 * while booting Fedora 17 64-bit guest.
15177 *
15178 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
15179 */
15180 if (fIOString)
15181 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RFLAGS);
15182
15183 /*
15184 * If any I/O breakpoints are armed, we need to check if one triggered
15185 * and take appropriate action.
15186 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
15187 */
15188 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_DR7);
15189 AssertRCReturn(rc, rc);
15190
15191 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
15192 * execution engines about whether hyper BPs and such are pending. */
15193 uint32_t const uDr7 = pCtx->dr[7];
15194 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
15195 && X86_DR7_ANY_RW_IO(uDr7)
15196 && (pCtx->cr4 & X86_CR4_DE))
15197 || DBGFBpIsHwIoArmed(pVM)))
15198 {
15199 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
15200
15201 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
15202 VMMRZCallRing3Disable(pVCpu);
15203 HM_DISABLE_PREEMPT(pVCpu);
15204
15205 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
15206
15207 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, uIOPort, cbValue);
15208 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
15209 {
15210 /* Raise #DB. */
15211 if (fIsGuestDbgActive)
15212 ASMSetDR6(pCtx->dr[6]);
15213 if (pCtx->dr[7] != uDr7)
15214 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_DR7;
15215
15216 hmR0VmxSetPendingXcptDB(pVCpu);
15217 }
15218 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
15219 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
15220 else if ( rcStrict2 != VINF_SUCCESS
15221 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
15222 rcStrict = rcStrict2;
15223 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
15224
15225 HM_RESTORE_PREEMPT();
15226 VMMRZCallRing3Enable(pVCpu);
15227 }
15228 }
15229
15230#ifdef VBOX_STRICT
15231 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15232 || rcStrict == VINF_EM_PENDING_R3_IOPORT_READ)
15233 Assert(!fIOWrite);
15234 else if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15235 || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
15236 || rcStrict == VINF_EM_PENDING_R3_IOPORT_WRITE)
15237 Assert(fIOWrite);
15238 else
15239 {
15240# if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
15241 * statuses, that the VMM device and some others may return. See
15242 * IOM_SUCCESS() for guidance. */
15243 AssertMsg( RT_FAILURE(rcStrict)
15244 || rcStrict == VINF_SUCCESS
15245 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
15246 || rcStrict == VINF_EM_DBG_BREAKPOINT
15247 || rcStrict == VINF_EM_RAW_GUEST_TRAP
15248 || rcStrict == VINF_EM_RAW_TO_R3
15249 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15250# endif
15251 }
15252#endif
15253 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
15254 }
15255 else
15256 {
15257 /*
15258 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
15259 */
15260 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15261 AssertRCReturn(rc2, rc2);
15262 STAM_COUNTER_INC(!fIOString ? fIOWrite ? &pVCpu->hm.s.StatExitIOWrite : &pVCpu->hm.s.StatExitIORead
15263 : fIOWrite ? &pVCpu->hm.s.StatExitIOStringWrite : &pVCpu->hm.s.StatExitIOStringRead);
15264 Log4(("IOExit/%u: %04x:%08RX64: %s%s%s %#x LB %u -> EMHistoryExec\n",
15265 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15266 VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual) ? "REP " : "",
15267 fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOSize));
15268
15269 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15270 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15271
15272 Log4(("IOExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15273 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15274 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15275 }
15276 return rcStrict;
15277}
15278
15279
15280/**
15281 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
15282 * VM-exit.
15283 */
15284HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15285{
15286 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15287
15288 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
15289 hmR0VmxReadExitQualVmcs(pVmxTransient);
15290 if (VMX_EXIT_QUAL_TASK_SWITCH_TYPE(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT)
15291 {
15292 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15293 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
15294 {
15295 uint32_t uErrCode;
15296 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uIdtVectoringInfo))
15297 {
15298 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15299 uErrCode = pVmxTransient->uIdtVectoringErrorCode;
15300 }
15301 else
15302 uErrCode = 0;
15303
15304 RTGCUINTPTR GCPtrFaultAddress;
15305 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(pVmxTransient->uIdtVectoringInfo))
15306 GCPtrFaultAddress = pVCpu->cpum.GstCtx.cr2;
15307 else
15308 GCPtrFaultAddress = 0;
15309
15310 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15311
15312 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
15313 pVmxTransient->cbInstr, uErrCode, GCPtrFaultAddress);
15314
15315 Log4Func(("Pending event. uIntType=%#x uVector=%#x\n", VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo),
15316 VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo)));
15317 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15318 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15319 }
15320 }
15321
15322 /* Fall back to the interpreter to emulate the task-switch. */
15323 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15324 return VERR_EM_INTERPRETER;
15325}
15326
15327
15328/**
15329 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
15330 */
15331HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15332{
15333 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15334
15335 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15336 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
15337 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15338 AssertRC(rc);
15339 return VINF_EM_DBG_STEPPED;
15340}
15341
15342
15343/**
15344 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
15345 */
15346HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15347{
15348 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15349 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
15350
15351 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15352 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15353 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15354 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15355 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15356
15357 /*
15358 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15359 */
15360 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15361 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15362 {
15363 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
15364 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
15365 {
15366 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15367 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15368 }
15369 }
15370 else
15371 {
15372 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15373 return rcStrict;
15374 }
15375
15376 /* IOMMIOPhysHandler() below may call into IEM, save the necessary state. */
15377 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15378 hmR0VmxReadExitQualVmcs(pVmxTransient);
15379 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15380 AssertRCReturn(rc, rc);
15381
15382 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
15383 uint32_t const uAccessType = VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual);
15384 switch (uAccessType)
15385 {
15386 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
15387 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
15388 {
15389 AssertMsg( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
15390 || VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual) != XAPIC_OFF_TPR,
15391 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
15392
15393 RTGCPHYS GCPhys = pVCpu->hm.s.vmx.u64GstMsrApicBase; /* Always up-to-date, as it is not part of the VMCS. */
15394 GCPhys &= PAGE_BASE_GC_MASK;
15395 GCPhys += VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual);
15396 Log4Func(("Linear access uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
15397 VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual)));
15398
15399 PVM pVM = pVCpu->CTX_SUFF(pVM);
15400 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15401 rcStrict = IOMMMIOPhysHandler(pVM, pVCpu,
15402 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW,
15403 CPUMCTX2CORE(pCtx), GCPhys);
15404 Log4Func(("IOMMMIOPhysHandler returned %Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15405 if ( rcStrict == VINF_SUCCESS
15406 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15407 || rcStrict == VERR_PAGE_NOT_PRESENT)
15408 {
15409 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15410 | HM_CHANGED_GUEST_APIC_TPR);
15411 rcStrict = VINF_SUCCESS;
15412 }
15413 break;
15414 }
15415
15416 default:
15417 {
15418 Log4Func(("uAccessType=%#x\n", uAccessType));
15419 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
15420 break;
15421 }
15422 }
15423
15424 if (rcStrict != VINF_SUCCESS)
15425 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
15426 return rcStrict;
15427}
15428
15429
15430/**
15431 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
15432 * VM-exit.
15433 */
15434HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15435{
15436 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15437 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15438
15439 /* We might get this VM-exit if the nested-guest is not intercepting MOV DRx accesses. */
15440 if (!pVmxTransient->fIsNestedGuest)
15441 {
15442 /* We should -not- get this VM-exit if the guest's debug registers were active. */
15443 if (pVmxTransient->fWasGuestDebugStateActive)
15444 {
15445 AssertMsgFailed(("Unexpected MOV DRx exit\n"));
15446 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
15447 }
15448
15449 if ( !pVCpu->hm.s.fSingleInstruction
15450 && !pVmxTransient->fWasHyperDebugStateActive)
15451 {
15452 Assert(!DBGFIsStepping(pVCpu));
15453 Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB));
15454
15455 /* Don't intercept MOV DRx any more. */
15456 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
15457 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15458 AssertRC(rc);
15459
15460 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
15461 VMMRZCallRing3Disable(pVCpu);
15462 HM_DISABLE_PREEMPT(pVCpu);
15463
15464 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
15465 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
15466 Assert(CPUMIsGuestDebugStateActive(pVCpu));
15467
15468 HM_RESTORE_PREEMPT();
15469 VMMRZCallRing3Enable(pVCpu);
15470
15471#ifdef VBOX_WITH_STATISTICS
15472 hmR0VmxReadExitQualVmcs(pVmxTransient);
15473 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
15474 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
15475 else
15476 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
15477#endif
15478 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
15479 return VINF_SUCCESS;
15480 }
15481 }
15482
15483 /*
15484 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER MSR, CS.
15485 * The EFER MSR is always up-to-date.
15486 * Update the segment registers and DR7 from the CPU.
15487 */
15488 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15489 hmR0VmxReadExitQualVmcs(pVmxTransient);
15490 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_DR7);
15491 AssertRCReturn(rc, rc);
15492 Log4Func(("cs:rip=%#04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
15493
15494 PVM pVM = pVCpu->CTX_SUFF(pVM);
15495 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
15496 {
15497 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pCtx),
15498 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual),
15499 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual));
15500 if (RT_SUCCESS(rc))
15501 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
15502 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
15503 }
15504 else
15505 {
15506 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pCtx),
15507 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual),
15508 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual));
15509 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
15510 }
15511
15512 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
15513 if (RT_SUCCESS(rc))
15514 {
15515 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15516 AssertRCReturn(rc2, rc2);
15517 return VINF_SUCCESS;
15518 }
15519 return rc;
15520}
15521
15522
15523/**
15524 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
15525 * Conditional VM-exit.
15526 */
15527HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15528{
15529 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15530 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
15531
15532 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15533 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15534 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15535 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15536 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15537
15538 /*
15539 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15540 */
15541 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15542 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15543 {
15544 /*
15545 * In the unlikely case where delivering an event causes an EPT misconfig (MMIO), go back to
15546 * instruction emulation to inject the original event. Otherwise, injecting the original event
15547 * using hardware-assisted VMX would would trigger the same EPT misconfig VM-exit again.
15548 */
15549 if (!pVCpu->hm.s.Event.fPending)
15550 { /* likely */ }
15551 else
15552 {
15553 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15554#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
15555 /** @todo NSTVMX: Think about how this should be handled. */
15556 if (pVmxTransient->fIsNestedGuest)
15557 return VERR_VMX_IPE_3;
15558#endif
15559 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15560 }
15561 }
15562 else
15563 {
15564 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15565 return rcStrict;
15566 }
15567
15568 /*
15569 * Get sufficent state and update the exit history entry.
15570 */
15571 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15572 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
15573 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15574 AssertRCReturn(rc, rc);
15575
15576 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
15577 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15578 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_MMIO),
15579 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15580 if (!pExitRec)
15581 {
15582 /*
15583 * If we succeed, resume guest execution.
15584 * If we fail in interpreting the instruction because we couldn't get the guest physical address
15585 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
15586 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
15587 * weird case. See @bugref{6043}.
15588 */
15589 PVM pVM = pVCpu->CTX_SUFF(pVM);
15590 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15591 rcStrict = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pCtx), GCPhys, UINT32_MAX);
15592 Log4Func(("At %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pCtx->rip, VBOXSTRICTRC_VAL(rcStrict)));
15593 if ( rcStrict == VINF_SUCCESS
15594 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15595 || rcStrict == VERR_PAGE_NOT_PRESENT)
15596 {
15597 /* Successfully handled MMIO operation. */
15598 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15599 | HM_CHANGED_GUEST_APIC_TPR);
15600 rcStrict = VINF_SUCCESS;
15601 }
15602 }
15603 else
15604 {
15605 /*
15606 * Frequent exit or something needing probing. Call EMHistoryExec.
15607 */
15608 Log4(("EptMisscfgExit/%u: %04x:%08RX64: %RGp -> EMHistoryExec\n",
15609 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPhys));
15610
15611 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15612 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15613
15614 Log4(("EptMisscfgExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15615 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15616 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15617 }
15618 return rcStrict;
15619}
15620
15621
15622/**
15623 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
15624 * VM-exit.
15625 */
15626HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15627{
15628 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15629 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
15630
15631 hmR0VmxReadExitQualVmcs(pVmxTransient);
15632 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15633 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15634 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15635 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15636 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15637
15638 /*
15639 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15640 */
15641 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15642 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15643 {
15644 /*
15645 * If delivery of an event causes an EPT violation (true nested #PF and not MMIO),
15646 * we shall resolve the nested #PF and re-inject the original event.
15647 */
15648 if (pVCpu->hm.s.Event.fPending)
15649 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflectNPF);
15650 }
15651 else
15652 {
15653 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15654 return rcStrict;
15655 }
15656
15657 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15658 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
15659 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15660 AssertRCReturn(rc, rc);
15661
15662 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
15663 uint64_t const uExitQual = pVmxTransient->uExitQual;
15664 AssertMsg(((pVmxTransient->uExitQual >> 7) & 3) != 2, ("%#RX64", uExitQual));
15665
15666 RTGCUINT uErrorCode = 0;
15667 if (uExitQual & VMX_EXIT_QUAL_EPT_INSTR_FETCH)
15668 uErrorCode |= X86_TRAP_PF_ID;
15669 if (uExitQual & VMX_EXIT_QUAL_EPT_DATA_WRITE)
15670 uErrorCode |= X86_TRAP_PF_RW;
15671 if (uExitQual & VMX_EXIT_QUAL_EPT_ENTRY_PRESENT)
15672 uErrorCode |= X86_TRAP_PF_P;
15673
15674 PVM pVM = pVCpu->CTX_SUFF(pVM);
15675 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15676 Log4Func(("at %#RX64 (%#RX64 errcode=%#x) cs:rip=%#04x:%#RX64\n", GCPhys, uExitQual, uErrorCode, pCtx->cs.Sel, pCtx->rip));
15677
15678 /*
15679 * Handle the pagefault trap for the nested shadow table.
15680 */
15681 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
15682 rcStrict = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pCtx), GCPhys);
15683 TRPMResetTrap(pVCpu);
15684
15685 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
15686 if ( rcStrict == VINF_SUCCESS
15687 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15688 || rcStrict == VERR_PAGE_NOT_PRESENT)
15689 {
15690 /* Successfully synced our nested page tables. */
15691 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
15692 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS);
15693 return VINF_SUCCESS;
15694 }
15695
15696 Log4Func(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15697 return rcStrict;
15698}
15699
15700
15701#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
15702/**
15703 * VM-exit handler for VMCLEAR (VMX_EXIT_VMCLEAR). Unconditional VM-exit.
15704 */
15705HMVMX_EXIT_DECL hmR0VmxExitVmclear(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15706{
15707 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15708
15709 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15710 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15711 hmR0VmxReadExitQualVmcs(pVmxTransient);
15712 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15713 | CPUMCTX_EXTRN_HWVIRT
15714 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15715 AssertRCReturn(rc, rc);
15716
15717 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15718
15719 VMXVEXITINFO ExitInfo;
15720 RT_ZERO(ExitInfo);
15721 ExitInfo.uReason = pVmxTransient->uExitReason;
15722 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15723 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15724 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15725 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15726
15727 VBOXSTRICTRC rcStrict = IEMExecDecodedVmclear(pVCpu, &ExitInfo);
15728 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15729 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15730 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15731 {
15732 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15733 rcStrict = VINF_SUCCESS;
15734 }
15735 return rcStrict;
15736}
15737
15738
15739/**
15740 * VM-exit handler for VMLAUNCH (VMX_EXIT_VMLAUNCH). Unconditional VM-exit.
15741 */
15742HMVMX_EXIT_DECL hmR0VmxExitVmlaunch(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15743{
15744 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15745
15746 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMLAUNCH,
15747 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
15748 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15749 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15750 AssertRCReturn(rc, rc);
15751
15752 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15753
15754 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
15755 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbInstr, VMXINSTRID_VMLAUNCH);
15756 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
15757 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15758 {
15759 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15760 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
15761 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
15762 }
15763 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15764 return rcStrict;
15765}
15766
15767
15768/**
15769 * VM-exit handler for VMPTRLD (VMX_EXIT_VMPTRLD). Unconditional VM-exit.
15770 */
15771HMVMX_EXIT_DECL hmR0VmxExitVmptrld(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15772{
15773 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15774
15775 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15776 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15777 hmR0VmxReadExitQualVmcs(pVmxTransient);
15778 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15779 | CPUMCTX_EXTRN_HWVIRT
15780 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15781 AssertRCReturn(rc, rc);
15782
15783 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15784
15785 VMXVEXITINFO ExitInfo;
15786 RT_ZERO(ExitInfo);
15787 ExitInfo.uReason = pVmxTransient->uExitReason;
15788 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15789 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15790 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15791 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15792
15793 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrld(pVCpu, &ExitInfo);
15794 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15795 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15796 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15797 {
15798 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15799 rcStrict = VINF_SUCCESS;
15800 }
15801 return rcStrict;
15802}
15803
15804
15805/**
15806 * VM-exit handler for VMPTRST (VMX_EXIT_VMPTRST). Unconditional VM-exit.
15807 */
15808HMVMX_EXIT_DECL hmR0VmxExitVmptrst(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15809{
15810 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15811
15812 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15813 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15814 hmR0VmxReadExitQualVmcs(pVmxTransient);
15815 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15816 | CPUMCTX_EXTRN_HWVIRT
15817 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15818 AssertRCReturn(rc, rc);
15819
15820 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15821
15822 VMXVEXITINFO ExitInfo;
15823 RT_ZERO(ExitInfo);
15824 ExitInfo.uReason = pVmxTransient->uExitReason;
15825 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15826 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15827 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15828 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
15829
15830 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrst(pVCpu, &ExitInfo);
15831 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15832 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15833 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15834 {
15835 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15836 rcStrict = VINF_SUCCESS;
15837 }
15838 return rcStrict;
15839}
15840
15841
15842/**
15843 * VM-exit handler for VMREAD (VMX_EXIT_VMREAD). Conditional VM-exit.
15844 */
15845HMVMX_EXIT_DECL hmR0VmxExitVmread(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15846{
15847 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15848
15849 /*
15850 * Strictly speaking we should not get VMREAD VM-exits for shadow VMCS fields and
15851 * thus might not need to import the shadow VMCS state, it's safer just in case
15852 * code elsewhere dares look at unsynced VMCS fields.
15853 */
15854 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15855 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15856 hmR0VmxReadExitQualVmcs(pVmxTransient);
15857 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15858 | CPUMCTX_EXTRN_HWVIRT
15859 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15860 AssertRCReturn(rc, rc);
15861
15862 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15863
15864 VMXVEXITINFO ExitInfo;
15865 RT_ZERO(ExitInfo);
15866 ExitInfo.uReason = pVmxTransient->uExitReason;
15867 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15868 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15869 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15870 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
15871 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
15872
15873 VBOXSTRICTRC rcStrict = IEMExecDecodedVmread(pVCpu, &ExitInfo);
15874 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15875 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15876 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15877 {
15878 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15879 rcStrict = VINF_SUCCESS;
15880 }
15881 return rcStrict;
15882}
15883
15884
15885/**
15886 * VM-exit handler for VMRESUME (VMX_EXIT_VMRESUME). Unconditional VM-exit.
15887 */
15888HMVMX_EXIT_DECL hmR0VmxExitVmresume(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15889{
15890 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15891
15892 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMRESUME,
15893 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
15894 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15895 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15896 AssertRCReturn(rc, rc);
15897
15898 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15899
15900 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
15901 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbInstr, VMXINSTRID_VMRESUME);
15902 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
15903 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15904 {
15905 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15906 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
15907 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
15908 }
15909 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15910 return rcStrict;
15911}
15912
15913
15914/**
15915 * VM-exit handler for VMWRITE (VMX_EXIT_VMWRITE). Conditional VM-exit.
15916 */
15917HMVMX_EXIT_DECL hmR0VmxExitVmwrite(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15918{
15919 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15920
15921 /*
15922 * Although we should not get VMWRITE VM-exits for shadow VMCS fields, since our HM hook
15923 * gets invoked when IEM's VMWRITE instruction emulation modifies the current VMCS and it
15924 * flags re-loading the entire shadow VMCS, we should save the entire shadow VMCS here.
15925 */
15926 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15927 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15928 hmR0VmxReadExitQualVmcs(pVmxTransient);
15929 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15930 | CPUMCTX_EXTRN_HWVIRT
15931 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15932 AssertRCReturn(rc, rc);
15933
15934 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15935
15936 VMXVEXITINFO ExitInfo;
15937 RT_ZERO(ExitInfo);
15938 ExitInfo.uReason = pVmxTransient->uExitReason;
15939 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15940 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15941 ExitInfo.cbInstr = pVmxTransient->cbInstr;
15942 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
15943 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15944
15945 VBOXSTRICTRC rcStrict = IEMExecDecodedVmwrite(pVCpu, &ExitInfo);
15946 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15947 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15948 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15949 {
15950 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15951 rcStrict = VINF_SUCCESS;
15952 }
15953 return rcStrict;
15954}
15955
15956
15957/**
15958 * VM-exit handler for VMXOFF (VMX_EXIT_VMXOFF). Unconditional VM-exit.
15959 */
15960HMVMX_EXIT_DECL hmR0VmxExitVmxoff(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15961{
15962 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15963
15964 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15965 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR4
15966 | CPUMCTX_EXTRN_HWVIRT
15967 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
15968 AssertRCReturn(rc, rc);
15969
15970 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15971
15972 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxoff(pVCpu, pVmxTransient->cbInstr);
15973 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15974 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_HWVIRT);
15975 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15976 {
15977 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15978 rcStrict = VINF_SUCCESS;
15979 }
15980 return rcStrict;
15981}
15982
15983
15984/**
15985 * VM-exit handler for VMXON (VMX_EXIT_VMXON). Unconditional VM-exit.
15986 */
15987HMVMX_EXIT_DECL hmR0VmxExitVmxon(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
15988{
15989 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15990
15991 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15992 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15993 hmR0VmxReadExitQualVmcs(pVmxTransient);
15994 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15995 | CPUMCTX_EXTRN_HWVIRT
15996 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15997 AssertRCReturn(rc, rc);
15998
15999 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16000
16001 VMXVEXITINFO ExitInfo;
16002 RT_ZERO(ExitInfo);
16003 ExitInfo.uReason = pVmxTransient->uExitReason;
16004 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16005 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16006 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16007 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16008
16009 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxon(pVCpu, &ExitInfo);
16010 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16011 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16012 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16013 {
16014 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16015 rcStrict = VINF_SUCCESS;
16016 }
16017 return rcStrict;
16018}
16019
16020
16021/**
16022 * VM-exit handler for INVVPID (VMX_EXIT_INVVPID). Unconditional VM-exit.
16023 */
16024HMVMX_EXIT_DECL hmR0VmxExitInvvpid(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16025{
16026 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16027
16028 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16029 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16030 hmR0VmxReadExitQualVmcs(pVmxTransient);
16031 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16032 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16033 AssertRCReturn(rc, rc);
16034
16035 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16036
16037 VMXVEXITINFO ExitInfo;
16038 RT_ZERO(ExitInfo);
16039 ExitInfo.uReason = pVmxTransient->uExitReason;
16040 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16041 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16042 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16043 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16044
16045 VBOXSTRICTRC rcStrict = IEMExecDecodedInvvpid(pVCpu, &ExitInfo);
16046 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16047 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16048 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16049 {
16050 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16051 rcStrict = VINF_SUCCESS;
16052 }
16053 return rcStrict;
16054}
16055#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16056/** @} */
16057
16058
16059#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16060/** @name Nested-guest VM-exit handlers.
16061 * @{
16062 */
16063/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16064/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Nested-guest VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16065/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16066
16067/**
16068 * Nested-guest VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
16069 * Conditional VM-exit.
16070 */
16071HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmiNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16072{
16073 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16074
16075 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16076
16077 uint64_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
16078 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
16079 Assert(VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo));
16080
16081 switch (uExitIntType)
16082 {
16083 /*
16084 * Physical NMIs:
16085 * We shouldn't direct host physical NMIs to the nested-guest. Dispatch it to the host.
16086 */
16087 case VMX_EXIT_INT_INFO_TYPE_NMI:
16088 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
16089
16090 /*
16091 * Hardware exceptions,
16092 * Software exceptions,
16093 * Privileged software exceptions:
16094 * Figure out if the exception must be delivered to the guest or the nested-guest.
16095 */
16096 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
16097 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
16098 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
16099 {
16100 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16101 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16102 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16103 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16104
16105 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16106 bool const fIntercept = CPUMIsGuestVmxXcptInterceptSet(pVCpu, pCtx, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo),
16107 pVmxTransient->uExitIntErrorCode);
16108 if (fIntercept)
16109 {
16110 /* Exit qualification is required for debug and page-fault exceptions. */
16111 hmR0VmxReadExitQualVmcs(pVmxTransient);
16112
16113 /*
16114 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged
16115 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
16116 * length. However, if delivery of a software interrupt, software exception or privileged
16117 * software exception causes a VM-exit, that too provides the VM-exit instruction length.
16118 */
16119 VMXVEXITINFO ExitInfo;
16120 RT_ZERO(ExitInfo);
16121 ExitInfo.uReason = pVmxTransient->uExitReason;
16122 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16123 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16124
16125 VMXVEXITEVENTINFO ExitEventInfo;
16126 RT_ZERO(ExitEventInfo);
16127 ExitEventInfo.uExitIntInfo = pVmxTransient->uExitIntInfo;
16128 ExitEventInfo.uExitIntErrCode = pVmxTransient->uExitIntErrorCode;
16129 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16130 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16131
16132#ifdef DEBUG_ramshankar
16133 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
16134 Log4Func(("cs:rip=%#04x:%#RX64 %s err_code=%#x exit_qual=%#RX64\n", pCtx->cs.Sel, pCtx->rip,
16135 VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo) ? "#PF" : "Unk",
16136 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual));
16137 Log4Func(("idt_info=%#RX64 (%s) idt_errcode=%#RX32\n", pVmxTransient->uIdtVectoringInfo,
16138 VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo) ? "Valid" : "Invalid",
16139 pVmxTransient->uIdtVectoringErrorCode));
16140#endif
16141 return IEMExecVmxVmexitXcpt(pVCpu, &ExitInfo, &ExitEventInfo);
16142 }
16143
16144 /* Nested paging is currently a requirement, otherwise we would need to handle shadow #PFs in hmR0VmxExitXcptPF. */
16145 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
16146 return hmR0VmxExitXcpt(pVCpu, pVmxTransient);
16147 }
16148
16149 /*
16150 * Software interrupts:
16151 * VM-exits cannot be caused by software interrupts.
16152 *
16153 * External interrupts:
16154 * This should only happen when "acknowledge external interrupts on VM-exit"
16155 * control is set. However, we never set this when executing a guest or
16156 * nested-guest. For nested-guests it is emulated while injecting interrupts into
16157 * the guest.
16158 */
16159 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
16160 case VMX_EXIT_INT_INFO_TYPE_EXT_INT:
16161 default:
16162 {
16163 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
16164 return VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
16165 }
16166 }
16167}
16168
16169
16170/**
16171 * Nested-guest VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT).
16172 * Unconditional VM-exit.
16173 */
16174HMVMX_EXIT_DECL hmR0VmxExitTripleFaultNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16175{
16176 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16177 return IEMExecVmxVmexitTripleFault(pVCpu);
16178}
16179
16180
16181/**
16182 * Nested-guest VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
16183 */
16184HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindowNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16185{
16186 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16187
16188 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
16189 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16190 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16191}
16192
16193
16194/**
16195 * Nested-guest VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
16196 */
16197HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindowNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16198{
16199 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16200
16201 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT))
16202 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16203 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16204}
16205
16206
16207/**
16208 * Nested-guest VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH).
16209 * Unconditional VM-exit.
16210 */
16211HMVMX_EXIT_DECL hmR0VmxExitTaskSwitchNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16212{
16213 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16214
16215 hmR0VmxReadExitQualVmcs(pVmxTransient);
16216 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16217 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16218 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16219
16220 VMXVEXITINFO ExitInfo;
16221 RT_ZERO(ExitInfo);
16222 ExitInfo.uReason = pVmxTransient->uExitReason;
16223 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16224 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16225
16226 VMXVEXITEVENTINFO ExitEventInfo;
16227 RT_ZERO(ExitEventInfo);
16228 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16229 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16230 return IEMExecVmxVmexitTaskSwitch(pVCpu, &ExitInfo, &ExitEventInfo);
16231}
16232
16233
16234/**
16235 * Nested-guest VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
16236 */
16237HMVMX_EXIT_DECL hmR0VmxExitHltNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16238{
16239 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16240
16241 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_HLT_EXIT))
16242 {
16243 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16244 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16245 }
16246 return hmR0VmxExitHlt(pVCpu, pVmxTransient);
16247}
16248
16249
16250/**
16251 * Nested-guest VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
16252 */
16253HMVMX_EXIT_DECL hmR0VmxExitInvlpgNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16254{
16255 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16256
16257 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16258 {
16259 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16260 hmR0VmxReadExitQualVmcs(pVmxTransient);
16261
16262 VMXVEXITINFO ExitInfo;
16263 RT_ZERO(ExitInfo);
16264 ExitInfo.uReason = pVmxTransient->uExitReason;
16265 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16266 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16267 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16268 }
16269 return hmR0VmxExitInvlpg(pVCpu, pVmxTransient);
16270}
16271
16272
16273/**
16274 * Nested-guest VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
16275 */
16276HMVMX_EXIT_DECL hmR0VmxExitRdpmcNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16277{
16278 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16279
16280 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDPMC_EXIT))
16281 {
16282 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16283 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16284 }
16285 return hmR0VmxExitRdpmc(pVCpu, pVmxTransient);
16286}
16287
16288
16289/**
16290 * Nested-guest VM-exit handler for VMREAD (VMX_EXIT_VMREAD) and VMWRITE
16291 * (VMX_EXIT_VMWRITE). Conditional VM-exit.
16292 */
16293HMVMX_EXIT_DECL hmR0VmxExitVmreadVmwriteNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16294{
16295 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16296
16297 Assert( pVmxTransient->uExitReason == VMX_EXIT_VMREAD
16298 || pVmxTransient->uExitReason == VMX_EXIT_VMWRITE);
16299
16300 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16301
16302 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
16303 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16304 uint64_t u64VmcsField = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16305
16306 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
16307 if (!CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
16308 u64VmcsField &= UINT64_C(0xffffffff);
16309
16310 if (CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, pVmxTransient->uExitReason, u64VmcsField))
16311 {
16312 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16313 hmR0VmxReadExitQualVmcs(pVmxTransient);
16314
16315 VMXVEXITINFO ExitInfo;
16316 RT_ZERO(ExitInfo);
16317 ExitInfo.uReason = pVmxTransient->uExitReason;
16318 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16319 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16320 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16321 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16322 }
16323
16324 if (pVmxTransient->uExitReason == VMX_EXIT_VMREAD)
16325 return hmR0VmxExitVmread(pVCpu, pVmxTransient);
16326 return hmR0VmxExitVmwrite(pVCpu, pVmxTransient);
16327}
16328
16329
16330/**
16331 * Nested-guest VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
16332 */
16333HMVMX_EXIT_DECL hmR0VmxExitRdtscNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16334{
16335 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16336
16337 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16338 {
16339 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16340 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16341 }
16342
16343 return hmR0VmxExitRdtsc(pVCpu, pVmxTransient);
16344}
16345
16346
16347/**
16348 * Nested-guest VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX).
16349 * Conditional VM-exit.
16350 */
16351HMVMX_EXIT_DECL hmR0VmxExitMovCRxNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16352{
16353 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16354
16355 hmR0VmxReadExitQualVmcs(pVmxTransient);
16356 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16357
16358 VBOXSTRICTRC rcStrict;
16359 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual);
16360 switch (uAccessType)
16361 {
16362 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
16363 {
16364 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16365 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
16366 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16367 uint64_t const uNewCrX = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16368
16369 bool fIntercept;
16370 switch (iCrReg)
16371 {
16372 case 0:
16373 case 4:
16374 fIntercept = CPUMIsGuestVmxMovToCr0Cr4InterceptSet(pVCpu, &pVCpu->cpum.GstCtx, iCrReg, uNewCrX);
16375 break;
16376
16377 case 3:
16378 fIntercept = CPUMIsGuestVmxMovToCr3InterceptSet(pVCpu, uNewCrX);
16379 break;
16380
16381 case 8:
16382 fIntercept = CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_CR8_LOAD_EXIT);
16383 break;
16384
16385 default:
16386 fIntercept = false;
16387 break;
16388 }
16389 if (fIntercept)
16390 {
16391 VMXVEXITINFO ExitInfo;
16392 RT_ZERO(ExitInfo);
16393 ExitInfo.uReason = pVmxTransient->uExitReason;
16394 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16395 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16396 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16397 }
16398 else
16399 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbInstr, iGReg, iCrReg);
16400 break;
16401 }
16402
16403 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
16404 {
16405 /*
16406 * CR0/CR4 reads do not cause VM-exits, the read-shadow is used (subject to masking).
16407 * CR2 reads do not cause a VM-exit.
16408 * CR3 reads cause a VM-exit depending on the "CR3 store exiting" control.
16409 * CR8 reads cause a VM-exit depending on the "CR8 store exiting" control.
16410 */
16411 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16412 if ( iCrReg == 3
16413 || iCrReg == 8)
16414 {
16415 static const uint32_t s_auCrXReadIntercepts[] = { 0, 0, 0, VMX_PROC_CTLS_CR3_STORE_EXIT, 0,
16416 0, 0, 0, VMX_PROC_CTLS_CR8_STORE_EXIT };
16417 uint32_t const uIntercept = s_auCrXReadIntercepts[iCrReg];
16418 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uIntercept))
16419 {
16420 VMXVEXITINFO ExitInfo;
16421 RT_ZERO(ExitInfo);
16422 ExitInfo.uReason = pVmxTransient->uExitReason;
16423 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16424 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16425 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16426 }
16427 else
16428 {
16429 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
16430 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbInstr, iGReg, iCrReg);
16431 }
16432 }
16433 else
16434 {
16435 AssertMsgFailed(("MOV from CR%d VM-exit must not happen\n", iCrReg));
16436 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, iCrReg);
16437 }
16438 break;
16439 }
16440
16441 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
16442 {
16443 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
16444 Assert(pVmcsNstGst);
16445 uint64_t const uGstHostMask = pVmcsNstGst->u64Cr0Mask.u;
16446 uint64_t const uReadShadow = pVmcsNstGst->u64Cr0ReadShadow.u;
16447 if ( (uGstHostMask & X86_CR0_TS)
16448 && (uReadShadow & X86_CR0_TS))
16449 {
16450 VMXVEXITINFO ExitInfo;
16451 RT_ZERO(ExitInfo);
16452 ExitInfo.uReason = pVmxTransient->uExitReason;
16453 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16454 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16455 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16456 }
16457 else
16458 rcStrict = hmR0VmxExitClts(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbInstr);
16459 break;
16460 }
16461
16462 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
16463 {
16464 RTGCPTR GCPtrEffDst;
16465 uint16_t const uNewMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(pVmxTransient->uExitQual);
16466 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(pVmxTransient->uExitQual);
16467 if (fMemOperand)
16468 {
16469 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
16470 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
16471 }
16472 else
16473 GCPtrEffDst = NIL_RTGCPTR;
16474
16475 if (CPUMIsGuestVmxLmswInterceptSet(pVCpu, &pVCpu->cpum.GstCtx, uNewMsw))
16476 {
16477 VMXVEXITINFO ExitInfo;
16478 RT_ZERO(ExitInfo);
16479 ExitInfo.uReason = pVmxTransient->uExitReason;
16480 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16481 ExitInfo.u64GuestLinearAddr = GCPtrEffDst;
16482 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16483 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16484 }
16485 else
16486 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbInstr, uNewMsw, GCPtrEffDst);
16487 break;
16488 }
16489
16490 default:
16491 {
16492 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
16493 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
16494 }
16495 }
16496
16497 if (rcStrict == VINF_IEM_RAISED_XCPT)
16498 {
16499 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16500 rcStrict = VINF_SUCCESS;
16501 }
16502 return rcStrict;
16503}
16504
16505
16506/**
16507 * Nested-guest VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX).
16508 * Conditional VM-exit.
16509 */
16510HMVMX_EXIT_DECL hmR0VmxExitMovDRxNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16511{
16512 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16513
16514 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MOV_DR_EXIT))
16515 {
16516 hmR0VmxReadExitQualVmcs(pVmxTransient);
16517 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16518
16519 VMXVEXITINFO ExitInfo;
16520 RT_ZERO(ExitInfo);
16521 ExitInfo.uReason = pVmxTransient->uExitReason;
16522 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16523 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16524 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16525 }
16526 return hmR0VmxExitMovDRx(pVCpu, pVmxTransient);
16527}
16528
16529
16530/**
16531 * Nested-guest VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR).
16532 * Conditional VM-exit.
16533 */
16534HMVMX_EXIT_DECL hmR0VmxExitIoInstrNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16535{
16536 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16537
16538 hmR0VmxReadExitQualVmcs(pVmxTransient);
16539
16540 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
16541 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
16542 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
16543
16544 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
16545 uint8_t const cbAccess = s_aIOSizes[uIOSize];
16546 if (CPUMIsGuestVmxIoInterceptSet(pVCpu, uIOPort, cbAccess))
16547 {
16548 /*
16549 * IN/OUT instruction:
16550 * - Provides VM-exit instruction length.
16551 *
16552 * INS/OUTS instruction:
16553 * - Provides VM-exit instruction length.
16554 * - Provides Guest-linear address.
16555 * - Optionally provides VM-exit instruction info (depends on CPU feature).
16556 */
16557 PVM pVM = pVCpu->CTX_SUFF(pVM);
16558 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16559
16560 /* Make sure we don't use stale/uninitialized VMX-transient info. below. */
16561 pVmxTransient->ExitInstrInfo.u = 0;
16562 pVmxTransient->uGuestLinearAddr = 0;
16563
16564 bool const fVmxInsOutsInfo = pVM->cpum.ro.GuestFeatures.fVmxInsOutInfo;
16565 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
16566 if (fIOString)
16567 {
16568 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
16569 if (fVmxInsOutsInfo)
16570 {
16571 Assert(RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS)); /* Paranoia. */
16572 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16573 }
16574 }
16575
16576 VMXVEXITINFO ExitInfo;
16577 RT_ZERO(ExitInfo);
16578 ExitInfo.uReason = pVmxTransient->uExitReason;
16579 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16580 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16581 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16582 ExitInfo.u64GuestLinearAddr = pVmxTransient->uGuestLinearAddr;
16583 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16584 }
16585 return hmR0VmxExitIoInstr(pVCpu, pVmxTransient);
16586}
16587
16588
16589/**
16590 * Nested-guest VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
16591 */
16592HMVMX_EXIT_DECL hmR0VmxExitRdmsrNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16593{
16594 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16595
16596 uint32_t fMsrpm;
16597 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
16598 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
16599 else
16600 fMsrpm = VMXMSRPM_EXIT_RD;
16601
16602 if (fMsrpm & VMXMSRPM_EXIT_RD)
16603 {
16604 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16605 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16606 }
16607 return hmR0VmxExitRdmsr(pVCpu, pVmxTransient);
16608}
16609
16610
16611/**
16612 * Nested-guest VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
16613 */
16614HMVMX_EXIT_DECL hmR0VmxExitWrmsrNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16615{
16616 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16617
16618 uint32_t fMsrpm;
16619 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
16620 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
16621 else
16622 fMsrpm = VMXMSRPM_EXIT_WR;
16623
16624 if (fMsrpm & VMXMSRPM_EXIT_WR)
16625 {
16626 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16627 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16628 }
16629 return hmR0VmxExitWrmsr(pVCpu, pVmxTransient);
16630}
16631
16632
16633/**
16634 * Nested-guest VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
16635 */
16636HMVMX_EXIT_DECL hmR0VmxExitMwaitNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16637{
16638 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16639
16640 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MWAIT_EXIT))
16641 {
16642 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16643 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16644 }
16645 return hmR0VmxExitMwait(pVCpu, pVmxTransient);
16646}
16647
16648
16649/**
16650 * Nested-guest VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional
16651 * VM-exit.
16652 */
16653HMVMX_EXIT_DECL hmR0VmxExitMtfNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16654{
16655 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16656
16657 /** @todo NSTVMX: Should consider debugging nested-guests using VM debugger. */
16658 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16659}
16660
16661
16662/**
16663 * Nested-guest VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
16664 */
16665HMVMX_EXIT_DECL hmR0VmxExitMonitorNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16666{
16667 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16668
16669 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MONITOR_EXIT))
16670 {
16671 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16672 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16673 }
16674 return hmR0VmxExitMonitor(pVCpu, pVmxTransient);
16675}
16676
16677
16678/**
16679 * Nested-guest VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
16680 */
16681HMVMX_EXIT_DECL hmR0VmxExitPauseNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16682{
16683 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16684
16685 /** @todo NSTVMX: Think about this more. Does the outer guest need to intercept
16686 * PAUSE when executing a nested-guest? If it does not, we would not need
16687 * to check for the intercepts here. Just call VM-exit... */
16688
16689 /* The CPU would have already performed the necessary CPL checks for PAUSE-loop exiting. */
16690 if ( CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_PAUSE_EXIT)
16691 || CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
16692 {
16693 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16694 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16695 }
16696 return hmR0VmxExitPause(pVCpu, pVmxTransient);
16697}
16698
16699
16700/**
16701 * Nested-guest VM-exit handler for when the TPR value is lowered below the
16702 * specified threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
16703 */
16704HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThresholdNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16705{
16706 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16707
16708 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_TPR_SHADOW))
16709 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16710 return hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient);
16711}
16712
16713
16714/**
16715 * Nested-guest VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional
16716 * VM-exit.
16717 */
16718HMVMX_EXIT_DECL hmR0VmxExitApicAccessNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16719{
16720 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16721
16722 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16723 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16724 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16725 hmR0VmxReadExitQualVmcs(pVmxTransient);
16726
16727 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
16728
16729 Log4Func(("at offset %#x type=%u\n", VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual),
16730 VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual)));
16731
16732 VMXVEXITINFO ExitInfo;
16733 RT_ZERO(ExitInfo);
16734 ExitInfo.uReason = pVmxTransient->uExitReason;
16735 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16736 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16737
16738 VMXVEXITEVENTINFO ExitEventInfo;
16739 RT_ZERO(ExitEventInfo);
16740 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16741 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16742 return IEMExecVmxVmexitApicAccess(pVCpu, &ExitInfo, &ExitEventInfo);
16743}
16744
16745
16746/**
16747 * Nested-guest VM-exit handler for APIC write emulation (VMX_EXIT_APIC_WRITE).
16748 * Conditional VM-exit.
16749 */
16750HMVMX_EXIT_DECL hmR0VmxExitApicWriteNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16751{
16752 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16753
16754 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_APIC_REG_VIRT));
16755 hmR0VmxReadExitQualVmcs(pVmxTransient);
16756 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
16757}
16758
16759
16760/**
16761 * Nested-guest VM-exit handler for virtualized EOI (VMX_EXIT_VIRTUALIZED_EOI).
16762 * Conditional VM-exit.
16763 */
16764HMVMX_EXIT_DECL hmR0VmxExitVirtEoiNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16765{
16766 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16767
16768 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_INT_DELIVERY));
16769 hmR0VmxReadExitQualVmcs(pVmxTransient);
16770 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
16771}
16772
16773
16774/**
16775 * Nested-guest VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
16776 */
16777HMVMX_EXIT_DECL hmR0VmxExitRdtscpNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16778{
16779 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16780
16781 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16782 {
16783 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_RDTSCP));
16784 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16785 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16786 }
16787 return hmR0VmxExitRdtscp(pVCpu, pVmxTransient);
16788}
16789
16790
16791/**
16792 * Nested-guest VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
16793 */
16794HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvdNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16795{
16796 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16797
16798 if (CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_WBINVD_EXIT))
16799 {
16800 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16801 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16802 }
16803 return hmR0VmxExitWbinvd(pVCpu, pVmxTransient);
16804}
16805
16806
16807/**
16808 * Nested-guest VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
16809 */
16810HMVMX_EXIT_DECL hmR0VmxExitInvpcidNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16811{
16812 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16813
16814 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16815 {
16816 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_INVPCID));
16817 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16818 hmR0VmxReadExitQualVmcs(pVmxTransient);
16819 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16820
16821 VMXVEXITINFO ExitInfo;
16822 RT_ZERO(ExitInfo);
16823 ExitInfo.uReason = pVmxTransient->uExitReason;
16824 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16825 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16826 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16827 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16828 }
16829 return hmR0VmxExitInvpcid(pVCpu, pVmxTransient);
16830}
16831
16832
16833/**
16834 * Nested-guest VM-exit handler for invalid-guest state
16835 * (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error VM-exit.
16836 */
16837HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestStateNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16838{
16839 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16840
16841 /*
16842 * Currently this should never happen because we fully emulate VMLAUNCH/VMRESUME in IEM.
16843 * So if it does happen, it indicates a bug possibly in the hardware-assisted VMX code.
16844 * Handle it like it's in an invalid guest state of the outer guest.
16845 *
16846 * When the fast path is implemented, this should be changed to cause the corresponding
16847 * nested-guest VM-exit.
16848 */
16849 return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
16850}
16851
16852
16853/**
16854 * Nested-guest VM-exit handler for instructions that cause VM-exits uncondtionally
16855 * and only provide the instruction length.
16856 *
16857 * Unconditional VM-exit.
16858 */
16859HMVMX_EXIT_DECL hmR0VmxExitInstrNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16860{
16861 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16862
16863#ifdef VBOX_STRICT
16864 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16865 switch (pVmxTransient->uExitReason)
16866 {
16867 case VMX_EXIT_ENCLS:
16868 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_ENCLS_EXIT));
16869 break;
16870
16871 case VMX_EXIT_VMFUNC:
16872 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_VMFUNC));
16873 break;
16874 }
16875#endif
16876
16877 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16878 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbInstr);
16879}
16880
16881
16882/**
16883 * Nested-guest VM-exit handler for instructions that provide instruction length as
16884 * well as more information.
16885 *
16886 * Unconditional VM-exit.
16887 */
16888HMVMX_EXIT_DECL hmR0VmxExitInstrWithInfoNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
16889{
16890 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16891
16892#ifdef VBOX_STRICT
16893 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16894 switch (pVmxTransient->uExitReason)
16895 {
16896 case VMX_EXIT_GDTR_IDTR_ACCESS:
16897 case VMX_EXIT_LDTR_TR_ACCESS:
16898 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_DESC_TABLE_EXIT));
16899 break;
16900
16901 case VMX_EXIT_RDRAND:
16902 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_RDRAND_EXIT));
16903 break;
16904
16905 case VMX_EXIT_RDSEED:
16906 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_RDSEED_EXIT));
16907 break;
16908
16909 case VMX_EXIT_XSAVES:
16910 case VMX_EXIT_XRSTORS:
16911 /** @todo NSTVMX: Verify XSS-bitmap. */
16912 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_XSAVES_XRSTORS));
16913 break;
16914
16915 case VMX_EXIT_UMWAIT:
16916 case VMX_EXIT_TPAUSE:
16917 Assert(CPUMIsGuestVmxProcCtlsSet(pVCpu, pCtx, VMX_PROC_CTLS_RDTSC_EXIT));
16918 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_USER_WAIT_PAUSE));
16919 break;
16920 }
16921#endif
16922
16923 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16924 hmR0VmxReadExitQualVmcs(pVmxTransient);
16925 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16926
16927 VMXVEXITINFO ExitInfo;
16928 RT_ZERO(ExitInfo);
16929 ExitInfo.uReason = pVmxTransient->uExitReason;
16930 ExitInfo.cbInstr = pVmxTransient->cbInstr;
16931 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16932 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16933 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16934}
16935
16936/** @} */
16937#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16938
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