VirtualBox

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

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

VMM/HMVMXR0: Space nit.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 702.7 KB
Line 
1/* $Id: HMVMXR0.cpp 80392 2019-08-23 05:04:15Z vboxsync $ */
2/** @file
3 * HM VMX (Intel VT-x) - Host Context Ring-0.
4 */
5
6/*
7 * Copyright (C) 2012-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_HM
23#define VMCPU_INCL_CPUM_GST_CTX
24#include <iprt/x86.h>
25#include <iprt/asm-amd64-x86.h>
26#include <iprt/thread.h>
27#include <iprt/mem.h>
28#include <iprt/mp.h>
29
30#include <VBox/vmm/pdmapi.h>
31#include <VBox/vmm/dbgf.h>
32#include <VBox/vmm/iem.h>
33#include <VBox/vmm/iom.h>
34#include <VBox/vmm/tm.h>
35#include <VBox/vmm/em.h>
36#include <VBox/vmm/gim.h>
37#include <VBox/vmm/apic.h>
38#ifdef VBOX_WITH_REM
39# include <VBox/vmm/rem.h>
40#endif
41#include "HMInternal.h"
42#include <VBox/vmm/vmcc.h>
43#include <VBox/vmm/hmvmxinline.h>
44#include "HMVMXR0.h"
45#include "dtrace/VBoxVMM.h"
46
47#ifdef DEBUG_ramshankar
48# define HMVMX_ALWAYS_SAVE_GUEST_RFLAGS
49# define HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
50# define HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE
51# define HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
52# define HMVMX_ALWAYS_CLEAN_TRANSIENT
53# define HMVMX_ALWAYS_CHECK_GUEST_STATE
54# define HMVMX_ALWAYS_TRAP_ALL_XCPTS
55# define HMVMX_ALWAYS_TRAP_PF
56# define HMVMX_ALWAYS_FLUSH_TLB
57# define HMVMX_ALWAYS_SWAP_EFER
58#endif
59
60
61/*********************************************************************************************************************************
62* Defined Constants And Macros *
63*********************************************************************************************************************************/
64/** Use the function table. */
65#define HMVMX_USE_FUNCTION_TABLE
66
67/** Determine which tagged-TLB flush handler to use. */
68#define HMVMX_FLUSH_TAGGED_TLB_EPT_VPID 0
69#define HMVMX_FLUSH_TAGGED_TLB_EPT 1
70#define HMVMX_FLUSH_TAGGED_TLB_VPID 2
71#define HMVMX_FLUSH_TAGGED_TLB_NONE 3
72
73/**
74 * Flags to skip redundant reads of some common VMCS fields that are not part of
75 * the guest-CPU or VCPU state but are needed while handling VM-exits.
76 */
77#define HMVMX_READ_IDT_VECTORING_INFO RT_BIT_32(0)
78#define HMVMX_READ_IDT_VECTORING_ERROR_CODE RT_BIT_32(1)
79#define HMVMX_READ_EXIT_QUALIFICATION RT_BIT_32(2)
80#define HMVMX_READ_EXIT_INSTR_LEN RT_BIT_32(3)
81#define HMVMX_READ_EXIT_INTERRUPTION_INFO RT_BIT_32(4)
82#define HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE RT_BIT_32(5)
83#define HMVMX_READ_EXIT_INSTR_INFO RT_BIT_32(6)
84#define HMVMX_READ_GUEST_LINEAR_ADDR RT_BIT_32(7)
85#define HMVMX_READ_GUEST_PHYSICAL_ADDR RT_BIT_32(8)
86#define HMVMX_READ_GUEST_PENDING_DBG_XCPTS RT_BIT_32(9)
87
88/** All the VMCS fields required for processing of exception/NMI VM-exits. */
89#define HMVMX_READ_XCPT_INFO ( HMVMX_READ_EXIT_INTERRUPTION_INFO \
90 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE \
91 | HMVMX_READ_EXIT_INSTR_LEN \
92 | HMVMX_READ_IDT_VECTORING_INFO \
93 | HMVMX_READ_IDT_VECTORING_ERROR_CODE)
94
95/** Assert that all the given fields have been read from the VMCS. */
96#ifdef VBOX_STRICT
97# define HMVMX_ASSERT_READ(a_pVmxTransient, a_fReadFields) \
98 do { \
99 uint32_t const fVmcsFieldRead = ASMAtomicUoReadU32(&pVmxTransient->fVmcsFieldsRead); \
100 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE(); \
101 Assert((fVmcsFieldRead & (a_fReadFields)) == (a_fReadFields)); \
102 } while (0)
103#else
104# define HMVMX_ASSERT_READ(a_pVmxTransient, a_fReadFields) do { } while (0)
105#endif
106
107/**
108 * Subset of the guest-CPU state that is kept by VMX R0 code while executing the
109 * guest using hardware-assisted VMX.
110 *
111 * This excludes state like GPRs (other than RSP) which are always are
112 * swapped and restored across the world-switch and also registers like EFER,
113 * MSR which cannot be modified by the guest without causing a VM-exit.
114 */
115#define HMVMX_CPUMCTX_EXTRN_ALL ( CPUMCTX_EXTRN_RIP \
116 | CPUMCTX_EXTRN_RFLAGS \
117 | CPUMCTX_EXTRN_RSP \
118 | CPUMCTX_EXTRN_SREG_MASK \
119 | CPUMCTX_EXTRN_TABLE_MASK \
120 | CPUMCTX_EXTRN_KERNEL_GS_BASE \
121 | CPUMCTX_EXTRN_SYSCALL_MSRS \
122 | CPUMCTX_EXTRN_SYSENTER_MSRS \
123 | CPUMCTX_EXTRN_TSC_AUX \
124 | CPUMCTX_EXTRN_OTHER_MSRS \
125 | CPUMCTX_EXTRN_CR0 \
126 | CPUMCTX_EXTRN_CR3 \
127 | CPUMCTX_EXTRN_CR4 \
128 | CPUMCTX_EXTRN_DR7 \
129 | CPUMCTX_EXTRN_HWVIRT \
130 | CPUMCTX_EXTRN_HM_VMX_MASK)
131
132/**
133 * Exception bitmap mask for real-mode guests (real-on-v86).
134 *
135 * We need to intercept all exceptions manually except:
136 * - \#AC and \#DB are always intercepted to prevent the CPU from deadlocking
137 * due to bugs in Intel CPUs.
138 * - \#PF need not be intercepted even in real-mode if we have nested paging
139 * support.
140 */
141#define HMVMX_REAL_MODE_XCPT_MASK ( RT_BIT(X86_XCPT_DE) /* always: | RT_BIT(X86_XCPT_DB) */ | RT_BIT(X86_XCPT_NMI) \
142 | RT_BIT(X86_XCPT_BP) | RT_BIT(X86_XCPT_OF) | RT_BIT(X86_XCPT_BR) \
143 | RT_BIT(X86_XCPT_UD) | RT_BIT(X86_XCPT_NM) | RT_BIT(X86_XCPT_DF) \
144 | RT_BIT(X86_XCPT_CO_SEG_OVERRUN) | RT_BIT(X86_XCPT_TS) | RT_BIT(X86_XCPT_NP) \
145 | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_GP) /* RT_BIT(X86_XCPT_PF) */ \
146 | RT_BIT(X86_XCPT_MF) /* always: | RT_BIT(X86_XCPT_AC) */ | RT_BIT(X86_XCPT_MC) \
147 | RT_BIT(X86_XCPT_XF))
148
149/** Maximum VM-instruction error number. */
150#define HMVMX_INSTR_ERROR_MAX 28
151
152/** Profiling macro. */
153#ifdef HM_PROFILE_EXIT_DISPATCH
154# define HMVMX_START_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitDispatch, ed)
155# define HMVMX_STOP_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitDispatch, ed)
156#else
157# define HMVMX_START_EXIT_DISPATCH_PROF() do { } while (0)
158# define HMVMX_STOP_EXIT_DISPATCH_PROF() do { } while (0)
159#endif
160
161/** Assert that preemption is disabled or covered by thread-context hooks. */
162#define HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu) Assert( VMMR0ThreadCtxHookIsEnabled((a_pVCpu)) \
163 || !RTThreadPreemptIsEnabled(NIL_RTTHREAD))
164
165/** Assert that we haven't migrated CPUs when thread-context hooks are not
166 * used. */
167#define HMVMX_ASSERT_CPU_SAFE(a_pVCpu) AssertMsg( VMMR0ThreadCtxHookIsEnabled((a_pVCpu)) \
168 || (a_pVCpu)->hm.s.idEnteredCpu == RTMpCpuId(), \
169 ("Illegal migration! Entered on CPU %u Current %u\n", \
170 (a_pVCpu)->hm.s.idEnteredCpu, RTMpCpuId()))
171
172/** Asserts that the given CPUMCTX_EXTRN_XXX bits are present in the guest-CPU
173 * context. */
174#define HMVMX_CPUMCTX_ASSERT(a_pVCpu, a_fExtrnMbz) AssertMsg(!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fExtrnMbz)), \
175 ("fExtrn=%#RX64 fExtrnMbz=%#RX64\n", \
176 (a_pVCpu)->cpum.GstCtx.fExtrn, (a_fExtrnMbz)))
177
178/** Log the VM-exit reason with an easily visible marker to identify it in a
179 * potential sea of logging data. */
180#define HMVMX_LOG_EXIT(a_pVCpu, a_uExitReason) \
181 do { \
182 Log4(("VM-exit: vcpu[%RU32] %85s -v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-\n", (a_pVCpu)->idCpu, \
183 HMGetVmxExitName(a_uExitReason))); \
184 } while (0) \
185
186
187/*********************************************************************************************************************************
188* Structures and Typedefs *
189*********************************************************************************************************************************/
190/**
191 * VMX per-VCPU transient state.
192 *
193 * A state structure for holding miscellaneous information across
194 * VMX non-root operation and restored after the transition.
195 */
196typedef struct VMXTRANSIENT
197{
198 /** The host's rflags/eflags. */
199 RTCCUINTREG fEFlags;
200
201 /** The guest's TPR value used for TPR shadowing. */
202 uint8_t u8GuestTpr;
203 /** Alignment. */
204 uint8_t abAlignment0[7];
205
206 /** The basic VM-exit reason. */
207 uint16_t uExitReason;
208 /** Alignment. */
209 uint16_t u16Alignment0;
210 /** The VM-exit interruption error code. */
211 uint32_t uExitIntErrorCode;
212 /** The VM-exit exit code qualification. */
213 uint64_t uExitQual;
214 /** The Guest-linear address. */
215 uint64_t uGuestLinearAddr;
216 /** The Guest-physical address. */
217 uint64_t uGuestPhysicalAddr;
218 /** The Guest pending-debug exceptions. */
219 uint64_t uGuestPendingDbgXcpts;
220
221 /** The VM-exit interruption-information field. */
222 uint32_t uExitIntInfo;
223 /** The VM-exit instruction-length field. */
224 uint32_t cbExitInstr;
225 /** The VM-exit instruction-information field. */
226 VMXEXITINSTRINFO ExitInstrInfo;
227 /** Whether the VM-entry failed or not. */
228 bool fVMEntryFailed;
229 /** Whether we are currently executing a nested-guest. */
230 bool fIsNestedGuest;
231 /** Alignment. */
232 uint8_t abAlignment1[2];
233
234 /** The VM-entry interruption-information field. */
235 uint32_t uEntryIntInfo;
236 /** The VM-entry exception error code field. */
237 uint32_t uEntryXcptErrorCode;
238 /** The VM-entry instruction length field. */
239 uint32_t cbEntryInstr;
240
241 /** IDT-vectoring information field. */
242 uint32_t uIdtVectoringInfo;
243 /** IDT-vectoring error code. */
244 uint32_t uIdtVectoringErrorCode;
245
246 /** Mask of currently read VMCS fields; HMVMX_READ_XXX. */
247 uint32_t fVmcsFieldsRead;
248
249 /** Whether the guest debug state was active at the time of VM-exit. */
250 bool fWasGuestDebugStateActive;
251 /** Whether the hyper debug state was active at the time of VM-exit. */
252 bool fWasHyperDebugStateActive;
253 /** Whether TSC-offsetting and VMX-preemption timer was updated before VM-entry. */
254 bool fUpdatedTscOffsettingAndPreemptTimer;
255 /** Whether the VM-exit was caused by a page-fault during delivery of a
256 * contributory exception or a page-fault. */
257 bool fVectoringDoublePF;
258 /** Whether the VM-exit was caused by a page-fault during delivery of an
259 * external interrupt or NMI. */
260 bool fVectoringPF;
261 /** Whether the TSC_AUX MSR needs to be removed from the auto-load/store MSR
262 * area after VM-exit. */
263 bool fRemoveTscAuxMsr;
264 bool afAlignment0[2];
265
266 /** The VMCS info. object. */
267 PVMXVMCSINFO pVmcsInfo;
268} VMXTRANSIENT;
269AssertCompileMemberAlignment(VMXTRANSIENT, uExitReason, sizeof(uint64_t));
270AssertCompileMemberAlignment(VMXTRANSIENT, uExitIntInfo, sizeof(uint64_t));
271AssertCompileMemberAlignment(VMXTRANSIENT, uEntryIntInfo, sizeof(uint64_t));
272AssertCompileMemberAlignment(VMXTRANSIENT, fWasGuestDebugStateActive, sizeof(uint64_t));
273AssertCompileMemberAlignment(VMXTRANSIENT, pVmcsInfo, sizeof(uint64_t));
274AssertCompileMemberSize(VMXTRANSIENT, ExitInstrInfo, sizeof(uint32_t));
275/** Pointer to VMX transient state. */
276typedef VMXTRANSIENT *PVMXTRANSIENT;
277/** Pointer to a const VMX transient state. */
278typedef const VMXTRANSIENT *PCVMXTRANSIENT;
279
280/**
281 * Memory operand read or write access.
282 */
283typedef enum VMXMEMACCESS
284{
285 VMXMEMACCESS_READ = 0,
286 VMXMEMACCESS_WRITE = 1
287} VMXMEMACCESS;
288
289/**
290 * VMX VM-exit handler.
291 *
292 * @returns Strict VBox status code (i.e. informational status codes too).
293 * @param pVCpu The cross context virtual CPU structure.
294 * @param pVmxTransient The VMX-transient structure.
295 */
296#ifndef HMVMX_USE_FUNCTION_TABLE
297typedef VBOXSTRICTRC FNVMXEXITHANDLER(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
298#else
299typedef DECLCALLBACK(VBOXSTRICTRC) FNVMXEXITHANDLER(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
300/** Pointer to VM-exit handler. */
301typedef FNVMXEXITHANDLER *PFNVMXEXITHANDLER;
302#endif
303
304/**
305 * VMX VM-exit handler, non-strict status code.
306 *
307 * This is generally the same as FNVMXEXITHANDLER, the NSRC bit is just FYI.
308 *
309 * @returns VBox status code, no informational status code returned.
310 * @param pVCpu The cross context virtual CPU structure.
311 * @param pVmxTransient The VMX-transient structure.
312 *
313 * @remarks This is not used on anything returning VERR_EM_INTERPRETER as the
314 * use of that status code will be replaced with VINF_EM_SOMETHING
315 * later when switching over to IEM.
316 */
317#ifndef HMVMX_USE_FUNCTION_TABLE
318typedef int FNVMXEXITHANDLERNSRC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
319#else
320typedef FNVMXEXITHANDLER FNVMXEXITHANDLERNSRC;
321#endif
322
323
324/*********************************************************************************************************************************
325* Internal Functions *
326*********************************************************************************************************************************/
327#ifndef HMVMX_USE_FUNCTION_TABLE
328DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
329# define HMVMX_EXIT_DECL DECLINLINE(VBOXSTRICTRC)
330# define HMVMX_EXIT_NSRC_DECL DECLINLINE(int)
331#else
332# define HMVMX_EXIT_DECL static DECLCALLBACK(VBOXSTRICTRC)
333# define HMVMX_EXIT_NSRC_DECL HMVMX_EXIT_DECL
334#endif
335#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
336DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
337#endif
338
339static int hmR0VmxImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat);
340
341/** @name VM-exit handler prototypes.
342 * @{
343 */
344static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmi;
345static FNVMXEXITHANDLER hmR0VmxExitExtInt;
346static FNVMXEXITHANDLER hmR0VmxExitTripleFault;
347static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindow;
348static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindow;
349static FNVMXEXITHANDLER hmR0VmxExitTaskSwitch;
350static FNVMXEXITHANDLER hmR0VmxExitCpuid;
351static FNVMXEXITHANDLER hmR0VmxExitGetsec;
352static FNVMXEXITHANDLER hmR0VmxExitHlt;
353static FNVMXEXITHANDLERNSRC hmR0VmxExitInvd;
354static FNVMXEXITHANDLER hmR0VmxExitInvlpg;
355static FNVMXEXITHANDLER hmR0VmxExitRdpmc;
356static FNVMXEXITHANDLER hmR0VmxExitVmcall;
357#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
358static FNVMXEXITHANDLER hmR0VmxExitVmclear;
359static FNVMXEXITHANDLER hmR0VmxExitVmlaunch;
360static FNVMXEXITHANDLER hmR0VmxExitVmptrld;
361static FNVMXEXITHANDLER hmR0VmxExitVmptrst;
362static FNVMXEXITHANDLER hmR0VmxExitVmread;
363static FNVMXEXITHANDLER hmR0VmxExitVmresume;
364static FNVMXEXITHANDLER hmR0VmxExitVmwrite;
365static FNVMXEXITHANDLER hmR0VmxExitVmxoff;
366static FNVMXEXITHANDLER hmR0VmxExitVmxon;
367static FNVMXEXITHANDLER hmR0VmxExitInvvpid;
368#endif
369static FNVMXEXITHANDLER hmR0VmxExitRdtsc;
370static FNVMXEXITHANDLER hmR0VmxExitMovCRx;
371static FNVMXEXITHANDLER hmR0VmxExitMovDRx;
372static FNVMXEXITHANDLER hmR0VmxExitIoInstr;
373static FNVMXEXITHANDLER hmR0VmxExitRdmsr;
374static FNVMXEXITHANDLER hmR0VmxExitWrmsr;
375static FNVMXEXITHANDLER hmR0VmxExitMwait;
376static FNVMXEXITHANDLER hmR0VmxExitMtf;
377static FNVMXEXITHANDLER hmR0VmxExitMonitor;
378static FNVMXEXITHANDLER hmR0VmxExitPause;
379static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThreshold;
380static FNVMXEXITHANDLER hmR0VmxExitApicAccess;
381static FNVMXEXITHANDLER hmR0VmxExitEptViolation;
382static FNVMXEXITHANDLER hmR0VmxExitEptMisconfig;
383static FNVMXEXITHANDLER hmR0VmxExitRdtscp;
384static FNVMXEXITHANDLER hmR0VmxExitPreemptTimer;
385static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvd;
386static FNVMXEXITHANDLER hmR0VmxExitXsetbv;
387static FNVMXEXITHANDLER hmR0VmxExitInvpcid;
388static FNVMXEXITHANDLERNSRC hmR0VmxExitSetPendingXcptUD;
389static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestState;
390static FNVMXEXITHANDLERNSRC hmR0VmxExitErrUnexpected;
391/** @} */
392
393#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
394/** @name Nested-guest VM-exit handler prototypes.
395 * @{
396 */
397static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmiNested;
398static FNVMXEXITHANDLER hmR0VmxExitTripleFaultNested;
399static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindowNested;
400static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindowNested;
401static FNVMXEXITHANDLER hmR0VmxExitTaskSwitchNested;
402static FNVMXEXITHANDLER hmR0VmxExitHltNested;
403static FNVMXEXITHANDLER hmR0VmxExitInvlpgNested;
404static FNVMXEXITHANDLER hmR0VmxExitRdpmcNested;
405static FNVMXEXITHANDLER hmR0VmxExitVmreadVmwriteNested;
406static FNVMXEXITHANDLER hmR0VmxExitRdtscNested;
407static FNVMXEXITHANDLER hmR0VmxExitMovCRxNested;
408static FNVMXEXITHANDLER hmR0VmxExitMovDRxNested;
409static FNVMXEXITHANDLER hmR0VmxExitIoInstrNested;
410static FNVMXEXITHANDLER hmR0VmxExitRdmsrNested;
411static FNVMXEXITHANDLER hmR0VmxExitWrmsrNested;
412static FNVMXEXITHANDLER hmR0VmxExitMwaitNested;
413static FNVMXEXITHANDLER hmR0VmxExitMtfNested;
414static FNVMXEXITHANDLER hmR0VmxExitMonitorNested;
415static FNVMXEXITHANDLER hmR0VmxExitPauseNested;
416static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThresholdNested;
417static FNVMXEXITHANDLER hmR0VmxExitApicAccessNested;
418static FNVMXEXITHANDLER hmR0VmxExitApicWriteNested;
419static FNVMXEXITHANDLER hmR0VmxExitVirtEoiNested;
420static FNVMXEXITHANDLER hmR0VmxExitRdtscpNested;
421static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvdNested;
422static FNVMXEXITHANDLER hmR0VmxExitInvpcidNested;
423static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestStateNested;
424static FNVMXEXITHANDLER hmR0VmxExitInstrNested;
425static FNVMXEXITHANDLER hmR0VmxExitInstrWithInfoNested;
426/** @} */
427#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
428
429
430/*********************************************************************************************************************************
431* Global Variables *
432*********************************************************************************************************************************/
433#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
434/**
435 * Array of all VMCS fields.
436 * Any fields added to the VT-x spec. should be added here.
437 *
438 * Currently only used to derive shadow VMCS fields for hardware-assisted execution
439 * of nested-guests.
440 */
441static const uint32_t g_aVmcsFields[] =
442{
443 /* 16-bit control fields. */
444 VMX_VMCS16_VPID,
445 VMX_VMCS16_POSTED_INT_NOTIFY_VECTOR,
446 VMX_VMCS16_EPTP_INDEX,
447
448 /* 16-bit guest-state fields. */
449 VMX_VMCS16_GUEST_ES_SEL,
450 VMX_VMCS16_GUEST_CS_SEL,
451 VMX_VMCS16_GUEST_SS_SEL,
452 VMX_VMCS16_GUEST_DS_SEL,
453 VMX_VMCS16_GUEST_FS_SEL,
454 VMX_VMCS16_GUEST_GS_SEL,
455 VMX_VMCS16_GUEST_LDTR_SEL,
456 VMX_VMCS16_GUEST_TR_SEL,
457 VMX_VMCS16_GUEST_INTR_STATUS,
458 VMX_VMCS16_GUEST_PML_INDEX,
459
460 /* 16-bits host-state fields. */
461 VMX_VMCS16_HOST_ES_SEL,
462 VMX_VMCS16_HOST_CS_SEL,
463 VMX_VMCS16_HOST_SS_SEL,
464 VMX_VMCS16_HOST_DS_SEL,
465 VMX_VMCS16_HOST_FS_SEL,
466 VMX_VMCS16_HOST_GS_SEL,
467 VMX_VMCS16_HOST_TR_SEL,
468
469 /* 64-bit control fields. */
470 VMX_VMCS64_CTRL_IO_BITMAP_A_FULL,
471 VMX_VMCS64_CTRL_IO_BITMAP_A_HIGH,
472 VMX_VMCS64_CTRL_IO_BITMAP_B_FULL,
473 VMX_VMCS64_CTRL_IO_BITMAP_B_HIGH,
474 VMX_VMCS64_CTRL_MSR_BITMAP_FULL,
475 VMX_VMCS64_CTRL_MSR_BITMAP_HIGH,
476 VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL,
477 VMX_VMCS64_CTRL_EXIT_MSR_STORE_HIGH,
478 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL,
479 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_HIGH,
480 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL,
481 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_HIGH,
482 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL,
483 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_HIGH,
484 VMX_VMCS64_CTRL_EXEC_PML_ADDR_FULL,
485 VMX_VMCS64_CTRL_EXEC_PML_ADDR_HIGH,
486 VMX_VMCS64_CTRL_TSC_OFFSET_FULL,
487 VMX_VMCS64_CTRL_TSC_OFFSET_HIGH,
488 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL,
489 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_HIGH,
490 VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL,
491 VMX_VMCS64_CTRL_APIC_ACCESSADDR_HIGH,
492 VMX_VMCS64_CTRL_POSTED_INTR_DESC_FULL,
493 VMX_VMCS64_CTRL_POSTED_INTR_DESC_HIGH,
494 VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL,
495 VMX_VMCS64_CTRL_VMFUNC_CTRLS_HIGH,
496 VMX_VMCS64_CTRL_EPTP_FULL,
497 VMX_VMCS64_CTRL_EPTP_HIGH,
498 VMX_VMCS64_CTRL_EOI_BITMAP_0_FULL,
499 VMX_VMCS64_CTRL_EOI_BITMAP_0_HIGH,
500 VMX_VMCS64_CTRL_EOI_BITMAP_1_FULL,
501 VMX_VMCS64_CTRL_EOI_BITMAP_1_HIGH,
502 VMX_VMCS64_CTRL_EOI_BITMAP_2_FULL,
503 VMX_VMCS64_CTRL_EOI_BITMAP_2_HIGH,
504 VMX_VMCS64_CTRL_EOI_BITMAP_3_FULL,
505 VMX_VMCS64_CTRL_EOI_BITMAP_3_HIGH,
506 VMX_VMCS64_CTRL_EPTP_LIST_FULL,
507 VMX_VMCS64_CTRL_EPTP_LIST_HIGH,
508 VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL,
509 VMX_VMCS64_CTRL_VMREAD_BITMAP_HIGH,
510 VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL,
511 VMX_VMCS64_CTRL_VMWRITE_BITMAP_HIGH,
512 VMX_VMCS64_CTRL_VIRTXCPT_INFO_ADDR_FULL,
513 VMX_VMCS64_CTRL_VIRTXCPT_INFO_ADDR_HIGH,
514 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_FULL,
515 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_HIGH,
516 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_FULL,
517 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_HIGH,
518 VMX_VMCS64_CTRL_TSC_MULTIPLIER_FULL,
519 VMX_VMCS64_CTRL_TSC_MULTIPLIER_HIGH,
520
521 /* 64-bit read-only data fields. */
522 VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL,
523 VMX_VMCS64_RO_GUEST_PHYS_ADDR_HIGH,
524
525 /* 64-bit guest-state fields. */
526 VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL,
527 VMX_VMCS64_GUEST_VMCS_LINK_PTR_HIGH,
528 VMX_VMCS64_GUEST_DEBUGCTL_FULL,
529 VMX_VMCS64_GUEST_DEBUGCTL_HIGH,
530 VMX_VMCS64_GUEST_PAT_FULL,
531 VMX_VMCS64_GUEST_PAT_HIGH,
532 VMX_VMCS64_GUEST_EFER_FULL,
533 VMX_VMCS64_GUEST_EFER_HIGH,
534 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL,
535 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_HIGH,
536 VMX_VMCS64_GUEST_PDPTE0_FULL,
537 VMX_VMCS64_GUEST_PDPTE0_HIGH,
538 VMX_VMCS64_GUEST_PDPTE1_FULL,
539 VMX_VMCS64_GUEST_PDPTE1_HIGH,
540 VMX_VMCS64_GUEST_PDPTE2_FULL,
541 VMX_VMCS64_GUEST_PDPTE2_HIGH,
542 VMX_VMCS64_GUEST_PDPTE3_FULL,
543 VMX_VMCS64_GUEST_PDPTE3_HIGH,
544 VMX_VMCS64_GUEST_BNDCFGS_FULL,
545 VMX_VMCS64_GUEST_BNDCFGS_HIGH,
546
547 /* 64-bit host-state fields. */
548 VMX_VMCS64_HOST_PAT_FULL,
549 VMX_VMCS64_HOST_PAT_HIGH,
550 VMX_VMCS64_HOST_EFER_FULL,
551 VMX_VMCS64_HOST_EFER_HIGH,
552 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL,
553 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_HIGH,
554
555 /* 32-bit control fields. */
556 VMX_VMCS32_CTRL_PIN_EXEC,
557 VMX_VMCS32_CTRL_PROC_EXEC,
558 VMX_VMCS32_CTRL_EXCEPTION_BITMAP,
559 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK,
560 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH,
561 VMX_VMCS32_CTRL_CR3_TARGET_COUNT,
562 VMX_VMCS32_CTRL_EXIT,
563 VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT,
564 VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT,
565 VMX_VMCS32_CTRL_ENTRY,
566 VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT,
567 VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO,
568 VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE,
569 VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH,
570 VMX_VMCS32_CTRL_TPR_THRESHOLD,
571 VMX_VMCS32_CTRL_PROC_EXEC2,
572 VMX_VMCS32_CTRL_PLE_GAP,
573 VMX_VMCS32_CTRL_PLE_WINDOW,
574
575 /* 32-bits read-only fields. */
576 VMX_VMCS32_RO_VM_INSTR_ERROR,
577 VMX_VMCS32_RO_EXIT_REASON,
578 VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO,
579 VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE,
580 VMX_VMCS32_RO_IDT_VECTORING_INFO,
581 VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE,
582 VMX_VMCS32_RO_EXIT_INSTR_LENGTH,
583 VMX_VMCS32_RO_EXIT_INSTR_INFO,
584
585 /* 32-bit guest-state fields. */
586 VMX_VMCS32_GUEST_ES_LIMIT,
587 VMX_VMCS32_GUEST_CS_LIMIT,
588 VMX_VMCS32_GUEST_SS_LIMIT,
589 VMX_VMCS32_GUEST_DS_LIMIT,
590 VMX_VMCS32_GUEST_FS_LIMIT,
591 VMX_VMCS32_GUEST_GS_LIMIT,
592 VMX_VMCS32_GUEST_LDTR_LIMIT,
593 VMX_VMCS32_GUEST_TR_LIMIT,
594 VMX_VMCS32_GUEST_GDTR_LIMIT,
595 VMX_VMCS32_GUEST_IDTR_LIMIT,
596 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
597 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
598 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
599 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
600 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
601 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS,
602 VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS,
603 VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS,
604 VMX_VMCS32_GUEST_INT_STATE,
605 VMX_VMCS32_GUEST_ACTIVITY_STATE,
606 VMX_VMCS32_GUEST_SMBASE,
607 VMX_VMCS32_GUEST_SYSENTER_CS,
608 VMX_VMCS32_PREEMPT_TIMER_VALUE,
609
610 /* 32-bit host-state fields. */
611 VMX_VMCS32_HOST_SYSENTER_CS,
612
613 /* Natural-width control fields. */
614 VMX_VMCS_CTRL_CR0_MASK,
615 VMX_VMCS_CTRL_CR4_MASK,
616 VMX_VMCS_CTRL_CR0_READ_SHADOW,
617 VMX_VMCS_CTRL_CR4_READ_SHADOW,
618 VMX_VMCS_CTRL_CR3_TARGET_VAL0,
619 VMX_VMCS_CTRL_CR3_TARGET_VAL1,
620 VMX_VMCS_CTRL_CR3_TARGET_VAL2,
621 VMX_VMCS_CTRL_CR3_TARGET_VAL3,
622
623 /* Natural-width read-only data fields. */
624 VMX_VMCS_RO_EXIT_QUALIFICATION,
625 VMX_VMCS_RO_IO_RCX,
626 VMX_VMCS_RO_IO_RSI,
627 VMX_VMCS_RO_IO_RDI,
628 VMX_VMCS_RO_IO_RIP,
629 VMX_VMCS_RO_GUEST_LINEAR_ADDR,
630
631 /* Natural-width guest-state field */
632 VMX_VMCS_GUEST_CR0,
633 VMX_VMCS_GUEST_CR3,
634 VMX_VMCS_GUEST_CR4,
635 VMX_VMCS_GUEST_ES_BASE,
636 VMX_VMCS_GUEST_CS_BASE,
637 VMX_VMCS_GUEST_SS_BASE,
638 VMX_VMCS_GUEST_DS_BASE,
639 VMX_VMCS_GUEST_FS_BASE,
640 VMX_VMCS_GUEST_GS_BASE,
641 VMX_VMCS_GUEST_LDTR_BASE,
642 VMX_VMCS_GUEST_TR_BASE,
643 VMX_VMCS_GUEST_GDTR_BASE,
644 VMX_VMCS_GUEST_IDTR_BASE,
645 VMX_VMCS_GUEST_DR7,
646 VMX_VMCS_GUEST_RSP,
647 VMX_VMCS_GUEST_RIP,
648 VMX_VMCS_GUEST_RFLAGS,
649 VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS,
650 VMX_VMCS_GUEST_SYSENTER_ESP,
651 VMX_VMCS_GUEST_SYSENTER_EIP,
652
653 /* Natural-width host-state fields */
654 VMX_VMCS_HOST_CR0,
655 VMX_VMCS_HOST_CR3,
656 VMX_VMCS_HOST_CR4,
657 VMX_VMCS_HOST_FS_BASE,
658 VMX_VMCS_HOST_GS_BASE,
659 VMX_VMCS_HOST_TR_BASE,
660 VMX_VMCS_HOST_GDTR_BASE,
661 VMX_VMCS_HOST_IDTR_BASE,
662 VMX_VMCS_HOST_SYSENTER_ESP,
663 VMX_VMCS_HOST_SYSENTER_EIP,
664 VMX_VMCS_HOST_RSP,
665 VMX_VMCS_HOST_RIP
666};
667#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
668
669static const uint32_t g_aVmcsSegBase[] =
670{
671 VMX_VMCS_GUEST_ES_BASE,
672 VMX_VMCS_GUEST_CS_BASE,
673 VMX_VMCS_GUEST_SS_BASE,
674 VMX_VMCS_GUEST_DS_BASE,
675 VMX_VMCS_GUEST_FS_BASE,
676 VMX_VMCS_GUEST_GS_BASE
677};
678static const uint32_t g_aVmcsSegSel[] =
679{
680 VMX_VMCS16_GUEST_ES_SEL,
681 VMX_VMCS16_GUEST_CS_SEL,
682 VMX_VMCS16_GUEST_SS_SEL,
683 VMX_VMCS16_GUEST_DS_SEL,
684 VMX_VMCS16_GUEST_FS_SEL,
685 VMX_VMCS16_GUEST_GS_SEL
686};
687static const uint32_t g_aVmcsSegLimit[] =
688{
689 VMX_VMCS32_GUEST_ES_LIMIT,
690 VMX_VMCS32_GUEST_CS_LIMIT,
691 VMX_VMCS32_GUEST_SS_LIMIT,
692 VMX_VMCS32_GUEST_DS_LIMIT,
693 VMX_VMCS32_GUEST_FS_LIMIT,
694 VMX_VMCS32_GUEST_GS_LIMIT
695};
696static const uint32_t g_aVmcsSegAttr[] =
697{
698 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
699 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
700 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
701 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
702 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
703 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS
704};
705AssertCompile(RT_ELEMENTS(g_aVmcsSegSel) == X86_SREG_COUNT);
706AssertCompile(RT_ELEMENTS(g_aVmcsSegLimit) == X86_SREG_COUNT);
707AssertCompile(RT_ELEMENTS(g_aVmcsSegBase) == X86_SREG_COUNT);
708AssertCompile(RT_ELEMENTS(g_aVmcsSegAttr) == X86_SREG_COUNT);
709
710#ifdef HMVMX_USE_FUNCTION_TABLE
711/**
712 * VMX_EXIT dispatch table.
713 */
714static const PFNVMXEXITHANDLER g_apfnVMExitHandlers[VMX_EXIT_MAX + 1] =
715{
716 /* 0 VMX_EXIT_XCPT_OR_NMI */ hmR0VmxExitXcptOrNmi,
717 /* 1 VMX_EXIT_EXT_INT */ hmR0VmxExitExtInt,
718 /* 2 VMX_EXIT_TRIPLE_FAULT */ hmR0VmxExitTripleFault,
719 /* 3 VMX_EXIT_INIT_SIGNAL */ hmR0VmxExitErrUnexpected,
720 /* 4 VMX_EXIT_SIPI */ hmR0VmxExitErrUnexpected,
721 /* 5 VMX_EXIT_IO_SMI */ hmR0VmxExitErrUnexpected,
722 /* 6 VMX_EXIT_SMI */ hmR0VmxExitErrUnexpected,
723 /* 7 VMX_EXIT_INT_WINDOW */ hmR0VmxExitIntWindow,
724 /* 8 VMX_EXIT_NMI_WINDOW */ hmR0VmxExitNmiWindow,
725 /* 9 VMX_EXIT_TASK_SWITCH */ hmR0VmxExitTaskSwitch,
726 /* 10 VMX_EXIT_CPUID */ hmR0VmxExitCpuid,
727 /* 11 VMX_EXIT_GETSEC */ hmR0VmxExitGetsec,
728 /* 12 VMX_EXIT_HLT */ hmR0VmxExitHlt,
729 /* 13 VMX_EXIT_INVD */ hmR0VmxExitInvd,
730 /* 14 VMX_EXIT_INVLPG */ hmR0VmxExitInvlpg,
731 /* 15 VMX_EXIT_RDPMC */ hmR0VmxExitRdpmc,
732 /* 16 VMX_EXIT_RDTSC */ hmR0VmxExitRdtsc,
733 /* 17 VMX_EXIT_RSM */ hmR0VmxExitErrUnexpected,
734 /* 18 VMX_EXIT_VMCALL */ hmR0VmxExitVmcall,
735#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
736 /* 19 VMX_EXIT_VMCLEAR */ hmR0VmxExitVmclear,
737 /* 20 VMX_EXIT_VMLAUNCH */ hmR0VmxExitVmlaunch,
738 /* 21 VMX_EXIT_VMPTRLD */ hmR0VmxExitVmptrld,
739 /* 22 VMX_EXIT_VMPTRST */ hmR0VmxExitVmptrst,
740 /* 23 VMX_EXIT_VMREAD */ hmR0VmxExitVmread,
741 /* 24 VMX_EXIT_VMRESUME */ hmR0VmxExitVmresume,
742 /* 25 VMX_EXIT_VMWRITE */ hmR0VmxExitVmwrite,
743 /* 26 VMX_EXIT_VMXOFF */ hmR0VmxExitVmxoff,
744 /* 27 VMX_EXIT_VMXON */ hmR0VmxExitVmxon,
745#else
746 /* 19 VMX_EXIT_VMCLEAR */ hmR0VmxExitSetPendingXcptUD,
747 /* 20 VMX_EXIT_VMLAUNCH */ hmR0VmxExitSetPendingXcptUD,
748 /* 21 VMX_EXIT_VMPTRLD */ hmR0VmxExitSetPendingXcptUD,
749 /* 22 VMX_EXIT_VMPTRST */ hmR0VmxExitSetPendingXcptUD,
750 /* 23 VMX_EXIT_VMREAD */ hmR0VmxExitSetPendingXcptUD,
751 /* 24 VMX_EXIT_VMRESUME */ hmR0VmxExitSetPendingXcptUD,
752 /* 25 VMX_EXIT_VMWRITE */ hmR0VmxExitSetPendingXcptUD,
753 /* 26 VMX_EXIT_VMXOFF */ hmR0VmxExitSetPendingXcptUD,
754 /* 27 VMX_EXIT_VMXON */ hmR0VmxExitSetPendingXcptUD,
755#endif
756 /* 28 VMX_EXIT_MOV_CRX */ hmR0VmxExitMovCRx,
757 /* 29 VMX_EXIT_MOV_DRX */ hmR0VmxExitMovDRx,
758 /* 30 VMX_EXIT_IO_INSTR */ hmR0VmxExitIoInstr,
759 /* 31 VMX_EXIT_RDMSR */ hmR0VmxExitRdmsr,
760 /* 32 VMX_EXIT_WRMSR */ hmR0VmxExitWrmsr,
761 /* 33 VMX_EXIT_ERR_INVALID_GUEST_STATE */ hmR0VmxExitErrInvalidGuestState,
762 /* 34 VMX_EXIT_ERR_MSR_LOAD */ hmR0VmxExitErrUnexpected,
763 /* 35 UNDEFINED */ hmR0VmxExitErrUnexpected,
764 /* 36 VMX_EXIT_MWAIT */ hmR0VmxExitMwait,
765 /* 37 VMX_EXIT_MTF */ hmR0VmxExitMtf,
766 /* 38 UNDEFINED */ hmR0VmxExitErrUnexpected,
767 /* 39 VMX_EXIT_MONITOR */ hmR0VmxExitMonitor,
768 /* 40 VMX_EXIT_PAUSE */ hmR0VmxExitPause,
769 /* 41 VMX_EXIT_ERR_MACHINE_CHECK */ hmR0VmxExitErrUnexpected,
770 /* 42 UNDEFINED */ hmR0VmxExitErrUnexpected,
771 /* 43 VMX_EXIT_TPR_BELOW_THRESHOLD */ hmR0VmxExitTprBelowThreshold,
772 /* 44 VMX_EXIT_APIC_ACCESS */ hmR0VmxExitApicAccess,
773 /* 45 VMX_EXIT_VIRTUALIZED_EOI */ hmR0VmxExitErrUnexpected,
774 /* 46 VMX_EXIT_GDTR_IDTR_ACCESS */ hmR0VmxExitErrUnexpected,
775 /* 47 VMX_EXIT_LDTR_TR_ACCESS */ hmR0VmxExitErrUnexpected,
776 /* 48 VMX_EXIT_EPT_VIOLATION */ hmR0VmxExitEptViolation,
777 /* 49 VMX_EXIT_EPT_MISCONFIG */ hmR0VmxExitEptMisconfig,
778 /* 50 VMX_EXIT_INVEPT */ hmR0VmxExitSetPendingXcptUD,
779 /* 51 VMX_EXIT_RDTSCP */ hmR0VmxExitRdtscp,
780 /* 52 VMX_EXIT_PREEMPT_TIMER */ hmR0VmxExitPreemptTimer,
781#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
782 /* 53 VMX_EXIT_INVVPID */ hmR0VmxExitInvvpid,
783#else
784 /* 53 VMX_EXIT_INVVPID */ hmR0VmxExitSetPendingXcptUD,
785#endif
786 /* 54 VMX_EXIT_WBINVD */ hmR0VmxExitWbinvd,
787 /* 55 VMX_EXIT_XSETBV */ hmR0VmxExitXsetbv,
788 /* 56 VMX_EXIT_APIC_WRITE */ hmR0VmxExitErrUnexpected,
789 /* 57 VMX_EXIT_RDRAND */ hmR0VmxExitErrUnexpected,
790 /* 58 VMX_EXIT_INVPCID */ hmR0VmxExitInvpcid,
791 /* 59 VMX_EXIT_VMFUNC */ hmR0VmxExitErrUnexpected,
792 /* 60 VMX_EXIT_ENCLS */ hmR0VmxExitErrUnexpected,
793 /* 61 VMX_EXIT_RDSEED */ hmR0VmxExitErrUnexpected,
794 /* 62 VMX_EXIT_PML_FULL */ hmR0VmxExitErrUnexpected,
795 /* 63 VMX_EXIT_XSAVES */ hmR0VmxExitErrUnexpected,
796 /* 64 VMX_EXIT_XRSTORS */ hmR0VmxExitErrUnexpected,
797 /* 65 UNDEFINED */ hmR0VmxExitErrUnexpected,
798 /* 66 VMX_EXIT_SPP_EVENT */ hmR0VmxExitErrUnexpected,
799 /* 67 VMX_EXIT_UMWAIT */ hmR0VmxExitErrUnexpected,
800 /* 68 VMX_EXIT_TPAUSE */ hmR0VmxExitErrUnexpected,
801};
802#endif /* HMVMX_USE_FUNCTION_TABLE */
803
804#if defined(VBOX_STRICT) && defined(LOG_ENABLED)
805static const char * const g_apszVmxInstrErrors[HMVMX_INSTR_ERROR_MAX + 1] =
806{
807 /* 0 */ "(Not Used)",
808 /* 1 */ "VMCALL executed in VMX root operation.",
809 /* 2 */ "VMCLEAR with invalid physical address.",
810 /* 3 */ "VMCLEAR with VMXON pointer.",
811 /* 4 */ "VMLAUNCH with non-clear VMCS.",
812 /* 5 */ "VMRESUME with non-launched VMCS.",
813 /* 6 */ "VMRESUME after VMXOFF",
814 /* 7 */ "VM-entry with invalid control fields.",
815 /* 8 */ "VM-entry with invalid host state fields.",
816 /* 9 */ "VMPTRLD with invalid physical address.",
817 /* 10 */ "VMPTRLD with VMXON pointer.",
818 /* 11 */ "VMPTRLD with incorrect revision identifier.",
819 /* 12 */ "VMREAD/VMWRITE from/to unsupported VMCS component.",
820 /* 13 */ "VMWRITE to read-only VMCS component.",
821 /* 14 */ "(Not Used)",
822 /* 15 */ "VMXON executed in VMX root operation.",
823 /* 16 */ "VM-entry with invalid executive-VMCS pointer.",
824 /* 17 */ "VM-entry with non-launched executing VMCS.",
825 /* 18 */ "VM-entry with executive-VMCS pointer not VMXON pointer.",
826 /* 19 */ "VMCALL with non-clear VMCS.",
827 /* 20 */ "VMCALL with invalid VM-exit control fields.",
828 /* 21 */ "(Not Used)",
829 /* 22 */ "VMCALL with incorrect MSEG revision identifier.",
830 /* 23 */ "VMXOFF under dual monitor treatment of SMIs and SMM.",
831 /* 24 */ "VMCALL with invalid SMM-monitor features.",
832 /* 25 */ "VM-entry with invalid VM-execution control fields in executive VMCS.",
833 /* 26 */ "VM-entry with events blocked by MOV SS.",
834 /* 27 */ "(Not Used)",
835 /* 28 */ "Invalid operand to INVEPT/INVVPID."
836};
837#endif /* VBOX_STRICT && LOG_ENABLED */
838
839
840/**
841 * Get the CR0 guest/host mask that does not change through the lifetime of a VM.
842 *
843 * Any bit set in this mask is owned by the host/hypervisor and would cause a
844 * VM-exit when modified by the guest.
845 *
846 * @returns The static CR0 guest/host mask.
847 * @param pVCpu The cross context virtual CPU structure.
848 */
849DECL_FORCE_INLINE(uint64_t) hmR0VmxGetFixedCr0Mask(PCVMCPUCC pVCpu)
850{
851 /*
852 * Modifications to CR0 bits that VT-x ignores saving/restoring (CD, ET, NW) and
853 * to CR0 bits that we require for shadow paging (PG) by the guest must cause VM-exits.
854 */
855 /** @todo Avoid intercepting CR0.PE with unrestricted guest execution. Fix PGM
856 * enmGuestMode to be in-sync with the current mode. See @bugref{6398}
857 * and @bugref{6944}. */
858 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
859 return ( X86_CR0_PE
860 | X86_CR0_NE
861 | (pVM->hm.s.fNestedPaging ? 0 : X86_CR0_WP)
862 | X86_CR0_PG
863 | X86_CR0_ET /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.ET */
864 | X86_CR0_CD /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.CD */
865 | X86_CR0_NW); /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.NW */
866}
867
868
869/**
870 * Gets the CR4 guest/host mask that does not change through the lifetime of a VM.
871 *
872 * Any bit set in this mask is owned by the host/hypervisor and would cause a
873 * VM-exit when modified by the guest.
874 *
875 * @returns The static CR4 guest/host mask.
876 * @param pVCpu The cross context virtual CPU structure.
877 */
878DECL_FORCE_INLINE(uint64_t) hmR0VmxGetFixedCr4Mask(PCVMCPUCC pVCpu)
879{
880 /*
881 * We need to look at the host features here (for e.g. OSXSAVE, PCID) because
882 * these bits are reserved on hardware that does not support them. Since the
883 * CPU cannot refer to our virtual CPUID, we need to intercept CR4 changes to
884 * these bits and handle it depending on whether we expose them to the guest.
885 */
886 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
887 bool const fXSaveRstor = pVM->cpum.ro.HostFeatures.fXSaveRstor;
888 bool const fPcid = pVM->cpum.ro.HostFeatures.fPcid;
889 return ( X86_CR4_VMXE
890 | X86_CR4_VME
891 | X86_CR4_PAE
892 | X86_CR4_PGE
893 | X86_CR4_PSE
894 | (fXSaveRstor ? X86_CR4_OSXSAVE : 0)
895 | (fPcid ? X86_CR4_PCIDE : 0));
896}
897
898
899/**
900 * Returns whether the the VM-exit MSR-store area differs from the VM-exit MSR-load
901 * area.
902 *
903 * @returns @c true if it's different, @c false otherwise.
904 * @param pVmcsInfo The VMCS info. object.
905 */
906DECL_FORCE_INLINE(bool) hmR0VmxIsSeparateExitMsrStoreAreaVmcs(PCVMXVMCSINFO pVmcsInfo)
907{
908 return RT_BOOL( pVmcsInfo->pvGuestMsrStore != pVmcsInfo->pvGuestMsrLoad
909 && pVmcsInfo->pvGuestMsrStore);
910}
911
912
913/**
914 * Sets the given Processor-based VM-execution controls.
915 *
916 * @param pVmxTransient The VMX-transient structure.
917 * @param uProcCtls The Processor-based VM-execution controls to set.
918 */
919static void hmR0VmxSetProcCtlsVmcs(PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
920{
921 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
922 if ((pVmcsInfo->u32ProcCtls & uProcCtls) != uProcCtls)
923 {
924 pVmcsInfo->u32ProcCtls |= uProcCtls;
925 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
926 AssertRC(rc);
927 }
928}
929
930
931/**
932 * Removes the given Processor-based VM-execution controls.
933 *
934 * @param pVCpu The cross context virtual CPU structure.
935 * @param pVmxTransient The VMX-transient structure.
936 * @param uProcCtls The Processor-based VM-execution controls to remove.
937 *
938 * @remarks When executing a nested-guest, this will not remove any of the specified
939 * controls if the guest hypervisor has set any one of them.
940 */
941static void hmR0VmxRemoveProcCtlsVmcs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
942{
943 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
944 if (pVmcsInfo->u32ProcCtls & uProcCtls)
945 {
946#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
947 bool const fRemoveCtls = !pVmxTransient->fIsNestedGuest
948 ? true
949 : !CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uProcCtls);
950#else
951 NOREF(pVCpu);
952 bool const fRemoveCtls = true;
953#endif
954 if (fRemoveCtls)
955 {
956 pVmcsInfo->u32ProcCtls &= ~uProcCtls;
957 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
958 AssertRC(rc);
959 }
960 }
961}
962
963
964/**
965 * Sets the TSC offset for the current VMCS.
966 *
967 * @param uTscOffset The TSC offset to set.
968 * @param pVmcsInfo The VMCS info. object.
969 */
970static void hmR0VmxSetTscOffsetVmcs(PVMXVMCSINFO pVmcsInfo, uint64_t uTscOffset)
971{
972 if (pVmcsInfo->u64TscOffset != uTscOffset)
973 {
974 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, uTscOffset);
975 AssertRC(rc);
976 pVmcsInfo->u64TscOffset = uTscOffset;
977 }
978}
979
980
981/**
982 * Adds one or more exceptions to the exception bitmap and commits it to the current
983 * VMCS.
984 *
985 * @param pVmxTransient The VMX-transient structure.
986 * @param uXcptMask The exception(s) to add.
987 */
988static void hmR0VmxAddXcptInterceptMask(PVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
989{
990 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
991 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
992 if ((uXcptBitmap & uXcptMask) != uXcptMask)
993 {
994 uXcptBitmap |= uXcptMask;
995 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
996 AssertRC(rc);
997 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
998 }
999}
1000
1001
1002/**
1003 * Adds an exception to the exception bitmap and commits it to the current VMCS.
1004 *
1005 * @param pVmxTransient The VMX-transient structure.
1006 * @param uXcpt The exception to add.
1007 */
1008static void hmR0VmxAddXcptIntercept(PVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1009{
1010 Assert(uXcpt <= X86_XCPT_LAST);
1011 hmR0VmxAddXcptInterceptMask(pVmxTransient, RT_BIT_32(uXcpt));
1012}
1013
1014
1015/**
1016 * Remove one or more exceptions from the exception bitmap and commits it to the
1017 * current VMCS.
1018 *
1019 * This takes care of not removing the exception intercept if a nested-guest
1020 * requires the exception to be intercepted.
1021 *
1022 * @returns VBox status code.
1023 * @param pVCpu The cross context virtual CPU structure.
1024 * @param pVmxTransient The VMX-transient structure.
1025 * @param uXcptMask The exception(s) to remove.
1026 */
1027static int hmR0VmxRemoveXcptInterceptMask(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1028{
1029 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1030 uint32_t u32XcptBitmap = pVmcsInfo->u32XcptBitmap;
1031 if (u32XcptBitmap & uXcptMask)
1032 {
1033#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1034 if (!pVmxTransient->fIsNestedGuest)
1035 { /* likely */ }
1036 else
1037 {
1038 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
1039 uXcptMask &= ~pVmcsNstGst->u32XcptBitmap;
1040 }
1041#endif
1042#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
1043 uXcptMask &= ~( RT_BIT(X86_XCPT_BP)
1044 | RT_BIT(X86_XCPT_DE)
1045 | RT_BIT(X86_XCPT_NM)
1046 | RT_BIT(X86_XCPT_TS)
1047 | RT_BIT(X86_XCPT_UD)
1048 | RT_BIT(X86_XCPT_NP)
1049 | RT_BIT(X86_XCPT_SS)
1050 | RT_BIT(X86_XCPT_GP)
1051 | RT_BIT(X86_XCPT_PF)
1052 | RT_BIT(X86_XCPT_MF));
1053#elif defined(HMVMX_ALWAYS_TRAP_PF)
1054 uXcptMask &= ~RT_BIT(X86_XCPT_PF);
1055#endif
1056 if (uXcptMask)
1057 {
1058 /* Validate we are not removing any essential exception intercepts. */
1059 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging || !(uXcptMask & RT_BIT(X86_XCPT_PF)));
1060 NOREF(pVCpu);
1061 Assert(!(uXcptMask & RT_BIT(X86_XCPT_DB)));
1062 Assert(!(uXcptMask & RT_BIT(X86_XCPT_AC)));
1063
1064 /* Remove it from the exception bitmap. */
1065 u32XcptBitmap &= ~uXcptMask;
1066
1067 /* Commit and update the cache if necessary. */
1068 if (pVmcsInfo->u32XcptBitmap != u32XcptBitmap)
1069 {
1070 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
1071 AssertRC(rc);
1072 pVmcsInfo->u32XcptBitmap = u32XcptBitmap;
1073 }
1074 }
1075 }
1076 return VINF_SUCCESS;
1077}
1078
1079
1080/**
1081 * Remove an exceptions from the exception bitmap and commits it to the current
1082 * VMCS.
1083 *
1084 * @returns VBox status code.
1085 * @param pVCpu The cross context virtual CPU structure.
1086 * @param pVmxTransient The VMX-transient structure.
1087 * @param uXcpt The exception to remove.
1088 */
1089static int hmR0VmxRemoveXcptIntercept(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1090{
1091 return hmR0VmxRemoveXcptInterceptMask(pVCpu, pVmxTransient, RT_BIT(uXcpt));
1092}
1093
1094
1095/**
1096 * Loads the VMCS specified by the VMCS info. object.
1097 *
1098 * @returns VBox status code.
1099 * @param pVmcsInfo The VMCS info. object.
1100 *
1101 * @remarks Can be called with interrupts disabled.
1102 */
1103static int hmR0VmxLoadVmcs(PVMXVMCSINFO pVmcsInfo)
1104{
1105 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1106 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1107
1108 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysVmcs);
1109 if (RT_SUCCESS(rc))
1110 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1111 return rc;
1112}
1113
1114
1115/**
1116 * Clears the VMCS specified by the VMCS info. object.
1117 *
1118 * @returns VBox status code.
1119 * @param pVmcsInfo The VMCS info. object.
1120 *
1121 * @remarks Can be called with interrupts disabled.
1122 */
1123static int hmR0VmxClearVmcs(PVMXVMCSINFO pVmcsInfo)
1124{
1125 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1126 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1127
1128 int rc = VMXClearVmcs(pVmcsInfo->HCPhysVmcs);
1129 if (RT_SUCCESS(rc))
1130 pVmcsInfo->fVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1131 return rc;
1132}
1133
1134
1135#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1136/**
1137 * Loads the shadow VMCS specified by the VMCS info. object.
1138 *
1139 * @returns VBox status code.
1140 * @param pVmcsInfo The VMCS info. object.
1141 *
1142 * @remarks Can be called with interrupts disabled.
1143 */
1144static int hmR0VmxLoadShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1145{
1146 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1147 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1148
1149 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysShadowVmcs);
1150 if (RT_SUCCESS(rc))
1151 pVmcsInfo->fShadowVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1152 return rc;
1153}
1154
1155
1156/**
1157 * Clears the shadow VMCS specified by the VMCS info. object.
1158 *
1159 * @returns VBox status code.
1160 * @param pVmcsInfo The VMCS info. object.
1161 *
1162 * @remarks Can be called with interrupts disabled.
1163 */
1164static int hmR0VmxClearShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1165{
1166 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1167 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1168
1169 int rc = VMXClearVmcs(pVmcsInfo->HCPhysShadowVmcs);
1170 if (RT_SUCCESS(rc))
1171 pVmcsInfo->fShadowVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1172 return rc;
1173}
1174
1175
1176/**
1177 * Switches from and to the specified VMCSes.
1178 *
1179 * @returns VBox status code.
1180 * @param pVmcsInfoFrom The VMCS info. object we are switching from.
1181 * @param pVmcsInfoTo The VMCS info. object we are switching to.
1182 *
1183 * @remarks Called with interrupts disabled.
1184 */
1185static int hmR0VmxSwitchVmcs(PVMXVMCSINFO pVmcsInfoFrom, PVMXVMCSINFO pVmcsInfoTo)
1186{
1187 /*
1188 * Clear the VMCS we are switching out if it has not already been cleared.
1189 * This will sync any CPU internal data back to the VMCS.
1190 */
1191 if (pVmcsInfoFrom->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1192 {
1193 int rc = hmR0VmxClearVmcs(pVmcsInfoFrom);
1194 if (RT_SUCCESS(rc))
1195 {
1196 /*
1197 * The shadow VMCS, if any, would not be active at this point since we
1198 * would have cleared it while importing the virtual hardware-virtualization
1199 * state as part the VMLAUNCH/VMRESUME VM-exit. Hence, there's no need to
1200 * clear the shadow VMCS here, just assert for safety.
1201 */
1202 Assert(!pVmcsInfoFrom->pvShadowVmcs || pVmcsInfoFrom->fShadowVmcsState == VMX_V_VMCS_LAUNCH_STATE_CLEAR);
1203 }
1204 else
1205 return rc;
1206 }
1207
1208 /*
1209 * Clear the VMCS we are switching to if it has not already been cleared.
1210 * This will initialize the VMCS launch state to "clear" required for loading it.
1211 *
1212 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
1213 */
1214 if (pVmcsInfoTo->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1215 {
1216 int rc = hmR0VmxClearVmcs(pVmcsInfoTo);
1217 if (RT_SUCCESS(rc))
1218 { /* likely */ }
1219 else
1220 return rc;
1221 }
1222
1223 /*
1224 * Finally, load the VMCS we are switching to.
1225 */
1226 return hmR0VmxLoadVmcs(pVmcsInfoTo);
1227}
1228
1229
1230/**
1231 * Switches between the guest VMCS and the nested-guest VMCS as specified by the
1232 * caller.
1233 *
1234 * @returns VBox status code.
1235 * @param pVCpu The cross context virtual CPU structure.
1236 * @param fSwitchToNstGstVmcs Whether to switch to the nested-guest VMCS (pass
1237 * true) or guest VMCS (pass false).
1238 */
1239static int hmR0VmxSwitchToGstOrNstGstVmcs(PVMCPUCC pVCpu, bool fSwitchToNstGstVmcs)
1240{
1241 /* Ensure we have synced everything from the guest-CPU context to the VMCS before switching. */
1242 HMVMX_CPUMCTX_ASSERT(pVCpu, HMVMX_CPUMCTX_EXTRN_ALL);
1243
1244 PVMXVMCSINFO pVmcsInfoFrom;
1245 PVMXVMCSINFO pVmcsInfoTo;
1246 if (fSwitchToNstGstVmcs)
1247 {
1248 pVmcsInfoFrom = &pVCpu->hm.s.vmx.VmcsInfo;
1249 pVmcsInfoTo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
1250 }
1251 else
1252 {
1253 pVmcsInfoFrom = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
1254 pVmcsInfoTo = &pVCpu->hm.s.vmx.VmcsInfo;
1255 }
1256
1257 /*
1258 * Disable interrupts to prevent being preempted while we switch the current VMCS as the
1259 * preemption hook code path acquires the current VMCS.
1260 */
1261 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1262
1263 int rc = hmR0VmxSwitchVmcs(pVmcsInfoFrom, pVmcsInfoTo);
1264 if (RT_SUCCESS(rc))
1265 {
1266 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs = fSwitchToNstGstVmcs;
1267
1268 /*
1269 * If we are switching to a VMCS that was executed on a different host CPU or was
1270 * never executed before, flag that we need to export the host state before executing
1271 * guest/nested-guest code using hardware-assisted VMX.
1272 *
1273 * This could probably be done in a preemptible context since the preemption hook
1274 * will flag the necessary change in host context. However, since preemption is
1275 * already disabled and to avoid making assumptions about host specific code in
1276 * RTMpCpuId when called with preemption enabled, we'll do this while preemption is
1277 * disabled.
1278 */
1279 if (pVmcsInfoTo->idHostCpu == RTMpCpuId())
1280 { /* likely */ }
1281 else
1282 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE);
1283
1284 ASMSetFlags(fEFlags);
1285
1286 /*
1287 * We use a different VM-exit MSR-store areas for the guest and nested-guest. Hence,
1288 * flag that we need to update the host MSR values there. Even if we decide in the
1289 * future to share the VM-exit MSR-store area page between the guest and nested-guest,
1290 * if its content differs, we would have to update the host MSRs anyway.
1291 */
1292 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
1293 }
1294 else
1295 ASMSetFlags(fEFlags);
1296 return rc;
1297}
1298#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
1299
1300
1301/**
1302 * Updates the VM's last error record.
1303 *
1304 * If there was a VMX instruction error, reads the error data from the VMCS and
1305 * updates VCPU's last error record as well.
1306 *
1307 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1308 * Can be NULL if @a rc is not VERR_VMX_UNABLE_TO_START_VM or
1309 * VERR_VMX_INVALID_VMCS_FIELD.
1310 * @param rc The error code.
1311 */
1312static void hmR0VmxUpdateErrorRecord(PVMCPUCC pVCpu, int rc)
1313{
1314 if ( rc == VERR_VMX_INVALID_VMCS_FIELD
1315 || rc == VERR_VMX_UNABLE_TO_START_VM)
1316 {
1317 AssertPtrReturnVoid(pVCpu);
1318 VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
1319 }
1320 pVCpu->CTX_SUFF(pVM)->hm.s.rcInit = rc;
1321}
1322
1323
1324#ifdef VBOX_STRICT
1325/**
1326 * Reads the VM-entry interruption-information field from the VMCS into the VMX
1327 * transient structure.
1328 *
1329 * @param pVmxTransient The VMX-transient structure.
1330 */
1331DECLINLINE(void) hmR0VmxReadEntryIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1332{
1333 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntInfo);
1334 AssertRC(rc);
1335}
1336
1337
1338/**
1339 * Reads the VM-entry exception error code field from the VMCS into
1340 * the VMX transient structure.
1341 *
1342 * @param pVmxTransient The VMX-transient structure.
1343 */
1344DECLINLINE(void) hmR0VmxReadEntryXcptErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1345{
1346 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
1347 AssertRC(rc);
1348}
1349
1350
1351/**
1352 * Reads the VM-entry exception error code field from the VMCS into
1353 * the VMX transient structure.
1354 *
1355 * @param pVmxTransient The VMX-transient structure.
1356 */
1357DECLINLINE(void) hmR0VmxReadEntryInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1358{
1359 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
1360 AssertRC(rc);
1361}
1362#endif /* VBOX_STRICT */
1363
1364
1365/**
1366 * Reads the VM-exit interruption-information field from the VMCS into the VMX
1367 * transient structure.
1368 *
1369 * @param pVmxTransient The VMX-transient structure.
1370 */
1371DECLINLINE(void) hmR0VmxReadExitIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1372{
1373 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_INFO))
1374 {
1375 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1376 AssertRC(rc);
1377 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_INFO;
1378 }
1379}
1380
1381
1382/**
1383 * Reads the VM-exit interruption error code from the VMCS into the VMX
1384 * transient structure.
1385 *
1386 * @param pVmxTransient The VMX-transient structure.
1387 */
1388DECLINLINE(void) hmR0VmxReadExitIntErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1389{
1390 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE))
1391 {
1392 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1393 AssertRC(rc);
1394 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE;
1395 }
1396}
1397
1398
1399/**
1400 * Reads the VM-exit instruction length field from the VMCS into the VMX
1401 * transient structure.
1402 *
1403 * @param pVmxTransient The VMX-transient structure.
1404 */
1405DECLINLINE(void) hmR0VmxReadExitInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1406{
1407 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_LEN))
1408 {
1409 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1410 AssertRC(rc);
1411 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_LEN;
1412 }
1413}
1414
1415
1416/**
1417 * Reads the VM-exit instruction-information field from the VMCS into
1418 * the VMX transient structure.
1419 *
1420 * @param pVmxTransient The VMX-transient structure.
1421 */
1422DECLINLINE(void) hmR0VmxReadExitInstrInfoVmcs(PVMXTRANSIENT pVmxTransient)
1423{
1424 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_INFO))
1425 {
1426 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1427 AssertRC(rc);
1428 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_INFO;
1429 }
1430}
1431
1432
1433/**
1434 * Reads the Exit Qualification from the VMCS into the VMX transient structure.
1435 *
1436 * @param pVmxTransient The VMX-transient structure.
1437 */
1438DECLINLINE(void) hmR0VmxReadExitQualVmcs(PVMXTRANSIENT pVmxTransient)
1439{
1440 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_QUALIFICATION))
1441 {
1442 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1443 AssertRC(rc);
1444 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION;
1445 }
1446}
1447
1448
1449/**
1450 * Reads the Guest-linear address from the VMCS into the VMX transient structure.
1451 *
1452 * @param pVmxTransient The VMX-transient structure.
1453 */
1454DECLINLINE(void) hmR0VmxReadGuestLinearAddrVmcs(PVMXTRANSIENT pVmxTransient)
1455{
1456 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_LINEAR_ADDR))
1457 {
1458 int rc = VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1459 AssertRC(rc);
1460 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_LINEAR_ADDR;
1461 }
1462}
1463
1464
1465/**
1466 * Reads the Guest-physical address from the VMCS into the VMX transient structure.
1467 *
1468 * @param pVmxTransient The VMX-transient structure.
1469 */
1470DECLINLINE(void) hmR0VmxReadGuestPhysicalAddrVmcs(PVMXTRANSIENT pVmxTransient)
1471{
1472 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PHYSICAL_ADDR))
1473 {
1474 int rc = VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1475 AssertRC(rc);
1476 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PHYSICAL_ADDR;
1477 }
1478}
1479
1480#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1481/**
1482 * Reads the Guest pending-debug exceptions from the VMCS into the VMX transient
1483 * structure.
1484 *
1485 * @param pVmxTransient The VMX-transient structure.
1486 */
1487DECLINLINE(void) hmR0VmxReadGuestPendingDbgXctps(PVMXTRANSIENT pVmxTransient)
1488{
1489 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PENDING_DBG_XCPTS))
1490 {
1491 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &pVmxTransient->uGuestPendingDbgXcpts);
1492 AssertRC(rc);
1493 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PENDING_DBG_XCPTS;
1494 }
1495}
1496#endif
1497
1498/**
1499 * Reads the IDT-vectoring information field from the VMCS into the VMX
1500 * transient structure.
1501 *
1502 * @param pVmxTransient The VMX-transient structure.
1503 *
1504 * @remarks No-long-jump zone!!!
1505 */
1506DECLINLINE(void) hmR0VmxReadIdtVectoringInfoVmcs(PVMXTRANSIENT pVmxTransient)
1507{
1508 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_INFO))
1509 {
1510 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1511 AssertRC(rc);
1512 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_INFO;
1513 }
1514}
1515
1516
1517/**
1518 * Reads the IDT-vectoring error code from the VMCS into the VMX
1519 * transient structure.
1520 *
1521 * @param pVmxTransient The VMX-transient structure.
1522 */
1523DECLINLINE(void) hmR0VmxReadIdtVectoringErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1524{
1525 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_ERROR_CODE))
1526 {
1527 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1528 AssertRC(rc);
1529 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_ERROR_CODE;
1530 }
1531}
1532
1533#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
1534/**
1535 * Reads all relevant read-only VMCS fields into the VMX transient structure.
1536 *
1537 * @param pVmxTransient The VMX-transient structure.
1538 */
1539static void hmR0VmxReadAllRoFieldsVmcs(PVMXTRANSIENT pVmxTransient)
1540{
1541 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1542 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1543 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1544 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1545 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1546 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1547 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1548 rc |= VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1549 rc |= VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1550 AssertRC(rc);
1551 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION
1552 | HMVMX_READ_EXIT_INSTR_LEN
1553 | HMVMX_READ_EXIT_INSTR_INFO
1554 | HMVMX_READ_IDT_VECTORING_INFO
1555 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
1556 | HMVMX_READ_EXIT_INTERRUPTION_INFO
1557 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
1558 | HMVMX_READ_GUEST_LINEAR_ADDR
1559 | HMVMX_READ_GUEST_PHYSICAL_ADDR;
1560}
1561#endif
1562
1563/**
1564 * Enters VMX root mode operation on the current CPU.
1565 *
1566 * @returns VBox status code.
1567 * @param pVM The cross context VM structure. Can be
1568 * NULL, after a resume.
1569 * @param HCPhysCpuPage Physical address of the VMXON region.
1570 * @param pvCpuPage Pointer to the VMXON region.
1571 */
1572static int hmR0VmxEnterRootMode(PVMCC pVM, RTHCPHYS HCPhysCpuPage, void *pvCpuPage)
1573{
1574 Assert(HCPhysCpuPage && HCPhysCpuPage != NIL_RTHCPHYS);
1575 Assert(RT_ALIGN_T(HCPhysCpuPage, _4K, RTHCPHYS) == HCPhysCpuPage);
1576 Assert(pvCpuPage);
1577 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1578
1579 if (pVM)
1580 {
1581 /* Write the VMCS revision identifier to the VMXON region. */
1582 *(uint32_t *)pvCpuPage = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
1583 }
1584
1585 /* Paranoid: Disable interrupts as, in theory, interrupt handlers might mess with CR4. */
1586 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1587
1588 /* Enable the VMX bit in CR4 if necessary. */
1589 RTCCUINTREG const uOldCr4 = SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
1590
1591 /* Enter VMX root mode. */
1592 int rc = VMXEnable(HCPhysCpuPage);
1593 if (RT_FAILURE(rc))
1594 {
1595 if (!(uOldCr4 & X86_CR4_VMXE))
1596 SUPR0ChangeCR4(0 /* fOrMask */, ~X86_CR4_VMXE);
1597
1598 if (pVM)
1599 pVM->hm.s.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
1600 }
1601
1602 /* Restore interrupts. */
1603 ASMSetFlags(fEFlags);
1604 return rc;
1605}
1606
1607
1608/**
1609 * Exits VMX root mode operation on the current CPU.
1610 *
1611 * @returns VBox status code.
1612 */
1613static int hmR0VmxLeaveRootMode(void)
1614{
1615 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1616
1617 /* Paranoid: Disable interrupts as, in theory, interrupts handlers might mess with CR4. */
1618 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1619
1620 /* If we're for some reason not in VMX root mode, then don't leave it. */
1621 RTCCUINTREG const uHostCr4 = ASMGetCR4();
1622
1623 int rc;
1624 if (uHostCr4 & X86_CR4_VMXE)
1625 {
1626 /* Exit VMX root mode and clear the VMX bit in CR4. */
1627 VMXDisable();
1628 SUPR0ChangeCR4(0 /* fOrMask */, ~X86_CR4_VMXE);
1629 rc = VINF_SUCCESS;
1630 }
1631 else
1632 rc = VERR_VMX_NOT_IN_VMX_ROOT_MODE;
1633
1634 /* Restore interrupts. */
1635 ASMSetFlags(fEFlags);
1636 return rc;
1637}
1638
1639
1640/**
1641 * Allocates and maps a physically contiguous page. The allocated page is
1642 * zero'd out (used by various VT-x structures).
1643 *
1644 * @returns IPRT status code.
1645 * @param pMemObj Pointer to the ring-0 memory object.
1646 * @param ppVirt Where to store the virtual address of the allocation.
1647 * @param pHCPhys Where to store the physical address of the allocation.
1648 */
1649static int hmR0VmxPageAllocZ(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
1650{
1651 AssertPtr(pMemObj);
1652 AssertPtr(ppVirt);
1653 AssertPtr(pHCPhys);
1654 int rc = RTR0MemObjAllocCont(pMemObj, X86_PAGE_4K_SIZE, false /* fExecutable */);
1655 if (RT_FAILURE(rc))
1656 return rc;
1657 *ppVirt = RTR0MemObjAddress(*pMemObj);
1658 *pHCPhys = RTR0MemObjGetPagePhysAddr(*pMemObj, 0 /* iPage */);
1659 ASMMemZero32(*ppVirt, X86_PAGE_4K_SIZE);
1660 return VINF_SUCCESS;
1661}
1662
1663
1664/**
1665 * Frees and unmaps an allocated, physical page.
1666 *
1667 * @param pMemObj Pointer to the ring-0 memory object.
1668 * @param ppVirt Where to re-initialize the virtual address of allocation as
1669 * 0.
1670 * @param pHCPhys Where to re-initialize the physical address of the
1671 * allocation as 0.
1672 */
1673static void hmR0VmxPageFree(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
1674{
1675 AssertPtr(pMemObj);
1676 AssertPtr(ppVirt);
1677 AssertPtr(pHCPhys);
1678 /* NULL is valid, accepted and ignored by the free function below. */
1679 RTR0MemObjFree(*pMemObj, true /* fFreeMappings */);
1680 *pMemObj = NIL_RTR0MEMOBJ;
1681 *ppVirt = NULL;
1682 *pHCPhys = NIL_RTHCPHYS;
1683}
1684
1685
1686/**
1687 * Initializes a VMCS info. object.
1688 *
1689 * @param pVmcsInfo The VMCS info. object.
1690 */
1691static void hmR0VmxInitVmcsInfo(PVMXVMCSINFO pVmcsInfo)
1692{
1693 memset(pVmcsInfo, 0, sizeof(*pVmcsInfo));
1694
1695 Assert(pVmcsInfo->hMemObjVmcs == NIL_RTR0MEMOBJ);
1696 Assert(pVmcsInfo->hMemObjShadowVmcs == NIL_RTR0MEMOBJ);
1697 Assert(pVmcsInfo->hMemObjMsrBitmap == NIL_RTR0MEMOBJ);
1698 Assert(pVmcsInfo->hMemObjGuestMsrLoad == NIL_RTR0MEMOBJ);
1699 Assert(pVmcsInfo->hMemObjGuestMsrStore == NIL_RTR0MEMOBJ);
1700 Assert(pVmcsInfo->hMemObjHostMsrLoad == NIL_RTR0MEMOBJ);
1701 pVmcsInfo->HCPhysVmcs = NIL_RTHCPHYS;
1702 pVmcsInfo->HCPhysShadowVmcs = NIL_RTHCPHYS;
1703 pVmcsInfo->HCPhysMsrBitmap = NIL_RTHCPHYS;
1704 pVmcsInfo->HCPhysGuestMsrLoad = NIL_RTHCPHYS;
1705 pVmcsInfo->HCPhysGuestMsrStore = NIL_RTHCPHYS;
1706 pVmcsInfo->HCPhysHostMsrLoad = NIL_RTHCPHYS;
1707 pVmcsInfo->HCPhysVirtApic = NIL_RTHCPHYS;
1708 pVmcsInfo->HCPhysEPTP = NIL_RTHCPHYS;
1709 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
1710 pVmcsInfo->idHostCpu = NIL_RTCPUID;
1711}
1712
1713
1714/**
1715 * Frees the VT-x structures for a VMCS info. object.
1716 *
1717 * @param pVM The cross context VM structure.
1718 * @param pVmcsInfo The VMCS info. object.
1719 */
1720static void hmR0VmxFreeVmcsInfo(PVMCC pVM, PVMXVMCSINFO pVmcsInfo)
1721{
1722 hmR0VmxPageFree(&pVmcsInfo->hMemObjVmcs, &pVmcsInfo->pvVmcs, &pVmcsInfo->HCPhysVmcs);
1723
1724#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1725 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1726 hmR0VmxPageFree(&pVmcsInfo->hMemObjShadowVmcs, &pVmcsInfo->pvShadowVmcs, &pVmcsInfo->HCPhysShadowVmcs);
1727#endif
1728
1729 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
1730 hmR0VmxPageFree(&pVmcsInfo->hMemObjMsrBitmap, &pVmcsInfo->pvMsrBitmap, &pVmcsInfo->HCPhysMsrBitmap);
1731
1732 hmR0VmxPageFree(&pVmcsInfo->hMemObjHostMsrLoad, &pVmcsInfo->pvHostMsrLoad, &pVmcsInfo->HCPhysHostMsrLoad);
1733 hmR0VmxPageFree(&pVmcsInfo->hMemObjGuestMsrLoad, &pVmcsInfo->pvGuestMsrLoad, &pVmcsInfo->HCPhysGuestMsrLoad);
1734 hmR0VmxPageFree(&pVmcsInfo->hMemObjGuestMsrStore, &pVmcsInfo->pvGuestMsrStore, &pVmcsInfo->HCPhysGuestMsrStore);
1735
1736 hmR0VmxInitVmcsInfo(pVmcsInfo);
1737}
1738
1739
1740/**
1741 * Allocates the VT-x structures for a VMCS info. object.
1742 *
1743 * @returns VBox status code.
1744 * @param pVCpu The cross context virtual CPU structure.
1745 * @param pVmcsInfo The VMCS info. object.
1746 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
1747 */
1748static int hmR0VmxAllocVmcsInfo(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
1749{
1750 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
1751
1752 /* Allocate the guest VM control structure (VMCS). */
1753 int rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjVmcs, &pVmcsInfo->pvVmcs, &pVmcsInfo->HCPhysVmcs);
1754 if (RT_SUCCESS(rc))
1755 {
1756 if (!fIsNstGstVmcs)
1757 {
1758#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1759 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1760 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjShadowVmcs, &pVmcsInfo->pvShadowVmcs, &pVmcsInfo->HCPhysShadowVmcs);
1761#endif
1762 if (RT_SUCCESS(rc))
1763 {
1764 /* Get the allocated virtual-APIC page from the virtual APIC device. */
1765 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
1766 && (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW))
1767 rc = APICGetApicPageForCpu(pVCpu, &pVmcsInfo->HCPhysVirtApic, (PRTR0PTR)&pVmcsInfo->pbVirtApic, NULL /*pR3Ptr*/);
1768 }
1769 }
1770 else
1771 {
1772 /* We don't yet support exposing VMCS shadowing to the guest. */
1773 Assert(pVmcsInfo->HCPhysShadowVmcs == NIL_RTHCPHYS);
1774 Assert(!pVmcsInfo->pvShadowVmcs);
1775
1776 /* Get the allocated virtual-APIC page from CPUM. */
1777 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW)
1778 {
1779 /** @todo NSTVMX: Get rid of this. There is no need to allocate a separate HC
1780 * page for this. Use the one provided by the nested-guest directly. */
1781 pVmcsInfo->pbVirtApic = (uint8_t *)CPUMGetGuestVmxVirtApicPage(pVCpu, &pVCpu->cpum.GstCtx,
1782 &pVmcsInfo->HCPhysVirtApic);
1783 Assert(pVmcsInfo->pbVirtApic);
1784 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1785 }
1786 }
1787
1788 if (RT_SUCCESS(rc))
1789 {
1790 /*
1791 * Allocate the MSR-bitmap if supported by the CPU. The MSR-bitmap is for
1792 * transparent accesses of specific MSRs.
1793 *
1794 * If the condition for enabling MSR bitmaps changes here, don't forget to
1795 * update HMIsMsrBitmapActive().
1796 *
1797 * We don't share MSR bitmaps between the guest and nested-guest as we then
1798 * don't need to care about carefully restoring the guest MSR bitmap.
1799 * The guest visible nested-guest MSR bitmap needs to remain unchanged.
1800 * Hence, allocate a separate MSR bitmap for the guest and nested-guest.
1801 * We also don't need to re-initialize the nested-guest MSR bitmap here as
1802 * we do that later while merging VMCS.
1803 */
1804 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
1805 {
1806 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjMsrBitmap, &pVmcsInfo->pvMsrBitmap, &pVmcsInfo->HCPhysMsrBitmap);
1807 if ( RT_SUCCESS(rc)
1808 && !fIsNstGstVmcs)
1809 ASMMemFill32(pVmcsInfo->pvMsrBitmap, X86_PAGE_4K_SIZE, UINT32_C(0xffffffff));
1810 }
1811
1812 if (RT_SUCCESS(rc))
1813 {
1814 /*
1815 * Allocate the VM-entry MSR-load area for the guest MSRs.
1816 *
1817 * Similar to MSR-bitmaps, we do not share the auto MSR-load/store are between
1818 * the guest and nested-guest.
1819 */
1820 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjGuestMsrLoad, &pVmcsInfo->pvGuestMsrLoad,
1821 &pVmcsInfo->HCPhysGuestMsrLoad);
1822 if (RT_SUCCESS(rc))
1823 {
1824 /*
1825 * We use the same page for VM-entry MSR-load and VM-exit MSR store areas.
1826 * These contain the guest MSRs to load on VM-entry and store on VM-exit.
1827 */
1828 Assert(pVmcsInfo->hMemObjGuestMsrStore == NIL_RTR0MEMOBJ);
1829 pVmcsInfo->pvGuestMsrStore = pVmcsInfo->pvGuestMsrLoad;
1830 pVmcsInfo->HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrLoad;
1831
1832 /* Allocate the VM-exit MSR-load page for the host MSRs. */
1833 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjHostMsrLoad, &pVmcsInfo->pvHostMsrLoad,
1834 &pVmcsInfo->HCPhysHostMsrLoad);
1835 }
1836 }
1837 }
1838 }
1839
1840 return rc;
1841}
1842
1843
1844/**
1845 * Free all VT-x structures for the VM.
1846 *
1847 * @returns IPRT status code.
1848 * @param pVM The cross context VM structure.
1849 */
1850static void hmR0VmxStructsFree(PVMCC pVM)
1851{
1852#ifdef VBOX_WITH_CRASHDUMP_MAGIC
1853 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
1854#endif
1855 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess, &pVM->hm.s.vmx.HCPhysApicAccess);
1856
1857#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1858 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1859 {
1860 RTMemFree(pVM->hm.s.vmx.paShadowVmcsFields);
1861 RTMemFree(pVM->hm.s.vmx.paShadowVmcsRoFields);
1862 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjVmreadBitmap, &pVM->hm.s.vmx.pvVmreadBitmap, &pVM->hm.s.vmx.HCPhysVmreadBitmap);
1863 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjVmwriteBitmap, &pVM->hm.s.vmx.pvVmwriteBitmap, &pVM->hm.s.vmx.HCPhysVmwriteBitmap);
1864 }
1865#endif
1866
1867 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1868 {
1869 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
1870 PVMXVMCSINFO pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfo;
1871 hmR0VmxFreeVmcsInfo(pVM, pVmcsInfo);
1872#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1873 if (pVM->cpum.ro.GuestFeatures.fVmx)
1874 {
1875 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
1876 hmR0VmxFreeVmcsInfo(pVM, pVmcsInfo);
1877 }
1878#endif
1879 }
1880}
1881
1882
1883/**
1884 * Allocate all VT-x structures for the VM.
1885 *
1886 * @returns IPRT status code.
1887 * @param pVM The cross context VM structure.
1888 */
1889static int hmR0VmxStructsAlloc(PVMCC pVM)
1890{
1891 /*
1892 * Sanity check the VMCS size reported by the CPU as we assume 4KB allocations.
1893 * The VMCS size cannot be more than 4096 bytes.
1894 *
1895 * See Intel spec. Appendix A.1 "Basic VMX Information".
1896 */
1897 uint32_t const cbVmcs = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_SIZE);
1898 if (cbVmcs <= X86_PAGE_4K_SIZE)
1899 { /* likely */ }
1900 else
1901 {
1902 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_INVALID_VMCS_SIZE;
1903 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1904 }
1905
1906 /*
1907 * Initialize/check members up-front so we can cleanup en masse on allocation failures.
1908 */
1909#ifdef VBOX_WITH_CRASHDUMP_MAGIC
1910 Assert(pVM->hm.s.vmx.hMemObjScratch == NIL_RTR0MEMOBJ);
1911 Assert(pVM->hm.s.vmx.pbScratch == NULL);
1912 pVM->hm.s.vmx.HCPhysScratch = NIL_RTHCPHYS;
1913#endif
1914
1915 Assert(pVM->hm.s.vmx.hMemObjApicAccess == NIL_RTR0MEMOBJ);
1916 Assert(pVM->hm.s.vmx.pbApicAccess == NULL);
1917 pVM->hm.s.vmx.HCPhysApicAccess = NIL_RTHCPHYS;
1918
1919 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1920 {
1921 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
1922 hmR0VmxInitVmcsInfo(&pVCpu->hm.s.vmx.VmcsInfo);
1923 hmR0VmxInitVmcsInfo(&pVCpu->hm.s.vmx.VmcsInfoNstGst);
1924 }
1925
1926 /*
1927 * Allocate per-VM VT-x structures.
1928 */
1929 int rc = VINF_SUCCESS;
1930#ifdef VBOX_WITH_CRASHDUMP_MAGIC
1931 /* Allocate crash-dump magic scratch page. */
1932 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
1933 if (RT_FAILURE(rc))
1934 {
1935 hmR0VmxStructsFree(pVM);
1936 return rc;
1937 }
1938 strcpy((char *)pVM->hm.s.vmx.pbScratch, "SCRATCH Magic");
1939 *(uint64_t *)(pVM->hm.s.vmx.pbScratch + 16) = UINT64_C(0xdeadbeefdeadbeef);
1940#endif
1941
1942 /* Allocate the APIC-access page for trapping APIC accesses from the guest. */
1943 if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
1944 {
1945 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess,
1946 &pVM->hm.s.vmx.HCPhysApicAccess);
1947 if (RT_FAILURE(rc))
1948 {
1949 hmR0VmxStructsFree(pVM);
1950 return rc;
1951 }
1952 }
1953
1954#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1955 /* Allocate the shadow VMCS fields array, VMREAD, VMWRITE bitmaps.. */
1956 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1957 {
1958 Assert(!pVM->hm.s.vmx.cShadowVmcsFields);
1959 Assert(!pVM->hm.s.vmx.cShadowVmcsRoFields);
1960 pVM->hm.s.vmx.paShadowVmcsFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
1961 pVM->hm.s.vmx.paShadowVmcsRoFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
1962 if (RT_LIKELY( pVM->hm.s.vmx.paShadowVmcsFields
1963 && pVM->hm.s.vmx.paShadowVmcsRoFields))
1964 {
1965 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjVmreadBitmap, &pVM->hm.s.vmx.pvVmreadBitmap,
1966 &pVM->hm.s.vmx.HCPhysVmreadBitmap);
1967 if (RT_SUCCESS(rc))
1968 {
1969 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjVmwriteBitmap, &pVM->hm.s.vmx.pvVmwriteBitmap,
1970 &pVM->hm.s.vmx.HCPhysVmwriteBitmap);
1971 }
1972 }
1973 else
1974 rc = VERR_NO_MEMORY;
1975
1976 if (RT_FAILURE(rc))
1977 {
1978 hmR0VmxStructsFree(pVM);
1979 return rc;
1980 }
1981 }
1982#endif
1983
1984 /*
1985 * Initialize per-VCPU VT-x structures.
1986 */
1987 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1988 {
1989 /* Allocate the guest VMCS structures. */
1990 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
1991 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hm.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
1992 if (RT_SUCCESS(rc))
1993 {
1994#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1995 /* Allocate the nested-guest VMCS structures, when the VMX feature is exposed to the guest. */
1996 if (pVM->cpum.ro.GuestFeatures.fVmx)
1997 {
1998 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hm.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
1999 if (RT_SUCCESS(rc))
2000 { /* likely */ }
2001 else
2002 break;
2003 }
2004#endif
2005 }
2006 else
2007 break;
2008 }
2009
2010 if (RT_FAILURE(rc))
2011 {
2012 hmR0VmxStructsFree(pVM);
2013 return rc;
2014 }
2015
2016 return VINF_SUCCESS;
2017}
2018
2019#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2020/**
2021 * Returns whether an MSR at the given MSR-bitmap offset is intercepted or not.
2022 *
2023 * @returns @c true if the MSR is intercepted, @c false otherwise.
2024 * @param pvMsrBitmap The MSR bitmap.
2025 * @param offMsr The MSR byte offset.
2026 * @param iBit The bit offset from the byte offset.
2027 */
2028DECLINLINE(bool) hmR0VmxIsMsrBitSet(const void *pvMsrBitmap, uint16_t offMsr, int32_t iBit)
2029{
2030 uint8_t const * const pbMsrBitmap = (uint8_t const * const)pvMsrBitmap;
2031 Assert(pbMsrBitmap);
2032 Assert(offMsr + (iBit >> 3) <= X86_PAGE_4K_SIZE);
2033 return ASMBitTest(pbMsrBitmap + offMsr, iBit);
2034}
2035#endif
2036
2037/**
2038 * Sets the permission bits for the specified MSR in the given MSR bitmap.
2039 *
2040 * If the passed VMCS is a nested-guest VMCS, this function ensures that the
2041 * read/write intercept is cleared from the MSR bitmap used for hardware-assisted
2042 * VMX execution of the nested-guest, only if nested-guest is also not intercepting
2043 * the read/write access of this MSR.
2044 *
2045 * @param pVCpu The cross context virtual CPU structure.
2046 * @param pVmcsInfo The VMCS info. object.
2047 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2048 * @param idMsr The MSR value.
2049 * @param fMsrpm The MSR permissions (see VMXMSRPM_XXX). This must
2050 * include both a read -and- a write permission!
2051 *
2052 * @sa CPUMGetVmxMsrPermission.
2053 * @remarks Can be called with interrupts disabled.
2054 */
2055static void hmR0VmxSetMsrPermission(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs, uint32_t idMsr, uint32_t fMsrpm)
2056{
2057 uint8_t *pbMsrBitmap = (uint8_t *)pVmcsInfo->pvMsrBitmap;
2058 Assert(pbMsrBitmap);
2059 Assert(VMXMSRPM_IS_FLAG_VALID(fMsrpm));
2060
2061 /*
2062 * MSR-bitmap Layout:
2063 * Byte index MSR range Interpreted as
2064 * 0x000 - 0x3ff 0x00000000 - 0x00001fff Low MSR read bits.
2065 * 0x400 - 0x7ff 0xc0000000 - 0xc0001fff High MSR read bits.
2066 * 0x800 - 0xbff 0x00000000 - 0x00001fff Low MSR write bits.
2067 * 0xc00 - 0xfff 0xc0000000 - 0xc0001fff High MSR write bits.
2068 *
2069 * A bit corresponding to an MSR within the above range causes a VM-exit
2070 * if the bit is 1 on executions of RDMSR/WRMSR. If an MSR falls out of
2071 * the MSR range, it always cause a VM-exit.
2072 *
2073 * See Intel spec. 24.6.9 "MSR-Bitmap Address".
2074 */
2075 uint16_t const offBitmapRead = 0;
2076 uint16_t const offBitmapWrite = 0x800;
2077 uint16_t offMsr;
2078 int32_t iBit;
2079 if (idMsr <= UINT32_C(0x00001fff))
2080 {
2081 offMsr = 0;
2082 iBit = idMsr;
2083 }
2084 else if (idMsr - UINT32_C(0xc0000000) <= UINT32_C(0x00001fff))
2085 {
2086 offMsr = 0x400;
2087 iBit = idMsr - UINT32_C(0xc0000000);
2088 }
2089 else
2090 AssertMsgFailedReturnVoid(("Invalid MSR %#RX32\n", idMsr));
2091
2092 /*
2093 * Set the MSR read permission.
2094 */
2095 uint16_t const offMsrRead = offBitmapRead + offMsr;
2096 Assert(offMsrRead + (iBit >> 3) < offBitmapWrite);
2097 if (fMsrpm & VMXMSRPM_ALLOW_RD)
2098 {
2099#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2100 bool const fClear = !fIsNstGstVmcs ? true
2101 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrRead, iBit);
2102#else
2103 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2104 bool const fClear = true;
2105#endif
2106 if (fClear)
2107 ASMBitClear(pbMsrBitmap + offMsrRead, iBit);
2108 }
2109 else
2110 ASMBitSet(pbMsrBitmap + offMsrRead, iBit);
2111
2112 /*
2113 * Set the MSR write permission.
2114 */
2115 uint16_t const offMsrWrite = offBitmapWrite + offMsr;
2116 Assert(offMsrWrite + (iBit >> 3) < X86_PAGE_4K_SIZE);
2117 if (fMsrpm & VMXMSRPM_ALLOW_WR)
2118 {
2119#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2120 bool const fClear = !fIsNstGstVmcs ? true
2121 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrWrite, iBit);
2122#else
2123 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2124 bool const fClear = true;
2125#endif
2126 if (fClear)
2127 ASMBitClear(pbMsrBitmap + offMsrWrite, iBit);
2128 }
2129 else
2130 ASMBitSet(pbMsrBitmap + offMsrWrite, iBit);
2131}
2132
2133
2134/**
2135 * Updates the VMCS with the number of effective MSRs in the auto-load/store MSR
2136 * area.
2137 *
2138 * @returns VBox status code.
2139 * @param pVCpu The cross context virtual CPU structure.
2140 * @param pVmcsInfo The VMCS info. object.
2141 * @param cMsrs The number of MSRs.
2142 */
2143static int hmR0VmxSetAutoLoadStoreMsrCount(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t cMsrs)
2144{
2145 /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
2146 uint32_t const cMaxSupportedMsrs = VMX_MISC_MAX_MSRS(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc);
2147 if (RT_LIKELY(cMsrs < cMaxSupportedMsrs))
2148 {
2149 /* Commit the MSR counts to the VMCS and update the cache. */
2150 if (pVmcsInfo->cEntryMsrLoad != cMsrs)
2151 {
2152 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2153 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, cMsrs); AssertRC(rc);
2154 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2155 pVmcsInfo->cEntryMsrLoad = cMsrs;
2156 pVmcsInfo->cExitMsrStore = cMsrs;
2157 pVmcsInfo->cExitMsrLoad = cMsrs;
2158 }
2159 return VINF_SUCCESS;
2160 }
2161
2162 LogRel(("Auto-load/store MSR count exceeded! cMsrs=%u MaxSupported=%u\n", cMsrs, cMaxSupportedMsrs));
2163 pVCpu->hm.s.u32HMError = VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE;
2164 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2165}
2166
2167
2168/**
2169 * Adds a new (or updates the value of an existing) guest/host MSR
2170 * pair to be swapped during the world-switch as part of the
2171 * auto-load/store MSR area in the VMCS.
2172 *
2173 * @returns VBox status code.
2174 * @param pVCpu The cross context virtual CPU structure.
2175 * @param pVmxTransient The VMX-transient structure.
2176 * @param idMsr The MSR.
2177 * @param uGuestMsrValue Value of the guest MSR.
2178 * @param fSetReadWrite Whether to set the guest read/write access of this
2179 * MSR (thus not causing a VM-exit).
2180 * @param fUpdateHostMsr Whether to update the value of the host MSR if
2181 * necessary.
2182 */
2183static int hmR0VmxAddAutoLoadStoreMsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t idMsr, uint64_t uGuestMsrValue,
2184 bool fSetReadWrite, bool fUpdateHostMsr)
2185{
2186 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2187 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2188 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2189 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2190 uint32_t i;
2191
2192 /* Paranoia. */
2193 Assert(pGuestMsrLoad);
2194
2195 LogFlowFunc(("pVCpu=%p idMsr=%#RX32 uGestMsrValue=%#RX64\n", pVCpu, idMsr, uGuestMsrValue));
2196
2197 /* Check if the MSR already exists in the VM-entry MSR-load area. */
2198 for (i = 0; i < cMsrs; i++)
2199 {
2200 if (pGuestMsrLoad[i].u32Msr == idMsr)
2201 break;
2202 }
2203
2204 bool fAdded = false;
2205 if (i == cMsrs)
2206 {
2207 /* The MSR does not exist, bump the MSR count to make room for the new MSR. */
2208 ++cMsrs;
2209 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2210 AssertMsgRCReturn(rc, ("Insufficient space to add MSR to VM-entry MSR-load/store area %u\n", idMsr), rc);
2211
2212 /* Set the guest to read/write this MSR without causing VM-exits. */
2213 if ( fSetReadWrite
2214 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
2215 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_ALLOW_RD_WR);
2216
2217 Log4Func(("Added MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2218 fAdded = true;
2219 }
2220
2221 /* Update the MSR value for the newly added or already existing MSR. */
2222 pGuestMsrLoad[i].u32Msr = idMsr;
2223 pGuestMsrLoad[i].u64Value = uGuestMsrValue;
2224
2225 /* Create the corresponding slot in the VM-exit MSR-store area if we use a different page. */
2226 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2227 {
2228 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2229 pGuestMsrStore[i].u32Msr = idMsr;
2230 pGuestMsrStore[i].u64Value = uGuestMsrValue;
2231 }
2232
2233 /* Update the corresponding slot in the host MSR area. */
2234 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2235 Assert(pHostMsr != pVmcsInfo->pvGuestMsrLoad);
2236 Assert(pHostMsr != pVmcsInfo->pvGuestMsrStore);
2237 pHostMsr[i].u32Msr = idMsr;
2238
2239 /*
2240 * Only if the caller requests to update the host MSR value AND we've newly added the
2241 * MSR to the host MSR area do we actually update the value. Otherwise, it will be
2242 * updated by hmR0VmxUpdateAutoLoadHostMsrs().
2243 *
2244 * We do this for performance reasons since reading MSRs may be quite expensive.
2245 */
2246 if (fAdded)
2247 {
2248 if (fUpdateHostMsr)
2249 {
2250 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2251 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2252 pHostMsr[i].u64Value = ASMRdMsr(idMsr);
2253 }
2254 else
2255 {
2256 /* Someone else can do the work. */
2257 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
2258 }
2259 }
2260 return VINF_SUCCESS;
2261}
2262
2263
2264/**
2265 * Removes a guest/host MSR pair to be swapped during the world-switch from the
2266 * auto-load/store MSR area in the VMCS.
2267 *
2268 * @returns VBox status code.
2269 * @param pVCpu The cross context virtual CPU structure.
2270 * @param pVmxTransient The VMX-transient structure.
2271 * @param idMsr The MSR.
2272 */
2273static int hmR0VmxRemoveAutoLoadStoreMsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t idMsr)
2274{
2275 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2276 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2277 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2278 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2279
2280 LogFlowFunc(("pVCpu=%p idMsr=%#RX32\n", pVCpu, idMsr));
2281
2282 for (uint32_t i = 0; i < cMsrs; i++)
2283 {
2284 /* Find the MSR. */
2285 if (pGuestMsrLoad[i].u32Msr == idMsr)
2286 {
2287 /*
2288 * If it's the last MSR, we only need to reduce the MSR count.
2289 * If it's -not- the last MSR, copy the last MSR in place of it and reduce the MSR count.
2290 */
2291 if (i < cMsrs - 1)
2292 {
2293 /* Remove it from the VM-entry MSR-load area. */
2294 pGuestMsrLoad[i].u32Msr = pGuestMsrLoad[cMsrs - 1].u32Msr;
2295 pGuestMsrLoad[i].u64Value = pGuestMsrLoad[cMsrs - 1].u64Value;
2296
2297 /* Remove it from the VM-exit MSR-store area if it's in a different page. */
2298 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2299 {
2300 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2301 Assert(pGuestMsrStore[i].u32Msr == idMsr);
2302 pGuestMsrStore[i].u32Msr = pGuestMsrStore[cMsrs - 1].u32Msr;
2303 pGuestMsrStore[i].u64Value = pGuestMsrStore[cMsrs - 1].u64Value;
2304 }
2305
2306 /* Remove it from the VM-exit MSR-load area. */
2307 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2308 Assert(pHostMsr[i].u32Msr == idMsr);
2309 pHostMsr[i].u32Msr = pHostMsr[cMsrs - 1].u32Msr;
2310 pHostMsr[i].u64Value = pHostMsr[cMsrs - 1].u64Value;
2311 }
2312
2313 /* Reduce the count to reflect the removed MSR and bail. */
2314 --cMsrs;
2315 break;
2316 }
2317 }
2318
2319 /* Update the VMCS if the count changed (meaning the MSR was found and removed). */
2320 if (cMsrs != pVmcsInfo->cEntryMsrLoad)
2321 {
2322 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2323 AssertRCReturn(rc, rc);
2324
2325 /* We're no longer swapping MSRs during the world-switch, intercept guest read/writes to them. */
2326 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2327 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR);
2328
2329 Log4Func(("Removed MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2330 return VINF_SUCCESS;
2331 }
2332
2333 return VERR_NOT_FOUND;
2334}
2335
2336
2337/**
2338 * Checks if the specified guest MSR is part of the VM-entry MSR-load area.
2339 *
2340 * @returns @c true if found, @c false otherwise.
2341 * @param pVmcsInfo The VMCS info. object.
2342 * @param idMsr The MSR to find.
2343 */
2344static bool hmR0VmxIsAutoLoadGuestMsr(PCVMXVMCSINFO pVmcsInfo, uint32_t idMsr)
2345{
2346 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2347 uint32_t const cMsrs = pVmcsInfo->cEntryMsrLoad;
2348 Assert(pMsrs);
2349 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
2350 for (uint32_t i = 0; i < cMsrs; i++)
2351 {
2352 if (pMsrs[i].u32Msr == idMsr)
2353 return true;
2354 }
2355 return false;
2356}
2357
2358
2359/**
2360 * Updates the value of all host MSRs in the VM-exit MSR-load area.
2361 *
2362 * @param pVCpu The cross context virtual CPU structure.
2363 * @param pVmcsInfo The VMCS info. object.
2364 *
2365 * @remarks No-long-jump zone!!!
2366 */
2367static void hmR0VmxUpdateAutoLoadHostMsrs(PCVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2368{
2369 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2370
2371 PVMXAUTOMSR pHostMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2372 uint32_t const cMsrs = pVmcsInfo->cExitMsrLoad;
2373 Assert(pHostMsrLoad);
2374 Assert(sizeof(*pHostMsrLoad) * cMsrs <= X86_PAGE_4K_SIZE);
2375 LogFlowFunc(("pVCpu=%p cMsrs=%u\n", pVCpu, cMsrs));
2376 for (uint32_t i = 0; i < cMsrs; i++)
2377 {
2378 /*
2379 * Performance hack for the host EFER MSR. We use the cached value rather than re-read it.
2380 * Strict builds will catch mismatches in hmR0VmxCheckAutoLoadStoreMsrs(). See @bugref{7368}.
2381 */
2382 if (pHostMsrLoad[i].u32Msr == MSR_K6_EFER)
2383 pHostMsrLoad[i].u64Value = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer;
2384 else
2385 pHostMsrLoad[i].u64Value = ASMRdMsr(pHostMsrLoad[i].u32Msr);
2386 }
2387}
2388
2389
2390/**
2391 * Saves a set of host MSRs to allow read/write passthru access to the guest and
2392 * perform lazy restoration of the host MSRs while leaving VT-x.
2393 *
2394 * @param pVCpu The cross context virtual CPU structure.
2395 *
2396 * @remarks No-long-jump zone!!!
2397 */
2398static void hmR0VmxLazySaveHostMsrs(PVMCPUCC pVCpu)
2399{
2400 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2401
2402 /*
2403 * Note: If you're adding MSRs here, make sure to update the MSR-bitmap accesses in hmR0VmxSetupVmcsProcCtls().
2404 */
2405 if (!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST))
2406 {
2407 Assert(!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)); /* Guest MSRs better not be loaded now. */
2408 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2409 {
2410 pVCpu->hm.s.vmx.u64HostMsrLStar = ASMRdMsr(MSR_K8_LSTAR);
2411 pVCpu->hm.s.vmx.u64HostMsrStar = ASMRdMsr(MSR_K6_STAR);
2412 pVCpu->hm.s.vmx.u64HostMsrSfMask = ASMRdMsr(MSR_K8_SF_MASK);
2413 pVCpu->hm.s.vmx.u64HostMsrKernelGsBase = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
2414 }
2415 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_SAVED_HOST;
2416 }
2417}
2418
2419
2420/**
2421 * Checks whether the MSR belongs to the set of guest MSRs that we restore
2422 * lazily while leaving VT-x.
2423 *
2424 * @returns true if it does, false otherwise.
2425 * @param pVCpu The cross context virtual CPU structure.
2426 * @param idMsr The MSR to check.
2427 */
2428static bool hmR0VmxIsLazyGuestMsr(PCVMCPUCC pVCpu, uint32_t idMsr)
2429{
2430 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2431 {
2432 switch (idMsr)
2433 {
2434 case MSR_K8_LSTAR:
2435 case MSR_K6_STAR:
2436 case MSR_K8_SF_MASK:
2437 case MSR_K8_KERNEL_GS_BASE:
2438 return true;
2439 }
2440 }
2441 return false;
2442}
2443
2444
2445/**
2446 * Loads a set of guests MSRs to allow read/passthru to the guest.
2447 *
2448 * The name of this function is slightly confusing. This function does NOT
2449 * postpone loading, but loads the MSR right now. "hmR0VmxLazy" is simply a
2450 * common prefix for functions dealing with "lazy restoration" of the shared
2451 * MSRs.
2452 *
2453 * @param pVCpu The cross context virtual CPU structure.
2454 *
2455 * @remarks No-long-jump zone!!!
2456 */
2457static void hmR0VmxLazyLoadGuestMsrs(PVMCPUCC pVCpu)
2458{
2459 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2460 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2461
2462 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2463 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2464 {
2465 /*
2466 * If the guest MSRs are not loaded -and- if all the guest MSRs are identical
2467 * to the MSRs on the CPU (which are the saved host MSRs, see assertion above) then
2468 * we can skip a few MSR writes.
2469 *
2470 * Otherwise, it implies either 1. they're not loaded, or 2. they're loaded but the
2471 * guest MSR values in the guest-CPU context might be different to what's currently
2472 * loaded in the CPU. In either case, we need to write the new guest MSR values to the
2473 * CPU, see @bugref{8728}.
2474 */
2475 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
2476 if ( !(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2477 && pCtx->msrKERNELGSBASE == pVCpu->hm.s.vmx.u64HostMsrKernelGsBase
2478 && pCtx->msrLSTAR == pVCpu->hm.s.vmx.u64HostMsrLStar
2479 && pCtx->msrSTAR == pVCpu->hm.s.vmx.u64HostMsrStar
2480 && pCtx->msrSFMASK == pVCpu->hm.s.vmx.u64HostMsrSfMask)
2481 {
2482#ifdef VBOX_STRICT
2483 Assert(ASMRdMsr(MSR_K8_KERNEL_GS_BASE) == pCtx->msrKERNELGSBASE);
2484 Assert(ASMRdMsr(MSR_K8_LSTAR) == pCtx->msrLSTAR);
2485 Assert(ASMRdMsr(MSR_K6_STAR) == pCtx->msrSTAR);
2486 Assert(ASMRdMsr(MSR_K8_SF_MASK) == pCtx->msrSFMASK);
2487#endif
2488 }
2489 else
2490 {
2491 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pCtx->msrKERNELGSBASE);
2492 ASMWrMsr(MSR_K8_LSTAR, pCtx->msrLSTAR);
2493 ASMWrMsr(MSR_K6_STAR, pCtx->msrSTAR);
2494 ASMWrMsr(MSR_K8_SF_MASK, pCtx->msrSFMASK);
2495 }
2496 }
2497 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_LOADED_GUEST;
2498}
2499
2500
2501/**
2502 * Performs lazy restoration of the set of host MSRs if they were previously
2503 * loaded with guest MSR values.
2504 *
2505 * @param pVCpu The cross context virtual CPU structure.
2506 *
2507 * @remarks No-long-jump zone!!!
2508 * @remarks The guest MSRs should have been saved back into the guest-CPU
2509 * context by hmR0VmxImportGuestState()!!!
2510 */
2511static void hmR0VmxLazyRestoreHostMsrs(PVMCPUCC pVCpu)
2512{
2513 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2514 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2515
2516 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2517 {
2518 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2519 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
2520 {
2521 ASMWrMsr(MSR_K8_LSTAR, pVCpu->hm.s.vmx.u64HostMsrLStar);
2522 ASMWrMsr(MSR_K6_STAR, pVCpu->hm.s.vmx.u64HostMsrStar);
2523 ASMWrMsr(MSR_K8_SF_MASK, pVCpu->hm.s.vmx.u64HostMsrSfMask);
2524 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pVCpu->hm.s.vmx.u64HostMsrKernelGsBase);
2525 }
2526 }
2527 pVCpu->hm.s.vmx.fLazyMsrs &= ~(VMX_LAZY_MSRS_LOADED_GUEST | VMX_LAZY_MSRS_SAVED_HOST);
2528}
2529
2530
2531/**
2532 * Verifies that our cached values of the VMCS fields are all consistent with
2533 * what's actually present in the VMCS.
2534 *
2535 * @returns VBox status code.
2536 * @retval VINF_SUCCESS if all our caches match their respective VMCS fields.
2537 * @retval VERR_VMX_VMCS_FIELD_CACHE_INVALID if a cache field doesn't match the
2538 * VMCS content. HMCPU error-field is
2539 * updated, see VMX_VCI_XXX.
2540 * @param pVCpu The cross context virtual CPU structure.
2541 * @param pVmcsInfo The VMCS info. object.
2542 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2543 */
2544static int hmR0VmxCheckVmcsCtls(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2545{
2546 const char * const pcszVmcs = fIsNstGstVmcs ? "Nested-guest VMCS" : "VMCS";
2547
2548 uint32_t u32Val;
2549 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
2550 AssertRC(rc);
2551 AssertMsgReturnStmt(pVmcsInfo->u32EntryCtls == u32Val,
2552 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32EntryCtls, u32Val),
2553 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_ENTRY,
2554 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2555
2556 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val);
2557 AssertRC(rc);
2558 AssertMsgReturnStmt(pVmcsInfo->u32ExitCtls == u32Val,
2559 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ExitCtls, u32Val),
2560 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_EXIT,
2561 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2562
2563 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val);
2564 AssertRC(rc);
2565 AssertMsgReturnStmt(pVmcsInfo->u32PinCtls == u32Val,
2566 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32PinCtls, u32Val),
2567 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PIN_EXEC,
2568 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2569
2570 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val);
2571 AssertRC(rc);
2572 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls == u32Val,
2573 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls, u32Val),
2574 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC,
2575 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2576
2577 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
2578 {
2579 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val);
2580 AssertRC(rc);
2581 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls2 == u32Val,
2582 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls2, u32Val),
2583 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC2,
2584 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2585 }
2586
2587 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val);
2588 AssertRC(rc);
2589 AssertMsgReturnStmt(pVmcsInfo->u32XcptBitmap == u32Val,
2590 ("%s exception bitmap mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32XcptBitmap, u32Val),
2591 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_XCPT_BITMAP,
2592 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2593
2594 uint64_t u64Val;
2595 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, &u64Val);
2596 AssertRC(rc);
2597 AssertMsgReturnStmt(pVmcsInfo->u64TscOffset == u64Val,
2598 ("%s TSC offset mismatch: Cache=%#RX64 VMCS=%#RX64\n", pcszVmcs, pVmcsInfo->u64TscOffset, u64Val),
2599 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_TSC_OFFSET,
2600 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2601
2602 NOREF(pcszVmcs);
2603 return VINF_SUCCESS;
2604}
2605
2606
2607#ifdef VBOX_STRICT
2608/**
2609 * Verifies that our cached host EFER MSR value has not changed since we cached it.
2610 *
2611 * @param pVCpu The cross context virtual CPU structure.
2612 * @param pVmcsInfo The VMCS info. object.
2613 */
2614static void hmR0VmxCheckHostEferMsr(PCVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2615{
2616 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2617
2618 if (pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_LOAD_EFER_MSR)
2619 {
2620 uint64_t const uHostEferMsr = ASMRdMsr(MSR_K6_EFER);
2621 uint64_t const uHostEferMsrCache = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer;
2622 uint64_t uVmcsEferMsrVmcs;
2623 int rc = VMXReadVmcs64(VMX_VMCS64_HOST_EFER_FULL, &uVmcsEferMsrVmcs);
2624 AssertRC(rc);
2625
2626 AssertMsgReturnVoid(uHostEferMsr == uVmcsEferMsrVmcs,
2627 ("EFER Host/VMCS mismatch! host=%#RX64 vmcs=%#RX64\n", uHostEferMsr, uVmcsEferMsrVmcs));
2628 AssertMsgReturnVoid(uHostEferMsr == uHostEferMsrCache,
2629 ("EFER Host/Cache mismatch! host=%#RX64 cache=%#RX64\n", uHostEferMsr, uHostEferMsrCache));
2630 }
2631}
2632
2633
2634/**
2635 * Verifies whether the guest/host MSR pairs in the auto-load/store area in the
2636 * VMCS are correct.
2637 *
2638 * @param pVCpu The cross context virtual CPU structure.
2639 * @param pVmcsInfo The VMCS info. object.
2640 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2641 */
2642static void hmR0VmxCheckAutoLoadStoreMsrs(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2643{
2644 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2645
2646 /* Read the various MSR-area counts from the VMCS. */
2647 uint32_t cEntryLoadMsrs;
2648 uint32_t cExitStoreMsrs;
2649 uint32_t cExitLoadMsrs;
2650 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &cEntryLoadMsrs); AssertRC(rc);
2651 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &cExitStoreMsrs); AssertRC(rc);
2652 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &cExitLoadMsrs); AssertRC(rc);
2653
2654 /* Verify all the MSR counts are the same. */
2655 Assert(cEntryLoadMsrs == cExitStoreMsrs);
2656 Assert(cExitStoreMsrs == cExitLoadMsrs);
2657 uint32_t const cMsrs = cExitLoadMsrs;
2658
2659 /* Verify the MSR counts do not exceed the maximum count supported by the hardware. */
2660 Assert(cMsrs < VMX_MISC_MAX_MSRS(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc));
2661
2662 /* Verify the MSR counts are within the allocated page size. */
2663 Assert(sizeof(VMXAUTOMSR) * cMsrs <= X86_PAGE_4K_SIZE);
2664
2665 /* Verify the relevant contents of the MSR areas match. */
2666 PCVMXAUTOMSR pGuestMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2667 PCVMXAUTOMSR pGuestMsrStore = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2668 PCVMXAUTOMSR pHostMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2669 bool const fSeparateExitMsrStorePage = hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo);
2670 for (uint32_t i = 0; i < cMsrs; i++)
2671 {
2672 /* Verify that the MSRs are paired properly and that the host MSR has the correct value. */
2673 if (fSeparateExitMsrStorePage)
2674 {
2675 AssertMsgReturnVoid(pGuestMsrLoad->u32Msr == pGuestMsrStore->u32Msr,
2676 ("GuestMsrLoad=%#RX32 GuestMsrStore=%#RX32 cMsrs=%u\n",
2677 pGuestMsrLoad->u32Msr, pGuestMsrStore->u32Msr, cMsrs));
2678 }
2679
2680 AssertMsgReturnVoid(pHostMsrLoad->u32Msr == pGuestMsrLoad->u32Msr,
2681 ("HostMsrLoad=%#RX32 GuestMsrLoad=%#RX32 cMsrs=%u\n",
2682 pHostMsrLoad->u32Msr, pGuestMsrLoad->u32Msr, cMsrs));
2683
2684 uint64_t const u64Msr = ASMRdMsr(pHostMsrLoad->u32Msr);
2685 AssertMsgReturnVoid(pHostMsrLoad->u64Value == u64Msr,
2686 ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2687 pHostMsrLoad->u32Msr, pHostMsrLoad->u64Value, u64Msr, cMsrs));
2688
2689 /* Verify that cached host EFER MSR matches what's loaded the CPU. */
2690 bool const fIsEferMsr = RT_BOOL(pHostMsrLoad->u32Msr == MSR_K6_EFER);
2691 if (fIsEferMsr)
2692 {
2693 AssertMsgReturnVoid(u64Msr == pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer,
2694 ("Cached=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2695 pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer, u64Msr, cMsrs));
2696 }
2697
2698 /* Verify that the accesses are as expected in the MSR bitmap for auto-load/store MSRs. */
2699 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2700 {
2701 uint32_t const fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, pGuestMsrLoad->u32Msr);
2702 if (fIsEferMsr)
2703 {
2704 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_RD), ("Passthru read for EFER MSR!?\n"));
2705 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_WR), ("Passthru write for EFER MSR!?\n"));
2706 }
2707 else
2708 {
2709 if (!fIsNstGstVmcs)
2710 {
2711 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_ALLOW_RD_WR) == VMXMSRPM_ALLOW_RD_WR,
2712 ("u32Msr=%#RX32 cMsrs=%u No passthru read/write!\n", pGuestMsrLoad->u32Msr, cMsrs));
2713 }
2714 else
2715 {
2716 /*
2717 * A nested-guest VMCS must -also- allow read/write passthrough for the MSR for us to
2718 * execute a nested-guest with MSR passthrough.
2719 *
2720 * Check if the nested-guest MSR bitmap allows passthrough, and if so, assert that we
2721 * allow passthrough too.
2722 */
2723 void const *pvMsrBitmapNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
2724 Assert(pvMsrBitmapNstGst);
2725 uint32_t const fMsrpmNstGst = CPUMGetVmxMsrPermission(pvMsrBitmapNstGst, pGuestMsrLoad->u32Msr);
2726 AssertMsgReturnVoid(fMsrpm == fMsrpmNstGst,
2727 ("u32Msr=%#RX32 cMsrs=%u Permission mismatch fMsrpm=%#x fMsrpmNstGst=%#x!\n",
2728 pGuestMsrLoad->u32Msr, cMsrs, fMsrpm, fMsrpmNstGst));
2729 }
2730 }
2731 }
2732
2733 /* Move to the next MSR. */
2734 pHostMsrLoad++;
2735 pGuestMsrLoad++;
2736 pGuestMsrStore++;
2737 }
2738}
2739#endif /* VBOX_STRICT */
2740
2741
2742/**
2743 * Flushes the TLB using EPT.
2744 *
2745 * @returns VBox status code.
2746 * @param pVCpu The cross context virtual CPU structure of the calling
2747 * EMT. Can be NULL depending on @a enmTlbFlush.
2748 * @param pVmcsInfo The VMCS info. object. Can be NULL depending on @a
2749 * enmTlbFlush.
2750 * @param enmTlbFlush Type of flush.
2751 *
2752 * @remarks Caller is responsible for making sure this function is called only
2753 * when NestedPaging is supported and providing @a enmTlbFlush that is
2754 * supported by the CPU.
2755 * @remarks Can be called with interrupts disabled.
2756 */
2757static void hmR0VmxFlushEpt(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, VMXTLBFLUSHEPT enmTlbFlush)
2758{
2759 uint64_t au64Descriptor[2];
2760 if (enmTlbFlush == VMXTLBFLUSHEPT_ALL_CONTEXTS)
2761 au64Descriptor[0] = 0;
2762 else
2763 {
2764 Assert(pVCpu);
2765 Assert(pVmcsInfo);
2766 au64Descriptor[0] = pVmcsInfo->HCPhysEPTP;
2767 }
2768 au64Descriptor[1] = 0; /* MBZ. Intel spec. 33.3 "VMX Instructions" */
2769
2770 int rc = VMXR0InvEPT(enmTlbFlush, &au64Descriptor[0]);
2771 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %#RHp failed. rc=%Rrc\n", enmTlbFlush, au64Descriptor[0], rc));
2772
2773 if ( RT_SUCCESS(rc)
2774 && pVCpu)
2775 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushNestedPaging);
2776}
2777
2778
2779/**
2780 * Flushes the TLB using VPID.
2781 *
2782 * @returns VBox status code.
2783 * @param pVCpu The cross context virtual CPU structure of the calling
2784 * EMT. Can be NULL depending on @a enmTlbFlush.
2785 * @param enmTlbFlush Type of flush.
2786 * @param GCPtr Virtual address of the page to flush (can be 0 depending
2787 * on @a enmTlbFlush).
2788 *
2789 * @remarks Can be called with interrupts disabled.
2790 */
2791static void hmR0VmxFlushVpid(PVMCPUCC pVCpu, VMXTLBFLUSHVPID enmTlbFlush, RTGCPTR GCPtr)
2792{
2793 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fVpid);
2794
2795 uint64_t au64Descriptor[2];
2796 if (enmTlbFlush == VMXTLBFLUSHVPID_ALL_CONTEXTS)
2797 {
2798 au64Descriptor[0] = 0;
2799 au64Descriptor[1] = 0;
2800 }
2801 else
2802 {
2803 AssertPtr(pVCpu);
2804 AssertMsg(pVCpu->hm.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
2805 AssertMsg(pVCpu->hm.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
2806 au64Descriptor[0] = pVCpu->hm.s.uCurrentAsid;
2807 au64Descriptor[1] = GCPtr;
2808 }
2809
2810 int rc = VMXR0InvVPID(enmTlbFlush, &au64Descriptor[0]);
2811 AssertMsg(rc == VINF_SUCCESS,
2812 ("VMXR0InvVPID %#x %u %RGv failed with %Rrc\n", enmTlbFlush, pVCpu ? pVCpu->hm.s.uCurrentAsid : 0, GCPtr, rc));
2813
2814 if ( RT_SUCCESS(rc)
2815 && pVCpu)
2816 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
2817 NOREF(rc);
2818}
2819
2820
2821/**
2822 * Invalidates a guest page by guest virtual address. Only relevant for EPT/VPID,
2823 * otherwise there is nothing really to invalidate.
2824 *
2825 * @returns VBox status code.
2826 * @param pVCpu The cross context virtual CPU structure.
2827 * @param GCVirt Guest virtual address of the page to invalidate.
2828 */
2829VMMR0DECL(int) VMXR0InvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt)
2830{
2831 AssertPtr(pVCpu);
2832 LogFlowFunc(("pVCpu=%p GCVirt=%RGv\n", pVCpu, GCVirt));
2833
2834 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_TLB_FLUSH))
2835 {
2836 /*
2837 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for
2838 * the EPT case. See @bugref{6043} and @bugref{6177}.
2839 *
2840 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VM-entry in hmR0VmxFlushTLB*()
2841 * as this function maybe called in a loop with individual addresses.
2842 */
2843 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2844 if (pVM->hm.s.vmx.fVpid)
2845 {
2846 bool fVpidFlush = RT_BOOL(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR);
2847 if (fVpidFlush)
2848 {
2849 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_INDIV_ADDR, GCVirt);
2850 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
2851 }
2852 else
2853 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2854 }
2855 else if (pVM->hm.s.fNestedPaging)
2856 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2857 }
2858
2859 return VINF_SUCCESS;
2860}
2861
2862
2863/**
2864 * Dummy placeholder for tagged-TLB flush handling before VM-entry. Used in the
2865 * case where neither EPT nor VPID is supported by the CPU.
2866 *
2867 * @param pHostCpu The HM physical-CPU structure.
2868 * @param pVCpu The cross context virtual CPU structure.
2869 *
2870 * @remarks Called with interrupts disabled.
2871 */
2872static void hmR0VmxFlushTaggedTlbNone(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
2873{
2874 AssertPtr(pVCpu);
2875 AssertPtr(pHostCpu);
2876
2877 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
2878
2879 Assert(pHostCpu->idCpu != NIL_RTCPUID);
2880 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
2881 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
2882 pVCpu->hm.s.fForceTLBFlush = false;
2883 return;
2884}
2885
2886
2887/**
2888 * Flushes the tagged-TLB entries for EPT+VPID CPUs as necessary.
2889 *
2890 * @param pHostCpu The HM physical-CPU structure.
2891 * @param pVCpu The cross context virtual CPU structure.
2892 * @param pVmcsInfo The VMCS info. object.
2893 *
2894 * @remarks All references to "ASID" in this function pertains to "VPID" in Intel's
2895 * nomenclature. The reason is, to avoid confusion in compare statements
2896 * since the host-CPU copies are named "ASID".
2897 *
2898 * @remarks Called with interrupts disabled.
2899 */
2900static void hmR0VmxFlushTaggedTlbBoth(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2901{
2902#ifdef VBOX_WITH_STATISTICS
2903 bool fTlbFlushed = false;
2904# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { fTlbFlushed = true; } while (0)
2905# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { \
2906 if (!fTlbFlushed) \
2907 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch); \
2908 } while (0)
2909#else
2910# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { } while (0)
2911# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { } while (0)
2912#endif
2913
2914 AssertPtr(pVCpu);
2915 AssertPtr(pHostCpu);
2916 Assert(pHostCpu->idCpu != NIL_RTCPUID);
2917
2918 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2919 AssertMsg(pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid,
2920 ("hmR0VmxFlushTaggedTlbBoth cannot be invoked unless NestedPaging & VPID are enabled."
2921 "fNestedPaging=%RTbool fVpid=%RTbool", pVM->hm.s.fNestedPaging, pVM->hm.s.vmx.fVpid));
2922
2923 /*
2924 * Force a TLB flush for the first world-switch if the current CPU differs from the one we
2925 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
2926 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
2927 * cannot reuse the current ASID anymore.
2928 */
2929 if ( pVCpu->hm.s.idLastCpu != pHostCpu->idCpu
2930 || pVCpu->hm.s.cTlbFlushes != pHostCpu->cTlbFlushes)
2931 {
2932 ++pHostCpu->uCurrentAsid;
2933 if (pHostCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
2934 {
2935 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0. */
2936 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
2937 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
2938 }
2939
2940 pVCpu->hm.s.uCurrentAsid = pHostCpu->uCurrentAsid;
2941 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
2942 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
2943
2944 /*
2945 * Flush by EPT when we get rescheduled to a new host CPU to ensure EPT-only tagged mappings are also
2946 * invalidated. We don't need to flush-by-VPID here as flushing by EPT covers it. See @bugref{6568}.
2947 */
2948 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hm.s.vmx.enmTlbFlushEpt);
2949 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
2950 HMVMX_SET_TAGGED_TLB_FLUSHED();
2951 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
2952 }
2953 else if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH)) /* Check for explicit TLB flushes. */
2954 {
2955 /*
2956 * Changes to the EPT paging structure by VMM requires flushing-by-EPT as the CPU
2957 * creates guest-physical (ie. only EPT-tagged) mappings while traversing the EPT
2958 * tables when EPT is in use. Flushing-by-VPID will only flush linear (only
2959 * VPID-tagged) and combined (EPT+VPID tagged) mappings but not guest-physical
2960 * mappings, see @bugref{6568}.
2961 *
2962 * See Intel spec. 28.3.2 "Creating and Using Cached Translation Information".
2963 */
2964 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hm.s.vmx.enmTlbFlushEpt);
2965 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
2966 HMVMX_SET_TAGGED_TLB_FLUSHED();
2967 }
2968 else if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
2969 {
2970 /*
2971 * The nested-guest specifies its own guest-physical address to use as the APIC-access
2972 * address which requires flushing the TLB of EPT cached structures.
2973 *
2974 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
2975 */
2976 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hm.s.vmx.enmTlbFlushEpt);
2977 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
2978 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
2979 HMVMX_SET_TAGGED_TLB_FLUSHED();
2980 }
2981
2982
2983 pVCpu->hm.s.fForceTLBFlush = false;
2984 HMVMX_UPDATE_FLUSH_SKIPPED_STAT();
2985
2986 Assert(pVCpu->hm.s.idLastCpu == pHostCpu->idCpu);
2987 Assert(pVCpu->hm.s.cTlbFlushes == pHostCpu->cTlbFlushes);
2988 AssertMsg(pVCpu->hm.s.cTlbFlushes == pHostCpu->cTlbFlushes,
2989 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pHostCpu->cTlbFlushes));
2990 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
2991 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
2992 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
2993 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
2994 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
2995
2996 /* Update VMCS with the VPID. */
2997 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
2998 AssertRC(rc);
2999
3000#undef HMVMX_SET_TAGGED_TLB_FLUSHED
3001}
3002
3003
3004/**
3005 * Flushes the tagged-TLB entries for EPT CPUs as necessary.
3006 *
3007 * @param pHostCpu The HM physical-CPU structure.
3008 * @param pVCpu The cross context virtual CPU structure.
3009 * @param pVmcsInfo The VMCS info. object.
3010 *
3011 * @remarks Called with interrupts disabled.
3012 */
3013static void hmR0VmxFlushTaggedTlbEpt(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3014{
3015 AssertPtr(pVCpu);
3016 AssertPtr(pHostCpu);
3017 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3018 AssertMsg(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked without NestedPaging."));
3019 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fVpid, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with VPID."));
3020
3021 /*
3022 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
3023 * A change in the TLB flush count implies the host CPU is online after a suspend/resume.
3024 */
3025 if ( pVCpu->hm.s.idLastCpu != pHostCpu->idCpu
3026 || pVCpu->hm.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3027 {
3028 pVCpu->hm.s.fForceTLBFlush = true;
3029 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3030 }
3031
3032 /* Check for explicit TLB flushes. */
3033 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3034 {
3035 pVCpu->hm.s.fForceTLBFlush = true;
3036 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3037 }
3038
3039 /* Check for TLB flushes while switching to/from a nested-guest. */
3040 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3041 {
3042 pVCpu->hm.s.fForceTLBFlush = true;
3043 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3044 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3045 }
3046
3047 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
3048 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3049
3050 if (pVCpu->hm.s.fForceTLBFlush)
3051 {
3052 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVCpu->CTX_SUFF(pVM)->hm.s.vmx.enmTlbFlushEpt);
3053 pVCpu->hm.s.fForceTLBFlush = false;
3054 }
3055}
3056
3057
3058/**
3059 * Flushes the tagged-TLB entries for VPID CPUs as necessary.
3060 *
3061 * @param pHostCpu The HM physical-CPU structure.
3062 * @param pVCpu The cross context virtual CPU structure.
3063 *
3064 * @remarks Called with interrupts disabled.
3065 */
3066static void hmR0VmxFlushTaggedTlbVpid(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
3067{
3068 AssertPtr(pVCpu);
3069 AssertPtr(pHostCpu);
3070 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3071 AssertMsg(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fVpid, ("hmR0VmxFlushTlbVpid cannot be invoked without VPID."));
3072 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging"));
3073
3074 /*
3075 * Force a TLB flush for the first world switch if the current CPU differs from the one we
3076 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
3077 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
3078 * cannot reuse the current ASID anymore.
3079 */
3080 if ( pVCpu->hm.s.idLastCpu != pHostCpu->idCpu
3081 || pVCpu->hm.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3082 {
3083 pVCpu->hm.s.fForceTLBFlush = true;
3084 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3085 }
3086
3087 /* Check for explicit TLB flushes. */
3088 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3089 {
3090 /*
3091 * If we ever support VPID flush combinations other than ALL or SINGLE-context (see
3092 * hmR0VmxSetupTaggedTlb()) we would need to explicitly flush in this case (add an
3093 * fExplicitFlush = true here and change the pHostCpu->fFlushAsidBeforeUse check below to
3094 * include fExplicitFlush's too) - an obscure corner case.
3095 */
3096 pVCpu->hm.s.fForceTLBFlush = true;
3097 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3098 }
3099
3100 /* Check for TLB flushes while switching to/from a nested-guest. */
3101 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3102 {
3103 pVCpu->hm.s.fForceTLBFlush = true;
3104 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3105 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3106 }
3107
3108 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3109 pVCpu->hm.s.idLastCpu = pHostCpu->idCpu;
3110 if (pVCpu->hm.s.fForceTLBFlush)
3111 {
3112 ++pHostCpu->uCurrentAsid;
3113 if (pHostCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
3114 {
3115 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0 */
3116 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
3117 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
3118 }
3119
3120 pVCpu->hm.s.fForceTLBFlush = false;
3121 pVCpu->hm.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3122 pVCpu->hm.s.uCurrentAsid = pHostCpu->uCurrentAsid;
3123 if (pHostCpu->fFlushAsidBeforeUse)
3124 {
3125 if (pVM->hm.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_SINGLE_CONTEXT)
3126 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_SINGLE_CONTEXT, 0 /* GCPtr */);
3127 else if (pVM->hm.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_ALL_CONTEXTS)
3128 {
3129 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_ALL_CONTEXTS, 0 /* GCPtr */);
3130 pHostCpu->fFlushAsidBeforeUse = false;
3131 }
3132 else
3133 {
3134 /* hmR0VmxSetupTaggedTlb() ensures we never get here. Paranoia. */
3135 AssertMsgFailed(("Unsupported VPID-flush context type.\n"));
3136 }
3137 }
3138 }
3139
3140 AssertMsg(pVCpu->hm.s.cTlbFlushes == pHostCpu->cTlbFlushes,
3141 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pHostCpu->cTlbFlushes));
3142 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
3143 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3144 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
3145 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
3146 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
3147
3148 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
3149 AssertRC(rc);
3150}
3151
3152
3153/**
3154 * Flushes the guest TLB entry based on CPU capabilities.
3155 *
3156 * @param pHostCpu The HM physical-CPU structure.
3157 * @param pVCpu The cross context virtual CPU structure.
3158 * @param pVmcsInfo The VMCS info. object.
3159 *
3160 * @remarks Called with interrupts disabled.
3161 */
3162static void hmR0VmxFlushTaggedTlb(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3163{
3164#ifdef HMVMX_ALWAYS_FLUSH_TLB
3165 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
3166#endif
3167 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3168 switch (pVM->hm.s.vmx.enmTlbFlushType)
3169 {
3170 case VMXTLBFLUSHTYPE_EPT_VPID: hmR0VmxFlushTaggedTlbBoth(pHostCpu, pVCpu, pVmcsInfo); break;
3171 case VMXTLBFLUSHTYPE_EPT: hmR0VmxFlushTaggedTlbEpt(pHostCpu, pVCpu, pVmcsInfo); break;
3172 case VMXTLBFLUSHTYPE_VPID: hmR0VmxFlushTaggedTlbVpid(pHostCpu, pVCpu); break;
3173 case VMXTLBFLUSHTYPE_NONE: hmR0VmxFlushTaggedTlbNone(pHostCpu, pVCpu); break;
3174 default:
3175 AssertMsgFailed(("Invalid flush-tag function identifier\n"));
3176 break;
3177 }
3178 /* Don't assert that VMCPU_FF_TLB_FLUSH should no longer be pending. It can be set by other EMTs. */
3179}
3180
3181
3182/**
3183 * Sets up the appropriate tagged TLB-flush level and handler for flushing guest
3184 * TLB entries from the host TLB before VM-entry.
3185 *
3186 * @returns VBox status code.
3187 * @param pVM The cross context VM structure.
3188 */
3189static int hmR0VmxSetupTaggedTlb(PVMCC pVM)
3190{
3191 /*
3192 * Determine optimal flush type for nested paging.
3193 * We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup
3194 * unrestricted guest execution (see hmR3InitFinalizeR0()).
3195 */
3196 if (pVM->hm.s.fNestedPaging)
3197 {
3198 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT)
3199 {
3200 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT)
3201 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_SINGLE_CONTEXT;
3202 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
3203 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_ALL_CONTEXTS;
3204 else
3205 {
3206 /* Shouldn't happen. EPT is supported but no suitable flush-types supported. */
3207 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3208 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED;
3209 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3210 }
3211
3212 /* Make sure the write-back cacheable memory type for EPT is supported. */
3213 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EMT_WB)))
3214 {
3215 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3216 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_MEM_TYPE_NOT_WB;
3217 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3218 }
3219
3220 /* EPT requires a page-walk length of 4. */
3221 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4)))
3222 {
3223 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3224 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED;
3225 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3226 }
3227 }
3228 else
3229 {
3230 /* Shouldn't happen. EPT is supported but INVEPT instruction is not supported. */
3231 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3232 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_INVEPT_UNAVAILABLE;
3233 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3234 }
3235 }
3236
3237 /*
3238 * Determine optimal flush type for VPID.
3239 */
3240 if (pVM->hm.s.vmx.fVpid)
3241 {
3242 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID)
3243 {
3244 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT)
3245 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_SINGLE_CONTEXT;
3246 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS)
3247 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_ALL_CONTEXTS;
3248 else
3249 {
3250 /* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
3251 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
3252 LogRelFunc(("Only INDIV_ADDR supported. Ignoring VPID.\n"));
3253 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
3254 LogRelFunc(("Only SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
3255 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3256 pVM->hm.s.vmx.fVpid = false;
3257 }
3258 }
3259 else
3260 {
3261 /* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
3262 Log4Func(("VPID supported without INVEPT support. Ignoring VPID.\n"));
3263 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3264 pVM->hm.s.vmx.fVpid = false;
3265 }
3266 }
3267
3268 /*
3269 * Setup the handler for flushing tagged-TLBs.
3270 */
3271 if (pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid)
3272 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT_VPID;
3273 else if (pVM->hm.s.fNestedPaging)
3274 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT;
3275 else if (pVM->hm.s.vmx.fVpid)
3276 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_VPID;
3277 else
3278 pVM->hm.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_NONE;
3279 return VINF_SUCCESS;
3280}
3281
3282
3283#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3284/**
3285 * Sets up the shadow VMCS fields arrays.
3286 *
3287 * This function builds arrays of VMCS fields to sync the shadow VMCS later while
3288 * executing the guest.
3289 *
3290 * @returns VBox status code.
3291 * @param pVM The cross context VM structure.
3292 */
3293static int hmR0VmxSetupShadowVmcsFieldsArrays(PVMCC pVM)
3294{
3295 /*
3296 * Paranoia. Ensure we haven't exposed the VMWRITE-All VMX feature to the guest
3297 * when the host does not support it.
3298 */
3299 bool const fGstVmwriteAll = pVM->cpum.ro.GuestFeatures.fVmxVmwriteAll;
3300 if ( !fGstVmwriteAll
3301 || (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL))
3302 { /* likely. */ }
3303 else
3304 {
3305 LogRelFunc(("VMX VMWRITE-All feature exposed to the guest but host CPU does not support it!\n"));
3306 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_GST_HOST_VMWRITE_ALL;
3307 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3308 }
3309
3310 uint32_t const cVmcsFields = RT_ELEMENTS(g_aVmcsFields);
3311 uint32_t cRwFields = 0;
3312 uint32_t cRoFields = 0;
3313 for (uint32_t i = 0; i < cVmcsFields; i++)
3314 {
3315 VMXVMCSFIELD VmcsField;
3316 VmcsField.u = g_aVmcsFields[i];
3317
3318 /*
3319 * We will be writing "FULL" (64-bit) fields while syncing the shadow VMCS.
3320 * Therefore, "HIGH" (32-bit portion of 64-bit) fields must not be included
3321 * in the shadow VMCS fields array as they would be redundant.
3322 *
3323 * If the VMCS field depends on a CPU feature that is not exposed to the guest,
3324 * we must not include it in the shadow VMCS fields array. Guests attempting to
3325 * VMREAD/VMWRITE such VMCS fields would cause a VM-exit and we shall emulate
3326 * the required behavior.
3327 */
3328 if ( VmcsField.n.fAccessType == VMX_VMCSFIELD_ACCESS_FULL
3329 && CPUMIsGuestVmxVmcsFieldValid(pVM, VmcsField.u))
3330 {
3331 /*
3332 * Read-only fields are placed in a separate array so that while syncing shadow
3333 * VMCS fields later (which is more performance critical) we can avoid branches.
3334 *
3335 * However, if the guest can write to all fields (including read-only fields),
3336 * we treat it a as read/write field. Otherwise, writing to these fields would
3337 * cause a VMWRITE instruction error while syncing the shadow VMCS .
3338 */
3339 if ( fGstVmwriteAll
3340 || !VMXIsVmcsFieldReadOnly(VmcsField.u))
3341 pVM->hm.s.vmx.paShadowVmcsFields[cRwFields++] = VmcsField.u;
3342 else
3343 pVM->hm.s.vmx.paShadowVmcsRoFields[cRoFields++] = VmcsField.u;
3344 }
3345 }
3346
3347 /* Update the counts. */
3348 pVM->hm.s.vmx.cShadowVmcsFields = cRwFields;
3349 pVM->hm.s.vmx.cShadowVmcsRoFields = cRoFields;
3350 return VINF_SUCCESS;
3351}
3352
3353
3354/**
3355 * Sets up the VMREAD and VMWRITE bitmaps.
3356 *
3357 * @param pVM The cross context VM structure.
3358 */
3359static void hmR0VmxSetupVmreadVmwriteBitmaps(PVMCC pVM)
3360{
3361 /*
3362 * By default, ensure guest attempts to acceses to any VMCS fields cause VM-exits.
3363 */
3364 uint32_t const cbBitmap = X86_PAGE_4K_SIZE;
3365 uint8_t *pbVmreadBitmap = (uint8_t *)pVM->hm.s.vmx.pvVmreadBitmap;
3366 uint8_t *pbVmwriteBitmap = (uint8_t *)pVM->hm.s.vmx.pvVmwriteBitmap;
3367 ASMMemFill32(pbVmreadBitmap, cbBitmap, UINT32_C(0xffffffff));
3368 ASMMemFill32(pbVmwriteBitmap, cbBitmap, UINT32_C(0xffffffff));
3369
3370 /*
3371 * Skip intercepting VMREAD/VMWRITE to guest read/write fields in the
3372 * VMREAD and VMWRITE bitmaps.
3373 */
3374 {
3375 uint32_t const *paShadowVmcsFields = pVM->hm.s.vmx.paShadowVmcsFields;
3376 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
3377 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
3378 {
3379 uint32_t const uVmcsField = paShadowVmcsFields[i];
3380 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3381 Assert(uVmcsField >> 3 < cbBitmap);
3382 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3383 ASMBitClear(pbVmwriteBitmap + (uVmcsField >> 3), uVmcsField & 7);
3384 }
3385 }
3386
3387 /*
3388 * Skip intercepting VMREAD for guest read-only fields in the VMREAD bitmap
3389 * if the host supports VMWRITE to all supported VMCS fields.
3390 */
3391 if (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL)
3392 {
3393 uint32_t const *paShadowVmcsRoFields = pVM->hm.s.vmx.paShadowVmcsRoFields;
3394 uint32_t const cShadowVmcsRoFields = pVM->hm.s.vmx.cShadowVmcsRoFields;
3395 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
3396 {
3397 uint32_t const uVmcsField = paShadowVmcsRoFields[i];
3398 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3399 Assert(uVmcsField >> 3 < cbBitmap);
3400 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3401 }
3402 }
3403}
3404#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
3405
3406
3407/**
3408 * Sets up the virtual-APIC page address for the VMCS.
3409 *
3410 * @param pVmcsInfo The VMCS info. object.
3411 */
3412DECLINLINE(void) hmR0VmxSetupVmcsVirtApicAddr(PCVMXVMCSINFO pVmcsInfo)
3413{
3414 RTHCPHYS const HCPhysVirtApic = pVmcsInfo->HCPhysVirtApic;
3415 Assert(HCPhysVirtApic != NIL_RTHCPHYS);
3416 Assert(!(HCPhysVirtApic & 0xfff)); /* Bits 11:0 MBZ. */
3417 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
3418 AssertRC(rc);
3419}
3420
3421
3422/**
3423 * Sets up the MSR-bitmap address for the VMCS.
3424 *
3425 * @param pVmcsInfo The VMCS info. object.
3426 */
3427DECLINLINE(void) hmR0VmxSetupVmcsMsrBitmapAddr(PCVMXVMCSINFO pVmcsInfo)
3428{
3429 RTHCPHYS const HCPhysMsrBitmap = pVmcsInfo->HCPhysMsrBitmap;
3430 Assert(HCPhysMsrBitmap != NIL_RTHCPHYS);
3431 Assert(!(HCPhysMsrBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3432 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_MSR_BITMAP_FULL, HCPhysMsrBitmap);
3433 AssertRC(rc);
3434}
3435
3436
3437/**
3438 * Sets up the APIC-access page address for the VMCS.
3439 *
3440 * @param pVCpu The cross context virtual CPU structure.
3441 */
3442DECLINLINE(void) hmR0VmxSetupVmcsApicAccessAddr(PVMCPUCC pVCpu)
3443{
3444 RTHCPHYS const HCPhysApicAccess = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysApicAccess;
3445 Assert(HCPhysApicAccess != NIL_RTHCPHYS);
3446 Assert(!(HCPhysApicAccess & 0xfff)); /* Bits 11:0 MBZ. */
3447 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
3448 AssertRC(rc);
3449}
3450
3451
3452#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3453/**
3454 * Sets up the VMREAD bitmap address for the VMCS.
3455 *
3456 * @param pVCpu The cross context virtual CPU structure.
3457 */
3458DECLINLINE(void) hmR0VmxSetupVmcsVmreadBitmapAddr(PVMCPUCC pVCpu)
3459{
3460 RTHCPHYS const HCPhysVmreadBitmap = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysVmreadBitmap;
3461 Assert(HCPhysVmreadBitmap != NIL_RTHCPHYS);
3462 Assert(!(HCPhysVmreadBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3463 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL, HCPhysVmreadBitmap);
3464 AssertRC(rc);
3465}
3466
3467
3468/**
3469 * Sets up the VMWRITE bitmap address for the VMCS.
3470 *
3471 * @param pVCpu The cross context virtual CPU structure.
3472 */
3473DECLINLINE(void) hmR0VmxSetupVmcsVmwriteBitmapAddr(PVMCPUCC pVCpu)
3474{
3475 RTHCPHYS const HCPhysVmwriteBitmap = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysVmwriteBitmap;
3476 Assert(HCPhysVmwriteBitmap != NIL_RTHCPHYS);
3477 Assert(!(HCPhysVmwriteBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3478 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL, HCPhysVmwriteBitmap);
3479 AssertRC(rc);
3480}
3481#endif
3482
3483
3484/**
3485 * Sets up the VM-entry MSR load, VM-exit MSR-store and VM-exit MSR-load addresses
3486 * in the VMCS.
3487 *
3488 * @returns VBox status code.
3489 * @param pVmcsInfo The VMCS info. object.
3490 */
3491DECLINLINE(int) hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(PVMXVMCSINFO pVmcsInfo)
3492{
3493 RTHCPHYS const HCPhysGuestMsrLoad = pVmcsInfo->HCPhysGuestMsrLoad;
3494 Assert(HCPhysGuestMsrLoad != NIL_RTHCPHYS);
3495 Assert(!(HCPhysGuestMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3496
3497 RTHCPHYS const HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrStore;
3498 Assert(HCPhysGuestMsrStore != NIL_RTHCPHYS);
3499 Assert(!(HCPhysGuestMsrStore & 0xf)); /* Bits 3:0 MBZ. */
3500
3501 RTHCPHYS const HCPhysHostMsrLoad = pVmcsInfo->HCPhysHostMsrLoad;
3502 Assert(HCPhysHostMsrLoad != NIL_RTHCPHYS);
3503 Assert(!(HCPhysHostMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3504
3505 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL, HCPhysGuestMsrLoad); AssertRC(rc);
3506 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL, HCPhysGuestMsrStore); AssertRC(rc);
3507 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL, HCPhysHostMsrLoad); AssertRC(rc);
3508 return VINF_SUCCESS;
3509}
3510
3511
3512/**
3513 * Sets up MSR permissions in the MSR bitmap of a VMCS info. object.
3514 *
3515 * @param pVCpu The cross context virtual CPU structure.
3516 * @param pVmcsInfo The VMCS info. object.
3517 */
3518static void hmR0VmxSetupVmcsMsrPermissions(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3519{
3520 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS);
3521
3522 /*
3523 * The guest can access the following MSRs (read, write) without causing
3524 * VM-exits; they are loaded/stored automatically using fields in the VMCS.
3525 */
3526 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3527 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_CS, VMXMSRPM_ALLOW_RD_WR);
3528 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_ESP, VMXMSRPM_ALLOW_RD_WR);
3529 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_EIP, VMXMSRPM_ALLOW_RD_WR);
3530 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3531 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_FS_BASE, VMXMSRPM_ALLOW_RD_WR);
3532
3533 /*
3534 * The IA32_PRED_CMD and IA32_FLUSH_CMD MSRs are write-only and has no state
3535 * associated with then. We never need to intercept access (writes need to be
3536 * executed without causing a VM-exit, reads will #GP fault anyway).
3537 *
3538 * The IA32_SPEC_CTRL MSR is read/write and has state. We allow the guest to
3539 * read/write them. We swap the the guest/host MSR value using the
3540 * auto-load/store MSR area.
3541 */
3542 if (pVM->cpum.ro.GuestFeatures.fIbpb)
3543 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_PRED_CMD, VMXMSRPM_ALLOW_RD_WR);
3544 if (pVM->cpum.ro.GuestFeatures.fFlushCmd)
3545 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_FLUSH_CMD, VMXMSRPM_ALLOW_RD_WR);
3546 if (pVM->cpum.ro.GuestFeatures.fIbrs)
3547 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SPEC_CTRL, VMXMSRPM_ALLOW_RD_WR);
3548
3549 /*
3550 * Allow full read/write access for the following MSRs (mandatory for VT-x)
3551 * required for 64-bit guests.
3552 */
3553 if (pVM->hm.s.fAllow64BitGuests)
3554 {
3555 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_LSTAR, VMXMSRPM_ALLOW_RD_WR);
3556 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K6_STAR, VMXMSRPM_ALLOW_RD_WR);
3557 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_SF_MASK, VMXMSRPM_ALLOW_RD_WR);
3558 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_KERNEL_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3559 }
3560
3561 /*
3562 * IA32_EFER MSR is always intercepted, see @bugref{9180#c37}.
3563 */
3564#ifdef VBOX_STRICT
3565 Assert(pVmcsInfo->pvMsrBitmap);
3566 uint32_t const fMsrpmEfer = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, MSR_K6_EFER);
3567 Assert(fMsrpmEfer == VMXMSRPM_EXIT_RD_WR);
3568#endif
3569}
3570
3571
3572/**
3573 * Sets up pin-based VM-execution controls in the VMCS.
3574 *
3575 * @returns VBox status code.
3576 * @param pVCpu The cross context virtual CPU structure.
3577 * @param pVmcsInfo The VMCS info. object.
3578 */
3579static int hmR0VmxSetupVmcsPinCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3580{
3581 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3582 uint32_t fVal = pVM->hm.s.vmx.Msrs.PinCtls.n.allowed0; /* Bits set here must always be set. */
3583 uint32_t const fZap = pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
3584
3585 fVal |= VMX_PIN_CTLS_EXT_INT_EXIT /* External interrupts cause a VM-exit. */
3586 | VMX_PIN_CTLS_NMI_EXIT; /* Non-maskable interrupts (NMIs) cause a VM-exit. */
3587
3588 if (pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1 & VMX_PIN_CTLS_VIRT_NMI)
3589 fVal |= VMX_PIN_CTLS_VIRT_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
3590
3591 /* Enable the VMX-preemption timer. */
3592 if (pVM->hm.s.vmx.fUsePreemptTimer)
3593 {
3594 Assert(pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1 & VMX_PIN_CTLS_PREEMPT_TIMER);
3595 fVal |= VMX_PIN_CTLS_PREEMPT_TIMER;
3596 }
3597
3598#if 0
3599 /* Enable posted-interrupt processing. */
3600 if (pVM->hm.s.fPostedIntrs)
3601 {
3602 Assert(pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1 & VMX_PIN_CTLS_POSTED_INT);
3603 Assert(pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_ACK_EXT_INT);
3604 fVal |= VMX_PIN_CTLS_POSTED_INT;
3605 }
3606#endif
3607
3608 if ((fVal & fZap) != fVal)
3609 {
3610 LogRelFunc(("Invalid pin-based VM-execution controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3611 pVM->hm.s.vmx.Msrs.PinCtls.n.allowed0, fVal, fZap));
3612 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
3613 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3614 }
3615
3616 /* Commit it to the VMCS and update our cache. */
3617 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, fVal);
3618 AssertRC(rc);
3619 pVmcsInfo->u32PinCtls = fVal;
3620
3621 return VINF_SUCCESS;
3622}
3623
3624
3625/**
3626 * Sets up secondary processor-based VM-execution controls in the VMCS.
3627 *
3628 * @returns VBox status code.
3629 * @param pVCpu The cross context virtual CPU structure.
3630 * @param pVmcsInfo The VMCS info. object.
3631 */
3632static int hmR0VmxSetupVmcsProcCtls2(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3633{
3634 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3635 uint32_t fVal = pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed0; /* Bits set here must be set in the VMCS. */
3636 uint32_t const fZap = pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3637
3638 /* WBINVD causes a VM-exit. */
3639 if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_WBINVD_EXIT)
3640 fVal |= VMX_PROC_CTLS2_WBINVD_EXIT;
3641
3642 /* Enable EPT (aka nested-paging). */
3643 if (pVM->hm.s.fNestedPaging)
3644 fVal |= VMX_PROC_CTLS2_EPT;
3645
3646 /* Enable the INVPCID instruction if we expose it to the guest and is supported
3647 by the hardware. Without this, guest executing INVPCID would cause a #UD. */
3648 if ( pVM->cpum.ro.GuestFeatures.fInvpcid
3649 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_INVPCID))
3650 fVal |= VMX_PROC_CTLS2_INVPCID;
3651
3652 /* Enable VPID. */
3653 if (pVM->hm.s.vmx.fVpid)
3654 fVal |= VMX_PROC_CTLS2_VPID;
3655
3656 /* Enable unrestricted guest execution. */
3657 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3658 fVal |= VMX_PROC_CTLS2_UNRESTRICTED_GUEST;
3659
3660#if 0
3661 if (pVM->hm.s.fVirtApicRegs)
3662 {
3663 /* Enable APIC-register virtualization. */
3664 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_APIC_REG_VIRT);
3665 fVal |= VMX_PROC_CTLS2_APIC_REG_VIRT;
3666
3667 /* Enable virtual-interrupt delivery. */
3668 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_INTR_DELIVERY);
3669 fVal |= VMX_PROC_CTLS2_VIRT_INTR_DELIVERY;
3670 }
3671#endif
3672
3673 /* Virtualize-APIC accesses if supported by the CPU. The virtual-APIC page is
3674 where the TPR shadow resides. */
3675 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
3676 * done dynamically. */
3677 if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
3678 {
3679 fVal |= VMX_PROC_CTLS2_VIRT_APIC_ACCESS;
3680 hmR0VmxSetupVmcsApicAccessAddr(pVCpu);
3681 }
3682
3683 /* Enable the RDTSCP instruction if we expose it to the guest and is supported
3684 by the hardware. Without this, guest executing RDTSCP would cause a #UD. */
3685 if ( pVM->cpum.ro.GuestFeatures.fRdTscP
3686 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_RDTSCP))
3687 fVal |= VMX_PROC_CTLS2_RDTSCP;
3688
3689 /* Enable Pause-Loop exiting. */
3690 if ( (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)
3691 && pVM->hm.s.vmx.cPleGapTicks
3692 && pVM->hm.s.vmx.cPleWindowTicks)
3693 {
3694 fVal |= VMX_PROC_CTLS2_PAUSE_LOOP_EXIT;
3695
3696 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, pVM->hm.s.vmx.cPleGapTicks); AssertRC(rc);
3697 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, pVM->hm.s.vmx.cPleWindowTicks); AssertRC(rc);
3698 }
3699
3700 if ((fVal & fZap) != fVal)
3701 {
3702 LogRelFunc(("Invalid secondary processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3703 pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed0, fVal, fZap));
3704 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
3705 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3706 }
3707
3708 /* Commit it to the VMCS and update our cache. */
3709 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, fVal);
3710 AssertRC(rc);
3711 pVmcsInfo->u32ProcCtls2 = fVal;
3712
3713 return VINF_SUCCESS;
3714}
3715
3716
3717/**
3718 * Sets up processor-based VM-execution controls in the VMCS.
3719 *
3720 * @returns VBox status code.
3721 * @param pVCpu The cross context virtual CPU structure.
3722 * @param pVmcsInfo The VMCS info. object.
3723 */
3724static int hmR0VmxSetupVmcsProcCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3725{
3726 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3727
3728 uint32_t fVal = pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
3729 uint32_t const fZap = pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3730
3731 fVal |= VMX_PROC_CTLS_HLT_EXIT /* HLT causes a VM-exit. */
3732 | VMX_PROC_CTLS_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
3733 | VMX_PROC_CTLS_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
3734 | VMX_PROC_CTLS_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
3735 | VMX_PROC_CTLS_RDPMC_EXIT /* RDPMC causes a VM-exit. */
3736 | VMX_PROC_CTLS_MONITOR_EXIT /* MONITOR causes a VM-exit. */
3737 | VMX_PROC_CTLS_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
3738
3739 /* We toggle VMX_PROC_CTLS_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
3740 if ( !(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MOV_DR_EXIT)
3741 || (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0 & VMX_PROC_CTLS_MOV_DR_EXIT))
3742 {
3743 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
3744 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3745 }
3746
3747 /* Without nested paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
3748 if (!pVM->hm.s.fNestedPaging)
3749 {
3750 Assert(!pVM->hm.s.vmx.fUnrestrictedGuest);
3751 fVal |= VMX_PROC_CTLS_INVLPG_EXIT
3752 | VMX_PROC_CTLS_CR3_LOAD_EXIT
3753 | VMX_PROC_CTLS_CR3_STORE_EXIT;
3754 }
3755
3756 /* Use TPR shadowing if supported by the CPU. */
3757 if ( PDMHasApic(pVM)
3758 && pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW)
3759 {
3760 fVal |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
3761 /* CR8 writes cause a VM-exit based on TPR threshold. */
3762 Assert(!(fVal & VMX_PROC_CTLS_CR8_STORE_EXIT));
3763 Assert(!(fVal & VMX_PROC_CTLS_CR8_LOAD_EXIT));
3764 hmR0VmxSetupVmcsVirtApicAddr(pVmcsInfo);
3765 }
3766 else
3767 {
3768 /* Some 32-bit CPUs do not support CR8 load/store exiting as MOV CR8 is
3769 invalid on 32-bit Intel CPUs. Set this control only for 64-bit guests. */
3770 if (pVM->hm.s.fAllow64BitGuests)
3771 {
3772 fVal |= VMX_PROC_CTLS_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
3773 | VMX_PROC_CTLS_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
3774 }
3775 }
3776
3777 /* Use MSR-bitmaps if supported by the CPU. */
3778 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
3779 {
3780 fVal |= VMX_PROC_CTLS_USE_MSR_BITMAPS;
3781 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
3782 }
3783
3784 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
3785 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
3786 fVal |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
3787
3788 if ((fVal & fZap) != fVal)
3789 {
3790 LogRelFunc(("Invalid processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3791 pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0, fVal, fZap));
3792 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
3793 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3794 }
3795
3796 /* Commit it to the VMCS and update our cache. */
3797 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, fVal);
3798 AssertRC(rc);
3799 pVmcsInfo->u32ProcCtls = fVal;
3800
3801 /* Set up MSR permissions that don't change through the lifetime of the VM. */
3802 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
3803 hmR0VmxSetupVmcsMsrPermissions(pVCpu, pVmcsInfo);
3804
3805 /* Set up secondary processor-based VM-execution controls if the CPU supports it. */
3806 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
3807 return hmR0VmxSetupVmcsProcCtls2(pVCpu, pVmcsInfo);
3808
3809 /* Sanity check, should not really happen. */
3810 if (RT_LIKELY(!pVM->hm.s.vmx.fUnrestrictedGuest))
3811 { /* likely */ }
3812 else
3813 {
3814 pVCpu->hm.s.u32HMError = VMX_UFC_INVALID_UX_COMBO;
3815 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3816 }
3817
3818 /* Old CPUs without secondary processor-based VM-execution controls would end up here. */
3819 return VINF_SUCCESS;
3820}
3821
3822
3823/**
3824 * Sets up miscellaneous (everything other than Pin, Processor and secondary
3825 * Processor-based VM-execution) control fields in the VMCS.
3826 *
3827 * @returns VBox status code.
3828 * @param pVCpu The cross context virtual CPU structure.
3829 * @param pVmcsInfo The VMCS info. object.
3830 */
3831static int hmR0VmxSetupVmcsMiscCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3832{
3833#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3834 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
3835 {
3836 hmR0VmxSetupVmcsVmreadBitmapAddr(pVCpu);
3837 hmR0VmxSetupVmcsVmwriteBitmapAddr(pVCpu);
3838 }
3839#endif
3840
3841 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
3842 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
3843 AssertRC(rc);
3844
3845 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
3846 if (RT_SUCCESS(rc))
3847 {
3848 uint64_t const u64Cr0Mask = hmR0VmxGetFixedCr0Mask(pVCpu);
3849 uint64_t const u64Cr4Mask = hmR0VmxGetFixedCr4Mask(pVCpu);
3850
3851 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask); AssertRC(rc);
3852 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask); AssertRC(rc);
3853
3854 pVmcsInfo->u64Cr0Mask = u64Cr0Mask;
3855 pVmcsInfo->u64Cr4Mask = u64Cr4Mask;
3856 return VINF_SUCCESS;
3857 }
3858 else
3859 LogRelFunc(("Failed to initialize VMCS auto-load/store MSR addresses. rc=%Rrc\n", rc));
3860 return rc;
3861}
3862
3863
3864/**
3865 * Sets up the initial exception bitmap in the VMCS based on static conditions.
3866 *
3867 * We shall setup those exception intercepts that don't change during the
3868 * lifetime of the VM here. The rest are done dynamically while loading the
3869 * guest state.
3870 *
3871 * @param pVCpu The cross context virtual CPU structure.
3872 * @param pVmcsInfo The VMCS info. object.
3873 */
3874static void hmR0VmxSetupVmcsXcptBitmap(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3875{
3876 /*
3877 * The following exceptions are always intercepted:
3878 *
3879 * #AC - To prevent the guest from hanging the CPU.
3880 * #DB - To maintain the DR6 state even when intercepting DRx reads/writes and
3881 * recursive #DBs can cause a CPU hang.
3882 * #PF - To sync our shadow page tables when nested-paging is not used.
3883 */
3884 bool const fNestedPaging = pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging;
3885 uint32_t const uXcptBitmap = RT_BIT(X86_XCPT_AC)
3886 | RT_BIT(X86_XCPT_DB)
3887 | (fNestedPaging ? 0 : RT_BIT(X86_XCPT_PF));
3888
3889 /* Commit it to the VMCS. */
3890 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
3891 AssertRC(rc);
3892
3893 /* Update our cache of the exception bitmap. */
3894 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
3895}
3896
3897
3898#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3899/**
3900 * Sets up the VMCS for executing a nested-guest using hardware-assisted VMX.
3901 *
3902 * @returns VBox status code.
3903 * @param pVCpu The cross context virtual CPU structure.
3904 * @param pVmcsInfo The VMCS info. object.
3905 */
3906static int hmR0VmxSetupVmcsCtlsNested(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3907{
3908 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
3909 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
3910 AssertRC(rc);
3911
3912 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
3913 if (RT_SUCCESS(rc))
3914 {
3915 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
3916 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
3917 return VINF_SUCCESS;
3918 }
3919 else
3920 LogRelFunc(("Failed to set up the VMCS link pointer in the nested-guest VMCS. rc=%Rrc\n", rc));
3921 return rc;
3922}
3923#endif
3924
3925
3926/**
3927 * Sets up the VMCS for executing a guest (or nested-guest) using hardware-assisted
3928 * VMX.
3929 *
3930 * @returns VBox status code.
3931 * @param pVCpu The cross context virtual CPU structure.
3932 * @param pVmcsInfo The VMCS info. object.
3933 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
3934 */
3935static int hmR0VmxSetupVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
3936{
3937 Assert(pVmcsInfo->pvVmcs);
3938 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
3939
3940 /* Set the CPU specified revision identifier at the beginning of the VMCS structure. */
3941 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3942 *(uint32_t *)pVmcsInfo->pvVmcs = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
3943 const char * const pszVmcs = fIsNstGstVmcs ? "nested-guest VMCS" : "guest VMCS";
3944
3945 LogFlowFunc(("\n"));
3946
3947 /*
3948 * Initialize the VMCS using VMCLEAR before loading the VMCS.
3949 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
3950 */
3951 int rc = hmR0VmxClearVmcs(pVmcsInfo);
3952 if (RT_SUCCESS(rc))
3953 {
3954 rc = hmR0VmxLoadVmcs(pVmcsInfo);
3955 if (RT_SUCCESS(rc))
3956 {
3957 if (!fIsNstGstVmcs)
3958 {
3959 rc = hmR0VmxSetupVmcsPinCtls(pVCpu, pVmcsInfo);
3960 if (RT_SUCCESS(rc))
3961 {
3962 rc = hmR0VmxSetupVmcsProcCtls(pVCpu, pVmcsInfo);
3963 if (RT_SUCCESS(rc))
3964 {
3965 rc = hmR0VmxSetupVmcsMiscCtls(pVCpu, pVmcsInfo);
3966 if (RT_SUCCESS(rc))
3967 {
3968 hmR0VmxSetupVmcsXcptBitmap(pVCpu, pVmcsInfo);
3969#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3970 /*
3971 * If a shadow VMCS is allocated for the VMCS info. object, initialize the
3972 * VMCS revision ID and shadow VMCS indicator bit. Also, clear the VMCS
3973 * making it fit for use when VMCS shadowing is later enabled.
3974 */
3975 if (pVmcsInfo->pvShadowVmcs)
3976 {
3977 VMXVMCSREVID VmcsRevId;
3978 VmcsRevId.u = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
3979 VmcsRevId.n.fIsShadowVmcs = 1;
3980 *(uint32_t *)pVmcsInfo->pvShadowVmcs = VmcsRevId.u;
3981 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
3982 if (RT_SUCCESS(rc))
3983 { /* likely */ }
3984 else
3985 LogRelFunc(("Failed to initialize shadow VMCS. rc=%Rrc\n", rc));
3986 }
3987#endif
3988 }
3989 else
3990 LogRelFunc(("Failed to setup miscellaneous controls. rc=%Rrc\n", rc));
3991 }
3992 else
3993 LogRelFunc(("Failed to setup processor-based VM-execution controls. rc=%Rrc\n", rc));
3994 }
3995 else
3996 LogRelFunc(("Failed to setup pin-based controls. rc=%Rrc\n", rc));
3997 }
3998 else
3999 {
4000#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4001 rc = hmR0VmxSetupVmcsCtlsNested(pVCpu, pVmcsInfo);
4002 if (RT_SUCCESS(rc))
4003 { /* likely */ }
4004 else
4005 LogRelFunc(("Failed to initialize nested-guest VMCS. rc=%Rrc\n", rc));
4006#else
4007 AssertFailed();
4008#endif
4009 }
4010 }
4011 else
4012 LogRelFunc(("Failed to load the %s. rc=%Rrc\n", rc, pszVmcs));
4013 }
4014 else
4015 LogRelFunc(("Failed to clear the %s. rc=%Rrc\n", rc, pszVmcs));
4016
4017 /* Sync any CPU internal VMCS data back into our VMCS in memory. */
4018 if (RT_SUCCESS(rc))
4019 {
4020 rc = hmR0VmxClearVmcs(pVmcsInfo);
4021 if (RT_SUCCESS(rc))
4022 { /* likely */ }
4023 else
4024 LogRelFunc(("Failed to clear the %s post setup. rc=%Rrc\n", rc, pszVmcs));
4025 }
4026
4027 /*
4028 * Update the last-error record both for failures and success, so we
4029 * can propagate the status code back to ring-3 for diagnostics.
4030 */
4031 hmR0VmxUpdateErrorRecord(pVCpu, rc);
4032 NOREF(pszVmcs);
4033 return rc;
4034}
4035
4036
4037/**
4038 * Does global VT-x initialization (called during module initialization).
4039 *
4040 * @returns VBox status code.
4041 */
4042VMMR0DECL(int) VMXR0GlobalInit(void)
4043{
4044#ifdef HMVMX_USE_FUNCTION_TABLE
4045 AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(g_apfnVMExitHandlers));
4046# ifdef VBOX_STRICT
4047 for (unsigned i = 0; i < RT_ELEMENTS(g_apfnVMExitHandlers); i++)
4048 Assert(g_apfnVMExitHandlers[i]);
4049# endif
4050#endif
4051 return VINF_SUCCESS;
4052}
4053
4054
4055/**
4056 * Does global VT-x termination (called during module termination).
4057 */
4058VMMR0DECL(void) VMXR0GlobalTerm()
4059{
4060 /* Nothing to do currently. */
4061}
4062
4063
4064/**
4065 * Sets up and activates VT-x on the current CPU.
4066 *
4067 * @returns VBox status code.
4068 * @param pHostCpu The HM physical-CPU structure.
4069 * @param pVM The cross context VM structure. Can be
4070 * NULL after a host resume operation.
4071 * @param pvCpuPage Pointer to the VMXON region (can be NULL if @a
4072 * fEnabledByHost is @c true).
4073 * @param HCPhysCpuPage Physical address of the VMXON region (can be 0 if
4074 * @a fEnabledByHost is @c true).
4075 * @param fEnabledByHost Set if SUPR0EnableVTx() or similar was used to
4076 * enable VT-x on the host.
4077 * @param pHwvirtMsrs Pointer to the hardware-virtualization MSRs.
4078 */
4079VMMR0DECL(int) VMXR0EnableCpu(PHMPHYSCPU pHostCpu, PVMCC pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost,
4080 PCSUPHWVIRTMSRS pHwvirtMsrs)
4081{
4082 AssertPtr(pHostCpu);
4083 AssertPtr(pHwvirtMsrs);
4084 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4085
4086 /* Enable VT-x if it's not already enabled by the host. */
4087 if (!fEnabledByHost)
4088 {
4089 int rc = hmR0VmxEnterRootMode(pVM, HCPhysCpuPage, pvCpuPage);
4090 if (RT_FAILURE(rc))
4091 return rc;
4092 }
4093
4094 /*
4095 * Flush all EPT tagged-TLB entries (in case VirtualBox or any other hypervisor have been
4096 * using EPTPs) so we don't retain any stale guest-physical mappings which won't get
4097 * invalidated when flushing by VPID.
4098 */
4099 if (pHwvirtMsrs->u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
4100 {
4101 hmR0VmxFlushEpt(NULL /* pVCpu */, NULL /* pVmcsInfo */, VMXTLBFLUSHEPT_ALL_CONTEXTS);
4102 pHostCpu->fFlushAsidBeforeUse = false;
4103 }
4104 else
4105 pHostCpu->fFlushAsidBeforeUse = true;
4106
4107 /* Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}. */
4108 ++pHostCpu->cTlbFlushes;
4109
4110 return VINF_SUCCESS;
4111}
4112
4113
4114/**
4115 * Deactivates VT-x on the current CPU.
4116 *
4117 * @returns VBox status code.
4118 * @param pvCpuPage Pointer to the VMXON region.
4119 * @param HCPhysCpuPage Physical address of the VMXON region.
4120 *
4121 * @remarks This function should never be called when SUPR0EnableVTx() or
4122 * similar was used to enable VT-x on the host.
4123 */
4124VMMR0DECL(int) VMXR0DisableCpu(void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
4125{
4126 RT_NOREF2(pvCpuPage, HCPhysCpuPage);
4127
4128 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4129 return hmR0VmxLeaveRootMode();
4130}
4131
4132
4133/**
4134 * Does per-VM VT-x initialization.
4135 *
4136 * @returns VBox status code.
4137 * @param pVM The cross context VM structure.
4138 */
4139VMMR0DECL(int) VMXR0InitVM(PVMCC pVM)
4140{
4141 AssertPtr(pVM);
4142 LogFlowFunc(("pVM=%p\n", pVM));
4143
4144 int rc = hmR0VmxStructsAlloc(pVM);
4145 if (RT_FAILURE(rc))
4146 {
4147 LogRelFunc(("Failed to allocated VMX structures. rc=%Rrc\n", rc));
4148 return rc;
4149 }
4150
4151 return VINF_SUCCESS;
4152}
4153
4154
4155/**
4156 * Does per-VM VT-x termination.
4157 *
4158 * @returns VBox status code.
4159 * @param pVM The cross context VM structure.
4160 */
4161VMMR0DECL(int) VMXR0TermVM(PVMCC pVM)
4162{
4163 AssertPtr(pVM);
4164 LogFlowFunc(("pVM=%p\n", pVM));
4165
4166#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4167 if (pVM->hm.s.vmx.hMemObjScratch != NIL_RTR0MEMOBJ)
4168 {
4169 Assert(pVM->hm.s.vmx.pvScratch);
4170 ASMMemZero32(pVM->hm.s.vmx.pvScratch, X86_PAGE_4K_SIZE);
4171 }
4172#endif
4173 hmR0VmxStructsFree(pVM);
4174 return VINF_SUCCESS;
4175}
4176
4177
4178/**
4179 * Sets up the VM for execution using hardware-assisted VMX.
4180 * This function is only called once per-VM during initialization.
4181 *
4182 * @returns VBox status code.
4183 * @param pVM The cross context VM structure.
4184 */
4185VMMR0DECL(int) VMXR0SetupVM(PVMCC pVM)
4186{
4187 AssertPtr(pVM);
4188 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4189
4190 LogFlowFunc(("pVM=%p\n", pVM));
4191
4192 /*
4193 * At least verify if VMX is enabled, since we can't check if we're in
4194 * VMX root mode or not without causing a #GP.
4195 */
4196 RTCCUINTREG const uHostCr4 = ASMGetCR4();
4197 if (RT_LIKELY(uHostCr4 & X86_CR4_VMXE))
4198 { /* likely */ }
4199 else
4200 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
4201
4202 /*
4203 * Without unrestricted guest execution, pRealModeTSS and pNonPagingModeEPTPageTable *must*
4204 * always be allocated. We no longer support the highly unlikely case of unrestricted guest
4205 * without pRealModeTSS, see hmR3InitFinalizeR0Intel().
4206 */
4207 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
4208 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
4209 || !pVM->hm.s.vmx.pRealModeTSS))
4210 {
4211 LogRelFunc(("Invalid real-on-v86 state.\n"));
4212 return VERR_INTERNAL_ERROR;
4213 }
4214
4215 /* Initialize these always, see hmR3InitFinalizeR0().*/
4216 pVM->hm.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NONE;
4217 pVM->hm.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NONE;
4218
4219 /* Setup the tagged-TLB flush handlers. */
4220 int rc = hmR0VmxSetupTaggedTlb(pVM);
4221 if (RT_FAILURE(rc))
4222 {
4223 LogRelFunc(("Failed to setup tagged TLB. rc=%Rrc\n", rc));
4224 return rc;
4225 }
4226
4227#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4228 /* Setup the shadow VMCS fields array and VMREAD/VMWRITE bitmaps. */
4229 if (pVM->hm.s.vmx.fUseVmcsShadowing)
4230 {
4231 rc = hmR0VmxSetupShadowVmcsFieldsArrays(pVM);
4232 if (RT_SUCCESS(rc))
4233 hmR0VmxSetupVmreadVmwriteBitmaps(pVM);
4234 else
4235 {
4236 LogRelFunc(("Failed to setup shadow VMCS fields arrays. rc=%Rrc\n", rc));
4237 return rc;
4238 }
4239 }
4240#endif
4241
4242 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
4243 {
4244 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
4245 Log4Func(("pVCpu=%p idCpu=%RU32\n", pVCpu, pVCpu->idCpu));
4246
4247 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hm.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
4248 if (RT_SUCCESS(rc))
4249 {
4250#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4251 if (pVM->cpum.ro.GuestFeatures.fVmx)
4252 {
4253 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hm.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
4254 if (RT_SUCCESS(rc))
4255 { /* likely */ }
4256 else
4257 {
4258 LogRelFunc(("Nested-guest VMCS setup failed. rc=%Rrc\n", rc));
4259 return rc;
4260 }
4261 }
4262#endif
4263 }
4264 else
4265 {
4266 LogRelFunc(("VMCS setup failed. rc=%Rrc\n", rc));
4267 return rc;
4268 }
4269 }
4270
4271 return VINF_SUCCESS;
4272}
4273
4274
4275/**
4276 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
4277 * the VMCS.
4278 */
4279static void hmR0VmxExportHostControlRegs(void)
4280{
4281 int rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR0, ASMGetCR0()); AssertRC(rc);
4282 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR3, ASMGetCR3()); AssertRC(rc);
4283 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR4, ASMGetCR4()); AssertRC(rc);
4284}
4285
4286
4287/**
4288 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
4289 * the host-state area in the VMCS.
4290 *
4291 * @returns VBox status code.
4292 * @param pVCpu The cross context virtual CPU structure.
4293 */
4294static int hmR0VmxExportHostSegmentRegs(PVMCPUCC pVCpu)
4295{
4296/**
4297 * Macro for adjusting host segment selectors to satisfy VT-x's VM-entry
4298 * requirements. See hmR0VmxExportHostSegmentRegs().
4299 */
4300#define VMXLOCAL_ADJUST_HOST_SEG(a_Seg, a_selValue) \
4301 if ((a_selValue) & (X86_SEL_RPL | X86_SEL_LDT)) \
4302 { \
4303 bool fValidSelector = true; \
4304 if ((a_selValue) & X86_SEL_LDT) \
4305 { \
4306 uint32_t const uAttr = ASMGetSegAttr(a_selValue); \
4307 fValidSelector = RT_BOOL(uAttr != UINT32_MAX && (uAttr & X86_DESC_P)); \
4308 } \
4309 if (fValidSelector) \
4310 { \
4311 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4312 pVCpu->hm.s.vmx.RestoreHost.uHostSel##a_Seg = (a_selValue); \
4313 } \
4314 (a_selValue) = 0; \
4315 }
4316
4317 /*
4318 * If we've executed guest code using hardware-assisted VMX, the host-state bits
4319 * will be messed up. We should -not- save the messed up state without restoring
4320 * the original host-state, see @bugref{7240}.
4321 *
4322 * This apparently can happen (most likely the FPU changes), deal with it rather than
4323 * asserting. Was observed booting Solaris 10u10 32-bit guest.
4324 */
4325 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
4326 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
4327 {
4328 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags,
4329 pVCpu->idCpu));
4330 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
4331 }
4332 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
4333
4334 /*
4335 * Host segment registers.
4336 */
4337 RTSEL uSelES = ASMGetES();
4338 RTSEL uSelCS = ASMGetCS();
4339 RTSEL uSelSS = ASMGetSS();
4340 RTSEL uSelDS = ASMGetDS();
4341 RTSEL uSelFS = ASMGetFS();
4342 RTSEL uSelGS = ASMGetGS();
4343 RTSEL uSelTR = ASMGetTR();
4344
4345 /*
4346 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to
4347 * gain VM-entry and restore them before we get preempted.
4348 *
4349 * See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
4350 */
4351 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
4352 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
4353 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
4354 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
4355
4356 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
4357 Assert(!(uSelCS & X86_SEL_RPL)); Assert(!(uSelCS & X86_SEL_LDT));
4358 Assert(!(uSelSS & X86_SEL_RPL)); Assert(!(uSelSS & X86_SEL_LDT));
4359 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
4360 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
4361 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
4362 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
4363 Assert(!(uSelTR & X86_SEL_RPL)); Assert(!(uSelTR & X86_SEL_LDT));
4364 Assert(uSelCS);
4365 Assert(uSelTR);
4366
4367 /* Write these host selector fields into the host-state area in the VMCS. */
4368 int rc = VMXWriteVmcs16(VMX_VMCS16_HOST_CS_SEL, uSelCS); AssertRC(rc);
4369 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_SS_SEL, uSelSS); AssertRC(rc);
4370 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_DS_SEL, uSelDS); AssertRC(rc);
4371 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_ES_SEL, uSelES); AssertRC(rc);
4372 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_FS_SEL, uSelFS); AssertRC(rc);
4373 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_GS_SEL, uSelGS); AssertRC(rc);
4374 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_TR_SEL, uSelTR); AssertRC(rc);
4375
4376 /*
4377 * Host GDTR and IDTR.
4378 */
4379 RTGDTR Gdtr;
4380 RTIDTR Idtr;
4381 RT_ZERO(Gdtr);
4382 RT_ZERO(Idtr);
4383 ASMGetGDTR(&Gdtr);
4384 ASMGetIDTR(&Idtr);
4385 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GDTR_BASE, Gdtr.pGdt); AssertRC(rc);
4386 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_IDTR_BASE, Idtr.pIdt); AssertRC(rc);
4387
4388 /*
4389 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps
4390 * them to the maximum limit (0xffff) on every VM-exit.
4391 */
4392 if (Gdtr.cbGdt != 0xffff)
4393 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
4394
4395 /*
4396 * IDT limit is effectively capped at 0xfff. (See Intel spec. 6.14.1 "64-Bit Mode IDT" and
4397 * Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit
4398 * as 0xfff, VT-x bloating the limit to 0xffff shouldn't cause any different CPU behavior.
4399 * However, several hosts either insists on 0xfff being the limit (Windows Patch Guard) or
4400 * uses the limit for other purposes (darwin puts the CPU ID in there but botches sidt
4401 * alignment in at least one consumer). So, we're only allowing the IDTR.LIMIT to be left
4402 * at 0xffff on hosts where we are sure it won't cause trouble.
4403 */
4404#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
4405 if (Idtr.cbIdt < 0x0fff)
4406#else
4407 if (Idtr.cbIdt != 0xffff)
4408#endif
4409 {
4410 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
4411 AssertCompile(sizeof(Idtr) == sizeof(X86XDTR64));
4412 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostIdtr, &Idtr, sizeof(X86XDTR64));
4413 }
4414
4415 /*
4416 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI
4417 * and RPL bits is effectively what the CPU does for "scaling by 8". TI is always 0 and
4418 * RPL should be too in most cases.
4419 */
4420 AssertMsgReturn((uSelTR | X86_SEL_RPL_LDT) <= Gdtr.cbGdt,
4421 ("TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, Gdtr.cbGdt), VERR_VMX_INVALID_HOST_STATE);
4422
4423 PCX86DESCHC pDesc = (PCX86DESCHC)(Gdtr.pGdt + (uSelTR & X86_SEL_MASK));
4424 uintptr_t const uTRBase = X86DESC64_BASE(pDesc);
4425
4426 /*
4427 * VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on
4428 * all VM-exits. The type is the same for 64-bit busy TSS[1]. The limit needs manual
4429 * restoration if the host has something else. Task switching is not supported in 64-bit
4430 * mode[2], but the limit still matters as IOPM is supported in 64-bit mode. Restoring the
4431 * limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
4432 *
4433 * [1] See Intel spec. 3.5 "System Descriptor Types".
4434 * [2] See Intel spec. 7.2.3 "TSS Descriptor in 64-bit mode".
4435 */
4436 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4437 Assert(pDesc->System.u4Type == 11);
4438 if ( pDesc->System.u16LimitLow != 0x67
4439 || pDesc->System.u4LimitHigh)
4440 {
4441 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_TR;
4442 /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */
4443 if (pVM->hm.s.fHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY)
4444 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY;
4445 pVCpu->hm.s.vmx.RestoreHost.uHostSelTR = uSelTR;
4446 }
4447
4448 /*
4449 * Store the GDTR as we need it when restoring the GDT and while restoring the TR.
4450 */
4451 if (pVCpu->hm.s.vmx.fRestoreHostFlags & (VMX_RESTORE_HOST_GDTR | VMX_RESTORE_HOST_SEL_TR))
4452 {
4453 AssertCompile(sizeof(Gdtr) == sizeof(X86XDTR64));
4454 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
4455 if (pVM->hm.s.fHostKernelFeatures & SUPKERNELFEATURES_GDT_NEED_WRITABLE)
4456 {
4457 /* The GDT is read-only but the writable GDT is available. */
4458 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_NEED_WRITABLE;
4459 pVCpu->hm.s.vmx.RestoreHost.HostGdtrRw.cb = Gdtr.cbGdt;
4460 rc = SUPR0GetCurrentGdtRw(&pVCpu->hm.s.vmx.RestoreHost.HostGdtrRw.uAddr);
4461 AssertRCReturn(rc, rc);
4462 }
4463 }
4464
4465 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_TR_BASE, uTRBase);
4466 AssertRC(rc);
4467
4468 /*
4469 * Host FS base and GS base.
4470 */
4471 uint64_t const u64FSBase = ASMRdMsr(MSR_K8_FS_BASE);
4472 uint64_t const u64GSBase = ASMRdMsr(MSR_K8_GS_BASE);
4473 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_FS_BASE, u64FSBase); AssertRC(rc);
4474 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GS_BASE, u64GSBase); AssertRC(rc);
4475
4476 /* Store the base if we have to restore FS or GS manually as we need to restore the base as well. */
4477 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_FS)
4478 pVCpu->hm.s.vmx.RestoreHost.uHostFSBase = u64FSBase;
4479 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_GS)
4480 pVCpu->hm.s.vmx.RestoreHost.uHostGSBase = u64GSBase;
4481
4482 return VINF_SUCCESS;
4483#undef VMXLOCAL_ADJUST_HOST_SEG
4484}
4485
4486
4487/**
4488 * Exports certain host MSRs in the VM-exit MSR-load area and some in the
4489 * host-state area of the VMCS.
4490 *
4491 * These MSRs will be automatically restored on the host after every successful
4492 * VM-exit.
4493 *
4494 * @param pVCpu The cross context virtual CPU structure.
4495 *
4496 * @remarks No-long-jump zone!!!
4497 */
4498static void hmR0VmxExportHostMsrs(PVMCPUCC pVCpu)
4499{
4500 AssertPtr(pVCpu);
4501
4502 /*
4503 * Save MSRs that we restore lazily (due to preemption or transition to ring-3)
4504 * rather than swapping them on every VM-entry.
4505 */
4506 hmR0VmxLazySaveHostMsrs(pVCpu);
4507
4508 /*
4509 * Host Sysenter MSRs.
4510 */
4511 int rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS)); AssertRC(rc);
4512 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP)); AssertRC(rc);
4513 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP)); AssertRC(rc);
4514
4515 /*
4516 * Host EFER MSR.
4517 *
4518 * If the CPU supports the newer VMCS controls for managing EFER, use it. Otherwise it's
4519 * done as part of auto-load/store MSR area in the VMCS, see hmR0VmxExportGuestMsrs().
4520 */
4521 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4522 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
4523 {
4524 rc = VMXWriteVmcs64(VMX_VMCS64_HOST_EFER_FULL, pVM->hm.s.vmx.u64HostMsrEfer);
4525 AssertRC(rc);
4526 }
4527
4528 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT also see
4529 * hmR0VmxExportGuestEntryExitCtls(). */
4530}
4531
4532
4533/**
4534 * Figures out if we need to swap the EFER MSR which is particularly expensive.
4535 *
4536 * We check all relevant bits. For now, that's everything besides LMA/LME, as
4537 * these two bits are handled by VM-entry, see hmR0VMxExportGuestEntryExitCtls().
4538 *
4539 * @returns true if we need to load guest EFER, false otherwise.
4540 * @param pVCpu The cross context virtual CPU structure.
4541 *
4542 * @remarks Requires EFER, CR4.
4543 * @remarks No-long-jump zone!!!
4544 */
4545static bool hmR0VmxShouldSwapEferMsr(PCVMCPUCC pVCpu)
4546{
4547#ifdef HMVMX_ALWAYS_SWAP_EFER
4548 RT_NOREF(pVCpu);
4549 return true;
4550#else
4551 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4552 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4553 uint64_t const u64HostEfer = pVM->hm.s.vmx.u64HostMsrEfer;
4554 uint64_t const u64GuestEfer = pCtx->msrEFER;
4555
4556 /*
4557 * For 64-bit guests, if EFER.SCE bit differs, we need to swap the EFER MSR
4558 * to ensure that the guest's SYSCALL behaviour isn't broken, see @bugref{7386}.
4559 */
4560 if ( CPUMIsGuestInLongModeEx(pCtx)
4561 && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
4562 return true;
4563
4564 /*
4565 * If the guest uses PAE and EFER.NXE bit differs, we need to swap the EFER MSR
4566 * as it affects guest paging. 64-bit paging implies CR4.PAE as well.
4567 *
4568 * See Intel spec. 4.5 "IA-32e Paging".
4569 * See Intel spec. 4.1.1 "Three Paging Modes".
4570 *
4571 * Verify that we always intercept CR4.PAE and CR0.PG bits, so we don't need to
4572 * import CR4 and CR0 from the VMCS here as those bits are always up to date.
4573 */
4574 Assert(hmR0VmxGetFixedCr4Mask(pVCpu) & X86_CR4_PAE);
4575 Assert(hmR0VmxGetFixedCr0Mask(pVCpu) & X86_CR0_PG);
4576 if ( (pCtx->cr4 & X86_CR4_PAE)
4577 && (pCtx->cr0 & X86_CR0_PG)
4578 && (u64GuestEfer & MSR_K6_EFER_NXE) != (u64HostEfer & MSR_K6_EFER_NXE))
4579 {
4580 /* Assert that host is NX capable. */
4581 Assert(pVCpu->CTX_SUFF(pVM)->cpum.ro.HostFeatures.fNoExecute);
4582 return true;
4583 }
4584
4585 return false;
4586#endif
4587}
4588
4589/**
4590 * Exports the guest state with appropriate VM-entry and VM-exit controls in the
4591 * VMCS.
4592 *
4593 * This is typically required when the guest changes paging mode.
4594 *
4595 * @returns VBox status code.
4596 * @param pVCpu The cross context virtual CPU structure.
4597 * @param pVmxTransient The VMX-transient structure.
4598 *
4599 * @remarks Requires EFER.
4600 * @remarks No-long-jump zone!!!
4601 */
4602static int hmR0VmxExportGuestEntryExitCtls(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
4603{
4604 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS)
4605 {
4606 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4607 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4608
4609 /*
4610 * VM-entry controls.
4611 */
4612 {
4613 uint32_t fVal = pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
4614 uint32_t const fZap = pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
4615
4616 /*
4617 * Load the guest debug controls (DR7 and IA32_DEBUGCTL MSR) on VM-entry.
4618 * The first VT-x capable CPUs only supported the 1-setting of this bit.
4619 *
4620 * For nested-guests, this is a mandatory VM-entry control. It's also
4621 * required because we do not want to leak host bits to the nested-guest.
4622 */
4623 fVal |= VMX_ENTRY_CTLS_LOAD_DEBUG;
4624
4625 /*
4626 * Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry.
4627 *
4628 * For nested-guests, the "IA-32e mode guest" control we initialize with what is
4629 * required to get the nested-guest working with hardware-assisted VMX execution.
4630 * It depends on the nested-guest's IA32_EFER.LMA bit. Remember, a guest hypervisor
4631 * can skip intercepting changes to the EFER MSR. This is why it it needs to be done
4632 * here rather than while merging the guest VMCS controls.
4633 */
4634 if (CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
4635 fVal |= VMX_ENTRY_CTLS_IA32E_MODE_GUEST;
4636 else
4637 Assert(!(fVal & VMX_ENTRY_CTLS_IA32E_MODE_GUEST));
4638
4639 /*
4640 * If the CPU supports the newer VMCS controls for managing guest/host EFER, use it.
4641 *
4642 * For nested-guests, we use the "load IA32_EFER" if the hardware supports it,
4643 * regardless of whether the nested-guest VMCS specifies it because we are free to
4644 * load whatever MSRs we require and we do not need to modify the guest visible copy
4645 * of the VM-entry MSR load area.
4646 */
4647 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
4648 && hmR0VmxShouldSwapEferMsr(pVCpu))
4649 fVal |= VMX_ENTRY_CTLS_LOAD_EFER_MSR;
4650 else
4651 Assert(!(fVal & VMX_ENTRY_CTLS_LOAD_EFER_MSR));
4652
4653 /*
4654 * The following should -not- be set (since we're not in SMM mode):
4655 * - VMX_ENTRY_CTLS_ENTRY_TO_SMM
4656 * - VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON
4657 */
4658
4659 /** @todo VMX_ENTRY_CTLS_LOAD_PERF_MSR,
4660 * VMX_ENTRY_CTLS_LOAD_PAT_MSR. */
4661
4662 if ((fVal & fZap) == fVal)
4663 { /* likely */ }
4664 else
4665 {
4666 Log4Func(("Invalid VM-entry controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
4667 pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed0, fVal, fZap));
4668 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_ENTRY;
4669 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4670 }
4671
4672 /* Commit it to the VMCS. */
4673 if (pVmcsInfo->u32EntryCtls != fVal)
4674 {
4675 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, fVal);
4676 AssertRC(rc);
4677 pVmcsInfo->u32EntryCtls = fVal;
4678 }
4679 }
4680
4681 /*
4682 * VM-exit controls.
4683 */
4684 {
4685 uint32_t fVal = pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
4686 uint32_t const fZap = pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
4687
4688 /*
4689 * Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only
4690 * supported the 1-setting of this bit.
4691 *
4692 * For nested-guests, we set the "save debug controls" as the converse
4693 * "load debug controls" is mandatory for nested-guests anyway.
4694 */
4695 fVal |= VMX_EXIT_CTLS_SAVE_DEBUG;
4696
4697 /*
4698 * Set the host long mode active (EFER.LMA) bit (which Intel calls
4699 * "Host address-space size") if necessary. On VM-exit, VT-x sets both the
4700 * host EFER.LMA and EFER.LME bit to this value. See assertion in
4701 * hmR0VmxExportHostMsrs().
4702 *
4703 * For nested-guests, we always set this bit as we do not support 32-bit
4704 * hosts.
4705 */
4706 fVal |= VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE;
4707
4708 /*
4709 * If the VMCS EFER MSR fields are supported by the hardware, we use it.
4710 *
4711 * For nested-guests, we should use the "save IA32_EFER" control if we also
4712 * used the "load IA32_EFER" control while exporting VM-entry controls.
4713 */
4714 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
4715 && hmR0VmxShouldSwapEferMsr(pVCpu))
4716 {
4717 fVal |= VMX_EXIT_CTLS_SAVE_EFER_MSR
4718 | VMX_EXIT_CTLS_LOAD_EFER_MSR;
4719 }
4720
4721 /*
4722 * Enable saving of the VMX-preemption timer value on VM-exit.
4723 * For nested-guests, currently not exposed/used.
4724 */
4725 if ( pVM->hm.s.vmx.fUsePreemptTimer
4726 && (pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER))
4727 fVal |= VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER;
4728
4729 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
4730 Assert(!(fVal & VMX_EXIT_CTLS_ACK_EXT_INT));
4731
4732 /** @todo VMX_EXIT_CTLS_LOAD_PERF_MSR,
4733 * VMX_EXIT_CTLS_SAVE_PAT_MSR,
4734 * VMX_EXIT_CTLS_LOAD_PAT_MSR. */
4735
4736 if ((fVal & fZap) == fVal)
4737 { /* likely */ }
4738 else
4739 {
4740 Log4Func(("Invalid VM-exit controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%R#X32\n",
4741 pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed0, fVal, fZap));
4742 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_EXIT;
4743 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4744 }
4745
4746 /* Commit it to the VMCS. */
4747 if (pVmcsInfo->u32ExitCtls != fVal)
4748 {
4749 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, fVal);
4750 AssertRC(rc);
4751 pVmcsInfo->u32ExitCtls = fVal;
4752 }
4753 }
4754
4755 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
4756 }
4757 return VINF_SUCCESS;
4758}
4759
4760
4761/**
4762 * Sets the TPR threshold in the VMCS.
4763 *
4764 * @param pVmcsInfo The VMCS info. object.
4765 * @param u32TprThreshold The TPR threshold (task-priority class only).
4766 */
4767DECLINLINE(void) hmR0VmxApicSetTprThreshold(PVMXVMCSINFO pVmcsInfo, uint32_t u32TprThreshold)
4768{
4769 Assert(!(u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)); /* Bits 31:4 MBZ. */
4770 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
4771 RT_NOREF(pVmcsInfo);
4772 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
4773 AssertRC(rc);
4774}
4775
4776
4777/**
4778 * Exports the guest APIC TPR state into the VMCS.
4779 *
4780 * @returns VBox status code.
4781 * @param pVCpu The cross context virtual CPU structure.
4782 * @param pVmxTransient The VMX-transient structure.
4783 *
4784 * @remarks No-long-jump zone!!!
4785 */
4786static int hmR0VmxExportGuestApicTpr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
4787{
4788 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_APIC_TPR)
4789 {
4790 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
4791
4792 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4793 if (!pVmxTransient->fIsNestedGuest)
4794 {
4795 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
4796 && APICIsEnabled(pVCpu))
4797 {
4798 /*
4799 * Setup TPR shadowing.
4800 */
4801 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
4802 {
4803 bool fPendingIntr = false;
4804 uint8_t u8Tpr = 0;
4805 uint8_t u8PendingIntr = 0;
4806 int rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
4807 AssertRCReturn(rc, rc);
4808
4809 /*
4810 * If there are interrupts pending but masked by the TPR, instruct VT-x to
4811 * cause a TPR-below-threshold VM-exit when the guest lowers its TPR below the
4812 * priority of the pending interrupt so we can deliver the interrupt. If there
4813 * are no interrupts pending, set threshold to 0 to not cause any
4814 * TPR-below-threshold VM-exits.
4815 */
4816 uint32_t u32TprThreshold = 0;
4817 if (fPendingIntr)
4818 {
4819 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR
4820 (which is the Task-Priority Class). */
4821 const uint8_t u8PendingPriority = u8PendingIntr >> 4;
4822 const uint8_t u8TprPriority = u8Tpr >> 4;
4823 if (u8PendingPriority <= u8TprPriority)
4824 u32TprThreshold = u8PendingPriority;
4825 }
4826
4827 hmR0VmxApicSetTprThreshold(pVmcsInfo, u32TprThreshold);
4828 }
4829 }
4830 }
4831 /* else: the TPR threshold has already been updated while merging the nested-guest VMCS. */
4832 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
4833 }
4834 return VINF_SUCCESS;
4835}
4836
4837
4838/**
4839 * Gets the guest interruptibility-state.
4840 *
4841 * @returns Guest's interruptibility-state.
4842 * @param pVCpu The cross context virtual CPU structure.
4843 * @param pVmxTransient The VMX-transient structure.
4844 *
4845 * @remarks No-long-jump zone!!!
4846 */
4847static uint32_t hmR0VmxGetGuestIntrState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
4848{
4849 /*
4850 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
4851 */
4852 uint32_t fIntrState = 0;
4853 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
4854 {
4855 /* If inhibition is active, RIP and RFLAGS should've been imported from the VMCS already. */
4856 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
4857
4858 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4859 if (pCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
4860 {
4861 if (pCtx->eflags.Bits.u1IF)
4862 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
4863 else
4864 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS;
4865 }
4866 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
4867 {
4868 /*
4869 * We can clear the inhibit force flag as even if we go back to the recompiler
4870 * without executing guest code in VT-x, the flag's condition to be cleared is
4871 * met and thus the cleared state is correct.
4872 */
4873 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
4874 }
4875 }
4876
4877 /*
4878 * NMIs to the guest are blocked after an NMI is injected until the guest executes an IRET. We only
4879 * bother with virtual-NMI blocking when we have support for virtual NMIs in the CPU, otherwise
4880 * setting this would block host-NMIs and IRET will not clear the blocking.
4881 *
4882 * We always set NMI-exiting so when the host receives an NMI we get a VM-exit.
4883 *
4884 * See Intel spec. 26.6.1 "Interruptibility state". See @bugref{7445}.
4885 */
4886 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4887 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
4888 && CPUMIsGuestNmiBlocking(pVCpu))
4889 fIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
4890
4891 return fIntrState;
4892}
4893
4894
4895/**
4896 * Exports the exception intercepts required for guest execution in the VMCS.
4897 *
4898 * @returns VBox status code.
4899 * @param pVCpu The cross context virtual CPU structure.
4900 * @param pVmxTransient The VMX-transient structure.
4901 *
4902 * @remarks No-long-jump zone!!!
4903 */
4904static int hmR0VmxExportGuestXcptIntercepts(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
4905{
4906 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_XCPT_INTERCEPTS)
4907 {
4908 /* When executing a nested-guest, we do not need to trap GIM hypercalls by intercepting #UD. */
4909 if ( !pVmxTransient->fIsNestedGuest
4910 && pVCpu->hm.s.fGIMTrapXcptUD)
4911 hmR0VmxAddXcptIntercept(pVmxTransient, X86_XCPT_UD);
4912 else
4913 hmR0VmxRemoveXcptIntercept(pVCpu, pVmxTransient, X86_XCPT_UD);
4914
4915 /* Other exception intercepts are handled elsewhere, e.g. while exporting guest CR0. */
4916 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_XCPT_INTERCEPTS);
4917 }
4918 return VINF_SUCCESS;
4919}
4920
4921
4922/**
4923 * Exports the guest's RIP into the guest-state area in the VMCS.
4924 *
4925 * @returns VBox status code.
4926 * @param pVCpu The cross context virtual CPU structure.
4927 *
4928 * @remarks No-long-jump zone!!!
4929 */
4930static int hmR0VmxExportGuestRip(PVMCPUCC pVCpu)
4931{
4932 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RIP)
4933 {
4934 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP);
4935
4936 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RIP, pVCpu->cpum.GstCtx.rip);
4937 AssertRC(rc);
4938
4939 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RIP);
4940 Log4Func(("rip=%#RX64\n", pVCpu->cpum.GstCtx.rip));
4941 }
4942 return VINF_SUCCESS;
4943}
4944
4945
4946/**
4947 * Exports the guest's RSP into the guest-state area in the VMCS.
4948 *
4949 * @returns VBox status code.
4950 * @param pVCpu The cross context virtual CPU structure.
4951 *
4952 * @remarks No-long-jump zone!!!
4953 */
4954static int hmR0VmxExportGuestRsp(PVMCPUCC pVCpu)
4955{
4956 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RSP)
4957 {
4958 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RSP);
4959
4960 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RSP, pVCpu->cpum.GstCtx.rsp);
4961 AssertRC(rc);
4962
4963 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RSP);
4964 Log4Func(("rsp=%#RX64\n", pVCpu->cpum.GstCtx.rsp));
4965 }
4966 return VINF_SUCCESS;
4967}
4968
4969
4970/**
4971 * Exports the guest's RFLAGS into the guest-state area in the VMCS.
4972 *
4973 * @returns VBox status code.
4974 * @param pVCpu The cross context virtual CPU structure.
4975 * @param pVmxTransient The VMX-transient structure.
4976 *
4977 * @remarks No-long-jump zone!!!
4978 */
4979static int hmR0VmxExportGuestRflags(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
4980{
4981 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RFLAGS)
4982 {
4983 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
4984
4985 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
4986 Let us assert it as such and use 32-bit VMWRITE. */
4987 Assert(!RT_HI_U32(pVCpu->cpum.GstCtx.rflags.u64));
4988 X86EFLAGS fEFlags = pVCpu->cpum.GstCtx.eflags;
4989 Assert(fEFlags.u32 & X86_EFL_RA1_MASK);
4990 Assert(!(fEFlags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
4991
4992 /*
4993 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so
4994 * we can restore them on VM-exit. Modify the real-mode guest's eflags so that VT-x
4995 * can run the real-mode guest code under Virtual 8086 mode.
4996 */
4997 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
4998 if (pVmcsInfo->RealMode.fRealOnV86Active)
4999 {
5000 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
5001 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
5002 Assert(!pVmxTransient->fIsNestedGuest);
5003 pVmcsInfo->RealMode.Eflags.u32 = fEFlags.u32; /* Save the original eflags of the real-mode guest. */
5004 fEFlags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
5005 fEFlags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
5006 }
5007
5008 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RFLAGS, fEFlags.u32);
5009 AssertRC(rc);
5010
5011 /*
5012 * Setup pending debug exceptions if the guest is single-stepping using EFLAGS.TF.
5013 *
5014 * We must avoid setting any automatic debug exceptions delivery when single-stepping
5015 * through the hypervisor debugger using EFLAGS.TF.
5016 */
5017 if ( !pVmxTransient->fIsNestedGuest
5018 && !pVCpu->hm.s.fSingleInstruction
5019 && fEFlags.Bits.u1TF)
5020 {
5021 /** @todo r=ramshankar: Warning!! We ASSUME EFLAGS.TF will not cleared on
5022 * premature trips to ring-3 esp since IEM does not yet handle it. */
5023 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS);
5024 AssertRC(rc);
5025 }
5026 /* else: for nested-guest currently handling while merging controls. */
5027
5028 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RFLAGS);
5029 Log4Func(("eflags=%#RX32\n", fEFlags.u32));
5030 }
5031 return VINF_SUCCESS;
5032}
5033
5034
5035#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5036/**
5037 * Copies the nested-guest VMCS to the shadow VMCS.
5038 *
5039 * @returns VBox status code.
5040 * @param pVCpu The cross context virtual CPU structure.
5041 * @param pVmcsInfo The VMCS info. object.
5042 *
5043 * @remarks No-long-jump zone!!!
5044 */
5045static int hmR0VmxCopyNstGstToShadowVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5046{
5047 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5048 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5049
5050 /*
5051 * Disable interrupts so we don't get preempted while the shadow VMCS is the
5052 * current VMCS, as we may try saving guest lazy MSRs.
5053 *
5054 * Strictly speaking the lazy MSRs are not in the VMCS, but I'd rather not risk
5055 * calling the import VMCS code which is currently performing the guest MSR reads
5056 * (on 64-bit hosts) and accessing the auto-load/store MSR area on 32-bit hosts
5057 * and the rest of the VMX leave session machinery.
5058 */
5059 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
5060
5061 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5062 if (RT_SUCCESS(rc))
5063 {
5064 /*
5065 * Copy all guest read/write VMCS fields.
5066 *
5067 * We don't check for VMWRITE failures here for performance reasons and
5068 * because they are not expected to fail, barring irrecoverable conditions
5069 * like hardware errors.
5070 */
5071 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
5072 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5073 {
5074 uint64_t u64Val;
5075 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
5076 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5077 VMXWriteVmcs64(uVmcsField, u64Val);
5078 }
5079
5080 /*
5081 * If the host CPU supports writing all VMCS fields, copy the guest read-only
5082 * VMCS fields, so the guest can VMREAD them without causing a VM-exit.
5083 */
5084 if (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL)
5085 {
5086 uint32_t const cShadowVmcsRoFields = pVM->hm.s.vmx.cShadowVmcsRoFields;
5087 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
5088 {
5089 uint64_t u64Val;
5090 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsRoFields[i];
5091 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5092 VMXWriteVmcs64(uVmcsField, u64Val);
5093 }
5094 }
5095
5096 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5097 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5098 }
5099
5100 ASMSetFlags(fEFlags);
5101 return rc;
5102}
5103
5104
5105/**
5106 * Copies the shadow VMCS to the nested-guest VMCS.
5107 *
5108 * @returns VBox status code.
5109 * @param pVCpu The cross context virtual CPU structure.
5110 * @param pVmcsInfo The VMCS info. object.
5111 *
5112 * @remarks Called with interrupts disabled.
5113 */
5114static int hmR0VmxCopyShadowToNstGstVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5115{
5116 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5117 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5118 PVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5119
5120 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5121 if (RT_SUCCESS(rc))
5122 {
5123 /*
5124 * Copy guest read/write fields from the shadow VMCS.
5125 * Guest read-only fields cannot be modified, so no need to copy them.
5126 *
5127 * We don't check for VMREAD failures here for performance reasons and
5128 * because they are not expected to fail, barring irrecoverable conditions
5129 * like hardware errors.
5130 */
5131 uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
5132 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5133 {
5134 uint64_t u64Val;
5135 uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
5136 VMXReadVmcs64(uVmcsField, &u64Val);
5137 IEMWriteVmxVmcsField(pVmcsNstGst, uVmcsField, u64Val);
5138 }
5139
5140 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5141 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5142 }
5143 return rc;
5144}
5145
5146
5147/**
5148 * Enables VMCS shadowing for the given VMCS info. object.
5149 *
5150 * @param pVmcsInfo The VMCS info. object.
5151 *
5152 * @remarks No-long-jump zone!!!
5153 */
5154static void hmR0VmxEnableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5155{
5156 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5157 if (!(uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING))
5158 {
5159 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
5160 uProcCtls2 |= VMX_PROC_CTLS2_VMCS_SHADOWING;
5161 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5162 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, pVmcsInfo->HCPhysShadowVmcs); AssertRC(rc);
5163 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5164 pVmcsInfo->u64VmcsLinkPtr = pVmcsInfo->HCPhysShadowVmcs;
5165 Log4Func(("Enabled\n"));
5166 }
5167}
5168
5169
5170/**
5171 * Disables VMCS shadowing for the given VMCS info. object.
5172 *
5173 * @param pVmcsInfo The VMCS info. object.
5174 *
5175 * @remarks No-long-jump zone!!!
5176 */
5177static void hmR0VmxDisableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5178{
5179 /*
5180 * We want all VMREAD and VMWRITE instructions to cause VM-exits, so we clear the
5181 * VMCS shadowing control. However, VM-entry requires the shadow VMCS indicator bit
5182 * to match the VMCS shadowing control if the VMCS link pointer is not NIL_RTHCPHYS.
5183 * Hence, we must also reset the VMCS link pointer to ensure VM-entry does not fail.
5184 *
5185 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
5186 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5187 */
5188 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5189 if (uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
5190 {
5191 uProcCtls2 &= ~VMX_PROC_CTLS2_VMCS_SHADOWING;
5192 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5193 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS); AssertRC(rc);
5194 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5195 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
5196 Log4Func(("Disabled\n"));
5197 }
5198}
5199#endif
5200
5201
5202/**
5203 * Exports the guest hardware-virtualization state.
5204 *
5205 * @returns VBox status code.
5206 * @param pVCpu The cross context virtual CPU structure.
5207 * @param pVmxTransient The VMX-transient structure.
5208 *
5209 * @remarks No-long-jump zone!!!
5210 */
5211static int hmR0VmxExportGuestHwvirtState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
5212{
5213 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_HWVIRT)
5214 {
5215#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5216 /*
5217 * Check if the VMX feature is exposed to the guest and if the host CPU supports
5218 * VMCS shadowing.
5219 */
5220 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
5221 {
5222 /*
5223 * If the guest hypervisor has loaded a current VMCS and is in VMX root mode,
5224 * copy the guest hypervisor's current VMCS into the shadow VMCS and enable
5225 * VMCS shadowing to skip intercepting some or all VMREAD/VMWRITE VM-exits.
5226 *
5227 * We check for VMX root mode here in case the guest executes VMXOFF without
5228 * clearing the current VMCS pointer and our VMXOFF instruction emulation does
5229 * not clear the current VMCS pointer.
5230 */
5231 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5232 if ( CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx)
5233 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx)
5234 && CPUMIsGuestVmxCurrentVmcsValid(pVCpu, &pVCpu->cpum.GstCtx))
5235 {
5236 /* Paranoia. */
5237 Assert(!pVmxTransient->fIsNestedGuest);
5238
5239 /*
5240 * For performance reasons, also check if the guest hypervisor's current VMCS
5241 * was newly loaded or modified before copying it to the shadow VMCS.
5242 */
5243 if (!pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs)
5244 {
5245 int rc = hmR0VmxCopyNstGstToShadowVmcs(pVCpu, pVmcsInfo);
5246 AssertRCReturn(rc, rc);
5247 pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs = true;
5248 }
5249 hmR0VmxEnableVmcsShadowing(pVmcsInfo);
5250 }
5251 else
5252 hmR0VmxDisableVmcsShadowing(pVmcsInfo);
5253 }
5254#else
5255 NOREF(pVmxTransient);
5256#endif
5257 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_HWVIRT);
5258 }
5259 return VINF_SUCCESS;
5260}
5261
5262
5263/**
5264 * Exports the guest CR0 control register into the guest-state area in the VMCS.
5265 *
5266 * The guest FPU state is always pre-loaded hence we don't need to bother about
5267 * sharing FPU related CR0 bits between the guest and host.
5268 *
5269 * @returns VBox status code.
5270 * @param pVCpu The cross context virtual CPU structure.
5271 * @param pVmxTransient The VMX-transient structure.
5272 *
5273 * @remarks No-long-jump zone!!!
5274 */
5275static int hmR0VmxExportGuestCR0(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
5276{
5277 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR0)
5278 {
5279 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5280 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5281
5282 /*
5283 * Figure out fixed CR0 bits in VMX operation.
5284 */
5285 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
5286 uint64_t fSetCr0 = pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1;
5287 uint64_t const fZapCr0 = pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1;
5288 if (pVM->hm.s.vmx.fUnrestrictedGuest)
5289 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
5290 else
5291 Assert((fSetCr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
5292
5293 if (!pVmxTransient->fIsNestedGuest)
5294 {
5295 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5296 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5297 uint64_t const u64ShadowCr0 = u64GuestCr0;
5298 Assert(!RT_HI_U32(u64GuestCr0));
5299
5300 /*
5301 * Setup VT-x's view of the guest CR0.
5302 */
5303 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5304 if (pVM->hm.s.fNestedPaging)
5305 {
5306 if (CPUMIsGuestPagingEnabled(pVCpu))
5307 {
5308 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
5309 uProcCtls &= ~( VMX_PROC_CTLS_CR3_LOAD_EXIT
5310 | VMX_PROC_CTLS_CR3_STORE_EXIT);
5311 }
5312 else
5313 {
5314 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
5315 uProcCtls |= VMX_PROC_CTLS_CR3_LOAD_EXIT
5316 | VMX_PROC_CTLS_CR3_STORE_EXIT;
5317 }
5318
5319 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
5320 if (pVM->hm.s.vmx.fUnrestrictedGuest)
5321 uProcCtls &= ~VMX_PROC_CTLS_CR3_STORE_EXIT;
5322 }
5323 else
5324 {
5325 /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
5326 u64GuestCr0 |= X86_CR0_WP;
5327 }
5328
5329 /*
5330 * Guest FPU bits.
5331 *
5332 * Since we pre-load the guest FPU always before VM-entry there is no need to track lazy state
5333 * using CR0.TS.
5334 *
5335 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be
5336 * set on the first CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
5337 */
5338 u64GuestCr0 |= X86_CR0_NE;
5339
5340 /* If CR0.NE isn't set, we need to intercept #MF exceptions and report them to the guest differently. */
5341 bool const fInterceptMF = !(u64ShadowCr0 & X86_CR0_NE);
5342
5343 /*
5344 * Update exception intercepts.
5345 */
5346 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
5347 if (pVmcsInfo->RealMode.fRealOnV86Active)
5348 {
5349 Assert(PDMVmmDevHeapIsEnabled(pVM));
5350 Assert(pVM->hm.s.vmx.pRealModeTSS);
5351 uXcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
5352 }
5353 else
5354 {
5355 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
5356 uXcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
5357 if (fInterceptMF)
5358 uXcptBitmap |= RT_BIT(X86_XCPT_MF);
5359 }
5360
5361 /* Additional intercepts for debugging, define these yourself explicitly. */
5362#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
5363 uXcptBitmap |= 0
5364 | RT_BIT(X86_XCPT_BP)
5365 | RT_BIT(X86_XCPT_DE)
5366 | RT_BIT(X86_XCPT_NM)
5367 | RT_BIT(X86_XCPT_TS)
5368 | RT_BIT(X86_XCPT_UD)
5369 | RT_BIT(X86_XCPT_NP)
5370 | RT_BIT(X86_XCPT_SS)
5371 | RT_BIT(X86_XCPT_GP)
5372 | RT_BIT(X86_XCPT_PF)
5373 | RT_BIT(X86_XCPT_MF)
5374 ;
5375#elif defined(HMVMX_ALWAYS_TRAP_PF)
5376 uXcptBitmap |= RT_BIT(X86_XCPT_PF);
5377#endif
5378 if (pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv)
5379 uXcptBitmap |= RT_BIT(X86_XCPT_GP);
5380 Assert(pVM->hm.s.fNestedPaging || (uXcptBitmap & RT_BIT(X86_XCPT_PF)));
5381
5382 /* Apply the hardware specified fixed CR0 bits and enable caching. */
5383 u64GuestCr0 |= fSetCr0;
5384 u64GuestCr0 &= fZapCr0;
5385 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5386
5387 /* Commit the CR0 and related fields to the guest VMCS. */
5388 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5389 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5390 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5391 {
5392 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5393 AssertRC(rc);
5394 }
5395 if (uXcptBitmap != pVmcsInfo->u32XcptBitmap)
5396 {
5397 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
5398 AssertRC(rc);
5399 }
5400
5401 /* Update our caches. */
5402 pVmcsInfo->u32ProcCtls = uProcCtls;
5403 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
5404
5405 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5406 }
5407 else
5408 {
5409 /*
5410 * With nested-guests, we may have extended the guest/host mask here since we
5411 * merged in the outer guest's mask. Thus, the merged mask can include more bits
5412 * (to read from the nested-guest CR0 read-shadow) than the guest hypervisor
5413 * originally supplied. We must copy those bits from the nested-guest CR0 into
5414 * the nested-guest CR0 read-shadow.
5415 */
5416 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5417 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5418 uint64_t const u64ShadowCr0 = CPUMGetGuestVmxMaskedCr0(pVCpu, &pVCpu->cpum.GstCtx, pVmcsInfo->u64Cr0Mask);
5419 Assert(!RT_HI_U32(u64GuestCr0));
5420 Assert(u64GuestCr0 & X86_CR0_NE);
5421
5422 /*
5423 * Apply the hardware specified fixed CR0 bits and enable caching.
5424 * Note! We could be altering our VMX emulation's fixed bits. We thus
5425 * need to re-apply them while importing CR0.
5426 */
5427 u64GuestCr0 |= fSetCr0;
5428 u64GuestCr0 &= fZapCr0;
5429 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5430
5431 /* Commit the CR0 and CR0 read-shadow to the nested-guest VMCS. */
5432 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5433 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5434
5435 Log4Func(("cr0=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5436 }
5437
5438 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR0);
5439 }
5440
5441 return VINF_SUCCESS;
5442}
5443
5444
5445/**
5446 * Exports the guest control registers (CR3, CR4) into the guest-state area
5447 * in the VMCS.
5448 *
5449 * @returns VBox strict status code.
5450 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
5451 * without unrestricted guest access and the VMMDev is not presently
5452 * mapped (e.g. EFI32).
5453 *
5454 * @param pVCpu The cross context virtual CPU structure.
5455 * @param pVmxTransient The VMX-transient structure.
5456 *
5457 * @remarks No-long-jump zone!!!
5458 */
5459static VBOXSTRICTRC hmR0VmxExportGuestCR3AndCR4(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
5460{
5461 int rc = VINF_SUCCESS;
5462 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5463
5464 /*
5465 * Guest CR2.
5466 * It's always loaded in the assembler code. Nothing to do here.
5467 */
5468
5469 /*
5470 * Guest CR3.
5471 */
5472 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR3)
5473 {
5474 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
5475
5476 if (pVM->hm.s.fNestedPaging)
5477 {
5478 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5479 pVmcsInfo->HCPhysEPTP = PGMGetHyperCR3(pVCpu);
5480
5481 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
5482 Assert(pVmcsInfo->HCPhysEPTP != NIL_RTHCPHYS);
5483 Assert(!(pVmcsInfo->HCPhysEPTP & UINT64_C(0xfff0000000000000)));
5484 Assert(!(pVmcsInfo->HCPhysEPTP & 0xfff));
5485
5486 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
5487 pVmcsInfo->HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
5488 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
5489
5490 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
5491 AssertMsg( ((pVmcsInfo->HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
5492 && ((pVmcsInfo->HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
5493 ("EPTP %#RX64\n", pVmcsInfo->HCPhysEPTP));
5494 AssertMsg( !((pVmcsInfo->HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
5495 || (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
5496 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVmcsInfo->HCPhysEPTP));
5497
5498 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVmcsInfo->HCPhysEPTP);
5499 AssertRC(rc);
5500
5501 uint64_t u64GuestCr3;
5502 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5503 if ( pVM->hm.s.vmx.fUnrestrictedGuest
5504 || CPUMIsGuestPagingEnabledEx(pCtx))
5505 {
5506 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
5507 if (CPUMIsGuestInPAEModeEx(pCtx))
5508 {
5509 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
5510 AssertRC(rc);
5511 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
5512 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
5513 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
5514 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
5515 }
5516
5517 /*
5518 * The guest's view of its CR3 is unblemished with nested paging when the
5519 * guest is using paging or we have unrestricted guest execution to handle
5520 * the guest when it's not using paging.
5521 */
5522 u64GuestCr3 = pCtx->cr3;
5523 }
5524 else
5525 {
5526 /*
5527 * The guest is not using paging, but the CPU (VT-x) has to. While the guest
5528 * thinks it accesses physical memory directly, we use our identity-mapped
5529 * page table to map guest-linear to guest-physical addresses. EPT takes care
5530 * of translating it to host-physical addresses.
5531 */
5532 RTGCPHYS GCPhys;
5533 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
5534
5535 /* We obtain it here every time as the guest could have relocated this PCI region. */
5536 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
5537 if (RT_SUCCESS(rc))
5538 { /* likely */ }
5539 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
5540 {
5541 Log4Func(("VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n"));
5542 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
5543 }
5544 else
5545 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
5546
5547 u64GuestCr3 = GCPhys;
5548 }
5549
5550 Log4Func(("guest_cr3=%#RX64 (GstN)\n", u64GuestCr3));
5551 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, u64GuestCr3);
5552 AssertRC(rc);
5553 }
5554 else
5555 {
5556 Assert(!pVmxTransient->fIsNestedGuest);
5557 /* Non-nested paging case, just use the hypervisor's CR3. */
5558 RTHCPHYS const HCPhysGuestCr3 = PGMGetHyperCR3(pVCpu);
5559
5560 Log4Func(("guest_cr3=%#RX64 (HstN)\n", HCPhysGuestCr3));
5561 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, HCPhysGuestCr3);
5562 AssertRC(rc);
5563 }
5564
5565 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR3);
5566 }
5567
5568 /*
5569 * Guest CR4.
5570 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
5571 */
5572 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR4)
5573 {
5574 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5575 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5576
5577 /*
5578 * Figure out fixed CR4 bits in VMX operation.
5579 */
5580 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
5581 uint64_t const fSetCr4 = pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1;
5582 uint64_t const fZapCr4 = pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1;
5583
5584 /*
5585 * With nested-guests, we may have extended the guest/host mask here (since we
5586 * merged in the outer guest's mask, see hmR0VmxMergeVmcsNested). This means, the
5587 * mask can include more bits (to read from the nested-guest CR4 read-shadow) than
5588 * the guest hypervisor originally supplied. Thus, we should, in essence, copy
5589 * those bits from the nested-guest CR4 into the nested-guest CR4 read-shadow.
5590 */
5591 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
5592 uint64_t u64GuestCr4 = pCtx->cr4;
5593 uint64_t const u64ShadowCr4 = !pVmxTransient->fIsNestedGuest
5594 ? pCtx->cr4
5595 : CPUMGetGuestVmxMaskedCr4(pVCpu, pCtx, pVmcsInfo->u64Cr4Mask);
5596 Assert(!RT_HI_U32(u64GuestCr4));
5597
5598 /*
5599 * Setup VT-x's view of the guest CR4.
5600 *
5601 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software
5602 * interrupts to the 8086 program interrupt handler. Clear the VME bit (the interrupt
5603 * redirection bitmap is already all 0, see hmR3InitFinalizeR0())
5604 *
5605 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
5606 */
5607 if (pVmcsInfo->RealMode.fRealOnV86Active)
5608 {
5609 Assert(pVM->hm.s.vmx.pRealModeTSS);
5610 Assert(PDMVmmDevHeapIsEnabled(pVM));
5611 u64GuestCr4 &= ~(uint64_t)X86_CR4_VME;
5612 }
5613
5614 if (pVM->hm.s.fNestedPaging)
5615 {
5616 if ( !CPUMIsGuestPagingEnabledEx(pCtx)
5617 && !pVM->hm.s.vmx.fUnrestrictedGuest)
5618 {
5619 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
5620 u64GuestCr4 |= X86_CR4_PSE;
5621 /* Our identity mapping is a 32-bit page directory. */
5622 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5623 }
5624 /* else use guest CR4.*/
5625 }
5626 else
5627 {
5628 Assert(!pVmxTransient->fIsNestedGuest);
5629
5630 /*
5631 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
5632 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
5633 */
5634 switch (pVCpu->hm.s.enmShadowMode)
5635 {
5636 case PGMMODE_REAL: /* Real-mode. */
5637 case PGMMODE_PROTECTED: /* Protected mode without paging. */
5638 case PGMMODE_32_BIT: /* 32-bit paging. */
5639 {
5640 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5641 break;
5642 }
5643
5644 case PGMMODE_PAE: /* PAE paging. */
5645 case PGMMODE_PAE_NX: /* PAE paging with NX. */
5646 {
5647 u64GuestCr4 |= X86_CR4_PAE;
5648 break;
5649 }
5650
5651 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
5652 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
5653#ifdef VBOX_WITH_64_BITS_GUESTS
5654 break;
5655#endif
5656 default:
5657 AssertFailed();
5658 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
5659 }
5660 }
5661
5662 /*
5663 * Apply the hardware specified fixed CR4 bits (mainly CR4.VMXE).
5664 * Note! For nested-guests, we could be altering our VMX emulation's
5665 * fixed bits. We thus need to re-apply them while importing CR4.
5666 */
5667 u64GuestCr4 |= fSetCr4;
5668 u64GuestCr4 &= fZapCr4;
5669
5670 /* Commit the CR4 and CR4 read-shadow to the guest VMCS. */
5671 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR4, u64GuestCr4); AssertRC(rc);
5672 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, u64ShadowCr4); AssertRC(rc);
5673
5674 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
5675 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
5676
5677 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR4);
5678
5679 Log4Func(("cr4=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr4, u64ShadowCr4, fSetCr4, fZapCr4));
5680 }
5681 return rc;
5682}
5683
5684
5685/**
5686 * Exports the guest debug registers into the guest-state area in the VMCS.
5687 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
5688 *
5689 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
5690 *
5691 * @returns VBox status code.
5692 * @param pVCpu The cross context virtual CPU structure.
5693 * @param pVmxTransient The VMX-transient structure.
5694 *
5695 * @remarks No-long-jump zone!!!
5696 */
5697static int hmR0VmxExportSharedDebugState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
5698{
5699 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5700
5701 /** @todo NSTVMX: Figure out what we want to do with nested-guest instruction
5702 * stepping. */
5703 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5704 if (pVmxTransient->fIsNestedGuest)
5705 {
5706 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, CPUMGetGuestDR7(pVCpu));
5707 AssertRC(rc);
5708
5709 /* Always intercept Mov DRx accesses for the nested-guest for now. */
5710 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
5711 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
5712 AssertRC(rc);
5713 return VINF_SUCCESS;
5714 }
5715
5716#ifdef VBOX_STRICT
5717 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
5718 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
5719 {
5720 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
5721 Assert((pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0);
5722 Assert((pVCpu->cpum.GstCtx.dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK);
5723 }
5724#endif
5725
5726 bool fSteppingDB = false;
5727 bool fInterceptMovDRx = false;
5728 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5729 if (pVCpu->hm.s.fSingleInstruction)
5730 {
5731 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
5732 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5733 if (pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
5734 {
5735 uProcCtls |= VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
5736 Assert(fSteppingDB == false);
5737 }
5738 else
5739 {
5740 pVCpu->cpum.GstCtx.eflags.u32 |= X86_EFL_TF;
5741 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_RFLAGS;
5742 pVCpu->hm.s.fClearTrapFlag = true;
5743 fSteppingDB = true;
5744 }
5745 }
5746
5747 uint64_t u64GuestDr7;
5748 if ( fSteppingDB
5749 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
5750 {
5751 /*
5752 * Use the combined guest and host DRx values found in the hypervisor register set
5753 * because the hypervisor debugger has breakpoints active or someone is single stepping
5754 * on the host side without a monitor trap flag.
5755 *
5756 * Note! DBGF expects a clean DR6 state before executing guest code.
5757 */
5758 if (!CPUMIsHyperDebugStateActive(pVCpu))
5759 {
5760 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
5761 Assert(CPUMIsHyperDebugStateActive(pVCpu));
5762 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
5763 }
5764
5765 /* Update DR7 with the hypervisor value (other DRx registers are handled by CPUM one way or another). */
5766 u64GuestDr7 = CPUMGetHyperDR7(pVCpu);
5767 pVCpu->hm.s.fUsingHyperDR7 = true;
5768 fInterceptMovDRx = true;
5769 }
5770 else
5771 {
5772 /*
5773 * If the guest has enabled debug registers, we need to load them prior to
5774 * executing guest code so they'll trigger at the right time.
5775 */
5776 if (pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
5777 {
5778 if (!CPUMIsGuestDebugStateActive(pVCpu))
5779 {
5780 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
5781 Assert(CPUMIsGuestDebugStateActive(pVCpu));
5782 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
5783 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
5784 }
5785 Assert(!fInterceptMovDRx);
5786 }
5787 else if (!CPUMIsGuestDebugStateActive(pVCpu))
5788 {
5789 /*
5790 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
5791 * must intercept #DB in order to maintain a correct DR6 guest value, and
5792 * because we need to intercept it to prevent nested #DBs from hanging the
5793 * CPU, we end up always having to intercept it. See hmR0VmxSetupVmcsXcptBitmap().
5794 */
5795 fInterceptMovDRx = true;
5796 }
5797
5798 /* Update DR7 with the actual guest value. */
5799 u64GuestDr7 = pVCpu->cpum.GstCtx.dr[7];
5800 pVCpu->hm.s.fUsingHyperDR7 = false;
5801 }
5802
5803 if (fInterceptMovDRx)
5804 uProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
5805 else
5806 uProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
5807
5808 /*
5809 * Update the processor-based VM-execution controls with the MOV-DRx intercepts and the
5810 * monitor-trap flag and update our cache.
5811 */
5812 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5813 {
5814 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5815 AssertRC(rc);
5816 pVmcsInfo->u32ProcCtls = uProcCtls;
5817 }
5818
5819 /*
5820 * Update guest DR7.
5821 */
5822 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, u64GuestDr7);
5823 AssertRC(rc);
5824
5825 /*
5826 * If we have forced EFLAGS.TF to be set because we're single-stepping in the hypervisor debugger,
5827 * we need to clear interrupt inhibition if any as otherwise it causes a VM-entry failure.
5828 *
5829 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5830 */
5831 if (fSteppingDB)
5832 {
5833 Assert(pVCpu->hm.s.fSingleInstruction);
5834 Assert(pVCpu->cpum.GstCtx.eflags.Bits.u1TF);
5835
5836 uint32_t fIntrState = 0;
5837 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
5838 AssertRC(rc);
5839
5840 if (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
5841 {
5842 fIntrState &= ~(VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
5843 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
5844 AssertRC(rc);
5845 }
5846 }
5847
5848 return VINF_SUCCESS;
5849}
5850
5851
5852#ifdef VBOX_STRICT
5853/**
5854 * Strict function to validate segment registers.
5855 *
5856 * @param pVCpu The cross context virtual CPU structure.
5857 * @param pVmcsInfo The VMCS info. object.
5858 *
5859 * @remarks Will import guest CR0 on strict builds during validation of
5860 * segments.
5861 */
5862static void hmR0VmxValidateSegmentRegs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5863{
5864 /*
5865 * Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
5866 *
5867 * The reason we check for attribute value 0 in this function and not just the unusable bit is
5868 * because hmR0VmxExportGuestSegReg() only updates the VMCS' copy of the value with the
5869 * unusable bit and doesn't change the guest-context value.
5870 */
5871 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5872 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5873 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR0);
5874 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
5875 && ( !CPUMIsGuestInRealModeEx(pCtx)
5876 && !CPUMIsGuestInV86ModeEx(pCtx)))
5877 {
5878 /* Protected mode checks */
5879 /* CS */
5880 Assert(pCtx->cs.Attr.n.u1Present);
5881 Assert(!(pCtx->cs.Attr.u & 0xf00));
5882 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
5883 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
5884 || !(pCtx->cs.Attr.n.u1Granularity));
5885 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
5886 || (pCtx->cs.Attr.n.u1Granularity));
5887 /* CS cannot be loaded with NULL in protected mode. */
5888 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
5889 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
5890 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
5891 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
5892 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
5893 else
5894 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
5895 /* SS */
5896 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
5897 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
5898 if ( !(pCtx->cr0 & X86_CR0_PE)
5899 || pCtx->cs.Attr.n.u4Type == 3)
5900 {
5901 Assert(!pCtx->ss.Attr.n.u2Dpl);
5902 }
5903 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
5904 {
5905 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
5906 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
5907 Assert(pCtx->ss.Attr.n.u1Present);
5908 Assert(!(pCtx->ss.Attr.u & 0xf00));
5909 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
5910 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
5911 || !(pCtx->ss.Attr.n.u1Granularity));
5912 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
5913 || (pCtx->ss.Attr.n.u1Granularity));
5914 }
5915 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSegReg(). */
5916 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
5917 {
5918 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5919 Assert(pCtx->ds.Attr.n.u1Present);
5920 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
5921 Assert(!(pCtx->ds.Attr.u & 0xf00));
5922 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
5923 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
5924 || !(pCtx->ds.Attr.n.u1Granularity));
5925 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
5926 || (pCtx->ds.Attr.n.u1Granularity));
5927 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5928 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
5929 }
5930 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
5931 {
5932 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5933 Assert(pCtx->es.Attr.n.u1Present);
5934 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
5935 Assert(!(pCtx->es.Attr.u & 0xf00));
5936 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
5937 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
5938 || !(pCtx->es.Attr.n.u1Granularity));
5939 Assert( !(pCtx->es.u32Limit & 0xfff00000)
5940 || (pCtx->es.Attr.n.u1Granularity));
5941 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5942 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
5943 }
5944 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
5945 {
5946 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5947 Assert(pCtx->fs.Attr.n.u1Present);
5948 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
5949 Assert(!(pCtx->fs.Attr.u & 0xf00));
5950 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
5951 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
5952 || !(pCtx->fs.Attr.n.u1Granularity));
5953 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
5954 || (pCtx->fs.Attr.n.u1Granularity));
5955 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5956 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
5957 }
5958 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
5959 {
5960 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
5961 Assert(pCtx->gs.Attr.n.u1Present);
5962 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
5963 Assert(!(pCtx->gs.Attr.u & 0xf00));
5964 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
5965 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
5966 || !(pCtx->gs.Attr.n.u1Granularity));
5967 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
5968 || (pCtx->gs.Attr.n.u1Granularity));
5969 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5970 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
5971 }
5972 /* 64-bit capable CPUs. */
5973 Assert(!RT_HI_U32(pCtx->cs.u64Base));
5974 Assert(!pCtx->ss.Attr.u || !RT_HI_U32(pCtx->ss.u64Base));
5975 Assert(!pCtx->ds.Attr.u || !RT_HI_U32(pCtx->ds.u64Base));
5976 Assert(!pCtx->es.Attr.u || !RT_HI_U32(pCtx->es.u64Base));
5977 }
5978 else if ( CPUMIsGuestInV86ModeEx(pCtx)
5979 || ( CPUMIsGuestInRealModeEx(pCtx)
5980 && !pVM->hm.s.vmx.fUnrestrictedGuest))
5981 {
5982 /* Real and v86 mode checks. */
5983 /* hmR0VmxExportGuestSegReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
5984 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
5985 if (pVmcsInfo->RealMode.fRealOnV86Active)
5986 {
5987 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3;
5988 u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
5989 }
5990 else
5991 {
5992 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
5993 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
5994 }
5995
5996 /* CS */
5997 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
5998 Assert(pCtx->cs.u32Limit == 0xffff);
5999 Assert(u32CSAttr == 0xf3);
6000 /* SS */
6001 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
6002 Assert(pCtx->ss.u32Limit == 0xffff);
6003 Assert(u32SSAttr == 0xf3);
6004 /* DS */
6005 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
6006 Assert(pCtx->ds.u32Limit == 0xffff);
6007 Assert(u32DSAttr == 0xf3);
6008 /* ES */
6009 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
6010 Assert(pCtx->es.u32Limit == 0xffff);
6011 Assert(u32ESAttr == 0xf3);
6012 /* FS */
6013 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
6014 Assert(pCtx->fs.u32Limit == 0xffff);
6015 Assert(u32FSAttr == 0xf3);
6016 /* GS */
6017 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
6018 Assert(pCtx->gs.u32Limit == 0xffff);
6019 Assert(u32GSAttr == 0xf3);
6020 /* 64-bit capable CPUs. */
6021 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6022 Assert(!u32SSAttr || !RT_HI_U32(pCtx->ss.u64Base));
6023 Assert(!u32DSAttr || !RT_HI_U32(pCtx->ds.u64Base));
6024 Assert(!u32ESAttr || !RT_HI_U32(pCtx->es.u64Base));
6025 }
6026}
6027#endif /* VBOX_STRICT */
6028
6029
6030/**
6031 * Exports a guest segment register into the guest-state area in the VMCS.
6032 *
6033 * @returns VBox status code.
6034 * @param pVCpu The cross context virtual CPU structure.
6035 * @param pVmcsInfo The VMCS info. object.
6036 * @param iSegReg The segment register number (X86_SREG_XXX).
6037 * @param pSelReg Pointer to the segment selector.
6038 *
6039 * @remarks No-long-jump zone!!!
6040 */
6041static int hmR0VmxExportGuestSegReg(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t iSegReg, PCCPUMSELREG pSelReg)
6042{
6043 Assert(iSegReg < X86_SREG_COUNT);
6044 uint32_t const idxSel = g_aVmcsSegSel[iSegReg];
6045 uint32_t const idxLimit = g_aVmcsSegLimit[iSegReg];
6046 uint32_t const idxBase = g_aVmcsSegBase[iSegReg];
6047 uint32_t const idxAttr = g_aVmcsSegAttr[iSegReg];
6048
6049 uint32_t u32Access = pSelReg->Attr.u;
6050 if (pVmcsInfo->RealMode.fRealOnV86Active)
6051 {
6052 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
6053 u32Access = 0xf3;
6054 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6055 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
6056 RT_NOREF_PV(pVCpu);
6057 }
6058 else
6059 {
6060 /*
6061 * The way to differentiate between whether this is really a null selector or was just
6062 * a selector loaded with 0 in real-mode is using the segment attributes. A selector
6063 * loaded in real-mode with the value 0 is valid and usable in protected-mode and we
6064 * should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures
6065 * NULL selectors loaded in protected-mode have their attribute as 0.
6066 */
6067 if (!u32Access)
6068 u32Access = X86DESCATTR_UNUSABLE;
6069 }
6070
6071 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
6072 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
6073 ("Access bit not set for usable segment. idx=%#x sel=%#x attr %#x\n", idxBase, pSelReg, pSelReg->Attr.u));
6074
6075 /*
6076 * Commit it to the VMCS.
6077 */
6078 int rc = VMXWriteVmcs32(idxSel, pSelReg->Sel); AssertRC(rc);
6079 rc = VMXWriteVmcs32(idxLimit, pSelReg->u32Limit); AssertRC(rc);
6080 rc = VMXWriteVmcsNw(idxBase, pSelReg->u64Base); AssertRC(rc);
6081 rc = VMXWriteVmcs32(idxAttr, u32Access); AssertRC(rc);
6082 return VINF_SUCCESS;
6083}
6084
6085
6086/**
6087 * Exports the guest segment registers, GDTR, IDTR, LDTR, TR into the guest-state
6088 * area in the VMCS.
6089 *
6090 * @returns VBox status code.
6091 * @param pVCpu The cross context virtual CPU structure.
6092 * @param pVmxTransient The VMX-transient structure.
6093 *
6094 * @remarks Will import guest CR0 on strict builds during validation of
6095 * segments.
6096 * @remarks No-long-jump zone!!!
6097 */
6098static int hmR0VmxExportGuestSegRegsXdtr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6099{
6100 int rc = VERR_INTERNAL_ERROR_5;
6101 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6102 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6103 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6104
6105 /*
6106 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
6107 */
6108 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SREG_MASK)
6109 {
6110#ifdef VBOX_WITH_REM
6111 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
6112 {
6113 Assert(!pVmxTransient->fIsNestedGuest);
6114 Assert(pVM->hm.s.vmx.pRealModeTSS);
6115 AssertCompile(PGMMODE_REAL < PGMMODE_PROTECTED);
6116 if ( pVmcsInfo->fWasInRealMode
6117 && PGMGetGuestMode(pVCpu) >= PGMMODE_PROTECTED)
6118 {
6119 /*
6120 * Notify the recompiler must flush its code-cache as the guest -may-
6121 * rewrite code it in real-mode (e.g. OpenBSD 4.0).
6122 */
6123 REMFlushTBs(pVM);
6124 Log4Func(("Switch to protected mode detected!\n"));
6125 pVmcsInfo->fWasInRealMode = false;
6126 }
6127 }
6128#endif
6129 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CS)
6130 {
6131 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CS);
6132 if (pVmcsInfo->RealMode.fRealOnV86Active)
6133 pVmcsInfo->RealMode.AttrCS.u = pCtx->cs.Attr.u;
6134 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_CS, &pCtx->cs);
6135 AssertRC(rc);
6136 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CS);
6137 }
6138
6139 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SS)
6140 {
6141 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SS);
6142 if (pVmcsInfo->RealMode.fRealOnV86Active)
6143 pVmcsInfo->RealMode.AttrSS.u = pCtx->ss.Attr.u;
6144 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_SS, &pCtx->ss);
6145 AssertRC(rc);
6146 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SS);
6147 }
6148
6149 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_DS)
6150 {
6151 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DS);
6152 if (pVmcsInfo->RealMode.fRealOnV86Active)
6153 pVmcsInfo->RealMode.AttrDS.u = pCtx->ds.Attr.u;
6154 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_DS, &pCtx->ds);
6155 AssertRC(rc);
6156 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_DS);
6157 }
6158
6159 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_ES)
6160 {
6161 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_ES);
6162 if (pVmcsInfo->RealMode.fRealOnV86Active)
6163 pVmcsInfo->RealMode.AttrES.u = pCtx->es.Attr.u;
6164 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_ES, &pCtx->es);
6165 AssertRC(rc);
6166 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_ES);
6167 }
6168
6169 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_FS)
6170 {
6171 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_FS);
6172 if (pVmcsInfo->RealMode.fRealOnV86Active)
6173 pVmcsInfo->RealMode.AttrFS.u = pCtx->fs.Attr.u;
6174 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_FS, &pCtx->fs);
6175 AssertRC(rc);
6176 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_FS);
6177 }
6178
6179 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GS)
6180 {
6181 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GS);
6182 if (pVmcsInfo->RealMode.fRealOnV86Active)
6183 pVmcsInfo->RealMode.AttrGS.u = pCtx->gs.Attr.u;
6184 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_GS, &pCtx->gs);
6185 AssertRC(rc);
6186 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GS);
6187 }
6188
6189#ifdef VBOX_STRICT
6190 hmR0VmxValidateSegmentRegs(pVCpu, pVmcsInfo);
6191#endif
6192 Log4Func(("cs={%#04x base=%#RX64 limit=%#RX32 attr=%#RX32}\n", pCtx->cs.Sel, pCtx->cs.u64Base, pCtx->cs.u32Limit,
6193 pCtx->cs.Attr.u));
6194 }
6195
6196 /*
6197 * Guest TR.
6198 */
6199 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_TR)
6200 {
6201 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_TR);
6202
6203 /*
6204 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is
6205 * achieved using the interrupt redirection bitmap (all bits cleared to let the guest
6206 * handle INT-n's) in the TSS. See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
6207 */
6208 uint16_t u16Sel;
6209 uint32_t u32Limit;
6210 uint64_t u64Base;
6211 uint32_t u32AccessRights;
6212 if (!pVmcsInfo->RealMode.fRealOnV86Active)
6213 {
6214 u16Sel = pCtx->tr.Sel;
6215 u32Limit = pCtx->tr.u32Limit;
6216 u64Base = pCtx->tr.u64Base;
6217 u32AccessRights = pCtx->tr.Attr.u;
6218 }
6219 else
6220 {
6221 Assert(!pVmxTransient->fIsNestedGuest);
6222 Assert(pVM->hm.s.vmx.pRealModeTSS);
6223 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMCanExecuteGuest() -XXX- what about inner loop changes? */
6224
6225 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
6226 RTGCPHYS GCPhys;
6227 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
6228 AssertRCReturn(rc, rc);
6229
6230 X86DESCATTR DescAttr;
6231 DescAttr.u = 0;
6232 DescAttr.n.u1Present = 1;
6233 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
6234
6235 u16Sel = 0;
6236 u32Limit = HM_VTX_TSS_SIZE;
6237 u64Base = GCPhys;
6238 u32AccessRights = DescAttr.u;
6239 }
6240
6241 /* Validate. */
6242 Assert(!(u16Sel & RT_BIT(2)));
6243 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
6244 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
6245 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
6246 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
6247 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
6248 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
6249 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
6250 Assert( (u32Limit & 0xfff) == 0xfff
6251 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
6252 Assert( !(pCtx->tr.u32Limit & 0xfff00000)
6253 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
6254
6255 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_TR_SEL, u16Sel); AssertRC(rc);
6256 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit); AssertRC(rc);
6257 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights); AssertRC(rc);
6258 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_TR_BASE, u64Base); AssertRC(rc);
6259
6260 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_TR);
6261 Log4Func(("tr base=%#RX64 limit=%#RX32\n", pCtx->tr.u64Base, pCtx->tr.u32Limit));
6262 }
6263
6264 /*
6265 * Guest GDTR.
6266 */
6267 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GDTR)
6268 {
6269 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GDTR);
6270
6271 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt); AssertRC(rc);
6272 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, pCtx->gdtr.pGdt); AssertRC(rc);
6273
6274 /* Validate. */
6275 Assert(!(pCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6276
6277 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GDTR);
6278 Log4Func(("gdtr base=%#RX64 limit=%#RX32\n", pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt));
6279 }
6280
6281 /*
6282 * Guest LDTR.
6283 */
6284 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_LDTR)
6285 {
6286 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_LDTR);
6287
6288 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
6289 uint32_t u32Access;
6290 if ( !pVmxTransient->fIsNestedGuest
6291 && !pCtx->ldtr.Attr.u)
6292 u32Access = X86DESCATTR_UNUSABLE;
6293 else
6294 u32Access = pCtx->ldtr.Attr.u;
6295
6296 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, pCtx->ldtr.Sel); AssertRC(rc);
6297 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtr.u32Limit); AssertRC(rc);
6298 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access); AssertRC(rc);
6299 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, pCtx->ldtr.u64Base); AssertRC(rc);
6300
6301 /* Validate. */
6302 if (!(u32Access & X86DESCATTR_UNUSABLE))
6303 {
6304 Assert(!(pCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
6305 Assert(pCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
6306 Assert(!pCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
6307 Assert(pCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
6308 Assert(!pCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
6309 Assert(!(pCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
6310 Assert( (pCtx->ldtr.u32Limit & 0xfff) == 0xfff
6311 || !pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
6312 Assert( !(pCtx->ldtr.u32Limit & 0xfff00000)
6313 || pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
6314 }
6315
6316 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_LDTR);
6317 Log4Func(("ldtr base=%#RX64 limit=%#RX32\n", pCtx->ldtr.u64Base, pCtx->ldtr.u32Limit));
6318 }
6319
6320 /*
6321 * Guest IDTR.
6322 */
6323 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_IDTR)
6324 {
6325 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_IDTR);
6326
6327 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt); AssertRC(rc);
6328 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, pCtx->idtr.pIdt); AssertRC(rc);
6329
6330 /* Validate. */
6331 Assert(!(pCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6332
6333 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_IDTR);
6334 Log4Func(("idtr base=%#RX64 limit=%#RX32\n", pCtx->idtr.pIdt, pCtx->idtr.cbIdt));
6335 }
6336
6337 return VINF_SUCCESS;
6338}
6339
6340
6341/**
6342 * Exports certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
6343 * areas.
6344 *
6345 * These MSRs will automatically be loaded to the host CPU on every successful
6346 * VM-entry and stored from the host CPU on every successful VM-exit.
6347 *
6348 * We creates/updates MSR slots for the host MSRs in the VM-exit MSR-load area. The
6349 * actual host MSR values are not- updated here for performance reasons. See
6350 * hmR0VmxExportHostMsrs().
6351 *
6352 * We also exports the guest sysenter MSRs into the guest-state area in the VMCS.
6353 *
6354 * @returns VBox status code.
6355 * @param pVCpu The cross context virtual CPU structure.
6356 * @param pVmxTransient The VMX-transient structure.
6357 *
6358 * @remarks No-long-jump zone!!!
6359 */
6360static int hmR0VmxExportGuestMsrs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6361{
6362 AssertPtr(pVCpu);
6363 AssertPtr(pVmxTransient);
6364
6365 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6366 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6367
6368 /*
6369 * MSRs that we use the auto-load/store MSR area in the VMCS.
6370 * For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(),
6371 * nothing to do here. The host MSR values are updated when it's safe in
6372 * hmR0VmxLazySaveHostMsrs().
6373 *
6374 * For nested-guests, the guests MSRs from the VM-entry MSR-load area are already
6375 * loaded (into the guest-CPU context) by the VMLAUNCH/VMRESUME instruction
6376 * emulation, nothing to do here.
6377 */
6378 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_GUEST_AUTO_MSRS)
6379 {
6380 /* No auto-load/store MSRs currently. */
6381 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_GUEST_AUTO_MSRS);
6382 }
6383
6384 /*
6385 * Guest Sysenter MSRs.
6386 */
6387 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_MSR_MASK)
6388 {
6389 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SYSENTER_MSRS);
6390
6391 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_CS_MSR)
6392 {
6393 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pCtx->SysEnter.cs);
6394 AssertRC(rc);
6395 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_CS_MSR);
6396 }
6397
6398 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_EIP_MSR)
6399 {
6400 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, pCtx->SysEnter.eip);
6401 AssertRC(rc);
6402 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
6403 }
6404
6405 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_ESP_MSR)
6406 {
6407 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, pCtx->SysEnter.esp);
6408 AssertRC(rc);
6409 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
6410 }
6411 }
6412
6413 /*
6414 * Guest/host EFER MSR.
6415 */
6416 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_EFER_MSR)
6417 {
6418 /* Whether we are using the VMCS to swap the EFER MSR must have been
6419 determined earlier while exporting VM-entry/VM-exit controls. */
6420 Assert(!(ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS));
6421 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
6422
6423 if (hmR0VmxShouldSwapEferMsr(pVCpu))
6424 {
6425 /*
6426 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
6427 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
6428 */
6429 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
6430 {
6431 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, pCtx->msrEFER);
6432 AssertRC(rc);
6433 }
6434 else
6435 {
6436 /*
6437 * We shall use the auto-load/store MSR area only for loading the EFER MSR but we must
6438 * continue to intercept guest read and write accesses to it, see @bugref{7386#c16}.
6439 */
6440 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER, pCtx->msrEFER,
6441 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6442 AssertRCReturn(rc, rc);
6443 }
6444 }
6445 else if (!pVM->hm.s.vmx.fSupportsVmcsEfer)
6446 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER);
6447
6448 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_EFER_MSR);
6449 }
6450
6451 /*
6452 * Other MSRs.
6453 * Speculation Control (R/W).
6454 */
6455 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_OTHER_MSRS)
6456 {
6457 HMVMX_CPUMCTX_ASSERT(pVCpu, HM_CHANGED_GUEST_OTHER_MSRS);
6458 if (pVM->cpum.ro.GuestFeatures.fIbrs)
6459 {
6460 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_IA32_SPEC_CTRL, CPUMGetGuestSpecCtrl(pVCpu),
6461 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6462 AssertRCReturn(rc, rc);
6463 }
6464 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
6465 }
6466
6467 return VINF_SUCCESS;
6468}
6469
6470
6471/**
6472 * Selects up the appropriate function to run guest code.
6473 *
6474 * @returns VBox status code.
6475 * @param pVCpu The cross context virtual CPU structure.
6476 * @param pVmxTransient The VMX-transient structure.
6477 *
6478 * @remarks No-long-jump zone!!!
6479 */
6480static int hmR0VmxSelectVMRunHandler(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6481{
6482 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6483 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6484
6485 if (CPUMIsGuestInLongModeEx(pCtx))
6486 {
6487#ifndef VBOX_WITH_64_BITS_GUESTS
6488 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
6489#else
6490 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
6491 /* Guest is in long mode, use the 64-bit handler (host is 64-bit). */
6492 pVmcsInfo->pfnStartVM = VMXR0StartVM64;
6493#endif
6494 }
6495 else
6496 {
6497 /* Guest is not in long mode, use the 32-bit handler. */
6498 pVmcsInfo->pfnStartVM = VMXR0StartVM32;
6499 }
6500 Assert(pVmcsInfo->pfnStartVM);
6501 return VINF_SUCCESS;
6502}
6503
6504
6505/**
6506 * Wrapper for running the guest code in VT-x.
6507 *
6508 * @returns VBox status code, no informational status codes.
6509 * @param pVCpu The cross context virtual CPU structure.
6510 * @param pVmxTransient The VMX-transient structure.
6511 *
6512 * @remarks No-long-jump zone!!!
6513 */
6514DECLINLINE(int) hmR0VmxRunGuest(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6515{
6516 /* Mark that HM is the keeper of all guest-CPU registers now that we're going to execute guest code. */
6517 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6518 pCtx->fExtrn |= HMVMX_CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_KEEPER_HM;
6519
6520 /** @todo Add stats for VMRESUME vs VMLAUNCH. */
6521
6522 /*
6523 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses
6524 * floating-point operations using SSE instructions. Some XMM registers (XMM6-XMM15) are
6525 * callee-saved and thus the need for this XMM wrapper.
6526 *
6527 * See MSDN "Configuring Programs for 64-bit/x64 Software Conventions / Register Usage".
6528 */
6529 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6530 bool const fResumeVM = RT_BOOL(pVmcsInfo->fVmcsState & VMX_V_VMCS_LAUNCH_STATE_LAUNCHED);
6531 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6532#ifdef VBOX_WITH_KERNEL_USING_XMM
6533 int rc = hmR0VMXStartVMWrapXMM(fResumeVM, pCtx, NULL /*pvUnused*/, pVM, pVCpu, pVmcsInfo->pfnStartVM);
6534#else
6535 int rc = pVmcsInfo->pfnStartVM(fResumeVM, pCtx, NULL /*pvUnused*/, pVM, pVCpu);
6536#endif
6537 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
6538 return rc;
6539}
6540
6541
6542/**
6543 * Reports world-switch error and dumps some useful debug info.
6544 *
6545 * @param pVCpu The cross context virtual CPU structure.
6546 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
6547 * @param pVmxTransient The VMX-transient structure (only
6548 * exitReason updated).
6549 */
6550static void hmR0VmxReportWorldSwitchError(PVMCPUCC pVCpu, int rcVMRun, PVMXTRANSIENT pVmxTransient)
6551{
6552 Assert(pVCpu);
6553 Assert(pVmxTransient);
6554 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
6555
6556 Log4Func(("VM-entry failure: %Rrc\n", rcVMRun));
6557 switch (rcVMRun)
6558 {
6559 case VERR_VMX_INVALID_VMXON_PTR:
6560 AssertFailed();
6561 break;
6562 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
6563 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
6564 {
6565 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
6566 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
6567 AssertRC(rc);
6568 hmR0VmxReadExitQualVmcs(pVmxTransient);
6569
6570 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
6571 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
6572 Cannot do it here as we may have been long preempted. */
6573
6574#ifdef VBOX_STRICT
6575 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6576 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
6577 pVmxTransient->uExitReason));
6578 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQual));
6579 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
6580 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
6581 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
6582 else
6583 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
6584 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
6585 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
6586
6587 static struct
6588 {
6589 /** Name of the field to log. */
6590 const char *pszName;
6591 /** The VMCS field. */
6592 uint32_t uVmcsField;
6593 /** Whether host support of this field needs to be checked. */
6594 bool fCheckSupport;
6595 } const s_aVmcsFields[] =
6596 {
6597 { "VMX_VMCS32_CTRL_PIN_EXEC", VMX_VMCS32_CTRL_PIN_EXEC, false },
6598 { "VMX_VMCS32_CTRL_PROC_EXEC", VMX_VMCS32_CTRL_PROC_EXEC, false },
6599 { "VMX_VMCS32_CTRL_PROC_EXEC2", VMX_VMCS32_CTRL_PROC_EXEC2, true },
6600 { "VMX_VMCS32_CTRL_ENTRY", VMX_VMCS32_CTRL_ENTRY, false },
6601 { "VMX_VMCS32_CTRL_EXIT", VMX_VMCS32_CTRL_EXIT, false },
6602 { "VMX_VMCS32_CTRL_CR3_TARGET_COUNT", VMX_VMCS32_CTRL_CR3_TARGET_COUNT, false },
6603 { "VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO", VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, false },
6604 { "VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE", VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, false },
6605 { "VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH", VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, false },
6606 { "VMX_VMCS32_CTRL_TPR_THRESHOLD", VMX_VMCS32_CTRL_TPR_THRESHOLD, false },
6607 { "VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, false },
6608 { "VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, false },
6609 { "VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, false },
6610 { "VMX_VMCS32_CTRL_EXCEPTION_BITMAP", VMX_VMCS32_CTRL_EXCEPTION_BITMAP, false },
6611 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, false },
6612 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, false },
6613 { "VMX_VMCS_CTRL_CR0_MASK", VMX_VMCS_CTRL_CR0_MASK, false },
6614 { "VMX_VMCS_CTRL_CR0_READ_SHADOW", VMX_VMCS_CTRL_CR0_READ_SHADOW, false },
6615 { "VMX_VMCS_CTRL_CR4_MASK", VMX_VMCS_CTRL_CR4_MASK, false },
6616 { "VMX_VMCS_CTRL_CR4_READ_SHADOW", VMX_VMCS_CTRL_CR4_READ_SHADOW, false },
6617 { "VMX_VMCS64_CTRL_EPTP_FULL", VMX_VMCS64_CTRL_EPTP_FULL, true },
6618 { "VMX_VMCS_GUEST_RIP", VMX_VMCS_GUEST_RIP, false },
6619 { "VMX_VMCS_GUEST_RSP", VMX_VMCS_GUEST_RSP, false },
6620 { "VMX_VMCS_GUEST_RFLAGS", VMX_VMCS_GUEST_RFLAGS, false },
6621 { "VMX_VMCS16_VPID", VMX_VMCS16_VPID, true, },
6622 { "VMX_VMCS_HOST_CR0", VMX_VMCS_HOST_CR0, false },
6623 { "VMX_VMCS_HOST_CR3", VMX_VMCS_HOST_CR3, false },
6624 { "VMX_VMCS_HOST_CR4", VMX_VMCS_HOST_CR4, false },
6625 /* The order of selector fields below are fixed! */
6626 { "VMX_VMCS16_HOST_ES_SEL", VMX_VMCS16_HOST_ES_SEL, false },
6627 { "VMX_VMCS16_HOST_CS_SEL", VMX_VMCS16_HOST_CS_SEL, false },
6628 { "VMX_VMCS16_HOST_SS_SEL", VMX_VMCS16_HOST_SS_SEL, false },
6629 { "VMX_VMCS16_HOST_DS_SEL", VMX_VMCS16_HOST_DS_SEL, false },
6630 { "VMX_VMCS16_HOST_FS_SEL", VMX_VMCS16_HOST_FS_SEL, false },
6631 { "VMX_VMCS16_HOST_GS_SEL", VMX_VMCS16_HOST_GS_SEL, false },
6632 { "VMX_VMCS16_HOST_TR_SEL", VMX_VMCS16_HOST_TR_SEL, false },
6633 /* End of ordered selector fields. */
6634 { "VMX_VMCS_HOST_TR_BASE", VMX_VMCS_HOST_TR_BASE, false },
6635 { "VMX_VMCS_HOST_GDTR_BASE", VMX_VMCS_HOST_GDTR_BASE, false },
6636 { "VMX_VMCS_HOST_IDTR_BASE", VMX_VMCS_HOST_IDTR_BASE, false },
6637 { "VMX_VMCS32_HOST_SYSENTER_CS", VMX_VMCS32_HOST_SYSENTER_CS, false },
6638 { "VMX_VMCS_HOST_SYSENTER_EIP", VMX_VMCS_HOST_SYSENTER_EIP, false },
6639 { "VMX_VMCS_HOST_SYSENTER_ESP", VMX_VMCS_HOST_SYSENTER_ESP, false },
6640 { "VMX_VMCS_HOST_RSP", VMX_VMCS_HOST_RSP, false },
6641 { "VMX_VMCS_HOST_RIP", VMX_VMCS_HOST_RIP, false }
6642 };
6643
6644 RTGDTR HostGdtr;
6645 ASMGetGDTR(&HostGdtr);
6646
6647 uint32_t const cVmcsFields = RT_ELEMENTS(s_aVmcsFields);
6648 for (uint32_t i = 0; i < cVmcsFields; i++)
6649 {
6650 uint32_t const uVmcsField = s_aVmcsFields[i].uVmcsField;
6651
6652 bool fSupported;
6653 if (!s_aVmcsFields[i].fCheckSupport)
6654 fSupported = true;
6655 else
6656 {
6657 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6658 switch (uVmcsField)
6659 {
6660 case VMX_VMCS64_CTRL_EPTP_FULL: fSupported = pVM->hm.s.fNestedPaging; break;
6661 case VMX_VMCS16_VPID: fSupported = pVM->hm.s.vmx.fVpid; break;
6662 case VMX_VMCS32_CTRL_PROC_EXEC2:
6663 fSupported = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
6664 break;
6665 default:
6666 AssertMsgFailedReturnVoid(("Failed to provide VMCS field support for %#RX32\n", uVmcsField));
6667 }
6668 }
6669
6670 if (fSupported)
6671 {
6672 uint8_t const uWidth = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH);
6673 switch (uWidth)
6674 {
6675 case VMX_VMCSFIELD_WIDTH_16BIT:
6676 {
6677 uint16_t u16Val;
6678 rc = VMXReadVmcs16(uVmcsField, &u16Val);
6679 AssertRC(rc);
6680 Log4(("%-40s = %#RX16\n", s_aVmcsFields[i].pszName, u16Val));
6681
6682 if ( uVmcsField >= VMX_VMCS16_HOST_ES_SEL
6683 && uVmcsField <= VMX_VMCS16_HOST_TR_SEL)
6684 {
6685 if (u16Val < HostGdtr.cbGdt)
6686 {
6687 /* Order of selectors in s_apszSel is fixed and matches the order in s_aVmcsFields. */
6688 static const char * const s_apszSel[] = { "Host ES", "Host CS", "Host SS", "Host DS",
6689 "Host FS", "Host GS", "Host TR" };
6690 uint8_t const idxSel = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_INDEX);
6691 Assert(idxSel < RT_ELEMENTS(s_apszSel));
6692 PCX86DESCHC pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u16Val & X86_SEL_MASK));
6693 hmR0DumpDescriptor(pDesc, u16Val, s_apszSel[idxSel]);
6694 }
6695 else
6696 Log4((" Selector value exceeds GDT limit!\n"));
6697 }
6698 break;
6699 }
6700
6701 case VMX_VMCSFIELD_WIDTH_32BIT:
6702 {
6703 uint32_t u32Val;
6704 rc = VMXReadVmcs32(uVmcsField, &u32Val);
6705 AssertRC(rc);
6706 Log4(("%-40s = %#RX32\n", s_aVmcsFields[i].pszName, u32Val));
6707 break;
6708 }
6709
6710 case VMX_VMCSFIELD_WIDTH_64BIT:
6711 case VMX_VMCSFIELD_WIDTH_NATURAL:
6712 {
6713 uint64_t u64Val;
6714 rc = VMXReadVmcs64(uVmcsField, &u64Val);
6715 AssertRC(rc);
6716 Log4(("%-40s = %#RX64\n", s_aVmcsFields[i].pszName, u64Val));
6717 break;
6718 }
6719 }
6720 }
6721 }
6722
6723 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
6724 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
6725 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
6726 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
6727 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
6728 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
6729#endif /* VBOX_STRICT */
6730 break;
6731 }
6732
6733 default:
6734 /* Impossible */
6735 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
6736 break;
6737 }
6738}
6739
6740
6741/**
6742 * Sets up the usage of TSC-offsetting and updates the VMCS.
6743 *
6744 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
6745 * VMX-preemption timer.
6746 *
6747 * @returns VBox status code.
6748 * @param pVCpu The cross context virtual CPU structure.
6749 * @param pVmxTransient The VMX-transient structure.
6750 *
6751 * @remarks No-long-jump zone!!!
6752 */
6753static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6754{
6755 bool fOffsettedTsc;
6756 bool fParavirtTsc;
6757 uint64_t uTscOffset;
6758 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6759 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6760
6761 if (pVM->hm.s.vmx.fUsePreemptTimer)
6762 {
6763 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &uTscOffset, &fOffsettedTsc, &fParavirtTsc);
6764
6765 /* Make sure the returned values have sane upper and lower boundaries. */
6766 uint64_t u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
6767 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second */
6768 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
6769 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
6770
6771 /** @todo r=ramshankar: We need to find a way to integrate nested-guest
6772 * preemption timers here. We probably need to clamp the preemption timer,
6773 * after converting the timer value to the host. */
6774 uint32_t const cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
6775 int rc = VMXWriteVmcs32(VMX_VMCS32_PREEMPT_TIMER_VALUE, cPreemptionTickCount);
6776 AssertRC(rc);
6777 }
6778 else
6779 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
6780
6781 if (fParavirtTsc)
6782 {
6783 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
6784 information before every VM-entry, hence disable it for performance sake. */
6785#if 0
6786 int rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
6787 AssertRC(rc);
6788#endif
6789 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
6790 }
6791
6792 if ( fOffsettedTsc
6793 && RT_LIKELY(!pVCpu->hm.s.fDebugWantRdTscExit))
6794 {
6795 if (pVmxTransient->fIsNestedGuest)
6796 uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
6797 hmR0VmxSetTscOffsetVmcs(pVmcsInfo, uTscOffset);
6798 hmR0VmxRemoveProcCtlsVmcs(pVCpu, pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
6799 }
6800 else
6801 {
6802 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
6803 hmR0VmxSetProcCtlsVmcs(pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
6804 }
6805}
6806
6807
6808/**
6809 * Gets the IEM exception flags for the specified vector and IDT vectoring /
6810 * VM-exit interruption info type.
6811 *
6812 * @returns The IEM exception flags.
6813 * @param uVector The event vector.
6814 * @param uVmxEventType The VMX event type.
6815 *
6816 * @remarks This function currently only constructs flags required for
6817 * IEMEvaluateRecursiveXcpt and not the complete flags (e.g, error-code
6818 * and CR2 aspects of an exception are not included).
6819 */
6820static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxEventType)
6821{
6822 uint32_t fIemXcptFlags;
6823 switch (uVmxEventType)
6824 {
6825 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
6826 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
6827 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
6828 break;
6829
6830 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
6831 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
6832 break;
6833
6834 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
6835 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
6836 break;
6837
6838 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
6839 {
6840 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6841 if (uVector == X86_XCPT_BP)
6842 fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
6843 else if (uVector == X86_XCPT_OF)
6844 fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
6845 else
6846 {
6847 fIemXcptFlags = 0;
6848 AssertMsgFailed(("Unexpected vector for software exception. uVector=%#x", uVector));
6849 }
6850 break;
6851 }
6852
6853 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
6854 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6855 break;
6856
6857 default:
6858 fIemXcptFlags = 0;
6859 AssertMsgFailed(("Unexpected vector type! uVmxEventType=%#x uVector=%#x", uVmxEventType, uVector));
6860 break;
6861 }
6862 return fIemXcptFlags;
6863}
6864
6865
6866/**
6867 * Sets an event as a pending event to be injected into the guest.
6868 *
6869 * @param pVCpu The cross context virtual CPU structure.
6870 * @param u32IntInfo The VM-entry interruption-information field.
6871 * @param cbInstr The VM-entry instruction length in bytes (for
6872 * software interrupts, exceptions and privileged
6873 * software exceptions).
6874 * @param u32ErrCode The VM-entry exception error code.
6875 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
6876 * page-fault.
6877 */
6878DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPUCC pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
6879 RTGCUINTPTR GCPtrFaultAddress)
6880{
6881 Assert(!pVCpu->hm.s.Event.fPending);
6882 pVCpu->hm.s.Event.fPending = true;
6883 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
6884 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
6885 pVCpu->hm.s.Event.cbInstr = cbInstr;
6886 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
6887}
6888
6889
6890/**
6891 * Sets an external interrupt as pending-for-injection into the VM.
6892 *
6893 * @param pVCpu The cross context virtual CPU structure.
6894 * @param u8Interrupt The external interrupt vector.
6895 */
6896DECLINLINE(void) hmR0VmxSetPendingExtInt(PVMCPUCC pVCpu, uint8_t u8Interrupt)
6897{
6898 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, u8Interrupt)
6899 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
6900 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6901 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6902 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6903}
6904
6905
6906/**
6907 * Sets an NMI (\#NMI) exception as pending-for-injection into the VM.
6908 *
6909 * @param pVCpu The cross context virtual CPU structure.
6910 */
6911DECLINLINE(void) hmR0VmxSetPendingXcptNmi(PVMCPUCC pVCpu)
6912{
6913 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI)
6914 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI)
6915 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6916 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6917 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6918}
6919
6920
6921/**
6922 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
6923 *
6924 * @param pVCpu The cross context virtual CPU structure.
6925 */
6926DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPUCC pVCpu)
6927{
6928 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
6929 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6930 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6931 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6932 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6933}
6934
6935
6936/**
6937 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
6938 *
6939 * @param pVCpu The cross context virtual CPU structure.
6940 */
6941DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPUCC pVCpu)
6942{
6943 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_UD)
6944 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6945 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6946 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6947 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6948}
6949
6950
6951/**
6952 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
6953 *
6954 * @param pVCpu The cross context virtual CPU structure.
6955 */
6956DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPUCC pVCpu)
6957{
6958 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
6959 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6960 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
6961 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6962 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6963}
6964
6965
6966#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6967/**
6968 * Sets a general-protection (\#GP) exception as pending-for-injection into the VM.
6969 *
6970 * @param pVCpu The cross context virtual CPU structure.
6971 * @param u32ErrCode The error code for the general-protection exception.
6972 */
6973DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPUCC pVCpu, uint32_t u32ErrCode)
6974{
6975 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
6976 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6977 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6978 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6979 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
6980}
6981
6982
6983/**
6984 * Sets a stack (\#SS) exception as pending-for-injection into the VM.
6985 *
6986 * @param pVCpu The cross context virtual CPU structure.
6987 * @param u32ErrCode The error code for the stack exception.
6988 */
6989DECLINLINE(void) hmR0VmxSetPendingXcptSS(PVMCPUCC pVCpu, uint32_t u32ErrCode)
6990{
6991 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_SS)
6992 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
6993 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
6994 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
6995 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
6996}
6997#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
6998
6999
7000/**
7001 * Fixes up attributes for the specified segment register.
7002 *
7003 * @param pVCpu The cross context virtual CPU structure.
7004 * @param pSelReg The segment register that needs fixing.
7005 * @param idxSel The VMCS field for the corresponding segment register.
7006 */
7007static void hmR0VmxFixUnusableSegRegAttr(PVMCPUCC pVCpu, PCPUMSELREG pSelReg, uint32_t idxSel)
7008{
7009 Assert(pSelReg->Attr.u & X86DESCATTR_UNUSABLE);
7010
7011 /*
7012 * If VT-x marks the segment as unusable, most other bits remain undefined:
7013 * - For CS the L, D and G bits have meaning.
7014 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
7015 * - For the remaining data segments no bits are defined.
7016 *
7017 * The present bit and the unusable bit has been observed to be set at the
7018 * same time (the selector was supposed to be invalid as we started executing
7019 * a V8086 interrupt in ring-0).
7020 *
7021 * What should be important for the rest of the VBox code, is that the P bit is
7022 * cleared. Some of the other VBox code recognizes the unusable bit, but
7023 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
7024 * safe side here, we'll strip off P and other bits we don't care about. If
7025 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
7026 *
7027 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
7028 */
7029#ifdef VBOX_STRICT
7030 uint32_t const uAttr = pSelReg->Attr.u;
7031#endif
7032
7033 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
7034 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
7035 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
7036
7037#ifdef VBOX_STRICT
7038 VMMRZCallRing3Disable(pVCpu);
7039 Log4Func(("Unusable %#x: sel=%#x attr=%#x -> %#x\n", idxSel, pSelReg->Sel, uAttr, pSelReg->Attr.u));
7040# ifdef DEBUG_bird
7041 AssertMsg((uAttr & ~X86DESCATTR_P) == pSelReg->Attr.u,
7042 ("%#x: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
7043 idxSel, uAttr, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
7044# endif
7045 VMMRZCallRing3Enable(pVCpu);
7046 NOREF(uAttr);
7047#endif
7048 RT_NOREF2(pVCpu, idxSel);
7049}
7050
7051
7052/**
7053 * Imports a guest segment register from the current VMCS into the guest-CPU
7054 * context.
7055 *
7056 * @param pVCpu The cross context virtual CPU structure.
7057 * @param iSegReg The segment register number (X86_SREG_XXX).
7058 *
7059 * @remarks Called with interrupts and/or preemption disabled.
7060 */
7061static void hmR0VmxImportGuestSegReg(PVMCPUCC pVCpu, uint8_t iSegReg)
7062{
7063 Assert(iSegReg < X86_SREG_COUNT);
7064
7065 uint32_t const idxSel = g_aVmcsSegSel[iSegReg];
7066 uint32_t const idxLimit = g_aVmcsSegLimit[iSegReg];
7067 uint32_t const idxAttr = g_aVmcsSegAttr[iSegReg];
7068 uint32_t const idxBase = g_aVmcsSegBase[iSegReg];
7069
7070 uint16_t u16Sel;
7071 uint64_t u64Base;
7072 uint32_t u32Limit, u32Attr;
7073 int rc = VMXReadVmcs16(idxSel, &u16Sel); AssertRC(rc);
7074 rc = VMXReadVmcs32(idxLimit, &u32Limit); AssertRC(rc);
7075 rc = VMXReadVmcs32(idxAttr, &u32Attr); AssertRC(rc);
7076 rc = VMXReadVmcsNw(idxBase, &u64Base); AssertRC(rc);
7077
7078 PCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
7079 pSelReg->Sel = u16Sel;
7080 pSelReg->ValidSel = u16Sel;
7081 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
7082 pSelReg->u32Limit = u32Limit;
7083 pSelReg->u64Base = u64Base;
7084 pSelReg->Attr.u = u32Attr;
7085 if (u32Attr & X86DESCATTR_UNUSABLE)
7086 hmR0VmxFixUnusableSegRegAttr(pVCpu, pSelReg, idxSel);
7087}
7088
7089
7090/**
7091 * Imports the guest LDTR from the current VMCS into the guest-CPU context.
7092 *
7093 * @param pVCpu The cross context virtual CPU structure.
7094 *
7095 * @remarks Called with interrupts and/or preemption disabled.
7096 */
7097static void hmR0VmxImportGuestLdtr(PVMCPUCC pVCpu)
7098{
7099 uint16_t u16Sel;
7100 uint64_t u64Base;
7101 uint32_t u32Limit, u32Attr;
7102 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, &u16Sel); AssertRC(rc);
7103 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, &u32Limit); AssertRC(rc);
7104 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7105 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, &u64Base); AssertRC(rc);
7106
7107 pVCpu->cpum.GstCtx.ldtr.Sel = u16Sel;
7108 pVCpu->cpum.GstCtx.ldtr.ValidSel = u16Sel;
7109 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
7110 pVCpu->cpum.GstCtx.ldtr.u32Limit = u32Limit;
7111 pVCpu->cpum.GstCtx.ldtr.u64Base = u64Base;
7112 pVCpu->cpum.GstCtx.ldtr.Attr.u = u32Attr;
7113 if (u32Attr & X86DESCATTR_UNUSABLE)
7114 hmR0VmxFixUnusableSegRegAttr(pVCpu, &pVCpu->cpum.GstCtx.ldtr, VMX_VMCS16_GUEST_LDTR_SEL);
7115}
7116
7117
7118/**
7119 * Imports the guest TR from the current VMCS into the guest-CPU context.
7120 *
7121 * @param pVCpu The cross context virtual CPU structure.
7122 *
7123 * @remarks Called with interrupts and/or preemption disabled.
7124 */
7125static void hmR0VmxImportGuestTr(PVMCPUCC pVCpu)
7126{
7127 uint16_t u16Sel;
7128 uint64_t u64Base;
7129 uint32_t u32Limit, u32Attr;
7130 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_TR_SEL, &u16Sel); AssertRC(rc);
7131 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, &u32Limit); AssertRC(rc);
7132 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7133 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_TR_BASE, &u64Base); AssertRC(rc);
7134
7135 pVCpu->cpum.GstCtx.tr.Sel = u16Sel;
7136 pVCpu->cpum.GstCtx.tr.ValidSel = u16Sel;
7137 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
7138 pVCpu->cpum.GstCtx.tr.u32Limit = u32Limit;
7139 pVCpu->cpum.GstCtx.tr.u64Base = u64Base;
7140 pVCpu->cpum.GstCtx.tr.Attr.u = u32Attr;
7141 /* TR is the only selector that can never be unusable. */
7142 Assert(!(u32Attr & X86DESCATTR_UNUSABLE));
7143}
7144
7145
7146/**
7147 * Imports the guest RIP from the VMCS back into the guest-CPU context.
7148 *
7149 * @param pVCpu The cross context virtual CPU structure.
7150 *
7151 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7152 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7153 * instead!!!
7154 */
7155static void hmR0VmxImportGuestRip(PVMCPUCC pVCpu)
7156{
7157 uint64_t u64Val;
7158 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7159 if (pCtx->fExtrn & CPUMCTX_EXTRN_RIP)
7160 {
7161 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
7162 AssertRC(rc);
7163
7164 pCtx->rip = u64Val;
7165 EMR0HistoryUpdatePC(pVCpu, pCtx->rip, false);
7166 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RIP;
7167 }
7168}
7169
7170
7171/**
7172 * Imports the guest RFLAGS from the VMCS back into the guest-CPU context.
7173 *
7174 * @param pVCpu The cross context virtual CPU structure.
7175 * @param pVmcsInfo The VMCS info. object.
7176 *
7177 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7178 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7179 * instead!!!
7180 */
7181static void hmR0VmxImportGuestRFlags(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7182{
7183 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7184 if (pCtx->fExtrn & CPUMCTX_EXTRN_RFLAGS)
7185 {
7186 uint64_t u64Val;
7187 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
7188 AssertRC(rc);
7189
7190 pCtx->rflags.u64 = u64Val;
7191 if (pVmcsInfo->RealMode.fRealOnV86Active)
7192 {
7193 pCtx->eflags.Bits.u1VM = 0;
7194 pCtx->eflags.Bits.u2IOPL = pVmcsInfo->RealMode.Eflags.Bits.u2IOPL;
7195 }
7196 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RFLAGS;
7197 }
7198}
7199
7200
7201/**
7202 * Imports the guest interruptibility-state from the VMCS back into the guest-CPU
7203 * context.
7204 *
7205 * @param pVCpu The cross context virtual CPU structure.
7206 * @param pVmcsInfo The VMCS info. object.
7207 *
7208 * @remarks Called with interrupts and/or preemption disabled, try not to assert and
7209 * do not log!
7210 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7211 * instead!!!
7212 */
7213static void hmR0VmxImportGuestIntrState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7214{
7215 uint32_t u32Val;
7216 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32Val); AssertRC(rc);
7217 if (!u32Val)
7218 {
7219 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7220 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7221 CPUMSetGuestNmiBlocking(pVCpu, false);
7222 }
7223 else
7224 {
7225 /*
7226 * We must import RIP here to set our EM interrupt-inhibited state.
7227 * We also import RFLAGS as our code that evaluates pending interrupts
7228 * before VM-entry requires it.
7229 */
7230 hmR0VmxImportGuestRip(pVCpu);
7231 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7232
7233 if (u32Val & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
7234 EMSetInhibitInterruptsPC(pVCpu, pVCpu->cpum.GstCtx.rip);
7235 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7236 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7237
7238 bool const fNmiBlocking = RT_BOOL(u32Val & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
7239 CPUMSetGuestNmiBlocking(pVCpu, fNmiBlocking);
7240 }
7241}
7242
7243
7244/**
7245 * Worker for VMXR0ImportStateOnDemand.
7246 *
7247 * @returns VBox status code.
7248 * @param pVCpu The cross context virtual CPU structure.
7249 * @param pVmcsInfo The VMCS info. object.
7250 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7251 */
7252static int hmR0VmxImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
7253{
7254 int rc = VINF_SUCCESS;
7255 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7256 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7257 uint32_t u32Val;
7258
7259 /*
7260 * Note! This is hack to workaround a mysterious BSOD observed with release builds
7261 * on Windows 10 64-bit hosts. Profile and debug builds are not affected and
7262 * neither are other host platforms.
7263 *
7264 * Committing this temporarily as it prevents BSOD.
7265 *
7266 * Update: This is very likely a compiler optimization bug, see @bugref{9180}.
7267 */
7268#ifdef RT_OS_WINDOWS
7269 if (pVM == 0 || pVM == (void *)(uintptr_t)-1)
7270 return VERR_HM_IPE_1;
7271#endif
7272
7273 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatImportGuestState, x);
7274
7275 /*
7276 * We disable interrupts to make the updating of the state and in particular
7277 * the fExtrn modification atomic wrt to preemption hooks.
7278 */
7279 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
7280
7281 fWhat &= pCtx->fExtrn;
7282 if (fWhat)
7283 {
7284 do
7285 {
7286 if (fWhat & CPUMCTX_EXTRN_RIP)
7287 hmR0VmxImportGuestRip(pVCpu);
7288
7289 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
7290 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7291
7292 if (fWhat & CPUMCTX_EXTRN_HM_VMX_INT_STATE)
7293 hmR0VmxImportGuestIntrState(pVCpu, pVmcsInfo);
7294
7295 if (fWhat & CPUMCTX_EXTRN_RSP)
7296 {
7297 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RSP, &pCtx->rsp);
7298 AssertRC(rc);
7299 }
7300
7301 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
7302 {
7303 bool const fRealOnV86Active = pVmcsInfo->RealMode.fRealOnV86Active;
7304 if (fWhat & CPUMCTX_EXTRN_CS)
7305 {
7306 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_CS);
7307 hmR0VmxImportGuestRip(pVCpu);
7308 if (fRealOnV86Active)
7309 pCtx->cs.Attr.u = pVmcsInfo->RealMode.AttrCS.u;
7310 EMR0HistoryUpdatePC(pVCpu, pCtx->cs.u64Base + pCtx->rip, true /* fFlattened */);
7311 }
7312 if (fWhat & CPUMCTX_EXTRN_SS)
7313 {
7314 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_SS);
7315 if (fRealOnV86Active)
7316 pCtx->ss.Attr.u = pVmcsInfo->RealMode.AttrSS.u;
7317 }
7318 if (fWhat & CPUMCTX_EXTRN_DS)
7319 {
7320 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_DS);
7321 if (fRealOnV86Active)
7322 pCtx->ds.Attr.u = pVmcsInfo->RealMode.AttrDS.u;
7323 }
7324 if (fWhat & CPUMCTX_EXTRN_ES)
7325 {
7326 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_ES);
7327 if (fRealOnV86Active)
7328 pCtx->es.Attr.u = pVmcsInfo->RealMode.AttrES.u;
7329 }
7330 if (fWhat & CPUMCTX_EXTRN_FS)
7331 {
7332 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_FS);
7333 if (fRealOnV86Active)
7334 pCtx->fs.Attr.u = pVmcsInfo->RealMode.AttrFS.u;
7335 }
7336 if (fWhat & CPUMCTX_EXTRN_GS)
7337 {
7338 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_GS);
7339 if (fRealOnV86Active)
7340 pCtx->gs.Attr.u = pVmcsInfo->RealMode.AttrGS.u;
7341 }
7342 }
7343
7344 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
7345 {
7346 if (fWhat & CPUMCTX_EXTRN_LDTR)
7347 hmR0VmxImportGuestLdtr(pVCpu);
7348
7349 if (fWhat & CPUMCTX_EXTRN_GDTR)
7350 {
7351 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &pCtx->gdtr.pGdt); AssertRC(rc);
7352 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRC(rc);
7353 pCtx->gdtr.cbGdt = u32Val;
7354 }
7355
7356 /* Guest IDTR. */
7357 if (fWhat & CPUMCTX_EXTRN_IDTR)
7358 {
7359 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &pCtx->idtr.pIdt); AssertRC(rc);
7360 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRC(rc);
7361 pCtx->idtr.cbIdt = u32Val;
7362 }
7363
7364 /* Guest TR. */
7365 if (fWhat & CPUMCTX_EXTRN_TR)
7366 {
7367 /* Real-mode emulation using virtual-8086 mode has the fake TSS (pRealModeTSS) in TR,
7368 don't need to import that one. */
7369 if (!pVmcsInfo->RealMode.fRealOnV86Active)
7370 hmR0VmxImportGuestTr(pVCpu);
7371 }
7372 }
7373
7374 if (fWhat & CPUMCTX_EXTRN_DR7)
7375 {
7376 if (!pVCpu->hm.s.fUsingHyperDR7)
7377 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_DR7, &pCtx->dr[7]); AssertRC(rc);
7378 }
7379
7380 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
7381 {
7382 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, &pCtx->SysEnter.eip); AssertRC(rc);
7383 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, &pCtx->SysEnter.esp); AssertRC(rc);
7384 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRC(rc);
7385 pCtx->SysEnter.cs = u32Val;
7386 }
7387
7388 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
7389 {
7390 if ( pVM->hm.s.fAllow64BitGuests
7391 && (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7392 pCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
7393 }
7394
7395 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
7396 {
7397 if ( pVM->hm.s.fAllow64BitGuests
7398 && (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7399 {
7400 pCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
7401 pCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
7402 pCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
7403 }
7404 }
7405
7406 if (fWhat & (CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS))
7407 {
7408 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
7409 uint32_t const cMsrs = pVmcsInfo->cExitMsrStore;
7410 Assert(pMsrs);
7411 Assert(cMsrs <= VMX_MISC_MAX_MSRS(pVM->hm.s.vmx.Msrs.u64Misc));
7412 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
7413 for (uint32_t i = 0; i < cMsrs; i++)
7414 {
7415 uint32_t const idMsr = pMsrs[i].u32Msr;
7416 switch (idMsr)
7417 {
7418 case MSR_K8_TSC_AUX: CPUMSetGuestTscAux(pVCpu, pMsrs[i].u64Value); break;
7419 case MSR_IA32_SPEC_CTRL: CPUMSetGuestSpecCtrl(pVCpu, pMsrs[i].u64Value); break;
7420 case MSR_K6_EFER: /* Can't be changed without causing a VM-exit */ break;
7421 default:
7422 {
7423 pCtx->fExtrn = 0;
7424 pVCpu->hm.s.u32HMError = pMsrs->u32Msr;
7425 ASMSetFlags(fEFlags);
7426 AssertMsgFailed(("Unexpected MSR in auto-load/store area. idMsr=%#RX32 cMsrs=%u\n", idMsr, cMsrs));
7427 return VERR_HM_UNEXPECTED_LD_ST_MSR;
7428 }
7429 }
7430 }
7431 }
7432
7433 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
7434 {
7435 if (fWhat & CPUMCTX_EXTRN_CR0)
7436 {
7437 uint64_t u64Cr0;
7438 uint64_t u64Shadow;
7439 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Cr0); AssertRC(rc);
7440 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Shadow); AssertRC(rc);
7441 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7442 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7443#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7444 /*
7445 * Reapply the nested-guest's CR0 fixed bits that might have been altered while
7446 * exporting the nested-guest CR0 for executing using hardware-assisted VMX.
7447 */
7448 if (CPUMIsGuestInVmxNonRootMode(pCtx))
7449 {
7450 u64Cr0 |= pCtx->hwvirt.vmx.Msrs.u64Cr0Fixed0;
7451 u64Cr0 &= pCtx->hwvirt.vmx.Msrs.u64Cr0Fixed1;
7452 }
7453#endif
7454 VMMRZCallRing3Disable(pVCpu); /* May call into PGM which has Log statements. */
7455 CPUMSetGuestCR0(pVCpu, u64Cr0);
7456 VMMRZCallRing3Enable(pVCpu);
7457 }
7458
7459 if (fWhat & CPUMCTX_EXTRN_CR4)
7460 {
7461 uint64_t u64Cr4;
7462 uint64_t u64Shadow;
7463 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64Cr4); AssertRC(rc);
7464 rc |= VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Shadow); AssertRC(rc);
7465 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7466 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7467#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7468 /*
7469 * Reapply the nested-guest's CR4 fixed bits that might have been altered while
7470 * exporting the nested-guest CR4 for executing using hardware-assisted VMX.
7471 */
7472 if (CPUMIsGuestInVmxNonRootMode(pCtx))
7473 {
7474 u64Cr4 |= pCtx->hwvirt.vmx.Msrs.u64Cr4Fixed0;
7475 u64Cr4 &= pCtx->hwvirt.vmx.Msrs.u64Cr4Fixed1;
7476 }
7477#endif
7478 pCtx->cr4 = u64Cr4;
7479 }
7480
7481 if (fWhat & CPUMCTX_EXTRN_CR3)
7482 {
7483 /* CR0.PG bit changes are always intercepted, so it's up to date. */
7484 if ( pVM->hm.s.vmx.fUnrestrictedGuest
7485 || ( pVM->hm.s.fNestedPaging
7486 && CPUMIsGuestPagingEnabledEx(pCtx)))
7487 {
7488 uint64_t u64Cr3;
7489 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR3, &u64Cr3); AssertRC(rc);
7490 if (pCtx->cr3 != u64Cr3)
7491 {
7492 pCtx->cr3 = u64Cr3;
7493 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
7494 }
7495
7496 /* If the guest is in PAE mode, sync back the PDPE's into the guest state.
7497 Note: CR4.PAE, CR0.PG, EFER MSR changes are always intercepted, so they're up to date. */
7498 if (CPUMIsGuestInPAEModeEx(pCtx))
7499 {
7500 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
7501 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
7502 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
7503 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
7504 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
7505 }
7506 }
7507 }
7508 }
7509
7510#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7511 if (fWhat & CPUMCTX_EXTRN_HWVIRT)
7512 {
7513 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
7514 && !CPUMIsGuestInVmxNonRootMode(pCtx))
7515 {
7516 Assert(CPUMIsGuestInVmxRootMode(pCtx));
7517 rc = hmR0VmxCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
7518 if (RT_SUCCESS(rc))
7519 { /* likely */ }
7520 else
7521 break;
7522 }
7523 }
7524#endif
7525 } while (0);
7526
7527 if (RT_SUCCESS(rc))
7528 {
7529 /* Update fExtrn. */
7530 pCtx->fExtrn &= ~fWhat;
7531
7532 /* If everything has been imported, clear the HM keeper bit. */
7533 if (!(pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL))
7534 {
7535 pCtx->fExtrn &= ~CPUMCTX_EXTRN_KEEPER_HM;
7536 Assert(!pCtx->fExtrn);
7537 }
7538 }
7539 }
7540 else
7541 AssertMsg(!pCtx->fExtrn || (pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL), ("%#RX64\n", pCtx->fExtrn));
7542
7543 /*
7544 * Restore interrupts.
7545 */
7546 ASMSetFlags(fEFlags);
7547
7548 STAM_PROFILE_ADV_STOP(& pVCpu->hm.s.StatImportGuestState, x);
7549
7550 if (RT_SUCCESS(rc))
7551 { /* likely */ }
7552 else
7553 return rc;
7554
7555 /*
7556 * Honor any pending CR3 updates.
7557 *
7558 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> hmR0VmxCallRing3Callback()
7559 * -> VMMRZCallRing3Disable() -> hmR0VmxImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
7560 * -> continue with VM-exit handling -> hmR0VmxImportGuestState() and here we are.
7561 *
7562 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
7563 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
7564 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
7565 * -NOT- check if CPUMCTX_EXTRN_CR3 is set!
7566 *
7567 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
7568 */
7569 if (VMMRZCallRing3IsEnabled(pVCpu))
7570 {
7571 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
7572 {
7573 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & CPUMCTX_EXTRN_CR3));
7574 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
7575 }
7576
7577 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
7578 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
7579
7580 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
7581 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
7582 }
7583
7584 return VINF_SUCCESS;
7585}
7586
7587
7588/**
7589 * Saves the guest state from the VMCS into the guest-CPU context.
7590 *
7591 * @returns VBox status code.
7592 * @param pVCpu The cross context virtual CPU structure.
7593 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7594 */
7595VMMR0DECL(int) VMXR0ImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat)
7596{
7597 AssertPtr(pVCpu);
7598 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7599 return hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fWhat);
7600}
7601
7602
7603/**
7604 * Check per-VM and per-VCPU force flag actions that require us to go back to
7605 * ring-3 for one reason or another.
7606 *
7607 * @returns Strict VBox status code (i.e. informational status codes too)
7608 * @retval VINF_SUCCESS if we don't have any actions that require going back to
7609 * ring-3.
7610 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
7611 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
7612 * interrupts)
7613 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
7614 * all EMTs to be in ring-3.
7615 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
7616 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
7617 * to the EM loop.
7618 *
7619 * @param pVCpu The cross context virtual CPU structure.
7620 * @param fStepping Whether we are single-stepping the guest using the
7621 * hypervisor debugger.
7622 *
7623 * @remarks This might cause nested-guest VM-exits, caller must check if the guest
7624 * is no longer in VMX non-root mode.
7625 */
7626static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVMCPUCC pVCpu, bool fStepping)
7627{
7628 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7629
7630 /*
7631 * Update pending interrupts into the APIC's IRR.
7632 */
7633 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
7634 APICUpdatePendingInterrupts(pVCpu);
7635
7636 /*
7637 * Anything pending? Should be more likely than not if we're doing a good job.
7638 */
7639 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7640 if ( !fStepping
7641 ? !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_MASK)
7642 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
7643 : !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
7644 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
7645 return VINF_SUCCESS;
7646
7647 /* Pending PGM C3 sync. */
7648 if (VMCPU_FF_IS_ANY_SET(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
7649 {
7650 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7651 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & (CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4)));
7652 VBOXSTRICTRC rcStrict = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4,
7653 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
7654 if (rcStrict != VINF_SUCCESS)
7655 {
7656 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
7657 Log4Func(("PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
7658 return rcStrict;
7659 }
7660 }
7661
7662 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
7663 if ( VM_FF_IS_ANY_SET(pVM, VM_FF_HM_TO_R3_MASK)
7664 || VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
7665 {
7666 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
7667 int rc = RT_LIKELY(!VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_RAW_TO_R3 : VINF_EM_NO_MEMORY;
7668 Log4Func(("HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc));
7669 return rc;
7670 }
7671
7672 /* Pending VM request packets, such as hardware interrupts. */
7673 if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
7674 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
7675 {
7676 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchVmReq);
7677 Log4Func(("Pending VM request forcing us back to ring-3\n"));
7678 return VINF_EM_PENDING_REQUEST;
7679 }
7680
7681 /* Pending PGM pool flushes. */
7682 if (VM_FF_IS_SET(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
7683 {
7684 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPgmPoolFlush);
7685 Log4Func(("PGM pool flush pending forcing us back to ring-3\n"));
7686 return VINF_PGM_POOL_FLUSH_PENDING;
7687 }
7688
7689 /* Pending DMA requests. */
7690 if (VM_FF_IS_SET(pVM, VM_FF_PDM_DMA))
7691 {
7692 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchDma);
7693 Log4Func(("Pending DMA request forcing us back to ring-3\n"));
7694 return VINF_EM_RAW_TO_R3;
7695 }
7696
7697#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7698 /* Pending nested-guest APIC-write (has highest priority among nested-guest FFs). */
7699 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
7700 {
7701 Log4Func(("Pending nested-guest APIC-write\n"));
7702 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitApicWrite(pVCpu);
7703 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
7704 return rcStrict;
7705 }
7706 /** @todo VMCPU_FF_VMX_MTF, VMCPU_FF_VMX_PREEMPT_TIMER */
7707#endif
7708
7709 return VINF_SUCCESS;
7710}
7711
7712
7713/**
7714 * Converts any TRPM trap into a pending HM event. This is typically used when
7715 * entering from ring-3 (not longjmp returns).
7716 *
7717 * @param pVCpu The cross context virtual CPU structure.
7718 */
7719static void hmR0VmxTrpmTrapToPendingEvent(PVMCPUCC pVCpu)
7720{
7721 Assert(TRPMHasTrap(pVCpu));
7722 Assert(!pVCpu->hm.s.Event.fPending);
7723
7724 uint8_t uVector;
7725 TRPMEVENT enmTrpmEvent;
7726 RTGCUINT uErrCode;
7727 RTGCUINTPTR GCPtrFaultAddress;
7728 uint8_t cbInstr;
7729
7730 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr);
7731 AssertRC(rc);
7732
7733 uint32_t u32IntInfo;
7734 u32IntInfo = uVector | VMX_IDT_VECTORING_INFO_VALID;
7735 u32IntInfo |= HMTrpmEventTypeToVmxEventType(uVector, enmTrpmEvent);
7736
7737 rc = TRPMResetTrap(pVCpu);
7738 AssertRC(rc);
7739 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
7740 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
7741
7742 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
7743}
7744
7745
7746/**
7747 * Converts the pending HM event into a TRPM trap.
7748 *
7749 * @param pVCpu The cross context virtual CPU structure.
7750 */
7751static void hmR0VmxPendingEventToTrpmTrap(PVMCPUCC pVCpu)
7752{
7753 Assert(pVCpu->hm.s.Event.fPending);
7754
7755 /* If a trap was already pending, we did something wrong! */
7756 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
7757
7758 uint32_t const u32IntInfo = pVCpu->hm.s.Event.u64IntInfo;
7759 uint32_t const uVector = VMX_IDT_VECTORING_INFO_VECTOR(u32IntInfo);
7760 TRPMEVENT const enmTrapType = HMVmxEventTypeToTrpmEventType(u32IntInfo);
7761
7762 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
7763
7764 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
7765 AssertRC(rc);
7766
7767 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
7768 TRPMSetErrorCode(pVCpu, pVCpu->hm.s.Event.u32ErrCode);
7769
7770 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(u32IntInfo))
7771 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
7772 else if (VMX_IDT_VECTORING_INFO_TYPE(u32IntInfo) == VMX_IDT_VECTORING_INFO_TYPE_SW_INT)
7773 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
7774
7775 /* We're now done converting the pending event. */
7776 pVCpu->hm.s.Event.fPending = false;
7777}
7778
7779
7780/**
7781 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
7782 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
7783 *
7784 * @param pVCpu The cross context virtual CPU structure.
7785 * @param pVmcsInfo The VMCS info. object.
7786 */
7787static void hmR0VmxSetIntWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
7788{
7789 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7790 {
7791 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
7792 {
7793 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_INT_WINDOW_EXIT;
7794 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7795 AssertRC(rc);
7796 }
7797 } /* else we will deliver interrupts whenever the guest Vm-exits next and is in a state to receive the interrupt. */
7798}
7799
7800
7801/**
7802 * Clears the interrupt-window exiting control in the VMCS.
7803 *
7804 * @param pVmcsInfo The VMCS info. object.
7805 */
7806DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
7807{
7808 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7809 {
7810 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_INT_WINDOW_EXIT;
7811 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7812 AssertRC(rc);
7813 }
7814}
7815
7816
7817/**
7818 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
7819 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
7820 *
7821 * @param pVCpu The cross context virtual CPU structure.
7822 * @param pVmcsInfo The VMCS info. object.
7823 */
7824static void hmR0VmxSetNmiWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
7825{
7826 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7827 {
7828 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
7829 {
7830 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_NMI_WINDOW_EXIT;
7831 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7832 AssertRC(rc);
7833 Log4Func(("Setup NMI-window exiting\n"));
7834 }
7835 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
7836}
7837
7838
7839/**
7840 * Clears the NMI-window exiting control in the VMCS.
7841 *
7842 * @param pVmcsInfo The VMCS info. object.
7843 */
7844DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
7845{
7846 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7847 {
7848 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_NMI_WINDOW_EXIT;
7849 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
7850 AssertRC(rc);
7851 }
7852}
7853
7854
7855/**
7856 * Does the necessary state syncing before returning to ring-3 for any reason
7857 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
7858 *
7859 * @returns VBox status code.
7860 * @param pVCpu The cross context virtual CPU structure.
7861 * @param fImportState Whether to import the guest state from the VMCS back
7862 * to the guest-CPU context.
7863 *
7864 * @remarks No-long-jmp zone!!!
7865 */
7866static int hmR0VmxLeave(PVMCPUCC pVCpu, bool fImportState)
7867{
7868 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7869 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7870
7871 RTCPUID const idCpu = RTMpCpuId();
7872 Log4Func(("HostCpuId=%u\n", idCpu));
7873
7874 /*
7875 * !!! IMPORTANT !!!
7876 * If you modify code here, check whether hmR0VmxCallRing3Callback() needs to be updated too.
7877 */
7878
7879 /* Save the guest state if necessary. */
7880 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7881 if (fImportState)
7882 {
7883 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
7884 AssertRCReturn(rc, rc);
7885 }
7886
7887 /* Restore host FPU state if necessary. We will resync on next R0 reentry. */
7888 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
7889 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
7890
7891 /* Restore host debug registers if necessary. We will resync on next R0 reentry. */
7892#ifdef VBOX_STRICT
7893 if (CPUMIsHyperDebugStateActive(pVCpu))
7894 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT);
7895#endif
7896 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
7897 Assert(!CPUMIsGuestDebugStateActive(pVCpu) && !CPUMIsGuestDebugStateActivePending(pVCpu));
7898 Assert(!CPUMIsHyperDebugStateActive(pVCpu) && !CPUMIsHyperDebugStateActivePending(pVCpu));
7899
7900 /* Restore host-state bits that VT-x only restores partially. */
7901 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7902 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7903 {
7904 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags, idCpu));
7905 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7906 }
7907 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7908
7909 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7910 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
7911 {
7912 /* We shouldn't restore the host MSRs without saving the guest MSRs first. */
7913 if (!fImportState)
7914 {
7915 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS);
7916 AssertRCReturn(rc, rc);
7917 }
7918 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7919 Assert(!pVCpu->hm.s.vmx.fLazyMsrs);
7920 }
7921 else
7922 pVCpu->hm.s.vmx.fLazyMsrs = 0;
7923
7924 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7925 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
7926
7927 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
7928 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatImportGuestState);
7929 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExportGuestState);
7930 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatPreExit);
7931 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitHandling);
7932 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
7933 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
7934 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
7935 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitVmentry);
7936 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7937
7938 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7939
7940 /** @todo This partially defeats the purpose of having preemption hooks.
7941 * The problem is, deregistering the hooks should be moved to a place that
7942 * lasts until the EMT is about to be destroyed not everytime while leaving HM
7943 * context.
7944 */
7945 int rc = hmR0VmxClearVmcs(pVmcsInfo);
7946 AssertRCReturn(rc, rc);
7947
7948#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7949 /*
7950 * A valid shadow VMCS is made active as part of VM-entry. It is necessary to
7951 * clear a shadow VMCS before allowing that VMCS to become active on another
7952 * logical processor. We may or may not be importing guest state which clears
7953 * it, so cover for it here.
7954 *
7955 * See Intel spec. 24.11.1 "Software Use of Virtual-Machine Control Structures".
7956 */
7957 if ( pVmcsInfo->pvShadowVmcs
7958 && pVmcsInfo->fShadowVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
7959 {
7960 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
7961 AssertRCReturn(rc, rc);
7962 }
7963
7964 /*
7965 * Flag that we need to re-import the host state if we switch to this VMCS before
7966 * executing guest or nested-guest code.
7967 */
7968 pVmcsInfo->idHostCpu = NIL_RTCPUID;
7969#endif
7970
7971 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
7972 NOREF(idCpu);
7973 return VINF_SUCCESS;
7974}
7975
7976
7977/**
7978 * Leaves the VT-x session.
7979 *
7980 * @returns VBox status code.
7981 * @param pVCpu The cross context virtual CPU structure.
7982 *
7983 * @remarks No-long-jmp zone!!!
7984 */
7985static int hmR0VmxLeaveSession(PVMCPUCC pVCpu)
7986{
7987 HM_DISABLE_PREEMPT(pVCpu);
7988 HMVMX_ASSERT_CPU_SAFE(pVCpu);
7989 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7990 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7991
7992 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
7993 and done this from the VMXR0ThreadCtxCallback(). */
7994 if (!pVCpu->hm.s.fLeaveDone)
7995 {
7996 int rc2 = hmR0VmxLeave(pVCpu, true /* fImportState */);
7997 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
7998 pVCpu->hm.s.fLeaveDone = true;
7999 }
8000 Assert(!pVCpu->cpum.GstCtx.fExtrn);
8001
8002 /*
8003 * !!! IMPORTANT !!!
8004 * If you modify code here, make sure to check whether hmR0VmxCallRing3Callback() needs to be updated too.
8005 */
8006
8007 /* Deregister hook now that we've left HM context before re-enabling preemption. */
8008 /** @todo Deregistering here means we need to VMCLEAR always
8009 * (longjmp/exit-to-r3) in VT-x which is not efficient, eliminate need
8010 * for calling VMMR0ThreadCtxHookDisable here! */
8011 VMMR0ThreadCtxHookDisable(pVCpu);
8012
8013 /* Leave HM context. This takes care of local init (term). */
8014 int rc = HMR0LeaveCpu(pVCpu);
8015
8016 HM_RESTORE_PREEMPT();
8017 return rc;
8018}
8019
8020
8021/**
8022 * Does the necessary state syncing before doing a longjmp to ring-3.
8023 *
8024 * @returns VBox status code.
8025 * @param pVCpu The cross context virtual CPU structure.
8026 *
8027 * @remarks No-long-jmp zone!!!
8028 */
8029DECLINLINE(int) hmR0VmxLongJmpToRing3(PVMCPUCC pVCpu)
8030{
8031 return hmR0VmxLeaveSession(pVCpu);
8032}
8033
8034
8035/**
8036 * Take necessary actions before going back to ring-3.
8037 *
8038 * An action requires us to go back to ring-3. This function does the necessary
8039 * steps before we can safely return to ring-3. This is not the same as longjmps
8040 * to ring-3, this is voluntary and prepares the guest so it may continue
8041 * executing outside HM (recompiler/IEM).
8042 *
8043 * @returns VBox status code.
8044 * @param pVCpu The cross context virtual CPU structure.
8045 * @param rcExit The reason for exiting to ring-3. Can be
8046 * VINF_VMM_UNKNOWN_RING3_CALL.
8047 */
8048static int hmR0VmxExitToRing3(PVMCPUCC pVCpu, VBOXSTRICTRC rcExit)
8049{
8050 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8051
8052 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8053 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
8054 {
8055 VMXGetCurrentVmcs(&pVCpu->hm.s.vmx.LastError.HCPhysCurrentVmcs);
8056 pVCpu->hm.s.vmx.LastError.u32VmcsRev = *(uint32_t *)pVmcsInfo->pvVmcs;
8057 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
8058 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
8059 }
8060
8061 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
8062 VMMRZCallRing3Disable(pVCpu);
8063 Log4Func(("rcExit=%d\n", VBOXSTRICTRC_VAL(rcExit)));
8064
8065 /*
8066 * Convert any pending HM events back to TRPM due to premature exits to ring-3.
8067 * We need to do this only on returns to ring-3 and not for longjmps to ring3.
8068 *
8069 * This is because execution may continue from ring-3 and we would need to inject
8070 * the event from there (hence place it back in TRPM).
8071 */
8072 if (pVCpu->hm.s.Event.fPending)
8073 {
8074 hmR0VmxPendingEventToTrpmTrap(pVCpu);
8075 Assert(!pVCpu->hm.s.Event.fPending);
8076
8077 /* Clear the events from the VMCS. */
8078 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0);
8079 AssertRC(rc);
8080 }
8081#ifdef VBOX_STRICT
8082 else
8083 {
8084 /*
8085 * Ensure we don't accidentally clear a pending HM event without clearing the VMCS.
8086 * This can be pretty hard to debug otherwise, interrupts might get injected twice
8087 * occasionally, see @bugref{9180#c42}.
8088 *
8089 * However, if the VM-entry failed, any VM entry-interruption info. field would
8090 * be left unmodified as the event would not have been injected to the guest. In
8091 * such cases, don't assert, we're not going to continue guest execution anyway.
8092 */
8093 uint32_t uExitReason;
8094 uint32_t uEntryIntInfo;
8095 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8096 rc |= VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &uEntryIntInfo);
8097 AssertRC(rc);
8098 Assert(VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason) || !VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo));
8099 }
8100#endif
8101
8102 /*
8103 * Clear the interrupt-window and NMI-window VMCS controls as we could have got
8104 * a VM-exit with higher priority than interrupt-window or NMI-window VM-exits
8105 * (e.g. TPR below threshold).
8106 */
8107 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8108 {
8109 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
8110 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
8111 }
8112
8113 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
8114 and if we're injecting an event we should have a TRPM trap pending. */
8115 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8116#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a triple fault in progress. */
8117 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8118#endif
8119
8120 /* Save guest state and restore host state bits. */
8121 int rc = hmR0VmxLeaveSession(pVCpu);
8122 AssertRCReturn(rc, rc);
8123 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8124
8125 /* Thread-context hooks are unregistered at this point!!! */
8126
8127 /* Sync recompiler state. */
8128 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
8129 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
8130 | CPUM_CHANGED_LDTR
8131 | CPUM_CHANGED_GDTR
8132 | CPUM_CHANGED_IDTR
8133 | CPUM_CHANGED_TR
8134 | CPUM_CHANGED_HIDDEN_SEL_REGS);
8135 if ( pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging
8136 && CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx))
8137 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
8138
8139 Assert(!pVCpu->hm.s.fClearTrapFlag);
8140
8141 /* Update the exit-to-ring 3 reason. */
8142 pVCpu->hm.s.rcLastExitToR3 = VBOXSTRICTRC_VAL(rcExit);
8143
8144 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
8145 if ( rcExit != VINF_EM_RAW_INTERRUPT
8146 || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8147 {
8148 Assert(!(pVCpu->cpum.GstCtx.fExtrn & HMVMX_CPUMCTX_EXTRN_ALL));
8149 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
8150 }
8151
8152 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
8153
8154 /* We do -not- want any longjmp notifications after this! We must return to ring-3 ASAP. */
8155 VMMRZCallRing3RemoveNotification(pVCpu);
8156 VMMRZCallRing3Enable(pVCpu);
8157
8158 return rc;
8159}
8160
8161
8162/**
8163 * VMMRZCallRing3() callback wrapper which saves the guest state before we
8164 * longjump to ring-3 and possibly get preempted.
8165 *
8166 * @returns VBox status code.
8167 * @param pVCpu The cross context virtual CPU structure.
8168 * @param enmOperation The operation causing the ring-3 longjump.
8169 * @param pvUser User argument, currently unused, NULL.
8170 */
8171static DECLCALLBACK(int) hmR0VmxCallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
8172{
8173 RT_NOREF(pvUser);
8174 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
8175 {
8176 /*
8177 * !!! IMPORTANT !!!
8178 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
8179 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
8180 */
8181 VMMRZCallRing3RemoveNotification(pVCpu);
8182 VMMRZCallRing3Disable(pVCpu);
8183 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
8184 RTThreadPreemptDisable(&PreemptState);
8185
8186 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8187 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8188 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8189 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8190
8191 /* Restore host-state bits that VT-x only restores partially. */
8192 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
8193 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
8194 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
8195 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
8196
8197 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8198 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8199 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8200
8201 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8202 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = false;
8203 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8204
8205 /* Clear the current VMCS data back to memory (shadow VMCS if any would have been
8206 cleared as part of importing the guest state above. */
8207 hmR0VmxClearVmcs(pVmcsInfo);
8208
8209 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
8210 VMMR0ThreadCtxHookDisable(pVCpu);
8211 HMR0LeaveCpu(pVCpu);
8212 RTThreadPreemptRestore(&PreemptState);
8213 return VINF_SUCCESS;
8214 }
8215
8216 Assert(pVCpu);
8217 Assert(pvUser);
8218 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8219 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8220
8221 VMMRZCallRing3Disable(pVCpu);
8222 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8223
8224 Log4Func(("-> hmR0VmxLongJmpToRing3 enmOperation=%d\n", enmOperation));
8225
8226 int rc = hmR0VmxLongJmpToRing3(pVCpu);
8227 AssertRCReturn(rc, rc);
8228
8229 VMMRZCallRing3Enable(pVCpu);
8230 return VINF_SUCCESS;
8231}
8232
8233
8234/**
8235 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
8236 * stack.
8237 *
8238 * @returns Strict VBox status code (i.e. informational status codes too).
8239 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
8240 * @param pVCpu The cross context virtual CPU structure.
8241 * @param uValue The value to push to the guest stack.
8242 */
8243static VBOXSTRICTRC hmR0VmxRealModeGuestStackPush(PVMCPUCC pVCpu, uint16_t uValue)
8244{
8245 /*
8246 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
8247 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
8248 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
8249 */
8250 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8251 if (pCtx->sp == 1)
8252 return VINF_EM_RESET;
8253 pCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
8254 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), pCtx->ss.u64Base + pCtx->sp, &uValue, sizeof(uint16_t));
8255 AssertRC(rc);
8256 return rc;
8257}
8258
8259
8260/**
8261 * Injects an event into the guest upon VM-entry by updating the relevant fields
8262 * in the VM-entry area in the VMCS.
8263 *
8264 * @returns Strict VBox status code (i.e. informational status codes too).
8265 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
8266 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
8267 *
8268 * @param pVCpu The cross context virtual CPU structure.
8269 * @param pVmxTransient The VMX-transient structure.
8270 * @param pEvent The event being injected.
8271 * @param pfIntrState Pointer to the VT-x guest-interruptibility-state. This
8272 * will be updated if necessary. This cannot not be NULL.
8273 * @param fStepping Whether we're single-stepping guest execution and should
8274 * return VINF_EM_DBG_STEPPED if the event is injected
8275 * directly (registers modified by us, not by hardware on
8276 * VM-entry).
8277 */
8278static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCHMEVENT pEvent, bool fStepping,
8279 uint32_t *pfIntrState)
8280{
8281 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
8282 AssertMsg(!RT_HI_U32(pEvent->u64IntInfo), ("%#RX64\n", pEvent->u64IntInfo));
8283 Assert(pfIntrState);
8284
8285 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8286 uint32_t u32IntInfo = pEvent->u64IntInfo;
8287 uint32_t const u32ErrCode = pEvent->u32ErrCode;
8288 uint32_t const cbInstr = pEvent->cbInstr;
8289 RTGCUINTPTR const GCPtrFault = pEvent->GCPtrFaultAddress;
8290 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(u32IntInfo);
8291 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(u32IntInfo);
8292
8293#ifdef VBOX_STRICT
8294 /*
8295 * Validate the error-code-valid bit for hardware exceptions.
8296 * No error codes for exceptions in real-mode.
8297 *
8298 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8299 */
8300 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8301 && !CPUMIsGuestInRealModeEx(pCtx))
8302 {
8303 switch (uVector)
8304 {
8305 case X86_XCPT_PF:
8306 case X86_XCPT_DF:
8307 case X86_XCPT_TS:
8308 case X86_XCPT_NP:
8309 case X86_XCPT_SS:
8310 case X86_XCPT_GP:
8311 case X86_XCPT_AC:
8312 AssertMsg(VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo),
8313 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
8314 RT_FALL_THRU();
8315 default:
8316 break;
8317 }
8318 }
8319
8320 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
8321 Assert( uIntType != VMX_EXIT_INT_INFO_TYPE_NMI
8322 || !(*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
8323#endif
8324
8325 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
8326
8327 /*
8328 * Hardware interrupts & exceptions cannot be delivered through the software interrupt
8329 * redirection bitmap to the real mode task in virtual-8086 mode. We must jump to the
8330 * interrupt handler in the (real-mode) guest.
8331 *
8332 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode".
8333 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
8334 */
8335 if (CPUMIsGuestInRealModeEx(pCtx)) /* CR0.PE bit changes are always intercepted, so it's up to date. */
8336 {
8337 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest)
8338 {
8339 /*
8340 * For CPUs with unrestricted guest execution enabled and with the guest
8341 * in real-mode, we must not set the deliver-error-code bit.
8342 *
8343 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8344 */
8345 u32IntInfo &= ~VMX_ENTRY_INT_INFO_ERROR_CODE_VALID;
8346 }
8347 else
8348 {
8349 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8350 Assert(PDMVmmDevHeapIsEnabled(pVM));
8351 Assert(pVM->hm.s.vmx.pRealModeTSS);
8352 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
8353
8354 /* We require RIP, RSP, RFLAGS, CS, IDTR, import them. */
8355 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8356 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TABLE_MASK
8357 | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS);
8358 AssertRCReturn(rc2, rc2);
8359
8360 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8361 size_t const cbIdtEntry = sizeof(X86IDTR16);
8362 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pCtx->idtr.cbIdt)
8363 {
8364 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8365 if (uVector == X86_XCPT_DF)
8366 return VINF_EM_RESET;
8367
8368 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault.
8369 No error codes for exceptions in real-mode. */
8370 if (uVector == X86_XCPT_GP)
8371 {
8372 uint32_t const uXcptDfInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
8373 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8374 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8375 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8376 HMEVENT EventXcptDf;
8377 RT_ZERO(EventXcptDf);
8378 EventXcptDf.u64IntInfo = uXcptDfInfo;
8379 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptDf, fStepping, pfIntrState);
8380 }
8381
8382 /*
8383 * If we're injecting an event with no valid IDT entry, inject a #GP.
8384 * No error codes for exceptions in real-mode.
8385 *
8386 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8387 */
8388 uint32_t const uXcptGpInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
8389 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8390 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8391 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8392 HMEVENT EventXcptGp;
8393 RT_ZERO(EventXcptGp);
8394 EventXcptGp.u64IntInfo = uXcptGpInfo;
8395 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptGp, fStepping, pfIntrState);
8396 }
8397
8398 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8399 uint16_t uGuestIp = pCtx->ip;
8400 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT)
8401 {
8402 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8403 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8404 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8405 }
8406 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_INT)
8407 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8408
8409 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8410 X86IDTR16 IdtEntry;
8411 RTGCPHYS const GCPhysIdtEntry = (RTGCPHYS)pCtx->idtr.pIdt + uVector * cbIdtEntry;
8412 rc2 = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8413 AssertRCReturn(rc2, rc2);
8414
8415 /* Construct the stack frame for the interrupt/exception handler. */
8416 VBOXSTRICTRC rcStrict;
8417 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->eflags.u32);
8418 if (rcStrict == VINF_SUCCESS)
8419 {
8420 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->cs.Sel);
8421 if (rcStrict == VINF_SUCCESS)
8422 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, uGuestIp);
8423 }
8424
8425 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8426 if (rcStrict == VINF_SUCCESS)
8427 {
8428 pCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8429 pCtx->rip = IdtEntry.offSel;
8430 pCtx->cs.Sel = IdtEntry.uSel;
8431 pCtx->cs.ValidSel = IdtEntry.uSel;
8432 pCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8433 if ( uIntType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
8434 && uVector == X86_XCPT_PF)
8435 pCtx->cr2 = GCPtrFault;
8436
8437 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CS | HM_CHANGED_GUEST_CR2
8438 | HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
8439 | HM_CHANGED_GUEST_RSP);
8440
8441 /*
8442 * If we delivered a hardware exception (other than an NMI) and if there was
8443 * block-by-STI in effect, we should clear it.
8444 */
8445 if (*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
8446 {
8447 Assert( uIntType != VMX_ENTRY_INT_INFO_TYPE_NMI
8448 && uIntType != VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
8449 Log4Func(("Clearing inhibition due to STI\n"));
8450 *pfIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
8451 }
8452
8453 Log4(("Injected real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8454 u32IntInfo, u32ErrCode, cbInstr, pCtx->eflags.u, pCtx->cs.Sel, pCtx->eip));
8455
8456 /*
8457 * The event has been truly dispatched to the guest. Mark it as no longer pending so
8458 * we don't attempt to undo it if we are returning to ring-3 before executing guest code.
8459 */
8460 pVCpu->hm.s.Event.fPending = false;
8461
8462 /*
8463 * If we eventually support nested-guest execution without unrestricted guest execution,
8464 * we should set fInterceptEvents here.
8465 */
8466 Assert(!pVmxTransient->fIsNestedGuest);
8467
8468 /* If we're stepping and we've changed cs:rip above, bail out of the VMX R0 execution loop. */
8469 if (fStepping)
8470 rcStrict = VINF_EM_DBG_STEPPED;
8471 }
8472 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8473 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8474 return rcStrict;
8475 }
8476 }
8477
8478 /*
8479 * Validate.
8480 */
8481 Assert(VMX_ENTRY_INT_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
8482 Assert(!(u32IntInfo & VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK)); /* Bits 30:12 MBZ. */
8483
8484 /*
8485 * Inject the event into the VMCS.
8486 */
8487 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8488 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8489 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8490 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8491 AssertRC(rc);
8492
8493 /*
8494 * Update guest CR2 if this is a page-fault.
8495 */
8496 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
8497 pCtx->cr2 = GCPtrFault;
8498
8499 Log4(("Injecting u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x CR2=%#RX64\n", u32IntInfo, u32ErrCode, cbInstr, pCtx->cr2));
8500 return VINF_SUCCESS;
8501}
8502
8503
8504/**
8505 * Evaluates the event to be delivered to the guest and sets it as the pending
8506 * event.
8507 *
8508 * @returns Strict VBox status code (i.e. informational status codes too).
8509 * @param pVCpu The cross context virtual CPU structure.
8510 * @param pVmxTransient The VMX-transient structure.
8511 * @param pfIntrState Where to store the VT-x guest-interruptibility state.
8512 */
8513static VBOXSTRICTRC hmR0VmxEvaluatePendingEvent(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t *pfIntrState)
8514{
8515 Assert(pfIntrState);
8516 Assert(!TRPMHasTrap(pVCpu));
8517
8518 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8519 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8520 bool const fIsNestedGuest = pVmxTransient->fIsNestedGuest;
8521
8522 /*
8523 * Get the current interruptibility-state of the guest or nested-guest and
8524 * then figure out what needs to be injected.
8525 */
8526 uint32_t const fIntrState = hmR0VmxGetGuestIntrState(pVCpu, pVmxTransient);
8527 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
8528 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
8529 bool const fBlockNmi = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
8530
8531 /* We don't support block-by-SMI yet.*/
8532 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI));
8533
8534 /* Block-by-STI must not be set when interrupts are disabled. */
8535 if (fBlockSti)
8536 {
8537 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
8538 Assert(pCtx->eflags.Bits.u1IF);
8539 }
8540
8541 /* Update interruptibility state to the caller. */
8542 *pfIntrState = fIntrState;
8543
8544 /*
8545 * Toggling of interrupt force-flags here is safe since we update TRPM on
8546 * premature exits to ring-3 before executing guest code, see hmR0VmxExitToRing3().
8547 * We must NOT restore these force-flags.
8548 */
8549
8550 /** @todo SMI. SMIs take priority over NMIs. */
8551
8552 /*
8553 * Check if an NMI is pending and if the guest or nested-guest can receive them.
8554 * NMIs take priority over external interrupts.
8555 */
8556 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
8557 {
8558 /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
8559 if ( !pVCpu->hm.s.Event.fPending
8560 && !fBlockNmi
8561 && !fBlockSti
8562 && !fBlockMovSS)
8563 {
8564#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8565 if ( fIsNestedGuest
8566 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_NMI_EXIT))
8567 return IEMExecVmxVmexitXcptNmi(pVCpu);
8568#endif
8569 hmR0VmxSetPendingXcptNmi(pVCpu);
8570 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
8571 Log4Func(("Pending NMI\n"));
8572 }
8573 else if (!fIsNestedGuest)
8574 hmR0VmxSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
8575 /* else: for nested-guests, NMI-window exiting will be picked up when merging VMCS controls. */
8576 }
8577 /*
8578 * Check if an external interrupt (PIC/APIC) is pending and if the guest or nested-guest
8579 * can receive them. Once PDMGetInterrupt() returns a valid interrupt we -must- deliver
8580 * the interrupt. We can no longer re-request it from the APIC.
8581 */
8582 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
8583 && !pVCpu->hm.s.fSingleInstruction)
8584 {
8585 Assert(!DBGFIsStepping(pVCpu));
8586 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
8587 AssertRCReturn(rc, rc);
8588
8589 bool const fBlockInt = !(pCtx->eflags.u32 & X86_EFL_IF);
8590 if ( !pVCpu->hm.s.Event.fPending
8591 && !fBlockInt
8592 && !fBlockSti
8593 && !fBlockMovSS)
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, 0 /* uVector */, true /* fIntPending */);
8601 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8602 return rcStrict;
8603 }
8604#endif
8605 uint8_t u8Interrupt;
8606 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
8607 if (RT_SUCCESS(rc))
8608 {
8609#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8610 if ( fIsNestedGuest
8611 && CPUMIsGuestVmxPinCtlsSet(pVCpu, pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
8612 && CPUMIsGuestVmxExitCtlsSet(pVCpu, pCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
8613 {
8614 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, u8Interrupt, false /* fIntPending */);
8615 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8616 return rcStrict;
8617 }
8618#endif
8619 hmR0VmxSetPendingExtInt(pVCpu, u8Interrupt);
8620 Log4Func(("Pending external interrupt vector %#x\n", u8Interrupt));
8621 }
8622 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
8623 {
8624 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
8625
8626 if ( !fIsNestedGuest
8627 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
8628 hmR0VmxApicSetTprThreshold(pVmcsInfo, u8Interrupt >> 4);
8629 /* else: for nested-guests, TPR threshold is picked up while merging VMCS controls. */
8630
8631 /*
8632 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
8633 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
8634 * need to re-set this force-flag here.
8635 */
8636 }
8637 else
8638 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
8639 }
8640 else if (!fIsNestedGuest)
8641 hmR0VmxSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
8642 /* else: for nested-guests, interrupt-window exiting will be picked up when merging VMCS controls. */
8643 }
8644
8645 return VINF_SUCCESS;
8646}
8647
8648
8649/**
8650 * Injects any pending events into the guest if the guest is in a state to
8651 * receive them.
8652 *
8653 * @returns Strict VBox status code (i.e. informational status codes too).
8654 * @param pVCpu The cross context virtual CPU structure.
8655 * @param pVmxTransient The VMX-transient structure.
8656 * @param fIntrState The VT-x guest-interruptibility state.
8657 * @param fStepping Whether we are single-stepping the guest using the
8658 * hypervisor debugger and should return
8659 * VINF_EM_DBG_STEPPED if the event was dispatched
8660 * directly.
8661 */
8662static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t fIntrState, bool fStepping)
8663{
8664 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8665 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8666
8667 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
8668 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
8669
8670 Assert(!fBlockSti || !(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_RFLAGS));
8671 Assert(!fBlockSti || pVCpu->cpum.GstCtx.eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
8672 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
8673 Assert(!TRPMHasTrap(pVCpu));
8674
8675 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
8676 if (pVCpu->hm.s.Event.fPending)
8677 {
8678 /*
8679 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
8680 * pending even while injecting an event and in this case, we want a VM-exit as soon as
8681 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
8682 *
8683 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
8684 */
8685 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
8686#ifdef VBOX_STRICT
8687 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
8688 {
8689 bool const fBlockInt = !(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_IF);
8690 Assert(!fBlockInt);
8691 Assert(!fBlockSti);
8692 Assert(!fBlockMovSS);
8693 }
8694 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_NMI)
8695 {
8696 bool const fBlockNmi = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
8697 Assert(!fBlockSti);
8698 Assert(!fBlockMovSS);
8699 Assert(!fBlockNmi);
8700 }
8701#endif
8702 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
8703 uIntType));
8704
8705 /*
8706 * Inject the event and get any changes to the guest-interruptibility state.
8707 *
8708 * The guest-interruptibility state may need to be updated if we inject the event
8709 * into the guest IDT ourselves (for real-on-v86 guest injecting software interrupts).
8710 */
8711 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &pVCpu->hm.s.Event, fStepping, &fIntrState);
8712 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
8713
8714 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
8715 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
8716 else
8717 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
8718 }
8719
8720 /*
8721 * Update the guest-interruptibility state.
8722 *
8723 * This is required for the real-on-v86 software interrupt injection case above, as well as
8724 * updates to the guest state from ring-3 or IEM/REM.
8725 */
8726 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
8727 AssertRC(rc);
8728
8729 /*
8730 * There's no need to clear the VM-entry interruption-information field here if we're not
8731 * injecting anything. VT-x clears the valid bit on every VM-exit.
8732 *
8733 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
8734 */
8735
8736 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
8737 NOREF(fBlockMovSS); NOREF(fBlockSti);
8738 return rcStrict;
8739}
8740
8741
8742/**
8743 * Enters the VT-x session.
8744 *
8745 * @returns VBox status code.
8746 * @param pVCpu The cross context virtual CPU structure.
8747 */
8748VMMR0DECL(int) VMXR0Enter(PVMCPUCC pVCpu)
8749{
8750 AssertPtr(pVCpu);
8751 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported);
8752 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8753
8754 LogFlowFunc(("pVCpu=%p\n", pVCpu));
8755 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
8756 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
8757
8758#ifdef VBOX_STRICT
8759 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
8760 RTCCUINTREG uHostCr4 = ASMGetCR4();
8761 if (!(uHostCr4 & X86_CR4_VMXE))
8762 {
8763 LogRelFunc(("X86_CR4_VMXE bit in CR4 is not set!\n"));
8764 return VERR_VMX_X86_CR4_VMXE_CLEARED;
8765 }
8766#endif
8767
8768 /*
8769 * Load the appropriate VMCS as the current and active one.
8770 */
8771 PVMXVMCSINFO pVmcsInfo;
8772 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx);
8773 if (!fInNestedGuestMode)
8774 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfo;
8775 else
8776 pVmcsInfo = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
8777 int rc = hmR0VmxLoadVmcs(pVmcsInfo);
8778 if (RT_SUCCESS(rc))
8779 {
8780 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs = fInNestedGuestMode;
8781 pVCpu->hm.s.fLeaveDone = false;
8782 Log4Func(("Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8783
8784 /*
8785 * Do the EMT scheduled L1D flush here if needed.
8786 */
8787 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
8788 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
8789 else if (pVCpu->CTX_SUFF(pVM)->hm.s.fMdsClearOnSched)
8790 hmR0MdsClear();
8791 }
8792 return rc;
8793}
8794
8795
8796/**
8797 * The thread-context callback (only on platforms which support it).
8798 *
8799 * @param enmEvent The thread-context event.
8800 * @param pVCpu The cross context virtual CPU structure.
8801 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
8802 * @thread EMT(pVCpu)
8803 */
8804VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPUCC pVCpu, bool fGlobalInit)
8805{
8806 AssertPtr(pVCpu);
8807 RT_NOREF1(fGlobalInit);
8808
8809 switch (enmEvent)
8810 {
8811 case RTTHREADCTXEVENT_OUT:
8812 {
8813 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8814 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8815 VMCPU_ASSERT_EMT(pVCpu);
8816
8817 /* No longjmps (logger flushes, locks) in this fragile context. */
8818 VMMRZCallRing3Disable(pVCpu);
8819 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
8820
8821 /* Restore host-state (FPU, debug etc.) */
8822 if (!pVCpu->hm.s.fLeaveDone)
8823 {
8824 /*
8825 * Do -not- import the guest-state here as we might already be in the middle of importing
8826 * it, esp. bad if we're holding the PGM lock, see comment in hmR0VmxImportGuestState().
8827 */
8828 hmR0VmxLeave(pVCpu, false /* fImportState */);
8829 pVCpu->hm.s.fLeaveDone = true;
8830 }
8831
8832 /* Leave HM context, takes care of local init (term). */
8833 int rc = HMR0LeaveCpu(pVCpu);
8834 AssertRC(rc);
8835
8836 /* Restore longjmp state. */
8837 VMMRZCallRing3Enable(pVCpu);
8838 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
8839 break;
8840 }
8841
8842 case RTTHREADCTXEVENT_IN:
8843 {
8844 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8845 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8846 VMCPU_ASSERT_EMT(pVCpu);
8847
8848 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
8849 VMMRZCallRing3Disable(pVCpu);
8850 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
8851
8852 /* Initialize the bare minimum state required for HM. This takes care of
8853 initializing VT-x if necessary (onlined CPUs, local init etc.) */
8854 int rc = hmR0EnterCpu(pVCpu);
8855 AssertRC(rc);
8856 Assert( (pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
8857 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
8858
8859 /* Load the active VMCS as the current one. */
8860 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8861 rc = hmR0VmxLoadVmcs(pVmcsInfo);
8862 AssertRC(rc);
8863 Log4Func(("Resumed: Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8864 pVCpu->hm.s.fLeaveDone = false;
8865
8866 /* Do the EMT scheduled L1D flush if needed. */
8867 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
8868 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
8869
8870 /* Restore longjmp state. */
8871 VMMRZCallRing3Enable(pVCpu);
8872 break;
8873 }
8874
8875 default:
8876 break;
8877 }
8878}
8879
8880
8881/**
8882 * Exports the host state into the VMCS host-state area.
8883 * Sets up the VM-exit MSR-load area.
8884 *
8885 * The CPU state will be loaded from these fields on every successful VM-exit.
8886 *
8887 * @returns VBox status code.
8888 * @param pVCpu The cross context virtual CPU structure.
8889 *
8890 * @remarks No-long-jump zone!!!
8891 */
8892static int hmR0VmxExportHostState(PVMCPUCC pVCpu)
8893{
8894 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8895
8896 int rc = VINF_SUCCESS;
8897 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
8898 {
8899 hmR0VmxExportHostControlRegs();
8900
8901 rc = hmR0VmxExportHostSegmentRegs(pVCpu);
8902 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8903
8904 hmR0VmxExportHostMsrs(pVCpu);
8905
8906 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_HOST_CONTEXT;
8907 }
8908 return rc;
8909}
8910
8911
8912/**
8913 * Saves the host state in the VMCS host-state.
8914 *
8915 * @returns VBox status code.
8916 * @param pVCpu The cross context virtual CPU structure.
8917 *
8918 * @remarks No-long-jump zone!!!
8919 */
8920VMMR0DECL(int) VMXR0ExportHostState(PVMCPUCC pVCpu)
8921{
8922 AssertPtr(pVCpu);
8923 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8924
8925 /*
8926 * Export the host state here while entering HM context.
8927 * When thread-context hooks are used, we might get preempted and have to re-save the host
8928 * state but most of the time we won't be, so do it here before we disable interrupts.
8929 */
8930 return hmR0VmxExportHostState(pVCpu);
8931}
8932
8933
8934/**
8935 * Exports the guest state into the VMCS guest-state area.
8936 *
8937 * The will typically be done before VM-entry when the guest-CPU state and the
8938 * VMCS state may potentially be out of sync.
8939 *
8940 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
8941 * VM-entry controls.
8942 * Sets up the appropriate VMX non-root function to execute guest code based on
8943 * the guest CPU mode.
8944 *
8945 * @returns VBox strict status code.
8946 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8947 * without unrestricted guest execution and the VMMDev is not presently
8948 * mapped (e.g. EFI32).
8949 *
8950 * @param pVCpu The cross context virtual CPU structure.
8951 * @param pVmxTransient The VMX-transient structure.
8952 *
8953 * @remarks No-long-jump zone!!!
8954 */
8955static VBOXSTRICTRC hmR0VmxExportGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8956{
8957 AssertPtr(pVCpu);
8958 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8959 LogFlowFunc(("pVCpu=%p\n", pVCpu));
8960
8961 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExportGuestState, x);
8962
8963 /*
8964 * Determine real-on-v86 mode.
8965 * Used when the guest is in real-mode and unrestricted guest execution is not used.
8966 */
8967 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8968 if ( pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest
8969 || !CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx))
8970 pVmcsInfo->RealMode. fRealOnV86Active = false;
8971 else
8972 {
8973 Assert(!pVmxTransient->fIsNestedGuest);
8974 pVmcsInfo->RealMode.fRealOnV86Active = true;
8975 }
8976
8977 /*
8978 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
8979 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
8980 */
8981 /** @todo r=ramshankar: Move hmR0VmxSelectVMRunHandler inside
8982 * hmR0VmxExportGuestEntryExitCtls and do it conditionally. There shouldn't
8983 * be a need to evaluate this everytime since I'm pretty sure we intercept
8984 * all guest paging mode changes. */
8985 int rc = hmR0VmxSelectVMRunHandler(pVCpu, pVmxTransient);
8986 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8987
8988 rc = hmR0VmxExportGuestEntryExitCtls(pVCpu, pVmxTransient);
8989 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8990
8991 rc = hmR0VmxExportGuestCR0(pVCpu, pVmxTransient);
8992 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
8993
8994 VBOXSTRICTRC rcStrict = hmR0VmxExportGuestCR3AndCR4(pVCpu, pVmxTransient);
8995 if (rcStrict == VINF_SUCCESS)
8996 { /* likely */ }
8997 else
8998 {
8999 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
9000 return rcStrict;
9001 }
9002
9003 rc = hmR0VmxExportGuestSegRegsXdtr(pVCpu, pVmxTransient);
9004 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9005
9006 rc = hmR0VmxExportGuestMsrs(pVCpu, pVmxTransient);
9007 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9008
9009 rc = hmR0VmxExportGuestApicTpr(pVCpu, pVmxTransient);
9010 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9011
9012 rc = hmR0VmxExportGuestXcptIntercepts(pVCpu, pVmxTransient);
9013 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9014
9015 rc = hmR0VmxExportGuestRip(pVCpu);
9016 rc |= hmR0VmxExportGuestRsp(pVCpu);
9017 rc |= hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9018 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9019
9020 rc = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9021 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9022
9023 /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
9024 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~( (HM_CHANGED_GUEST_GPRS_MASK & ~HM_CHANGED_GUEST_RSP)
9025 | HM_CHANGED_GUEST_CR2
9026 | (HM_CHANGED_GUEST_DR_MASK & ~HM_CHANGED_GUEST_DR7)
9027 | HM_CHANGED_GUEST_X87
9028 | HM_CHANGED_GUEST_SSE_AVX
9029 | HM_CHANGED_GUEST_OTHER_XSAVE
9030 | HM_CHANGED_GUEST_XCRx
9031 | HM_CHANGED_GUEST_KERNEL_GS_BASE /* Part of lazy or auto load-store MSRs. */
9032 | HM_CHANGED_GUEST_SYSCALL_MSRS /* Part of lazy or auto load-store MSRs. */
9033 | HM_CHANGED_GUEST_TSC_AUX
9034 | HM_CHANGED_GUEST_OTHER_MSRS
9035 | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
9036
9037 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExportGuestState, x);
9038 return rc;
9039}
9040
9041
9042/**
9043 * Exports the state shared between the host and guest into the VMCS.
9044 *
9045 * @param pVCpu The cross context virtual CPU structure.
9046 * @param pVmxTransient The VMX-transient structure.
9047 *
9048 * @remarks No-long-jump zone!!!
9049 */
9050static void hmR0VmxExportSharedState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9051{
9052 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9053 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9054
9055 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_DR_MASK)
9056 {
9057 int rc = hmR0VmxExportSharedDebugState(pVCpu, pVmxTransient);
9058 AssertRC(rc);
9059 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_GUEST_DR_MASK;
9060
9061 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
9062 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_RFLAGS)
9063 {
9064 rc = hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9065 AssertRC(rc);
9066 }
9067 }
9068
9069 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_GUEST_LAZY_MSRS)
9070 {
9071 hmR0VmxLazyLoadGuestMsrs(pVCpu);
9072 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_VMX_GUEST_LAZY_MSRS;
9073 }
9074
9075 AssertMsg(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE),
9076 ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
9077}
9078
9079
9080/**
9081 * Worker for loading the guest-state bits in the inner VT-x execution loop.
9082 *
9083 * @returns Strict VBox status code (i.e. informational status codes too).
9084 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9085 * without unrestricted guest execution and the VMMDev is not presently
9086 * mapped (e.g. EFI32).
9087 *
9088 * @param pVCpu The cross context virtual CPU structure.
9089 * @param pVmxTransient The VMX-transient structure.
9090 *
9091 * @remarks No-long-jump zone!!!
9092 */
9093static VBOXSTRICTRC hmR0VmxExportGuestStateOptimal(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9094{
9095 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9096 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9097 Assert(VMMR0IsLogFlushDisabled(pVCpu));
9098
9099#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
9100 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
9101#endif
9102
9103 /*
9104 * For many exits it's only RIP that changes and hence try to export it first
9105 * without going through a lot of change flag checks.
9106 */
9107 VBOXSTRICTRC rcStrict;
9108 uint64_t fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9109 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
9110 if ((fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)) == HM_CHANGED_GUEST_RIP)
9111 {
9112 rcStrict = hmR0VmxExportGuestRip(pVCpu);
9113 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9114 { /* likely */}
9115 else
9116 AssertMsgFailedReturn(("Failed to export guest RIP! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)), rcStrict);
9117 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportMinimal);
9118 }
9119 else if (fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9120 {
9121 rcStrict = hmR0VmxExportGuestState(pVCpu, pVmxTransient);
9122 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9123 { /* likely */}
9124 else
9125 {
9126 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM, ("Failed to export guest state! rc=%Rrc\n",
9127 VBOXSTRICTRC_VAL(rcStrict)));
9128 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9129 return rcStrict;
9130 }
9131 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportFull);
9132 }
9133 else
9134 rcStrict = VINF_SUCCESS;
9135
9136#ifdef VBOX_STRICT
9137 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
9138 fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9139 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
9140 AssertMsg(!(fCtxChanged & (HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)),
9141 ("fCtxChanged=%#RX64\n", fCtxChanged));
9142#endif
9143 return rcStrict;
9144}
9145
9146
9147/**
9148 * Tries to determine what part of the guest-state VT-x has deemed as invalid
9149 * and update error record fields accordingly.
9150 *
9151 * @returns VMX_IGS_* error codes.
9152 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
9153 * wrong with the guest state.
9154 *
9155 * @param pVCpu The cross context virtual CPU structure.
9156 * @param pVmcsInfo The VMCS info. object.
9157 *
9158 * @remarks This function assumes our cache of the VMCS controls
9159 * are valid, i.e. hmR0VmxCheckVmcsCtls() succeeded.
9160 */
9161static uint32_t hmR0VmxCheckGuestState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
9162{
9163#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
9164#define HMVMX_CHECK_BREAK(expr, err) do { \
9165 if (!(expr)) { uError = (err); break; } \
9166 } while (0)
9167
9168 int rc;
9169 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9170 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9171 uint32_t uError = VMX_IGS_ERROR;
9172 uint32_t u32Val;
9173 bool const fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuest;
9174
9175 do
9176 {
9177 /*
9178 * CR0.
9179 */
9180 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9181 uint64_t fSetCr0 = (pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
9182 uint64_t const fZapCr0 = (pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
9183 /* Exceptions for unrestricted guest execution for fixed CR0 bits (PE, PG).
9184 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
9185 if (fUnrestrictedGuest)
9186 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
9187
9188 uint64_t u64GuestCr0;
9189 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64GuestCr0);
9190 AssertRC(rc);
9191 HMVMX_CHECK_BREAK((u64GuestCr0 & fSetCr0) == fSetCr0, VMX_IGS_CR0_FIXED1);
9192 HMVMX_CHECK_BREAK(!(u64GuestCr0 & ~fZapCr0), VMX_IGS_CR0_FIXED0);
9193 if ( !fUnrestrictedGuest
9194 && (u64GuestCr0 & X86_CR0_PG)
9195 && !(u64GuestCr0 & X86_CR0_PE))
9196 {
9197 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
9198 }
9199
9200 /*
9201 * CR4.
9202 */
9203 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9204 uint64_t const fSetCr4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
9205 uint64_t const fZapCr4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
9206
9207 uint64_t u64GuestCr4;
9208 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64GuestCr4);
9209 AssertRC(rc);
9210 HMVMX_CHECK_BREAK((u64GuestCr4 & fSetCr4) == fSetCr4, VMX_IGS_CR4_FIXED1);
9211 HMVMX_CHECK_BREAK(!(u64GuestCr4 & ~fZapCr4), VMX_IGS_CR4_FIXED0);
9212
9213 /*
9214 * IA32_DEBUGCTL MSR.
9215 */
9216 uint64_t u64Val;
9217 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
9218 AssertRC(rc);
9219 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9220 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
9221 {
9222 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
9223 }
9224 uint64_t u64DebugCtlMsr = u64Val;
9225
9226#ifdef VBOX_STRICT
9227 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
9228 AssertRC(rc);
9229 Assert(u32Val == pVmcsInfo->u32EntryCtls);
9230#endif
9231 bool const fLongModeGuest = RT_BOOL(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
9232
9233 /*
9234 * RIP and RFLAGS.
9235 */
9236 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
9237 AssertRC(rc);
9238 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
9239 if ( !fLongModeGuest
9240 || !pCtx->cs.Attr.n.u1Long)
9241 {
9242 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
9243 }
9244 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
9245 * must be identical if the "IA-32e mode guest" VM-entry
9246 * control is 1 and CS.L is 1. No check applies if the
9247 * CPU supports 64 linear-address bits. */
9248
9249 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
9250 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
9251 AssertRC(rc);
9252 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
9253 VMX_IGS_RFLAGS_RESERVED);
9254 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
9255 uint32_t const u32Eflags = u64Val;
9256
9257 if ( fLongModeGuest
9258 || ( fUnrestrictedGuest
9259 && !(u64GuestCr0 & X86_CR0_PE)))
9260 {
9261 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
9262 }
9263
9264 uint32_t u32EntryInfo;
9265 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
9266 AssertRC(rc);
9267 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9268 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
9269
9270 /*
9271 * 64-bit checks.
9272 */
9273 if (fLongModeGuest)
9274 {
9275 HMVMX_CHECK_BREAK(u64GuestCr0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
9276 HMVMX_CHECK_BREAK(u64GuestCr4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
9277 }
9278
9279 if ( !fLongModeGuest
9280 && (u64GuestCr4 & X86_CR4_PCIDE))
9281 {
9282 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
9283 }
9284
9285 /** @todo CR3 field must be such that bits 63:52 and bits in the range
9286 * 51:32 beyond the processor's physical-address width are 0. */
9287
9288 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9289 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
9290 {
9291 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
9292 }
9293
9294 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
9295 AssertRC(rc);
9296 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
9297
9298 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
9299 AssertRC(rc);
9300 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
9301
9302 /*
9303 * PERF_GLOBAL MSR.
9304 */
9305 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR)
9306 {
9307 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
9308 AssertRC(rc);
9309 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
9310 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
9311 }
9312
9313 /*
9314 * PAT MSR.
9315 */
9316 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
9317 {
9318 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
9319 AssertRC(rc);
9320 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
9321 for (unsigned i = 0; i < 8; i++)
9322 {
9323 uint8_t u8Val = (u64Val & 0xff);
9324 if ( u8Val != 0 /* UC */
9325 && u8Val != 1 /* WC */
9326 && u8Val != 4 /* WT */
9327 && u8Val != 5 /* WP */
9328 && u8Val != 6 /* WB */
9329 && u8Val != 7 /* UC- */)
9330 {
9331 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
9332 }
9333 u64Val >>= 8;
9334 }
9335 }
9336
9337 /*
9338 * EFER MSR.
9339 */
9340 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
9341 {
9342 Assert(pVM->hm.s.vmx.fSupportsVmcsEfer);
9343 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
9344 AssertRC(rc);
9345 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
9346 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
9347 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVmcsInfo->u32EntryCtls
9348 & VMX_ENTRY_CTLS_IA32E_MODE_GUEST),
9349 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
9350 /** @todo r=ramshankar: Unrestricted check here is probably wrong, see
9351 * iemVmxVmentryCheckGuestState(). */
9352 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9353 || !(u64GuestCr0 & X86_CR0_PG)
9354 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
9355 VMX_IGS_EFER_LMA_LME_MISMATCH);
9356 }
9357
9358 /*
9359 * Segment registers.
9360 */
9361 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9362 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
9363 if (!(u32Eflags & X86_EFL_VM))
9364 {
9365 /* CS */
9366 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
9367 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
9368 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
9369 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
9370 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9371 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
9372 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9373 /* CS cannot be loaded with NULL in protected mode. */
9374 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
9375 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
9376 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
9377 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
9378 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
9379 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
9380 else if (pVM->hm.s.vmx.fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
9381 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
9382 else
9383 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
9384
9385 /* SS */
9386 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9387 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
9388 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
9389 if ( !(pCtx->cr0 & X86_CR0_PE)
9390 || pCtx->cs.Attr.n.u4Type == 3)
9391 {
9392 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
9393 }
9394 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
9395 {
9396 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
9397 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
9398 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
9399 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
9400 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
9401 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9402 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
9403 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9404 }
9405
9406 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSReg(). */
9407 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
9408 {
9409 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
9410 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
9411 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9412 || pCtx->ds.Attr.n.u4Type > 11
9413 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9414 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
9415 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
9416 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
9417 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9418 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
9419 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9420 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9421 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
9422 }
9423 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
9424 {
9425 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
9426 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
9427 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9428 || pCtx->es.Attr.n.u4Type > 11
9429 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9430 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
9431 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
9432 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
9433 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9434 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
9435 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9436 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9437 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
9438 }
9439 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
9440 {
9441 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
9442 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
9443 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9444 || pCtx->fs.Attr.n.u4Type > 11
9445 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
9446 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
9447 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
9448 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
9449 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9450 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
9451 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9452 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9453 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
9454 }
9455 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
9456 {
9457 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
9458 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
9459 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
9460 || pCtx->gs.Attr.n.u4Type > 11
9461 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
9462 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
9463 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
9464 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
9465 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9466 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
9467 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9468 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9469 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
9470 }
9471 /* 64-bit capable CPUs. */
9472 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9473 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9474 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9475 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9476 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9477 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9478 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9479 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9480 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9481 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9482 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9483 }
9484 else
9485 {
9486 /* V86 mode checks. */
9487 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
9488 if (pVmcsInfo->RealMode.fRealOnV86Active)
9489 {
9490 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
9491 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
9492 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
9493 }
9494 else
9495 {
9496 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
9497 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
9498 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
9499 }
9500
9501 /* CS */
9502 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
9503 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
9504 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
9505 /* SS */
9506 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
9507 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
9508 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
9509 /* DS */
9510 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
9511 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
9512 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
9513 /* ES */
9514 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
9515 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
9516 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
9517 /* FS */
9518 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
9519 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
9520 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
9521 /* GS */
9522 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
9523 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
9524 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
9525 /* 64-bit capable CPUs. */
9526 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9527 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9528 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9529 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9530 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9531 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9532 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9533 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9534 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9535 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9536 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9537 }
9538
9539 /*
9540 * TR.
9541 */
9542 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
9543 /* 64-bit capable CPUs. */
9544 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
9545 if (fLongModeGuest)
9546 {
9547 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
9548 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
9549 }
9550 else
9551 {
9552 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
9553 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
9554 VMX_IGS_TR_ATTR_TYPE_INVALID);
9555 }
9556 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
9557 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
9558 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
9559 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
9560 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
9561 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
9562 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
9563 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
9564
9565 /*
9566 * GDTR and IDTR (64-bit capable checks).
9567 */
9568 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
9569 AssertRC(rc);
9570 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
9571
9572 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
9573 AssertRC(rc);
9574 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
9575
9576 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
9577 AssertRC(rc);
9578 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
9579
9580 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
9581 AssertRC(rc);
9582 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
9583
9584 /*
9585 * Guest Non-Register State.
9586 */
9587 /* Activity State. */
9588 uint32_t u32ActivityState;
9589 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
9590 AssertRC(rc);
9591 HMVMX_CHECK_BREAK( !u32ActivityState
9592 || (u32ActivityState & RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Misc, VMX_BF_MISC_ACTIVITY_STATES)),
9593 VMX_IGS_ACTIVITY_STATE_INVALID);
9594 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
9595 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
9596 uint32_t u32IntrState;
9597 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32IntrState);
9598 AssertRC(rc);
9599 if ( u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS
9600 || u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9601 {
9602 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
9603 }
9604
9605 /** @todo Activity state and injecting interrupts. Left as a todo since we
9606 * currently don't use activity states but ACTIVE. */
9607
9608 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
9609 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
9610
9611 /* Guest interruptibility-state. */
9612 HMVMX_CHECK_BREAK(!(u32IntrState & 0xffffffe0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
9613 HMVMX_CHECK_BREAK((u32IntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
9614 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9615 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
9616 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
9617 || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
9618 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
9619 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9620 {
9621 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9622 && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9623 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
9624 }
9625 else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
9626 {
9627 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
9628 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
9629 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
9630 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
9631 }
9632 /** @todo Assumes the processor is not in SMM. */
9633 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
9634 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
9635 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
9636 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
9637 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
9638 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
9639 && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
9640 {
9641 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI),
9642 VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
9643 }
9644
9645 /* Pending debug exceptions. */
9646 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &u64Val);
9647 AssertRC(rc);
9648 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
9649 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
9650 u32Val = u64Val; /* For pending debug exceptions checks below. */
9651
9652 if ( (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
9653 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
9654 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
9655 {
9656 if ( (u32Eflags & X86_EFL_TF)
9657 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
9658 {
9659 /* Bit 14 is PendingDebug.BS. */
9660 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
9661 }
9662 if ( !(u32Eflags & X86_EFL_TF)
9663 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
9664 {
9665 /* Bit 14 is PendingDebug.BS. */
9666 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
9667 }
9668 }
9669
9670 /* VMCS link pointer. */
9671 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
9672 AssertRC(rc);
9673 if (u64Val != UINT64_C(0xffffffffffffffff))
9674 {
9675 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
9676 /** @todo Bits beyond the processor's physical-address width MBZ. */
9677 /** @todo SMM checks. */
9678 Assert(pVmcsInfo->HCPhysShadowVmcs == u64Val);
9679 Assert(pVmcsInfo->pvShadowVmcs);
9680 VMXVMCSREVID VmcsRevId;
9681 VmcsRevId.u = *(uint32_t *)pVmcsInfo->pvShadowVmcs;
9682 HMVMX_CHECK_BREAK(VmcsRevId.n.u31RevisionId == RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID),
9683 VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID);
9684 HMVMX_CHECK_BREAK(VmcsRevId.n.fIsShadowVmcs == (uint32_t)!!(pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING),
9685 VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW);
9686 }
9687
9688 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
9689 * not using nested paging? */
9690 if ( pVM->hm.s.fNestedPaging
9691 && !fLongModeGuest
9692 && CPUMIsGuestInPAEModeEx(pCtx))
9693 {
9694 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
9695 AssertRC(rc);
9696 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9697
9698 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
9699 AssertRC(rc);
9700 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9701
9702 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
9703 AssertRC(rc);
9704 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9705
9706 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
9707 AssertRC(rc);
9708 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
9709 }
9710
9711 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
9712 if (uError == VMX_IGS_ERROR)
9713 uError = VMX_IGS_REASON_NOT_FOUND;
9714 } while (0);
9715
9716 pVCpu->hm.s.u32HMError = uError;
9717 return uError;
9718
9719#undef HMVMX_ERROR_BREAK
9720#undef HMVMX_CHECK_BREAK
9721}
9722
9723
9724/**
9725 * Map the APIC-access page for virtualizing APIC accesses.
9726 *
9727 * This can cause a longjumps to R3 due to the acquisition of the PGM lock. Hence,
9728 * this not done as part of exporting guest state, see @bugref{8721}.
9729 *
9730 * @returns VBox status code.
9731 * @param pVCpu The cross context virtual CPU structure.
9732 */
9733static int hmR0VmxMapHCApicAccessPage(PVMCPUCC pVCpu)
9734{
9735 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9736 uint64_t const u64MsrApicBase = APICGetBaseMsrNoCheck(pVCpu);
9737
9738 Assert(PDMHasApic(pVM));
9739 Assert(u64MsrApicBase);
9740
9741 RTGCPHYS const GCPhysApicBase = u64MsrApicBase & PAGE_BASE_GC_MASK;
9742 Log4Func(("Mappping HC APIC-access page at %#RGp\n", GCPhysApicBase));
9743
9744 /* Unalias the existing mapping. */
9745 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
9746 AssertRCReturn(rc, rc);
9747
9748 /* Map the HC APIC-access page in place of the MMIO page, also updates the shadow page tables if necessary. */
9749 Assert(pVM->hm.s.vmx.HCPhysApicAccess != NIL_RTHCPHYS);
9750 rc = IOMMMIOMapMMIOHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hm.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
9751 AssertRCReturn(rc, rc);
9752
9753 /* Update the per-VCPU cache of the APIC base MSR. */
9754 pVCpu->hm.s.vmx.u64GstMsrApicBase = u64MsrApicBase;
9755 return VINF_SUCCESS;
9756}
9757
9758
9759/**
9760 * Worker function passed to RTMpOnSpecific() that is to be called on the target
9761 * CPU.
9762 *
9763 * @param idCpu The ID for the CPU the function is called on.
9764 * @param pvUser1 Null, not used.
9765 * @param pvUser2 Null, not used.
9766 */
9767static DECLCALLBACK(void) hmR0DispatchHostNmi(RTCPUID idCpu, void *pvUser1, void *pvUser2)
9768{
9769 RT_NOREF3(idCpu, pvUser1, pvUser2);
9770 VMXDispatchHostNmi();
9771}
9772
9773
9774/**
9775 * Dispatching an NMI on the host CPU that received it.
9776 *
9777 * @returns VBox status code.
9778 * @param pVCpu The cross context virtual CPU structure.
9779 * @param pVmcsInfo The VMCS info. object corresponding to the VMCS that was
9780 * executing when receiving the host NMI in VMX non-root
9781 * operation.
9782 */
9783static int hmR0VmxExitHostNmi(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
9784{
9785 RTCPUID const idCpu = pVmcsInfo->idHostCpu;
9786
9787 /*
9788 * We don't want to delay dispatching the NMI any more than we have to. However,
9789 * we have already chosen -not- to dispatch NMIs when interrupts were still disabled
9790 * after executing guest or nested-guest code for the following reasons:
9791 *
9792 * - We would need to perform VMREADs with interrupts disabled and is orders of
9793 * magnitude worse when we run as a guest hypervisor without VMCS shadowing
9794 * supported by the host hypervisor.
9795 *
9796 * - It affects the common VM-exit scenario and keeps interrupts disabled for a
9797 * longer period of time just for handling an edge case like host NMIs which do
9798 * not occur nearly as frequently as other VM-exits.
9799 *
9800 * Let's cover the most likely scenario first. Check if we are on the target CPU
9801 * and dispatch the NMI right away. This should be much faster than calling into
9802 * RTMpOnSpecific() machinery.
9803 */
9804 bool fDispatched = false;
9805 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
9806 if (idCpu == RTMpCpuId())
9807 {
9808 VMXDispatchHostNmi();
9809 fDispatched = true;
9810 }
9811 ASMSetFlags(fEFlags);
9812 if (fDispatched)
9813 {
9814 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
9815 return VINF_SUCCESS;
9816 }
9817
9818 /*
9819 * RTMpOnSpecific() waits until the worker function has run on the target CPU. So
9820 * there should be no race or recursion even if we are unlucky enough to be preempted
9821 * (to the target CPU) without dispatching the host NMI above.
9822 */
9823 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGCIpi);
9824 return RTMpOnSpecific(idCpu, &hmR0DispatchHostNmi, NULL /* pvUser1 */, NULL /* pvUser2 */);
9825}
9826
9827
9828#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9829/**
9830 * Merges the guest with the nested-guest MSR bitmap in preparation of executing the
9831 * nested-guest using hardware-assisted VMX.
9832 *
9833 * @param pVCpu The cross context virtual CPU structure.
9834 * @param pVmcsInfoNstGst The nested-guest VMCS info. object.
9835 * @param pVmcsInfoGst The guest VMCS info. object.
9836 */
9837static void hmR0VmxMergeMsrBitmapNested(PCVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfoNstGst, PCVMXVMCSINFO pVmcsInfoGst)
9838{
9839 uint32_t const cbMsrBitmap = X86_PAGE_4K_SIZE;
9840 uint64_t *pu64MsrBitmap = (uint64_t *)pVmcsInfoNstGst->pvMsrBitmap;
9841 Assert(pu64MsrBitmap);
9842
9843 /*
9844 * We merge the guest MSR bitmap with the nested-guest MSR bitmap such that any
9845 * MSR that is intercepted by the guest is also intercepted while executing the
9846 * nested-guest using hardware-assisted VMX.
9847 *
9848 * Note! If the nested-guest is not using an MSR bitmap, ever MSR must cause a
9849 * nested-guest VM-exit even if the outer guest is not intercepting some
9850 * MSRs. We cannot assume the caller has initialized the nested-guest
9851 * MSR bitmap in this case.
9852 *
9853 * The guest hypervisor may also switch whether it uses MSR bitmaps for
9854 * each VM-entry, hence initializing it once per-VM while setting up the
9855 * nested-guest VMCS is not sufficient.
9856 */
9857 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
9858 if (pVmcsNstGst->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
9859 {
9860 uint64_t const *pu64MsrBitmapNstGst = (uint64_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
9861 uint64_t const *pu64MsrBitmapGst = (uint64_t const *)pVmcsInfoGst->pvMsrBitmap;
9862 Assert(pu64MsrBitmapNstGst);
9863 Assert(pu64MsrBitmapGst);
9864
9865 uint32_t const cFrags = cbMsrBitmap / sizeof(uint64_t);
9866 for (uint32_t i = 0; i < cFrags; i++)
9867 pu64MsrBitmap[i] = pu64MsrBitmapNstGst[i] | pu64MsrBitmapGst[i];
9868 }
9869 else
9870 ASMMemFill32(pu64MsrBitmap, cbMsrBitmap, UINT32_C(0xffffffff));
9871}
9872
9873
9874/**
9875 * Merges the guest VMCS in to the nested-guest VMCS controls in preparation of
9876 * hardware-assisted VMX execution of the nested-guest.
9877 *
9878 * For a guest, we don't modify these controls once we set up the VMCS and hence
9879 * this function is never called.
9880 *
9881 * For nested-guests since the guest hypervisor provides these controls on every
9882 * nested-guest VM-entry and could potentially change them everytime we need to
9883 * merge them before every nested-guest VM-entry.
9884 *
9885 * @returns VBox status code.
9886 * @param pVCpu The cross context virtual CPU structure.
9887 */
9888static int hmR0VmxMergeVmcsNested(PVMCPUCC pVCpu)
9889{
9890 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9891 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hm.s.vmx.VmcsInfo;
9892 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
9893 Assert(pVmcsNstGst);
9894
9895 /*
9896 * Merge the controls with the requirements of the guest VMCS.
9897 *
9898 * We do not need to validate the nested-guest VMX features specified in the nested-guest
9899 * VMCS with the features supported by the physical CPU as it's already done by the
9900 * VMLAUNCH/VMRESUME instruction emulation.
9901 *
9902 * This is because the VMX features exposed by CPUM (through CPUID/MSRs) to the guest are
9903 * derived from the VMX features supported by the physical CPU.
9904 */
9905
9906 /* Pin-based VM-execution controls. */
9907 uint32_t const u32PinCtls = pVmcsNstGst->u32PinCtls | pVmcsInfoGst->u32PinCtls;
9908
9909 /* Processor-based VM-execution controls. */
9910 uint32_t u32ProcCtls = (pVmcsNstGst->u32ProcCtls & ~VMX_PROC_CTLS_USE_IO_BITMAPS)
9911 | (pVmcsInfoGst->u32ProcCtls & ~( VMX_PROC_CTLS_INT_WINDOW_EXIT
9912 | VMX_PROC_CTLS_NMI_WINDOW_EXIT
9913 | VMX_PROC_CTLS_USE_TPR_SHADOW
9914 | VMX_PROC_CTLS_MONITOR_TRAP_FLAG));
9915
9916 /* Secondary processor-based VM-execution controls. */
9917 uint32_t const u32ProcCtls2 = (pVmcsNstGst->u32ProcCtls2 & ~VMX_PROC_CTLS2_VPID)
9918 | (pVmcsInfoGst->u32ProcCtls2 & ~( VMX_PROC_CTLS2_VIRT_APIC_ACCESS
9919 | VMX_PROC_CTLS2_INVPCID
9920 | VMX_PROC_CTLS2_VMCS_SHADOWING
9921 | VMX_PROC_CTLS2_RDTSCP
9922 | VMX_PROC_CTLS2_XSAVES_XRSTORS
9923 | VMX_PROC_CTLS2_APIC_REG_VIRT
9924 | VMX_PROC_CTLS2_VIRT_INT_DELIVERY
9925 | VMX_PROC_CTLS2_VMFUNC));
9926
9927 /*
9928 * VM-entry controls:
9929 * These controls contains state that depends on the nested-guest state (primarily
9930 * EFER MSR) and is thus not constant between VMLAUNCH/VMRESUME and the nested-guest
9931 * VM-exit. Although the guest hypervisor cannot change it, we need to in order to
9932 * properly continue executing the nested-guest if the EFER MSR changes but does not
9933 * cause a nested-guest VM-exits.
9934 *
9935 * VM-exit controls:
9936 * These controls specify the host state on return. We cannot use the controls from
9937 * the guest hypervisor state as is as it would contain the guest state rather than
9938 * the host state. Since the host state is subject to change (e.g. preemption, trips
9939 * to ring-3, longjmp and rescheduling to a different host CPU) they are not constant
9940 * through VMLAUNCH/VMRESUME and the nested-guest VM-exit.
9941 *
9942 * VM-entry MSR-load:
9943 * The guest MSRs from the VM-entry MSR-load area are already loaded into the guest-CPU
9944 * context by the VMLAUNCH/VMRESUME instruction emulation.
9945 *
9946 * VM-exit MSR-store:
9947 * The VM-exit emulation will take care of populating the MSRs from the guest-CPU context
9948 * back into the VM-exit MSR-store area.
9949 *
9950 * VM-exit MSR-load areas:
9951 * This must contain the real host MSRs with hardware-assisted VMX execution. Hence, we
9952 * can entirely ignore what the guest hypervisor wants to load here.
9953 */
9954
9955 /*
9956 * Exception bitmap.
9957 *
9958 * We could remove #UD from the guest bitmap and merge it with the nested-guest bitmap
9959 * here (and avoid doing anything while exporting nested-guest state), but to keep the
9960 * code more flexible if intercepting exceptions become more dynamic in the future we do
9961 * it as part of exporting the nested-guest state.
9962 */
9963 uint32_t const u32XcptBitmap = pVmcsNstGst->u32XcptBitmap | pVmcsInfoGst->u32XcptBitmap;
9964
9965 /*
9966 * CR0/CR4 guest/host mask.
9967 *
9968 * Modifications by the nested-guest to CR0/CR4 bits owned by the host and the guest must
9969 * cause VM-exits, so we need to merge them here.
9970 */
9971 uint64_t const u64Cr0Mask = pVmcsNstGst->u64Cr0Mask.u | pVmcsInfoGst->u64Cr0Mask;
9972 uint64_t const u64Cr4Mask = pVmcsNstGst->u64Cr4Mask.u | pVmcsInfoGst->u64Cr4Mask;
9973
9974 /*
9975 * Page-fault error-code mask and match.
9976 *
9977 * Although we require unrestricted guest execution (and thereby nested-paging) for
9978 * hardware-assisted VMX execution of nested-guests and thus the outer guest doesn't
9979 * normally intercept #PFs, it might intercept them for debugging purposes.
9980 *
9981 * If the outer guest is not intercepting #PFs, we can use the nested-guest #PF filters.
9982 * If the outer guest is intercepting #PFs, we must intercept all #PFs.
9983 */
9984 uint32_t u32XcptPFMask;
9985 uint32_t u32XcptPFMatch;
9986 if (!(pVmcsInfoGst->u32XcptBitmap & RT_BIT(X86_XCPT_PF)))
9987 {
9988 u32XcptPFMask = pVmcsNstGst->u32XcptPFMask;
9989 u32XcptPFMatch = pVmcsNstGst->u32XcptPFMatch;
9990 }
9991 else
9992 {
9993 u32XcptPFMask = 0;
9994 u32XcptPFMatch = 0;
9995 }
9996
9997 /*
9998 * Pause-Loop exiting.
9999 */
10000 uint32_t const cPleGapTicks = RT_MIN(pVM->hm.s.vmx.cPleGapTicks, pVmcsNstGst->u32PleGap);
10001 uint32_t const cPleWindowTicks = RT_MIN(pVM->hm.s.vmx.cPleWindowTicks, pVmcsNstGst->u32PleWindow);
10002
10003 /*
10004 * Pending debug exceptions.
10005 * Currently just copy whatever the nested-guest provides us.
10006 */
10007 uint64_t const uPendingDbgXcpts = pVmcsNstGst->u64GuestPendingDbgXcpts.u;
10008
10009 /*
10010 * I/O Bitmap.
10011 *
10012 * We do not use the I/O bitmap that may be provided by the guest hypervisor as we always
10013 * intercept all I/O port accesses.
10014 */
10015 Assert(u32ProcCtls & VMX_PROC_CTLS_UNCOND_IO_EXIT);
10016 Assert(!(u32ProcCtls & VMX_PROC_CTLS_USE_IO_BITMAPS));
10017
10018 /*
10019 * VMCS shadowing.
10020 *
10021 * We do not yet expose VMCS shadowing to the guest and thus VMCS shadowing should not be
10022 * enabled while executing the nested-guest.
10023 */
10024 Assert(!(u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING));
10025
10026 /*
10027 * APIC-access page.
10028 */
10029 RTHCPHYS HCPhysApicAccess;
10030 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10031 {
10032 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
10033 RTGCPHYS const GCPhysApicAccess = pVmcsNstGst->u64AddrApicAccess.u;
10034
10035 /** @todo NSTVMX: This is not really correct but currently is required to make
10036 * things work. We need to re-enable the page handler when we fallback to
10037 * IEM execution of the nested-guest! */
10038 PGMHandlerPhysicalPageTempOff(pVM, GCPhysApicAccess, GCPhysApicAccess);
10039
10040 void *pvPage;
10041 PGMPAGEMAPLOCK PgLockApicAccess;
10042 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysApicAccess, &pvPage, &PgLockApicAccess);
10043 if (RT_SUCCESS(rc))
10044 {
10045 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysApicAccess, &HCPhysApicAccess);
10046 AssertMsgRCReturn(rc, ("Failed to get host-physical address for APIC-access page at %#RGp\n", GCPhysApicAccess), rc);
10047
10048 /** @todo Handle proper releasing of page-mapping lock later. */
10049 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockApicAccess);
10050 }
10051 else
10052 return rc;
10053 }
10054 else
10055 HCPhysApicAccess = 0;
10056
10057 /*
10058 * Virtual-APIC page and TPR threshold.
10059 */
10060 PVMXVMCSINFO pVmcsInfoNstGst = &pVCpu->hm.s.vmx.VmcsInfoNstGst;
10061 RTHCPHYS HCPhysVirtApic;
10062 uint32_t u32TprThreshold;
10063 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10064 {
10065 Assert(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW);
10066 RTGCPHYS const GCPhysVirtApic = pVmcsNstGst->u64AddrVirtApic.u;
10067
10068 void *pvPage;
10069 PGMPAGEMAPLOCK PgLockVirtApic;
10070 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysVirtApic, &pvPage, &PgLockVirtApic);
10071 if (RT_SUCCESS(rc))
10072 {
10073 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysVirtApic, &HCPhysVirtApic);
10074 AssertMsgRCReturn(rc, ("Failed to get host-physical address for virtual-APIC page at %#RGp\n", GCPhysVirtApic), rc);
10075
10076 /** @todo Handle proper releasing of page-mapping lock later. */
10077 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockVirtApic);
10078 }
10079 else
10080 return rc;
10081
10082 u32TprThreshold = pVmcsNstGst->u32TprThreshold;
10083 }
10084 else
10085 {
10086 HCPhysVirtApic = 0;
10087 u32TprThreshold = 0;
10088
10089 /*
10090 * We must make sure CR8 reads/write must cause VM-exits when TPR shadowing is not
10091 * used by the guest hypervisor. Preventing MMIO accesses to the physical APIC will
10092 * be taken care of by EPT/shadow paging.
10093 */
10094 if (pVM->hm.s.fAllow64BitGuests)
10095 {
10096 u32ProcCtls |= VMX_PROC_CTLS_CR8_STORE_EXIT
10097 | VMX_PROC_CTLS_CR8_LOAD_EXIT;
10098 }
10099 }
10100
10101 /*
10102 * Validate basic assumptions.
10103 */
10104 Assert(pVM->hm.s.vmx.fAllowUnrestricted);
10105 Assert(pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
10106 Assert(hmGetVmxActiveVmcsInfo(pVCpu) == pVmcsInfoNstGst);
10107
10108 /*
10109 * Commit it to the nested-guest VMCS.
10110 */
10111 int rc = VINF_SUCCESS;
10112 if (pVmcsInfoNstGst->u32PinCtls != u32PinCtls)
10113 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, u32PinCtls);
10114 if (pVmcsInfoNstGst->u32ProcCtls != u32ProcCtls)
10115 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, u32ProcCtls);
10116 if (pVmcsInfoNstGst->u32ProcCtls2 != u32ProcCtls2)
10117 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, u32ProcCtls2);
10118 if (pVmcsInfoNstGst->u32XcptBitmap != u32XcptBitmap)
10119 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
10120 if (pVmcsInfoNstGst->u64Cr0Mask != u64Cr0Mask)
10121 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask);
10122 if (pVmcsInfoNstGst->u64Cr4Mask != u64Cr4Mask)
10123 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask);
10124 if (pVmcsInfoNstGst->u32XcptPFMask != u32XcptPFMask)
10125 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, u32XcptPFMask);
10126 if (pVmcsInfoNstGst->u32XcptPFMatch != u32XcptPFMatch)
10127 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, u32XcptPFMatch);
10128 if ( !(u32ProcCtls & VMX_PROC_CTLS_PAUSE_EXIT)
10129 && (u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
10130 {
10131 Assert(pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT);
10132 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, cPleGapTicks);
10133 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, cPleWindowTicks);
10134 }
10135 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10136 {
10137 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
10138 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
10139 }
10140 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10141 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
10142 rc |= VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, uPendingDbgXcpts);
10143 AssertRC(rc);
10144
10145 /*
10146 * Update the nested-guest VMCS cache.
10147 */
10148 pVmcsInfoNstGst->u32PinCtls = u32PinCtls;
10149 pVmcsInfoNstGst->u32ProcCtls = u32ProcCtls;
10150 pVmcsInfoNstGst->u32ProcCtls2 = u32ProcCtls2;
10151 pVmcsInfoNstGst->u32XcptBitmap = u32XcptBitmap;
10152 pVmcsInfoNstGst->u64Cr0Mask = u64Cr0Mask;
10153 pVmcsInfoNstGst->u64Cr4Mask = u64Cr4Mask;
10154 pVmcsInfoNstGst->u32XcptPFMask = u32XcptPFMask;
10155 pVmcsInfoNstGst->u32XcptPFMatch = u32XcptPFMatch;
10156 pVmcsInfoNstGst->HCPhysVirtApic = HCPhysVirtApic;
10157
10158 /*
10159 * We need to flush the TLB if we are switching the APIC-access page address.
10160 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
10161 */
10162 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10163 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = true;
10164
10165 /*
10166 * MSR bitmap.
10167 *
10168 * The MSR bitmap address has already been initialized while setting up the nested-guest
10169 * VMCS, here we need to merge the MSR bitmaps.
10170 */
10171 if (u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10172 hmR0VmxMergeMsrBitmapNested(pVCpu, pVmcsInfoNstGst, pVmcsInfoGst);
10173
10174 return VINF_SUCCESS;
10175}
10176#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10177
10178
10179/**
10180 * Does the preparations before executing guest code in VT-x.
10181 *
10182 * This may cause longjmps to ring-3 and may even result in rescheduling to the
10183 * recompiler/IEM. We must be cautious what we do here regarding committing
10184 * guest-state information into the VMCS assuming we assuredly execute the
10185 * guest in VT-x mode.
10186 *
10187 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
10188 * the common-state (TRPM/forceflags), we must undo those changes so that the
10189 * recompiler/IEM can (and should) use them when it resumes guest execution.
10190 * Otherwise such operations must be done when we can no longer exit to ring-3.
10191 *
10192 * @returns Strict VBox status code (i.e. informational status codes too).
10193 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
10194 * have been disabled.
10195 * @retval VINF_VMX_VMEXIT if a nested-guest VM-exit occurs (e.g., while evaluating
10196 * pending events).
10197 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
10198 * double-fault into the guest.
10199 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
10200 * dispatched directly.
10201 * @retval VINF_* scheduling changes, we have to go back to ring-3.
10202 *
10203 * @param pVCpu The cross context virtual CPU structure.
10204 * @param pVmxTransient The VMX-transient structure.
10205 * @param fStepping Whether we are single-stepping the guest in the
10206 * hypervisor debugger. Makes us ignore some of the reasons
10207 * for returning to ring-3, and return VINF_EM_DBG_STEPPED
10208 * if event dispatching took place.
10209 */
10210static VBOXSTRICTRC hmR0VmxPreRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, bool fStepping)
10211{
10212 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10213
10214 Log4Func(("fIsNested=%RTbool fStepping=%RTbool\n", pVmxTransient->fIsNestedGuest, fStepping));
10215
10216#ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
10217 if (pVmxTransient->fIsNestedGuest)
10218 {
10219 RT_NOREF2(pVCpu, fStepping);
10220 Log2Func(("Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
10221 return VINF_EM_RESCHEDULE_REM;
10222 }
10223#endif
10224
10225#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
10226 PGMRZDynMapFlushAutoSet(pVCpu);
10227#endif
10228
10229 /*
10230 * Check and process force flag actions, some of which might require us to go back to ring-3.
10231 */
10232 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVCpu, fStepping);
10233 if (rcStrict == VINF_SUCCESS)
10234 {
10235 /* FFs don't get set all the time. */
10236#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10237 if ( pVmxTransient->fIsNestedGuest
10238 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10239 {
10240 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10241 return VINF_VMX_VMEXIT;
10242 }
10243#endif
10244 }
10245 else
10246 return rcStrict;
10247
10248 /*
10249 * Virtualize memory-mapped accesses to the physical APIC (may take locks).
10250 */
10251 /** @todo Doing this from ring-3 after VM setup phase causes a
10252 * VERR_IOM_MMIO_RANGE_NOT_FOUND guru while booting Visa 64 SMP VM. No
10253 * idea why atm. */
10254 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10255 if ( !pVCpu->hm.s.vmx.u64GstMsrApicBase
10256 && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10257 && PDMHasApic(pVM))
10258 {
10259 int rc = hmR0VmxMapHCApicAccessPage(pVCpu);
10260 AssertRCReturn(rc, rc);
10261 }
10262
10263#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10264 /*
10265 * Merge guest VMCS controls with the nested-guest VMCS controls.
10266 *
10267 * Even if we have not executed the guest prior to this (e.g. when resuming from a
10268 * saved state), we should be okay with merging controls as we initialize the
10269 * guest VMCS controls as part of VM setup phase.
10270 */
10271 if ( pVmxTransient->fIsNestedGuest
10272 && !pVCpu->hm.s.vmx.fMergedNstGstCtls)
10273 {
10274 int rc = hmR0VmxMergeVmcsNested(pVCpu);
10275 AssertRCReturn(rc, rc);
10276 pVCpu->hm.s.vmx.fMergedNstGstCtls = true;
10277 }
10278#endif
10279
10280 /*
10281 * Evaluate events to be injected into the guest.
10282 *
10283 * Events in TRPM can be injected without inspecting the guest state.
10284 * If any new events (interrupts/NMI) are pending currently, we try to set up the
10285 * guest to cause a VM-exit the next time they are ready to receive the event.
10286 *
10287 * With nested-guests, evaluating pending events may cause VM-exits.
10288 */
10289 if (TRPMHasTrap(pVCpu))
10290 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
10291
10292 uint32_t fIntrState;
10293 rcStrict = hmR0VmxEvaluatePendingEvent(pVCpu, pVmxTransient, &fIntrState);
10294
10295#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10296 /*
10297 * While evaluating pending events if something failed (unlikely) or if we were
10298 * preparing to run a nested-guest but performed a nested-guest VM-exit, we should bail.
10299 */
10300 if (rcStrict != VINF_SUCCESS)
10301 return rcStrict;
10302 if ( pVmxTransient->fIsNestedGuest
10303 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10304 {
10305 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10306 return VINF_VMX_VMEXIT;
10307 }
10308#else
10309 Assert(rcStrict == VINF_SUCCESS);
10310#endif
10311
10312 /*
10313 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus
10314 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might
10315 * also result in triple-faulting the VM.
10316 *
10317 * With nested-guests, the above does not apply since unrestricted guest execution is a
10318 * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
10319 */
10320 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pVmxTransient, fIntrState, fStepping);
10321 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10322 { /* likely */ }
10323 else
10324 {
10325 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
10326 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
10327 return rcStrict;
10328 }
10329
10330 /*
10331 * A longjump might result in importing CR3 even for VM-exits that don't necessarily
10332 * import CR3 themselves. We will need to update them here, as even as late as the above
10333 * hmR0VmxInjectPendingEvent() call may lazily import guest-CPU state on demand causing
10334 * the below force flags to be set.
10335 */
10336 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
10337 {
10338 Assert(!(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_CR3));
10339 int rc2 = PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
10340 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
10341 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
10342 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10343 }
10344 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
10345 {
10346 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
10347 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10348 }
10349
10350#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10351 /* Paranoia. */
10352 Assert(!pVmxTransient->fIsNestedGuest || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10353#endif
10354
10355 /*
10356 * No longjmps to ring-3 from this point on!!!
10357 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
10358 * This also disables flushing of the R0-logger instance (if any).
10359 */
10360 VMMRZCallRing3Disable(pVCpu);
10361
10362 /*
10363 * Export the guest state bits.
10364 *
10365 * We cannot perform longjmps while loading the guest state because we do not preserve the
10366 * host/guest state (although the VMCS will be preserved) across longjmps which can cause
10367 * CPU migration.
10368 *
10369 * If we are injecting events to a real-on-v86 mode guest, we would have updated RIP and some segment
10370 * registers. Hence, exporting of the guest state needs to be done -after- injection of events.
10371 */
10372 rcStrict = hmR0VmxExportGuestStateOptimal(pVCpu, pVmxTransient);
10373 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10374 { /* likely */ }
10375 else
10376 {
10377 VMMRZCallRing3Enable(pVCpu);
10378 return rcStrict;
10379 }
10380
10381 /*
10382 * We disable interrupts so that we don't miss any interrupts that would flag preemption
10383 * (IPI/timers etc.) when thread-context hooks aren't used and we've been running with
10384 * preemption disabled for a while. Since this is purely to aid the
10385 * RTThreadPreemptIsPending() code, it doesn't matter that it may temporarily reenable and
10386 * disable interrupt on NT.
10387 *
10388 * We need to check for force-flags that could've possible been altered since we last
10389 * checked them (e.g. by PDMGetInterrupt() leaving the PDM critical section,
10390 * see @bugref{6398}).
10391 *
10392 * We also check a couple of other force-flags as a last opportunity to get the EMT back
10393 * to ring-3 before executing guest code.
10394 */
10395 pVmxTransient->fEFlags = ASMIntDisableFlags();
10396
10397 if ( ( !VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
10398 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
10399 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
10400 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
10401 {
10402 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
10403 {
10404#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10405 /*
10406 * If we are executing a nested-guest make sure that we should intercept subsequent
10407 * events. The one we are injecting might be part of VM-entry. This is mainly to keep
10408 * the VM-exit instruction emulation happy.
10409 */
10410 if (pVmxTransient->fIsNestedGuest)
10411 pVCpu->cpum.GstCtx.hwvirt.vmx.fInterceptEvents = true;
10412#endif
10413
10414 /*
10415 * We've injected any pending events. This is really the point of no return (to ring-3).
10416 *
10417 * Note! The caller expects to continue with interrupts & longjmps disabled on successful
10418 * returns from this function, so do -not- enable them here.
10419 */
10420 pVCpu->hm.s.Event.fPending = false;
10421 return VINF_SUCCESS;
10422 }
10423
10424 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPendingHostIrq);
10425 rcStrict = VINF_EM_RAW_INTERRUPT;
10426 }
10427 else
10428 {
10429 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
10430 rcStrict = VINF_EM_RAW_TO_R3;
10431 }
10432
10433 ASMSetFlags(pVmxTransient->fEFlags);
10434 VMMRZCallRing3Enable(pVCpu);
10435
10436 return rcStrict;
10437}
10438
10439
10440/**
10441 * Final preparations before executing guest code using hardware-assisted VMX.
10442 *
10443 * We can no longer get preempted to a different host CPU and there are no returns
10444 * to ring-3. We ignore any errors that may happen from this point (e.g. VMWRITE
10445 * failures), this function is not intended to fail sans unrecoverable hardware
10446 * errors.
10447 *
10448 * @param pVCpu The cross context virtual CPU structure.
10449 * @param pVmxTransient The VMX-transient structure.
10450 *
10451 * @remarks Called with preemption disabled.
10452 * @remarks No-long-jump zone!!!
10453 */
10454static void hmR0VmxPreRunGuestCommitted(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10455{
10456 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10457 Assert(VMMR0IsLogFlushDisabled(pVCpu));
10458 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
10459 Assert(!pVCpu->hm.s.Event.fPending);
10460
10461 /*
10462 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
10463 */
10464 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10465 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
10466
10467 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10468 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10469 PHMPHYSCPU pHostCpu = hmR0GetCurrentCpu();
10470 RTCPUID const idCurrentCpu = pHostCpu->idCpu;
10471
10472 if (!CPUMIsGuestFPUStateActive(pVCpu))
10473 {
10474 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10475 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
10476 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_HOST_CONTEXT;
10477 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10478 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadGuestFpu);
10479 }
10480
10481 /*
10482 * Re-export the host state bits as we may've been preempted (only happens when
10483 * thread-context hooks are used or when the VM start function changes) or if
10484 * the host CR0 is modified while loading the guest FPU state above.
10485 *
10486 * The 64-on-32 switcher saves the (64-bit) host state into the VMCS and if we
10487 * changed the switcher back to 32-bit, we *must* save the 32-bit host state here,
10488 * see @bugref{8432}.
10489 *
10490 * This may also happen when switching to/from a nested-guest VMCS without leaving
10491 * ring-0.
10492 */
10493 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
10494 {
10495 hmR0VmxExportHostState(pVCpu);
10496 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportHostState);
10497 }
10498 Assert(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT));
10499
10500 /*
10501 * Export the state shared between host and guest (FPU, debug, lazy MSRs).
10502 */
10503 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)
10504 hmR0VmxExportSharedState(pVCpu, pVmxTransient);
10505 AssertMsg(!pVCpu->hm.s.fCtxChanged, ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
10506
10507 /*
10508 * Store status of the shared guest/host debug state at the time of VM-entry.
10509 */
10510 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
10511 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
10512
10513 /*
10514 * Always cache the TPR-shadow if the virtual-APIC page exists, thereby skipping
10515 * more than one conditional check. The post-run side of our code shall determine
10516 * if it needs to sync. the virtual APIC TPR with the TPR-shadow.
10517 */
10518 if (pVmcsInfo->pbVirtApic)
10519 pVmxTransient->u8GuestTpr = pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR];
10520
10521 /*
10522 * Update the host MSRs values in the VM-exit MSR-load area.
10523 */
10524 if (!pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs)
10525 {
10526 if (pVmcsInfo->cExitMsrLoad > 0)
10527 hmR0VmxUpdateAutoLoadHostMsrs(pVCpu, pVmcsInfo);
10528 pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs = true;
10529 }
10530
10531 /*
10532 * Evaluate if we need to intercept guest RDTSC/P accesses. Set up the
10533 * VMX-preemption timer based on the next virtual sync clock deadline.
10534 */
10535 if ( !pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer
10536 || idCurrentCpu != pVCpu->hm.s.idLastCpu)
10537 {
10538 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVCpu, pVmxTransient);
10539 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = true;
10540 }
10541
10542 /* Record statistics of how often we use TSC offsetting as opposed to intercepting RDTSC/P. */
10543 bool const fIsRdtscIntercepted = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT);
10544 if (!fIsRdtscIntercepted)
10545 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
10546 else
10547 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
10548
10549 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
10550 hmR0VmxFlushTaggedTlb(pHostCpu, pVCpu, pVmcsInfo); /* Invalidate the appropriate guest entries from the TLB. */
10551 Assert(idCurrentCpu == pVCpu->hm.s.idLastCpu);
10552 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Update the error reporting info. with the current host CPU. */
10553 pVmcsInfo->idHostCpu = idCurrentCpu; /* Update the CPU for which we updated host-state in this VMCS. */
10554
10555 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
10556
10557 TMNotifyStartOfExecution(pVM, pVCpu); /* Notify TM to resume its clocks when TSC is tied to execution,
10558 as we're about to start executing the guest . */
10559
10560 /*
10561 * Load the guest TSC_AUX MSR when we are not intercepting RDTSCP.
10562 *
10563 * This is done this late as updating the TSC offsetting/preemption timer above
10564 * figures out if we can skip intercepting RDTSCP by calculating the number of
10565 * host CPU ticks till the next virtual sync deadline (for the dynamic case).
10566 */
10567 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_RDTSCP)
10568 && !fIsRdtscIntercepted)
10569 {
10570 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_TSC_AUX);
10571
10572 /* NB: Because we call hmR0VmxAddAutoLoadStoreMsr with fUpdateHostMsr=true,
10573 it's safe even after hmR0VmxUpdateAutoLoadHostMsrs has already been done. */
10574 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX, CPUMGetGuestTscAux(pVCpu),
10575 true /* fSetReadWrite */, true /* fUpdateHostMsr */);
10576 AssertRC(rc);
10577 Assert(!pVmxTransient->fRemoveTscAuxMsr);
10578 pVmxTransient->fRemoveTscAuxMsr = true;
10579 }
10580
10581#ifdef VBOX_STRICT
10582 Assert(pVCpu->hm.s.vmx.fUpdatedHostAutoMsrs);
10583 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
10584 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo);
10585 AssertRC(hmR0VmxCheckVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest));
10586#endif
10587
10588#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
10589 /** @todo r=ramshankar: We can now probably use iemVmxVmentryCheckGuestState here.
10590 * Add a PVMXMSRS parameter to it, so that IEM can look at the host MSRs,
10591 * see @bugref{9180#c54}. */
10592 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
10593 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
10594 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
10595#endif
10596}
10597
10598
10599/**
10600 * First C routine invoked after running guest code using hardware-assisted VMX.
10601 *
10602 * @param pVCpu The cross context virtual CPU structure.
10603 * @param pVmxTransient The VMX-transient structure.
10604 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
10605 *
10606 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
10607 *
10608 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
10609 * unconditionally when it is safe to do so.
10610 */
10611static void hmR0VmxPostRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, int rcVMRun)
10612{
10613 uint64_t const uHostTsc = ASMReadTSC(); /** @todo We can do a lot better here, see @bugref{9180#c38}. */
10614
10615 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
10616 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
10617 pVCpu->hm.s.fCtxChanged = 0; /* Exits/longjmps to ring-3 requires saving the guest state. */
10618 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
10619 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
10620 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
10621
10622 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10623 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
10624 {
10625 uint64_t uGstTsc;
10626 if (!pVmxTransient->fIsNestedGuest)
10627 uGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
10628 else
10629 {
10630 uint64_t const uNstGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
10631 uGstTsc = CPUMRemoveNestedGuestTscOffset(pVCpu, uNstGstTsc);
10632 }
10633 TMCpuTickSetLastSeen(pVCpu, uGstTsc); /* Update TM with the guest TSC. */
10634 }
10635
10636 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatPreExit, x);
10637 TMNotifyEndOfExecution(pVCpu->CTX_SUFF(pVM), pVCpu); /* Notify TM that the guest is no longer running. */
10638 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10639
10640 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Some host state messed up by VMX needs restoring. */
10641 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
10642#ifdef VBOX_STRICT
10643 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo); /* Verify that the host EFER MSR wasn't modified. */
10644#endif
10645 Assert(!ASMIntAreEnabled());
10646 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
10647 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10648
10649#ifdef HMVMX_ALWAYS_CLEAN_TRANSIENT
10650 /*
10651 * Clean all the VMCS fields in the transient structure before reading
10652 * anything from the VMCS.
10653 */
10654 pVmxTransient->uExitReason = 0;
10655 pVmxTransient->uExitIntErrorCode = 0;
10656 pVmxTransient->uExitQual = 0;
10657 pVmxTransient->uGuestLinearAddr = 0;
10658 pVmxTransient->uExitIntInfo = 0;
10659 pVmxTransient->cbExitInstr = 0;
10660 pVmxTransient->ExitInstrInfo.u = 0;
10661 pVmxTransient->uEntryIntInfo = 0;
10662 pVmxTransient->uEntryXcptErrorCode = 0;
10663 pVmxTransient->cbEntryInstr = 0;
10664 pVmxTransient->uIdtVectoringInfo = 0;
10665 pVmxTransient->uIdtVectoringErrorCode = 0;
10666#endif
10667
10668 /*
10669 * Save the basic VM-exit reason and check if the VM-entry failed.
10670 * See Intel spec. 24.9.1 "Basic VM-exit Information".
10671 */
10672 uint32_t uExitReason;
10673 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
10674 AssertRC(rc);
10675 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason);
10676 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
10677
10678 /*
10679 * Log the VM-exit before logging anything else as otherwise it might be a
10680 * tad confusing what happens before and after the world-switch.
10681 */
10682 HMVMX_LOG_EXIT(pVCpu, uExitReason);
10683
10684 /*
10685 * Remove the TSC_AUX MSR from the auto-load/store MSR area and reset any MSR
10686 * bitmap permissions, if it was added before VM-entry.
10687 */
10688 if (pVmxTransient->fRemoveTscAuxMsr)
10689 {
10690 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX);
10691 pVmxTransient->fRemoveTscAuxMsr = false;
10692 }
10693
10694 /*
10695 * Check if VMLAUNCH/VMRESUME succeeded.
10696 * If this failed, we cause a guru meditation and cease further execution.
10697 *
10698 * However, if we are executing a nested-guest we might fail if we use the
10699 * fast path rather than fully emulating VMLAUNCH/VMRESUME instruction in IEM.
10700 */
10701 if (RT_LIKELY(rcVMRun == VINF_SUCCESS))
10702 {
10703 /*
10704 * Update the VM-exit history array here even if the VM-entry failed due to:
10705 * - Invalid guest state.
10706 * - MSR loading.
10707 * - Machine-check event.
10708 *
10709 * In any of the above cases we will still have a "valid" VM-exit reason
10710 * despite @a fVMEntryFailed being false.
10711 *
10712 * See Intel spec. 26.7 "VM-Entry failures during or after loading guest state".
10713 *
10714 * Note! We don't have CS or RIP at this point. Will probably address that later
10715 * by amending the history entry added here.
10716 */
10717 EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_VMX, pVmxTransient->uExitReason & EMEXIT_F_TYPE_MASK),
10718 UINT64_MAX, uHostTsc);
10719
10720 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
10721 {
10722 VMMRZCallRing3Enable(pVCpu);
10723
10724 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10725 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10726
10727#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
10728 hmR0VmxReadAllRoFieldsVmcs(pVmxTransient);
10729#endif
10730#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
10731 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
10732 AssertRC(rc);
10733#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
10734 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_RFLAGS);
10735 AssertRC(rc);
10736#else
10737 /*
10738 * Import the guest-interruptibility state always as we need it while evaluating
10739 * injecting events on re-entry.
10740 *
10741 * We don't import CR0 (when unrestricted guest execution is unavailable) despite
10742 * checking for real-mode while exporting the state because all bits that cause
10743 * mode changes wrt CR0 are intercepted.
10744 */
10745 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_HM_VMX_INT_STATE);
10746 AssertRC(rc);
10747#endif
10748
10749 /*
10750 * Sync the TPR shadow with our APIC state.
10751 */
10752 if ( !pVmxTransient->fIsNestedGuest
10753 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
10754 {
10755 Assert(pVmcsInfo->pbVirtApic);
10756 if (pVmxTransient->u8GuestTpr != pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR])
10757 {
10758 rc = APICSetTpr(pVCpu, pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR]);
10759 AssertRC(rc);
10760 ASMAtomicOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
10761 }
10762 }
10763
10764 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10765 return;
10766 }
10767 }
10768#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10769 else if (pVmxTransient->fIsNestedGuest)
10770 AssertMsgFailed(("VMLAUNCH/VMRESUME failed but shouldn't happen when VMLAUNCH/VMRESUME was emulated in IEM!\n"));
10771#endif
10772 else
10773 Log4Func(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
10774
10775 VMMRZCallRing3Enable(pVCpu);
10776}
10777
10778
10779/**
10780 * Runs the guest code using hardware-assisted VMX the normal way.
10781 *
10782 * @returns VBox status code.
10783 * @param pVCpu The cross context virtual CPU structure.
10784 * @param pcLoops Pointer to the number of executed loops.
10785 */
10786static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVMCPUCC pVCpu, uint32_t *pcLoops)
10787{
10788 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
10789 Assert(pcLoops);
10790 Assert(*pcLoops <= cMaxResumeLoops);
10791 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10792
10793#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10794 /*
10795 * Switch to the guest VMCS as we may have transitioned from executing the nested-guest
10796 * without leaving ring-0. Otherwise, if we came from ring-3 we would have loaded the
10797 * guest VMCS while entering the VMX ring-0 session.
10798 */
10799 if (pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs)
10800 {
10801 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, false /* fSwitchToNstGstVmcs */);
10802 if (RT_SUCCESS(rc))
10803 { /* likely */ }
10804 else
10805 {
10806 LogRelFunc(("Failed to switch to the guest VMCS. rc=%Rrc\n", rc));
10807 return rc;
10808 }
10809 }
10810#endif
10811
10812 VMXTRANSIENT VmxTransient;
10813 RT_ZERO(VmxTransient);
10814 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
10815
10816 /* Paranoia. */
10817 Assert(VmxTransient.pVmcsInfo == &pVCpu->hm.s.vmx.VmcsInfo);
10818
10819 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10820 for (;;)
10821 {
10822 Assert(!HMR0SuspendPending());
10823 HMVMX_ASSERT_CPU_SAFE(pVCpu);
10824 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10825
10826 /*
10827 * Preparatory work for running nested-guest code, this may force us to
10828 * return to ring-3.
10829 *
10830 * Warning! This bugger disables interrupts on VINF_SUCCESS!
10831 */
10832 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
10833 if (rcStrict != VINF_SUCCESS)
10834 break;
10835
10836 /* Interrupts are disabled at this point! */
10837 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
10838 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
10839 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
10840 /* Interrupts are re-enabled at this point! */
10841
10842 /*
10843 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
10844 */
10845 if (RT_SUCCESS(rcRun))
10846 { /* very likely */ }
10847 else
10848 {
10849 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
10850 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
10851 return rcRun;
10852 }
10853
10854 /*
10855 * Profile the VM-exit.
10856 */
10857 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10858 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10859 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10860 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
10861 HMVMX_START_EXIT_DISPATCH_PROF();
10862
10863 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
10864
10865 /*
10866 * Handle the VM-exit.
10867 */
10868#ifdef HMVMX_USE_FUNCTION_TABLE
10869 rcStrict = g_apfnVMExitHandlers[VmxTransient.uExitReason](pVCpu, &VmxTransient);
10870#else
10871 rcStrict = hmR0VmxHandleExit(pVCpu, &VmxTransient);
10872#endif
10873 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
10874 if (rcStrict == VINF_SUCCESS)
10875 {
10876 if (++(*pcLoops) <= cMaxResumeLoops)
10877 continue;
10878 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10879 rcStrict = VINF_EM_RAW_INTERRUPT;
10880 }
10881 break;
10882 }
10883
10884 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10885 return rcStrict;
10886}
10887
10888
10889#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10890/**
10891 * Runs the nested-guest code using hardware-assisted VMX.
10892 *
10893 * @returns VBox status code.
10894 * @param pVCpu The cross context virtual CPU structure.
10895 * @param pcLoops Pointer to the number of executed loops.
10896 *
10897 * @sa hmR0VmxRunGuestCodeNormal.
10898 */
10899static VBOXSTRICTRC hmR0VmxRunGuestCodeNested(PVMCPUCC pVCpu, uint32_t *pcLoops)
10900{
10901 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
10902 Assert(pcLoops);
10903 Assert(*pcLoops <= cMaxResumeLoops);
10904 Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10905
10906 /*
10907 * Switch to the nested-guest VMCS as we may have transitioned from executing the
10908 * guest without leaving ring-0. Otherwise, if we came from ring-3 we would have
10909 * loaded the nested-guest VMCS while entering the VMX ring-0 session.
10910 */
10911 if (!pVCpu->hm.s.vmx.fSwitchedToNstGstVmcs)
10912 {
10913 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, true /* fSwitchToNstGstVmcs */);
10914 if (RT_SUCCESS(rc))
10915 { /* likely */ }
10916 else
10917 {
10918 LogRelFunc(("Failed to switch to the nested-guest VMCS. rc=%Rrc\n", rc));
10919 return rc;
10920 }
10921 }
10922
10923 VMXTRANSIENT VmxTransient;
10924 RT_ZERO(VmxTransient);
10925 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
10926 VmxTransient.fIsNestedGuest = true;
10927
10928 /* Paranoia. */
10929 Assert(VmxTransient.pVmcsInfo == &pVCpu->hm.s.vmx.VmcsInfoNstGst);
10930
10931 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10932 for (;;)
10933 {
10934 Assert(!HMR0SuspendPending());
10935 HMVMX_ASSERT_CPU_SAFE(pVCpu);
10936 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10937
10938 /*
10939 * Preparatory work for running guest code, this may force us to
10940 * return to ring-3.
10941 *
10942 * Warning! This bugger disables interrupts on VINF_SUCCESS!
10943 */
10944 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
10945 if (rcStrict != VINF_SUCCESS)
10946 break;
10947
10948 /* Interrupts are disabled at this point! */
10949 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
10950 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
10951 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
10952 /* Interrupts are re-enabled at this point! */
10953
10954 /*
10955 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
10956 */
10957 if (RT_SUCCESS(rcRun))
10958 { /* very likely */ }
10959 else
10960 {
10961 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
10962 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
10963 return rcRun;
10964 }
10965
10966 /*
10967 * Profile the VM-exit.
10968 */
10969 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10970 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10971 STAM_COUNTER_INC(&pVCpu->hm.s.StatNestedExitAll);
10972 STAM_COUNTER_INC(&pVCpu->hm.s.paStatNestedExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10973 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
10974 HMVMX_START_EXIT_DISPATCH_PROF();
10975
10976 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
10977
10978 /*
10979 * Handle the VM-exit.
10980 */
10981 rcStrict = hmR0VmxHandleExitNested(pVCpu, &VmxTransient);
10982 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
10983 if (rcStrict == VINF_SUCCESS)
10984 {
10985 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10986 {
10987 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10988 rcStrict = VINF_VMX_VMEXIT;
10989 }
10990 else
10991 {
10992 if (++(*pcLoops) <= cMaxResumeLoops)
10993 continue;
10994 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10995 rcStrict = VINF_EM_RAW_INTERRUPT;
10996 }
10997 }
10998 else
10999 Assert(rcStrict != VINF_VMX_VMEXIT);
11000 break;
11001 }
11002
11003 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
11004 return rcStrict;
11005}
11006#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
11007
11008
11009/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
11010 * probes.
11011 *
11012 * The following few functions and associated structure contains the bloat
11013 * necessary for providing detailed debug events and dtrace probes as well as
11014 * reliable host side single stepping. This works on the principle of
11015 * "subclassing" the normal execution loop and workers. We replace the loop
11016 * method completely and override selected helpers to add necessary adjustments
11017 * to their core operation.
11018 *
11019 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
11020 * any performance for debug and analysis features.
11021 *
11022 * @{
11023 */
11024
11025/**
11026 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
11027 * the debug run loop.
11028 */
11029typedef struct VMXRUNDBGSTATE
11030{
11031 /** The RIP we started executing at. This is for detecting that we stepped. */
11032 uint64_t uRipStart;
11033 /** The CS we started executing with. */
11034 uint16_t uCsStart;
11035
11036 /** Whether we've actually modified the 1st execution control field. */
11037 bool fModifiedProcCtls : 1;
11038 /** Whether we've actually modified the 2nd execution control field. */
11039 bool fModifiedProcCtls2 : 1;
11040 /** Whether we've actually modified the exception bitmap. */
11041 bool fModifiedXcptBitmap : 1;
11042
11043 /** We desire the modified the CR0 mask to be cleared. */
11044 bool fClearCr0Mask : 1;
11045 /** We desire the modified the CR4 mask to be cleared. */
11046 bool fClearCr4Mask : 1;
11047 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
11048 uint32_t fCpe1Extra;
11049 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
11050 uint32_t fCpe1Unwanted;
11051 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
11052 uint32_t fCpe2Extra;
11053 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
11054 uint32_t bmXcptExtra;
11055 /** The sequence number of the Dtrace provider settings the state was
11056 * configured against. */
11057 uint32_t uDtraceSettingsSeqNo;
11058 /** VM-exits to check (one bit per VM-exit). */
11059 uint32_t bmExitsToCheck[3];
11060
11061 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
11062 uint32_t fProcCtlsInitial;
11063 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
11064 uint32_t fProcCtls2Initial;
11065 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
11066 uint32_t bmXcptInitial;
11067} VMXRUNDBGSTATE;
11068AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
11069typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
11070
11071
11072/**
11073 * Initializes the VMXRUNDBGSTATE structure.
11074 *
11075 * @param pVCpu The cross context virtual CPU structure of the
11076 * calling EMT.
11077 * @param pVmxTransient The VMX-transient structure.
11078 * @param pDbgState The debug state to initialize.
11079 */
11080static void hmR0VmxRunDebugStateInit(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11081{
11082 pDbgState->uRipStart = pVCpu->cpum.GstCtx.rip;
11083 pDbgState->uCsStart = pVCpu->cpum.GstCtx.cs.Sel;
11084
11085 pDbgState->fModifiedProcCtls = false;
11086 pDbgState->fModifiedProcCtls2 = false;
11087 pDbgState->fModifiedXcptBitmap = false;
11088 pDbgState->fClearCr0Mask = false;
11089 pDbgState->fClearCr4Mask = false;
11090 pDbgState->fCpe1Extra = 0;
11091 pDbgState->fCpe1Unwanted = 0;
11092 pDbgState->fCpe2Extra = 0;
11093 pDbgState->bmXcptExtra = 0;
11094 pDbgState->fProcCtlsInitial = pVmxTransient->pVmcsInfo->u32ProcCtls;
11095 pDbgState->fProcCtls2Initial = pVmxTransient->pVmcsInfo->u32ProcCtls2;
11096 pDbgState->bmXcptInitial = pVmxTransient->pVmcsInfo->u32XcptBitmap;
11097}
11098
11099
11100/**
11101 * Updates the VMSC fields with changes requested by @a pDbgState.
11102 *
11103 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
11104 * immediately before executing guest code, i.e. when interrupts are disabled.
11105 * We don't check status codes here as we cannot easily assert or return in the
11106 * latter case.
11107 *
11108 * @param pVCpu The cross context virtual CPU structure.
11109 * @param pVmxTransient The VMX-transient structure.
11110 * @param pDbgState The debug state.
11111 */
11112static void hmR0VmxPreRunGuestDebugStateApply(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11113{
11114 /*
11115 * Ensure desired flags in VMCS control fields are set.
11116 * (Ignoring write failure here, as we're committed and it's just debug extras.)
11117 *
11118 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
11119 * there should be no stale data in pCtx at this point.
11120 */
11121 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11122 if ( (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
11123 || (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Unwanted))
11124 {
11125 pVmcsInfo->u32ProcCtls |= pDbgState->fCpe1Extra;
11126 pVmcsInfo->u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
11127 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
11128 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVmcsInfo->u32ProcCtls));
11129 pDbgState->fModifiedProcCtls = true;
11130 }
11131
11132 if ((pVmcsInfo->u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
11133 {
11134 pVmcsInfo->u32ProcCtls2 |= pDbgState->fCpe2Extra;
11135 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVmcsInfo->u32ProcCtls2);
11136 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVmcsInfo->u32ProcCtls2));
11137 pDbgState->fModifiedProcCtls2 = true;
11138 }
11139
11140 if ((pVmcsInfo->u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
11141 {
11142 pVmcsInfo->u32XcptBitmap |= pDbgState->bmXcptExtra;
11143 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVmcsInfo->u32XcptBitmap);
11144 Log6Func(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVmcsInfo->u32XcptBitmap));
11145 pDbgState->fModifiedXcptBitmap = true;
11146 }
11147
11148 if (pDbgState->fClearCr0Mask && pVmcsInfo->u64Cr0Mask != 0)
11149 {
11150 pVmcsInfo->u64Cr0Mask = 0;
11151 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, 0);
11152 Log6Func(("VMX_VMCS_CTRL_CR0_MASK: 0\n"));
11153 }
11154
11155 if (pDbgState->fClearCr4Mask && pVmcsInfo->u64Cr4Mask != 0)
11156 {
11157 pVmcsInfo->u64Cr4Mask = 0;
11158 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, 0);
11159 Log6Func(("VMX_VMCS_CTRL_CR4_MASK: 0\n"));
11160 }
11161
11162 NOREF(pVCpu);
11163}
11164
11165
11166/**
11167 * Restores VMCS fields that were changed by hmR0VmxPreRunGuestDebugStateApply for
11168 * re-entry next time around.
11169 *
11170 * @returns Strict VBox status code (i.e. informational status codes too).
11171 * @param pVCpu The cross context virtual CPU structure.
11172 * @param pVmxTransient The VMX-transient structure.
11173 * @param pDbgState The debug state.
11174 * @param rcStrict The return code from executing the guest using single
11175 * stepping.
11176 */
11177static VBOXSTRICTRC hmR0VmxRunDebugStateRevert(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState,
11178 VBOXSTRICTRC rcStrict)
11179{
11180 /*
11181 * Restore VM-exit control settings as we may not reenter this function the
11182 * next time around.
11183 */
11184 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11185
11186 /* We reload the initial value, trigger what we can of recalculations the
11187 next time around. From the looks of things, that's all that's required atm. */
11188 if (pDbgState->fModifiedProcCtls)
11189 {
11190 if (!(pDbgState->fProcCtlsInitial & VMX_PROC_CTLS_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
11191 pDbgState->fProcCtlsInitial |= VMX_PROC_CTLS_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
11192 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
11193 AssertRC(rc2);
11194 pVmcsInfo->u32ProcCtls = pDbgState->fProcCtlsInitial;
11195 }
11196
11197 /* We're currently the only ones messing with this one, so just restore the
11198 cached value and reload the field. */
11199 if ( pDbgState->fModifiedProcCtls2
11200 && pVmcsInfo->u32ProcCtls2 != pDbgState->fProcCtls2Initial)
11201 {
11202 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
11203 AssertRC(rc2);
11204 pVmcsInfo->u32ProcCtls2 = pDbgState->fProcCtls2Initial;
11205 }
11206
11207 /* If we've modified the exception bitmap, we restore it and trigger
11208 reloading and partial recalculation the next time around. */
11209 if (pDbgState->fModifiedXcptBitmap)
11210 pVmcsInfo->u32XcptBitmap = pDbgState->bmXcptInitial;
11211
11212 return rcStrict;
11213}
11214
11215
11216/**
11217 * Configures VM-exit controls for current DBGF and DTrace settings.
11218 *
11219 * This updates @a pDbgState and the VMCS execution control fields to reflect
11220 * the necessary VM-exits demanded by DBGF and DTrace.
11221 *
11222 * @param pVCpu The cross context virtual CPU structure.
11223 * @param pVmxTransient The VMX-transient structure. May update
11224 * fUpdatedTscOffsettingAndPreemptTimer.
11225 * @param pDbgState The debug state.
11226 */
11227static void hmR0VmxPreRunGuestDebugStateUpdate(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11228{
11229 /*
11230 * Take down the dtrace serial number so we can spot changes.
11231 */
11232 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
11233 ASMCompilerBarrier();
11234
11235 /*
11236 * We'll rebuild most of the middle block of data members (holding the
11237 * current settings) as we go along here, so start by clearing it all.
11238 */
11239 pDbgState->bmXcptExtra = 0;
11240 pDbgState->fCpe1Extra = 0;
11241 pDbgState->fCpe1Unwanted = 0;
11242 pDbgState->fCpe2Extra = 0;
11243 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
11244 pDbgState->bmExitsToCheck[i] = 0;
11245
11246 /*
11247 * Software interrupts (INT XXh) - no idea how to trigger these...
11248 */
11249 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11250 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
11251 || VBOXVMM_INT_SOFTWARE_ENABLED())
11252 {
11253 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11254 }
11255
11256 /*
11257 * INT3 breakpoints - triggered by #BP exceptions.
11258 */
11259 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
11260 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11261
11262 /*
11263 * Exception bitmap and XCPT events+probes.
11264 */
11265 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
11266 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
11267 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
11268
11269 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
11270 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
11271 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11272 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
11273 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
11274 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
11275 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
11276 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
11277 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
11278 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
11279 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
11280 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
11281 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
11282 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
11283 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
11284 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
11285 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
11286 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
11287
11288 if (pDbgState->bmXcptExtra)
11289 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11290
11291 /*
11292 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
11293 *
11294 * Note! This is the reverse of what hmR0VmxHandleExitDtraceEvents does.
11295 * So, when adding/changing/removing please don't forget to update it.
11296 *
11297 * Some of the macros are picking up local variables to save horizontal space,
11298 * (being able to see it in a table is the lesser evil here).
11299 */
11300#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
11301 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
11302 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
11303#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
11304 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11305 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11306 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11307 } else do { } while (0)
11308#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
11309 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11310 { \
11311 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
11312 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11313 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11314 } else do { } while (0)
11315#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
11316 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11317 { \
11318 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
11319 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11320 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11321 } else do { } while (0)
11322#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
11323 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11324 { \
11325 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
11326 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11327 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11328 } else do { } while (0)
11329
11330 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
11331 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
11332 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
11333 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
11334 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
11335
11336 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
11337 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
11338 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
11339 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
11340 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_PROC_CTLS_HLT_EXIT); /* paranoia */
11341 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
11342 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
11343 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
11344 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_PROC_CTLS_INVLPG_EXIT);
11345 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
11346 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_PROC_CTLS_RDPMC_EXIT);
11347 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
11348 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_PROC_CTLS_RDTSC_EXIT);
11349 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
11350 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
11351 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
11352 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
11353 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
11354 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
11355 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
11356 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
11357 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
11358 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
11359 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
11360 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
11361 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
11362 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
11363 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
11364 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
11365 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
11366 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
11367 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
11368 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
11369 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
11370 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
11371 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
11372
11373 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
11374 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11375 {
11376 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4
11377 | CPUMCTX_EXTRN_APIC_TPR);
11378 AssertRC(rc);
11379
11380#if 0 /** @todo fix me */
11381 pDbgState->fClearCr0Mask = true;
11382 pDbgState->fClearCr4Mask = true;
11383#endif
11384 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
11385 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_STORE_EXIT | VMX_PROC_CTLS_CR8_STORE_EXIT;
11386 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11387 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_LOAD_EXIT | VMX_PROC_CTLS_CR8_LOAD_EXIT;
11388 pDbgState->fCpe1Unwanted |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* risky? */
11389 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
11390 require clearing here and in the loop if we start using it. */
11391 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
11392 }
11393 else
11394 {
11395 if (pDbgState->fClearCr0Mask)
11396 {
11397 pDbgState->fClearCr0Mask = false;
11398 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR0);
11399 }
11400 if (pDbgState->fClearCr4Mask)
11401 {
11402 pDbgState->fClearCr4Mask = false;
11403 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR4);
11404 }
11405 }
11406 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
11407 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
11408
11409 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
11410 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
11411 {
11412 /** @todo later, need to fix handler as it assumes this won't usually happen. */
11413 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
11414 }
11415 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
11416 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
11417
11418 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS); /* risky clearing this? */
11419 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
11420 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS);
11421 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
11422 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_PROC_CTLS_MWAIT_EXIT); /* paranoia */
11423 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
11424 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_PROC_CTLS_MONITOR_EXIT); /* paranoia */
11425 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
11426#if 0 /** @todo too slow, fix handler. */
11427 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_PROC_CTLS_PAUSE_EXIT);
11428#endif
11429 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
11430
11431 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
11432 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
11433 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
11434 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
11435 {
11436 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11437 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_GDTR_IDTR_ACCESS);
11438 }
11439 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11440 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11441 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11442 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11443
11444 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
11445 || IS_EITHER_ENABLED(pVM, INSTR_STR)
11446 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
11447 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
11448 {
11449 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11450 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_LDTR_TR_ACCESS);
11451 }
11452 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_LDTR_TR_ACCESS);
11453 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_LDTR_TR_ACCESS);
11454 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_LDTR_TR_ACCESS);
11455 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_LDTR_TR_ACCESS);
11456
11457 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
11458 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
11459 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_PROC_CTLS_RDTSC_EXIT);
11460 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
11461 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
11462 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
11463 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_PROC_CTLS2_WBINVD_EXIT);
11464 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
11465 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
11466 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
11467 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_PROC_CTLS2_RDRAND_EXIT);
11468 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
11469 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_PROC_CTLS_INVLPG_EXIT);
11470 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
11471 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
11472 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
11473 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_PROC_CTLS2_RDSEED_EXIT);
11474 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
11475 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
11476 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
11477 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
11478 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
11479
11480#undef IS_EITHER_ENABLED
11481#undef SET_ONLY_XBM_IF_EITHER_EN
11482#undef SET_CPE1_XBM_IF_EITHER_EN
11483#undef SET_CPEU_XBM_IF_EITHER_EN
11484#undef SET_CPE2_XBM_IF_EITHER_EN
11485
11486 /*
11487 * Sanitize the control stuff.
11488 */
11489 pDbgState->fCpe2Extra &= pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1;
11490 if (pDbgState->fCpe2Extra)
11491 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
11492 pDbgState->fCpe1Extra &= pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed1;
11493 pDbgState->fCpe1Unwanted &= ~pVM->hm.s.vmx.Msrs.ProcCtls.n.allowed0;
11494 if (pVCpu->hm.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_PROC_CTLS_RDTSC_EXIT))
11495 {
11496 pVCpu->hm.s.fDebugWantRdTscExit ^= true;
11497 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
11498 }
11499
11500 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
11501 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
11502 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
11503 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
11504}
11505
11506
11507/**
11508 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
11509 * appropriate.
11510 *
11511 * The caller has checked the VM-exit against the
11512 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
11513 * already, so we don't have to do that either.
11514 *
11515 * @returns Strict VBox status code (i.e. informational status codes too).
11516 * @param pVCpu The cross context virtual CPU structure.
11517 * @param pVmxTransient The VMX-transient structure.
11518 * @param uExitReason The VM-exit reason.
11519 *
11520 * @remarks The name of this function is displayed by dtrace, so keep it short
11521 * and to the point. No longer than 33 chars long, please.
11522 */
11523static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
11524{
11525 /*
11526 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
11527 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
11528 *
11529 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
11530 * does. Must add/change/remove both places. Same ordering, please.
11531 *
11532 * Added/removed events must also be reflected in the next section
11533 * where we dispatch dtrace events.
11534 */
11535 bool fDtrace1 = false;
11536 bool fDtrace2 = false;
11537 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
11538 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
11539 uint32_t uEventArg = 0;
11540#define SET_EXIT(a_EventSubName) \
11541 do { \
11542 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11543 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11544 } while (0)
11545#define SET_BOTH(a_EventSubName) \
11546 do { \
11547 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
11548 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11549 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
11550 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11551 } while (0)
11552 switch (uExitReason)
11553 {
11554 case VMX_EXIT_MTF:
11555 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
11556
11557 case VMX_EXIT_XCPT_OR_NMI:
11558 {
11559 uint8_t const idxVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
11560 switch (VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo))
11561 {
11562 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
11563 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
11564 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
11565 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
11566 {
11567 if (VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uExitIntInfo))
11568 {
11569 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
11570 uEventArg = pVmxTransient->uExitIntErrorCode;
11571 }
11572 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
11573 switch (enmEvent1)
11574 {
11575 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
11576 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
11577 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
11578 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
11579 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
11580 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
11581 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
11582 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
11583 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
11584 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
11585 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
11586 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
11587 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
11588 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
11589 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
11590 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
11591 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
11592 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
11593 default: break;
11594 }
11595 }
11596 else
11597 AssertFailed();
11598 break;
11599
11600 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
11601 uEventArg = idxVector;
11602 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
11603 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
11604 break;
11605 }
11606 break;
11607 }
11608
11609 case VMX_EXIT_TRIPLE_FAULT:
11610 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
11611 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
11612 break;
11613 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
11614 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
11615 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
11616 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
11617 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
11618
11619 /* Instruction specific VM-exits: */
11620 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
11621 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
11622 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
11623 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
11624 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
11625 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
11626 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
11627 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
11628 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
11629 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
11630 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
11631 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
11632 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
11633 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
11634 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
11635 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
11636 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
11637 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
11638 case VMX_EXIT_MOV_CRX:
11639 hmR0VmxReadExitQualVmcs(pVmxTransient);
11640 if (VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_CRX_ACCESS_READ)
11641 SET_BOTH(CRX_READ);
11642 else
11643 SET_BOTH(CRX_WRITE);
11644 uEventArg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
11645 break;
11646 case VMX_EXIT_MOV_DRX:
11647 hmR0VmxReadExitQualVmcs(pVmxTransient);
11648 if ( VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual)
11649 == VMX_EXIT_QUAL_DRX_DIRECTION_READ)
11650 SET_BOTH(DRX_READ);
11651 else
11652 SET_BOTH(DRX_WRITE);
11653 uEventArg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
11654 break;
11655 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
11656 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
11657 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
11658 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
11659 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
11660 case VMX_EXIT_GDTR_IDTR_ACCESS:
11661 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
11662 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_XDTR_INSINFO_INSTR_ID))
11663 {
11664 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
11665 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
11666 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
11667 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
11668 }
11669 break;
11670
11671 case VMX_EXIT_LDTR_TR_ACCESS:
11672 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
11673 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_YYTR_INSINFO_INSTR_ID))
11674 {
11675 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
11676 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
11677 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
11678 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
11679 }
11680 break;
11681
11682 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
11683 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
11684 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
11685 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
11686 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
11687 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
11688 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
11689 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
11690 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
11691 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
11692 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
11693
11694 /* Events that aren't relevant at this point. */
11695 case VMX_EXIT_EXT_INT:
11696 case VMX_EXIT_INT_WINDOW:
11697 case VMX_EXIT_NMI_WINDOW:
11698 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11699 case VMX_EXIT_PREEMPT_TIMER:
11700 case VMX_EXIT_IO_INSTR:
11701 break;
11702
11703 /* Errors and unexpected events. */
11704 case VMX_EXIT_INIT_SIGNAL:
11705 case VMX_EXIT_SIPI:
11706 case VMX_EXIT_IO_SMI:
11707 case VMX_EXIT_SMI:
11708 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
11709 case VMX_EXIT_ERR_MSR_LOAD:
11710 case VMX_EXIT_ERR_MACHINE_CHECK:
11711 case VMX_EXIT_PML_FULL:
11712 case VMX_EXIT_VIRTUALIZED_EOI:
11713 break;
11714
11715 default:
11716 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
11717 break;
11718 }
11719#undef SET_BOTH
11720#undef SET_EXIT
11721
11722 /*
11723 * Dtrace tracepoints go first. We do them here at once so we don't
11724 * have to copy the guest state saving and stuff a few dozen times.
11725 * Down side is that we've got to repeat the switch, though this time
11726 * we use enmEvent since the probes are a subset of what DBGF does.
11727 */
11728 if (fDtrace1 || fDtrace2)
11729 {
11730 hmR0VmxReadExitQualVmcs(pVmxTransient);
11731 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
11732 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
11733 switch (enmEvent1)
11734 {
11735 /** @todo consider which extra parameters would be helpful for each probe. */
11736 case DBGFEVENT_END: break;
11737 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pCtx); break;
11738 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pCtx, pCtx->dr[6]); break;
11739 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pCtx); break;
11740 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pCtx); break;
11741 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pCtx); break;
11742 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pCtx); break;
11743 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pCtx); break;
11744 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pCtx); break;
11745 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pCtx, uEventArg); break;
11746 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pCtx, uEventArg); break;
11747 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pCtx, uEventArg); break;
11748 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pCtx, uEventArg); break;
11749 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pCtx, uEventArg, pCtx->cr2); break;
11750 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pCtx); break;
11751 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pCtx); break;
11752 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pCtx); break;
11753 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pCtx); break;
11754 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pCtx, uEventArg); break;
11755 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11756 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11757 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pCtx); break;
11758 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pCtx); break;
11759 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pCtx); break;
11760 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pCtx); break;
11761 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pCtx); break;
11762 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pCtx); break;
11763 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pCtx); break;
11764 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11765 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11766 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11767 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11768 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11769 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pCtx, pCtx->ecx,
11770 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11771 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pCtx); break;
11772 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pCtx); break;
11773 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pCtx); break;
11774 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pCtx); break;
11775 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pCtx); break;
11776 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pCtx); break;
11777 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pCtx); break;
11778 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pCtx); break;
11779 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pCtx); break;
11780 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pCtx); break;
11781 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pCtx); break;
11782 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pCtx); break;
11783 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pCtx); break;
11784 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pCtx); break;
11785 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pCtx); break;
11786 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pCtx); break;
11787 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pCtx); break;
11788 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pCtx); break;
11789 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pCtx); break;
11790 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pCtx); break;
11791 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pCtx); break;
11792 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pCtx); break;
11793 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pCtx); break;
11794 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pCtx); break;
11795 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pCtx); break;
11796 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pCtx); break;
11797 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pCtx); break;
11798 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pCtx); break;
11799 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pCtx); break;
11800 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pCtx); break;
11801 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pCtx); break;
11802 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pCtx); break;
11803 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
11804 }
11805 switch (enmEvent2)
11806 {
11807 /** @todo consider which extra parameters would be helpful for each probe. */
11808 case DBGFEVENT_END: break;
11809 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pCtx); break;
11810 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11811 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pCtx); break;
11812 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pCtx); break;
11813 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pCtx); break;
11814 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pCtx); break;
11815 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pCtx); break;
11816 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pCtx); break;
11817 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pCtx); break;
11818 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11819 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11820 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11821 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11822 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11823 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pCtx, pCtx->ecx,
11824 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11825 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pCtx); break;
11826 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pCtx); break;
11827 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pCtx); break;
11828 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pCtx); break;
11829 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pCtx); break;
11830 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pCtx); break;
11831 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pCtx); break;
11832 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pCtx); break;
11833 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pCtx); break;
11834 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pCtx); break;
11835 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pCtx); break;
11836 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pCtx); break;
11837 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pCtx); break;
11838 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pCtx); break;
11839 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pCtx); break;
11840 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pCtx); break;
11841 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pCtx); break;
11842 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pCtx); break;
11843 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pCtx); break;
11844 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pCtx); break;
11845 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pCtx); break;
11846 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pCtx); break;
11847 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pCtx); break;
11848 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pCtx); break;
11849 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pCtx); break;
11850 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pCtx); break;
11851 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pCtx); break;
11852 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pCtx); break;
11853 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pCtx); break;
11854 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pCtx); break;
11855 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pCtx); break;
11856 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pCtx); break;
11857 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pCtx); break;
11858 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pCtx); break;
11859 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pCtx); break;
11860 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pCtx); break;
11861 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
11862 }
11863 }
11864
11865 /*
11866 * Fire of the DBGF event, if enabled (our check here is just a quick one,
11867 * the DBGF call will do a full check).
11868 *
11869 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
11870 * Note! If we have to events, we prioritize the first, i.e. the instruction
11871 * one, in order to avoid event nesting.
11872 */
11873 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11874 if ( enmEvent1 != DBGFEVENT_END
11875 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
11876 {
11877 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11878 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent1, DBGFEVENTCTX_HM, 1, uEventArg);
11879 if (rcStrict != VINF_SUCCESS)
11880 return rcStrict;
11881 }
11882 else if ( enmEvent2 != DBGFEVENT_END
11883 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
11884 {
11885 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
11886 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent2, DBGFEVENTCTX_HM, 1, uEventArg);
11887 if (rcStrict != VINF_SUCCESS)
11888 return rcStrict;
11889 }
11890
11891 return VINF_SUCCESS;
11892}
11893
11894
11895/**
11896 * Single-stepping VM-exit filtering.
11897 *
11898 * This is preprocessing the VM-exits and deciding whether we've gotten far
11899 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
11900 * handling is performed.
11901 *
11902 * @returns Strict VBox status code (i.e. informational status codes too).
11903 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
11904 * @param pVmxTransient The VMX-transient structure.
11905 * @param pDbgState The debug state.
11906 */
11907DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11908{
11909 /*
11910 * Expensive (saves context) generic dtrace VM-exit probe.
11911 */
11912 uint32_t const uExitReason = pVmxTransient->uExitReason;
11913 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
11914 { /* more likely */ }
11915 else
11916 {
11917 hmR0VmxReadExitQualVmcs(pVmxTransient);
11918 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
11919 AssertRC(rc);
11920 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, &pVCpu->cpum.GstCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
11921 }
11922
11923 /*
11924 * Check for host NMI, just to get that out of the way.
11925 */
11926 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
11927 { /* normally likely */ }
11928 else
11929 {
11930 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
11931 uint32_t const uIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
11932 if (uIntType == VMX_EXIT_INT_INFO_TYPE_NMI)
11933 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
11934 }
11935
11936 /*
11937 * Check for single stepping event if we're stepping.
11938 */
11939 if (pVCpu->hm.s.fSingleInstruction)
11940 {
11941 switch (uExitReason)
11942 {
11943 case VMX_EXIT_MTF:
11944 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
11945
11946 /* Various events: */
11947 case VMX_EXIT_XCPT_OR_NMI:
11948 case VMX_EXIT_EXT_INT:
11949 case VMX_EXIT_TRIPLE_FAULT:
11950 case VMX_EXIT_INT_WINDOW:
11951 case VMX_EXIT_NMI_WINDOW:
11952 case VMX_EXIT_TASK_SWITCH:
11953 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11954 case VMX_EXIT_APIC_ACCESS:
11955 case VMX_EXIT_EPT_VIOLATION:
11956 case VMX_EXIT_EPT_MISCONFIG:
11957 case VMX_EXIT_PREEMPT_TIMER:
11958
11959 /* Instruction specific VM-exits: */
11960 case VMX_EXIT_CPUID:
11961 case VMX_EXIT_GETSEC:
11962 case VMX_EXIT_HLT:
11963 case VMX_EXIT_INVD:
11964 case VMX_EXIT_INVLPG:
11965 case VMX_EXIT_RDPMC:
11966 case VMX_EXIT_RDTSC:
11967 case VMX_EXIT_RSM:
11968 case VMX_EXIT_VMCALL:
11969 case VMX_EXIT_VMCLEAR:
11970 case VMX_EXIT_VMLAUNCH:
11971 case VMX_EXIT_VMPTRLD:
11972 case VMX_EXIT_VMPTRST:
11973 case VMX_EXIT_VMREAD:
11974 case VMX_EXIT_VMRESUME:
11975 case VMX_EXIT_VMWRITE:
11976 case VMX_EXIT_VMXOFF:
11977 case VMX_EXIT_VMXON:
11978 case VMX_EXIT_MOV_CRX:
11979 case VMX_EXIT_MOV_DRX:
11980 case VMX_EXIT_IO_INSTR:
11981 case VMX_EXIT_RDMSR:
11982 case VMX_EXIT_WRMSR:
11983 case VMX_EXIT_MWAIT:
11984 case VMX_EXIT_MONITOR:
11985 case VMX_EXIT_PAUSE:
11986 case VMX_EXIT_GDTR_IDTR_ACCESS:
11987 case VMX_EXIT_LDTR_TR_ACCESS:
11988 case VMX_EXIT_INVEPT:
11989 case VMX_EXIT_RDTSCP:
11990 case VMX_EXIT_INVVPID:
11991 case VMX_EXIT_WBINVD:
11992 case VMX_EXIT_XSETBV:
11993 case VMX_EXIT_RDRAND:
11994 case VMX_EXIT_INVPCID:
11995 case VMX_EXIT_VMFUNC:
11996 case VMX_EXIT_RDSEED:
11997 case VMX_EXIT_XSAVES:
11998 case VMX_EXIT_XRSTORS:
11999 {
12000 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12001 AssertRCReturn(rc, rc);
12002 if ( pVCpu->cpum.GstCtx.rip != pDbgState->uRipStart
12003 || pVCpu->cpum.GstCtx.cs.Sel != pDbgState->uCsStart)
12004 return VINF_EM_DBG_STEPPED;
12005 break;
12006 }
12007
12008 /* Errors and unexpected events: */
12009 case VMX_EXIT_INIT_SIGNAL:
12010 case VMX_EXIT_SIPI:
12011 case VMX_EXIT_IO_SMI:
12012 case VMX_EXIT_SMI:
12013 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
12014 case VMX_EXIT_ERR_MSR_LOAD:
12015 case VMX_EXIT_ERR_MACHINE_CHECK:
12016 case VMX_EXIT_PML_FULL:
12017 case VMX_EXIT_VIRTUALIZED_EOI:
12018 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
12019 break;
12020
12021 default:
12022 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12023 break;
12024 }
12025 }
12026
12027 /*
12028 * Check for debugger event breakpoints and dtrace probes.
12029 */
12030 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
12031 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
12032 {
12033 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVCpu, pVmxTransient, uExitReason);
12034 if (rcStrict != VINF_SUCCESS)
12035 return rcStrict;
12036 }
12037
12038 /*
12039 * Normal processing.
12040 */
12041#ifdef HMVMX_USE_FUNCTION_TABLE
12042 return g_apfnVMExitHandlers[uExitReason](pVCpu, pVmxTransient);
12043#else
12044 return hmR0VmxHandleExit(pVCpu, pVmxTransient, uExitReason);
12045#endif
12046}
12047
12048
12049/**
12050 * Single steps guest code using hardware-assisted VMX.
12051 *
12052 * This is -not- the same as the guest single-stepping itself (say using EFLAGS.TF)
12053 * but single-stepping through the hypervisor debugger.
12054 *
12055 * @returns Strict VBox status code (i.e. informational status codes too).
12056 * @param pVCpu The cross context virtual CPU structure.
12057 * @param pcLoops Pointer to the number of executed loops.
12058 *
12059 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
12060 */
12061static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVMCPUCC pVCpu, uint32_t *pcLoops)
12062{
12063 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hm.s.cMaxResumeLoops;
12064 Assert(pcLoops);
12065 Assert(*pcLoops <= cMaxResumeLoops);
12066
12067 VMXTRANSIENT VmxTransient;
12068 RT_ZERO(VmxTransient);
12069 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
12070
12071 /* Set HMCPU indicators. */
12072 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
12073 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
12074 pVCpu->hm.s.fDebugWantRdTscExit = false;
12075 pVCpu->hm.s.fUsingDebugLoop = true;
12076
12077 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
12078 VMXRUNDBGSTATE DbgState;
12079 hmR0VmxRunDebugStateInit(pVCpu, &VmxTransient, &DbgState);
12080 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12081
12082 /*
12083 * The loop.
12084 */
12085 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
12086 for (;;)
12087 {
12088 Assert(!HMR0SuspendPending());
12089 HMVMX_ASSERT_CPU_SAFE(pVCpu);
12090 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
12091 bool fStepping = pVCpu->hm.s.fSingleInstruction;
12092
12093 /* Set up VM-execution controls the next two can respond to. */
12094 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12095
12096 /*
12097 * Preparatory work for running guest code, this may force us to
12098 * return to ring-3.
12099 *
12100 * Warning! This bugger disables interrupts on VINF_SUCCESS!
12101 */
12102 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, fStepping);
12103 if (rcStrict != VINF_SUCCESS)
12104 break;
12105
12106 /* Interrupts are disabled at this point! */
12107 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
12108
12109 /* Override any obnoxious code in the above two calls. */
12110 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12111
12112 /*
12113 * Finally execute the guest.
12114 */
12115 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
12116
12117 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
12118 /* Interrupts are re-enabled at this point! */
12119
12120 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
12121 if (RT_SUCCESS(rcRun))
12122 { /* very likely */ }
12123 else
12124 {
12125 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
12126 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
12127 return rcRun;
12128 }
12129
12130 /* Profile the VM-exit. */
12131 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
12132 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
12133 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
12134 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
12135 HMVMX_START_EXIT_DISPATCH_PROF();
12136
12137 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
12138
12139 /*
12140 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
12141 */
12142 rcStrict = hmR0VmxRunDebugHandleExit(pVCpu, &VmxTransient, &DbgState);
12143 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
12144 if (rcStrict != VINF_SUCCESS)
12145 break;
12146 if (++(*pcLoops) > cMaxResumeLoops)
12147 {
12148 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
12149 rcStrict = VINF_EM_RAW_INTERRUPT;
12150 break;
12151 }
12152
12153 /*
12154 * Stepping: Did the RIP change, if so, consider it a single step.
12155 * Otherwise, make sure one of the TFs gets set.
12156 */
12157 if (fStepping)
12158 {
12159 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12160 AssertRC(rc);
12161 if ( pVCpu->cpum.GstCtx.rip != DbgState.uRipStart
12162 || pVCpu->cpum.GstCtx.cs.Sel != DbgState.uCsStart)
12163 {
12164 rcStrict = VINF_EM_DBG_STEPPED;
12165 break;
12166 }
12167 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
12168 }
12169
12170 /*
12171 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
12172 */
12173 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
12174 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12175 }
12176
12177 /*
12178 * Clear the X86_EFL_TF if necessary.
12179 */
12180 if (pVCpu->hm.s.fClearTrapFlag)
12181 {
12182 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
12183 AssertRC(rc);
12184 pVCpu->hm.s.fClearTrapFlag = false;
12185 pVCpu->cpum.GstCtx.eflags.Bits.u1TF = 0;
12186 }
12187 /** @todo there seems to be issues with the resume flag when the monitor trap
12188 * flag is pending without being used. Seen early in bios init when
12189 * accessing APIC page in protected mode. */
12190
12191 /*
12192 * Restore VM-exit control settings as we may not re-enter this function the
12193 * next time around.
12194 */
12195 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &VmxTransient, &DbgState, rcStrict);
12196
12197 /* Restore HMCPU indicators. */
12198 pVCpu->hm.s.fUsingDebugLoop = false;
12199 pVCpu->hm.s.fDebugWantRdTscExit = false;
12200 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
12201
12202 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
12203 return rcStrict;
12204}
12205
12206
12207/** @} */
12208
12209
12210/**
12211 * Checks if any expensive dtrace probes are enabled and we should go to the
12212 * debug loop.
12213 *
12214 * @returns true if we should use debug loop, false if not.
12215 */
12216static bool hmR0VmxAnyExpensiveProbesEnabled(void)
12217{
12218 /* It's probably faster to OR the raw 32-bit counter variables together.
12219 Since the variables are in an array and the probes are next to one
12220 another (more or less), we have good locality. So, better read
12221 eight-nine cache lines ever time and only have one conditional, than
12222 128+ conditionals, right? */
12223 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
12224 | VBOXVMM_XCPT_DE_ENABLED_RAW()
12225 | VBOXVMM_XCPT_DB_ENABLED_RAW()
12226 | VBOXVMM_XCPT_BP_ENABLED_RAW()
12227 | VBOXVMM_XCPT_OF_ENABLED_RAW()
12228 | VBOXVMM_XCPT_BR_ENABLED_RAW()
12229 | VBOXVMM_XCPT_UD_ENABLED_RAW()
12230 | VBOXVMM_XCPT_NM_ENABLED_RAW()
12231 | VBOXVMM_XCPT_DF_ENABLED_RAW()
12232 | VBOXVMM_XCPT_TS_ENABLED_RAW()
12233 | VBOXVMM_XCPT_NP_ENABLED_RAW()
12234 | VBOXVMM_XCPT_SS_ENABLED_RAW()
12235 | VBOXVMM_XCPT_GP_ENABLED_RAW()
12236 | VBOXVMM_XCPT_PF_ENABLED_RAW()
12237 | VBOXVMM_XCPT_MF_ENABLED_RAW()
12238 | VBOXVMM_XCPT_AC_ENABLED_RAW()
12239 | VBOXVMM_XCPT_XF_ENABLED_RAW()
12240 | VBOXVMM_XCPT_VE_ENABLED_RAW()
12241 | VBOXVMM_XCPT_SX_ENABLED_RAW()
12242 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
12243 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
12244 ) != 0
12245 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
12246 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
12247 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
12248 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
12249 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
12250 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
12251 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
12252 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
12253 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
12254 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
12255 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
12256 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
12257 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
12258 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
12259 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
12260 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
12261 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
12262 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
12263 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
12264 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
12265 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
12266 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
12267 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
12268 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
12269 | VBOXVMM_INSTR_STR_ENABLED_RAW()
12270 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
12271 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
12272 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
12273 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
12274 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
12275 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
12276 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
12277 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
12278 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
12279 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
12280 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
12281 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
12282 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
12283 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
12284 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
12285 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
12286 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
12287 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
12288 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
12289 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
12290 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
12291 ) != 0
12292 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
12293 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
12294 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
12295 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
12296 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
12297 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
12298 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
12299 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
12300 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
12301 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
12302 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
12303 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
12304 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
12305 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
12306 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
12307 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
12308 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
12309 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
12310 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
12311 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
12312 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
12313 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
12314 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
12315 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
12316 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
12317 | VBOXVMM_EXIT_STR_ENABLED_RAW()
12318 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
12319 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
12320 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
12321 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
12322 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
12323 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
12324 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
12325 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
12326 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
12327 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
12328 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
12329 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
12330 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
12331 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
12332 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
12333 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
12334 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
12335 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
12336 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
12337 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
12338 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
12339 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
12340 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
12341 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
12342 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
12343 ) != 0;
12344}
12345
12346
12347/**
12348 * Runs the guest using hardware-assisted VMX.
12349 *
12350 * @returns Strict VBox status code (i.e. informational status codes too).
12351 * @param pVCpu The cross context virtual CPU structure.
12352 */
12353VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVMCPUCC pVCpu)
12354{
12355 AssertPtr(pVCpu);
12356 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12357 Assert(VMMRZCallRing3IsEnabled(pVCpu));
12358 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12359 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
12360
12361 VMMRZCallRing3SetNotification(pVCpu, hmR0VmxCallRing3Callback, pCtx);
12362
12363 VBOXSTRICTRC rcStrict;
12364 uint32_t cLoops = 0;
12365 for (;;)
12366 {
12367#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12368 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(pCtx);
12369#else
12370 bool const fInNestedGuestMode = false;
12371#endif
12372 if (!fInNestedGuestMode)
12373 {
12374 if ( !pVCpu->hm.s.fUseDebugLoop
12375 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
12376 && !DBGFIsStepping(pVCpu)
12377 && !pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
12378 rcStrict = hmR0VmxRunGuestCodeNormal(pVCpu, &cLoops);
12379 else
12380 rcStrict = hmR0VmxRunGuestCodeDebug(pVCpu, &cLoops);
12381 }
12382#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12383 else
12384 rcStrict = hmR0VmxRunGuestCodeNested(pVCpu, &cLoops);
12385
12386 if (rcStrict == VINF_VMX_VMLAUNCH_VMRESUME)
12387 {
12388 Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
12389 continue;
12390 }
12391 if (rcStrict == VINF_VMX_VMEXIT)
12392 {
12393 Assert(!CPUMIsGuestInVmxNonRootMode(pCtx));
12394 continue;
12395 }
12396#endif
12397 break;
12398 }
12399
12400 int const rcLoop = VBOXSTRICTRC_VAL(rcStrict);
12401 switch (rcLoop)
12402 {
12403 case VERR_EM_INTERPRETER: rcStrict = VINF_EM_RAW_EMULATE_INSTR; break;
12404 case VINF_EM_RESET: rcStrict = VINF_EM_TRIPLE_FAULT; break;
12405 }
12406
12407 int rc2 = hmR0VmxExitToRing3(pVCpu, rcStrict);
12408 if (RT_FAILURE(rc2))
12409 {
12410 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
12411 rcStrict = rc2;
12412 }
12413 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12414 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
12415 return rcStrict;
12416}
12417
12418
12419#ifndef HMVMX_USE_FUNCTION_TABLE
12420/**
12421 * Handles a guest VM-exit from hardware-assisted VMX execution.
12422 *
12423 * @returns Strict VBox status code (i.e. informational status codes too).
12424 * @param pVCpu The cross context virtual CPU structure.
12425 * @param pVmxTransient The VMX-transient structure.
12426 */
12427DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12428{
12429#ifdef DEBUG_ramshankar
12430# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) \
12431 do { \
12432 if (a_fSave != 0) \
12433 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL); \
12434 VBOXSTRICTRC rcStrict = a_CallExpr; \
12435 if (a_fSave != 0) \
12436 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST); \
12437 return rcStrict; \
12438 } while (0)
12439#else
12440# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) return a_CallExpr
12441#endif
12442 uint32_t const uExitReason = pVmxTransient->uExitReason;
12443 switch (uExitReason)
12444 {
12445 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient));
12446 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, hmR0VmxExitEptViolation(pVCpu, pVmxTransient));
12447 case VMX_EXIT_IO_INSTR: VMEXIT_CALL_RET(0, hmR0VmxExitIoInstr(pVCpu, pVmxTransient));
12448 case VMX_EXIT_CPUID: VMEXIT_CALL_RET(0, hmR0VmxExitCpuid(pVCpu, pVmxTransient));
12449 case VMX_EXIT_RDTSC: VMEXIT_CALL_RET(0, hmR0VmxExitRdtsc(pVCpu, pVmxTransient));
12450 case VMX_EXIT_RDTSCP: VMEXIT_CALL_RET(0, hmR0VmxExitRdtscp(pVCpu, pVmxTransient));
12451 case VMX_EXIT_APIC_ACCESS: VMEXIT_CALL_RET(0, hmR0VmxExitApicAccess(pVCpu, pVmxTransient));
12452 case VMX_EXIT_XCPT_OR_NMI: VMEXIT_CALL_RET(0, hmR0VmxExitXcptOrNmi(pVCpu, pVmxTransient));
12453 case VMX_EXIT_MOV_CRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovCRx(pVCpu, pVmxTransient));
12454 case VMX_EXIT_EXT_INT: VMEXIT_CALL_RET(0, hmR0VmxExitExtInt(pVCpu, pVmxTransient));
12455 case VMX_EXIT_INT_WINDOW: VMEXIT_CALL_RET(0, hmR0VmxExitIntWindow(pVCpu, pVmxTransient));
12456 case VMX_EXIT_TPR_BELOW_THRESHOLD: VMEXIT_CALL_RET(0, hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient));
12457 case VMX_EXIT_MWAIT: VMEXIT_CALL_RET(0, hmR0VmxExitMwait(pVCpu, pVmxTransient));
12458 case VMX_EXIT_MONITOR: VMEXIT_CALL_RET(0, hmR0VmxExitMonitor(pVCpu, pVmxTransient));
12459 case VMX_EXIT_TASK_SWITCH: VMEXIT_CALL_RET(0, hmR0VmxExitTaskSwitch(pVCpu, pVmxTransient));
12460 case VMX_EXIT_PREEMPT_TIMER: VMEXIT_CALL_RET(0, hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient));
12461 case VMX_EXIT_RDMSR: VMEXIT_CALL_RET(0, hmR0VmxExitRdmsr(pVCpu, pVmxTransient));
12462 case VMX_EXIT_WRMSR: VMEXIT_CALL_RET(0, hmR0VmxExitWrmsr(pVCpu, pVmxTransient));
12463 case VMX_EXIT_VMCALL: VMEXIT_CALL_RET(0, hmR0VmxExitVmcall(pVCpu, pVmxTransient));
12464 case VMX_EXIT_MOV_DRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovDRx(pVCpu, pVmxTransient));
12465 case VMX_EXIT_HLT: VMEXIT_CALL_RET(0, hmR0VmxExitHlt(pVCpu, pVmxTransient));
12466 case VMX_EXIT_INVD: VMEXIT_CALL_RET(0, hmR0VmxExitInvd(pVCpu, pVmxTransient));
12467 case VMX_EXIT_INVLPG: VMEXIT_CALL_RET(0, hmR0VmxExitInvlpg(pVCpu, pVmxTransient));
12468 case VMX_EXIT_MTF: VMEXIT_CALL_RET(0, hmR0VmxExitMtf(pVCpu, pVmxTransient));
12469 case VMX_EXIT_PAUSE: VMEXIT_CALL_RET(0, hmR0VmxExitPause(pVCpu, pVmxTransient));
12470 case VMX_EXIT_WBINVD: VMEXIT_CALL_RET(0, hmR0VmxExitWbinvd(pVCpu, pVmxTransient));
12471 case VMX_EXIT_XSETBV: VMEXIT_CALL_RET(0, hmR0VmxExitXsetbv(pVCpu, pVmxTransient));
12472 case VMX_EXIT_INVPCID: VMEXIT_CALL_RET(0, hmR0VmxExitInvpcid(pVCpu, pVmxTransient));
12473 case VMX_EXIT_GETSEC: VMEXIT_CALL_RET(0, hmR0VmxExitGetsec(pVCpu, pVmxTransient));
12474 case VMX_EXIT_RDPMC: VMEXIT_CALL_RET(0, hmR0VmxExitRdpmc(pVCpu, pVmxTransient));
12475#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12476 case VMX_EXIT_VMCLEAR: VMEXIT_CALL_RET(0, hmR0VmxExitVmclear(pVCpu, pVmxTransient));
12477 case VMX_EXIT_VMLAUNCH: VMEXIT_CALL_RET(0, hmR0VmxExitVmlaunch(pVCpu, pVmxTransient));
12478 case VMX_EXIT_VMPTRLD: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrld(pVCpu, pVmxTransient));
12479 case VMX_EXIT_VMPTRST: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrst(pVCpu, pVmxTransient));
12480 case VMX_EXIT_VMREAD: VMEXIT_CALL_RET(0, hmR0VmxExitVmread(pVCpu, pVmxTransient));
12481 case VMX_EXIT_VMRESUME: VMEXIT_CALL_RET(0, hmR0VmxExitVmwrite(pVCpu, pVmxTransient));
12482 case VMX_EXIT_VMWRITE: VMEXIT_CALL_RET(0, hmR0VmxExitVmresume(pVCpu, pVmxTransient));
12483 case VMX_EXIT_VMXOFF: VMEXIT_CALL_RET(0, hmR0VmxExitVmxoff(pVCpu, pVmxTransient));
12484 case VMX_EXIT_VMXON: VMEXIT_CALL_RET(0, hmR0VmxExitVmxon(pVCpu, pVmxTransient));
12485 case VMX_EXIT_INVVPID: VMEXIT_CALL_RET(0, hmR0VmxExitInvvpid(pVCpu, pVmxTransient));
12486 case VMX_EXIT_INVEPT: VMEXIT_CALL_RET(0, hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient));
12487#else
12488 case VMX_EXIT_VMCLEAR:
12489 case VMX_EXIT_VMLAUNCH:
12490 case VMX_EXIT_VMPTRLD:
12491 case VMX_EXIT_VMPTRST:
12492 case VMX_EXIT_VMREAD:
12493 case VMX_EXIT_VMRESUME:
12494 case VMX_EXIT_VMWRITE:
12495 case VMX_EXIT_VMXOFF:
12496 case VMX_EXIT_VMXON:
12497 case VMX_EXIT_INVVPID:
12498 case VMX_EXIT_INVEPT:
12499 return hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient);
12500#endif
12501
12502 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pVmxTransient);
12503 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pVmxTransient);
12504 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
12505
12506 case VMX_EXIT_INIT_SIGNAL:
12507 case VMX_EXIT_SIPI:
12508 case VMX_EXIT_IO_SMI:
12509 case VMX_EXIT_SMI:
12510 case VMX_EXIT_ERR_MSR_LOAD:
12511 case VMX_EXIT_ERR_MACHINE_CHECK:
12512 case VMX_EXIT_PML_FULL:
12513 case VMX_EXIT_VIRTUALIZED_EOI:
12514 case VMX_EXIT_GDTR_IDTR_ACCESS:
12515 case VMX_EXIT_LDTR_TR_ACCESS:
12516 case VMX_EXIT_APIC_WRITE:
12517 case VMX_EXIT_RDRAND:
12518 case VMX_EXIT_RSM:
12519 case VMX_EXIT_VMFUNC:
12520 case VMX_EXIT_ENCLS:
12521 case VMX_EXIT_RDSEED:
12522 case VMX_EXIT_XSAVES:
12523 case VMX_EXIT_XRSTORS:
12524 case VMX_EXIT_UMWAIT:
12525 case VMX_EXIT_TPAUSE:
12526 default:
12527 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
12528 }
12529#undef VMEXIT_CALL_RET
12530}
12531#endif /* !HMVMX_USE_FUNCTION_TABLE */
12532
12533
12534#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12535/**
12536 * Handles a nested-guest VM-exit from hardware-assisted VMX execution.
12537 *
12538 * @returns Strict VBox status code (i.e. informational status codes too).
12539 * @param pVCpu The cross context virtual CPU structure.
12540 * @param pVmxTransient The VMX-transient structure.
12541 */
12542DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12543{
12544 /** @todo NSTVMX: Remove after debugging page-fault issue. */
12545#ifdef DEBUG_ramshankar
12546 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
12547 Log4Func(("cs:rip=%#04x:%#RX64 rsp=%#RX64 eflags=%#RX32 cr3=%#RX64\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
12548 pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u32, pVCpu->cpum.GstCtx.cr3));
12549#endif
12550
12551 uint32_t const uExitReason = pVmxTransient->uExitReason;
12552 switch (uExitReason)
12553 {
12554 case VMX_EXIT_EPT_MISCONFIG: return hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient);
12555 case VMX_EXIT_EPT_VIOLATION: return hmR0VmxExitEptViolation(pVCpu, pVmxTransient);
12556 case VMX_EXIT_XCPT_OR_NMI: return hmR0VmxExitXcptOrNmiNested(pVCpu, pVmxTransient);
12557 case VMX_EXIT_IO_INSTR: return hmR0VmxExitIoInstrNested(pVCpu, pVmxTransient);
12558 case VMX_EXIT_HLT: return hmR0VmxExitHltNested(pVCpu, pVmxTransient);
12559
12560 /*
12561 * We shouldn't direct host physical interrupts to the nested-guest.
12562 */
12563 case VMX_EXIT_EXT_INT:
12564 return hmR0VmxExitExtInt(pVCpu, pVmxTransient);
12565
12566 /*
12567 * Instructions that cause VM-exits unconditionally or the condition is
12568 * always is taken solely from the guest hypervisor (meaning if the VM-exit
12569 * happens, it's guaranteed to be a nested-guest VM-exit).
12570 *
12571 * - Provides VM-exit instruction length ONLY.
12572 */
12573 case VMX_EXIT_CPUID: /* Unconditional. */
12574 case VMX_EXIT_VMCALL:
12575 case VMX_EXIT_GETSEC:
12576 case VMX_EXIT_INVD:
12577 case VMX_EXIT_XSETBV:
12578 case VMX_EXIT_VMLAUNCH:
12579 case VMX_EXIT_VMRESUME:
12580 case VMX_EXIT_VMXOFF:
12581 case VMX_EXIT_ENCLS: /* Condition specified solely by guest hypervisor. */
12582 case VMX_EXIT_VMFUNC:
12583 return hmR0VmxExitInstrNested(pVCpu, pVmxTransient);
12584
12585 /*
12586 * Instructions that cause VM-exits unconditionally or the condition is
12587 * always is taken solely from the guest hypervisor (meaning if the VM-exit
12588 * happens, it's guaranteed to be a nested-guest VM-exit).
12589 *
12590 * - Provides VM-exit instruction length.
12591 * - Provides VM-exit information.
12592 * - Optionally provides Exit qualification.
12593 *
12594 * Since Exit qualification is 0 for all VM-exits where it is not
12595 * applicable, reading and passing it to the guest should produce
12596 * defined behavior.
12597 *
12598 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
12599 */
12600 case VMX_EXIT_INVEPT: /* Unconditional. */
12601 case VMX_EXIT_INVVPID:
12602 case VMX_EXIT_VMCLEAR:
12603 case VMX_EXIT_VMPTRLD:
12604 case VMX_EXIT_VMPTRST:
12605 case VMX_EXIT_VMXON:
12606 case VMX_EXIT_GDTR_IDTR_ACCESS: /* Condition specified solely by guest hypervisor. */
12607 case VMX_EXIT_LDTR_TR_ACCESS:
12608 case VMX_EXIT_RDRAND:
12609 case VMX_EXIT_RDSEED:
12610 case VMX_EXIT_XSAVES:
12611 case VMX_EXIT_XRSTORS:
12612 case VMX_EXIT_UMWAIT:
12613 case VMX_EXIT_TPAUSE:
12614 return hmR0VmxExitInstrWithInfoNested(pVCpu, pVmxTransient);
12615
12616 case VMX_EXIT_RDTSC: return hmR0VmxExitRdtscNested(pVCpu, pVmxTransient);
12617 case VMX_EXIT_RDTSCP: return hmR0VmxExitRdtscpNested(pVCpu, pVmxTransient);
12618 case VMX_EXIT_RDMSR: return hmR0VmxExitRdmsrNested(pVCpu, pVmxTransient);
12619 case VMX_EXIT_WRMSR: return hmR0VmxExitWrmsrNested(pVCpu, pVmxTransient);
12620 case VMX_EXIT_INVLPG: return hmR0VmxExitInvlpgNested(pVCpu, pVmxTransient);
12621 case VMX_EXIT_INVPCID: return hmR0VmxExitInvpcidNested(pVCpu, pVmxTransient);
12622 case VMX_EXIT_TASK_SWITCH: return hmR0VmxExitTaskSwitchNested(pVCpu, pVmxTransient);
12623 case VMX_EXIT_WBINVD: return hmR0VmxExitWbinvdNested(pVCpu, pVmxTransient);
12624 case VMX_EXIT_MTF: return hmR0VmxExitMtfNested(pVCpu, pVmxTransient);
12625 case VMX_EXIT_APIC_ACCESS: return hmR0VmxExitApicAccessNested(pVCpu, pVmxTransient);
12626 case VMX_EXIT_APIC_WRITE: return hmR0VmxExitApicWriteNested(pVCpu, pVmxTransient);
12627 case VMX_EXIT_VIRTUALIZED_EOI: return hmR0VmxExitVirtEoiNested(pVCpu, pVmxTransient);
12628 case VMX_EXIT_MOV_CRX: return hmR0VmxExitMovCRxNested(pVCpu, pVmxTransient);
12629 case VMX_EXIT_INT_WINDOW: return hmR0VmxExitIntWindowNested(pVCpu, pVmxTransient);
12630 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindowNested(pVCpu, pVmxTransient);
12631 case VMX_EXIT_TPR_BELOW_THRESHOLD: return hmR0VmxExitTprBelowThresholdNested(pVCpu, pVmxTransient);
12632 case VMX_EXIT_MWAIT: return hmR0VmxExitMwaitNested(pVCpu, pVmxTransient);
12633 case VMX_EXIT_MONITOR: return hmR0VmxExitMonitorNested(pVCpu, pVmxTransient);
12634 case VMX_EXIT_PAUSE: return hmR0VmxExitPauseNested(pVCpu, pVmxTransient);
12635
12636 case VMX_EXIT_PREEMPT_TIMER:
12637 {
12638 /** @todo NSTVMX: Preempt timer. */
12639 return hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient);
12640 }
12641
12642 case VMX_EXIT_MOV_DRX: return hmR0VmxExitMovDRxNested(pVCpu, pVmxTransient);
12643 case VMX_EXIT_RDPMC: return hmR0VmxExitRdpmcNested(pVCpu, pVmxTransient);
12644
12645 case VMX_EXIT_VMREAD:
12646 case VMX_EXIT_VMWRITE: return hmR0VmxExitVmreadVmwriteNested(pVCpu, pVmxTransient);
12647
12648 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFaultNested(pVCpu, pVmxTransient);
12649 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestStateNested(pVCpu, pVmxTransient);
12650
12651 case VMX_EXIT_INIT_SIGNAL:
12652 case VMX_EXIT_SIPI:
12653 case VMX_EXIT_IO_SMI:
12654 case VMX_EXIT_SMI:
12655 case VMX_EXIT_ERR_MSR_LOAD:
12656 case VMX_EXIT_ERR_MACHINE_CHECK:
12657 case VMX_EXIT_PML_FULL:
12658 case VMX_EXIT_RSM:
12659 default:
12660 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
12661 }
12662}
12663#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
12664
12665
12666/** @name VM-exit helpers.
12667 * @{
12668 */
12669/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12670/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= VM-exit helpers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
12671/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12672
12673/** Macro for VM-exits called unexpectedly. */
12674#define HMVMX_UNEXPECTED_EXIT_RET(a_pVCpu, a_HmError) \
12675 do { \
12676 (a_pVCpu)->hm.s.u32HMError = (a_HmError); \
12677 return VERR_VMX_UNEXPECTED_EXIT; \
12678 } while (0)
12679
12680#ifdef VBOX_STRICT
12681/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
12682# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
12683 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
12684
12685# define HMVMX_ASSERT_PREEMPT_CPUID() \
12686 do { \
12687 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
12688 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
12689 } while (0)
12690
12691# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12692 do { \
12693 AssertPtr((a_pVCpu)); \
12694 AssertPtr((a_pVmxTransient)); \
12695 Assert((a_pVmxTransient)->fVMEntryFailed == false); \
12696 Assert((a_pVmxTransient)->pVmcsInfo); \
12697 Assert(ASMIntAreEnabled()); \
12698 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
12699 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
12700 Log4Func(("vcpu[%RU32]\n", (a_pVCpu)->idCpu)); \
12701 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
12702 if (VMMR0IsLogFlushDisabled((a_pVCpu))) \
12703 HMVMX_ASSERT_PREEMPT_CPUID(); \
12704 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
12705 } while (0)
12706
12707# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12708 do { \
12709 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); \
12710 Assert((a_pVmxTransient)->fIsNestedGuest); \
12711 } while (0)
12712
12713# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12714 do { \
12715 Log4Func(("\n")); \
12716 } while (0)
12717#else
12718# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12719 do { \
12720 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
12721 NOREF((a_pVCpu)); NOREF((a_pVmxTransient)); \
12722 } while (0)
12723
12724# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
12725 do { HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); } while (0)
12726
12727# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) do { } while (0)
12728#endif
12729
12730#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12731/** Macro that does the necessary privilege checks and intercepted VM-exits for
12732 * guests that attempted to execute a VMX instruction. */
12733# define HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(a_pVCpu, a_uExitReason) \
12734 do \
12735 { \
12736 VBOXSTRICTRC rcStrictTmp = hmR0VmxCheckExitDueToVmxInstr((a_pVCpu), (a_uExitReason)); \
12737 if (rcStrictTmp == VINF_SUCCESS) \
12738 { /* likely */ } \
12739 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
12740 { \
12741 Assert((a_pVCpu)->hm.s.Event.fPending); \
12742 Log4Func(("Privilege checks failed -> %#x\n", VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo))); \
12743 return VINF_SUCCESS; \
12744 } \
12745 else \
12746 { \
12747 int rcTmp = VBOXSTRICTRC_VAL(rcStrictTmp); \
12748 AssertMsgFailedReturn(("Unexpected failure. rc=%Rrc", rcTmp), rcTmp); \
12749 } \
12750 } while (0)
12751
12752/** Macro that decodes a memory operand for an VM-exit caused by an instruction. */
12753# define HMVMX_DECODE_MEM_OPERAND(a_pVCpu, a_uExitInstrInfo, a_uExitQual, a_enmMemAccess, a_pGCPtrEffAddr) \
12754 do \
12755 { \
12756 VBOXSTRICTRC rcStrictTmp = hmR0VmxDecodeMemOperand((a_pVCpu), (a_uExitInstrInfo), (a_uExitQual), (a_enmMemAccess), \
12757 (a_pGCPtrEffAddr)); \
12758 if (rcStrictTmp == VINF_SUCCESS) \
12759 { /* likely */ } \
12760 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
12761 { \
12762 uint8_t const uXcptTmp = VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo); \
12763 Log4Func(("Memory operand decoding failed, raising xcpt %#x\n", uXcptTmp)); \
12764 NOREF(uXcptTmp); \
12765 return VINF_SUCCESS; \
12766 } \
12767 else \
12768 { \
12769 Log4Func(("hmR0VmxDecodeMemOperand failed. rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrictTmp))); \
12770 return rcStrictTmp; \
12771 } \
12772 } while (0)
12773#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
12774
12775
12776/**
12777 * Advances the guest RIP by the specified number of bytes.
12778 *
12779 * @param pVCpu The cross context virtual CPU structure.
12780 * @param cbInstr Number of bytes to advance the RIP by.
12781 *
12782 * @remarks No-long-jump zone!!!
12783 */
12784DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPUCC pVCpu, uint32_t cbInstr)
12785{
12786 /* Advance the RIP. */
12787 pVCpu->cpum.GstCtx.rip += cbInstr;
12788 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
12789
12790 /* Update interrupt inhibition. */
12791 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
12792 && pVCpu->cpum.GstCtx.rip != EMGetInhibitInterruptsPC(pVCpu))
12793 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
12794}
12795
12796
12797/**
12798 * Advances the guest RIP after reading it from the VMCS.
12799 *
12800 * @returns VBox status code, no informational status codes.
12801 * @param pVCpu The cross context virtual CPU structure.
12802 * @param pVmxTransient The VMX-transient structure.
12803 *
12804 * @remarks No-long-jump zone!!!
12805 */
12806static int hmR0VmxAdvanceGuestRip(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12807{
12808 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12809 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
12810 AssertRCReturn(rc, rc);
12811
12812 hmR0VmxAdvanceGuestRipBy(pVCpu, pVmxTransient->cbExitInstr);
12813 return VINF_SUCCESS;
12814}
12815
12816
12817/**
12818 * Handle a condition that occurred while delivering an event through the guest or
12819 * nested-guest IDT.
12820 *
12821 * @returns Strict VBox status code (i.e. informational status codes too).
12822 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
12823 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
12824 * to continue execution of the guest which will delivery the \#DF.
12825 * @retval VINF_EM_RESET if we detected a triple-fault condition.
12826 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
12827 *
12828 * @param pVCpu The cross context virtual CPU structure.
12829 * @param pVmxTransient The VMX-transient structure.
12830 *
12831 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
12832 * Additionally, HMVMX_READ_EXIT_QUALIFICATION is required if the VM-exit
12833 * is due to an EPT violation, PML full or SPP-related event.
12834 *
12835 * @remarks No-long-jump zone!!!
12836 */
12837static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12838{
12839 Assert(!pVCpu->hm.s.Event.fPending);
12840 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
12841 if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
12842 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
12843 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
12844 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_EXIT_QUALIFICATION);
12845
12846 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
12847 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
12848 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo;
12849 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
12850 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo))
12851 {
12852 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo);
12853 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo);
12854
12855 /*
12856 * If the event was a software interrupt (generated with INT n) or a software exception
12857 * (generated by INT3/INTO) or a privileged software exception (generated by INT1), we
12858 * can handle the VM-exit and continue guest execution which will re-execute the
12859 * instruction rather than re-injecting the exception, as that can cause premature
12860 * trips to ring-3 before injection and involve TRPM which currently has no way of
12861 * storing that these exceptions were caused by these instructions (ICEBP's #DB poses
12862 * the problem).
12863 */
12864 IEMXCPTRAISE enmRaise;
12865 IEMXCPTRAISEINFO fRaiseInfo;
12866 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
12867 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
12868 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
12869 {
12870 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
12871 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
12872 }
12873 else if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo))
12874 {
12875 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
12876 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo);
12877 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT);
12878
12879 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
12880 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
12881
12882 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo);
12883
12884 /* Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF(). */
12885 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
12886 {
12887 pVmxTransient->fVectoringPF = true;
12888 enmRaise = IEMXCPTRAISE_PREV_EVENT;
12889 }
12890 }
12891 else
12892 {
12893 /*
12894 * If an exception or hardware interrupt delivery caused an EPT violation/misconfig or APIC access
12895 * VM-exit, then the VM-exit interruption-information will not be valid and we end up here.
12896 * It is sufficient to reflect the original event to the guest after handling the VM-exit.
12897 */
12898 Assert( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
12899 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
12900 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
12901 enmRaise = IEMXCPTRAISE_PREV_EVENT;
12902 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
12903 }
12904
12905 /*
12906 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
12907 * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
12908 * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
12909 * subsequent VM-entry would fail, see @bugref{7445}.
12910 *
12911 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception".
12912 */
12913 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
12914 && enmRaise == IEMXCPTRAISE_PREV_EVENT
12915 && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
12916 && CPUMIsGuestNmiBlocking(pVCpu))
12917 {
12918 CPUMSetGuestNmiBlocking(pVCpu, false);
12919 }
12920
12921 switch (enmRaise)
12922 {
12923 case IEMXCPTRAISE_CURRENT_XCPT:
12924 {
12925 Log4Func(("IDT: Pending secondary Xcpt: idtinfo=%#RX64 exitinfo=%#RX64\n", uIdtVectorInfo, uExitIntInfo));
12926 Assert(rcStrict == VINF_SUCCESS);
12927 break;
12928 }
12929
12930 case IEMXCPTRAISE_PREV_EVENT:
12931 {
12932 uint32_t u32ErrCode;
12933 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo))
12934 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
12935 else
12936 u32ErrCode = 0;
12937
12938 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
12939 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflect);
12940 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(uIdtVectorInfo), 0 /* cbInstr */,
12941 u32ErrCode, pVCpu->cpum.GstCtx.cr2);
12942
12943 Log4Func(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntInfo,
12944 pVCpu->hm.s.Event.u32ErrCode));
12945 Assert(rcStrict == VINF_SUCCESS);
12946 break;
12947 }
12948
12949 case IEMXCPTRAISE_REEXEC_INSTR:
12950 Assert(rcStrict == VINF_SUCCESS);
12951 break;
12952
12953 case IEMXCPTRAISE_DOUBLE_FAULT:
12954 {
12955 /*
12956 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
12957 * second #PF as a guest #PF (and not a shadow #PF) and needs to be converted into a #DF.
12958 */
12959 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
12960 {
12961 pVmxTransient->fVectoringDoublePF = true;
12962 Log4Func(("IDT: Vectoring double #PF %#RX64 cr2=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo,
12963 pVCpu->cpum.GstCtx.cr2));
12964 rcStrict = VINF_SUCCESS;
12965 }
12966 else
12967 {
12968 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectConvertDF);
12969 hmR0VmxSetPendingXcptDF(pVCpu);
12970 Log4Func(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntInfo,
12971 uIdtVector, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
12972 rcStrict = VINF_HM_DOUBLE_FAULT;
12973 }
12974 break;
12975 }
12976
12977 case IEMXCPTRAISE_TRIPLE_FAULT:
12978 {
12979 Log4Func(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector,
12980 VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
12981 rcStrict = VINF_EM_RESET;
12982 break;
12983 }
12984
12985 case IEMXCPTRAISE_CPU_HANG:
12986 {
12987 Log4Func(("IDT: Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", fRaiseInfo));
12988 rcStrict = VERR_EM_GUEST_CPU_HANG;
12989 break;
12990 }
12991
12992 default:
12993 {
12994 AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
12995 rcStrict = VERR_VMX_IPE_2;
12996 break;
12997 }
12998 }
12999 }
13000 else if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
13001 && !CPUMIsGuestNmiBlocking(pVCpu))
13002 {
13003 if ( VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)
13004 && VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo) != X86_XCPT_DF
13005 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(uExitIntInfo))
13006 {
13007 /*
13008 * Execution of IRET caused a fault when NMI blocking was in effect (i.e we're in
13009 * the guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13010 * that NMIs remain blocked until the IRET execution is completed.
13011 *
13012 * See Intel spec. 31.7.1.2 "Resuming Guest Software After Handling An Exception".
13013 */
13014 CPUMSetGuestNmiBlocking(pVCpu, true);
13015 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13016 }
13017 else if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
13018 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
13019 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
13020 {
13021 /*
13022 * Execution of IRET caused an EPT violation, page-modification log-full event or
13023 * SPP-related event VM-exit when NMI blocking was in effect (i.e. we're in the
13024 * guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13025 * that NMIs remain blocked until the IRET execution is completed.
13026 *
13027 * See Intel spec. 27.2.3 "Information about NMI unblocking due to IRET"
13028 */
13029 if (VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(pVmxTransient->uExitQual))
13030 {
13031 CPUMSetGuestNmiBlocking(pVCpu, true);
13032 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13033 }
13034 }
13035 }
13036
13037 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
13038 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
13039 return rcStrict;
13040}
13041
13042
13043#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13044/**
13045 * Perform the relevant VMX instruction checks for VM-exits that occurred due to the
13046 * guest attempting to execute a VMX instruction.
13047 *
13048 * @returns Strict VBox status code (i.e. informational status codes too).
13049 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13050 * @retval VINF_HM_PENDING_XCPT if an exception was raised.
13051 *
13052 * @param pVCpu The cross context virtual CPU structure.
13053 * @param uExitReason The VM-exit reason.
13054 *
13055 * @todo NSTVMX: Document other error codes when VM-exit is implemented.
13056 * @remarks No-long-jump zone!!!
13057 */
13058static VBOXSTRICTRC hmR0VmxCheckExitDueToVmxInstr(PVMCPUCC pVCpu, uint32_t uExitReason)
13059{
13060 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS
13061 | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
13062
13063 /*
13064 * The physical CPU would have already checked the CPU mode/code segment.
13065 * We shall just assert here for paranoia.
13066 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
13067 */
13068 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13069 Assert( !CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx)
13070 || CPUMIsGuestIn64BitCodeEx(&pVCpu->cpum.GstCtx));
13071
13072 if (uExitReason == VMX_EXIT_VMXON)
13073 {
13074 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
13075
13076 /*
13077 * We check CR4.VMXE because it is required to be always set while in VMX operation
13078 * by physical CPUs and our CR4 read-shadow is only consulted when executing specific
13079 * instructions (CLTS, LMSW, MOV CR, and SMSW) and thus doesn't affect CPU operation
13080 * otherwise (i.e. physical CPU won't automatically #UD if Cr4Shadow.VMXE is 0).
13081 */
13082 if (!CPUMIsGuestVmxEnabled(&pVCpu->cpum.GstCtx))
13083 {
13084 Log4Func(("CR4.VMXE is not set -> #UD\n"));
13085 hmR0VmxSetPendingXcptUD(pVCpu);
13086 return VINF_HM_PENDING_XCPT;
13087 }
13088 }
13089 else if (!CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx))
13090 {
13091 /*
13092 * The guest has not entered VMX operation but attempted to execute a VMX instruction
13093 * (other than VMXON), we need to raise a #UD.
13094 */
13095 Log4Func(("Not in VMX root mode -> #UD\n"));
13096 hmR0VmxSetPendingXcptUD(pVCpu);
13097 return VINF_HM_PENDING_XCPT;
13098 }
13099
13100 /* All other checks (including VM-exit intercepts) are handled by IEM instruction emulation. */
13101 return VINF_SUCCESS;
13102}
13103
13104
13105/**
13106 * Decodes the memory operand of an instruction that caused a VM-exit.
13107 *
13108 * The Exit qualification field provides the displacement field for memory
13109 * operand instructions, if any.
13110 *
13111 * @returns Strict VBox status code (i.e. informational status codes too).
13112 * @retval VINF_SUCCESS if the operand was successfully decoded.
13113 * @retval VINF_HM_PENDING_XCPT if an exception was raised while decoding the
13114 * operand.
13115 * @param pVCpu The cross context virtual CPU structure.
13116 * @param uExitInstrInfo The VM-exit instruction information field.
13117 * @param enmMemAccess The memory operand's access type (read or write).
13118 * @param GCPtrDisp The instruction displacement field, if any. For
13119 * RIP-relative addressing pass RIP + displacement here.
13120 * @param pGCPtrMem Where to store the effective destination memory address.
13121 *
13122 * @remarks Warning! This function ASSUMES the instruction cannot be used in real or
13123 * virtual-8086 mode hence skips those checks while verifying if the
13124 * segment is valid.
13125 */
13126static VBOXSTRICTRC hmR0VmxDecodeMemOperand(PVMCPUCC pVCpu, uint32_t uExitInstrInfo, RTGCPTR GCPtrDisp, VMXMEMACCESS enmMemAccess,
13127 PRTGCPTR pGCPtrMem)
13128{
13129 Assert(pGCPtrMem);
13130 Assert(!CPUMIsGuestInRealOrV86Mode(pVCpu));
13131 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_EFER
13132 | CPUMCTX_EXTRN_CR0);
13133
13134 static uint64_t const s_auAddrSizeMasks[] = { UINT64_C(0xffff), UINT64_C(0xffffffff), UINT64_C(0xffffffffffffffff) };
13135 static uint64_t const s_auAccessSizeMasks[] = { sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t) };
13136 AssertCompile(RT_ELEMENTS(s_auAccessSizeMasks) == RT_ELEMENTS(s_auAddrSizeMasks));
13137
13138 VMXEXITINSTRINFO ExitInstrInfo;
13139 ExitInstrInfo.u = uExitInstrInfo;
13140 uint8_t const uAddrSize = ExitInstrInfo.All.u3AddrSize;
13141 uint8_t const iSegReg = ExitInstrInfo.All.iSegReg;
13142 bool const fIdxRegValid = !ExitInstrInfo.All.fIdxRegInvalid;
13143 uint8_t const iIdxReg = ExitInstrInfo.All.iIdxReg;
13144 uint8_t const uScale = ExitInstrInfo.All.u2Scaling;
13145 bool const fBaseRegValid = !ExitInstrInfo.All.fBaseRegInvalid;
13146 uint8_t const iBaseReg = ExitInstrInfo.All.iBaseReg;
13147 bool const fIsMemOperand = !ExitInstrInfo.All.fIsRegOperand;
13148 bool const fIsLongMode = CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx);
13149
13150 /*
13151 * Validate instruction information.
13152 * This shouldn't happen on real hardware but useful while testing our nested hardware-virtualization code.
13153 */
13154 AssertLogRelMsgReturn(uAddrSize < RT_ELEMENTS(s_auAddrSizeMasks),
13155 ("Invalid address size. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_1);
13156 AssertLogRelMsgReturn(iSegReg < X86_SREG_COUNT,
13157 ("Invalid segment register. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_2);
13158 AssertLogRelMsgReturn(fIsMemOperand,
13159 ("Expected memory operand. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_3);
13160
13161 /*
13162 * Compute the complete effective address.
13163 *
13164 * See AMD instruction spec. 1.4.2 "SIB Byte Format"
13165 * See AMD spec. 4.5.2 "Segment Registers".
13166 */
13167 RTGCPTR GCPtrMem = GCPtrDisp;
13168 if (fBaseRegValid)
13169 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iBaseReg].u64;
13170 if (fIdxRegValid)
13171 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iIdxReg].u64 << uScale;
13172
13173 RTGCPTR const GCPtrOff = GCPtrMem;
13174 if ( !fIsLongMode
13175 || iSegReg >= X86_SREG_FS)
13176 GCPtrMem += pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
13177 GCPtrMem &= s_auAddrSizeMasks[uAddrSize];
13178
13179 /*
13180 * Validate effective address.
13181 * See AMD spec. 4.5.3 "Segment Registers in 64-Bit Mode".
13182 */
13183 uint8_t const cbAccess = s_auAccessSizeMasks[uAddrSize];
13184 Assert(cbAccess > 0);
13185 if (fIsLongMode)
13186 {
13187 if (X86_IS_CANONICAL(GCPtrMem))
13188 {
13189 *pGCPtrMem = GCPtrMem;
13190 return VINF_SUCCESS;
13191 }
13192
13193 /** @todo r=ramshankar: We should probably raise \#SS or \#GP. See AMD spec. 4.12.2
13194 * "Data Limit Checks in 64-bit Mode". */
13195 Log4Func(("Long mode effective address is not canonical GCPtrMem=%#RX64\n", GCPtrMem));
13196 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13197 return VINF_HM_PENDING_XCPT;
13198 }
13199
13200 /*
13201 * This is a watered down version of iemMemApplySegment().
13202 * Parts that are not applicable for VMX instructions like real-or-v8086 mode
13203 * and segment CPL/DPL checks are skipped.
13204 */
13205 RTGCPTR32 const GCPtrFirst32 = (RTGCPTR32)GCPtrOff;
13206 RTGCPTR32 const GCPtrLast32 = GCPtrFirst32 + cbAccess - 1;
13207 PCCPUMSELREG pSel = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
13208
13209 /* Check if the segment is present and usable. */
13210 if ( pSel->Attr.n.u1Present
13211 && !pSel->Attr.n.u1Unusable)
13212 {
13213 Assert(pSel->Attr.n.u1DescType);
13214 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
13215 {
13216 /* Check permissions for the data segment. */
13217 if ( enmMemAccess == VMXMEMACCESS_WRITE
13218 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE))
13219 {
13220 Log4Func(("Data segment access invalid. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13221 hmR0VmxSetPendingXcptGP(pVCpu, iSegReg);
13222 return VINF_HM_PENDING_XCPT;
13223 }
13224
13225 /* Check limits if it's a normal data segment. */
13226 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
13227 {
13228 if ( GCPtrFirst32 > pSel->u32Limit
13229 || GCPtrLast32 > pSel->u32Limit)
13230 {
13231 Log4Func(("Data segment limit exceeded. "
13232 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13233 GCPtrLast32, pSel->u32Limit));
13234 if (iSegReg == X86_SREG_SS)
13235 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13236 else
13237 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13238 return VINF_HM_PENDING_XCPT;
13239 }
13240 }
13241 else
13242 {
13243 /* Check limits if it's an expand-down data segment.
13244 Note! The upper boundary is defined by the B bit, not the G bit! */
13245 if ( GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
13246 || GCPtrLast32 > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
13247 {
13248 Log4Func(("Expand-down data segment limit exceeded. "
13249 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13250 GCPtrLast32, pSel->u32Limit));
13251 if (iSegReg == X86_SREG_SS)
13252 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13253 else
13254 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13255 return VINF_HM_PENDING_XCPT;
13256 }
13257 }
13258 }
13259 else
13260 {
13261 /* Check permissions for the code segment. */
13262 if ( enmMemAccess == VMXMEMACCESS_WRITE
13263 || ( enmMemAccess == VMXMEMACCESS_READ
13264 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)))
13265 {
13266 Log4Func(("Code segment access invalid. Attr=%#RX32\n", pSel->Attr.u));
13267 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13268 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13269 return VINF_HM_PENDING_XCPT;
13270 }
13271
13272 /* Check limits for the code segment (normal/expand-down not applicable for code segments). */
13273 if ( GCPtrFirst32 > pSel->u32Limit
13274 || GCPtrLast32 > pSel->u32Limit)
13275 {
13276 Log4Func(("Code segment limit exceeded. GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n",
13277 GCPtrFirst32, GCPtrLast32, pSel->u32Limit));
13278 if (iSegReg == X86_SREG_SS)
13279 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13280 else
13281 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13282 return VINF_HM_PENDING_XCPT;
13283 }
13284 }
13285 }
13286 else
13287 {
13288 Log4Func(("Not present or unusable segment. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13289 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13290 return VINF_HM_PENDING_XCPT;
13291 }
13292
13293 *pGCPtrMem = GCPtrMem;
13294 return VINF_SUCCESS;
13295}
13296#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13297
13298
13299/**
13300 * VM-exit helper for LMSW.
13301 */
13302static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst)
13303{
13304 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13305 AssertRCReturn(rc, rc);
13306
13307 VBOXSTRICTRC rcStrict = IEMExecDecodedLmsw(pVCpu, cbInstr, uMsw, GCPtrEffDst);
13308 AssertMsg( rcStrict == VINF_SUCCESS
13309 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13310
13311 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13312 if (rcStrict == VINF_IEM_RAISED_XCPT)
13313 {
13314 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13315 rcStrict = VINF_SUCCESS;
13316 }
13317
13318 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
13319 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13320 return rcStrict;
13321}
13322
13323
13324/**
13325 * VM-exit helper for CLTS.
13326 */
13327static VBOXSTRICTRC hmR0VmxExitClts(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
13328{
13329 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13330 AssertRCReturn(rc, rc);
13331
13332 VBOXSTRICTRC rcStrict = IEMExecDecodedClts(pVCpu, cbInstr);
13333 AssertMsg( rcStrict == VINF_SUCCESS
13334 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13335
13336 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13337 if (rcStrict == VINF_IEM_RAISED_XCPT)
13338 {
13339 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13340 rcStrict = VINF_SUCCESS;
13341 }
13342
13343 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
13344 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13345 return rcStrict;
13346}
13347
13348
13349/**
13350 * VM-exit helper for MOV from CRx (CRx read).
13351 */
13352static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13353{
13354 Assert(iCrReg < 16);
13355 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
13356
13357 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13358 AssertRCReturn(rc, rc);
13359
13360 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxRead(pVCpu, cbInstr, iGReg, iCrReg);
13361 AssertMsg( rcStrict == VINF_SUCCESS
13362 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13363
13364 if (iGReg == X86_GREG_xSP)
13365 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_RSP);
13366 else
13367 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13368#ifdef VBOX_WITH_STATISTICS
13369 switch (iCrReg)
13370 {
13371 case 0: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Read); break;
13372 case 2: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Read); break;
13373 case 3: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Read); break;
13374 case 4: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Read); break;
13375 case 8: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Read); break;
13376 }
13377#endif
13378 Log4Func(("CR%d Read access rcStrict=%Rrc\n", iCrReg, VBOXSTRICTRC_VAL(rcStrict)));
13379 return rcStrict;
13380}
13381
13382
13383/**
13384 * VM-exit helper for MOV to CRx (CRx write).
13385 */
13386static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13387{
13388 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13389 AssertRCReturn(rc, rc);
13390
13391 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, cbInstr, iCrReg, iGReg);
13392 AssertMsg( rcStrict == VINF_SUCCESS
13393 || rcStrict == VINF_IEM_RAISED_XCPT
13394 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13395
13396 switch (iCrReg)
13397 {
13398 case 0:
13399 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13400 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Write);
13401 Log4Func(("CR0 write. rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr0));
13402 break;
13403
13404 case 2:
13405 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Write);
13406 /* Nothing to do here, CR2 it's not part of the VMCS. */
13407 break;
13408
13409 case 3:
13410 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR3);
13411 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Write);
13412 Log4Func(("CR3 write. rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr3));
13413 break;
13414
13415 case 4:
13416 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR4);
13417 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Write);
13418 Log4Func(("CR4 write. rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n", VBOXSTRICTRC_VAL(rcStrict),
13419 pVCpu->cpum.GstCtx.cr4, pVCpu->hm.s.fLoadSaveGuestXcr0));
13420 break;
13421
13422 case 8:
13423 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged,
13424 HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_APIC_TPR);
13425 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Write);
13426 break;
13427
13428 default:
13429 AssertMsgFailed(("Invalid CRx register %#x\n", iCrReg));
13430 break;
13431 }
13432
13433 if (rcStrict == VINF_IEM_RAISED_XCPT)
13434 {
13435 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13436 rcStrict = VINF_SUCCESS;
13437 }
13438 return rcStrict;
13439}
13440
13441
13442/**
13443 * VM-exit exception handler for \#PF (Page-fault exception).
13444 *
13445 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13446 */
13447static VBOXSTRICTRC hmR0VmxExitXcptPF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13448{
13449 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13450 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
13451 hmR0VmxReadExitQualVmcs(pVmxTransient);
13452
13453 if (!pVM->hm.s.fNestedPaging)
13454 { /* likely */ }
13455 else
13456 {
13457#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13458 Assert(pVmxTransient->fIsNestedGuest || pVCpu->hm.s.fUsingDebugLoop);
13459#endif
13460 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13461 if (!pVmxTransient->fVectoringDoublePF)
13462 {
13463 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13464 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual);
13465 }
13466 else
13467 {
13468 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13469 Assert(!pVmxTransient->fIsNestedGuest);
13470 hmR0VmxSetPendingXcptDF(pVCpu);
13471 Log4Func(("Pending #DF due to vectoring #PF w/ NestedPaging\n"));
13472 }
13473 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13474 return VINF_SUCCESS;
13475 }
13476
13477 Assert(!pVmxTransient->fIsNestedGuest);
13478
13479 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
13480 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
13481 if (pVmxTransient->fVectoringPF)
13482 {
13483 Assert(pVCpu->hm.s.Event.fPending);
13484 return VINF_EM_RAW_INJECT_TRPM_EVENT;
13485 }
13486
13487 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13488 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13489 AssertRCReturn(rc, rc);
13490
13491 Log4Func(("#PF: cr2=%#RX64 cs:rip=%#04x:%#RX64 uErrCode %#RX32 cr3=%#RX64\n", pVmxTransient->uExitQual, pCtx->cs.Sel,
13492 pCtx->rip, pVmxTransient->uExitIntErrorCode, pCtx->cr3));
13493
13494 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQual, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
13495 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pCtx), (RTGCPTR)pVmxTransient->uExitQual);
13496
13497 Log4Func(("#PF: rc=%Rrc\n", rc));
13498 if (rc == VINF_SUCCESS)
13499 {
13500 /*
13501 * This is typically a shadow page table sync or a MMIO instruction. But we may have
13502 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
13503 */
13504 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13505 TRPMResetTrap(pVCpu);
13506 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
13507 return rc;
13508 }
13509
13510 if (rc == VINF_EM_RAW_GUEST_TRAP)
13511 {
13512 if (!pVmxTransient->fVectoringDoublePF)
13513 {
13514 /* It's a guest page fault and needs to be reflected to the guest. */
13515 uint32_t uGstErrorCode = TRPMGetErrorCode(pVCpu);
13516 TRPMResetTrap(pVCpu);
13517 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
13518 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13519 uGstErrorCode, pVmxTransient->uExitQual);
13520 }
13521 else
13522 {
13523 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13524 TRPMResetTrap(pVCpu);
13525 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
13526 hmR0VmxSetPendingXcptDF(pVCpu);
13527 Log4Func(("#PF: Pending #DF due to vectoring #PF\n"));
13528 }
13529
13530 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13531 return VINF_SUCCESS;
13532 }
13533
13534 TRPMResetTrap(pVCpu);
13535 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
13536 return rc;
13537}
13538
13539
13540/**
13541 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
13542 *
13543 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13544 */
13545static VBOXSTRICTRC hmR0VmxExitXcptMF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13546{
13547 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13548 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
13549
13550 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0);
13551 AssertRCReturn(rc, rc);
13552
13553 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_NE))
13554 {
13555 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
13556 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
13557
13558 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
13559 * provides VM-exit instruction length. If this causes problem later,
13560 * disassemble the instruction like it's done on AMD-V. */
13561 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
13562 AssertRCReturn(rc2, rc2);
13563 return rc;
13564 }
13565
13566 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbExitInstr,
13567 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13568 return VINF_SUCCESS;
13569}
13570
13571
13572/**
13573 * VM-exit exception handler for \#BP (Breakpoint exception).
13574 *
13575 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13576 */
13577static VBOXSTRICTRC hmR0VmxExitXcptBP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13578{
13579 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13580 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
13581
13582 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13583 AssertRCReturn(rc, rc);
13584
13585 if (!pVmxTransient->fIsNestedGuest)
13586 rc = DBGFRZTrap03Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(&pVCpu->cpum.GstCtx));
13587 else
13588 rc = VINF_EM_RAW_GUEST_TRAP;
13589
13590 if (rc == VINF_EM_RAW_GUEST_TRAP)
13591 {
13592 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13593 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13594 rc = VINF_SUCCESS;
13595 }
13596
13597 Assert(rc == VINF_SUCCESS || rc == VINF_EM_DBG_BREAKPOINT);
13598 return rc;
13599}
13600
13601
13602/**
13603 * VM-exit exception handler for \#AC (Alignment-check exception).
13604 *
13605 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13606 */
13607static VBOXSTRICTRC hmR0VmxExitXcptAC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13608{
13609 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13610 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC);
13611
13612 /* Re-inject it. We'll detect any nesting before getting here. */
13613 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13614 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13615 return VINF_SUCCESS;
13616}
13617
13618
13619/**
13620 * VM-exit exception handler for \#DB (Debug exception).
13621 *
13622 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13623 */
13624static VBOXSTRICTRC hmR0VmxExitXcptDB(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13625{
13626 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13627 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
13628
13629 /*
13630 * Get the DR6-like values from the Exit qualification and pass it to DBGF for processing.
13631 */
13632 hmR0VmxReadExitQualVmcs(pVmxTransient);
13633
13634 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
13635 uint64_t const uDR6 = X86_DR6_INIT_VAL
13636 | (pVmxTransient->uExitQual & ( X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3
13637 | X86_DR6_BD | X86_DR6_BS));
13638
13639 int rc;
13640 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13641 if (!pVmxTransient->fIsNestedGuest)
13642 rc = DBGFRZTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
13643 else
13644 rc = VINF_EM_RAW_GUEST_TRAP;
13645 Log6Func(("rc=%Rrc\n", rc));
13646 if (rc == VINF_EM_RAW_GUEST_TRAP)
13647 {
13648 /*
13649 * The exception was for the guest. Update DR6, DR7.GD and
13650 * IA32_DEBUGCTL.LBR before forwarding it.
13651 * See Intel spec. 27.1 "Architectural State before a VM-Exit".
13652 */
13653 VMMRZCallRing3Disable(pVCpu);
13654 HM_DISABLE_PREEMPT(pVCpu);
13655
13656 pCtx->dr[6] &= ~X86_DR6_B_MASK;
13657 pCtx->dr[6] |= uDR6;
13658 if (CPUMIsGuestDebugStateActive(pVCpu))
13659 ASMSetDR6(pCtx->dr[6]);
13660
13661 HM_RESTORE_PREEMPT();
13662 VMMRZCallRing3Enable(pVCpu);
13663
13664 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_DR7);
13665 AssertRCReturn(rc, rc);
13666
13667 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
13668 pCtx->dr[7] &= ~(uint64_t)X86_DR7_GD;
13669
13670 /* Paranoia. */
13671 pCtx->dr[7] &= ~(uint64_t)X86_DR7_RAZ_MASK;
13672 pCtx->dr[7] |= X86_DR7_RA1_MASK;
13673
13674 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, pCtx->dr[7]);
13675 AssertRC(rc);
13676
13677 /*
13678 * Raise #DB in the guest.
13679 *
13680 * It is important to reflect exactly what the VM-exit gave us (preserving the
13681 * interruption-type) rather than use hmR0VmxSetPendingXcptDB() as the #DB could've
13682 * been raised while executing ICEBP (INT1) and not the regular #DB. Thus it may
13683 * trigger different handling in the CPU (like skipping DPL checks), see @bugref{6398}.
13684 *
13685 * Intel re-documented ICEBP/INT1 on May 2018 previously documented as part of
13686 * Intel 386, see Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
13687 */
13688 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13689 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13690 return VINF_SUCCESS;
13691 }
13692
13693 /*
13694 * Not a guest trap, must be a hypervisor related debug event then.
13695 * Update DR6 in case someone is interested in it.
13696 */
13697 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
13698 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
13699 CPUMSetHyperDR6(pVCpu, uDR6);
13700
13701 return rc;
13702}
13703
13704
13705/**
13706 * Hacks its way around the lovely mesa driver's backdoor accesses.
13707 *
13708 * @sa hmR0SvmHandleMesaDrvGp.
13709 */
13710static int hmR0VmxHandleMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
13711{
13712 LogFunc(("cs:rip=%#04x:%#RX64 rcx=%#RX64 rbx=%#RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->rcx, pCtx->rbx));
13713 RT_NOREF(pCtx);
13714
13715 /* For now we'll just skip the instruction. */
13716 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
13717}
13718
13719
13720/**
13721 * Checks if the \#GP'ing instruction is the mesa driver doing it's lovely
13722 * backdoor logging w/o checking what it is running inside.
13723 *
13724 * This recognizes an "IN EAX,DX" instruction executed in flat ring-3, with the
13725 * backdoor port and magic numbers loaded in registers.
13726 *
13727 * @returns true if it is, false if it isn't.
13728 * @sa hmR0SvmIsMesaDrvGp.
13729 */
13730DECLINLINE(bool) hmR0VmxIsMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
13731{
13732 /* 0xed: IN eAX,dx */
13733 uint8_t abInstr[1];
13734 if (pVmxTransient->cbExitInstr != sizeof(abInstr))
13735 return false;
13736
13737 /* Check that it is #GP(0). */
13738 if (pVmxTransient->uExitIntErrorCode != 0)
13739 return false;
13740
13741 /* Check magic and port. */
13742 Assert(!(pCtx->fExtrn & (CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX)));
13743 /*Log(("hmR0VmxIsMesaDrvGp: rax=%RX64 rdx=%RX64\n", pCtx->rax, pCtx->rdx));*/
13744 if (pCtx->rax != UINT32_C(0x564d5868))
13745 return false;
13746 if (pCtx->dx != UINT32_C(0x5658))
13747 return false;
13748
13749 /* Flat ring-3 CS. */
13750 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_CS);
13751 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_CS));
13752 /*Log(("hmR0VmxIsMesaDrvGp: cs.Attr.n.u2Dpl=%d base=%Rx64\n", pCtx->cs.Attr.n.u2Dpl, pCtx->cs.u64Base));*/
13753 if (pCtx->cs.Attr.n.u2Dpl != 3)
13754 return false;
13755 if (pCtx->cs.u64Base != 0)
13756 return false;
13757
13758 /* Check opcode. */
13759 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_RIP);
13760 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_RIP));
13761 int rc = PGMPhysSimpleReadGCPtr(pVCpu, abInstr, pCtx->rip, sizeof(abInstr));
13762 /*Log(("hmR0VmxIsMesaDrvGp: PGMPhysSimpleReadGCPtr -> %Rrc %#x\n", rc, abInstr[0]));*/
13763 if (RT_FAILURE(rc))
13764 return false;
13765 if (abInstr[0] != 0xed)
13766 return false;
13767
13768 return true;
13769}
13770
13771
13772/**
13773 * VM-exit exception handler for \#GP (General-protection exception).
13774 *
13775 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13776 */
13777static VBOXSTRICTRC hmR0VmxExitXcptGP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13778{
13779 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13780 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
13781
13782 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13783 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13784 if (pVmcsInfo->RealMode.fRealOnV86Active)
13785 { /* likely */ }
13786 else
13787 {
13788#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13789 Assert(pVCpu->hm.s.fUsingDebugLoop || pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
13790#endif
13791 /*
13792 * If the guest is not in real-mode or we have unrestricted guest execution support, or if we are
13793 * executing a nested-guest, reflect #GP to the guest or nested-guest.
13794 */
13795 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13796 AssertRCReturn(rc, rc);
13797 Log4Func(("Gst: cs:rip=%#04x:%#RX64 ErrorCode=%#x cr0=%#RX64 cpl=%u tr=%#04x\n", pCtx->cs.Sel, pCtx->rip,
13798 pVmxTransient->uExitIntErrorCode, pCtx->cr0, CPUMGetGuestCPL(pVCpu), pCtx->tr.Sel));
13799
13800 if ( pVmxTransient->fIsNestedGuest
13801 || !pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv
13802 || !hmR0VmxIsMesaDrvGp(pVCpu, pVmxTransient, pCtx))
13803 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13804 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13805 else
13806 rc = hmR0VmxHandleMesaDrvGp(pVCpu, pVmxTransient, pCtx);
13807 return rc;
13808 }
13809
13810 Assert(CPUMIsGuestInRealModeEx(pCtx));
13811 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest);
13812 Assert(!pVmxTransient->fIsNestedGuest);
13813
13814 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13815 AssertRCReturn(rc, rc);
13816
13817 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
13818 if (rcStrict == VINF_SUCCESS)
13819 {
13820 if (!CPUMIsGuestInRealModeEx(pCtx))
13821 {
13822 /*
13823 * The guest is no longer in real-mode, check if we can continue executing the
13824 * guest using hardware-assisted VMX. Otherwise, fall back to emulation.
13825 */
13826 pVmcsInfo->RealMode.fRealOnV86Active = false;
13827 if (HMCanExecuteVmxGuest(pVCpu->pVMR0, pVCpu, pCtx))
13828 {
13829 Log4Func(("Mode changed but guest still suitable for executing using hardware-assisted VMX\n"));
13830 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13831 }
13832 else
13833 {
13834 Log4Func(("Mode changed -> VINF_EM_RESCHEDULE\n"));
13835 rcStrict = VINF_EM_RESCHEDULE;
13836 }
13837 }
13838 else
13839 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
13840 }
13841 else if (rcStrict == VINF_IEM_RAISED_XCPT)
13842 {
13843 rcStrict = VINF_SUCCESS;
13844 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13845 }
13846 return VBOXSTRICTRC_VAL(rcStrict);
13847}
13848
13849
13850/**
13851 * VM-exit exception handler wrapper for all other exceptions that are not handled
13852 * by a specific handler.
13853 *
13854 * This simply re-injects the exception back into the VM without any special
13855 * processing.
13856 *
13857 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13858 */
13859static VBOXSTRICTRC hmR0VmxExitXcptOthers(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13860{
13861 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13862
13863#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13864 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13865 AssertMsg(pVCpu->hm.s.fUsingDebugLoop || pVmcsInfo->RealMode.fRealOnV86Active || pVmxTransient->fIsNestedGuest,
13866 ("uVector=%#x u32XcptBitmap=%#X32\n",
13867 VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVmcsInfo->u32XcptBitmap));
13868 NOREF(pVmcsInfo);
13869#endif
13870
13871 /*
13872 * Re-inject the exception into the guest. This cannot be a double-fault condition which
13873 * would have been handled while checking exits due to event delivery.
13874 */
13875 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13876
13877#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13878 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
13879 AssertRCReturn(rc, rc);
13880 Log4Func(("Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
13881#endif
13882
13883#ifdef VBOX_WITH_STATISTICS
13884 switch (uVector)
13885 {
13886 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE); break;
13887 case X86_XCPT_DB: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB); break;
13888 case X86_XCPT_BP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP); break;
13889 case X86_XCPT_OF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
13890 case X86_XCPT_BR: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBR); break;
13891 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD); break;
13892 case X86_XCPT_NM: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
13893 case X86_XCPT_DF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDF); break;
13894 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS); break;
13895 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP); break;
13896 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS); break;
13897 case X86_XCPT_GP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP); break;
13898 case X86_XCPT_PF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF); break;
13899 case X86_XCPT_MF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF); break;
13900 case X86_XCPT_AC: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC); break;
13901 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF); break;
13902 default:
13903 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
13904 break;
13905 }
13906#endif
13907
13908 /* We should never call this function for a page-fault, we'd need to pass on the fault address below otherwise. */
13909 Assert(!VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo));
13910 NOREF(uVector);
13911
13912 /* Re-inject the original exception into the guest. */
13913 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13914 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13915 return VINF_SUCCESS;
13916}
13917
13918
13919/**
13920 * VM-exit exception handler for all exceptions (except NMIs!).
13921 *
13922 * @remarks This may be called for both guests and nested-guests. Take care to not
13923 * make assumptions and avoid doing anything that is not relevant when
13924 * executing a nested-guest (e.g., Mesa driver hacks).
13925 */
13926static VBOXSTRICTRC hmR0VmxExitXcpt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13927{
13928 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
13929
13930 /*
13931 * If this VM-exit occurred while delivering an event through the guest IDT, take
13932 * action based on the return code and additional hints (e.g. for page-faults)
13933 * that will be updated in the VMX transient structure.
13934 */
13935 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
13936 if (rcStrict == VINF_SUCCESS)
13937 {
13938 /*
13939 * If an exception caused a VM-exit due to delivery of an event, the original
13940 * event may have to be re-injected into the guest. We shall reinject it and
13941 * continue guest execution. However, page-fault is a complicated case and
13942 * needs additional processing done in hmR0VmxExitXcptPF().
13943 */
13944 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
13945 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13946 if ( !pVCpu->hm.s.Event.fPending
13947 || uVector == X86_XCPT_PF)
13948 {
13949 switch (uVector)
13950 {
13951 case X86_XCPT_PF: return hmR0VmxExitXcptPF(pVCpu, pVmxTransient);
13952 case X86_XCPT_GP: return hmR0VmxExitXcptGP(pVCpu, pVmxTransient);
13953 case X86_XCPT_MF: return hmR0VmxExitXcptMF(pVCpu, pVmxTransient);
13954 case X86_XCPT_DB: return hmR0VmxExitXcptDB(pVCpu, pVmxTransient);
13955 case X86_XCPT_BP: return hmR0VmxExitXcptBP(pVCpu, pVmxTransient);
13956 case X86_XCPT_AC: return hmR0VmxExitXcptAC(pVCpu, pVmxTransient);
13957 default:
13958 return hmR0VmxExitXcptOthers(pVCpu, pVmxTransient);
13959 }
13960 }
13961 /* else: inject pending event before resuming guest execution. */
13962 }
13963 else if (rcStrict == VINF_HM_DOUBLE_FAULT)
13964 {
13965 Assert(pVCpu->hm.s.Event.fPending);
13966 rcStrict = VINF_SUCCESS;
13967 }
13968
13969 return rcStrict;
13970}
13971/** @} */
13972
13973
13974/** @name VM-exit handlers.
13975 * @{
13976 */
13977/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13978/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
13979/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13980
13981/**
13982 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
13983 */
13984HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13985{
13986 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13987 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
13988 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
13989 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
13990 return VINF_SUCCESS;
13991 return VINF_EM_RAW_INTERRUPT;
13992}
13993
13994
13995/**
13996 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI). Conditional
13997 * VM-exit.
13998 */
13999HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14000{
14001 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14002 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
14003
14004 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
14005
14006 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
14007 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14008 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
14009
14010 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14011 Assert( !(pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT)
14012 && uExitIntType != VMX_EXIT_INT_INFO_TYPE_EXT_INT);
14013 NOREF(pVmcsInfo);
14014
14015 VBOXSTRICTRC rcStrict;
14016 switch (uExitIntType)
14017 {
14018 /*
14019 * Host physical NMIs:
14020 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we
14021 * injected it ourselves and anything we inject is not going to cause a VM-exit directly
14022 * for the event being injected[1]. Go ahead and dispatch the NMI to the host[2].
14023 *
14024 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
14025 * See Intel spec. 27.5.5 "Updating Non-Register State".
14026 */
14027 case VMX_EXIT_INT_INFO_TYPE_NMI:
14028 {
14029 rcStrict = hmR0VmxExitHostNmi(pVCpu, pVmcsInfo);
14030 break;
14031 }
14032
14033 /*
14034 * Privileged software exceptions (#DB from ICEBP),
14035 * Software exceptions (#BP and #OF),
14036 * Hardware exceptions:
14037 * Process the required exceptions and resume guest execution if possible.
14038 */
14039 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
14040 Assert(uVector == X86_XCPT_DB);
14041 RT_FALL_THRU();
14042 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
14043 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uExitIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT);
14044 RT_FALL_THRU();
14045 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
14046 {
14047 NOREF(uVector);
14048 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
14049 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14050 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
14051 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
14052
14053 rcStrict = hmR0VmxExitXcpt(pVCpu, pVmxTransient);
14054 break;
14055 }
14056
14057 default:
14058 {
14059 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
14060 rcStrict = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
14061 AssertMsgFailed(("Invalid/unexpected VM-exit interruption info %#x\n", pVmxTransient->uExitIntInfo));
14062 break;
14063 }
14064 }
14065
14066 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
14067 return rcStrict;
14068}
14069
14070
14071/**
14072 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
14073 */
14074HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14075{
14076 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14077
14078 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
14079 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14080 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
14081
14082 /* Evaluate and deliver pending events and resume guest execution. */
14083 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
14084 return VINF_SUCCESS;
14085}
14086
14087
14088/**
14089 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
14090 */
14091HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14092{
14093 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14094
14095 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14096 if (RT_UNLIKELY(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))) /** @todo NSTVMX: Turn this into an assertion. */
14097 {
14098 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
14099 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14100 }
14101
14102 Assert(!CPUMIsGuestNmiBlocking(pVCpu));
14103
14104 /*
14105 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
14106 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
14107 */
14108 uint32_t fIntrState;
14109 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
14110 AssertRC(rc);
14111 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
14112 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
14113 {
14114 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
14115 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
14116
14117 fIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
14118 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
14119 AssertRC(rc);
14120 }
14121
14122 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
14123 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
14124
14125 /* Evaluate and deliver pending events and resume guest execution. */
14126 return VINF_SUCCESS;
14127}
14128
14129
14130/**
14131 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
14132 */
14133HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14134{
14135 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14136 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14137}
14138
14139
14140/**
14141 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
14142 */
14143HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14144{
14145 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14146 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14147}
14148
14149
14150/**
14151 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
14152 */
14153HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14154{
14155 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14156
14157 /*
14158 * Get the state we need and update the exit history entry.
14159 */
14160 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14161 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14162
14163 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14164 AssertRCReturn(rc, rc);
14165
14166 VBOXSTRICTRC rcStrict;
14167 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
14168 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_CPUID),
14169 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
14170 if (!pExitRec)
14171 {
14172 /*
14173 * Regular CPUID instruction execution.
14174 */
14175 rcStrict = IEMExecDecodedCpuid(pVCpu, pVmxTransient->cbExitInstr);
14176 if (rcStrict == VINF_SUCCESS)
14177 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14178 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14179 {
14180 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14181 rcStrict = VINF_SUCCESS;
14182 }
14183 }
14184 else
14185 {
14186 /*
14187 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
14188 */
14189 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14190 AssertRCReturn(rc2, rc2);
14191
14192 Log4(("CpuIdExit/%u: %04x:%08RX64: %#x/%#x -> EMHistoryExec\n",
14193 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx));
14194
14195 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
14196 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14197
14198 Log4(("CpuIdExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
14199 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
14200 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
14201 }
14202 return rcStrict;
14203}
14204
14205
14206/**
14207 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
14208 */
14209HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14210{
14211 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14212
14213 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14214 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4);
14215 AssertRCReturn(rc, rc);
14216
14217 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_SMXE)
14218 return VINF_EM_RAW_EMULATE_INSTR;
14219
14220 AssertMsgFailed(("hmR0VmxExitGetsec: Unexpected VM-exit when CR4.SMXE is 0.\n"));
14221 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14222}
14223
14224
14225/**
14226 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
14227 */
14228HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14229{
14230 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14231
14232 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14233 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14234 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14235 AssertRCReturn(rc, rc);
14236
14237 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtsc(pVCpu, pVmxTransient->cbExitInstr);
14238 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14239 {
14240 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14241 we must reset offsetting on VM-entry. See @bugref{6634}. */
14242 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14243 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14244 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14245 }
14246 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14247 {
14248 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14249 rcStrict = VINF_SUCCESS;
14250 }
14251 return rcStrict;
14252}
14253
14254
14255/**
14256 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
14257 */
14258HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14259{
14260 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14261
14262 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14263 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14264 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_TSC_AUX);
14265 AssertRCReturn(rc, rc);
14266
14267 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtscp(pVCpu, pVmxTransient->cbExitInstr);
14268 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14269 {
14270 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14271 we must reset offsetting on VM-reentry. See @bugref{6634}. */
14272 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14273 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14274 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14275 }
14276 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14277 {
14278 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14279 rcStrict = VINF_SUCCESS;
14280 }
14281 return rcStrict;
14282}
14283
14284
14285/**
14286 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
14287 */
14288HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14289{
14290 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14291
14292 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14293 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_CR0
14294 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS);
14295 AssertRCReturn(rc, rc);
14296
14297 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14298 rc = EMInterpretRdpmc(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
14299 if (RT_LIKELY(rc == VINF_SUCCESS))
14300 {
14301 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14302 Assert(pVmxTransient->cbExitInstr == 2);
14303 }
14304 else
14305 {
14306 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
14307 rc = VERR_EM_INTERPRETER;
14308 }
14309 return rc;
14310}
14311
14312
14313/**
14314 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
14315 */
14316HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14317{
14318 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14319
14320 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
14321 if (EMAreHypercallInstructionsEnabled(pVCpu))
14322 {
14323 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14324 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CR0
14325 | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
14326 AssertRCReturn(rc, rc);
14327
14328 /* Perform the hypercall. */
14329 rcStrict = GIMHypercall(pVCpu, &pVCpu->cpum.GstCtx);
14330 if (rcStrict == VINF_SUCCESS)
14331 {
14332 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14333 AssertRCReturn(rc, rc);
14334 }
14335 else
14336 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
14337 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
14338 || RT_FAILURE(rcStrict));
14339
14340 /* If the hypercall changes anything other than guest's general-purpose registers,
14341 we would need to reload the guest changed bits here before VM-entry. */
14342 }
14343 else
14344 Log4Func(("Hypercalls not enabled\n"));
14345
14346 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
14347 if (RT_FAILURE(rcStrict))
14348 {
14349 hmR0VmxSetPendingXcptUD(pVCpu);
14350 rcStrict = VINF_SUCCESS;
14351 }
14352
14353 return rcStrict;
14354}
14355
14356
14357/**
14358 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
14359 */
14360HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14361{
14362 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14363 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging || pVCpu->hm.s.fUsingDebugLoop);
14364
14365 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14366 hmR0VmxReadExitQualVmcs(pVmxTransient);
14367 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14368 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
14369 AssertRCReturn(rc, rc);
14370
14371 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpg(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->uExitQual);
14372
14373 if (rcStrict == VINF_SUCCESS || rcStrict == VINF_PGM_SYNC_CR3)
14374 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14375 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14376 {
14377 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14378 rcStrict = VINF_SUCCESS;
14379 }
14380 else
14381 AssertMsgFailed(("Unexpected IEMExecDecodedInvlpg(%#RX64) status: %Rrc\n", pVmxTransient->uExitQual,
14382 VBOXSTRICTRC_VAL(rcStrict)));
14383 return rcStrict;
14384}
14385
14386
14387/**
14388 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
14389 */
14390HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14391{
14392 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14393
14394 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14395 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14396 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_DS);
14397 AssertRCReturn(rc, rc);
14398
14399 VBOXSTRICTRC rcStrict = IEMExecDecodedMonitor(pVCpu, pVmxTransient->cbExitInstr);
14400 if (rcStrict == VINF_SUCCESS)
14401 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14402 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14403 {
14404 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14405 rcStrict = VINF_SUCCESS;
14406 }
14407
14408 return rcStrict;
14409}
14410
14411
14412/**
14413 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
14414 */
14415HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14416{
14417 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14418
14419 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14420 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14421 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14422 AssertRCReturn(rc, rc);
14423
14424 VBOXSTRICTRC rcStrict = IEMExecDecodedMwait(pVCpu, pVmxTransient->cbExitInstr);
14425 if (RT_SUCCESS(rcStrict))
14426 {
14427 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14428 if (EMMonitorWaitShouldContinue(pVCpu, &pVCpu->cpum.GstCtx))
14429 rcStrict = VINF_SUCCESS;
14430 }
14431
14432 return rcStrict;
14433}
14434
14435
14436/**
14437 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
14438 * VM-exit.
14439 */
14440HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14441{
14442 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14443 return VINF_EM_RESET;
14444}
14445
14446
14447/**
14448 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
14449 */
14450HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14451{
14452 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14453
14454 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14455 AssertRCReturn(rc, rc);
14456
14457 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS); /* Advancing the RIP above should've imported eflags. */
14458 if (EMShouldContinueAfterHalt(pVCpu, &pVCpu->cpum.GstCtx)) /* Requires eflags. */
14459 rc = VINF_SUCCESS;
14460 else
14461 rc = VINF_EM_HALT;
14462
14463 if (rc != VINF_SUCCESS)
14464 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
14465 return rc;
14466}
14467
14468
14469/**
14470 * VM-exit handler for instructions that result in a \#UD exception delivered to
14471 * the guest.
14472 */
14473HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14474{
14475 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14476 hmR0VmxSetPendingXcptUD(pVCpu);
14477 return VINF_SUCCESS;
14478}
14479
14480
14481/**
14482 * VM-exit handler for expiry of the VMX-preemption timer.
14483 */
14484HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14485{
14486 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14487
14488 /* If the VMX-preemption timer has expired, reinitialize the preemption timer on next VM-entry. */
14489 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14490
14491 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
14492 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
14493 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
14494 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
14495 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
14496}
14497
14498
14499/**
14500 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
14501 */
14502HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14503{
14504 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14505
14506 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14507 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14508 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_CR4);
14509 AssertRCReturn(rc, rc);
14510
14511 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbExitInstr);
14512 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
14513 : HM_CHANGED_RAISED_XCPT_MASK);
14514
14515 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14516 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
14517
14518 return rcStrict;
14519}
14520
14521
14522/**
14523 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
14524 */
14525HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14526{
14527 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14528 /** @todo Use VM-exit instruction information. */
14529 return VERR_EM_INTERPRETER;
14530}
14531
14532
14533/**
14534 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error
14535 * VM-exit.
14536 */
14537HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14538{
14539 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14540 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14541 AssertRCReturn(rc, rc);
14542
14543 rc = hmR0VmxCheckVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
14544 if (RT_FAILURE(rc))
14545 return rc;
14546
14547 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
14548 NOREF(uInvalidReason);
14549
14550#ifdef VBOX_STRICT
14551 uint32_t fIntrState;
14552 uint64_t u64Val;
14553 hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
14554 hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
14555 hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
14556
14557 Log4(("uInvalidReason %u\n", uInvalidReason));
14558 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
14559 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
14560 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
14561
14562 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState); AssertRC(rc);
14563 Log4(("VMX_VMCS32_GUEST_INT_STATE %#RX32\n", fIntrState));
14564 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Val); AssertRC(rc);
14565 Log4(("VMX_VMCS_GUEST_CR0 %#RX64\n", u64Val));
14566 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_MASK, &u64Val); AssertRC(rc);
14567 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RX64\n", u64Val));
14568 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Val); AssertRC(rc);
14569 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
14570 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_MASK, &u64Val); AssertRC(rc);
14571 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RX64\n", u64Val));
14572 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Val); AssertRC(rc);
14573 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
14574 if (pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging)
14575 {
14576 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
14577 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
14578 }
14579 hmR0DumpRegs(pVCpu, HM_DUMP_REG_FLAGS_ALL);
14580#endif
14581
14582 return VERR_VMX_INVALID_GUEST_STATE;
14583}
14584
14585/**
14586 * VM-exit handler for all undefined/unexpected reasons. Should never happen.
14587 */
14588HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUnexpected(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14589{
14590 /*
14591 * Cummulative notes of all recognized but unexpected VM-exits.
14592 *
14593 * 1. This does -not- cover scenarios like like a page-fault VM-exit occurring when
14594 * nested-paging is used.
14595 *
14596 * 2. Any instruction that causes a VM-exit unconditionally (for e.g. VMXON) must be
14597 * emulated or a #UD must be raised in the guest. Therefore, we should -not- be using
14598 * this function (and thereby stop VM execution) for handling such instructions.
14599 *
14600 *
14601 * VMX_EXIT_INIT_SIGNAL:
14602 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
14603 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these
14604 * VM-exits. However, we should not receive INIT signals VM-exit while executing a VM.
14605 *
14606 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery"
14607 * See Intel spec. 29.3 "VMX Instructions" for "VMXON".
14608 * See Intel spec. "23.8 Restrictions on VMX operation".
14609 *
14610 * VMX_EXIT_SIPI:
14611 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest
14612 * activity state is used. We don't make use of it as our guests don't have direct
14613 * access to the host local APIC.
14614 *
14615 * See Intel spec. 25.3 "Other Causes of VM-exits".
14616 *
14617 * VMX_EXIT_IO_SMI:
14618 * VMX_EXIT_SMI:
14619 * This can only happen if we support dual-monitor treatment of SMI, which can be
14620 * activated by executing VMCALL in VMX root operation. Only an STM (SMM transfer
14621 * monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL in
14622 * VMX root mode or receive an SMI. If we get here, something funny is going on.
14623 *
14624 * See Intel spec. 33.15.6 "Activating the Dual-Monitor Treatment"
14625 * See Intel spec. 25.3 "Other Causes of VM-Exits"
14626 *
14627 * VMX_EXIT_ERR_MSR_LOAD:
14628 * Failures while loading MSRs are part of the VM-entry MSR-load area are unexpected
14629 * and typically indicates a bug in the hypervisor code. We thus cannot not resume
14630 * execution.
14631 *
14632 * See Intel spec. 26.7 "VM-Entry Failures During Or After Loading Guest State".
14633 *
14634 * VMX_EXIT_ERR_MACHINE_CHECK:
14635 * Machine check exceptions indicates a fatal/unrecoverable hardware condition
14636 * including but not limited to system bus, ECC, parity, cache and TLB errors. A
14637 * #MC exception abort class exception is raised. We thus cannot assume a
14638 * reasonable chance of continuing any sort of execution and we bail.
14639 *
14640 * See Intel spec. 15.1 "Machine-check Architecture".
14641 * See Intel spec. 27.1 "Architectural State Before A VM Exit".
14642 *
14643 * VMX_EXIT_PML_FULL:
14644 * VMX_EXIT_VIRTUALIZED_EOI:
14645 * VMX_EXIT_APIC_WRITE:
14646 * We do not currently support any of these features and thus they are all unexpected
14647 * VM-exits.
14648 *
14649 * VMX_EXIT_GDTR_IDTR_ACCESS:
14650 * VMX_EXIT_LDTR_TR_ACCESS:
14651 * VMX_EXIT_RDRAND:
14652 * VMX_EXIT_RSM:
14653 * VMX_EXIT_VMFUNC:
14654 * VMX_EXIT_ENCLS:
14655 * VMX_EXIT_RDSEED:
14656 * VMX_EXIT_XSAVES:
14657 * VMX_EXIT_XRSTORS:
14658 * VMX_EXIT_UMWAIT:
14659 * VMX_EXIT_TPAUSE:
14660 * These VM-exits are -not- caused unconditionally by execution of the corresponding
14661 * instruction. Any VM-exit for these instructions indicate a hardware problem,
14662 * unsupported CPU modes (like SMM) or potentially corrupt VMCS controls.
14663 *
14664 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
14665 */
14666 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14667 AssertMsgFailed(("Unexpected VM-exit %u\n", pVmxTransient->uExitReason));
14668 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14669}
14670
14671
14672/**
14673 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
14674 */
14675HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14676{
14677 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14678
14679 /** @todo Optimize this: We currently drag in in the whole MSR state
14680 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
14681 * MSRs required. That would require changes to IEM and possibly CPUM too.
14682 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
14683 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14684 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
14685 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
14686 switch (idMsr)
14687 {
14688 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
14689 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
14690 }
14691
14692 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14693 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
14694 AssertRCReturn(rc, rc);
14695
14696 Log4Func(("ecx=%#RX32\n", idMsr));
14697
14698#ifdef VBOX_STRICT
14699 Assert(!pVmxTransient->fIsNestedGuest);
14700 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
14701 {
14702 if ( hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr)
14703 && idMsr != MSR_K6_EFER)
14704 {
14705 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", idMsr));
14706 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14707 }
14708 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14709 {
14710 Assert(pVmcsInfo->pvMsrBitmap);
14711 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
14712 if (fMsrpm & VMXMSRPM_ALLOW_RD)
14713 {
14714 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", idMsr));
14715 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14716 }
14717 }
14718 }
14719#endif
14720
14721 VBOXSTRICTRC rcStrict = IEMExecDecodedRdmsr(pVCpu, pVmxTransient->cbExitInstr);
14722 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
14723 if (rcStrict == VINF_SUCCESS)
14724 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
14725 | HM_CHANGED_GUEST_RAX | HM_CHANGED_GUEST_RDX);
14726 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14727 {
14728 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14729 rcStrict = VINF_SUCCESS;
14730 }
14731 else
14732 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_READ, ("Unexpected IEMExecDecodedRdmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
14733
14734 return rcStrict;
14735}
14736
14737
14738/**
14739 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
14740 */
14741HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14742{
14743 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14744
14745 /** @todo Optimize this: We currently drag in in the whole MSR state
14746 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
14747 * MSRs required. That would require changes to IEM and possibly CPUM too.
14748 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
14749 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
14750 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
14751
14752 /*
14753 * The FS and GS base MSRs are not part of the above all-MSRs mask.
14754 * Although we don't need to fetch the base as it will be overwritten shortly, while
14755 * loading guest-state we would also load the entire segment register including limit
14756 * and attributes and thus we need to load them here.
14757 */
14758 switch (idMsr)
14759 {
14760 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
14761 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
14762 }
14763
14764 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14765 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14766 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
14767 AssertRCReturn(rc, rc);
14768
14769 Log4Func(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", idMsr, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.eax));
14770
14771 VBOXSTRICTRC rcStrict = IEMExecDecodedWrmsr(pVCpu, pVmxTransient->cbExitInstr);
14772 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
14773
14774 if (rcStrict == VINF_SUCCESS)
14775 {
14776 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14777
14778 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
14779 if ( idMsr == MSR_IA32_APICBASE
14780 || ( idMsr >= MSR_IA32_X2APIC_START
14781 && idMsr <= MSR_IA32_X2APIC_END))
14782 {
14783 /*
14784 * We've already saved the APIC related guest-state (TPR) in post-run phase.
14785 * When full APIC register virtualization is implemented we'll have to make
14786 * sure APIC state is saved from the VMCS before IEM changes it.
14787 */
14788 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
14789 }
14790 else if (idMsr == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
14791 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14792 else if (idMsr == MSR_K6_EFER)
14793 {
14794 /*
14795 * If the guest touches the EFER MSR we need to update the VM-Entry and VM-Exit controls
14796 * as well, even if it is -not- touching bits that cause paging mode changes (LMA/LME).
14797 * We care about the other bits as well, SCE and NXE. See @bugref{7368}.
14798 */
14799 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
14800 }
14801
14802 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not used. */
14803 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
14804 {
14805 switch (idMsr)
14806 {
14807 case MSR_IA32_SYSENTER_CS: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
14808 case MSR_IA32_SYSENTER_EIP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
14809 case MSR_IA32_SYSENTER_ESP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
14810 case MSR_K8_FS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_FS); break;
14811 case MSR_K8_GS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_GS); break;
14812 case MSR_K6_EFER: /* Nothing to do, already handled above. */ break;
14813 default:
14814 {
14815 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14816 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_LAZY_MSRS);
14817 else if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
14818 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
14819 break;
14820 }
14821 }
14822 }
14823#ifdef VBOX_STRICT
14824 else
14825 {
14826 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
14827 switch (idMsr)
14828 {
14829 case MSR_IA32_SYSENTER_CS:
14830 case MSR_IA32_SYSENTER_EIP:
14831 case MSR_IA32_SYSENTER_ESP:
14832 case MSR_K8_FS_BASE:
14833 case MSR_K8_GS_BASE:
14834 {
14835 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", idMsr));
14836 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14837 }
14838
14839 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
14840 default:
14841 {
14842 if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
14843 {
14844 /* EFER MSR writes are always intercepted. */
14845 if (idMsr != MSR_K6_EFER)
14846 {
14847 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
14848 idMsr));
14849 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14850 }
14851 }
14852
14853 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
14854 {
14855 Assert(pVmcsInfo->pvMsrBitmap);
14856 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
14857 if (fMsrpm & VMXMSRPM_ALLOW_WR)
14858 {
14859 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", idMsr));
14860 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
14861 }
14862 }
14863 break;
14864 }
14865 }
14866 }
14867#endif /* VBOX_STRICT */
14868 }
14869 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14870 {
14871 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14872 rcStrict = VINF_SUCCESS;
14873 }
14874 else
14875 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_WRITE, ("Unexpected IEMExecDecodedWrmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
14876
14877 return rcStrict;
14878}
14879
14880
14881/**
14882 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
14883 */
14884HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14885{
14886 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14887
14888 /** @todo The guest has likely hit a contended spinlock. We might want to
14889 * poke a schedule different guest VCPU. */
14890 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14891 if (RT_SUCCESS(rc))
14892 return VINF_EM_RAW_INTERRUPT;
14893
14894 AssertMsgFailed(("hmR0VmxExitPause: Failed to increment RIP. rc=%Rrc\n", rc));
14895 return rc;
14896}
14897
14898
14899/**
14900 * VM-exit handler for when the TPR value is lowered below the specified
14901 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
14902 */
14903HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14904{
14905 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14906 Assert(pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
14907
14908 /*
14909 * The TPR shadow would've been synced with the APIC TPR in the post-run phase.
14910 * We'll re-evaluate pending interrupts and inject them before the next VM
14911 * entry so we can just continue execution here.
14912 */
14913 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
14914 return VINF_SUCCESS;
14915}
14916
14917
14918/**
14919 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
14920 * VM-exit.
14921 *
14922 * @retval VINF_SUCCESS when guest execution can continue.
14923 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
14924 * @retval VERR_EM_RESCHEDULE_REM when we need to return to ring-3 due to
14925 * incompatible guest state for VMX execution (real-on-v86 case).
14926 */
14927HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14928{
14929 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14930 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
14931
14932 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14933 hmR0VmxReadExitQualVmcs(pVmxTransient);
14934 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14935
14936 VBOXSTRICTRC rcStrict;
14937 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
14938 uint64_t const uExitQual = pVmxTransient->uExitQual;
14939 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(uExitQual);
14940 switch (uAccessType)
14941 {
14942 /*
14943 * MOV to CRx.
14944 */
14945 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
14946 {
14947 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14948 AssertRCReturn(rc, rc);
14949
14950 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
14951 uint32_t const uOldCr0 = pVCpu->cpum.GstCtx.cr0;
14952 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
14953 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
14954
14955 /*
14956 * MOV to CR3 only cause a VM-exit when one or more of the following are true:
14957 * - When nested paging isn't used.
14958 * - If the guest doesn't have paging enabled (intercept CR3 to update shadow page tables).
14959 * - We are executing in the VM debug loop.
14960 */
14961 Assert( iCrReg != 3
14962 || !pVM->hm.s.fNestedPaging
14963 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
14964 || pVCpu->hm.s.fUsingDebugLoop);
14965
14966 /* MOV to CR8 writes only cause VM-exits when TPR shadow is not used. */
14967 Assert( iCrReg != 8
14968 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
14969
14970 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
14971 AssertMsg( rcStrict == VINF_SUCCESS
14972 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
14973
14974 /*
14975 * This is a kludge for handling switches back to real mode when we try to use
14976 * V86 mode to run real mode code directly. Problem is that V86 mode cannot
14977 * deal with special selector values, so we have to return to ring-3 and run
14978 * there till the selector values are V86 mode compatible.
14979 *
14980 * Note! Using VINF_EM_RESCHEDULE_REM here rather than VINF_EM_RESCHEDULE since the
14981 * latter is an alias for VINF_IEM_RAISED_XCPT which is asserted at the end of
14982 * this function.
14983 */
14984 if ( iCrReg == 0
14985 && rcStrict == VINF_SUCCESS
14986 && !pVM->hm.s.vmx.fUnrestrictedGuest
14987 && CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx)
14988 && (uOldCr0 & X86_CR0_PE)
14989 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
14990 {
14991 /** @todo Check selectors rather than returning all the time. */
14992 Assert(!pVmxTransient->fIsNestedGuest);
14993 Log4Func(("CR0 write, back to real mode -> VINF_EM_RESCHEDULE_REM\n"));
14994 rcStrict = VINF_EM_RESCHEDULE_REM;
14995 }
14996 break;
14997 }
14998
14999 /*
15000 * MOV from CRx.
15001 */
15002 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
15003 {
15004 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
15005 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
15006
15007 /*
15008 * MOV from CR3 only cause a VM-exit when one or more of the following are true:
15009 * - When nested paging isn't used.
15010 * - If the guest doesn't have paging enabled (pass guest's CR3 rather than our identity mapped CR3).
15011 * - We are executing in the VM debug loop.
15012 */
15013 Assert( iCrReg != 3
15014 || !pVM->hm.s.fNestedPaging
15015 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
15016 || pVCpu->hm.s.fUsingDebugLoop);
15017
15018 /* MOV from CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
15019 Assert( iCrReg != 8
15020 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
15021
15022 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
15023 break;
15024 }
15025
15026 /*
15027 * CLTS (Clear Task-Switch Flag in CR0).
15028 */
15029 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
15030 {
15031 rcStrict = hmR0VmxExitClts(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr);
15032 break;
15033 }
15034
15035 /*
15036 * LMSW (Load Machine-Status Word into CR0).
15037 * LMSW cannot clear CR0.PE, so no fRealOnV86Active kludge needed here.
15038 */
15039 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW:
15040 {
15041 RTGCPTR GCPtrEffDst;
15042 uint8_t const cbInstr = pVmxTransient->cbExitInstr;
15043 uint16_t const uMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(uExitQual);
15044 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(uExitQual);
15045 if (fMemOperand)
15046 {
15047 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
15048 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
15049 }
15050 else
15051 GCPtrEffDst = NIL_RTGCPTR;
15052 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmcsInfo, cbInstr, uMsw, GCPtrEffDst);
15053 break;
15054 }
15055
15056 default:
15057 {
15058 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
15059 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
15060 }
15061 }
15062
15063 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS))
15064 == (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS));
15065 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15066
15067 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
15068 NOREF(pVM);
15069 return rcStrict;
15070}
15071
15072
15073/**
15074 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
15075 * VM-exit.
15076 */
15077HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15078{
15079 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15080 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
15081
15082 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15083 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15084 hmR0VmxReadExitQualVmcs(pVmxTransient);
15085 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15086 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_SREG_MASK
15087 | CPUMCTX_EXTRN_EFER);
15088 /* EFER MSR also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
15089 AssertRCReturn(rc, rc);
15090
15091 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
15092 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
15093 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
15094 bool const fIOWrite = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
15095 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
15096 bool const fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
15097 bool const fDbgStepping = pVCpu->hm.s.fSingleInstruction;
15098 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
15099
15100 /*
15101 * Update exit history to see if this exit can be optimized.
15102 */
15103 VBOXSTRICTRC rcStrict;
15104 PCEMEXITREC pExitRec = NULL;
15105 if ( !fGstStepping
15106 && !fDbgStepping)
15107 pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15108 !fIOString
15109 ? !fIOWrite
15110 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_READ)
15111 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_WRITE)
15112 : !fIOWrite
15113 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_READ)
15114 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_WRITE),
15115 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15116 if (!pExitRec)
15117 {
15118 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
15119 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving result in AL/AX/EAX. */
15120
15121 uint32_t const cbValue = s_aIOSizes[uIOSize];
15122 uint32_t const cbInstr = pVmxTransient->cbExitInstr;
15123 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
15124 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15125 if (fIOString)
15126 {
15127 /*
15128 * INS/OUTS - I/O String instruction.
15129 *
15130 * Use instruction-information if available, otherwise fall back on
15131 * interpreting the instruction.
15132 */
15133 Log4Func(("cs:rip=%#04x:%#RX64 %#06x/%u %c str\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15134 AssertReturn(pCtx->dx == uIOPort, VERR_VMX_IPE_2);
15135 bool const fInsOutsInfo = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS);
15136 if (fInsOutsInfo)
15137 {
15138 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15139 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
15140 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
15141 IEMMODE const enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
15142 bool const fRep = VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual);
15143 if (fIOWrite)
15144 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
15145 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
15146 else
15147 {
15148 /*
15149 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
15150 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
15151 * See Intel Instruction spec. for "INS".
15152 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
15153 */
15154 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
15155 }
15156 }
15157 else
15158 rcStrict = IEMExecOne(pVCpu);
15159
15160 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15161 fUpdateRipAlready = true;
15162 }
15163 else
15164 {
15165 /*
15166 * IN/OUT - I/O instruction.
15167 */
15168 Log4Func(("cs:rip=%04x:%08RX64 %#06x/%u %c\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15169 uint32_t const uAndVal = s_aIOOpAnd[uIOSize];
15170 Assert(!VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual));
15171 if (fIOWrite)
15172 {
15173 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pCtx->eax & uAndVal, cbValue);
15174 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
15175 if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15176 && !pCtx->eflags.Bits.u1TF)
15177 rcStrict = EMRZSetPendingIoPortWrite(pVCpu, uIOPort, cbInstr, cbValue, pCtx->eax & uAndVal);
15178 }
15179 else
15180 {
15181 uint32_t u32Result = 0;
15182 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
15183 if (IOM_SUCCESS(rcStrict))
15184 {
15185 /* Save result of I/O IN instr. in AL/AX/EAX. */
15186 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Result & uAndVal);
15187 }
15188 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15189 && !pCtx->eflags.Bits.u1TF)
15190 rcStrict = EMRZSetPendingIoPortRead(pVCpu, uIOPort, cbInstr, cbValue);
15191 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
15192 }
15193 }
15194
15195 if (IOM_SUCCESS(rcStrict))
15196 {
15197 if (!fUpdateRipAlready)
15198 {
15199 hmR0VmxAdvanceGuestRipBy(pVCpu, cbInstr);
15200 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15201 }
15202
15203 /*
15204 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru
15205 * while booting Fedora 17 64-bit guest.
15206 *
15207 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
15208 */
15209 if (fIOString)
15210 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RFLAGS);
15211
15212 /*
15213 * If any I/O breakpoints are armed, we need to check if one triggered
15214 * and take appropriate action.
15215 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
15216 */
15217 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_DR7);
15218 AssertRCReturn(rc, rc);
15219
15220 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
15221 * execution engines about whether hyper BPs and such are pending. */
15222 uint32_t const uDr7 = pCtx->dr[7];
15223 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
15224 && X86_DR7_ANY_RW_IO(uDr7)
15225 && (pCtx->cr4 & X86_CR4_DE))
15226 || DBGFBpIsHwIoArmed(pVM)))
15227 {
15228 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
15229
15230 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
15231 VMMRZCallRing3Disable(pVCpu);
15232 HM_DISABLE_PREEMPT(pVCpu);
15233
15234 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
15235
15236 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, uIOPort, cbValue);
15237 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
15238 {
15239 /* Raise #DB. */
15240 if (fIsGuestDbgActive)
15241 ASMSetDR6(pCtx->dr[6]);
15242 if (pCtx->dr[7] != uDr7)
15243 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_DR7;
15244
15245 hmR0VmxSetPendingXcptDB(pVCpu);
15246 }
15247 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
15248 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
15249 else if ( rcStrict2 != VINF_SUCCESS
15250 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
15251 rcStrict = rcStrict2;
15252 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
15253
15254 HM_RESTORE_PREEMPT();
15255 VMMRZCallRing3Enable(pVCpu);
15256 }
15257 }
15258
15259#ifdef VBOX_STRICT
15260 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15261 || rcStrict == VINF_EM_PENDING_R3_IOPORT_READ)
15262 Assert(!fIOWrite);
15263 else if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15264 || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
15265 || rcStrict == VINF_EM_PENDING_R3_IOPORT_WRITE)
15266 Assert(fIOWrite);
15267 else
15268 {
15269# if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
15270 * statuses, that the VMM device and some others may return. See
15271 * IOM_SUCCESS() for guidance. */
15272 AssertMsg( RT_FAILURE(rcStrict)
15273 || rcStrict == VINF_SUCCESS
15274 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
15275 || rcStrict == VINF_EM_DBG_BREAKPOINT
15276 || rcStrict == VINF_EM_RAW_GUEST_TRAP
15277 || rcStrict == VINF_EM_RAW_TO_R3
15278 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15279# endif
15280 }
15281#endif
15282 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
15283 }
15284 else
15285 {
15286 /*
15287 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
15288 */
15289 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15290 AssertRCReturn(rc2, rc2);
15291 STAM_COUNTER_INC(!fIOString ? fIOWrite ? &pVCpu->hm.s.StatExitIOWrite : &pVCpu->hm.s.StatExitIORead
15292 : fIOWrite ? &pVCpu->hm.s.StatExitIOStringWrite : &pVCpu->hm.s.StatExitIOStringRead);
15293 Log4(("IOExit/%u: %04x:%08RX64: %s%s%s %#x LB %u -> EMHistoryExec\n",
15294 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15295 VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual) ? "REP " : "",
15296 fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOSize));
15297
15298 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15299 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15300
15301 Log4(("IOExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15302 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15303 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15304 }
15305 return rcStrict;
15306}
15307
15308
15309/**
15310 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
15311 * VM-exit.
15312 */
15313HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15314{
15315 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15316
15317 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
15318 hmR0VmxReadExitQualVmcs(pVmxTransient);
15319 if (VMX_EXIT_QUAL_TASK_SWITCH_TYPE(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT)
15320 {
15321 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15322 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
15323 {
15324 uint32_t uErrCode;
15325 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uIdtVectoringInfo))
15326 {
15327 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15328 uErrCode = pVmxTransient->uIdtVectoringErrorCode;
15329 }
15330 else
15331 uErrCode = 0;
15332
15333 RTGCUINTPTR GCPtrFaultAddress;
15334 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(pVmxTransient->uIdtVectoringInfo))
15335 GCPtrFaultAddress = pVCpu->cpum.GstCtx.cr2;
15336 else
15337 GCPtrFaultAddress = 0;
15338
15339 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15340
15341 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
15342 pVmxTransient->cbExitInstr, uErrCode, GCPtrFaultAddress);
15343
15344 Log4Func(("Pending event. uIntType=%#x uVector=%#x\n", VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo),
15345 VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo)));
15346 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15347 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15348 }
15349 }
15350
15351 /* Fall back to the interpreter to emulate the task-switch. */
15352 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15353 return VERR_EM_INTERPRETER;
15354}
15355
15356
15357/**
15358 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
15359 */
15360HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15361{
15362 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15363
15364 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15365 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
15366 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15367 AssertRC(rc);
15368 return VINF_EM_DBG_STEPPED;
15369}
15370
15371
15372/**
15373 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
15374 */
15375HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15376{
15377 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15378 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
15379
15380 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15381 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15382 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15383 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15384 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15385
15386 /*
15387 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15388 */
15389 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15390 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15391 {
15392 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
15393 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
15394 {
15395 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15396 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15397 }
15398 }
15399 else
15400 {
15401 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15402 return rcStrict;
15403 }
15404
15405 /* IOMMIOPhysHandler() below may call into IEM, save the necessary state. */
15406 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15407 hmR0VmxReadExitQualVmcs(pVmxTransient);
15408 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15409 AssertRCReturn(rc, rc);
15410
15411 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
15412 uint32_t const uAccessType = VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual);
15413 switch (uAccessType)
15414 {
15415 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
15416 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
15417 {
15418 AssertMsg( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
15419 || VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual) != XAPIC_OFF_TPR,
15420 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
15421
15422 RTGCPHYS GCPhys = pVCpu->hm.s.vmx.u64GstMsrApicBase; /* Always up-to-date, as it is not part of the VMCS. */
15423 GCPhys &= PAGE_BASE_GC_MASK;
15424 GCPhys += VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual);
15425 Log4Func(("Linear access uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
15426 VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual)));
15427
15428 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15429 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15430 rcStrict = IOMMMIOPhysHandler(pVM, pVCpu,
15431 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW,
15432 CPUMCTX2CORE(pCtx), GCPhys);
15433 Log4Func(("IOMMMIOPhysHandler returned %Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15434 if ( rcStrict == VINF_SUCCESS
15435 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15436 || rcStrict == VERR_PAGE_NOT_PRESENT)
15437 {
15438 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15439 | HM_CHANGED_GUEST_APIC_TPR);
15440 rcStrict = VINF_SUCCESS;
15441 }
15442 break;
15443 }
15444
15445 default:
15446 {
15447 Log4Func(("uAccessType=%#x\n", uAccessType));
15448 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
15449 break;
15450 }
15451 }
15452
15453 if (rcStrict != VINF_SUCCESS)
15454 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
15455 return rcStrict;
15456}
15457
15458
15459/**
15460 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
15461 * VM-exit.
15462 */
15463HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15464{
15465 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15466 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15467
15468 /* We might get this VM-exit if the nested-guest is not intercepting MOV DRx accesses. */
15469 if (!pVmxTransient->fIsNestedGuest)
15470 {
15471 /* We should -not- get this VM-exit if the guest's debug registers were active. */
15472 if (pVmxTransient->fWasGuestDebugStateActive)
15473 {
15474 AssertMsgFailed(("Unexpected MOV DRx exit\n"));
15475 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
15476 }
15477
15478 if ( !pVCpu->hm.s.fSingleInstruction
15479 && !pVmxTransient->fWasHyperDebugStateActive)
15480 {
15481 Assert(!DBGFIsStepping(pVCpu));
15482 Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB));
15483
15484 /* Don't intercept MOV DRx any more. */
15485 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
15486 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15487 AssertRC(rc);
15488
15489 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
15490 VMMRZCallRing3Disable(pVCpu);
15491 HM_DISABLE_PREEMPT(pVCpu);
15492
15493 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
15494 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
15495 Assert(CPUMIsGuestDebugStateActive(pVCpu));
15496
15497 HM_RESTORE_PREEMPT();
15498 VMMRZCallRing3Enable(pVCpu);
15499
15500#ifdef VBOX_WITH_STATISTICS
15501 hmR0VmxReadExitQualVmcs(pVmxTransient);
15502 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
15503 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
15504 else
15505 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
15506#endif
15507 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
15508 return VINF_SUCCESS;
15509 }
15510 }
15511
15512 /*
15513 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER MSR, CS.
15514 * The EFER MSR is always up-to-date.
15515 * Update the segment registers and DR7 from the CPU.
15516 */
15517 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15518 hmR0VmxReadExitQualVmcs(pVmxTransient);
15519 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_DR7);
15520 AssertRCReturn(rc, rc);
15521 Log4Func(("cs:rip=%#04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
15522
15523 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15524 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
15525 {
15526 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pCtx),
15527 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual),
15528 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual));
15529 if (RT_SUCCESS(rc))
15530 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
15531 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
15532 }
15533 else
15534 {
15535 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pCtx),
15536 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual),
15537 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual));
15538 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
15539 }
15540
15541 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
15542 if (RT_SUCCESS(rc))
15543 {
15544 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15545 AssertRCReturn(rc2, rc2);
15546 return VINF_SUCCESS;
15547 }
15548 return rc;
15549}
15550
15551
15552/**
15553 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
15554 * Conditional VM-exit.
15555 */
15556HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15557{
15558 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15559 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
15560
15561 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15562 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15563 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15564 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15565 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15566
15567 /*
15568 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15569 */
15570 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15571 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15572 {
15573 /*
15574 * In the unlikely case where delivering an event causes an EPT misconfig (MMIO), go back to
15575 * instruction emulation to inject the original event. Otherwise, injecting the original event
15576 * using hardware-assisted VMX would would trigger the same EPT misconfig VM-exit again.
15577 */
15578 if (!pVCpu->hm.s.Event.fPending)
15579 { /* likely */ }
15580 else
15581 {
15582 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15583#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
15584 /** @todo NSTVMX: Think about how this should be handled. */
15585 if (pVmxTransient->fIsNestedGuest)
15586 return VERR_VMX_IPE_3;
15587#endif
15588 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15589 }
15590 }
15591 else
15592 {
15593 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15594 return rcStrict;
15595 }
15596
15597 /*
15598 * Get sufficent state and update the exit history entry.
15599 */
15600 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15601 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
15602 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15603 AssertRCReturn(rc, rc);
15604
15605 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
15606 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15607 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_MMIO),
15608 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15609 if (!pExitRec)
15610 {
15611 /*
15612 * If we succeed, resume guest execution.
15613 * If we fail in interpreting the instruction because we couldn't get the guest physical address
15614 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
15615 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
15616 * weird case. See @bugref{6043}.
15617 */
15618 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15619 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15620 rcStrict = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pCtx), GCPhys, UINT32_MAX);
15621 Log4Func(("At %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pCtx->rip, VBOXSTRICTRC_VAL(rcStrict)));
15622 if ( rcStrict == VINF_SUCCESS
15623 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15624 || rcStrict == VERR_PAGE_NOT_PRESENT)
15625 {
15626 /* Successfully handled MMIO operation. */
15627 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15628 | HM_CHANGED_GUEST_APIC_TPR);
15629 rcStrict = VINF_SUCCESS;
15630 }
15631 }
15632 else
15633 {
15634 /*
15635 * Frequent exit or something needing probing. Call EMHistoryExec.
15636 */
15637 Log4(("EptMisscfgExit/%u: %04x:%08RX64: %RGp -> EMHistoryExec\n",
15638 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPhys));
15639
15640 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15641 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15642
15643 Log4(("EptMisscfgExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15644 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15645 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15646 }
15647 return rcStrict;
15648}
15649
15650
15651/**
15652 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
15653 * VM-exit.
15654 */
15655HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15656{
15657 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15658 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
15659
15660 hmR0VmxReadExitQualVmcs(pVmxTransient);
15661 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15662 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15663 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15664 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15665 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15666
15667 /*
15668 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15669 */
15670 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15671 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15672 {
15673 /*
15674 * If delivery of an event causes an EPT violation (true nested #PF and not MMIO),
15675 * we shall resolve the nested #PF and re-inject the original event.
15676 */
15677 if (pVCpu->hm.s.Event.fPending)
15678 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflectNPF);
15679 }
15680 else
15681 {
15682 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15683 return rcStrict;
15684 }
15685
15686 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15687 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
15688 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15689 AssertRCReturn(rc, rc);
15690
15691 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
15692 uint64_t const uExitQual = pVmxTransient->uExitQual;
15693 AssertMsg(((pVmxTransient->uExitQual >> 7) & 3) != 2, ("%#RX64", uExitQual));
15694
15695 RTGCUINT uErrorCode = 0;
15696 if (uExitQual & VMX_EXIT_QUAL_EPT_INSTR_FETCH)
15697 uErrorCode |= X86_TRAP_PF_ID;
15698 if (uExitQual & VMX_EXIT_QUAL_EPT_DATA_WRITE)
15699 uErrorCode |= X86_TRAP_PF_RW;
15700 if (uExitQual & VMX_EXIT_QUAL_EPT_ENTRY_PRESENT)
15701 uErrorCode |= X86_TRAP_PF_P;
15702
15703 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15704 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15705 Log4Func(("at %#RX64 (%#RX64 errcode=%#x) cs:rip=%#04x:%#RX64\n", GCPhys, uExitQual, uErrorCode, pCtx->cs.Sel, pCtx->rip));
15706
15707 /*
15708 * Handle the pagefault trap for the nested shadow table.
15709 */
15710 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
15711 rcStrict = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pCtx), GCPhys);
15712 TRPMResetTrap(pVCpu);
15713
15714 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
15715 if ( rcStrict == VINF_SUCCESS
15716 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15717 || rcStrict == VERR_PAGE_NOT_PRESENT)
15718 {
15719 /* Successfully synced our nested page tables. */
15720 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
15721 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS);
15722 return VINF_SUCCESS;
15723 }
15724
15725 Log4Func(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15726 return rcStrict;
15727}
15728
15729
15730#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
15731/**
15732 * VM-exit handler for VMCLEAR (VMX_EXIT_VMCLEAR). Unconditional VM-exit.
15733 */
15734HMVMX_EXIT_DECL hmR0VmxExitVmclear(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15735{
15736 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15737
15738 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15739 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15740 hmR0VmxReadExitQualVmcs(pVmxTransient);
15741 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15742 | CPUMCTX_EXTRN_HWVIRT
15743 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15744 AssertRCReturn(rc, rc);
15745
15746 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15747
15748 VMXVEXITINFO ExitInfo;
15749 RT_ZERO(ExitInfo);
15750 ExitInfo.uReason = pVmxTransient->uExitReason;
15751 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15752 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15753 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
15754 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15755
15756 VBOXSTRICTRC rcStrict = IEMExecDecodedVmclear(pVCpu, &ExitInfo);
15757 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15758 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15759 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15760 {
15761 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15762 rcStrict = VINF_SUCCESS;
15763 }
15764 return rcStrict;
15765}
15766
15767
15768/**
15769 * VM-exit handler for VMLAUNCH (VMX_EXIT_VMLAUNCH). Unconditional VM-exit.
15770 */
15771HMVMX_EXIT_DECL hmR0VmxExitVmlaunch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15772{
15773 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15774
15775 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMLAUNCH,
15776 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
15777 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15778 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15779 AssertRCReturn(rc, rc);
15780
15781 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15782
15783 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
15784 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMLAUNCH);
15785 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
15786 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15787 {
15788 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15789 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
15790 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
15791 }
15792 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15793 return rcStrict;
15794}
15795
15796
15797/**
15798 * VM-exit handler for VMPTRLD (VMX_EXIT_VMPTRLD). Unconditional VM-exit.
15799 */
15800HMVMX_EXIT_DECL hmR0VmxExitVmptrld(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15801{
15802 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15803
15804 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15805 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15806 hmR0VmxReadExitQualVmcs(pVmxTransient);
15807 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15808 | CPUMCTX_EXTRN_HWVIRT
15809 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15810 AssertRCReturn(rc, rc);
15811
15812 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15813
15814 VMXVEXITINFO ExitInfo;
15815 RT_ZERO(ExitInfo);
15816 ExitInfo.uReason = pVmxTransient->uExitReason;
15817 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15818 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15819 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
15820 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15821
15822 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrld(pVCpu, &ExitInfo);
15823 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15824 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15825 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15826 {
15827 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15828 rcStrict = VINF_SUCCESS;
15829 }
15830 return rcStrict;
15831}
15832
15833
15834/**
15835 * VM-exit handler for VMPTRST (VMX_EXIT_VMPTRST). Unconditional VM-exit.
15836 */
15837HMVMX_EXIT_DECL hmR0VmxExitVmptrst(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15838{
15839 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15840
15841 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15842 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15843 hmR0VmxReadExitQualVmcs(pVmxTransient);
15844 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15845 | CPUMCTX_EXTRN_HWVIRT
15846 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15847 AssertRCReturn(rc, rc);
15848
15849 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15850
15851 VMXVEXITINFO ExitInfo;
15852 RT_ZERO(ExitInfo);
15853 ExitInfo.uReason = pVmxTransient->uExitReason;
15854 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15855 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15856 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
15857 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
15858
15859 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrst(pVCpu, &ExitInfo);
15860 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15861 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15862 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15863 {
15864 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15865 rcStrict = VINF_SUCCESS;
15866 }
15867 return rcStrict;
15868}
15869
15870
15871/**
15872 * VM-exit handler for VMREAD (VMX_EXIT_VMREAD). Conditional VM-exit.
15873 */
15874HMVMX_EXIT_DECL hmR0VmxExitVmread(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15875{
15876 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15877
15878 /*
15879 * Strictly speaking we should not get VMREAD VM-exits for shadow VMCS fields and
15880 * thus might not need to import the shadow VMCS state, it's safer just in case
15881 * code elsewhere dares look at unsynced VMCS fields.
15882 */
15883 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15884 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15885 hmR0VmxReadExitQualVmcs(pVmxTransient);
15886 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15887 | CPUMCTX_EXTRN_HWVIRT
15888 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15889 AssertRCReturn(rc, rc);
15890
15891 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15892
15893 VMXVEXITINFO ExitInfo;
15894 RT_ZERO(ExitInfo);
15895 ExitInfo.uReason = pVmxTransient->uExitReason;
15896 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15897 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15898 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
15899 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
15900 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
15901
15902 VBOXSTRICTRC rcStrict = IEMExecDecodedVmread(pVCpu, &ExitInfo);
15903 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15904 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15905 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15906 {
15907 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15908 rcStrict = VINF_SUCCESS;
15909 }
15910 return rcStrict;
15911}
15912
15913
15914/**
15915 * VM-exit handler for VMRESUME (VMX_EXIT_VMRESUME). Unconditional VM-exit.
15916 */
15917HMVMX_EXIT_DECL hmR0VmxExitVmresume(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15918{
15919 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15920
15921 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMRESUME,
15922 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
15923 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15924 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15925 AssertRCReturn(rc, rc);
15926
15927 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15928
15929 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
15930 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMRESUME);
15931 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
15932 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15933 {
15934 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15935 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
15936 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
15937 }
15938 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15939 return rcStrict;
15940}
15941
15942
15943/**
15944 * VM-exit handler for VMWRITE (VMX_EXIT_VMWRITE). Conditional VM-exit.
15945 */
15946HMVMX_EXIT_DECL hmR0VmxExitVmwrite(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15947{
15948 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15949
15950 /*
15951 * Although we should not get VMWRITE VM-exits for shadow VMCS fields, since our HM hook
15952 * gets invoked when IEM's VMWRITE instruction emulation modifies the current VMCS and it
15953 * flags re-loading the entire shadow VMCS, we should save the entire shadow VMCS here.
15954 */
15955 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15956 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15957 hmR0VmxReadExitQualVmcs(pVmxTransient);
15958 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15959 | CPUMCTX_EXTRN_HWVIRT
15960 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15961 AssertRCReturn(rc, rc);
15962
15963 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
15964
15965 VMXVEXITINFO ExitInfo;
15966 RT_ZERO(ExitInfo);
15967 ExitInfo.uReason = pVmxTransient->uExitReason;
15968 ExitInfo.u64Qual = pVmxTransient->uExitQual;
15969 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
15970 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
15971 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
15972 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
15973
15974 VBOXSTRICTRC rcStrict = IEMExecDecodedVmwrite(pVCpu, &ExitInfo);
15975 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15976 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
15977 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15978 {
15979 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15980 rcStrict = VINF_SUCCESS;
15981 }
15982 return rcStrict;
15983}
15984
15985
15986/**
15987 * VM-exit handler for VMXOFF (VMX_EXIT_VMXOFF). Unconditional VM-exit.
15988 */
15989HMVMX_EXIT_DECL hmR0VmxExitVmxoff(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15990{
15991 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15992
15993 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15994 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR4
15995 | CPUMCTX_EXTRN_HWVIRT
15996 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
15997 AssertRCReturn(rc, rc);
15998
15999 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16000
16001 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxoff(pVCpu, pVmxTransient->cbExitInstr);
16002 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16003 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_HWVIRT);
16004 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16005 {
16006 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16007 rcStrict = VINF_SUCCESS;
16008 }
16009 return rcStrict;
16010}
16011
16012
16013/**
16014 * VM-exit handler for VMXON (VMX_EXIT_VMXON). Unconditional VM-exit.
16015 */
16016HMVMX_EXIT_DECL hmR0VmxExitVmxon(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16017{
16018 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16019
16020 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16021 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16022 hmR0VmxReadExitQualVmcs(pVmxTransient);
16023 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16024 | CPUMCTX_EXTRN_HWVIRT
16025 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16026 AssertRCReturn(rc, rc);
16027
16028 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16029
16030 VMXVEXITINFO ExitInfo;
16031 RT_ZERO(ExitInfo);
16032 ExitInfo.uReason = pVmxTransient->uExitReason;
16033 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16034 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16035 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16036 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16037
16038 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxon(pVCpu, &ExitInfo);
16039 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16040 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16041 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16042 {
16043 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16044 rcStrict = VINF_SUCCESS;
16045 }
16046 return rcStrict;
16047}
16048
16049
16050/**
16051 * VM-exit handler for INVVPID (VMX_EXIT_INVVPID). Unconditional VM-exit.
16052 */
16053HMVMX_EXIT_DECL hmR0VmxExitInvvpid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16054{
16055 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16056
16057 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16058 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16059 hmR0VmxReadExitQualVmcs(pVmxTransient);
16060 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16061 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16062 AssertRCReturn(rc, rc);
16063
16064 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16065
16066 VMXVEXITINFO ExitInfo;
16067 RT_ZERO(ExitInfo);
16068 ExitInfo.uReason = pVmxTransient->uExitReason;
16069 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16070 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16071 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16072 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16073
16074 VBOXSTRICTRC rcStrict = IEMExecDecodedInvvpid(pVCpu, &ExitInfo);
16075 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16076 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16077 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16078 {
16079 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16080 rcStrict = VINF_SUCCESS;
16081 }
16082 return rcStrict;
16083}
16084#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16085/** @} */
16086
16087
16088#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16089/** @name Nested-guest VM-exit handlers.
16090 * @{
16091 */
16092/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16093/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Nested-guest VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16094/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16095
16096/**
16097 * Nested-guest VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
16098 * Conditional VM-exit.
16099 */
16100HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16101{
16102 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16103
16104 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16105
16106 uint64_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
16107 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
16108 Assert(VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo));
16109
16110 switch (uExitIntType)
16111 {
16112 /*
16113 * Physical NMIs:
16114 * We shouldn't direct host physical NMIs to the nested-guest. Dispatch it to the host.
16115 */
16116 case VMX_EXIT_INT_INFO_TYPE_NMI:
16117 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
16118
16119 /*
16120 * Hardware exceptions,
16121 * Software exceptions,
16122 * Privileged software exceptions:
16123 * Figure out if the exception must be delivered to the guest or the nested-guest.
16124 */
16125 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
16126 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
16127 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
16128 {
16129 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16130 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16131 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16132 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16133
16134 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16135 bool const fIntercept = CPUMIsGuestVmxXcptInterceptSet(pVCpu, pCtx, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo),
16136 pVmxTransient->uExitIntErrorCode);
16137 if (fIntercept)
16138 {
16139 /* Exit qualification is required for debug and page-fault exceptions. */
16140 hmR0VmxReadExitQualVmcs(pVmxTransient);
16141
16142 /*
16143 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged
16144 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
16145 * length. However, if delivery of a software interrupt, software exception or privileged
16146 * software exception causes a VM-exit, that too provides the VM-exit instruction length.
16147 */
16148 VMXVEXITINFO ExitInfo;
16149 RT_ZERO(ExitInfo);
16150 ExitInfo.uReason = pVmxTransient->uExitReason;
16151 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16152 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16153
16154 VMXVEXITEVENTINFO ExitEventInfo;
16155 RT_ZERO(ExitEventInfo);
16156 ExitEventInfo.uExitIntInfo = pVmxTransient->uExitIntInfo;
16157 ExitEventInfo.uExitIntErrCode = pVmxTransient->uExitIntErrorCode;
16158 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16159 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16160
16161#ifdef DEBUG_ramshankar
16162 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16163 Log4Func(("exit_int_info=%#x err_code=%#x exit_qual=%#RX64\n", pVmxTransient->uExitIntInfo,
16164 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual));
16165 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
16166 {
16167 Log4Func(("idt_info=%#RX32 idt_errcode=%#RX32 cr2=%#RX64\n", pVmxTransient->uIdtVectoringInfo,
16168 pVmxTransient->uIdtVectoringErrorCode, pCtx->cr2));
16169 }
16170#endif
16171 return IEMExecVmxVmexitXcpt(pVCpu, &ExitInfo, &ExitEventInfo);
16172 }
16173
16174 /* Nested paging is currently a requirement, otherwise we would need to handle shadow #PFs in hmR0VmxExitXcptPF. */
16175 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
16176 return hmR0VmxExitXcpt(pVCpu, pVmxTransient);
16177 }
16178
16179 /*
16180 * Software interrupts:
16181 * VM-exits cannot be caused by software interrupts.
16182 *
16183 * External interrupts:
16184 * This should only happen when "acknowledge external interrupts on VM-exit"
16185 * control is set. However, we never set this when executing a guest or
16186 * nested-guest. For nested-guests it is emulated while injecting interrupts into
16187 * the guest.
16188 */
16189 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
16190 case VMX_EXIT_INT_INFO_TYPE_EXT_INT:
16191 default:
16192 {
16193 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
16194 return VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
16195 }
16196 }
16197}
16198
16199
16200/**
16201 * Nested-guest VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT).
16202 * Unconditional VM-exit.
16203 */
16204HMVMX_EXIT_DECL hmR0VmxExitTripleFaultNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16205{
16206 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16207 return IEMExecVmxVmexitTripleFault(pVCpu);
16208}
16209
16210
16211/**
16212 * Nested-guest VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
16213 */
16214HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16215{
16216 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16217
16218 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
16219 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16220 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16221}
16222
16223
16224/**
16225 * Nested-guest VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
16226 */
16227HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16228{
16229 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16230
16231 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT))
16232 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16233 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16234}
16235
16236
16237/**
16238 * Nested-guest VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH).
16239 * Unconditional VM-exit.
16240 */
16241HMVMX_EXIT_DECL hmR0VmxExitTaskSwitchNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16242{
16243 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16244
16245 hmR0VmxReadExitQualVmcs(pVmxTransient);
16246 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16247 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16248 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16249
16250 VMXVEXITINFO ExitInfo;
16251 RT_ZERO(ExitInfo);
16252 ExitInfo.uReason = pVmxTransient->uExitReason;
16253 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16254 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16255
16256 VMXVEXITEVENTINFO ExitEventInfo;
16257 RT_ZERO(ExitEventInfo);
16258 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16259 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16260 return IEMExecVmxVmexitTaskSwitch(pVCpu, &ExitInfo, &ExitEventInfo);
16261}
16262
16263
16264/**
16265 * Nested-guest VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
16266 */
16267HMVMX_EXIT_DECL hmR0VmxExitHltNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16268{
16269 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16270
16271 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_HLT_EXIT))
16272 {
16273 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16274 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16275 }
16276 return hmR0VmxExitHlt(pVCpu, pVmxTransient);
16277}
16278
16279
16280/**
16281 * Nested-guest VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
16282 */
16283HMVMX_EXIT_DECL hmR0VmxExitInvlpgNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16284{
16285 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16286
16287 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16288 {
16289 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16290 hmR0VmxReadExitQualVmcs(pVmxTransient);
16291
16292 VMXVEXITINFO ExitInfo;
16293 RT_ZERO(ExitInfo);
16294 ExitInfo.uReason = pVmxTransient->uExitReason;
16295 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16296 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16297 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16298 }
16299 return hmR0VmxExitInvlpg(pVCpu, pVmxTransient);
16300}
16301
16302
16303/**
16304 * Nested-guest VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
16305 */
16306HMVMX_EXIT_DECL hmR0VmxExitRdpmcNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16307{
16308 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16309
16310 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDPMC_EXIT))
16311 {
16312 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16313 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16314 }
16315 return hmR0VmxExitRdpmc(pVCpu, pVmxTransient);
16316}
16317
16318
16319/**
16320 * Nested-guest VM-exit handler for VMREAD (VMX_EXIT_VMREAD) and VMWRITE
16321 * (VMX_EXIT_VMWRITE). Conditional VM-exit.
16322 */
16323HMVMX_EXIT_DECL hmR0VmxExitVmreadVmwriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16324{
16325 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16326
16327 Assert( pVmxTransient->uExitReason == VMX_EXIT_VMREAD
16328 || pVmxTransient->uExitReason == VMX_EXIT_VMWRITE);
16329
16330 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16331
16332 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
16333 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16334 uint64_t u64VmcsField = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16335
16336 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
16337 if (!CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
16338 u64VmcsField &= UINT64_C(0xffffffff);
16339
16340 if (CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, pVmxTransient->uExitReason, u64VmcsField))
16341 {
16342 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16343 hmR0VmxReadExitQualVmcs(pVmxTransient);
16344
16345 VMXVEXITINFO ExitInfo;
16346 RT_ZERO(ExitInfo);
16347 ExitInfo.uReason = pVmxTransient->uExitReason;
16348 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16349 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16350 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16351 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16352 }
16353
16354 if (pVmxTransient->uExitReason == VMX_EXIT_VMREAD)
16355 return hmR0VmxExitVmread(pVCpu, pVmxTransient);
16356 return hmR0VmxExitVmwrite(pVCpu, pVmxTransient);
16357}
16358
16359
16360/**
16361 * Nested-guest VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
16362 */
16363HMVMX_EXIT_DECL hmR0VmxExitRdtscNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16364{
16365 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16366
16367 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16368 {
16369 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16370 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16371 }
16372
16373 return hmR0VmxExitRdtsc(pVCpu, pVmxTransient);
16374}
16375
16376
16377/**
16378 * Nested-guest VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX).
16379 * Conditional VM-exit.
16380 */
16381HMVMX_EXIT_DECL hmR0VmxExitMovCRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16382{
16383 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16384
16385 hmR0VmxReadExitQualVmcs(pVmxTransient);
16386 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16387
16388 VBOXSTRICTRC rcStrict;
16389 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual);
16390 switch (uAccessType)
16391 {
16392 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
16393 {
16394 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16395 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
16396 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16397 uint64_t const uNewCrX = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16398
16399 bool fIntercept;
16400 switch (iCrReg)
16401 {
16402 case 0:
16403 case 4:
16404 fIntercept = CPUMIsGuestVmxMovToCr0Cr4InterceptSet(pVCpu, &pVCpu->cpum.GstCtx, iCrReg, uNewCrX);
16405 break;
16406
16407 case 3:
16408 fIntercept = CPUMIsGuestVmxMovToCr3InterceptSet(pVCpu, uNewCrX);
16409 break;
16410
16411 case 8:
16412 fIntercept = CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_CR8_LOAD_EXIT);
16413 break;
16414
16415 default:
16416 fIntercept = false;
16417 break;
16418 }
16419 if (fIntercept)
16420 {
16421 VMXVEXITINFO ExitInfo;
16422 RT_ZERO(ExitInfo);
16423 ExitInfo.uReason = pVmxTransient->uExitReason;
16424 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16425 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16426 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16427 }
16428 else
16429 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
16430 break;
16431 }
16432
16433 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
16434 {
16435 /*
16436 * CR0/CR4 reads do not cause VM-exits, the read-shadow is used (subject to masking).
16437 * CR2 reads do not cause a VM-exit.
16438 * CR3 reads cause a VM-exit depending on the "CR3 store exiting" control.
16439 * CR8 reads cause a VM-exit depending on the "CR8 store exiting" control.
16440 */
16441 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16442 if ( iCrReg == 3
16443 || iCrReg == 8)
16444 {
16445 static const uint32_t s_auCrXReadIntercepts[] = { 0, 0, 0, VMX_PROC_CTLS_CR3_STORE_EXIT, 0,
16446 0, 0, 0, VMX_PROC_CTLS_CR8_STORE_EXIT };
16447 uint32_t const uIntercept = s_auCrXReadIntercepts[iCrReg];
16448 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uIntercept))
16449 {
16450 VMXVEXITINFO ExitInfo;
16451 RT_ZERO(ExitInfo);
16452 ExitInfo.uReason = pVmxTransient->uExitReason;
16453 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16454 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16455 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16456 }
16457 else
16458 {
16459 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
16460 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
16461 }
16462 }
16463 else
16464 {
16465 AssertMsgFailed(("MOV from CR%d VM-exit must not happen\n", iCrReg));
16466 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, iCrReg);
16467 }
16468 break;
16469 }
16470
16471 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
16472 {
16473 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
16474 Assert(pVmcsNstGst);
16475 uint64_t const uGstHostMask = pVmcsNstGst->u64Cr0Mask.u;
16476 uint64_t const uReadShadow = pVmcsNstGst->u64Cr0ReadShadow.u;
16477 if ( (uGstHostMask & X86_CR0_TS)
16478 && (uReadShadow & X86_CR0_TS))
16479 {
16480 VMXVEXITINFO ExitInfo;
16481 RT_ZERO(ExitInfo);
16482 ExitInfo.uReason = pVmxTransient->uExitReason;
16483 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16484 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16485 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16486 }
16487 else
16488 rcStrict = hmR0VmxExitClts(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr);
16489 break;
16490 }
16491
16492 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
16493 {
16494 RTGCPTR GCPtrEffDst;
16495 uint16_t const uNewMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(pVmxTransient->uExitQual);
16496 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(pVmxTransient->uExitQual);
16497 if (fMemOperand)
16498 {
16499 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
16500 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
16501 }
16502 else
16503 GCPtrEffDst = NIL_RTGCPTR;
16504
16505 if (CPUMIsGuestVmxLmswInterceptSet(pVCpu, &pVCpu->cpum.GstCtx, uNewMsw))
16506 {
16507 VMXVEXITINFO ExitInfo;
16508 RT_ZERO(ExitInfo);
16509 ExitInfo.uReason = pVmxTransient->uExitReason;
16510 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16511 ExitInfo.u64GuestLinearAddr = GCPtrEffDst;
16512 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16513 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16514 }
16515 else
16516 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, uNewMsw, GCPtrEffDst);
16517 break;
16518 }
16519
16520 default:
16521 {
16522 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
16523 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
16524 }
16525 }
16526
16527 if (rcStrict == VINF_IEM_RAISED_XCPT)
16528 {
16529 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16530 rcStrict = VINF_SUCCESS;
16531 }
16532 return rcStrict;
16533}
16534
16535
16536/**
16537 * Nested-guest VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX).
16538 * Conditional VM-exit.
16539 */
16540HMVMX_EXIT_DECL hmR0VmxExitMovDRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16541{
16542 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16543
16544 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MOV_DR_EXIT))
16545 {
16546 hmR0VmxReadExitQualVmcs(pVmxTransient);
16547 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16548
16549 VMXVEXITINFO ExitInfo;
16550 RT_ZERO(ExitInfo);
16551 ExitInfo.uReason = pVmxTransient->uExitReason;
16552 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16553 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16554 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16555 }
16556 return hmR0VmxExitMovDRx(pVCpu, pVmxTransient);
16557}
16558
16559
16560/**
16561 * Nested-guest VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR).
16562 * Conditional VM-exit.
16563 */
16564HMVMX_EXIT_DECL hmR0VmxExitIoInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16565{
16566 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16567
16568 hmR0VmxReadExitQualVmcs(pVmxTransient);
16569
16570 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
16571 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
16572 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
16573
16574 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
16575 uint8_t const cbAccess = s_aIOSizes[uIOSize];
16576 if (CPUMIsGuestVmxIoInterceptSet(pVCpu, uIOPort, cbAccess))
16577 {
16578 /*
16579 * IN/OUT instruction:
16580 * - Provides VM-exit instruction length.
16581 *
16582 * INS/OUTS instruction:
16583 * - Provides VM-exit instruction length.
16584 * - Provides Guest-linear address.
16585 * - Optionally provides VM-exit instruction info (depends on CPU feature).
16586 */
16587 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16588 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16589
16590 /* Make sure we don't use stale/uninitialized VMX-transient info. below. */
16591 pVmxTransient->ExitInstrInfo.u = 0;
16592 pVmxTransient->uGuestLinearAddr = 0;
16593
16594 bool const fVmxInsOutsInfo = pVM->cpum.ro.GuestFeatures.fVmxInsOutInfo;
16595 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
16596 if (fIOString)
16597 {
16598 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
16599 if (fVmxInsOutsInfo)
16600 {
16601 Assert(RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS)); /* Paranoia. */
16602 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16603 }
16604 }
16605
16606 VMXVEXITINFO ExitInfo;
16607 RT_ZERO(ExitInfo);
16608 ExitInfo.uReason = pVmxTransient->uExitReason;
16609 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16610 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16611 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16612 ExitInfo.u64GuestLinearAddr = pVmxTransient->uGuestLinearAddr;
16613 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16614 }
16615 return hmR0VmxExitIoInstr(pVCpu, pVmxTransient);
16616}
16617
16618
16619/**
16620 * Nested-guest VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
16621 */
16622HMVMX_EXIT_DECL hmR0VmxExitRdmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16623{
16624 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16625
16626 uint32_t fMsrpm;
16627 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
16628 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
16629 else
16630 fMsrpm = VMXMSRPM_EXIT_RD;
16631
16632 if (fMsrpm & VMXMSRPM_EXIT_RD)
16633 {
16634 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16635 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16636 }
16637 return hmR0VmxExitRdmsr(pVCpu, pVmxTransient);
16638}
16639
16640
16641/**
16642 * Nested-guest VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
16643 */
16644HMVMX_EXIT_DECL hmR0VmxExitWrmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16645{
16646 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16647
16648 uint32_t fMsrpm;
16649 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
16650 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
16651 else
16652 fMsrpm = VMXMSRPM_EXIT_WR;
16653
16654 if (fMsrpm & VMXMSRPM_EXIT_WR)
16655 {
16656 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16657 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16658 }
16659 return hmR0VmxExitWrmsr(pVCpu, pVmxTransient);
16660}
16661
16662
16663/**
16664 * Nested-guest VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
16665 */
16666HMVMX_EXIT_DECL hmR0VmxExitMwaitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16667{
16668 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16669
16670 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MWAIT_EXIT))
16671 {
16672 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16673 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16674 }
16675 return hmR0VmxExitMwait(pVCpu, pVmxTransient);
16676}
16677
16678
16679/**
16680 * Nested-guest VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional
16681 * VM-exit.
16682 */
16683HMVMX_EXIT_DECL hmR0VmxExitMtfNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16684{
16685 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16686
16687 /** @todo NSTVMX: Should consider debugging nested-guests using VM debugger. */
16688 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
16689 VMXVEXITINFO ExitInfo;
16690 RT_ZERO(ExitInfo);
16691 ExitInfo.uReason = pVmxTransient->uExitReason;
16692 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
16693 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
16694}
16695
16696
16697/**
16698 * Nested-guest VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
16699 */
16700HMVMX_EXIT_DECL hmR0VmxExitMonitorNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16701{
16702 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16703
16704 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MONITOR_EXIT))
16705 {
16706 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16707 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16708 }
16709 return hmR0VmxExitMonitor(pVCpu, pVmxTransient);
16710}
16711
16712
16713/**
16714 * Nested-guest VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
16715 */
16716HMVMX_EXIT_DECL hmR0VmxExitPauseNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16717{
16718 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16719
16720 /** @todo NSTVMX: Think about this more. Does the outer guest need to intercept
16721 * PAUSE when executing a nested-guest? If it does not, we would not need
16722 * to check for the intercepts here. Just call VM-exit... */
16723
16724 /* The CPU would have already performed the necessary CPL checks for PAUSE-loop exiting. */
16725 if ( CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_PAUSE_EXIT)
16726 || CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
16727 {
16728 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16729 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16730 }
16731 return hmR0VmxExitPause(pVCpu, pVmxTransient);
16732}
16733
16734
16735/**
16736 * Nested-guest VM-exit handler for when the TPR value is lowered below the
16737 * specified threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
16738 */
16739HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThresholdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16740{
16741 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16742
16743 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_TPR_SHADOW))
16744 {
16745 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
16746 VMXVEXITINFO ExitInfo;
16747 RT_ZERO(ExitInfo);
16748 ExitInfo.uReason = pVmxTransient->uExitReason;
16749 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
16750 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
16751 }
16752 return hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient);
16753}
16754
16755
16756/**
16757 * Nested-guest VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional
16758 * VM-exit.
16759 */
16760HMVMX_EXIT_DECL hmR0VmxExitApicAccessNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16761{
16762 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16763
16764 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16765 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16766 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16767 hmR0VmxReadExitQualVmcs(pVmxTransient);
16768
16769 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
16770
16771 Log4Func(("at offset %#x type=%u\n", VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual),
16772 VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual)));
16773
16774 VMXVEXITINFO ExitInfo;
16775 RT_ZERO(ExitInfo);
16776 ExitInfo.uReason = pVmxTransient->uExitReason;
16777 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16778 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16779
16780 VMXVEXITEVENTINFO ExitEventInfo;
16781 RT_ZERO(ExitEventInfo);
16782 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16783 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16784 return IEMExecVmxVmexitApicAccess(pVCpu, &ExitInfo, &ExitEventInfo);
16785}
16786
16787
16788/**
16789 * Nested-guest VM-exit handler for APIC write emulation (VMX_EXIT_APIC_WRITE).
16790 * Conditional VM-exit.
16791 */
16792HMVMX_EXIT_DECL hmR0VmxExitApicWriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16793{
16794 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16795
16796 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_APIC_REG_VIRT));
16797 hmR0VmxReadExitQualVmcs(pVmxTransient);
16798 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
16799}
16800
16801
16802/**
16803 * Nested-guest VM-exit handler for virtualized EOI (VMX_EXIT_VIRTUALIZED_EOI).
16804 * Conditional VM-exit.
16805 */
16806HMVMX_EXIT_DECL hmR0VmxExitVirtEoiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16807{
16808 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16809
16810 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_INT_DELIVERY));
16811 hmR0VmxReadExitQualVmcs(pVmxTransient);
16812 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
16813}
16814
16815
16816/**
16817 * Nested-guest VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
16818 */
16819HMVMX_EXIT_DECL hmR0VmxExitRdtscpNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16820{
16821 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16822
16823 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16824 {
16825 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_RDTSCP));
16826 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16827 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16828 }
16829 return hmR0VmxExitRdtscp(pVCpu, pVmxTransient);
16830}
16831
16832
16833/**
16834 * Nested-guest VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
16835 */
16836HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16837{
16838 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16839
16840 if (CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_WBINVD_EXIT))
16841 {
16842 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16843 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16844 }
16845 return hmR0VmxExitWbinvd(pVCpu, pVmxTransient);
16846}
16847
16848
16849/**
16850 * Nested-guest VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
16851 */
16852HMVMX_EXIT_DECL hmR0VmxExitInvpcidNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16853{
16854 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16855
16856 if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16857 {
16858 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_INVPCID));
16859 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16860 hmR0VmxReadExitQualVmcs(pVmxTransient);
16861 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16862
16863 VMXVEXITINFO ExitInfo;
16864 RT_ZERO(ExitInfo);
16865 ExitInfo.uReason = pVmxTransient->uExitReason;
16866 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16867 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16868 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16869 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16870 }
16871 return hmR0VmxExitInvpcid(pVCpu, pVmxTransient);
16872}
16873
16874
16875/**
16876 * Nested-guest VM-exit handler for invalid-guest state
16877 * (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error VM-exit.
16878 */
16879HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestStateNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16880{
16881 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16882
16883 /*
16884 * Currently this should never happen because we fully emulate VMLAUNCH/VMRESUME in IEM.
16885 * So if it does happen, it indicates a bug possibly in the hardware-assisted VMX code.
16886 * Handle it like it's in an invalid guest state of the outer guest.
16887 *
16888 * When the fast path is implemented, this should be changed to cause the corresponding
16889 * nested-guest VM-exit.
16890 */
16891 return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
16892}
16893
16894
16895/**
16896 * Nested-guest VM-exit handler for instructions that cause VM-exits uncondtionally
16897 * and only provide the instruction length.
16898 *
16899 * Unconditional VM-exit.
16900 */
16901HMVMX_EXIT_DECL hmR0VmxExitInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16902{
16903 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16904
16905#ifdef VBOX_STRICT
16906 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16907 switch (pVmxTransient->uExitReason)
16908 {
16909 case VMX_EXIT_ENCLS:
16910 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_ENCLS_EXIT));
16911 break;
16912
16913 case VMX_EXIT_VMFUNC:
16914 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_VMFUNC));
16915 break;
16916 }
16917#endif
16918
16919 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16920 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16921}
16922
16923
16924/**
16925 * Nested-guest VM-exit handler for instructions that provide instruction length as
16926 * well as more information.
16927 *
16928 * Unconditional VM-exit.
16929 */
16930HMVMX_EXIT_DECL hmR0VmxExitInstrWithInfoNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16931{
16932 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16933
16934#ifdef VBOX_STRICT
16935 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16936 switch (pVmxTransient->uExitReason)
16937 {
16938 case VMX_EXIT_GDTR_IDTR_ACCESS:
16939 case VMX_EXIT_LDTR_TR_ACCESS:
16940 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_DESC_TABLE_EXIT));
16941 break;
16942
16943 case VMX_EXIT_RDRAND:
16944 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_RDRAND_EXIT));
16945 break;
16946
16947 case VMX_EXIT_RDSEED:
16948 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_RDSEED_EXIT));
16949 break;
16950
16951 case VMX_EXIT_XSAVES:
16952 case VMX_EXIT_XRSTORS:
16953 /** @todo NSTVMX: Verify XSS-bitmap. */
16954 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_XSAVES_XRSTORS));
16955 break;
16956
16957 case VMX_EXIT_UMWAIT:
16958 case VMX_EXIT_TPAUSE:
16959 Assert(CPUMIsGuestVmxProcCtlsSet(pVCpu, pCtx, VMX_PROC_CTLS_RDTSC_EXIT));
16960 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, pCtx, VMX_PROC_CTLS2_USER_WAIT_PAUSE));
16961 break;
16962 }
16963#endif
16964
16965 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16966 hmR0VmxReadExitQualVmcs(pVmxTransient);
16967 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16968
16969 VMXVEXITINFO ExitInfo;
16970 RT_ZERO(ExitInfo);
16971 ExitInfo.uReason = pVmxTransient->uExitReason;
16972 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16973 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16974 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16975 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16976}
16977
16978/** @} */
16979#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16980
Note: See TracBrowser for help on using the repository browser.

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