VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/VMXAllTemplate.cpp.h@ 101189

Last change on this file since 101189 was 101060, checked in by vboxsync, 15 months ago

VMM: Nested VMX: bugref:10318 VMX PAT MSR checking nit.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 526.3 KB
Line 
1/* $Id: VMXAllTemplate.cpp.h 101060 2023-09-08 07:59:48Z vboxsync $ */
2/** @file
3 * HM VMX (Intel VT-x) - Code template for our own hypervisor and the NEM darwin backend using Apple's Hypervisor.framework.
4 */
5
6/*
7 * Copyright (C) 2012-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Defined Constants And Macros *
31*********************************************************************************************************************************/
32#if !defined(VMX_VMCS_WRITE_16) || !defined(VMX_VMCS_WRITE_32) || !defined(VMX_VMCS_WRITE_64) || !defined(VMX_VMCS_WRITE_64)
33# error "At least one of the VMX_VMCS_WRITE_16, VMX_VMCS_WRITE_32, VMX_VMCS_WRITE_64 or VMX_VMCS_WRITE_64 is missing"
34#endif
35
36
37#if !defined(VMX_VMCS_READ_16) || !defined(VMX_VMCS_READ_32) || !defined(VMX_VMCS_READ_64) || !defined(VMX_VMCS_READ_64)
38# error "At least one of the VMX_VMCS_READ_16, VMX_VMCS_READ_32, VMX_VMCS_READ_64 or VMX_VMCS_READ_64 is missing"
39#endif
40
41/** Enables condensing of VMREAD instructions, see vmxHCReadToTransient(). */
42#define HMVMX_WITH_CONDENSED_VMREADS
43
44/** Use the function table. */
45#define HMVMX_USE_FUNCTION_TABLE
46
47/** Determine which tagged-TLB flush handler to use. */
48#define HMVMX_FLUSH_TAGGED_TLB_EPT_VPID 0
49#define HMVMX_FLUSH_TAGGED_TLB_EPT 1
50#define HMVMX_FLUSH_TAGGED_TLB_VPID 2
51#define HMVMX_FLUSH_TAGGED_TLB_NONE 3
52
53/** Assert that all the given fields have been read from the VMCS. */
54#ifdef VBOX_STRICT
55# define HMVMX_ASSERT_READ(a_pVmxTransient, a_fReadFields) \
56 do { \
57 uint32_t const fVmcsFieldRead = ASMAtomicUoReadU32(&pVmxTransient->fVmcsFieldsRead); \
58 Assert((fVmcsFieldRead & (a_fReadFields)) == (a_fReadFields)); \
59 } while (0)
60#else
61# define HMVMX_ASSERT_READ(a_pVmxTransient, a_fReadFields) do { } while (0)
62#endif
63
64/**
65 * Subset of the guest-CPU state that is kept by VMX R0 code while executing the
66 * guest using hardware-assisted VMX.
67 *
68 * This excludes state like GPRs (other than RSP) which are always are
69 * swapped and restored across the world-switch and also registers like EFER,
70 * MSR which cannot be modified by the guest without causing a VM-exit.
71 */
72#define HMVMX_CPUMCTX_EXTRN_ALL ( CPUMCTX_EXTRN_RIP \
73 | CPUMCTX_EXTRN_RFLAGS \
74 | CPUMCTX_EXTRN_RSP \
75 | CPUMCTX_EXTRN_SREG_MASK \
76 | CPUMCTX_EXTRN_TABLE_MASK \
77 | CPUMCTX_EXTRN_KERNEL_GS_BASE \
78 | CPUMCTX_EXTRN_SYSCALL_MSRS \
79 | CPUMCTX_EXTRN_SYSENTER_MSRS \
80 | CPUMCTX_EXTRN_TSC_AUX \
81 | CPUMCTX_EXTRN_OTHER_MSRS \
82 | CPUMCTX_EXTRN_CR0 \
83 | CPUMCTX_EXTRN_CR3 \
84 | CPUMCTX_EXTRN_CR4 \
85 | CPUMCTX_EXTRN_DR7 \
86 | CPUMCTX_EXTRN_HWVIRT \
87 | CPUMCTX_EXTRN_INHIBIT_INT \
88 | CPUMCTX_EXTRN_INHIBIT_NMI)
89
90/**
91 * Exception bitmap mask for real-mode guests (real-on-v86).
92 *
93 * We need to intercept all exceptions manually except:
94 * - \#AC and \#DB are always intercepted to prevent the CPU from deadlocking
95 * due to bugs in Intel CPUs.
96 * - \#PF need not be intercepted even in real-mode if we have nested paging
97 * support.
98 */
99#define HMVMX_REAL_MODE_XCPT_MASK ( RT_BIT(X86_XCPT_DE) /* always: | RT_BIT(X86_XCPT_DB) */ | RT_BIT(X86_XCPT_NMI) \
100 | RT_BIT(X86_XCPT_BP) | RT_BIT(X86_XCPT_OF) | RT_BIT(X86_XCPT_BR) \
101 | RT_BIT(X86_XCPT_UD) | RT_BIT(X86_XCPT_NM) | RT_BIT(X86_XCPT_DF) \
102 | RT_BIT(X86_XCPT_CO_SEG_OVERRUN) | RT_BIT(X86_XCPT_TS) | RT_BIT(X86_XCPT_NP) \
103 | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_GP) /* RT_BIT(X86_XCPT_PF) */ \
104 | RT_BIT(X86_XCPT_MF) /* always: | RT_BIT(X86_XCPT_AC) */ | RT_BIT(X86_XCPT_MC) \
105 | RT_BIT(X86_XCPT_XF))
106
107/** Maximum VM-instruction error number. */
108#define HMVMX_INSTR_ERROR_MAX 28
109
110/** Profiling macro. */
111#ifdef HM_PROFILE_EXIT_DISPATCH
112# define HMVMX_START_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_START(&VCPU_2_VMXSTATS(pVCpu).StatExitDispatch, ed)
113# define HMVMX_STOP_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_STOP(&VCPU_2_VMXSTATS(pVCpu).StatExitDispatch, ed)
114#else
115# define HMVMX_START_EXIT_DISPATCH_PROF() do { } while (0)
116# define HMVMX_STOP_EXIT_DISPATCH_PROF() do { } while (0)
117#endif
118
119#ifndef IN_NEM_DARWIN
120/** Assert that preemption is disabled or covered by thread-context hooks. */
121# define HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu) Assert( VMMR0ThreadCtxHookIsEnabled((a_pVCpu)) \
122 || !RTThreadPreemptIsEnabled(NIL_RTTHREAD))
123
124/** Assert that we haven't migrated CPUs when thread-context hooks are not
125 * used. */
126# define HMVMX_ASSERT_CPU_SAFE(a_pVCpu) AssertMsg( VMMR0ThreadCtxHookIsEnabled((a_pVCpu)) \
127 || (a_pVCpu)->hmr0.s.idEnteredCpu == RTMpCpuId(), \
128 ("Illegal migration! Entered on CPU %u Current %u\n", \
129 (a_pVCpu)->hmr0.s.idEnteredCpu, RTMpCpuId()))
130#else
131# define HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu) do { } while (0)
132# define HMVMX_ASSERT_CPU_SAFE(a_pVCpu) do { } while (0)
133#endif
134
135/** Asserts that the given CPUMCTX_EXTRN_XXX bits are present in the guest-CPU
136 * context. */
137#define HMVMX_CPUMCTX_ASSERT(a_pVCpu, a_fExtrnMbz) AssertMsg(!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fExtrnMbz)), \
138 ("fExtrn=%#RX64 fExtrnMbz=%#RX64\n", \
139 (a_pVCpu)->cpum.GstCtx.fExtrn, (a_fExtrnMbz)))
140
141/** Log the VM-exit reason with an easily visible marker to identify it in a
142 * potential sea of logging data. */
143#define HMVMX_LOG_EXIT(a_pVCpu, a_uExitReason) \
144 do { \
145 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, \
146 HMGetVmxExitName(a_uExitReason))); \
147 } while (0) \
148
149
150/*********************************************************************************************************************************
151* Structures and Typedefs *
152*********************************************************************************************************************************/
153/**
154 * Memory operand read or write access.
155 */
156typedef enum VMXMEMACCESS
157{
158 VMXMEMACCESS_READ = 0,
159 VMXMEMACCESS_WRITE = 1
160} VMXMEMACCESS;
161
162
163/**
164 * VMX VM-exit handler.
165 *
166 * @returns Strict VBox status code (i.e. informational status codes too).
167 * @param pVCpu The cross context virtual CPU structure.
168 * @param pVmxTransient The VMX-transient structure.
169 */
170#ifndef HMVMX_USE_FUNCTION_TABLE
171typedef VBOXSTRICTRC FNVMXEXITHANDLER(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
172#else
173typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNVMXEXITHANDLER,(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient));
174/** Pointer to VM-exit handler. */
175typedef FNVMXEXITHANDLER *PFNVMXEXITHANDLER;
176#endif
177
178/**
179 * VMX VM-exit handler, non-strict status code.
180 *
181 * This is generally the same as FNVMXEXITHANDLER, the NSRC bit is just FYI.
182 *
183 * @returns VBox status code, no informational status code returned.
184 * @param pVCpu The cross context virtual CPU structure.
185 * @param pVmxTransient The VMX-transient structure.
186 *
187 * @remarks This is not used on anything returning VERR_EM_INTERPRETER as the
188 * use of that status code will be replaced with VINF_EM_SOMETHING
189 * later when switching over to IEM.
190 */
191#ifndef HMVMX_USE_FUNCTION_TABLE
192typedef int FNVMXEXITHANDLERNSRC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
193#else
194typedef FNVMXEXITHANDLER FNVMXEXITHANDLERNSRC;
195#endif
196
197
198/*********************************************************************************************************************************
199* Internal Functions *
200*********************************************************************************************************************************/
201#ifndef HMVMX_USE_FUNCTION_TABLE
202DECLINLINE(VBOXSTRICTRC) vmxHCHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
203# define HMVMX_EXIT_DECL DECLINLINE(VBOXSTRICTRC)
204# define HMVMX_EXIT_NSRC_DECL DECLINLINE(int)
205#else
206# define HMVMX_EXIT_DECL static DECLCALLBACK(VBOXSTRICTRC)
207# define HMVMX_EXIT_NSRC_DECL HMVMX_EXIT_DECL
208#endif
209#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
210DECLINLINE(VBOXSTRICTRC) vmxHCHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
211#endif
212
213static int vmxHCImportGuestStateEx(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat);
214
215/** @name VM-exit handler prototypes.
216 * @{
217 */
218static FNVMXEXITHANDLER vmxHCExitXcptOrNmi;
219static FNVMXEXITHANDLER vmxHCExitExtInt;
220static FNVMXEXITHANDLER vmxHCExitTripleFault;
221static FNVMXEXITHANDLERNSRC vmxHCExitIntWindow;
222static FNVMXEXITHANDLERNSRC vmxHCExitNmiWindow;
223static FNVMXEXITHANDLER vmxHCExitTaskSwitch;
224static FNVMXEXITHANDLER vmxHCExitCpuid;
225static FNVMXEXITHANDLER vmxHCExitGetsec;
226static FNVMXEXITHANDLER vmxHCExitHlt;
227static FNVMXEXITHANDLERNSRC vmxHCExitInvd;
228static FNVMXEXITHANDLER vmxHCExitInvlpg;
229static FNVMXEXITHANDLER vmxHCExitRdpmc;
230static FNVMXEXITHANDLER vmxHCExitVmcall;
231#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
232static FNVMXEXITHANDLER vmxHCExitVmclear;
233static FNVMXEXITHANDLER vmxHCExitVmlaunch;
234static FNVMXEXITHANDLER vmxHCExitVmptrld;
235static FNVMXEXITHANDLER vmxHCExitVmptrst;
236static FNVMXEXITHANDLER vmxHCExitVmread;
237static FNVMXEXITHANDLER vmxHCExitVmresume;
238static FNVMXEXITHANDLER vmxHCExitVmwrite;
239static FNVMXEXITHANDLER vmxHCExitVmxoff;
240static FNVMXEXITHANDLER vmxHCExitVmxon;
241static FNVMXEXITHANDLER vmxHCExitInvvpid;
242# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
243static FNVMXEXITHANDLER vmxHCExitInvept;
244# endif
245#endif
246static FNVMXEXITHANDLER vmxHCExitRdtsc;
247static FNVMXEXITHANDLER vmxHCExitMovCRx;
248static FNVMXEXITHANDLER vmxHCExitMovDRx;
249static FNVMXEXITHANDLER vmxHCExitIoInstr;
250static FNVMXEXITHANDLER vmxHCExitRdmsr;
251static FNVMXEXITHANDLER vmxHCExitWrmsr;
252static FNVMXEXITHANDLER vmxHCExitMwait;
253static FNVMXEXITHANDLER vmxHCExitMtf;
254static FNVMXEXITHANDLER vmxHCExitMonitor;
255static FNVMXEXITHANDLER vmxHCExitPause;
256static FNVMXEXITHANDLERNSRC vmxHCExitTprBelowThreshold;
257static FNVMXEXITHANDLER vmxHCExitApicAccess;
258static FNVMXEXITHANDLER vmxHCExitEptViolation;
259static FNVMXEXITHANDLER vmxHCExitEptMisconfig;
260static FNVMXEXITHANDLER vmxHCExitRdtscp;
261static FNVMXEXITHANDLER vmxHCExitPreemptTimer;
262static FNVMXEXITHANDLERNSRC vmxHCExitWbinvd;
263static FNVMXEXITHANDLER vmxHCExitXsetbv;
264static FNVMXEXITHANDLER vmxHCExitInvpcid;
265#ifndef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
266static FNVMXEXITHANDLERNSRC vmxHCExitSetPendingXcptUD;
267#endif
268static FNVMXEXITHANDLERNSRC vmxHCExitErrInvalidGuestState;
269static FNVMXEXITHANDLERNSRC vmxHCExitErrUnexpected;
270/** @} */
271
272#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
273/** @name Nested-guest VM-exit handler prototypes.
274 * @{
275 */
276static FNVMXEXITHANDLER vmxHCExitXcptOrNmiNested;
277static FNVMXEXITHANDLER vmxHCExitTripleFaultNested;
278static FNVMXEXITHANDLERNSRC vmxHCExitIntWindowNested;
279static FNVMXEXITHANDLERNSRC vmxHCExitNmiWindowNested;
280static FNVMXEXITHANDLER vmxHCExitTaskSwitchNested;
281static FNVMXEXITHANDLER vmxHCExitHltNested;
282static FNVMXEXITHANDLER vmxHCExitInvlpgNested;
283static FNVMXEXITHANDLER vmxHCExitRdpmcNested;
284static FNVMXEXITHANDLER vmxHCExitVmreadVmwriteNested;
285static FNVMXEXITHANDLER vmxHCExitRdtscNested;
286static FNVMXEXITHANDLER vmxHCExitMovCRxNested;
287static FNVMXEXITHANDLER vmxHCExitMovDRxNested;
288static FNVMXEXITHANDLER vmxHCExitIoInstrNested;
289static FNVMXEXITHANDLER vmxHCExitRdmsrNested;
290static FNVMXEXITHANDLER vmxHCExitWrmsrNested;
291static FNVMXEXITHANDLER vmxHCExitMwaitNested;
292static FNVMXEXITHANDLER vmxHCExitMtfNested;
293static FNVMXEXITHANDLER vmxHCExitMonitorNested;
294static FNVMXEXITHANDLER vmxHCExitPauseNested;
295static FNVMXEXITHANDLERNSRC vmxHCExitTprBelowThresholdNested;
296static FNVMXEXITHANDLER vmxHCExitApicAccessNested;
297static FNVMXEXITHANDLER vmxHCExitApicWriteNested;
298static FNVMXEXITHANDLER vmxHCExitVirtEoiNested;
299static FNVMXEXITHANDLER vmxHCExitRdtscpNested;
300static FNVMXEXITHANDLERNSRC vmxHCExitWbinvdNested;
301static FNVMXEXITHANDLER vmxHCExitInvpcidNested;
302static FNVMXEXITHANDLERNSRC vmxHCExitErrInvalidGuestStateNested;
303static FNVMXEXITHANDLER vmxHCExitInstrNested;
304static FNVMXEXITHANDLER vmxHCExitInstrWithInfoNested;
305# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
306static FNVMXEXITHANDLER vmxHCExitEptViolationNested;
307static FNVMXEXITHANDLER vmxHCExitEptMisconfigNested;
308# endif
309/** @} */
310#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
311
312
313/*********************************************************************************************************************************
314* Global Variables *
315*********************************************************************************************************************************/
316#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
317/**
318 * Array of all VMCS fields.
319 * Any fields added to the VT-x spec. should be added here.
320 *
321 * Currently only used to derive shadow VMCS fields for hardware-assisted execution
322 * of nested-guests.
323 */
324static const uint32_t g_aVmcsFields[] =
325{
326 /* 16-bit control fields. */
327 VMX_VMCS16_VPID,
328 VMX_VMCS16_POSTED_INT_NOTIFY_VECTOR,
329 VMX_VMCS16_EPTP_INDEX,
330 VMX_VMCS16_HLAT_PREFIX_SIZE,
331
332 /* 16-bit guest-state fields. */
333 VMX_VMCS16_GUEST_ES_SEL,
334 VMX_VMCS16_GUEST_CS_SEL,
335 VMX_VMCS16_GUEST_SS_SEL,
336 VMX_VMCS16_GUEST_DS_SEL,
337 VMX_VMCS16_GUEST_FS_SEL,
338 VMX_VMCS16_GUEST_GS_SEL,
339 VMX_VMCS16_GUEST_LDTR_SEL,
340 VMX_VMCS16_GUEST_TR_SEL,
341 VMX_VMCS16_GUEST_INTR_STATUS,
342 VMX_VMCS16_GUEST_PML_INDEX,
343
344 /* 16-bits host-state fields. */
345 VMX_VMCS16_HOST_ES_SEL,
346 VMX_VMCS16_HOST_CS_SEL,
347 VMX_VMCS16_HOST_SS_SEL,
348 VMX_VMCS16_HOST_DS_SEL,
349 VMX_VMCS16_HOST_FS_SEL,
350 VMX_VMCS16_HOST_GS_SEL,
351 VMX_VMCS16_HOST_TR_SEL,
352
353 /* 64-bit control fields. */
354 VMX_VMCS64_CTRL_IO_BITMAP_A_FULL,
355 VMX_VMCS64_CTRL_IO_BITMAP_A_HIGH,
356 VMX_VMCS64_CTRL_IO_BITMAP_B_FULL,
357 VMX_VMCS64_CTRL_IO_BITMAP_B_HIGH,
358 VMX_VMCS64_CTRL_MSR_BITMAP_FULL,
359 VMX_VMCS64_CTRL_MSR_BITMAP_HIGH,
360 VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL,
361 VMX_VMCS64_CTRL_EXIT_MSR_STORE_HIGH,
362 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL,
363 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_HIGH,
364 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL,
365 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_HIGH,
366 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL,
367 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_HIGH,
368 VMX_VMCS64_CTRL_EXEC_PML_ADDR_FULL,
369 VMX_VMCS64_CTRL_EXEC_PML_ADDR_HIGH,
370 VMX_VMCS64_CTRL_TSC_OFFSET_FULL,
371 VMX_VMCS64_CTRL_TSC_OFFSET_HIGH,
372 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL,
373 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_HIGH,
374 VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL,
375 VMX_VMCS64_CTRL_APIC_ACCESSADDR_HIGH,
376 VMX_VMCS64_CTRL_POSTED_INTR_DESC_FULL,
377 VMX_VMCS64_CTRL_POSTED_INTR_DESC_HIGH,
378 VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL,
379 VMX_VMCS64_CTRL_VMFUNC_CTRLS_HIGH,
380 VMX_VMCS64_CTRL_EPTP_FULL,
381 VMX_VMCS64_CTRL_EPTP_HIGH,
382 VMX_VMCS64_CTRL_EOI_BITMAP_0_FULL,
383 VMX_VMCS64_CTRL_EOI_BITMAP_0_HIGH,
384 VMX_VMCS64_CTRL_EOI_BITMAP_1_FULL,
385 VMX_VMCS64_CTRL_EOI_BITMAP_1_HIGH,
386 VMX_VMCS64_CTRL_EOI_BITMAP_2_FULL,
387 VMX_VMCS64_CTRL_EOI_BITMAP_2_HIGH,
388 VMX_VMCS64_CTRL_EOI_BITMAP_3_FULL,
389 VMX_VMCS64_CTRL_EOI_BITMAP_3_HIGH,
390 VMX_VMCS64_CTRL_EPTP_LIST_FULL,
391 VMX_VMCS64_CTRL_EPTP_LIST_HIGH,
392 VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL,
393 VMX_VMCS64_CTRL_VMREAD_BITMAP_HIGH,
394 VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL,
395 VMX_VMCS64_CTRL_VMWRITE_BITMAP_HIGH,
396 VMX_VMCS64_CTRL_VE_XCPT_INFO_ADDR_FULL,
397 VMX_VMCS64_CTRL_VE_XCPT_INFO_ADDR_HIGH,
398 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_FULL,
399 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_HIGH,
400 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_FULL,
401 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_HIGH,
402 VMX_VMCS64_CTRL_SPPTP_FULL,
403 VMX_VMCS64_CTRL_SPPTP_HIGH,
404 VMX_VMCS64_CTRL_TSC_MULTIPLIER_FULL,
405 VMX_VMCS64_CTRL_TSC_MULTIPLIER_HIGH,
406 VMX_VMCS64_CTRL_PROC_EXEC3_FULL,
407 VMX_VMCS64_CTRL_PROC_EXEC3_HIGH,
408 VMX_VMCS64_CTRL_ENCLV_EXITING_BITMAP_FULL,
409 VMX_VMCS64_CTRL_ENCLV_EXITING_BITMAP_HIGH,
410 VMX_VMCS64_CTRL_PCONFIG_EXITING_BITMAP_FULL,
411 VMX_VMCS64_CTRL_PCONFIG_EXITING_BITMAP_HIGH,
412 VMX_VMCS64_CTRL_HLAT_PTR_FULL,
413 VMX_VMCS64_CTRL_HLAT_PTR_HIGH,
414 VMX_VMCS64_CTRL_EXIT2_FULL,
415 VMX_VMCS64_CTRL_EXIT2_HIGH,
416
417 /* 64-bit read-only data fields. */
418 VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL,
419 VMX_VMCS64_RO_GUEST_PHYS_ADDR_HIGH,
420
421 /* 64-bit guest-state fields. */
422 VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL,
423 VMX_VMCS64_GUEST_VMCS_LINK_PTR_HIGH,
424 VMX_VMCS64_GUEST_DEBUGCTL_FULL,
425 VMX_VMCS64_GUEST_DEBUGCTL_HIGH,
426 VMX_VMCS64_GUEST_PAT_FULL,
427 VMX_VMCS64_GUEST_PAT_HIGH,
428 VMX_VMCS64_GUEST_EFER_FULL,
429 VMX_VMCS64_GUEST_EFER_HIGH,
430 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL,
431 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_HIGH,
432 VMX_VMCS64_GUEST_PDPTE0_FULL,
433 VMX_VMCS64_GUEST_PDPTE0_HIGH,
434 VMX_VMCS64_GUEST_PDPTE1_FULL,
435 VMX_VMCS64_GUEST_PDPTE1_HIGH,
436 VMX_VMCS64_GUEST_PDPTE2_FULL,
437 VMX_VMCS64_GUEST_PDPTE2_HIGH,
438 VMX_VMCS64_GUEST_PDPTE3_FULL,
439 VMX_VMCS64_GUEST_PDPTE3_HIGH,
440 VMX_VMCS64_GUEST_BNDCFGS_FULL,
441 VMX_VMCS64_GUEST_BNDCFGS_HIGH,
442 VMX_VMCS64_GUEST_RTIT_CTL_FULL,
443 VMX_VMCS64_GUEST_RTIT_CTL_HIGH,
444 VMX_VMCS64_GUEST_PKRS_FULL,
445 VMX_VMCS64_GUEST_PKRS_HIGH,
446
447 /* 64-bit host-state fields. */
448 VMX_VMCS64_HOST_PAT_FULL,
449 VMX_VMCS64_HOST_PAT_HIGH,
450 VMX_VMCS64_HOST_EFER_FULL,
451 VMX_VMCS64_HOST_EFER_HIGH,
452 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL,
453 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_HIGH,
454 VMX_VMCS64_HOST_PKRS_FULL,
455 VMX_VMCS64_HOST_PKRS_HIGH,
456
457 /* 32-bit control fields. */
458 VMX_VMCS32_CTRL_PIN_EXEC,
459 VMX_VMCS32_CTRL_PROC_EXEC,
460 VMX_VMCS32_CTRL_EXCEPTION_BITMAP,
461 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK,
462 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH,
463 VMX_VMCS32_CTRL_CR3_TARGET_COUNT,
464 VMX_VMCS32_CTRL_EXIT,
465 VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT,
466 VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT,
467 VMX_VMCS32_CTRL_ENTRY,
468 VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT,
469 VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO,
470 VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE,
471 VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH,
472 VMX_VMCS32_CTRL_TPR_THRESHOLD,
473 VMX_VMCS32_CTRL_PROC_EXEC2,
474 VMX_VMCS32_CTRL_PLE_GAP,
475 VMX_VMCS32_CTRL_PLE_WINDOW,
476
477 /* 32-bits read-only fields. */
478 VMX_VMCS32_RO_VM_INSTR_ERROR,
479 VMX_VMCS32_RO_EXIT_REASON,
480 VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO,
481 VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE,
482 VMX_VMCS32_RO_IDT_VECTORING_INFO,
483 VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE,
484 VMX_VMCS32_RO_EXIT_INSTR_LENGTH,
485 VMX_VMCS32_RO_EXIT_INSTR_INFO,
486
487 /* 32-bit guest-state fields. */
488 VMX_VMCS32_GUEST_ES_LIMIT,
489 VMX_VMCS32_GUEST_CS_LIMIT,
490 VMX_VMCS32_GUEST_SS_LIMIT,
491 VMX_VMCS32_GUEST_DS_LIMIT,
492 VMX_VMCS32_GUEST_FS_LIMIT,
493 VMX_VMCS32_GUEST_GS_LIMIT,
494 VMX_VMCS32_GUEST_LDTR_LIMIT,
495 VMX_VMCS32_GUEST_TR_LIMIT,
496 VMX_VMCS32_GUEST_GDTR_LIMIT,
497 VMX_VMCS32_GUEST_IDTR_LIMIT,
498 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
499 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
500 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
501 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
502 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
503 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS,
504 VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS,
505 VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS,
506 VMX_VMCS32_GUEST_INT_STATE,
507 VMX_VMCS32_GUEST_ACTIVITY_STATE,
508 VMX_VMCS32_GUEST_SMBASE,
509 VMX_VMCS32_GUEST_SYSENTER_CS,
510 VMX_VMCS32_PREEMPT_TIMER_VALUE,
511
512 /* 32-bit host-state fields. */
513 VMX_VMCS32_HOST_SYSENTER_CS,
514
515 /* Natural-width control fields. */
516 VMX_VMCS_CTRL_CR0_MASK,
517 VMX_VMCS_CTRL_CR4_MASK,
518 VMX_VMCS_CTRL_CR0_READ_SHADOW,
519 VMX_VMCS_CTRL_CR4_READ_SHADOW,
520 VMX_VMCS_CTRL_CR3_TARGET_VAL0,
521 VMX_VMCS_CTRL_CR3_TARGET_VAL1,
522 VMX_VMCS_CTRL_CR3_TARGET_VAL2,
523 VMX_VMCS_CTRL_CR3_TARGET_VAL3,
524
525 /* Natural-width read-only data fields. */
526 VMX_VMCS_RO_EXIT_QUALIFICATION,
527 VMX_VMCS_RO_IO_RCX,
528 VMX_VMCS_RO_IO_RSI,
529 VMX_VMCS_RO_IO_RDI,
530 VMX_VMCS_RO_IO_RIP,
531 VMX_VMCS_RO_GUEST_LINEAR_ADDR,
532
533 /* Natural-width guest-state field */
534 VMX_VMCS_GUEST_CR0,
535 VMX_VMCS_GUEST_CR3,
536 VMX_VMCS_GUEST_CR4,
537 VMX_VMCS_GUEST_ES_BASE,
538 VMX_VMCS_GUEST_CS_BASE,
539 VMX_VMCS_GUEST_SS_BASE,
540 VMX_VMCS_GUEST_DS_BASE,
541 VMX_VMCS_GUEST_FS_BASE,
542 VMX_VMCS_GUEST_GS_BASE,
543 VMX_VMCS_GUEST_LDTR_BASE,
544 VMX_VMCS_GUEST_TR_BASE,
545 VMX_VMCS_GUEST_GDTR_BASE,
546 VMX_VMCS_GUEST_IDTR_BASE,
547 VMX_VMCS_GUEST_DR7,
548 VMX_VMCS_GUEST_RSP,
549 VMX_VMCS_GUEST_RIP,
550 VMX_VMCS_GUEST_RFLAGS,
551 VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS,
552 VMX_VMCS_GUEST_SYSENTER_ESP,
553 VMX_VMCS_GUEST_SYSENTER_EIP,
554 VMX_VMCS_GUEST_S_CET,
555 VMX_VMCS_GUEST_SSP,
556 VMX_VMCS_GUEST_INTR_SSP_TABLE_ADDR,
557
558 /* Natural-width host-state fields */
559 VMX_VMCS_HOST_CR0,
560 VMX_VMCS_HOST_CR3,
561 VMX_VMCS_HOST_CR4,
562 VMX_VMCS_HOST_FS_BASE,
563 VMX_VMCS_HOST_GS_BASE,
564 VMX_VMCS_HOST_TR_BASE,
565 VMX_VMCS_HOST_GDTR_BASE,
566 VMX_VMCS_HOST_IDTR_BASE,
567 VMX_VMCS_HOST_SYSENTER_ESP,
568 VMX_VMCS_HOST_SYSENTER_EIP,
569 VMX_VMCS_HOST_RSP,
570 VMX_VMCS_HOST_RIP,
571 VMX_VMCS_HOST_S_CET,
572 VMX_VMCS_HOST_SSP,
573 VMX_VMCS_HOST_INTR_SSP_TABLE_ADDR
574};
575#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
576
577#ifdef HMVMX_USE_FUNCTION_TABLE
578/**
579 * VMX_EXIT dispatch table.
580 */
581static const struct CLANG11NOTHROWWEIRDNESS { PFNVMXEXITHANDLER pfn; } g_aVMExitHandlers[VMX_EXIT_MAX + 1] =
582{
583 /* 0 VMX_EXIT_XCPT_OR_NMI */ { vmxHCExitXcptOrNmi },
584 /* 1 VMX_EXIT_EXT_INT */ { vmxHCExitExtInt },
585 /* 2 VMX_EXIT_TRIPLE_FAULT */ { vmxHCExitTripleFault },
586 /* 3 VMX_EXIT_INIT_SIGNAL */ { vmxHCExitErrUnexpected },
587 /* 4 VMX_EXIT_SIPI */ { vmxHCExitErrUnexpected },
588 /* 5 VMX_EXIT_IO_SMI */ { vmxHCExitErrUnexpected },
589 /* 6 VMX_EXIT_SMI */ { vmxHCExitErrUnexpected },
590 /* 7 VMX_EXIT_INT_WINDOW */ { vmxHCExitIntWindow },
591 /* 8 VMX_EXIT_NMI_WINDOW */ { vmxHCExitNmiWindow },
592 /* 9 VMX_EXIT_TASK_SWITCH */ { vmxHCExitTaskSwitch },
593 /* 10 VMX_EXIT_CPUID */ { vmxHCExitCpuid },
594 /* 11 VMX_EXIT_GETSEC */ { vmxHCExitGetsec },
595 /* 12 VMX_EXIT_HLT */ { vmxHCExitHlt },
596 /* 13 VMX_EXIT_INVD */ { vmxHCExitInvd },
597 /* 14 VMX_EXIT_INVLPG */ { vmxHCExitInvlpg },
598 /* 15 VMX_EXIT_RDPMC */ { vmxHCExitRdpmc },
599 /* 16 VMX_EXIT_RDTSC */ { vmxHCExitRdtsc },
600 /* 17 VMX_EXIT_RSM */ { vmxHCExitErrUnexpected },
601 /* 18 VMX_EXIT_VMCALL */ { vmxHCExitVmcall },
602#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
603 /* 19 VMX_EXIT_VMCLEAR */ { vmxHCExitVmclear },
604 /* 20 VMX_EXIT_VMLAUNCH */ { vmxHCExitVmlaunch },
605 /* 21 VMX_EXIT_VMPTRLD */ { vmxHCExitVmptrld },
606 /* 22 VMX_EXIT_VMPTRST */ { vmxHCExitVmptrst },
607 /* 23 VMX_EXIT_VMREAD */ { vmxHCExitVmread },
608 /* 24 VMX_EXIT_VMRESUME */ { vmxHCExitVmresume },
609 /* 25 VMX_EXIT_VMWRITE */ { vmxHCExitVmwrite },
610 /* 26 VMX_EXIT_VMXOFF */ { vmxHCExitVmxoff },
611 /* 27 VMX_EXIT_VMXON */ { vmxHCExitVmxon },
612#else
613 /* 19 VMX_EXIT_VMCLEAR */ { vmxHCExitSetPendingXcptUD },
614 /* 20 VMX_EXIT_VMLAUNCH */ { vmxHCExitSetPendingXcptUD },
615 /* 21 VMX_EXIT_VMPTRLD */ { vmxHCExitSetPendingXcptUD },
616 /* 22 VMX_EXIT_VMPTRST */ { vmxHCExitSetPendingXcptUD },
617 /* 23 VMX_EXIT_VMREAD */ { vmxHCExitSetPendingXcptUD },
618 /* 24 VMX_EXIT_VMRESUME */ { vmxHCExitSetPendingXcptUD },
619 /* 25 VMX_EXIT_VMWRITE */ { vmxHCExitSetPendingXcptUD },
620 /* 26 VMX_EXIT_VMXOFF */ { vmxHCExitSetPendingXcptUD },
621 /* 27 VMX_EXIT_VMXON */ { vmxHCExitSetPendingXcptUD },
622#endif
623 /* 28 VMX_EXIT_MOV_CRX */ { vmxHCExitMovCRx },
624 /* 29 VMX_EXIT_MOV_DRX */ { vmxHCExitMovDRx },
625 /* 30 VMX_EXIT_IO_INSTR */ { vmxHCExitIoInstr },
626 /* 31 VMX_EXIT_RDMSR */ { vmxHCExitRdmsr },
627 /* 32 VMX_EXIT_WRMSR */ { vmxHCExitWrmsr },
628 /* 33 VMX_EXIT_ERR_INVALID_GUEST_STATE */ { vmxHCExitErrInvalidGuestState },
629 /* 34 VMX_EXIT_ERR_MSR_LOAD */ { vmxHCExitErrUnexpected },
630 /* 35 UNDEFINED */ { vmxHCExitErrUnexpected },
631 /* 36 VMX_EXIT_MWAIT */ { vmxHCExitMwait },
632 /* 37 VMX_EXIT_MTF */ { vmxHCExitMtf },
633 /* 38 UNDEFINED */ { vmxHCExitErrUnexpected },
634 /* 39 VMX_EXIT_MONITOR */ { vmxHCExitMonitor },
635 /* 40 VMX_EXIT_PAUSE */ { vmxHCExitPause },
636 /* 41 VMX_EXIT_ERR_MACHINE_CHECK */ { vmxHCExitErrUnexpected },
637 /* 42 UNDEFINED */ { vmxHCExitErrUnexpected },
638 /* 43 VMX_EXIT_TPR_BELOW_THRESHOLD */ { vmxHCExitTprBelowThreshold },
639 /* 44 VMX_EXIT_APIC_ACCESS */ { vmxHCExitApicAccess },
640 /* 45 VMX_EXIT_VIRTUALIZED_EOI */ { vmxHCExitErrUnexpected },
641 /* 46 VMX_EXIT_GDTR_IDTR_ACCESS */ { vmxHCExitErrUnexpected },
642 /* 47 VMX_EXIT_LDTR_TR_ACCESS */ { vmxHCExitErrUnexpected },
643 /* 48 VMX_EXIT_EPT_VIOLATION */ { vmxHCExitEptViolation },
644 /* 49 VMX_EXIT_EPT_MISCONFIG */ { vmxHCExitEptMisconfig },
645#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
646 /* 50 VMX_EXIT_INVEPT */ { vmxHCExitInvept },
647#else
648 /* 50 VMX_EXIT_INVEPT */ { vmxHCExitSetPendingXcptUD },
649#endif
650 /* 51 VMX_EXIT_RDTSCP */ { vmxHCExitRdtscp },
651 /* 52 VMX_EXIT_PREEMPT_TIMER */ { vmxHCExitPreemptTimer },
652#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
653 /* 53 VMX_EXIT_INVVPID */ { vmxHCExitInvvpid },
654#else
655 /* 53 VMX_EXIT_INVVPID */ { vmxHCExitSetPendingXcptUD },
656#endif
657 /* 54 VMX_EXIT_WBINVD */ { vmxHCExitWbinvd },
658 /* 55 VMX_EXIT_XSETBV */ { vmxHCExitXsetbv },
659 /* 56 VMX_EXIT_APIC_WRITE */ { vmxHCExitErrUnexpected },
660 /* 57 VMX_EXIT_RDRAND */ { vmxHCExitErrUnexpected },
661 /* 58 VMX_EXIT_INVPCID */ { vmxHCExitInvpcid },
662 /* 59 VMX_EXIT_VMFUNC */ { vmxHCExitErrUnexpected },
663 /* 60 VMX_EXIT_ENCLS */ { vmxHCExitErrUnexpected },
664 /* 61 VMX_EXIT_RDSEED */ { vmxHCExitErrUnexpected },
665 /* 62 VMX_EXIT_PML_FULL */ { vmxHCExitErrUnexpected },
666 /* 63 VMX_EXIT_XSAVES */ { vmxHCExitErrUnexpected },
667 /* 64 VMX_EXIT_XRSTORS */ { vmxHCExitErrUnexpected },
668 /* 65 UNDEFINED */ { vmxHCExitErrUnexpected },
669 /* 66 VMX_EXIT_SPP_EVENT */ { vmxHCExitErrUnexpected },
670 /* 67 VMX_EXIT_UMWAIT */ { vmxHCExitErrUnexpected },
671 /* 68 VMX_EXIT_TPAUSE */ { vmxHCExitErrUnexpected },
672 /* 69 VMX_EXIT_LOADIWKEY */ { vmxHCExitErrUnexpected },
673};
674#endif /* HMVMX_USE_FUNCTION_TABLE */
675
676#if defined(VBOX_STRICT) && defined(LOG_ENABLED)
677static const char * const g_apszVmxInstrErrors[HMVMX_INSTR_ERROR_MAX + 1] =
678{
679 /* 0 */ "(Not Used)",
680 /* 1 */ "VMCALL executed in VMX root operation.",
681 /* 2 */ "VMCLEAR with invalid physical address.",
682 /* 3 */ "VMCLEAR with VMXON pointer.",
683 /* 4 */ "VMLAUNCH with non-clear VMCS.",
684 /* 5 */ "VMRESUME with non-launched VMCS.",
685 /* 6 */ "VMRESUME after VMXOFF",
686 /* 7 */ "VM-entry with invalid control fields.",
687 /* 8 */ "VM-entry with invalid host state fields.",
688 /* 9 */ "VMPTRLD with invalid physical address.",
689 /* 10 */ "VMPTRLD with VMXON pointer.",
690 /* 11 */ "VMPTRLD with incorrect revision identifier.",
691 /* 12 */ "VMREAD/VMWRITE from/to unsupported VMCS component.",
692 /* 13 */ "VMWRITE to read-only VMCS component.",
693 /* 14 */ "(Not Used)",
694 /* 15 */ "VMXON executed in VMX root operation.",
695 /* 16 */ "VM-entry with invalid executive-VMCS pointer.",
696 /* 17 */ "VM-entry with non-launched executing VMCS.",
697 /* 18 */ "VM-entry with executive-VMCS pointer not VMXON pointer.",
698 /* 19 */ "VMCALL with non-clear VMCS.",
699 /* 20 */ "VMCALL with invalid VM-exit control fields.",
700 /* 21 */ "(Not Used)",
701 /* 22 */ "VMCALL with incorrect MSEG revision identifier.",
702 /* 23 */ "VMXOFF under dual monitor treatment of SMIs and SMM.",
703 /* 24 */ "VMCALL with invalid SMM-monitor features.",
704 /* 25 */ "VM-entry with invalid VM-execution control fields in executive VMCS.",
705 /* 26 */ "VM-entry with events blocked by MOV SS.",
706 /* 27 */ "(Not Used)",
707 /* 28 */ "Invalid operand to INVEPT/INVVPID."
708};
709#endif /* VBOX_STRICT && LOG_ENABLED */
710
711
712/**
713 * Gets the CR0 guest/host mask.
714 *
715 * These bits typically does not change through the lifetime of a VM. Any bit set in
716 * this mask is owned by the host/hypervisor and would cause a VM-exit when modified
717 * by the guest.
718 *
719 * @returns The CR0 guest/host mask.
720 * @param pVCpu The cross context virtual CPU structure.
721 */
722static uint64_t vmxHCGetFixedCr0Mask(PCVMCPUCC pVCpu)
723{
724 /*
725 * Modifications to CR0 bits that VT-x ignores saving/restoring (CD, ET, NW) and
726 * to CR0 bits that we require for shadow paging (PG) by the guest must cause VM-exits.
727 *
728 * Furthermore, modifications to any bits that are reserved/unspecified currently
729 * by the Intel spec. must also cause a VM-exit. This prevents unpredictable behavior
730 * when future CPUs specify and use currently reserved/unspecified bits.
731 */
732 /** @todo Avoid intercepting CR0.PE with unrestricted guest execution. Fix PGM
733 * enmGuestMode to be in-sync with the current mode. See @bugref{6398}
734 * and @bugref{6944}. */
735 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
736 AssertCompile(RT_HI_U32(VMX_EXIT_HOST_CR0_IGNORE_MASK) == UINT32_C(0xffffffff)); /* Paranoia. */
737 return ( X86_CR0_PE
738 | X86_CR0_NE
739 | (VM_IS_VMX_NESTED_PAGING(pVM) ? 0 : X86_CR0_WP)
740 | X86_CR0_PG
741 | VMX_EXIT_HOST_CR0_IGNORE_MASK);
742}
743
744
745/**
746 * Gets the CR4 guest/host mask.
747 *
748 * These bits typically does not change through the lifetime of a VM. Any bit set in
749 * this mask is owned by the host/hypervisor and would cause a VM-exit when modified
750 * by the guest.
751 *
752 * @returns The CR4 guest/host mask.
753 * @param pVCpu The cross context virtual CPU structure.
754 */
755static uint64_t vmxHCGetFixedCr4Mask(PCVMCPUCC pVCpu)
756{
757 /*
758 * We construct a mask of all CR4 bits that the guest can modify without causing
759 * a VM-exit. Then invert this mask to obtain all CR4 bits that should cause
760 * a VM-exit when the guest attempts to modify them when executing using
761 * hardware-assisted VMX.
762 *
763 * When a feature is not exposed to the guest (and may be present on the host),
764 * we want to intercept guest modifications to the bit so we can emulate proper
765 * behavior (e.g., #GP).
766 *
767 * Furthermore, only modifications to those bits that don't require immediate
768 * emulation is allowed. For e.g., PCIDE is excluded because the behavior
769 * depends on CR3 which might not always be the guest value while executing
770 * using hardware-assisted VMX.
771 */
772 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
773 bool fFsGsBase = pVM->cpum.ro.GuestFeatures.fFsGsBase;
774#ifdef IN_NEM_DARWIN
775 bool fXSaveRstor = pVM->cpum.ro.GuestFeatures.fXSaveRstor;
776#endif
777 bool fFxSaveRstor = pVM->cpum.ro.GuestFeatures.fFxSaveRstor;
778
779 /*
780 * Paranoia.
781 * Ensure features exposed to the guest are present on the host.
782 */
783 AssertStmt(!fFsGsBase || g_CpumHostFeatures.s.fFsGsBase, fFsGsBase = 0);
784#ifdef IN_NEM_DARWIN
785 AssertStmt(!fXSaveRstor || g_CpumHostFeatures.s.fXSaveRstor, fXSaveRstor = 0);
786#endif
787 AssertStmt(!fFxSaveRstor || g_CpumHostFeatures.s.fFxSaveRstor, fFxSaveRstor = 0);
788
789 uint64_t const fGstMask = X86_CR4_PVI
790 | X86_CR4_TSD
791 | X86_CR4_DE
792 | X86_CR4_MCE
793 | X86_CR4_PCE
794 | X86_CR4_OSXMMEEXCPT
795 | (fFsGsBase ? X86_CR4_FSGSBASE : 0)
796#ifdef IN_NEM_DARWIN /* On native VT-x setting OSXSAVE must exit as we need to load guest XCR0 (see
797 fLoadSaveGuestXcr0). These exits are not needed on Darwin as that's not our problem. */
798 | (fXSaveRstor ? X86_CR4_OSXSAVE : 0)
799#endif
800 | (fFxSaveRstor ? X86_CR4_OSFXSR : 0);
801 return ~fGstMask;
802}
803
804
805/**
806 * Adds one or more exceptions to the exception bitmap and commits it to the current
807 * VMCS.
808 *
809 * @param pVCpu The cross context virtual CPU structure.
810 * @param pVmxTransient The VMX-transient structure.
811 * @param uXcptMask The exception(s) to add.
812 */
813static void vmxHCAddXcptInterceptMask(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
814{
815 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
816 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
817 if ((uXcptBitmap & uXcptMask) != uXcptMask)
818 {
819 uXcptBitmap |= uXcptMask;
820 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
821 AssertRC(rc);
822 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
823 }
824}
825
826
827/**
828 * Adds an exception to the exception bitmap and commits it to the current VMCS.
829 *
830 * @param pVCpu The cross context virtual CPU structure.
831 * @param pVmxTransient The VMX-transient structure.
832 * @param uXcpt The exception to add.
833 */
834static void vmxHCAddXcptIntercept(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
835{
836 Assert(uXcpt <= X86_XCPT_LAST);
837 vmxHCAddXcptInterceptMask(pVCpu, pVmxTransient, RT_BIT_32(uXcpt));
838}
839
840
841/**
842 * Remove one or more exceptions from the exception bitmap and commits it to the
843 * current VMCS.
844 *
845 * This takes care of not removing the exception intercept if a nested-guest
846 * requires the exception to be intercepted.
847 *
848 * @returns VBox status code.
849 * @param pVCpu The cross context virtual CPU structure.
850 * @param pVmxTransient The VMX-transient structure.
851 * @param uXcptMask The exception(s) to remove.
852 */
853static int vmxHCRemoveXcptInterceptMask(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
854{
855 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
856 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
857 if (uXcptBitmap & uXcptMask)
858 {
859#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
860 if (!pVmxTransient->fIsNestedGuest)
861 { /* likely */ }
862 else
863 uXcptMask &= ~pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32XcptBitmap;
864#endif
865#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
866 uXcptMask &= ~( RT_BIT(X86_XCPT_BP)
867 | RT_BIT(X86_XCPT_DE)
868 | RT_BIT(X86_XCPT_NM)
869 | RT_BIT(X86_XCPT_TS)
870 | RT_BIT(X86_XCPT_UD)
871 | RT_BIT(X86_XCPT_NP)
872 | RT_BIT(X86_XCPT_SS)
873 | RT_BIT(X86_XCPT_GP)
874 | RT_BIT(X86_XCPT_PF)
875 | RT_BIT(X86_XCPT_MF));
876#elif defined(HMVMX_ALWAYS_TRAP_PF)
877 uXcptMask &= ~RT_BIT(X86_XCPT_PF);
878#endif
879 if (uXcptMask)
880 {
881 /* Validate we are not removing any essential exception intercepts. */
882#ifndef IN_NEM_DARWIN
883 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging || !(uXcptMask & RT_BIT(X86_XCPT_PF)));
884#else
885 Assert(!(uXcptMask & RT_BIT(X86_XCPT_PF)));
886#endif
887 NOREF(pVCpu);
888 Assert(!(uXcptMask & RT_BIT(X86_XCPT_DB)));
889 Assert(!(uXcptMask & RT_BIT(X86_XCPT_AC)));
890
891 /* Remove it from the exception bitmap. */
892 uXcptBitmap &= ~uXcptMask;
893
894 /* Commit and update the cache if necessary. */
895 if (pVmcsInfo->u32XcptBitmap != uXcptBitmap)
896 {
897 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
898 AssertRC(rc);
899 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
900 }
901 }
902 }
903 return VINF_SUCCESS;
904}
905
906
907/**
908 * Remove an exceptions from the exception bitmap and commits it to the current
909 * VMCS.
910 *
911 * @returns VBox status code.
912 * @param pVCpu The cross context virtual CPU structure.
913 * @param pVmxTransient The VMX-transient structure.
914 * @param uXcpt The exception to remove.
915 */
916static int vmxHCRemoveXcptIntercept(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
917{
918 return vmxHCRemoveXcptInterceptMask(pVCpu, pVmxTransient, RT_BIT(uXcpt));
919}
920
921#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
922
923/**
924 * Loads the shadow VMCS specified by the VMCS info. object.
925 *
926 * @returns VBox status code.
927 * @param pVmcsInfo The VMCS info. object.
928 *
929 * @remarks Can be called with interrupts disabled.
930 */
931static int vmxHCLoadShadowVmcs(PVMXVMCSINFO pVmcsInfo)
932{
933 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
934 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
935
936 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysShadowVmcs);
937 if (RT_SUCCESS(rc))
938 pVmcsInfo->fShadowVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
939 return rc;
940}
941
942
943/**
944 * Clears the shadow VMCS specified by the VMCS info. object.
945 *
946 * @returns VBox status code.
947 * @param pVmcsInfo The VMCS info. object.
948 *
949 * @remarks Can be called with interrupts disabled.
950 */
951static int vmxHCClearShadowVmcs(PVMXVMCSINFO pVmcsInfo)
952{
953 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
954 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
955
956 int rc = VMXClearVmcs(pVmcsInfo->HCPhysShadowVmcs);
957 if (RT_SUCCESS(rc))
958 pVmcsInfo->fShadowVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
959 return rc;
960}
961
962
963/**
964 * Switches from and to the specified VMCSes.
965 *
966 * @returns VBox status code.
967 * @param pVmcsInfoFrom The VMCS info. object we are switching from.
968 * @param pVmcsInfoTo The VMCS info. object we are switching to.
969 *
970 * @remarks Called with interrupts disabled.
971 */
972static int vmxHCSwitchVmcs(PVMXVMCSINFO pVmcsInfoFrom, PVMXVMCSINFO pVmcsInfoTo)
973{
974 /*
975 * Clear the VMCS we are switching out if it has not already been cleared.
976 * This will sync any CPU internal data back to the VMCS.
977 */
978 if (pVmcsInfoFrom->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
979 {
980 int rc = hmR0VmxClearVmcs(pVmcsInfoFrom);
981 if (RT_SUCCESS(rc))
982 {
983 /*
984 * The shadow VMCS, if any, would not be active at this point since we
985 * would have cleared it while importing the virtual hardware-virtualization
986 * state as part the VMLAUNCH/VMRESUME VM-exit. Hence, there's no need to
987 * clear the shadow VMCS here, just assert for safety.
988 */
989 Assert(!pVmcsInfoFrom->pvShadowVmcs || pVmcsInfoFrom->fShadowVmcsState == VMX_V_VMCS_LAUNCH_STATE_CLEAR);
990 }
991 else
992 return rc;
993 }
994
995 /*
996 * Clear the VMCS we are switching to if it has not already been cleared.
997 * This will initialize the VMCS launch state to "clear" required for loading it.
998 *
999 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
1000 */
1001 if (pVmcsInfoTo->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1002 {
1003 int rc = hmR0VmxClearVmcs(pVmcsInfoTo);
1004 if (RT_SUCCESS(rc))
1005 { /* likely */ }
1006 else
1007 return rc;
1008 }
1009
1010 /*
1011 * Finally, load the VMCS we are switching to.
1012 */
1013 return hmR0VmxLoadVmcs(pVmcsInfoTo);
1014}
1015
1016
1017/**
1018 * Switches between the guest VMCS and the nested-guest VMCS as specified by the
1019 * caller.
1020 *
1021 * @returns VBox status code.
1022 * @param pVCpu The cross context virtual CPU structure.
1023 * @param fSwitchToNstGstVmcs Whether to switch to the nested-guest VMCS (pass
1024 * true) or guest VMCS (pass false).
1025 */
1026static int vmxHCSwitchToGstOrNstGstVmcs(PVMCPUCC pVCpu, bool fSwitchToNstGstVmcs)
1027{
1028 /* Ensure we have synced everything from the guest-CPU context to the VMCS before switching. */
1029 HMVMX_CPUMCTX_ASSERT(pVCpu, HMVMX_CPUMCTX_EXTRN_ALL);
1030
1031 PVMXVMCSINFO pVmcsInfoFrom;
1032 PVMXVMCSINFO pVmcsInfoTo;
1033 if (fSwitchToNstGstVmcs)
1034 {
1035 pVmcsInfoFrom = &pVCpu->hmr0.s.vmx.VmcsInfo;
1036 pVmcsInfoTo = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1037 }
1038 else
1039 {
1040 pVmcsInfoFrom = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1041 pVmcsInfoTo = &pVCpu->hmr0.s.vmx.VmcsInfo;
1042 }
1043
1044 /*
1045 * Disable interrupts to prevent being preempted while we switch the current VMCS as the
1046 * preemption hook code path acquires the current VMCS.
1047 */
1048 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1049
1050 int rc = vmxHCSwitchVmcs(pVmcsInfoFrom, pVmcsInfoTo);
1051 if (RT_SUCCESS(rc))
1052 {
1053 pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs = fSwitchToNstGstVmcs;
1054 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcsCopyForRing3 = fSwitchToNstGstVmcs;
1055
1056 /*
1057 * If we are switching to a VMCS that was executed on a different host CPU or was
1058 * never executed before, flag that we need to export the host state before executing
1059 * guest/nested-guest code using hardware-assisted VMX.
1060 *
1061 * This could probably be done in a preemptible context since the preemption hook
1062 * will flag the necessary change in host context. However, since preemption is
1063 * already disabled and to avoid making assumptions about host specific code in
1064 * RTMpCpuId when called with preemption enabled, we'll do this while preemption is
1065 * disabled.
1066 */
1067 if (pVmcsInfoTo->idHostCpuState == RTMpCpuId())
1068 { /* likely */ }
1069 else
1070 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE);
1071
1072 ASMSetFlags(fEFlags);
1073
1074 /*
1075 * We use a different VM-exit MSR-store areas for the guest and nested-guest. Hence,
1076 * flag that we need to update the host MSR values there. Even if we decide in the
1077 * future to share the VM-exit MSR-store area page between the guest and nested-guest,
1078 * if its content differs, we would have to update the host MSRs anyway.
1079 */
1080 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
1081 }
1082 else
1083 ASMSetFlags(fEFlags);
1084 return rc;
1085}
1086
1087#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
1088#ifdef VBOX_STRICT
1089
1090/**
1091 * Reads the VM-entry interruption-information field from the VMCS into the VMX
1092 * transient structure.
1093 *
1094 * @param pVCpu The cross context virtual CPU structure.
1095 * @param pVmxTransient The VMX-transient structure.
1096 */
1097DECLINLINE(void) vmxHCReadEntryIntInfoVmcs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
1098{
1099 int rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntInfo);
1100 AssertRC(rc);
1101}
1102
1103
1104/**
1105 * Reads the VM-entry exception error code field from the VMCS into
1106 * the VMX transient structure.
1107 *
1108 * @param pVCpu The cross context virtual CPU structure.
1109 * @param pVmxTransient The VMX-transient structure.
1110 */
1111DECLINLINE(void) vmxHCReadEntryXcptErrorCodeVmcs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
1112{
1113 int rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
1114 AssertRC(rc);
1115}
1116
1117
1118/**
1119 * Reads the VM-entry exception error code field from the VMCS into
1120 * the VMX transient structure.
1121 *
1122 * @param pVCpu The cross context virtual CPU structure.
1123 * @param pVmxTransient The VMX-transient structure.
1124 */
1125DECLINLINE(void) vmxHCReadEntryInstrLenVmcs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
1126{
1127 int rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
1128 AssertRC(rc);
1129}
1130
1131#endif /* VBOX_STRICT */
1132
1133
1134/**
1135 * Reads VMCS fields into the VMXTRANSIENT structure, slow path version.
1136 *
1137 * Don't call directly unless the it's likely that some or all of the fields
1138 * given in @a a_fReadMask have already been read.
1139 *
1140 * @tparam a_fReadMask The fields to read.
1141 * @param pVCpu The cross context virtual CPU structure.
1142 * @param pVmxTransient The VMX-transient structure.
1143 */
1144template<uint32_t const a_fReadMask>
1145static void vmxHCReadToTransientSlow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
1146{
1147 AssertCompile((a_fReadMask & ~( HMVMX_READ_EXIT_QUALIFICATION
1148 | HMVMX_READ_EXIT_INSTR_LEN
1149 | HMVMX_READ_EXIT_INSTR_INFO
1150 | HMVMX_READ_IDT_VECTORING_INFO
1151 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
1152 | HMVMX_READ_EXIT_INTERRUPTION_INFO
1153 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
1154 | HMVMX_READ_GUEST_LINEAR_ADDR
1155 | HMVMX_READ_GUEST_PHYSICAL_ADDR
1156 | HMVMX_READ_GUEST_PENDING_DBG_XCPTS
1157 )) == 0);
1158
1159 if ((pVmxTransient->fVmcsFieldsRead & a_fReadMask) != a_fReadMask)
1160 {
1161 uint32_t const fVmcsFieldsRead = pVmxTransient->fVmcsFieldsRead;
1162
1163 if ( (a_fReadMask & HMVMX_READ_EXIT_QUALIFICATION)
1164 && !(fVmcsFieldsRead & HMVMX_READ_EXIT_QUALIFICATION))
1165 {
1166 int const rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1167 AssertRC(rc);
1168 }
1169 if ( (a_fReadMask & HMVMX_READ_EXIT_INSTR_LEN)
1170 && !(fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_LEN))
1171 {
1172 int const rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1173 AssertRC(rc);
1174 }
1175 if ( (a_fReadMask & HMVMX_READ_EXIT_INSTR_INFO)
1176 && !(fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_INFO))
1177 {
1178 int const rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1179 AssertRC(rc);
1180 }
1181 if ( (a_fReadMask & HMVMX_READ_IDT_VECTORING_INFO)
1182 && !(fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_INFO))
1183 {
1184 int const rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1185 AssertRC(rc);
1186 }
1187 if ( (a_fReadMask & HMVMX_READ_IDT_VECTORING_ERROR_CODE)
1188 && !(fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_ERROR_CODE))
1189 {
1190 int const rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1191 AssertRC(rc);
1192 }
1193 if ( (a_fReadMask & HMVMX_READ_EXIT_INTERRUPTION_INFO)
1194 && !(fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_INFO))
1195 {
1196 int const rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1197 AssertRC(rc);
1198 }
1199 if ( (a_fReadMask & HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE)
1200 && !(fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE))
1201 {
1202 int const rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1203 AssertRC(rc);
1204 }
1205 if ( (a_fReadMask & HMVMX_READ_GUEST_LINEAR_ADDR)
1206 && !(fVmcsFieldsRead & HMVMX_READ_GUEST_LINEAR_ADDR))
1207 {
1208 int const rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1209 AssertRC(rc);
1210 }
1211 if ( (a_fReadMask & HMVMX_READ_GUEST_PHYSICAL_ADDR)
1212 && !(fVmcsFieldsRead & HMVMX_READ_GUEST_PHYSICAL_ADDR))
1213 {
1214 int const rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1215 AssertRC(rc);
1216 }
1217 if ( (a_fReadMask & HMVMX_READ_GUEST_PENDING_DBG_XCPTS)
1218 && !(fVmcsFieldsRead & HMVMX_READ_GUEST_PENDING_DBG_XCPTS))
1219 {
1220 int const rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &pVmxTransient->uGuestPendingDbgXcpts);
1221 AssertRC(rc);
1222 }
1223
1224 pVmxTransient->fVmcsFieldsRead |= a_fReadMask;
1225 }
1226}
1227
1228
1229/**
1230 * Reads VMCS fields into the VMXTRANSIENT structure.
1231 *
1232 * This optimizes for the case where none of @a a_fReadMask has been read yet,
1233 * generating an optimized read sequences w/o any conditionals between in
1234 * non-strict builds.
1235 *
1236 * @tparam a_fReadMask The fields to read. One or more of the
1237 * HMVMX_READ_XXX fields ORed together.
1238 * @param pVCpu The cross context virtual CPU structure.
1239 * @param pVmxTransient The VMX-transient structure.
1240 */
1241template<uint32_t const a_fReadMask>
1242DECLINLINE(void) vmxHCReadToTransient(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
1243{
1244 AssertCompile((a_fReadMask & ~( HMVMX_READ_EXIT_QUALIFICATION
1245 | HMVMX_READ_EXIT_INSTR_LEN
1246 | HMVMX_READ_EXIT_INSTR_INFO
1247 | HMVMX_READ_IDT_VECTORING_INFO
1248 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
1249 | HMVMX_READ_EXIT_INTERRUPTION_INFO
1250 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
1251 | HMVMX_READ_GUEST_LINEAR_ADDR
1252 | HMVMX_READ_GUEST_PHYSICAL_ADDR
1253 | HMVMX_READ_GUEST_PENDING_DBG_XCPTS
1254 )) == 0);
1255
1256 if (RT_LIKELY(!(pVmxTransient->fVmcsFieldsRead & a_fReadMask)))
1257 {
1258 if (a_fReadMask & HMVMX_READ_EXIT_QUALIFICATION)
1259 {
1260 int const rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1261 AssertRC(rc);
1262 }
1263 if (a_fReadMask & HMVMX_READ_EXIT_INSTR_LEN)
1264 {
1265 int const rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1266 AssertRC(rc);
1267 }
1268 if (a_fReadMask & HMVMX_READ_EXIT_INSTR_INFO)
1269 {
1270 int const rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1271 AssertRC(rc);
1272 }
1273 if (a_fReadMask & HMVMX_READ_IDT_VECTORING_INFO)
1274 {
1275 int const rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1276 AssertRC(rc);
1277 }
1278 if (a_fReadMask & HMVMX_READ_IDT_VECTORING_ERROR_CODE)
1279 {
1280 int const rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1281 AssertRC(rc);
1282 }
1283 if (a_fReadMask & HMVMX_READ_EXIT_INTERRUPTION_INFO)
1284 {
1285 int const rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1286 AssertRC(rc);
1287 }
1288 if (a_fReadMask & HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE)
1289 {
1290 int const rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1291 AssertRC(rc);
1292 }
1293 if (a_fReadMask & HMVMX_READ_GUEST_LINEAR_ADDR)
1294 {
1295 int const rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1296 AssertRC(rc);
1297 }
1298 if (a_fReadMask & HMVMX_READ_GUEST_PHYSICAL_ADDR)
1299 {
1300 int const rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1301 AssertRC(rc);
1302 }
1303 if (a_fReadMask & HMVMX_READ_GUEST_PENDING_DBG_XCPTS)
1304 {
1305 int const rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &pVmxTransient->uGuestPendingDbgXcpts);
1306 AssertRC(rc);
1307 }
1308
1309 pVmxTransient->fVmcsFieldsRead |= a_fReadMask;
1310 }
1311 else
1312 {
1313 STAM_REL_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatReadToTransientFallback);
1314 Log11Func(("a_fReadMask=%#x fVmcsFieldsRead=%#x => %#x - Taking inefficient code path!\n",
1315 a_fReadMask, pVmxTransient->fVmcsFieldsRead, a_fReadMask & pVmxTransient->fVmcsFieldsRead));
1316 vmxHCReadToTransientSlow<a_fReadMask>(pVCpu, pVmxTransient);
1317 }
1318}
1319
1320
1321#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
1322/**
1323 * Reads all relevant read-only VMCS fields into the VMX transient structure.
1324 *
1325 * @param pVCpu The cross context virtual CPU structure.
1326 * @param pVmxTransient The VMX-transient structure.
1327 */
1328static void vmxHCReadAllRoFieldsVmcs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
1329{
1330 int rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1331 rc |= VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1332 rc |= VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1333 rc |= VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1334 rc |= VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1335 rc |= VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1336 rc |= VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1337 rc |= VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1338 rc |= VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1339 AssertRC(rc);
1340 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION
1341 | HMVMX_READ_EXIT_INSTR_LEN
1342 | HMVMX_READ_EXIT_INSTR_INFO
1343 | HMVMX_READ_IDT_VECTORING_INFO
1344 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
1345 | HMVMX_READ_EXIT_INTERRUPTION_INFO
1346 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
1347 | HMVMX_READ_GUEST_LINEAR_ADDR
1348 | HMVMX_READ_GUEST_PHYSICAL_ADDR;
1349}
1350#endif
1351
1352/**
1353 * Verifies that our cached values of the VMCS fields are all consistent with
1354 * what's actually present in the VMCS.
1355 *
1356 * @returns VBox status code.
1357 * @retval VINF_SUCCESS if all our caches match their respective VMCS fields.
1358 * @retval VERR_VMX_VMCS_FIELD_CACHE_INVALID if a cache field doesn't match the
1359 * VMCS content. HMCPU error-field is
1360 * updated, see VMX_VCI_XXX.
1361 * @param pVCpu The cross context virtual CPU structure.
1362 * @param pVmcsInfo The VMCS info. object.
1363 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
1364 */
1365static int vmxHCCheckCachedVmcsCtls(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
1366{
1367 const char * const pcszVmcs = fIsNstGstVmcs ? "Nested-guest VMCS" : "VMCS";
1368
1369 uint32_t u32Val;
1370 int rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_CTRL_ENTRY, &u32Val);
1371 AssertRC(rc);
1372 AssertMsgReturnStmt(pVmcsInfo->u32EntryCtls == u32Val,
1373 ("%s entry controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32EntryCtls, u32Val),
1374 VCPU_2_VMXSTATE(pVCpu).u32HMError = VMX_VCI_CTRL_ENTRY,
1375 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
1376
1377 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_CTRL_EXIT, &u32Val);
1378 AssertRC(rc);
1379 AssertMsgReturnStmt(pVmcsInfo->u32ExitCtls == u32Val,
1380 ("%s exit controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ExitCtls, u32Val),
1381 VCPU_2_VMXSTATE(pVCpu).u32HMError = VMX_VCI_CTRL_EXIT,
1382 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
1383
1384 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_CTRL_PIN_EXEC, &u32Val);
1385 AssertRC(rc);
1386 AssertMsgReturnStmt(pVmcsInfo->u32PinCtls == u32Val,
1387 ("%s pin controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32PinCtls, u32Val),
1388 VCPU_2_VMXSTATE(pVCpu).u32HMError = VMX_VCI_CTRL_PIN_EXEC,
1389 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
1390
1391 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, &u32Val);
1392 AssertRC(rc);
1393 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls == u32Val,
1394 ("%s proc controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls, u32Val),
1395 VCPU_2_VMXSTATE(pVCpu).u32HMError = VMX_VCI_CTRL_PROC_EXEC,
1396 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
1397
1398 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
1399 {
1400 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val);
1401 AssertRC(rc);
1402 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls2 == u32Val,
1403 ("%s proc2 controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls2, u32Val),
1404 VCPU_2_VMXSTATE(pVCpu).u32HMError = VMX_VCI_CTRL_PROC_EXEC2,
1405 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
1406 }
1407
1408 uint64_t u64Val;
1409 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TERTIARY_CTLS)
1410 {
1411 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_CTRL_PROC_EXEC3_FULL, &u64Val);
1412 AssertRC(rc);
1413 AssertMsgReturnStmt(pVmcsInfo->u64ProcCtls3 == u64Val,
1414 ("%s proc3 controls mismatch: Cache=%#RX32 VMCS=%#RX64\n", pcszVmcs, pVmcsInfo->u64ProcCtls3, u64Val),
1415 VCPU_2_VMXSTATE(pVCpu).u32HMError = VMX_VCI_CTRL_PROC_EXEC3,
1416 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
1417 }
1418
1419 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val);
1420 AssertRC(rc);
1421 AssertMsgReturnStmt(pVmcsInfo->u32XcptBitmap == u32Val,
1422 ("%s exception bitmap mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32XcptBitmap, u32Val),
1423 VCPU_2_VMXSTATE(pVCpu).u32HMError = VMX_VCI_CTRL_XCPT_BITMAP,
1424 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
1425
1426 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_CTRL_TSC_OFFSET_FULL, &u64Val);
1427 AssertRC(rc);
1428 AssertMsgReturnStmt(pVmcsInfo->u64TscOffset == u64Val,
1429 ("%s TSC offset mismatch: Cache=%#RX64 VMCS=%#RX64\n", pcszVmcs, pVmcsInfo->u64TscOffset, u64Val),
1430 VCPU_2_VMXSTATE(pVCpu).u32HMError = VMX_VCI_CTRL_TSC_OFFSET,
1431 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
1432
1433 NOREF(pcszVmcs);
1434 return VINF_SUCCESS;
1435}
1436
1437
1438/**
1439 * Exports the guest state with appropriate VM-entry and VM-exit controls in the
1440 * VMCS.
1441 *
1442 * This is typically required when the guest changes paging mode.
1443 *
1444 * @returns VBox status code.
1445 * @param pVCpu The cross context virtual CPU structure.
1446 * @param pVmxTransient The VMX-transient structure.
1447 *
1448 * @remarks Requires EFER.
1449 * @remarks No-long-jump zone!!!
1450 */
1451static int vmxHCExportGuestEntryExitCtls(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
1452{
1453 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS)
1454 {
1455 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
1456 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1457
1458 /*
1459 * VM-entry controls.
1460 */
1461 {
1462 uint32_t fVal = g_HmMsrs.u.vmx.EntryCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
1463 uint32_t const fZap = g_HmMsrs.u.vmx.EntryCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
1464
1465 /*
1466 * Load the guest debug controls (DR7 and IA32_DEBUGCTL MSR) on VM-entry.
1467 * The first VT-x capable CPUs only supported the 1-setting of this bit.
1468 *
1469 * For nested-guests, this is a mandatory VM-entry control. It's also
1470 * required because we do not want to leak host bits to the nested-guest.
1471 */
1472 fVal |= VMX_ENTRY_CTLS_LOAD_DEBUG;
1473
1474 /*
1475 * Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry.
1476 *
1477 * For nested-guests, the "IA-32e mode guest" control we initialize with what is
1478 * required to get the nested-guest working with hardware-assisted VMX execution.
1479 * It depends on the nested-guest's IA32_EFER.LMA bit. Remember, a nested hypervisor
1480 * can skip intercepting changes to the EFER MSR. This is why it needs to be done
1481 * here rather than while merging the guest VMCS controls.
1482 */
1483 if (CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
1484 {
1485 Assert(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LME);
1486 fVal |= VMX_ENTRY_CTLS_IA32E_MODE_GUEST;
1487 }
1488 else
1489 Assert(!(fVal & VMX_ENTRY_CTLS_IA32E_MODE_GUEST));
1490
1491 /*
1492 * If the CPU supports the newer VMCS controls for managing guest/host EFER, use it.
1493 *
1494 * For nested-guests, we use the "load IA32_EFER" if the hardware supports it,
1495 * regardless of whether the nested-guest VMCS specifies it because we are free to
1496 * load whatever MSRs we require and we do not need to modify the guest visible copy
1497 * of the VM-entry MSR load area.
1498 */
1499 if ( g_fHmVmxSupportsVmcsEfer
1500#ifndef IN_NEM_DARWIN
1501 && hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient)
1502#endif
1503 )
1504 fVal |= VMX_ENTRY_CTLS_LOAD_EFER_MSR;
1505 else
1506 Assert(!(fVal & VMX_ENTRY_CTLS_LOAD_EFER_MSR));
1507
1508 /*
1509 * The following should -not- be set (since we're not in SMM mode):
1510 * - VMX_ENTRY_CTLS_ENTRY_TO_SMM
1511 * - VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON
1512 */
1513
1514 /** @todo VMX_ENTRY_CTLS_LOAD_PERF_MSR,
1515 * VMX_ENTRY_CTLS_LOAD_PAT_MSR. */
1516
1517 if ((fVal & fZap) == fVal)
1518 { /* likely */ }
1519 else
1520 {
1521 Log4Func(("Invalid VM-entry controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
1522 g_HmMsrs.u.vmx.EntryCtls.n.allowed0, fVal, fZap));
1523 VCPU_2_VMXSTATE(pVCpu).u32HMError = VMX_UFC_CTRL_ENTRY;
1524 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1525 }
1526
1527 /* Commit it to the VMCS. */
1528 if (pVmcsInfo->u32EntryCtls != fVal)
1529 {
1530 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_ENTRY, fVal);
1531 AssertRC(rc);
1532 pVmcsInfo->u32EntryCtls = fVal;
1533 }
1534 }
1535
1536 /*
1537 * VM-exit controls.
1538 */
1539 {
1540 uint32_t fVal = g_HmMsrs.u.vmx.ExitCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
1541 uint32_t const fZap = g_HmMsrs.u.vmx.ExitCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
1542
1543 /*
1544 * Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only
1545 * supported the 1-setting of this bit.
1546 *
1547 * For nested-guests, we set the "save debug controls" as the converse
1548 * "load debug controls" is mandatory for nested-guests anyway.
1549 */
1550 fVal |= VMX_EXIT_CTLS_SAVE_DEBUG;
1551
1552 /*
1553 * Set the host long mode active (EFER.LMA) bit (which Intel calls
1554 * "Host address-space size") if necessary. On VM-exit, VT-x sets both the
1555 * host EFER.LMA and EFER.LME bit to this value. See assertion in
1556 * vmxHCExportHostMsrs().
1557 *
1558 * For nested-guests, we always set this bit as we do not support 32-bit
1559 * hosts.
1560 */
1561 fVal |= VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE;
1562
1563#ifndef IN_NEM_DARWIN
1564 /*
1565 * If the VMCS EFER MSR fields are supported by the hardware, we use it.
1566 *
1567 * For nested-guests, we should use the "save IA32_EFER" control if we also
1568 * used the "load IA32_EFER" control while exporting VM-entry controls.
1569 */
1570 if ( g_fHmVmxSupportsVmcsEfer
1571 && hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
1572 {
1573 fVal |= VMX_EXIT_CTLS_SAVE_EFER_MSR
1574 | VMX_EXIT_CTLS_LOAD_EFER_MSR;
1575 }
1576#endif
1577
1578 /*
1579 * Enable saving of the VMX-preemption timer value on VM-exit.
1580 * For nested-guests, currently not exposed/used.
1581 */
1582 /** @todo r=bird: Measure performance hit because of this vs. always rewriting
1583 * the timer value. */
1584 if (VM_IS_VMX_PREEMPT_TIMER_USED(pVM))
1585 {
1586 Assert(g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER);
1587 fVal |= VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER;
1588 }
1589
1590 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
1591 Assert(!(fVal & VMX_EXIT_CTLS_ACK_EXT_INT));
1592
1593 /** @todo VMX_EXIT_CTLS_LOAD_PERF_MSR,
1594 * VMX_EXIT_CTLS_SAVE_PAT_MSR,
1595 * VMX_EXIT_CTLS_LOAD_PAT_MSR. */
1596
1597 if ((fVal & fZap) == fVal)
1598 { /* likely */ }
1599 else
1600 {
1601 Log4Func(("Invalid VM-exit controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
1602 g_HmMsrs.u.vmx.ExitCtls.n.allowed0, fVal, fZap));
1603 VCPU_2_VMXSTATE(pVCpu).u32HMError = VMX_UFC_CTRL_EXIT;
1604 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1605 }
1606
1607 /* Commit it to the VMCS. */
1608 if (pVmcsInfo->u32ExitCtls != fVal)
1609 {
1610 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_EXIT, fVal);
1611 AssertRC(rc);
1612 pVmcsInfo->u32ExitCtls = fVal;
1613 }
1614 }
1615
1616 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
1617 }
1618 return VINF_SUCCESS;
1619}
1620
1621
1622/**
1623 * Sets the TPR threshold in the VMCS.
1624 *
1625 * @param pVCpu The cross context virtual CPU structure.
1626 * @param pVmcsInfo The VMCS info. object.
1627 * @param u32TprThreshold The TPR threshold (task-priority class only).
1628 */
1629DECLINLINE(void) vmxHCApicSetTprThreshold(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t u32TprThreshold)
1630{
1631 Assert(!(u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)); /* Bits 31:4 MBZ. */
1632 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
1633 RT_NOREF(pVmcsInfo);
1634 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
1635 AssertRC(rc);
1636}
1637
1638
1639/**
1640 * Exports the guest APIC TPR state into the VMCS.
1641 *
1642 * @param pVCpu The cross context virtual CPU structure.
1643 * @param pVmxTransient The VMX-transient structure.
1644 *
1645 * @remarks No-long-jump zone!!!
1646 */
1647static void vmxHCExportGuestApicTpr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
1648{
1649 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_APIC_TPR)
1650 {
1651 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
1652
1653 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1654 if (!pVmxTransient->fIsNestedGuest)
1655 {
1656 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
1657 && APICIsEnabled(pVCpu))
1658 {
1659 /*
1660 * Setup TPR shadowing.
1661 */
1662 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
1663 {
1664 bool fPendingIntr = false;
1665 uint8_t u8Tpr = 0;
1666 uint8_t u8PendingIntr = 0;
1667 int rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
1668 AssertRC(rc);
1669
1670 /*
1671 * If there are interrupts pending but masked by the TPR, instruct VT-x to
1672 * cause a TPR-below-threshold VM-exit when the guest lowers its TPR below the
1673 * priority of the pending interrupt so we can deliver the interrupt. If there
1674 * are no interrupts pending, set threshold to 0 to not cause any
1675 * TPR-below-threshold VM-exits.
1676 */
1677 uint32_t u32TprThreshold = 0;
1678 if (fPendingIntr)
1679 {
1680 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR
1681 (which is the Task-Priority Class). */
1682 const uint8_t u8PendingPriority = u8PendingIntr >> 4;
1683 const uint8_t u8TprPriority = u8Tpr >> 4;
1684 if (u8PendingPriority <= u8TprPriority)
1685 u32TprThreshold = u8PendingPriority;
1686 }
1687
1688 vmxHCApicSetTprThreshold(pVCpu, pVmcsInfo, u32TprThreshold);
1689 }
1690 }
1691 }
1692 /* else: the TPR threshold has already been updated while merging the nested-guest VMCS. */
1693 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
1694 }
1695}
1696
1697
1698/**
1699 * Gets the guest interruptibility-state and updates related internal eflags
1700 * inhibition state.
1701 *
1702 * @returns Guest's interruptibility-state.
1703 * @param pVCpu The cross context virtual CPU structure.
1704 *
1705 * @remarks No-long-jump zone!!!
1706 */
1707static uint32_t vmxHCGetGuestIntrStateWithUpdate(PVMCPUCC pVCpu)
1708{
1709 uint32_t fIntrState;
1710
1711 /*
1712 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
1713 */
1714 if (!CPUMIsInInterruptShadowWithUpdate(&pVCpu->cpum.GstCtx))
1715 fIntrState = 0;
1716 else
1717 {
1718 /* If inhibition is active, RIP should've been imported from the VMCS already. */
1719 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP);
1720
1721 if (CPUMIsInInterruptShadowAfterSs(&pVCpu->cpum.GstCtx))
1722 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS;
1723 else
1724 {
1725 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
1726
1727 /* Block-by-STI must not be set when interrupts are disabled. */
1728 AssertStmt(pVCpu->cpum.GstCtx.eflags.Bits.u1IF, fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
1729 }
1730 }
1731
1732 /*
1733 * Check if we should inhibit NMI delivery.
1734 */
1735 if (!CPUMAreInterruptsInhibitedByNmiEx(&pVCpu->cpum.GstCtx))
1736 { /* likely */ }
1737 else
1738 fIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
1739
1740 /*
1741 * Validate.
1742 */
1743 /* We don't support block-by-SMI yet.*/
1744 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI));
1745
1746 return fIntrState;
1747}
1748
1749
1750/**
1751 * Exports the exception intercepts required for guest execution in the VMCS.
1752 *
1753 * @param pVCpu The cross context virtual CPU structure.
1754 * @param pVmxTransient The VMX-transient structure.
1755 *
1756 * @remarks No-long-jump zone!!!
1757 */
1758static void vmxHCExportGuestXcptIntercepts(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
1759{
1760 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_VMX_XCPT_INTERCEPTS)
1761 {
1762 /* When executing a nested-guest, we do not need to trap GIM hypercalls by intercepting #UD. */
1763 if ( !pVmxTransient->fIsNestedGuest
1764 && VCPU_2_VMXSTATE(pVCpu).fGIMTrapXcptUD)
1765 vmxHCAddXcptIntercept(pVCpu, pVmxTransient, X86_XCPT_UD);
1766 else
1767 vmxHCRemoveXcptIntercept(pVCpu, pVmxTransient, X86_XCPT_UD);
1768
1769 /* Other exception intercepts are handled elsewhere, e.g. while exporting guest CR0. */
1770 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_VMX_XCPT_INTERCEPTS);
1771 }
1772}
1773
1774
1775/**
1776 * Exports the guest's RIP into the guest-state area in the VMCS.
1777 *
1778 * @param pVCpu The cross context virtual CPU structure.
1779 *
1780 * @remarks No-long-jump zone!!!
1781 */
1782static void vmxHCExportGuestRip(PVMCPUCC pVCpu)
1783{
1784 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_RIP)
1785 {
1786 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP);
1787
1788 int rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_RIP, pVCpu->cpum.GstCtx.rip);
1789 AssertRC(rc);
1790
1791 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_RIP);
1792 Log4Func(("rip=%#RX64\n", pVCpu->cpum.GstCtx.rip));
1793 }
1794}
1795
1796
1797/**
1798 * Exports the guest's RFLAGS into the guest-state area in the VMCS.
1799 *
1800 * @param pVCpu The cross context virtual CPU structure.
1801 * @param pVmxTransient The VMX-transient structure.
1802 *
1803 * @remarks No-long-jump zone!!!
1804 */
1805static void vmxHCExportGuestRflags(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
1806{
1807 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_RFLAGS)
1808 {
1809 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
1810
1811 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits
1812 of RFLAGS are reserved (MBZ). We use bits 63:24 for internal purposes, so no need
1813 to assert this, the CPUMX86EFLAGS/CPUMX86RFLAGS union masks these off for us.
1814 Use 32-bit VMWRITE. */
1815 uint32_t fEFlags = pVCpu->cpum.GstCtx.eflags.u;
1816 Assert((fEFlags & X86_EFL_RA1_MASK) == X86_EFL_RA1_MASK);
1817 AssertMsg(!(fEFlags & ~(X86_EFL_LIVE_MASK | X86_EFL_RA1_MASK)), ("%#x\n", fEFlags));
1818
1819#ifndef IN_NEM_DARWIN
1820 /*
1821 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so
1822 * we can restore them on VM-exit. Modify the real-mode guest's eflags so that VT-x
1823 * can run the real-mode guest code under Virtual 8086 mode.
1824 */
1825 PVMXVMCSINFOSHARED pVmcsInfo = pVmxTransient->pVmcsInfo->pShared;
1826 if (pVmcsInfo->RealMode.fRealOnV86Active)
1827 {
1828 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
1829 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
1830 Assert(!pVmxTransient->fIsNestedGuest);
1831 pVmcsInfo->RealMode.Eflags.u32 = fEFlags; /* Save the original eflags of the real-mode guest. */
1832 fEFlags |= X86_EFL_VM; /* Set the Virtual 8086 mode bit. */
1833 fEFlags &= ~X86_EFL_IOPL; /* Change IOPL to 0, otherwise certain instructions won't fault. */
1834 }
1835#else
1836 RT_NOREF(pVmxTransient);
1837#endif
1838
1839 int rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_RFLAGS, fEFlags);
1840 AssertRC(rc);
1841
1842 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_RFLAGS);
1843 Log4Func(("eflags=%#RX32\n", fEFlags));
1844 }
1845}
1846
1847
1848#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1849/**
1850 * Copies the nested-guest VMCS to the shadow VMCS.
1851 *
1852 * @returns VBox status code.
1853 * @param pVCpu The cross context virtual CPU structure.
1854 * @param pVmcsInfo The VMCS info. object.
1855 *
1856 * @remarks No-long-jump zone!!!
1857 */
1858static int vmxHCCopyNstGstToShadowVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
1859{
1860 PVMCC const pVM = pVCpu->CTX_SUFF(pVM);
1861 PCVMXVVMCS const pVmcsNstGst = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
1862
1863 /*
1864 * Disable interrupts so we don't get preempted while the shadow VMCS is the
1865 * current VMCS, as we may try saving guest lazy MSRs.
1866 *
1867 * Strictly speaking the lazy MSRs are not in the VMCS, but I'd rather not risk
1868 * calling the import VMCS code which is currently performing the guest MSR reads
1869 * (on 64-bit hosts) and accessing the auto-load/store MSR area on 32-bit hosts
1870 * and the rest of the VMX leave session machinery.
1871 */
1872 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1873
1874 int rc = vmxHCLoadShadowVmcs(pVmcsInfo);
1875 if (RT_SUCCESS(rc))
1876 {
1877 /*
1878 * Copy all guest read/write VMCS fields.
1879 *
1880 * We don't check for VMWRITE failures here for performance reasons and
1881 * because they are not expected to fail, barring irrecoverable conditions
1882 * like hardware errors.
1883 */
1884 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
1885 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
1886 {
1887 uint64_t u64Val;
1888 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsFields[i];
1889 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
1890 VMX_VMCS_WRITE_64(pVCpu, uVmcsField, u64Val);
1891 }
1892
1893 /*
1894 * If the host CPU supports writing all VMCS fields, copy the guest read-only
1895 * VMCS fields, so the guest can VMREAD them without causing a VM-exit.
1896 */
1897 if (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL)
1898 {
1899 uint32_t const cShadowVmcsRoFields = pVM->hmr0.s.vmx.cShadowVmcsRoFields;
1900 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
1901 {
1902 uint64_t u64Val;
1903 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsRoFields[i];
1904 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
1905 VMX_VMCS_WRITE_64(pVCpu, uVmcsField, u64Val);
1906 }
1907 }
1908
1909 rc = vmxHCClearShadowVmcs(pVmcsInfo);
1910 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
1911 }
1912
1913 ASMSetFlags(fEFlags);
1914 return rc;
1915}
1916
1917
1918/**
1919 * Copies the shadow VMCS to the nested-guest VMCS.
1920 *
1921 * @returns VBox status code.
1922 * @param pVCpu The cross context virtual CPU structure.
1923 * @param pVmcsInfo The VMCS info. object.
1924 *
1925 * @remarks Called with interrupts disabled.
1926 */
1927static int vmxHCCopyShadowToNstGstVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
1928{
1929 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1930 PVMCC const pVM = pVCpu->CTX_SUFF(pVM);
1931 PVMXVVMCS const pVmcsNstGst = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
1932
1933 int rc = vmxHCLoadShadowVmcs(pVmcsInfo);
1934 if (RT_SUCCESS(rc))
1935 {
1936 /*
1937 * Copy guest read/write fields from the shadow VMCS.
1938 * Guest read-only fields cannot be modified, so no need to copy them.
1939 *
1940 * We don't check for VMREAD failures here for performance reasons and
1941 * because they are not expected to fail, barring irrecoverable conditions
1942 * like hardware errors.
1943 */
1944 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
1945 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
1946 {
1947 uint64_t u64Val;
1948 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsFields[i];
1949 VMX_VMCS_READ_64(pVCpu, uVmcsField, &u64Val);
1950 IEMWriteVmxVmcsField(pVmcsNstGst, uVmcsField, u64Val);
1951 }
1952
1953 rc = vmxHCClearShadowVmcs(pVmcsInfo);
1954 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
1955 }
1956 return rc;
1957}
1958
1959
1960/**
1961 * Enables VMCS shadowing for the given VMCS info. object.
1962 *
1963 * @param pVCpu The cross context virtual CPU structure.
1964 * @param pVmcsInfo The VMCS info. object.
1965 *
1966 * @remarks No-long-jump zone!!!
1967 */
1968static void vmxHCEnableVmcsShadowing(PCVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
1969{
1970 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
1971 if (!(uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING))
1972 {
1973 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1974 uProcCtls2 |= VMX_PROC_CTLS2_VMCS_SHADOWING;
1975 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
1976 rc = VMX_VMCS_WRITE_64(pVCpu, VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, pVmcsInfo->HCPhysShadowVmcs); AssertRC(rc);
1977 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
1978 pVmcsInfo->u64VmcsLinkPtr = pVmcsInfo->HCPhysShadowVmcs;
1979 Log4Func(("Enabled\n"));
1980 }
1981}
1982
1983
1984/**
1985 * Disables VMCS shadowing for the given VMCS info. object.
1986 *
1987 * @param pVCpu The cross context virtual CPU structure.
1988 * @param pVmcsInfo The VMCS info. object.
1989 *
1990 * @remarks No-long-jump zone!!!
1991 */
1992static void vmxHCDisableVmcsShadowing(PCVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
1993{
1994 /*
1995 * We want all VMREAD and VMWRITE instructions to cause VM-exits, so we clear the
1996 * VMCS shadowing control. However, VM-entry requires the shadow VMCS indicator bit
1997 * to match the VMCS shadowing control if the VMCS link pointer is not NIL_RTHCPHYS.
1998 * Hence, we must also reset the VMCS link pointer to ensure VM-entry does not fail.
1999 *
2000 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
2001 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
2002 */
2003 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
2004 if (uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
2005 {
2006 uProcCtls2 &= ~VMX_PROC_CTLS2_VMCS_SHADOWING;
2007 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
2008 rc = VMX_VMCS_WRITE_64(pVCpu, VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS); AssertRC(rc);
2009 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
2010 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
2011 Log4Func(("Disabled\n"));
2012 }
2013}
2014#endif
2015
2016
2017/**
2018 * Exports the guest CR0 control register into the guest-state area in the VMCS.
2019 *
2020 * The guest FPU state is always pre-loaded hence we don't need to bother about
2021 * sharing FPU related CR0 bits between the guest and host.
2022 *
2023 * @returns VBox status code.
2024 * @param pVCpu The cross context virtual CPU structure.
2025 * @param pVmxTransient The VMX-transient structure.
2026 *
2027 * @remarks No-long-jump zone!!!
2028 */
2029static int vmxHCExportGuestCR0(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
2030{
2031 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_CR0)
2032 {
2033 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2034 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2035
2036 uint64_t fSetCr0 = g_HmMsrs.u.vmx.u64Cr0Fixed0;
2037 uint64_t const fZapCr0 = g_HmMsrs.u.vmx.u64Cr0Fixed1;
2038 if (VM_IS_VMX_UNRESTRICTED_GUEST(pVM))
2039 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
2040 else
2041 Assert((fSetCr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
2042
2043 if (!pVmxTransient->fIsNestedGuest)
2044 {
2045 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
2046 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
2047 uint64_t const u64ShadowCr0 = u64GuestCr0;
2048 Assert(!RT_HI_U32(u64GuestCr0));
2049
2050 /*
2051 * Setup VT-x's view of the guest CR0.
2052 */
2053 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
2054 if (VM_IS_VMX_NESTED_PAGING(pVM))
2055 {
2056#ifndef HMVMX_ALWAYS_INTERCEPT_CR3_ACCESS
2057 if (CPUMIsGuestPagingEnabled(pVCpu))
2058 {
2059 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
2060 uProcCtls &= ~( VMX_PROC_CTLS_CR3_LOAD_EXIT
2061 | VMX_PROC_CTLS_CR3_STORE_EXIT);
2062 }
2063 else
2064 {
2065 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
2066 uProcCtls |= VMX_PROC_CTLS_CR3_LOAD_EXIT
2067 | VMX_PROC_CTLS_CR3_STORE_EXIT;
2068 }
2069
2070 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
2071 if (VM_IS_VMX_UNRESTRICTED_GUEST(pVM))
2072 uProcCtls &= ~VMX_PROC_CTLS_CR3_STORE_EXIT;
2073#endif
2074 }
2075 else
2076 {
2077 /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
2078 u64GuestCr0 |= X86_CR0_WP;
2079 }
2080
2081 /*
2082 * Guest FPU bits.
2083 *
2084 * Since we pre-load the guest FPU always before VM-entry there is no need to track lazy state
2085 * using CR0.TS.
2086 *
2087 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be
2088 * set on the first CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
2089 */
2090 u64GuestCr0 |= X86_CR0_NE;
2091
2092 /* If CR0.NE isn't set, we need to intercept #MF exceptions and report them to the guest differently. */
2093 bool const fInterceptMF = !(u64ShadowCr0 & X86_CR0_NE);
2094
2095 /*
2096 * Update exception intercepts.
2097 */
2098 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
2099#ifndef IN_NEM_DARWIN
2100 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
2101 {
2102 Assert(PDMVmmDevHeapIsEnabled(pVM));
2103 Assert(pVM->hm.s.vmx.pRealModeTSS);
2104 uXcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
2105 }
2106 else
2107#endif
2108 {
2109 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
2110 uXcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
2111 if (fInterceptMF)
2112 uXcptBitmap |= RT_BIT(X86_XCPT_MF);
2113 }
2114
2115 /* Additional intercepts for debugging, define these yourself explicitly. */
2116#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
2117 uXcptBitmap |= 0
2118 | RT_BIT(X86_XCPT_BP)
2119 | RT_BIT(X86_XCPT_DE)
2120 | RT_BIT(X86_XCPT_NM)
2121 | RT_BIT(X86_XCPT_TS)
2122 | RT_BIT(X86_XCPT_UD)
2123 | RT_BIT(X86_XCPT_NP)
2124 | RT_BIT(X86_XCPT_SS)
2125 | RT_BIT(X86_XCPT_GP)
2126 | RT_BIT(X86_XCPT_PF)
2127 | RT_BIT(X86_XCPT_MF)
2128 ;
2129#elif defined(HMVMX_ALWAYS_TRAP_PF)
2130 uXcptBitmap |= RT_BIT(X86_XCPT_PF);
2131#endif
2132 if (VCPU_2_VMXSTATE(pVCpu).fTrapXcptGpForLovelyMesaDrv)
2133 uXcptBitmap |= RT_BIT(X86_XCPT_GP);
2134 if (VCPU_2_VMXSTATE(pVCpu).fGCMTrapXcptDE)
2135 uXcptBitmap |= RT_BIT(X86_XCPT_DE);
2136 Assert(VM_IS_VMX_NESTED_PAGING(pVM) || (uXcptBitmap & RT_BIT(X86_XCPT_PF)));
2137
2138 /* Apply the hardware specified CR0 fixed bits and enable caching. */
2139 u64GuestCr0 |= fSetCr0;
2140 u64GuestCr0 &= fZapCr0;
2141 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
2142
2143 Assert(!RT_HI_U32(u64GuestCr0));
2144 Assert(u64GuestCr0 & X86_CR0_NE);
2145
2146 /* Commit the CR0 and related fields to the guest VMCS. */
2147 int rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
2148 rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
2149 if (uProcCtls != pVmcsInfo->u32ProcCtls)
2150 {
2151 rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
2152 AssertRC(rc);
2153 }
2154 if (uXcptBitmap != pVmcsInfo->u32XcptBitmap)
2155 {
2156 rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
2157 AssertRC(rc);
2158 }
2159
2160 /* Update our caches. */
2161 pVmcsInfo->u32ProcCtls = uProcCtls;
2162 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
2163
2164 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
2165 }
2166 else
2167 {
2168 /*
2169 * With nested-guests, we may have extended the guest/host mask here since we
2170 * merged in the outer guest's mask. Thus, the merged mask can include more bits
2171 * (to read from the nested-guest CR0 read-shadow) than the nested hypervisor
2172 * originally supplied. We must copy those bits from the nested-guest CR0 into
2173 * the nested-guest CR0 read-shadow.
2174 */
2175 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
2176 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
2177 uint64_t const u64ShadowCr0 = CPUMGetGuestVmxMaskedCr0(&pVCpu->cpum.GstCtx, pVmcsInfo->u64Cr0Mask);
2178
2179 /* Apply the hardware specified CR0 fixed bits and enable caching. */
2180 u64GuestCr0 |= fSetCr0;
2181 u64GuestCr0 &= fZapCr0;
2182 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
2183
2184 Assert(!RT_HI_U32(u64GuestCr0));
2185 Assert(u64GuestCr0 & X86_CR0_NE);
2186
2187 /* Commit the CR0 and CR0 read-shadow to the nested-guest VMCS. */
2188 int rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
2189 rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
2190
2191 Log4Func(("cr0=%#RX64 shadow=%#RX64 vmcs_read_shw=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr0, u64ShadowCr0,
2192 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64Cr0ReadShadow.u, fSetCr0, fZapCr0));
2193 }
2194
2195 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_CR0);
2196 }
2197
2198 return VINF_SUCCESS;
2199}
2200
2201
2202/**
2203 * Exports the guest control registers (CR3, CR4) into the guest-state area
2204 * in the VMCS.
2205 *
2206 * @returns VBox strict status code.
2207 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
2208 * without unrestricted guest access and the VMMDev is not presently
2209 * mapped (e.g. EFI32).
2210 *
2211 * @param pVCpu The cross context virtual CPU structure.
2212 * @param pVmxTransient The VMX-transient structure.
2213 *
2214 * @remarks No-long-jump zone!!!
2215 */
2216static VBOXSTRICTRC vmxHCExportGuestCR3AndCR4(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
2217{
2218 int rc = VINF_SUCCESS;
2219 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2220
2221 /*
2222 * Guest CR2.
2223 * It's always loaded in the assembler code. Nothing to do here.
2224 */
2225
2226 /*
2227 * Guest CR3.
2228 */
2229 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_CR3)
2230 {
2231 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
2232
2233 if (VM_IS_VMX_NESTED_PAGING(pVM))
2234 {
2235#ifndef IN_NEM_DARWIN
2236 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2237 pVmcsInfo->HCPhysEPTP = PGMGetHyperCR3(pVCpu);
2238
2239 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
2240 Assert(pVmcsInfo->HCPhysEPTP != NIL_RTHCPHYS);
2241 Assert(!(pVmcsInfo->HCPhysEPTP & UINT64_C(0xfff0000000000000)));
2242 Assert(!(pVmcsInfo->HCPhysEPTP & 0xfff));
2243
2244 /* VMX_EPT_MEMTYPE_WB support is already checked in vmxHCSetupTaggedTlb(). */
2245 pVmcsInfo->HCPhysEPTP |= RT_BF_MAKE(VMX_BF_EPTP_MEMTYPE, VMX_EPTP_MEMTYPE_WB)
2246 | RT_BF_MAKE(VMX_BF_EPTP_PAGE_WALK_LENGTH, VMX_EPTP_PAGE_WALK_LENGTH_4);
2247
2248 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
2249 AssertMsg( ((pVmcsInfo->HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
2250 && ((pVmcsInfo->HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
2251 ("EPTP %#RX64\n", pVmcsInfo->HCPhysEPTP));
2252 AssertMsg( !((pVmcsInfo->HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
2253 || (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_ACCESS_DIRTY),
2254 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVmcsInfo->HCPhysEPTP));
2255
2256 rc = VMX_VMCS_WRITE_64(pVCpu, VMX_VMCS64_CTRL_EPTP_FULL, pVmcsInfo->HCPhysEPTP);
2257 AssertRC(rc);
2258#endif
2259
2260 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
2261 uint64_t u64GuestCr3 = pCtx->cr3;
2262 if ( VM_IS_VMX_UNRESTRICTED_GUEST(pVM)
2263 || CPUMIsGuestPagingEnabledEx(pCtx))
2264 {
2265 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
2266 if (CPUMIsGuestInPAEModeEx(pCtx))
2267 {
2268 rc = VMX_VMCS_WRITE_64(pVCpu, VMX_VMCS64_GUEST_PDPTE0_FULL, pCtx->aPaePdpes[0].u); AssertRC(rc);
2269 rc = VMX_VMCS_WRITE_64(pVCpu, VMX_VMCS64_GUEST_PDPTE1_FULL, pCtx->aPaePdpes[1].u); AssertRC(rc);
2270 rc = VMX_VMCS_WRITE_64(pVCpu, VMX_VMCS64_GUEST_PDPTE2_FULL, pCtx->aPaePdpes[2].u); AssertRC(rc);
2271 rc = VMX_VMCS_WRITE_64(pVCpu, VMX_VMCS64_GUEST_PDPTE3_FULL, pCtx->aPaePdpes[3].u); AssertRC(rc);
2272 }
2273
2274 /*
2275 * The guest's view of its CR3 is unblemished with nested paging when the
2276 * guest is using paging or we have unrestricted guest execution to handle
2277 * the guest when it's not using paging.
2278 */
2279 }
2280#ifndef IN_NEM_DARWIN
2281 else
2282 {
2283 /*
2284 * The guest is not using paging, but the CPU (VT-x) has to. While the guest
2285 * thinks it accesses physical memory directly, we use our identity-mapped
2286 * page table to map guest-linear to guest-physical addresses. EPT takes care
2287 * of translating it to host-physical addresses.
2288 */
2289 RTGCPHYS GCPhys;
2290 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
2291
2292 /* We obtain it here every time as the guest could have relocated this PCI region. */
2293 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
2294 if (RT_SUCCESS(rc))
2295 { /* likely */ }
2296 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
2297 {
2298 Log4Func(("VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n"));
2299 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
2300 }
2301 else
2302 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
2303
2304 u64GuestCr3 = GCPhys;
2305 }
2306#endif
2307
2308 Log4Func(("guest_cr3=%#RX64 (GstN)\n", u64GuestCr3));
2309 rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_CR3, u64GuestCr3);
2310 AssertRC(rc);
2311 }
2312 else
2313 {
2314 Assert(!pVmxTransient->fIsNestedGuest);
2315 /* Non-nested paging case, just use the hypervisor's CR3. */
2316 RTHCPHYS const HCPhysGuestCr3 = PGMGetHyperCR3(pVCpu);
2317
2318 Log4Func(("guest_cr3=%#RX64 (HstN)\n", HCPhysGuestCr3));
2319 rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_CR3, HCPhysGuestCr3);
2320 AssertRC(rc);
2321 }
2322
2323 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_CR3);
2324 }
2325
2326 /*
2327 * Guest CR4.
2328 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
2329 */
2330 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_CR4)
2331 {
2332 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
2333 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2334
2335 uint64_t const fSetCr4 = g_HmMsrs.u.vmx.u64Cr4Fixed0;
2336 uint64_t const fZapCr4 = g_HmMsrs.u.vmx.u64Cr4Fixed1;
2337
2338 /*
2339 * With nested-guests, we may have extended the guest/host mask here (since we
2340 * merged in the outer guest's mask, see hmR0VmxMergeVmcsNested). This means, the
2341 * mask can include more bits (to read from the nested-guest CR4 read-shadow) than
2342 * the nested hypervisor originally supplied. Thus, we should, in essence, copy
2343 * those bits from the nested-guest CR4 into the nested-guest CR4 read-shadow.
2344 */
2345 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
2346 uint64_t u64GuestCr4 = pCtx->cr4;
2347 uint64_t const u64ShadowCr4 = !pVmxTransient->fIsNestedGuest
2348 ? pCtx->cr4
2349 : CPUMGetGuestVmxMaskedCr4(pCtx, pVmcsInfo->u64Cr4Mask);
2350 Assert(!RT_HI_U32(u64GuestCr4));
2351
2352#ifndef IN_NEM_DARWIN
2353 /*
2354 * Setup VT-x's view of the guest CR4.
2355 *
2356 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software
2357 * interrupts to the 8086 program interrupt handler. Clear the VME bit (the interrupt
2358 * redirection bitmap is already all 0, see hmR3InitFinalizeR0())
2359 *
2360 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
2361 */
2362 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
2363 {
2364 Assert(pVM->hm.s.vmx.pRealModeTSS);
2365 Assert(PDMVmmDevHeapIsEnabled(pVM));
2366 u64GuestCr4 &= ~(uint64_t)X86_CR4_VME;
2367 }
2368#endif
2369
2370 if (VM_IS_VMX_NESTED_PAGING(pVM))
2371 {
2372 if ( !CPUMIsGuestPagingEnabledEx(pCtx)
2373 && !VM_IS_VMX_UNRESTRICTED_GUEST(pVM))
2374 {
2375 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
2376 u64GuestCr4 |= X86_CR4_PSE;
2377 /* Our identity mapping is a 32-bit page directory. */
2378 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
2379 }
2380 /* else use guest CR4.*/
2381 }
2382 else
2383 {
2384 Assert(!pVmxTransient->fIsNestedGuest);
2385
2386 /*
2387 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
2388 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
2389 */
2390 switch (VCPU_2_VMXSTATE(pVCpu).enmShadowMode)
2391 {
2392 case PGMMODE_REAL: /* Real-mode. */
2393 case PGMMODE_PROTECTED: /* Protected mode without paging. */
2394 case PGMMODE_32_BIT: /* 32-bit paging. */
2395 {
2396 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
2397 break;
2398 }
2399
2400 case PGMMODE_PAE: /* PAE paging. */
2401 case PGMMODE_PAE_NX: /* PAE paging with NX. */
2402 {
2403 u64GuestCr4 |= X86_CR4_PAE;
2404 break;
2405 }
2406
2407 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
2408 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
2409 {
2410#ifdef VBOX_WITH_64_BITS_GUESTS
2411 /* For our assumption in vmxHCShouldSwapEferMsr. */
2412 Assert(u64GuestCr4 & X86_CR4_PAE);
2413 break;
2414#endif
2415 }
2416 default:
2417 AssertFailed();
2418 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
2419 }
2420 }
2421
2422 /* Apply the hardware specified CR4 fixed bits (mainly CR4.VMXE). */
2423 u64GuestCr4 |= fSetCr4;
2424 u64GuestCr4 &= fZapCr4;
2425
2426 Assert(!RT_HI_U32(u64GuestCr4));
2427 Assert(u64GuestCr4 & X86_CR4_VMXE);
2428
2429 /* Commit the CR4 and CR4 read-shadow to the guest VMCS. */
2430 rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_CR4, u64GuestCr4); AssertRC(rc);
2431 rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_CTRL_CR4_READ_SHADOW, u64ShadowCr4); AssertRC(rc);
2432
2433#ifndef IN_NEM_DARWIN
2434 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
2435 bool const fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
2436 if (fLoadSaveGuestXcr0 != pVCpu->hmr0.s.fLoadSaveGuestXcr0)
2437 {
2438 pVCpu->hmr0.s.fLoadSaveGuestXcr0 = fLoadSaveGuestXcr0;
2439 hmR0VmxUpdateStartVmFunction(pVCpu);
2440 }
2441#endif
2442
2443 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_CR4);
2444
2445 Log4Func(("cr4=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr4, u64ShadowCr4, fSetCr4, fZapCr4));
2446 }
2447 return rc;
2448}
2449
2450
2451#ifdef VBOX_STRICT
2452/**
2453 * Strict function to validate segment registers.
2454 *
2455 * @param pVCpu The cross context virtual CPU structure.
2456 * @param pVmcsInfo The VMCS info. object.
2457 *
2458 * @remarks Will import guest CR0 on strict builds during validation of
2459 * segments.
2460 */
2461static void vmxHCValidateSegmentRegs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
2462{
2463 /*
2464 * Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
2465 *
2466 * The reason we check for attribute value 0 in this function and not just the unusable bit is
2467 * because vmxHCExportGuestSegReg() only updates the VMCS' copy of the value with the
2468 * unusable bit and doesn't change the guest-context value.
2469 */
2470 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2471 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
2472 vmxHCImportGuestStateEx(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR0);
2473 if ( !VM_IS_VMX_UNRESTRICTED_GUEST(pVM)
2474 && ( !CPUMIsGuestInRealModeEx(pCtx)
2475 && !CPUMIsGuestInV86ModeEx(pCtx)))
2476 {
2477 /* Protected mode checks */
2478 /* CS */
2479 Assert(pCtx->cs.Attr.n.u1Present);
2480 Assert(!(pCtx->cs.Attr.u & 0xf00));
2481 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
2482 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
2483 || !(pCtx->cs.Attr.n.u1Granularity));
2484 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
2485 || (pCtx->cs.Attr.n.u1Granularity));
2486 /* CS cannot be loaded with NULL in protected mode. */
2487 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
2488 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
2489 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
2490 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
2491 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
2492 else
2493 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
2494 /* SS */
2495 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
2496 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
2497 if ( !(pCtx->cr0 & X86_CR0_PE)
2498 || pCtx->cs.Attr.n.u4Type == 3)
2499 {
2500 Assert(!pCtx->ss.Attr.n.u2Dpl);
2501 }
2502 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
2503 {
2504 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
2505 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
2506 Assert(pCtx->ss.Attr.n.u1Present);
2507 Assert(!(pCtx->ss.Attr.u & 0xf00));
2508 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
2509 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
2510 || !(pCtx->ss.Attr.n.u1Granularity));
2511 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
2512 || (pCtx->ss.Attr.n.u1Granularity));
2513 }
2514 /* DS, ES, FS, GS - only check for usable selectors, see vmxHCExportGuestSegReg(). */
2515 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
2516 {
2517 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
2518 Assert(pCtx->ds.Attr.n.u1Present);
2519 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
2520 Assert(!(pCtx->ds.Attr.u & 0xf00));
2521 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
2522 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
2523 || !(pCtx->ds.Attr.n.u1Granularity));
2524 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
2525 || (pCtx->ds.Attr.n.u1Granularity));
2526 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
2527 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
2528 }
2529 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
2530 {
2531 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
2532 Assert(pCtx->es.Attr.n.u1Present);
2533 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
2534 Assert(!(pCtx->es.Attr.u & 0xf00));
2535 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
2536 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
2537 || !(pCtx->es.Attr.n.u1Granularity));
2538 Assert( !(pCtx->es.u32Limit & 0xfff00000)
2539 || (pCtx->es.Attr.n.u1Granularity));
2540 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
2541 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
2542 }
2543 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
2544 {
2545 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
2546 Assert(pCtx->fs.Attr.n.u1Present);
2547 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
2548 Assert(!(pCtx->fs.Attr.u & 0xf00));
2549 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
2550 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
2551 || !(pCtx->fs.Attr.n.u1Granularity));
2552 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
2553 || (pCtx->fs.Attr.n.u1Granularity));
2554 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
2555 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
2556 }
2557 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
2558 {
2559 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
2560 Assert(pCtx->gs.Attr.n.u1Present);
2561 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
2562 Assert(!(pCtx->gs.Attr.u & 0xf00));
2563 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
2564 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
2565 || !(pCtx->gs.Attr.n.u1Granularity));
2566 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
2567 || (pCtx->gs.Attr.n.u1Granularity));
2568 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
2569 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
2570 }
2571 /* 64-bit capable CPUs. */
2572 Assert(!RT_HI_U32(pCtx->cs.u64Base));
2573 Assert(!pCtx->ss.Attr.u || !RT_HI_U32(pCtx->ss.u64Base));
2574 Assert(!pCtx->ds.Attr.u || !RT_HI_U32(pCtx->ds.u64Base));
2575 Assert(!pCtx->es.Attr.u || !RT_HI_U32(pCtx->es.u64Base));
2576 }
2577 else if ( CPUMIsGuestInV86ModeEx(pCtx)
2578 || ( CPUMIsGuestInRealModeEx(pCtx)
2579 && !VM_IS_VMX_UNRESTRICTED_GUEST(pVM)))
2580 {
2581 /* Real and v86 mode checks. */
2582 /* vmxHCExportGuestSegReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
2583 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
2584#ifndef IN_NEM_DARWIN
2585 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
2586 {
2587 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3;
2588 u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
2589 }
2590 else
2591#endif
2592 {
2593 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
2594 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
2595 }
2596
2597 /* CS */
2598 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
2599 Assert(pCtx->cs.u32Limit == 0xffff);
2600 AssertMsg(u32CSAttr == 0xf3, ("cs=%#x %#x ", pCtx->cs.Sel, u32CSAttr));
2601 /* SS */
2602 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
2603 Assert(pCtx->ss.u32Limit == 0xffff);
2604 Assert(u32SSAttr == 0xf3);
2605 /* DS */
2606 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
2607 Assert(pCtx->ds.u32Limit == 0xffff);
2608 Assert(u32DSAttr == 0xf3);
2609 /* ES */
2610 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
2611 Assert(pCtx->es.u32Limit == 0xffff);
2612 Assert(u32ESAttr == 0xf3);
2613 /* FS */
2614 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
2615 Assert(pCtx->fs.u32Limit == 0xffff);
2616 Assert(u32FSAttr == 0xf3);
2617 /* GS */
2618 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
2619 Assert(pCtx->gs.u32Limit == 0xffff);
2620 Assert(u32GSAttr == 0xf3);
2621 /* 64-bit capable CPUs. */
2622 Assert(!RT_HI_U32(pCtx->cs.u64Base));
2623 Assert(!u32SSAttr || !RT_HI_U32(pCtx->ss.u64Base));
2624 Assert(!u32DSAttr || !RT_HI_U32(pCtx->ds.u64Base));
2625 Assert(!u32ESAttr || !RT_HI_U32(pCtx->es.u64Base));
2626 }
2627}
2628#endif /* VBOX_STRICT */
2629
2630
2631/**
2632 * Exports a guest segment register into the guest-state area in the VMCS.
2633 *
2634 * @returns VBox status code.
2635 * @param pVCpu The cross context virtual CPU structure.
2636 * @param pVmcsInfo The VMCS info. object.
2637 * @param iSegReg The segment register number (X86_SREG_XXX).
2638 * @param pSelReg Pointer to the segment selector.
2639 *
2640 * @remarks No-long-jump zone!!!
2641 */
2642static int vmxHCExportGuestSegReg(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, uint32_t iSegReg, PCCPUMSELREG pSelReg)
2643{
2644 Assert(iSegReg < X86_SREG_COUNT);
2645
2646 uint32_t u32Access = pSelReg->Attr.u;
2647#ifndef IN_NEM_DARWIN
2648 if (!pVmcsInfo->pShared->RealMode.fRealOnV86Active)
2649#endif
2650 {
2651 /*
2652 * The way to differentiate between whether this is really a null selector or was just
2653 * a selector loaded with 0 in real-mode is using the segment attributes. A selector
2654 * loaded in real-mode with the value 0 is valid and usable in protected-mode and we
2655 * should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures
2656 * NULL selectors loaded in protected-mode have their attribute as 0.
2657 */
2658 if (u32Access)
2659 { }
2660 else
2661 u32Access = X86DESCATTR_UNUSABLE;
2662 }
2663#ifndef IN_NEM_DARWIN
2664 else
2665 {
2666 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
2667 u32Access = 0xf3;
2668 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
2669 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
2670 RT_NOREF_PV(pVCpu);
2671 }
2672#else
2673 RT_NOREF(pVmcsInfo);
2674#endif
2675
2676 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
2677 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
2678 ("Access bit not set for usable segment. %.2s sel=%#x attr %#x\n", "ESCSSSDSFSGS" + iSegReg * 2, pSelReg, pSelReg->Attr.u));
2679
2680 /*
2681 * Commit it to the VMCS.
2682 */
2683 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS16_GUEST_SEG_SEL(iSegReg), pSelReg->Sel); AssertRC(rc);
2684 rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg), pSelReg->u32Limit); AssertRC(rc);
2685 rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_SEG_BASE(iSegReg), pSelReg->u64Base); AssertRC(rc);
2686 rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg), u32Access); AssertRC(rc);
2687 return VINF_SUCCESS;
2688}
2689
2690
2691/**
2692 * Exports the guest segment registers, GDTR, IDTR, LDTR, TR into the guest-state
2693 * area in the VMCS.
2694 *
2695 * @returns VBox status code.
2696 * @param pVCpu The cross context virtual CPU structure.
2697 * @param pVmxTransient The VMX-transient structure.
2698 *
2699 * @remarks Will import guest CR0 on strict builds during validation of
2700 * segments.
2701 * @remarks No-long-jump zone!!!
2702 */
2703static int vmxHCExportGuestSegRegsXdtr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
2704{
2705 int rc = VERR_INTERNAL_ERROR_5;
2706#ifndef IN_NEM_DARWIN
2707 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2708#endif
2709 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
2710 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2711#ifndef IN_NEM_DARWIN
2712 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
2713#endif
2714
2715 /*
2716 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
2717 */
2718 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_SREG_MASK)
2719 {
2720 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_CS)
2721 {
2722 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CS);
2723#ifndef IN_NEM_DARWIN
2724 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
2725 pVmcsInfoShared->RealMode.AttrCS.u = pCtx->cs.Attr.u;
2726#endif
2727 rc = vmxHCExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_CS, &pCtx->cs);
2728 AssertRC(rc);
2729 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_CS);
2730 }
2731
2732 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_SS)
2733 {
2734 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SS);
2735#ifndef IN_NEM_DARWIN
2736 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
2737 pVmcsInfoShared->RealMode.AttrSS.u = pCtx->ss.Attr.u;
2738#endif
2739 rc = vmxHCExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_SS, &pCtx->ss);
2740 AssertRC(rc);
2741 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_SS);
2742 }
2743
2744 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_DS)
2745 {
2746 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DS);
2747#ifndef IN_NEM_DARWIN
2748 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
2749 pVmcsInfoShared->RealMode.AttrDS.u = pCtx->ds.Attr.u;
2750#endif
2751 rc = vmxHCExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_DS, &pCtx->ds);
2752 AssertRC(rc);
2753 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_DS);
2754 }
2755
2756 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_ES)
2757 {
2758 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_ES);
2759#ifndef IN_NEM_DARWIN
2760 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
2761 pVmcsInfoShared->RealMode.AttrES.u = pCtx->es.Attr.u;
2762#endif
2763 rc = vmxHCExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_ES, &pCtx->es);
2764 AssertRC(rc);
2765 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_ES);
2766 }
2767
2768 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_FS)
2769 {
2770 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_FS);
2771#ifndef IN_NEM_DARWIN
2772 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
2773 pVmcsInfoShared->RealMode.AttrFS.u = pCtx->fs.Attr.u;
2774#endif
2775 rc = vmxHCExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_FS, &pCtx->fs);
2776 AssertRC(rc);
2777 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_FS);
2778 }
2779
2780 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_GS)
2781 {
2782 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GS);
2783#ifndef IN_NEM_DARWIN
2784 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
2785 pVmcsInfoShared->RealMode.AttrGS.u = pCtx->gs.Attr.u;
2786#endif
2787 rc = vmxHCExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_GS, &pCtx->gs);
2788 AssertRC(rc);
2789 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_GS);
2790 }
2791
2792#ifdef VBOX_STRICT
2793 vmxHCValidateSegmentRegs(pVCpu, pVmcsInfo);
2794#endif
2795 Log4Func(("cs={%#04x base=%#RX64 limit=%#RX32 attr=%#RX32}\n", pCtx->cs.Sel, pCtx->cs.u64Base, pCtx->cs.u32Limit,
2796 pCtx->cs.Attr.u));
2797 }
2798
2799 /*
2800 * Guest TR.
2801 */
2802 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_TR)
2803 {
2804 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_TR);
2805
2806 /*
2807 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is
2808 * achieved using the interrupt redirection bitmap (all bits cleared to let the guest
2809 * handle INT-n's) in the TSS. See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
2810 */
2811 uint16_t u16Sel;
2812 uint32_t u32Limit;
2813 uint64_t u64Base;
2814 uint32_t u32AccessRights;
2815#ifndef IN_NEM_DARWIN
2816 if (!pVmcsInfoShared->RealMode.fRealOnV86Active)
2817#endif
2818 {
2819 u16Sel = pCtx->tr.Sel;
2820 u32Limit = pCtx->tr.u32Limit;
2821 u64Base = pCtx->tr.u64Base;
2822 u32AccessRights = pCtx->tr.Attr.u;
2823 }
2824#ifndef IN_NEM_DARWIN
2825 else
2826 {
2827 Assert(!pVmxTransient->fIsNestedGuest);
2828 Assert(pVM->hm.s.vmx.pRealModeTSS);
2829 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMCanExecuteGuest() -XXX- what about inner loop changes? */
2830
2831 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
2832 RTGCPHYS GCPhys;
2833 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
2834 AssertRCReturn(rc, rc);
2835
2836 X86DESCATTR DescAttr;
2837 DescAttr.u = 0;
2838 DescAttr.n.u1Present = 1;
2839 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
2840
2841 u16Sel = 0;
2842 u32Limit = HM_VTX_TSS_SIZE;
2843 u64Base = GCPhys;
2844 u32AccessRights = DescAttr.u;
2845 }
2846#endif
2847
2848 /* Validate. */
2849 Assert(!(u16Sel & RT_BIT(2)));
2850 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
2851 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
2852 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
2853 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
2854 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
2855 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
2856 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
2857 Assert( (u32Limit & 0xfff) == 0xfff
2858 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
2859 Assert( !(pCtx->tr.u32Limit & 0xfff00000)
2860 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
2861
2862 rc = VMX_VMCS_WRITE_16(pVCpu, VMX_VMCS16_GUEST_TR_SEL, u16Sel); AssertRC(rc);
2863 rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_GUEST_TR_LIMIT, u32Limit); AssertRC(rc);
2864 rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights); AssertRC(rc);
2865 rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_TR_BASE, u64Base); AssertRC(rc);
2866
2867 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_TR);
2868 Log4Func(("tr base=%#RX64 limit=%#RX32\n", pCtx->tr.u64Base, pCtx->tr.u32Limit));
2869 }
2870
2871 /*
2872 * Guest GDTR.
2873 */
2874 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_GDTR)
2875 {
2876 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GDTR);
2877
2878 rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt); AssertRC(rc);
2879 rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_GDTR_BASE, pCtx->gdtr.pGdt); AssertRC(rc);
2880
2881 /* Validate. */
2882 Assert(!(pCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
2883
2884 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_GDTR);
2885 Log4Func(("gdtr base=%#RX64 limit=%#RX32\n", pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt));
2886 }
2887
2888 /*
2889 * Guest LDTR.
2890 */
2891 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_LDTR)
2892 {
2893 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_LDTR);
2894
2895 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
2896 uint32_t u32Access;
2897 if ( !pVmxTransient->fIsNestedGuest
2898 && !pCtx->ldtr.Attr.u)
2899 u32Access = X86DESCATTR_UNUSABLE;
2900 else
2901 u32Access = pCtx->ldtr.Attr.u;
2902
2903 rc = VMX_VMCS_WRITE_16(pVCpu, VMX_VMCS16_GUEST_LDTR_SEL, pCtx->ldtr.Sel); AssertRC(rc);
2904 rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtr.u32Limit); AssertRC(rc);
2905 rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access); AssertRC(rc);
2906 rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_LDTR_BASE, pCtx->ldtr.u64Base); AssertRC(rc);
2907
2908 /* Validate. */
2909 if (!(u32Access & X86DESCATTR_UNUSABLE))
2910 {
2911 Assert(!(pCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
2912 Assert(pCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
2913 Assert(!pCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
2914 Assert(pCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
2915 Assert(!pCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
2916 Assert(!(pCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
2917 Assert( (pCtx->ldtr.u32Limit & 0xfff) == 0xfff
2918 || !pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
2919 Assert( !(pCtx->ldtr.u32Limit & 0xfff00000)
2920 || pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
2921 }
2922
2923 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_LDTR);
2924 Log4Func(("ldtr base=%#RX64 limit=%#RX32\n", pCtx->ldtr.u64Base, pCtx->ldtr.u32Limit));
2925 }
2926
2927 /*
2928 * Guest IDTR.
2929 */
2930 if (ASMAtomicUoReadU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged) & HM_CHANGED_GUEST_IDTR)
2931 {
2932 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_IDTR);
2933
2934 rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt); AssertRC(rc);
2935 rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_IDTR_BASE, pCtx->idtr.pIdt); AssertRC(rc);
2936
2937 /* Validate. */
2938 Assert(!(pCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
2939
2940 ASMAtomicUoAndU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, ~HM_CHANGED_GUEST_IDTR);
2941 Log4Func(("idtr base=%#RX64 limit=%#RX32\n", pCtx->idtr.pIdt, pCtx->idtr.cbIdt));
2942 }
2943
2944 return VINF_SUCCESS;
2945}
2946
2947
2948/**
2949 * Gets the IEM exception flags for the specified vector and IDT vectoring /
2950 * VM-exit interruption info type.
2951 *
2952 * @returns The IEM exception flags.
2953 * @param uVector The event vector.
2954 * @param uVmxEventType The VMX event type.
2955 *
2956 * @remarks This function currently only constructs flags required for
2957 * IEMEvaluateRecursiveXcpt and not the complete flags (e.g, error-code
2958 * and CR2 aspects of an exception are not included).
2959 */
2960static uint32_t vmxHCGetIemXcptFlags(uint8_t uVector, uint32_t uVmxEventType)
2961{
2962 uint32_t fIemXcptFlags;
2963 switch (uVmxEventType)
2964 {
2965 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
2966 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
2967 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
2968 break;
2969
2970 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
2971 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
2972 break;
2973
2974 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
2975 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
2976 break;
2977
2978 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
2979 {
2980 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
2981 if (uVector == X86_XCPT_BP)
2982 fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
2983 else if (uVector == X86_XCPT_OF)
2984 fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
2985 else
2986 {
2987 fIemXcptFlags = 0;
2988 AssertMsgFailed(("Unexpected vector for software exception. uVector=%#x", uVector));
2989 }
2990 break;
2991 }
2992
2993 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
2994 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
2995 break;
2996
2997 default:
2998 fIemXcptFlags = 0;
2999 AssertMsgFailed(("Unexpected vector type! uVmxEventType=%#x uVector=%#x", uVmxEventType, uVector));
3000 break;
3001 }
3002 return fIemXcptFlags;
3003}
3004
3005
3006/**
3007 * Sets an event as a pending event to be injected into the guest.
3008 *
3009 * @param pVCpu The cross context virtual CPU structure.
3010 * @param u32IntInfo The VM-entry interruption-information field.
3011 * @param cbInstr The VM-entry instruction length in bytes (for
3012 * software interrupts, exceptions and privileged
3013 * software exceptions).
3014 * @param u32ErrCode The VM-entry exception error code.
3015 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
3016 * page-fault.
3017 */
3018DECLINLINE(void) vmxHCSetPendingEvent(PVMCPUCC pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
3019 RTGCUINTPTR GCPtrFaultAddress)
3020{
3021 Assert(!VCPU_2_VMXSTATE(pVCpu).Event.fPending);
3022 VCPU_2_VMXSTATE(pVCpu).Event.fPending = true;
3023 VCPU_2_VMXSTATE(pVCpu).Event.u64IntInfo = u32IntInfo;
3024 VCPU_2_VMXSTATE(pVCpu).Event.u32ErrCode = u32ErrCode;
3025 VCPU_2_VMXSTATE(pVCpu).Event.cbInstr = cbInstr;
3026 VCPU_2_VMXSTATE(pVCpu).Event.GCPtrFaultAddress = GCPtrFaultAddress;
3027}
3028
3029
3030/**
3031 * Sets an external interrupt as pending-for-injection into the VM.
3032 *
3033 * @param pVCpu The cross context virtual CPU structure.
3034 * @param u8Interrupt The external interrupt vector.
3035 */
3036DECLINLINE(void) vmxHCSetPendingExtInt(PVMCPUCC pVCpu, uint8_t u8Interrupt)
3037{
3038 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, u8Interrupt)
3039 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
3040 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
3041 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
3042 vmxHCSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
3043 Log4Func(("External interrupt (%#x) pending injection\n", u8Interrupt));
3044}
3045
3046
3047/**
3048 * Sets an NMI (\#NMI) exception as pending-for-injection into the VM.
3049 *
3050 * @param pVCpu The cross context virtual CPU structure.
3051 */
3052DECLINLINE(void) vmxHCSetPendingXcptNmi(PVMCPUCC pVCpu)
3053{
3054 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI)
3055 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI)
3056 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
3057 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
3058 vmxHCSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
3059 Log4Func(("NMI pending injection\n"));
3060}
3061
3062
3063/**
3064 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
3065 *
3066 * @param pVCpu The cross context virtual CPU structure.
3067 */
3068DECLINLINE(void) vmxHCSetPendingXcptDF(PVMCPUCC pVCpu)
3069{
3070 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
3071 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
3072 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
3073 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
3074 vmxHCSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
3075}
3076
3077
3078/**
3079 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
3080 *
3081 * @param pVCpu The cross context virtual CPU structure.
3082 */
3083DECLINLINE(void) vmxHCSetPendingXcptUD(PVMCPUCC pVCpu)
3084{
3085 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_UD)
3086 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
3087 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
3088 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
3089 vmxHCSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
3090}
3091
3092
3093/**
3094 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
3095 *
3096 * @param pVCpu The cross context virtual CPU structure.
3097 */
3098DECLINLINE(void) vmxHCSetPendingXcptDB(PVMCPUCC pVCpu)
3099{
3100 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
3101 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
3102 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
3103 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
3104 vmxHCSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
3105}
3106
3107
3108#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3109/**
3110 * Sets a general-protection (\#GP) exception as pending-for-injection into the VM.
3111 *
3112 * @param pVCpu The cross context virtual CPU structure.
3113 * @param u32ErrCode The error code for the general-protection exception.
3114 */
3115DECLINLINE(void) vmxHCSetPendingXcptGP(PVMCPUCC pVCpu, uint32_t u32ErrCode)
3116{
3117 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
3118 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
3119 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
3120 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
3121 vmxHCSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
3122}
3123
3124
3125/**
3126 * Sets a stack (\#SS) exception as pending-for-injection into the VM.
3127 *
3128 * @param pVCpu The cross context virtual CPU structure.
3129 * @param u32ErrCode The error code for the stack exception.
3130 */
3131DECLINLINE(void) vmxHCSetPendingXcptSS(PVMCPUCC pVCpu, uint32_t u32ErrCode)
3132{
3133 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_SS)
3134 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
3135 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
3136 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
3137 vmxHCSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
3138}
3139#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
3140
3141
3142/**
3143 * Fixes up attributes for the specified segment register.
3144 *
3145 * @param pVCpu The cross context virtual CPU structure.
3146 * @param pSelReg The segment register that needs fixing.
3147 * @param pszRegName The register name (for logging and assertions).
3148 */
3149static void vmxHCFixUnusableSegRegAttr(PVMCPUCC pVCpu, PCPUMSELREG pSelReg, const char *pszRegName)
3150{
3151 Assert(pSelReg->Attr.u & X86DESCATTR_UNUSABLE);
3152
3153 /*
3154 * If VT-x marks the segment as unusable, most other bits remain undefined:
3155 * - For CS the L, D and G bits have meaning.
3156 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
3157 * - For the remaining data segments no bits are defined.
3158 *
3159 * The present bit and the unusable bit has been observed to be set at the
3160 * same time (the selector was supposed to be invalid as we started executing
3161 * a V8086 interrupt in ring-0).
3162 *
3163 * What should be important for the rest of the VBox code, is that the P bit is
3164 * cleared. Some of the other VBox code recognizes the unusable bit, but
3165 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
3166 * safe side here, we'll strip off P and other bits we don't care about. If
3167 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
3168 *
3169 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
3170 */
3171#ifdef VBOX_STRICT
3172 uint32_t const uAttr = pSelReg->Attr.u;
3173#endif
3174
3175 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
3176 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
3177 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
3178
3179#ifdef VBOX_STRICT
3180# ifndef IN_NEM_DARWIN
3181 VMMRZCallRing3Disable(pVCpu);
3182# endif
3183 Log4Func(("Unusable %s: sel=%#x attr=%#x -> %#x\n", pszRegName, pSelReg->Sel, uAttr, pSelReg->Attr.u));
3184# ifdef DEBUG_bird
3185 AssertMsg((uAttr & ~X86DESCATTR_P) == pSelReg->Attr.u,
3186 ("%s: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
3187 pszRegName, uAttr, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
3188# endif
3189# ifndef IN_NEM_DARWIN
3190 VMMRZCallRing3Enable(pVCpu);
3191# endif
3192 NOREF(uAttr);
3193#endif
3194 RT_NOREF2(pVCpu, pszRegName);
3195}
3196
3197
3198/**
3199 * Imports a guest segment register from the current VMCS into the guest-CPU
3200 * context.
3201 *
3202 * @param pVCpu The cross context virtual CPU structure.
3203 * @tparam a_iSegReg The segment register number (X86_SREG_XXX).
3204 *
3205 * @remarks Called with interrupts and/or preemption disabled.
3206 */
3207template<uint32_t const a_iSegReg>
3208DECLINLINE(void) vmxHCImportGuestSegReg(PVMCPUCC pVCpu)
3209{
3210 AssertCompile(a_iSegReg < X86_SREG_COUNT);
3211 /* Check that the macros we depend upon here and in the export parenter function works: */
3212#define MY_SEG_VMCS_FIELD(a_FieldPrefix, a_FieldSuff) \
3213 ( a_iSegReg == X86_SREG_ES ? a_FieldPrefix ## ES ## a_FieldSuff \
3214 : a_iSegReg == X86_SREG_CS ? a_FieldPrefix ## CS ## a_FieldSuff \
3215 : a_iSegReg == X86_SREG_SS ? a_FieldPrefix ## SS ## a_FieldSuff \
3216 : a_iSegReg == X86_SREG_DS ? a_FieldPrefix ## DS ## a_FieldSuff \
3217 : a_iSegReg == X86_SREG_FS ? a_FieldPrefix ## FS ## a_FieldSuff \
3218 : a_iSegReg == X86_SREG_GS ? a_FieldPrefix ## GS ## a_FieldSuff : 0)
3219 AssertCompile(VMX_VMCS_GUEST_SEG_BASE(a_iSegReg) == MY_SEG_VMCS_FIELD(VMX_VMCS_GUEST_,_BASE));
3220 AssertCompile(VMX_VMCS16_GUEST_SEG_SEL(a_iSegReg) == MY_SEG_VMCS_FIELD(VMX_VMCS16_GUEST_,_SEL));
3221 AssertCompile(VMX_VMCS32_GUEST_SEG_LIMIT(a_iSegReg) == MY_SEG_VMCS_FIELD(VMX_VMCS32_GUEST_,_LIMIT));
3222 AssertCompile(VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(a_iSegReg) == MY_SEG_VMCS_FIELD(VMX_VMCS32_GUEST_,_ACCESS_RIGHTS));
3223
3224 PCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[a_iSegReg];
3225
3226 uint16_t u16Sel;
3227 int rc = VMX_VMCS_READ_16(pVCpu, VMX_VMCS16_GUEST_SEG_SEL(a_iSegReg), &u16Sel); AssertRC(rc);
3228 pSelReg->Sel = u16Sel;
3229 pSelReg->ValidSel = u16Sel;
3230
3231 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_SEG_LIMIT(a_iSegReg), &pSelReg->u32Limit); AssertRC(rc);
3232 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_SEG_BASE(a_iSegReg), &pSelReg->u64Base); AssertRC(rc);
3233
3234 uint32_t u32Attr;
3235 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(a_iSegReg), &u32Attr); AssertRC(rc);
3236 pSelReg->Attr.u = u32Attr;
3237 if (u32Attr & X86DESCATTR_UNUSABLE)
3238 vmxHCFixUnusableSegRegAttr(pVCpu, pSelReg, "ES\0CS\0SS\0DS\0FS\0GS" + a_iSegReg * 3);
3239
3240 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
3241}
3242
3243
3244/**
3245 * Imports the guest LDTR from the VMCS into the guest-CPU context.
3246 *
3247 * @param pVCpu The cross context virtual CPU structure.
3248 *
3249 * @remarks Called with interrupts and/or preemption disabled.
3250 */
3251DECL_FORCE_INLINE(void) vmxHCImportGuestLdtr(PVMCPUCC pVCpu)
3252{
3253 uint16_t u16Sel;
3254 uint64_t u64Base;
3255 uint32_t u32Limit, u32Attr;
3256 int rc = VMX_VMCS_READ_16(pVCpu, VMX_VMCS16_GUEST_LDTR_SEL, &u16Sel); AssertRC(rc);
3257 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_LDTR_LIMIT, &u32Limit); AssertRC(rc);
3258 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
3259 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_LDTR_BASE, &u64Base); AssertRC(rc);
3260
3261 pVCpu->cpum.GstCtx.ldtr.Sel = u16Sel;
3262 pVCpu->cpum.GstCtx.ldtr.ValidSel = u16Sel;
3263 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
3264 pVCpu->cpum.GstCtx.ldtr.u32Limit = u32Limit;
3265 pVCpu->cpum.GstCtx.ldtr.u64Base = u64Base;
3266 pVCpu->cpum.GstCtx.ldtr.Attr.u = u32Attr;
3267 if (u32Attr & X86DESCATTR_UNUSABLE)
3268 vmxHCFixUnusableSegRegAttr(pVCpu, &pVCpu->cpum.GstCtx.ldtr, "LDTR");
3269}
3270
3271
3272/**
3273 * Imports the guest TR from the VMCS into the guest-CPU context.
3274 *
3275 * @param pVCpu The cross context virtual CPU structure.
3276 *
3277 * @remarks Called with interrupts and/or preemption disabled.
3278 */
3279DECL_FORCE_INLINE(void) vmxHCImportGuestTr(PVMCPUCC pVCpu)
3280{
3281 uint16_t u16Sel;
3282 uint64_t u64Base;
3283 uint32_t u32Limit, u32Attr;
3284 int rc = VMX_VMCS_READ_16(pVCpu, VMX_VMCS16_GUEST_TR_SEL, &u16Sel); AssertRC(rc);
3285 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_TR_LIMIT, &u32Limit); AssertRC(rc);
3286 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
3287 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_TR_BASE, &u64Base); AssertRC(rc);
3288
3289 pVCpu->cpum.GstCtx.tr.Sel = u16Sel;
3290 pVCpu->cpum.GstCtx.tr.ValidSel = u16Sel;
3291 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
3292 pVCpu->cpum.GstCtx.tr.u32Limit = u32Limit;
3293 pVCpu->cpum.GstCtx.tr.u64Base = u64Base;
3294 pVCpu->cpum.GstCtx.tr.Attr.u = u32Attr;
3295 /* TR is the only selector that can never be unusable. */
3296 Assert(!(u32Attr & X86DESCATTR_UNUSABLE));
3297}
3298
3299
3300/**
3301 * Core: Imports the guest RIP from the VMCS into the guest-CPU context.
3302 *
3303 * @returns The RIP value.
3304 * @param pVCpu The cross context virtual CPU structure.
3305 *
3306 * @remarks Called with interrupts and/or preemption disabled, should not assert!
3307 * @remarks Do -not- call this function directly!
3308 */
3309DECL_FORCE_INLINE(uint64_t) vmxHCImportGuestCoreRip(PVMCPUCC pVCpu)
3310{
3311 uint64_t u64Val;
3312 int const rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_RIP, &u64Val);
3313 AssertRC(rc);
3314
3315 pVCpu->cpum.GstCtx.rip = u64Val;
3316
3317 return u64Val;
3318}
3319
3320
3321/**
3322 * Imports the guest RIP from the VMCS into the guest-CPU context.
3323 *
3324 * @param pVCpu The cross context virtual CPU structure.
3325 *
3326 * @remarks Called with interrupts and/or preemption disabled, should not assert!
3327 * @remarks Do -not- call this function directly, use vmxHCImportGuestState()
3328 * instead!!!
3329 */
3330DECL_FORCE_INLINE(void) vmxHCImportGuestRip(PVMCPUCC pVCpu)
3331{
3332 if (pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_RIP)
3333 {
3334 EMHistoryUpdatePC(pVCpu, vmxHCImportGuestCoreRip(pVCpu), false);
3335 pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_RIP;
3336 }
3337}
3338
3339
3340/**
3341 * Core: Imports the guest RFLAGS from the VMCS into the guest-CPU context.
3342 *
3343 * @param pVCpu The cross context virtual CPU structure.
3344 * @param pVmcsInfo The VMCS info. object.
3345 *
3346 * @remarks Called with interrupts and/or preemption disabled, should not assert!
3347 * @remarks Do -not- call this function directly!
3348 */
3349DECL_FORCE_INLINE(void) vmxHCImportGuestCoreRFlags(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3350{
3351 uint64_t fRFlags;
3352 int const rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_RFLAGS, &fRFlags);
3353 AssertRC(rc);
3354
3355 Assert((fRFlags & X86_EFL_RA1_MASK) == X86_EFL_RA1_MASK);
3356 Assert((fRFlags & ~(uint64_t)(X86_EFL_1 | X86_EFL_LIVE_MASK)) == 0);
3357
3358 pVCpu->cpum.GstCtx.rflags.u = fRFlags;
3359#ifndef IN_NEM_DARWIN
3360 PCVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
3361 if (!pVmcsInfoShared->RealMode.fRealOnV86Active)
3362 { /* mostly likely */ }
3363 else
3364 {
3365 pVCpu->cpum.GstCtx.eflags.Bits.u1VM = 0;
3366 pVCpu->cpum.GstCtx.eflags.Bits.u2IOPL = pVmcsInfoShared->RealMode.Eflags.Bits.u2IOPL;
3367 }
3368#else
3369 RT_NOREF(pVmcsInfo);
3370#endif
3371}
3372
3373
3374/**
3375 * Imports the guest RFLAGS from the VMCS into the guest-CPU context.
3376 *
3377 * @param pVCpu The cross context virtual CPU structure.
3378 * @param pVmcsInfo The VMCS info. object.
3379 *
3380 * @remarks Called with interrupts and/or preemption disabled, should not assert!
3381 * @remarks Do -not- call this function directly, use vmxHCImportGuestState()
3382 * instead!!!
3383 */
3384DECL_FORCE_INLINE(void) vmxHCImportGuestRFlags(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3385{
3386 if (pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_RFLAGS)
3387 {
3388 vmxHCImportGuestCoreRFlags(pVCpu, pVmcsInfo);
3389 pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_RFLAGS;
3390 }
3391}
3392
3393
3394#ifndef IN_NEM_DARWIN
3395/**
3396 * Imports the guest TSX AUX and certain other MSRs from the VMCS into the guest-CPU
3397 * context.
3398 *
3399 * The other MSRs are in the VM-exit MSR-store.
3400 *
3401 * @returns VBox status code.
3402 * @param pVCpu The cross context virtual CPU structure.
3403 * @param pVmcsInfo The VMCS info. object.
3404 * @param fEFlags Saved EFLAGS for restoring the interrupt flag (in case of
3405 * unexpected errors). Ignored in NEM/darwin context.
3406 */
3407DECL_FORCE_INLINE(int) vmxHCImportGuestTscAuxAndOtherMsrs(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, uint32_t fEFlags)
3408{
3409 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
3410 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
3411 uint32_t const cMsrs = pVmcsInfo->cExitMsrStore;
3412 Assert(pMsrs);
3413 Assert(cMsrs <= VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc));
3414 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
3415 for (uint32_t i = 0; i < cMsrs; i++)
3416 {
3417 uint32_t const idMsr = pMsrs[i].u32Msr;
3418 switch (idMsr)
3419 {
3420 case MSR_K8_TSC_AUX: CPUMSetGuestTscAux(pVCpu, pMsrs[i].u64Value); break;
3421 case MSR_IA32_SPEC_CTRL: CPUMSetGuestSpecCtrl(pVCpu, pMsrs[i].u64Value); break;
3422 case MSR_K6_EFER: /* Can't be changed without causing a VM-exit */ break;
3423 default:
3424 {
3425 uint32_t idxLbrMsr;
3426 PVMCC const pVM = pVCpu->CTX_SUFF(pVM);
3427 if (VM_IS_VMX_LBR(pVM))
3428 {
3429 if (hmR0VmxIsLbrBranchFromMsr(pVM, idMsr, &idxLbrMsr))
3430 {
3431 Assert(idxLbrMsr < RT_ELEMENTS(pVmcsInfoShared->au64LbrFromIpMsr));
3432 pVmcsInfoShared->au64LbrFromIpMsr[idxLbrMsr] = pMsrs[i].u64Value;
3433 break;
3434 }
3435 if (hmR0VmxIsLbrBranchToMsr(pVM, idMsr, &idxLbrMsr))
3436 {
3437 Assert(idxLbrMsr < RT_ELEMENTS(pVmcsInfoShared->au64LbrFromIpMsr));
3438 pVmcsInfoShared->au64LbrToIpMsr[idxLbrMsr] = pMsrs[i].u64Value;
3439 break;
3440 }
3441 if (idMsr == pVM->hmr0.s.vmx.idLbrTosMsr)
3442 {
3443 pVmcsInfoShared->u64LbrTosMsr = pMsrs[i].u64Value;
3444 break;
3445 }
3446 /* Fallthru (no break) */
3447 }
3448 pVCpu->cpum.GstCtx.fExtrn = 0;
3449 VCPU_2_VMXSTATE(pVCpu).u32HMError = pMsrs->u32Msr;
3450 ASMSetFlags(fEFlags);
3451 AssertMsgFailed(("Unexpected MSR in auto-load/store area. idMsr=%#RX32 cMsrs=%u\n", idMsr, cMsrs));
3452 return VERR_HM_UNEXPECTED_LD_ST_MSR;
3453 }
3454 }
3455 }
3456 return VINF_SUCCESS;
3457}
3458#endif /* !IN_NEM_DARWIN */
3459
3460
3461/**
3462 * Imports the guest CR0 from the VMCS into the guest-CPU context.
3463 *
3464 * @param pVCpu The cross context virtual CPU structure.
3465 * @param pVmcsInfo The VMCS info. object.
3466 */
3467DECL_FORCE_INLINE(void) vmxHCImportGuestCr0(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3468{
3469 uint64_t u64Cr0;
3470 uint64_t u64Shadow;
3471 int rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_CR0, &u64Cr0); AssertRC(rc);
3472 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Shadow); AssertRC(rc);
3473#ifndef VBOX_WITH_NESTED_HWVIRT_VMX
3474 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
3475 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
3476#else
3477 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
3478 {
3479 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
3480 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
3481 }
3482 else
3483 {
3484 /*
3485 * We've merged the guest and nested-guest's CR0 guest/host mask while executing
3486 * the nested-guest using hardware-assisted VMX. Accordingly we need to
3487 * re-construct CR0. See @bugref{9180#c95} for details.
3488 */
3489 PCVMXVMCSINFO const pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
3490 PVMXVVMCS const pVmcsNstGst = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
3491 u64Cr0 = (u64Cr0 & ~(pVmcsInfoGst->u64Cr0Mask & pVmcsNstGst->u64Cr0Mask.u))
3492 | (pVmcsNstGst->u64GuestCr0.u & pVmcsNstGst->u64Cr0Mask.u)
3493 | (u64Shadow & (pVmcsInfoGst->u64Cr0Mask & ~pVmcsNstGst->u64Cr0Mask.u));
3494 Assert(u64Cr0 & X86_CR0_NE);
3495 }
3496#endif
3497
3498#ifndef IN_NEM_DARWIN
3499 VMMRZCallRing3Disable(pVCpu); /* May call into PGM which has Log statements. */
3500#endif
3501 CPUMSetGuestCR0(pVCpu, u64Cr0);
3502#ifndef IN_NEM_DARWIN
3503 VMMRZCallRing3Enable(pVCpu);
3504#endif
3505}
3506
3507
3508/**
3509 * Imports the guest CR3 from the VMCS into the guest-CPU context.
3510 *
3511 * @param pVCpu The cross context virtual CPU structure.
3512 */
3513DECL_FORCE_INLINE(void) vmxHCImportGuestCr3(PVMCPUCC pVCpu)
3514{
3515 PVMCC const pVM = pVCpu->CTX_SUFF(pVM);
3516 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
3517
3518 /* CR0.PG bit changes are always intercepted, so it's up to date. */
3519 if ( VM_IS_VMX_UNRESTRICTED_GUEST(pVM)
3520 || ( VM_IS_VMX_NESTED_PAGING(pVM)
3521 && CPUMIsGuestPagingEnabledEx(pCtx)))
3522 {
3523 uint64_t u64Cr3;
3524 int rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_CR3, &u64Cr3); AssertRC(rc);
3525 if (pCtx->cr3 != u64Cr3)
3526 {
3527 pCtx->cr3 = u64Cr3;
3528 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
3529 }
3530
3531 /*
3532 * If the guest is in PAE mode, sync back the PDPE's into the guest state.
3533 * CR4.PAE, CR0.PG, EFER MSR changes are always intercepted, so they're up to date.
3534 */
3535 if (CPUMIsGuestInPAEModeEx(pCtx))
3536 {
3537 X86PDPE aPaePdpes[4];
3538 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_PDPTE0_FULL, &aPaePdpes[0].u); AssertRC(rc);
3539 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_PDPTE1_FULL, &aPaePdpes[1].u); AssertRC(rc);
3540 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_PDPTE2_FULL, &aPaePdpes[2].u); AssertRC(rc);
3541 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_PDPTE3_FULL, &aPaePdpes[3].u); AssertRC(rc);
3542 if (memcmp(&aPaePdpes[0], &pCtx->aPaePdpes[0], sizeof(aPaePdpes)))
3543 {
3544 memcpy(&pCtx->aPaePdpes[0], &aPaePdpes[0], sizeof(aPaePdpes));
3545 /* PGM now updates PAE PDPTEs while updating CR3. */
3546 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
3547 }
3548 }
3549 }
3550}
3551
3552
3553/**
3554 * Imports the guest CR4 from the VMCS into the guest-CPU context.
3555 *
3556 * @param pVCpu The cross context virtual CPU structure.
3557 * @param pVmcsInfo The VMCS info. object.
3558 */
3559DECL_FORCE_INLINE(void) vmxHCImportGuestCr4(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3560{
3561 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
3562 uint64_t u64Cr4;
3563 uint64_t u64Shadow;
3564 int rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_CR4, &u64Cr4); AssertRC(rc);
3565 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Shadow); AssertRC(rc);
3566#ifndef VBOX_WITH_NESTED_HWVIRT_VMX
3567 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
3568 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
3569#else
3570 if (!CPUMIsGuestInVmxNonRootMode(pCtx))
3571 {
3572 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
3573 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
3574 }
3575 else
3576 {
3577 /*
3578 * We've merged the guest and nested-guest's CR4 guest/host mask while executing
3579 * the nested-guest using hardware-assisted VMX. Accordingly we need to
3580 * re-construct CR4. See @bugref{9180#c95} for details.
3581 */
3582 PCVMXVMCSINFO const pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
3583 PVMXVVMCS const pVmcsNstGst = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
3584 u64Cr4 = (u64Cr4 & ~(pVmcsInfo->u64Cr4Mask & pVmcsNstGst->u64Cr4Mask.u))
3585 | (pVmcsNstGst->u64GuestCr4.u & pVmcsNstGst->u64Cr4Mask.u)
3586 | (u64Shadow & (pVmcsInfoGst->u64Cr4Mask & ~pVmcsNstGst->u64Cr4Mask.u));
3587 Assert(u64Cr4 & X86_CR4_VMXE);
3588 }
3589#endif
3590 pCtx->cr4 = u64Cr4;
3591}
3592
3593
3594/**
3595 * Worker for vmxHCImportGuestIntrState that handles the case where any of the
3596 * relevant VMX_VMCS32_GUEST_INT_STATE bits are set.
3597 */
3598DECL_NO_INLINE(static,void) vmxHCImportGuestIntrStateSlow(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, uint32_t fGstIntState)
3599{
3600 /*
3601 * We must import RIP here to set our EM interrupt-inhibited state.
3602 * We also import RFLAGS as our code that evaluates pending interrupts
3603 * before VM-entry requires it.
3604 */
3605 vmxHCImportGuestRip(pVCpu);
3606 vmxHCImportGuestRFlags(pVCpu, pVmcsInfo);
3607
3608 CPUMUpdateInterruptShadowSsStiEx(&pVCpu->cpum.GstCtx,
3609 RT_BOOL(fGstIntState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
3610 RT_BOOL(fGstIntState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
3611 pVCpu->cpum.GstCtx.rip);
3612 CPUMUpdateInterruptInhibitingByNmiEx(&pVCpu->cpum.GstCtx, RT_BOOL(fGstIntState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI));
3613}
3614
3615
3616/**
3617 * Imports the guest interruptibility-state from the VMCS into the guest-CPU
3618 * context.
3619 *
3620 * @note May import RIP and RFLAGS if interrupt or NMI are blocked.
3621 *
3622 * @param pVCpu The cross context virtual CPU structure.
3623 * @param pVmcsInfo The VMCS info. object.
3624 *
3625 * @remarks Called with interrupts and/or preemption disabled, try not to assert and
3626 * do not log!
3627 * @remarks Do -not- call this function directly, use vmxHCImportGuestState()
3628 * instead!!!
3629 */
3630DECLINLINE(void) vmxHCImportGuestIntrState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3631{
3632 uint32_t u32Val;
3633 int rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_INT_STATE, &u32Val); AssertRC(rc);
3634 Assert((u32Val & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
3635 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
3636 if (!u32Val)
3637 {
3638 CPUMClearInterruptShadow(&pVCpu->cpum.GstCtx);
3639 CPUMClearInterruptInhibitingByNmiEx(&pVCpu->cpum.GstCtx);
3640 }
3641 else
3642 vmxHCImportGuestIntrStateSlow(pVCpu, pVmcsInfo, u32Val);
3643}
3644
3645
3646/**
3647 * Worker for VMXR0ImportStateOnDemand.
3648 *
3649 * @returns VBox status code.
3650 * @param pVCpu The cross context virtual CPU structure.
3651 * @param pVmcsInfo The VMCS info. object.
3652 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
3653 */
3654static int vmxHCImportGuestStateEx(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
3655{
3656 int rc = VINF_SUCCESS;
3657 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3658 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
3659 uint32_t u32Val;
3660
3661 /*
3662 * Note! This is hack to workaround a mysterious BSOD observed with release builds
3663 * on Windows 10 64-bit hosts. Profile and debug builds are not affected and
3664 * neither are other host platforms.
3665 *
3666 * Committing this temporarily as it prevents BSOD.
3667 *
3668 * Update: This is very likely a compiler optimization bug, see @bugref{9180}.
3669 */
3670#ifdef RT_OS_WINDOWS
3671 if (pVM == 0 || pVM == (void *)(uintptr_t)-1)
3672 return VERR_HM_IPE_1;
3673#endif
3674
3675 STAM_PROFILE_ADV_START(&VCPU_2_VMXSTATS(pVCpu).StatImportGuestState, x);
3676
3677#ifndef IN_NEM_DARWIN
3678 /*
3679 * We disable interrupts to make the updating of the state and in particular
3680 * the fExtrn modification atomic wrt to preemption hooks.
3681 */
3682 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
3683#endif
3684
3685 fWhat &= pCtx->fExtrn;
3686 if (fWhat)
3687 {
3688 do
3689 {
3690 if (fWhat & CPUMCTX_EXTRN_RIP)
3691 vmxHCImportGuestRip(pVCpu);
3692
3693 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
3694 vmxHCImportGuestRFlags(pVCpu, pVmcsInfo);
3695
3696 /* Note! vmxHCImportGuestIntrState may also include RIP and RFLAGS and update fExtrn. */
3697 if (fWhat & (CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI))
3698 vmxHCImportGuestIntrState(pVCpu, pVmcsInfo);
3699
3700 if (fWhat & CPUMCTX_EXTRN_RSP)
3701 {
3702 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_RSP, &pCtx->rsp);
3703 AssertRC(rc);
3704 }
3705
3706 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
3707 {
3708 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
3709#ifndef IN_NEM_DARWIN
3710 bool const fRealOnV86Active = pVmcsInfoShared->RealMode.fRealOnV86Active;
3711#else
3712 bool const fRealOnV86Active = false; /* HV supports only unrestricted guest execution. */
3713#endif
3714 if (fWhat & CPUMCTX_EXTRN_CS)
3715 {
3716 vmxHCImportGuestSegReg<X86_SREG_CS>(pVCpu);
3717 vmxHCImportGuestRip(pVCpu); /** @todo WTF? */
3718 if (fRealOnV86Active)
3719 pCtx->cs.Attr.u = pVmcsInfoShared->RealMode.AttrCS.u;
3720 EMHistoryUpdatePC(pVCpu, pCtx->cs.u64Base + pCtx->rip, true /* fFlattened */);
3721 }
3722 if (fWhat & CPUMCTX_EXTRN_SS)
3723 {
3724 vmxHCImportGuestSegReg<X86_SREG_SS>(pVCpu);
3725 if (fRealOnV86Active)
3726 pCtx->ss.Attr.u = pVmcsInfoShared->RealMode.AttrSS.u;
3727 }
3728 if (fWhat & CPUMCTX_EXTRN_DS)
3729 {
3730 vmxHCImportGuestSegReg<X86_SREG_DS>(pVCpu);
3731 if (fRealOnV86Active)
3732 pCtx->ds.Attr.u = pVmcsInfoShared->RealMode.AttrDS.u;
3733 }
3734 if (fWhat & CPUMCTX_EXTRN_ES)
3735 {
3736 vmxHCImportGuestSegReg<X86_SREG_ES>(pVCpu);
3737 if (fRealOnV86Active)
3738 pCtx->es.Attr.u = pVmcsInfoShared->RealMode.AttrES.u;
3739 }
3740 if (fWhat & CPUMCTX_EXTRN_FS)
3741 {
3742 vmxHCImportGuestSegReg<X86_SREG_FS>(pVCpu);
3743 if (fRealOnV86Active)
3744 pCtx->fs.Attr.u = pVmcsInfoShared->RealMode.AttrFS.u;
3745 }
3746 if (fWhat & CPUMCTX_EXTRN_GS)
3747 {
3748 vmxHCImportGuestSegReg<X86_SREG_GS>(pVCpu);
3749 if (fRealOnV86Active)
3750 pCtx->gs.Attr.u = pVmcsInfoShared->RealMode.AttrGS.u;
3751 }
3752 }
3753
3754 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
3755 {
3756 if (fWhat & CPUMCTX_EXTRN_LDTR)
3757 vmxHCImportGuestLdtr(pVCpu);
3758
3759 if (fWhat & CPUMCTX_EXTRN_GDTR)
3760 {
3761 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_GDTR_BASE, &pCtx->gdtr.pGdt); AssertRC(rc);
3762 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRC(rc);
3763 pCtx->gdtr.cbGdt = u32Val;
3764 }
3765
3766 /* Guest IDTR. */
3767 if (fWhat & CPUMCTX_EXTRN_IDTR)
3768 {
3769 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_IDTR_BASE, &pCtx->idtr.pIdt); AssertRC(rc);
3770 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRC(rc);
3771 pCtx->idtr.cbIdt = u32Val;
3772 }
3773
3774 /* Guest TR. */
3775 if (fWhat & CPUMCTX_EXTRN_TR)
3776 {
3777#ifndef IN_NEM_DARWIN
3778 /* Real-mode emulation using virtual-8086 mode has the fake TSS (pRealModeTSS) in TR,
3779 don't need to import that one. */
3780 if (!pVmcsInfo->pShared->RealMode.fRealOnV86Active)
3781#endif
3782 vmxHCImportGuestTr(pVCpu);
3783 }
3784 }
3785
3786 if (fWhat & CPUMCTX_EXTRN_DR7)
3787 {
3788#ifndef IN_NEM_DARWIN
3789 if (!pVCpu->hmr0.s.fUsingHyperDR7)
3790#endif
3791 {
3792 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_DR7, &pCtx->dr[7]);
3793 AssertRC(rc);
3794 }
3795 }
3796
3797 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
3798 {
3799 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_SYSENTER_EIP, &pCtx->SysEnter.eip); AssertRC(rc);
3800 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_SYSENTER_ESP, &pCtx->SysEnter.esp); AssertRC(rc);
3801 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRC(rc);
3802 pCtx->SysEnter.cs = u32Val;
3803 }
3804
3805#ifndef IN_NEM_DARWIN
3806 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
3807 {
3808 if ( pVM->hmr0.s.fAllow64BitGuests
3809 && (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
3810 pCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
3811 }
3812
3813 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
3814 {
3815 if ( pVM->hmr0.s.fAllow64BitGuests
3816 && (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
3817 {
3818 pCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
3819 pCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
3820 pCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
3821 }
3822 }
3823
3824 if (fWhat & (CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS))
3825 {
3826 rc = vmxHCImportGuestTscAuxAndOtherMsrs(pVCpu, pVmcsInfo, fEFlags);
3827 AssertRCReturn(rc, rc);
3828 }
3829#else
3830 NOREF(pVM);
3831#endif
3832
3833 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
3834 {
3835 if (fWhat & CPUMCTX_EXTRN_CR0)
3836 vmxHCImportGuestCr0(pVCpu, pVmcsInfo);
3837
3838 if (fWhat & CPUMCTX_EXTRN_CR4)
3839 vmxHCImportGuestCr4(pVCpu, pVmcsInfo);
3840
3841 if (fWhat & CPUMCTX_EXTRN_CR3)
3842 vmxHCImportGuestCr3(pVCpu);
3843 }
3844
3845#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3846 if (fWhat & CPUMCTX_EXTRN_HWVIRT)
3847 {
3848 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
3849 && !CPUMIsGuestInVmxNonRootMode(pCtx))
3850 {
3851 Assert(CPUMIsGuestInVmxRootMode(pCtx));
3852 rc = vmxHCCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
3853 if (RT_SUCCESS(rc))
3854 { /* likely */ }
3855 else
3856 break;
3857 }
3858 }
3859#endif
3860 } while (0);
3861
3862 if (RT_SUCCESS(rc))
3863 {
3864 /* Update fExtrn. */
3865 pCtx->fExtrn &= ~fWhat;
3866
3867 /* If everything has been imported, clear the HM keeper bit. */
3868 if (!(pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL))
3869 {
3870#ifndef IN_NEM_DARWIN
3871 pCtx->fExtrn &= ~CPUMCTX_EXTRN_KEEPER_HM;
3872#else
3873 pCtx->fExtrn &= ~CPUMCTX_EXTRN_KEEPER_NEM;
3874#endif
3875 Assert(!pCtx->fExtrn);
3876 }
3877 }
3878 }
3879#ifndef IN_NEM_DARWIN
3880 else
3881 AssertMsg(!pCtx->fExtrn || (pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL), ("%#RX64\n", pCtx->fExtrn));
3882
3883 /*
3884 * Restore interrupts.
3885 */
3886 ASMSetFlags(fEFlags);
3887#endif
3888
3889 STAM_PROFILE_ADV_STOP(&VCPU_2_VMXSTATS(pVCpu).StatImportGuestState, x);
3890
3891 if (RT_SUCCESS(rc))
3892 { /* likely */ }
3893 else
3894 return rc;
3895
3896 /*
3897 * Honor any pending CR3 updates.
3898 *
3899 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> VMXR0CallRing3Callback()
3900 * -> VMMRZCallRing3Disable() -> vmxHCImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
3901 * -> continue with VM-exit handling -> vmxHCImportGuestState() and here we are.
3902 *
3903 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
3904 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
3905 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
3906 * -NOT- check if CPUMCTX_EXTRN_CR3 is set!
3907 *
3908 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
3909 *
3910 * The force-flag is checked first as it's cheaper for potential superfluous calls to this function.
3911 */
3912 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3)
3913#ifndef IN_NEM_DARWIN
3914 && VMMRZCallRing3IsEnabled(pVCpu)
3915#endif
3916 )
3917 {
3918 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & CPUMCTX_EXTRN_CR3));
3919 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
3920 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
3921 }
3922
3923 return VINF_SUCCESS;
3924}
3925
3926
3927/**
3928 * Internal state fetcher, inner version where we fetch all of a_fWhat.
3929 *
3930 * @returns VBox status code.
3931 * @param pVCpu The cross context virtual CPU structure.
3932 * @param pVmcsInfo The VMCS info. object.
3933 * @param fEFlags Saved EFLAGS for restoring the interrupt flag. Ignored
3934 * in NEM/darwin context.
3935 * @tparam a_fWhat What to import, zero or more bits from
3936 * HMVMX_CPUMCTX_EXTRN_ALL.
3937 */
3938template<uint64_t const a_fWhat>
3939static int vmxHCImportGuestStateInner(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t fEFlags)
3940{
3941 Assert(a_fWhat != 0); /* No AssertCompile as the assertion probably kicks in before the compiler (clang) discards it. */
3942 AssertCompile(!(a_fWhat & ~HMVMX_CPUMCTX_EXTRN_ALL));
3943 Assert( (pVCpu->cpum.GstCtx.fExtrn & a_fWhat) == a_fWhat
3944 || (pVCpu->cpum.GstCtx.fExtrn & a_fWhat) == (a_fWhat & ~(CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS)));
3945
3946 STAM_PROFILE_ADV_STOP(&VCPU_2_VMXSTATS(pVCpu).StatImportGuestState, x);
3947
3948 PVMCC const pVM = pVCpu->CTX_SUFF(pVM);
3949
3950 /* RIP and RFLAGS may have been imported already by the post exit code
3951 together with the CPUMCTX_EXTRN_INHIBIT_INT/NMI state, so this part
3952 of the code is skipping this part of the code. */
3953 if ( (a_fWhat & (CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS))
3954 && pVCpu->cpum.GstCtx.fExtrn & (CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS))
3955 {
3956 if (a_fWhat & CPUMCTX_EXTRN_RFLAGS)
3957 vmxHCImportGuestCoreRFlags(pVCpu, pVmcsInfo);
3958
3959 if (a_fWhat & CPUMCTX_EXTRN_RIP)
3960 {
3961 if (!(a_fWhat & CPUMCTX_EXTRN_CS))
3962 EMHistoryUpdatePC(pVCpu, vmxHCImportGuestCoreRip(pVCpu), false);
3963 else
3964 vmxHCImportGuestCoreRip(pVCpu);
3965 }
3966 }
3967
3968 /* Note! vmxHCImportGuestIntrState may also include RIP and RFLAGS and update fExtrn. */
3969 if (a_fWhat & (CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI))
3970 vmxHCImportGuestIntrState(pVCpu, pVmcsInfo);
3971
3972 if (a_fWhat & (CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TR))
3973 {
3974 if (a_fWhat & CPUMCTX_EXTRN_CS)
3975 {
3976 vmxHCImportGuestSegReg<X86_SREG_CS>(pVCpu);
3977 /** @todo try get rid of this carp, it smells and is probably never ever
3978 * used: */
3979 if ( !(a_fWhat & CPUMCTX_EXTRN_RIP)
3980 && (pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_RIP))
3981 {
3982 vmxHCImportGuestCoreRip(pVCpu);
3983 pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_RIP;
3984 }
3985 EMHistoryUpdatePC(pVCpu, pVCpu->cpum.GstCtx.cs.u64Base + pVCpu->cpum.GstCtx.rip, true /* fFlattened */);
3986 }
3987 if (a_fWhat & CPUMCTX_EXTRN_SS)
3988 vmxHCImportGuestSegReg<X86_SREG_SS>(pVCpu);
3989 if (a_fWhat & CPUMCTX_EXTRN_DS)
3990 vmxHCImportGuestSegReg<X86_SREG_DS>(pVCpu);
3991 if (a_fWhat & CPUMCTX_EXTRN_ES)
3992 vmxHCImportGuestSegReg<X86_SREG_ES>(pVCpu);
3993 if (a_fWhat & CPUMCTX_EXTRN_FS)
3994 vmxHCImportGuestSegReg<X86_SREG_FS>(pVCpu);
3995 if (a_fWhat & CPUMCTX_EXTRN_GS)
3996 vmxHCImportGuestSegReg<X86_SREG_GS>(pVCpu);
3997
3998 /* Guest TR.
3999 Real-mode emulation using virtual-8086 mode has the fake TSS
4000 (pRealModeTSS) in TR, don't need to import that one. */
4001#ifndef IN_NEM_DARWIN
4002 PVMXVMCSINFOSHARED const pVmcsInfoShared = pVmcsInfo->pShared;
4003 bool const fRealOnV86Active = pVmcsInfoShared->RealMode.fRealOnV86Active;
4004 if ((a_fWhat & CPUMCTX_EXTRN_TR) && !fRealOnV86Active)
4005#else
4006 if (a_fWhat & CPUMCTX_EXTRN_TR)
4007#endif
4008 vmxHCImportGuestTr(pVCpu);
4009
4010#ifndef IN_NEM_DARWIN /* NEM/Darwin: HV supports only unrestricted guest execution. */
4011 if (fRealOnV86Active)
4012 {
4013 if (a_fWhat & CPUMCTX_EXTRN_CS)
4014 pVCpu->cpum.GstCtx.cs.Attr.u = pVmcsInfoShared->RealMode.AttrCS.u;
4015 if (a_fWhat & CPUMCTX_EXTRN_SS)
4016 pVCpu->cpum.GstCtx.ss.Attr.u = pVmcsInfoShared->RealMode.AttrSS.u;
4017 if (a_fWhat & CPUMCTX_EXTRN_DS)
4018 pVCpu->cpum.GstCtx.ds.Attr.u = pVmcsInfoShared->RealMode.AttrDS.u;
4019 if (a_fWhat & CPUMCTX_EXTRN_ES)
4020 pVCpu->cpum.GstCtx.es.Attr.u = pVmcsInfoShared->RealMode.AttrES.u;
4021 if (a_fWhat & CPUMCTX_EXTRN_FS)
4022 pVCpu->cpum.GstCtx.fs.Attr.u = pVmcsInfoShared->RealMode.AttrFS.u;
4023 if (a_fWhat & CPUMCTX_EXTRN_GS)
4024 pVCpu->cpum.GstCtx.gs.Attr.u = pVmcsInfoShared->RealMode.AttrGS.u;
4025 }
4026#endif
4027 }
4028
4029 if (a_fWhat & CPUMCTX_EXTRN_RSP)
4030 {
4031 int const rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_RSP, &pVCpu->cpum.GstCtx.rsp);
4032 AssertRC(rc);
4033 }
4034
4035 if (a_fWhat & CPUMCTX_EXTRN_LDTR)
4036 vmxHCImportGuestLdtr(pVCpu);
4037
4038 if (a_fWhat & CPUMCTX_EXTRN_GDTR)
4039 {
4040 int const rc1 = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_GDTR_BASE, &pVCpu->cpum.GstCtx.gdtr.pGdt); AssertRC(rc1);
4041 uint32_t u32Val;
4042 int const rc2 = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRC(rc2);
4043 pVCpu->cpum.GstCtx.gdtr.cbGdt = (uint16_t)u32Val;
4044 }
4045
4046 /* Guest IDTR. */
4047 if (a_fWhat & CPUMCTX_EXTRN_IDTR)
4048 {
4049 int const rc1 = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_IDTR_BASE, &pVCpu->cpum.GstCtx.idtr.pIdt); AssertRC(rc1);
4050 uint32_t u32Val;
4051 int const rc2 = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRC(rc2);
4052 pVCpu->cpum.GstCtx.idtr.cbIdt = (uint64_t)u32Val;
4053 }
4054
4055 if (a_fWhat & CPUMCTX_EXTRN_DR7)
4056 {
4057#ifndef IN_NEM_DARWIN
4058 if (!pVCpu->hmr0.s.fUsingHyperDR7)
4059#endif
4060 {
4061 int rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_DR7, &pVCpu->cpum.GstCtx.dr[7]);
4062 AssertRC(rc);
4063 }
4064 }
4065
4066 if (a_fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
4067 {
4068 int const rc1 = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_SYSENTER_EIP, &pVCpu->cpum.GstCtx.SysEnter.eip); AssertRC(rc1);
4069 int const rc2 = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_SYSENTER_ESP, &pVCpu->cpum.GstCtx.SysEnter.esp); AssertRC(rc2);
4070 uint32_t u32Val;
4071 int const rc3 = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRC(rc3);
4072 pVCpu->cpum.GstCtx.SysEnter.cs = u32Val;
4073 }
4074
4075#ifndef IN_NEM_DARWIN
4076 if (a_fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
4077 {
4078 if ( (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
4079 && pVM->hmr0.s.fAllow64BitGuests)
4080 pVCpu->cpum.GstCtx.msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
4081 }
4082
4083 if (a_fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
4084 {
4085 if ( (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
4086 && pVM->hmr0.s.fAllow64BitGuests)
4087 {
4088 pVCpu->cpum.GstCtx.msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
4089 pVCpu->cpum.GstCtx.msrSTAR = ASMRdMsr(MSR_K6_STAR);
4090 pVCpu->cpum.GstCtx.msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
4091 }
4092 }
4093
4094 if (a_fWhat & (CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS))
4095 {
4096 int const rc1 = vmxHCImportGuestTscAuxAndOtherMsrs(pVCpu, pVmcsInfo, fEFlags);
4097 AssertRCReturn(rc1, rc1);
4098 }
4099#else
4100 NOREF(pVM);
4101#endif
4102
4103 if (a_fWhat & CPUMCTX_EXTRN_CR0)
4104 vmxHCImportGuestCr0(pVCpu, pVmcsInfo);
4105
4106 if (a_fWhat & CPUMCTX_EXTRN_CR4)
4107 vmxHCImportGuestCr4(pVCpu, pVmcsInfo);
4108
4109 if (a_fWhat & CPUMCTX_EXTRN_CR3)
4110 vmxHCImportGuestCr3(pVCpu);
4111
4112#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4113 if (a_fWhat & CPUMCTX_EXTRN_HWVIRT)
4114 {
4115 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
4116 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
4117 {
4118 Assert(CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx));
4119 int const rc = vmxHCCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
4120 AssertRCReturn(rc, rc);
4121 }
4122 }
4123#endif
4124
4125 /* Update fExtrn. */
4126 pVCpu->cpum.GstCtx.fExtrn &= ~a_fWhat;
4127
4128 /* If everything has been imported, clear the HM keeper bit. */
4129 if (!(pVCpu->cpum.GstCtx.fExtrn & HMVMX_CPUMCTX_EXTRN_ALL))
4130 {
4131#ifndef IN_NEM_DARWIN
4132 pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_KEEPER_HM;
4133#else
4134 pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_KEEPER_NEM;
4135#endif
4136 Assert(!pVCpu->cpum.GstCtx.fExtrn);
4137 }
4138
4139 STAM_PROFILE_ADV_STOP(&VCPU_2_VMXSTATS(pVCpu).StatImportGuestState, x);
4140
4141 /*
4142 * Honor any pending CR3 updates.
4143 *
4144 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> VMXR0CallRing3Callback()
4145 * -> VMMRZCallRing3Disable() -> vmxHCImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
4146 * -> continue with VM-exit handling -> vmxHCImportGuestState() and here we are.
4147 *
4148 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
4149 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
4150 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
4151 * -NOT- check if CPUMCTX_EXTRN_CR3 is set!
4152 *
4153 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
4154 *
4155 * The force-flag is checked first as it's cheaper for potential superfluous calls to this function.
4156 */
4157#ifndef IN_NEM_DARWIN
4158 if (!(a_fWhat & CPUMCTX_EXTRN_CR3)
4159 ? RT_LIKELY(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3) || !VMMRZCallRing3IsEnabled(pVCpu))
4160 : !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3) || !VMMRZCallRing3IsEnabled(pVCpu) )
4161 return VINF_SUCCESS;
4162 ASMSetFlags(fEFlags);
4163#else
4164 if (!(a_fWhat & CPUMCTX_EXTRN_CR3)
4165 ? RT_LIKELY(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
4166 : !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3) )
4167 return VINF_SUCCESS;
4168 RT_NOREF_PV(fEFlags);
4169#endif
4170
4171 Assert(!(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_CR3));
4172 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
4173 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
4174 return VINF_SUCCESS;
4175}
4176
4177
4178/**
4179 * Internal state fetcher.
4180 *
4181 * @returns VBox status code.
4182 * @param pVCpu The cross context virtual CPU structure.
4183 * @param pVmcsInfo The VMCS info. object.
4184 * @param pszCaller For logging.
4185 * @tparam a_fWhat What needs to be imported, CPUMCTX_EXTRN_XXX.
4186 * @tparam a_fDoneLocal What's ASSUMED to have been retrieved locally
4187 * already. This is ORed together with @a a_fWhat when
4188 * calculating what needs fetching (just for safety).
4189 * @tparam a_fDonePostExit What's ASSUMED to been been retrieved by
4190 * hmR0VmxPostRunGuest()/nemR3DarwinHandleExitCommon()
4191 * already. This is ORed together with @a a_fWhat when
4192 * calculating what needs fetching (just for safety).
4193 */
4194template<uint64_t const a_fWhat,
4195 uint64_t const a_fDoneLocal = 0,
4196 uint64_t const a_fDonePostExit = 0
4197#ifndef IN_NEM_DARWIN
4198 | CPUMCTX_EXTRN_INHIBIT_INT
4199 | CPUMCTX_EXTRN_INHIBIT_NMI
4200# if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
4201 | HMVMX_CPUMCTX_EXTRN_ALL
4202# elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
4203 | CPUMCTX_EXTRN_RFLAGS
4204# endif
4205#else /* IN_NEM_DARWIN */
4206 | CPUMCTX_EXTRN_ALL /** @todo optimize */
4207#endif /* IN_NEM_DARWIN */
4208>
4209DECLINLINE(int) vmxHCImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, const char *pszCaller)
4210{
4211 RT_NOREF_PV(pszCaller);
4212 if ((a_fWhat | a_fDoneLocal | a_fDonePostExit) & HMVMX_CPUMCTX_EXTRN_ALL)
4213 {
4214#ifndef IN_NEM_DARWIN
4215 /*
4216 * We disable interrupts to make the updating of the state and in particular
4217 * the fExtrn modification atomic wrt to preemption hooks.
4218 */
4219 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
4220#else
4221 RTCCUINTREG const fEFlags = 0;
4222#endif
4223
4224 /*
4225 * We combine all three parameters and take the (probably) inlined optimized
4226 * code path for the new things specified in a_fWhat.
4227 *
4228 * As a tweak to deal with exits that have INHIBIT_INT/NMI active, causing
4229 * vmxHCImportGuestIntrState to automatically fetch both RIP & RFLAGS, we
4230 * also take the streamlined path when both of these are cleared in fExtrn
4231 * already. vmxHCImportGuestStateInner checks fExtrn before fetching. This
4232 * helps with MWAIT and HLT exits that always inhibit IRQs on many platforms.
4233 */
4234 uint64_t const fWhatToDo = pVCpu->cpum.GstCtx.fExtrn
4235 & ((a_fWhat | a_fDoneLocal | a_fDonePostExit) & HMVMX_CPUMCTX_EXTRN_ALL);
4236 if (RT_LIKELY( ( fWhatToDo == (a_fWhat & HMVMX_CPUMCTX_EXTRN_ALL & ~(a_fDoneLocal | a_fDonePostExit))
4237 || fWhatToDo == ( a_fWhat & HMVMX_CPUMCTX_EXTRN_ALL & ~(a_fDoneLocal | a_fDonePostExit)
4238 & ~(CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS)) /* fetch with INHIBIT_INT/NMI */))
4239 && (a_fWhat & HMVMX_CPUMCTX_EXTRN_ALL & ~(a_fDoneLocal | a_fDonePostExit)) != 0 /* just in case */)
4240 {
4241 int const rc = vmxHCImportGuestStateInner< a_fWhat
4242 & HMVMX_CPUMCTX_EXTRN_ALL
4243 & ~(a_fDoneLocal | a_fDonePostExit)>(pVCpu, pVmcsInfo, fEFlags);
4244#ifndef IN_NEM_DARWIN
4245 ASMSetFlags(fEFlags);
4246#endif
4247 return rc;
4248 }
4249
4250#ifndef IN_NEM_DARWIN
4251 ASMSetFlags(fEFlags);
4252#endif
4253
4254 /*
4255 * We shouldn't normally get here, but it may happen when executing
4256 * in the debug run-loops. Typically, everything should already have
4257 * been fetched then. Otherwise call the fallback state import function.
4258 */
4259 if (fWhatToDo == 0)
4260 { /* hope the cause was the debug loop or something similar */ }
4261 else
4262 {
4263 STAM_REL_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatImportGuestStateFallback);
4264 Log11Func(("a_fWhat=%#RX64/%#RX64/%#RX64 fExtrn=%#RX64 => %#RX64 - Taking inefficient code path from %s!\n",
4265 a_fWhat & HMVMX_CPUMCTX_EXTRN_ALL, a_fDoneLocal & HMVMX_CPUMCTX_EXTRN_ALL,
4266 a_fDonePostExit & HMVMX_CPUMCTX_EXTRN_ALL, pVCpu->cpum.GstCtx.fExtrn, fWhatToDo, pszCaller));
4267 return vmxHCImportGuestStateEx(pVCpu, pVmcsInfo, a_fWhat | a_fDoneLocal | a_fDonePostExit);
4268 }
4269 }
4270 return VINF_SUCCESS;
4271}
4272
4273
4274/**
4275 * Check per-VM and per-VCPU force flag actions that require us to go back to
4276 * ring-3 for one reason or another.
4277 *
4278 * @returns Strict VBox status code (i.e. informational status codes too)
4279 * @retval VINF_SUCCESS if we don't have any actions that require going back to
4280 * ring-3.
4281 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
4282 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
4283 * interrupts)
4284 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
4285 * all EMTs to be in ring-3.
4286 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
4287 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
4288 * to the EM loop.
4289 *
4290 * @param pVCpu The cross context virtual CPU structure.
4291 * @param fIsNestedGuest Flag whether this is for a for a pending nested guest event.
4292 * @param fStepping Whether we are single-stepping the guest using the
4293 * hypervisor debugger.
4294 *
4295 * @remarks This might cause nested-guest VM-exits, caller must check if the guest
4296 * is no longer in VMX non-root mode.
4297 */
4298static VBOXSTRICTRC vmxHCCheckForceFlags(PVMCPUCC pVCpu, bool fIsNestedGuest, bool fStepping)
4299{
4300#ifndef IN_NEM_DARWIN
4301 Assert(VMMRZCallRing3IsEnabled(pVCpu));
4302#endif
4303
4304 /*
4305 * Update pending interrupts into the APIC's IRR.
4306 */
4307 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
4308 APICUpdatePendingInterrupts(pVCpu);
4309
4310 /*
4311 * Anything pending? Should be more likely than not if we're doing a good job.
4312 */
4313 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4314 if ( !fStepping
4315 ? !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_MASK)
4316 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
4317 : !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
4318 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
4319 return VINF_SUCCESS;
4320
4321 /* Pending PGM C3 sync. */
4322 if (VMCPU_FF_IS_ANY_SET(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
4323 {
4324 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4325 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & (CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4)));
4326 VBOXSTRICTRC rcStrict = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4,
4327 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
4328 if (rcStrict != VINF_SUCCESS)
4329 {
4330 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
4331 Log4Func(("PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
4332 return rcStrict;
4333 }
4334 }
4335
4336 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
4337 if ( VM_FF_IS_ANY_SET(pVM, VM_FF_HM_TO_R3_MASK)
4338 || VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
4339 {
4340 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatSwitchHmToR3FF);
4341 int rc = RT_LIKELY(!VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_RAW_TO_R3 : VINF_EM_NO_MEMORY;
4342 Log4Func(("HM_TO_R3 forcing us back to ring-3. rc=%d (fVM=%#RX64 fCpu=%#RX64)\n",
4343 rc, pVM->fGlobalForcedActions, pVCpu->fLocalForcedActions));
4344 return rc;
4345 }
4346
4347 /* Pending VM request packets, such as hardware interrupts. */
4348 if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
4349 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
4350 {
4351 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatSwitchVmReq);
4352 Log4Func(("Pending VM request forcing us back to ring-3\n"));
4353 return VINF_EM_PENDING_REQUEST;
4354 }
4355
4356 /* Pending PGM pool flushes. */
4357 if (VM_FF_IS_SET(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
4358 {
4359 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatSwitchPgmPoolFlush);
4360 Log4Func(("PGM pool flush pending forcing us back to ring-3\n"));
4361 return VINF_PGM_POOL_FLUSH_PENDING;
4362 }
4363
4364 /* Pending DMA requests. */
4365 if (VM_FF_IS_SET(pVM, VM_FF_PDM_DMA))
4366 {
4367 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatSwitchDma);
4368 Log4Func(("Pending DMA request forcing us back to ring-3\n"));
4369 return VINF_EM_RAW_TO_R3;
4370 }
4371
4372#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4373 /*
4374 * Pending nested-guest events.
4375 *
4376 * Please note the priority of these events are specified and important.
4377 * See Intel spec. 29.4.3.2 "APIC-Write Emulation".
4378 * See Intel spec. 6.9 "Priority Among Simultaneous Exceptions And Interrupts".
4379 *
4380 * Interrupt-window and NMI-window VM-exits for the nested-guest need not be
4381 * handled here. They'll be handled by the hardware while executing the nested-guest
4382 * or by us when we injecting events that are not part of VM-entry of the nested-guest.
4383 */
4384 if (fIsNestedGuest)
4385 {
4386 /* Pending nested-guest APIC-write (may or may not cause a VM-exit). */
4387 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
4388 {
4389 Log4Func(("Pending nested-guest APIC-write\n"));
4390 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitApicWrite(pVCpu);
4391 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
4392 if ( rcStrict == VINF_SUCCESS
4393 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
4394 return rcStrict;
4395 }
4396
4397 /* Pending nested-guest monitor-trap flag (MTF). */
4398 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF))
4399 {
4400 Log4Func(("Pending nested-guest MTF\n"));
4401 VBOXSTRICTRC rcStrict = IEMExecVmxVmexit(pVCpu, VMX_EXIT_MTF, 0 /* uExitQual */);
4402 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
4403 return rcStrict;
4404 }
4405
4406 /* Pending nested-guest VMX-preemption timer expired. */
4407 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER))
4408 {
4409 Log4Func(("Pending nested-guest preempt timer\n"));
4410 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitPreemptTimer(pVCpu);
4411 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
4412 return rcStrict;
4413 }
4414 }
4415#else
4416 NOREF(fIsNestedGuest);
4417#endif
4418
4419 return VINF_SUCCESS;
4420}
4421
4422
4423/**
4424 * Converts any TRPM trap into a pending HM event. This is typically used when
4425 * entering from ring-3 (not longjmp returns).
4426 *
4427 * @param pVCpu The cross context virtual CPU structure.
4428 */
4429static void vmxHCTrpmTrapToPendingEvent(PVMCPUCC pVCpu)
4430{
4431 Assert(TRPMHasTrap(pVCpu));
4432 Assert(!VCPU_2_VMXSTATE(pVCpu).Event.fPending);
4433
4434 uint8_t uVector;
4435 TRPMEVENT enmTrpmEvent;
4436 uint32_t uErrCode;
4437 RTGCUINTPTR GCPtrFaultAddress;
4438 uint8_t cbInstr;
4439 bool fIcebp;
4440
4441 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr, &fIcebp);
4442 AssertRC(rc);
4443
4444 uint32_t u32IntInfo;
4445 u32IntInfo = uVector | VMX_IDT_VECTORING_INFO_VALID;
4446 u32IntInfo |= HMTrpmEventTypeToVmxEventType(uVector, enmTrpmEvent, fIcebp);
4447
4448 rc = TRPMResetTrap(pVCpu);
4449 AssertRC(rc);
4450 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
4451 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
4452
4453 vmxHCSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
4454}
4455
4456
4457/**
4458 * Converts the pending HM event into a TRPM trap.
4459 *
4460 * @param pVCpu The cross context virtual CPU structure.
4461 */
4462static void vmxHCPendingEventToTrpmTrap(PVMCPUCC pVCpu)
4463{
4464 Assert(VCPU_2_VMXSTATE(pVCpu).Event.fPending);
4465
4466 /* If a trap was already pending, we did something wrong! */
4467 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
4468
4469 uint32_t const u32IntInfo = VCPU_2_VMXSTATE(pVCpu).Event.u64IntInfo;
4470 uint32_t const uVector = VMX_IDT_VECTORING_INFO_VECTOR(u32IntInfo);
4471 TRPMEVENT const enmTrapType = HMVmxEventTypeToTrpmEventType(u32IntInfo);
4472
4473 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
4474
4475 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
4476 AssertRC(rc);
4477
4478 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
4479 TRPMSetErrorCode(pVCpu, VCPU_2_VMXSTATE(pVCpu).Event.u32ErrCode);
4480
4481 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(u32IntInfo))
4482 TRPMSetFaultAddress(pVCpu, VCPU_2_VMXSTATE(pVCpu).Event.GCPtrFaultAddress);
4483 else
4484 {
4485 uint8_t const uVectorType = VMX_IDT_VECTORING_INFO_TYPE(u32IntInfo);
4486 switch (uVectorType)
4487 {
4488 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
4489 TRPMSetTrapDueToIcebp(pVCpu);
4490 RT_FALL_THRU();
4491 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
4492 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
4493 {
4494 AssertMsg( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
4495 || ( uVector == X86_XCPT_BP /* INT3 */
4496 || uVector == X86_XCPT_OF /* INTO */
4497 || uVector == X86_XCPT_DB /* INT1 (ICEBP) */),
4498 ("Invalid vector: uVector=%#x uVectorType=%#x\n", uVector, uVectorType));
4499 TRPMSetInstrLength(pVCpu, VCPU_2_VMXSTATE(pVCpu).Event.cbInstr);
4500 break;
4501 }
4502 }
4503 }
4504
4505 /* We're now done converting the pending event. */
4506 VCPU_2_VMXSTATE(pVCpu).Event.fPending = false;
4507}
4508
4509
4510/**
4511 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
4512 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
4513 *
4514 * @param pVCpu The cross context virtual CPU structure.
4515 * @param pVmcsInfo The VMCS info. object.
4516 */
4517static void vmxHCSetIntWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
4518{
4519 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_INT_WINDOW_EXIT)
4520 {
4521 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
4522 {
4523 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_INT_WINDOW_EXIT;
4524 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
4525 AssertRC(rc);
4526 }
4527 Log4Func(("Enabled interrupt-window exiting\n"));
4528 } /* else we will deliver interrupts whenever the guest Vm-exits next and is in a state to receive the interrupt. */
4529}
4530
4531
4532/**
4533 * Clears the interrupt-window exiting control in the VMCS.
4534 *
4535 * @param pVCpu The cross context virtual CPU structure.
4536 * @param pVmcsInfo The VMCS info. object.
4537 */
4538DECLINLINE(void) vmxHCClearIntWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
4539{
4540 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
4541 {
4542 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_INT_WINDOW_EXIT;
4543 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
4544 AssertRC(rc);
4545 Log4Func(("Disabled interrupt-window exiting\n"));
4546 }
4547}
4548
4549
4550/**
4551 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
4552 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
4553 *
4554 * @param pVCpu The cross context virtual CPU structure.
4555 * @param pVmcsInfo The VMCS info. object.
4556 */
4557static void vmxHCSetNmiWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
4558{
4559 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
4560 {
4561 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
4562 {
4563 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_NMI_WINDOW_EXIT;
4564 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
4565 AssertRC(rc);
4566 Log4Func(("Enabled NMI-window exiting\n"));
4567 }
4568 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
4569}
4570
4571
4572/**
4573 * Clears the NMI-window exiting control in the VMCS.
4574 *
4575 * @param pVCpu The cross context virtual CPU structure.
4576 * @param pVmcsInfo The VMCS info. object.
4577 */
4578DECLINLINE(void) vmxHCClearNmiWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
4579{
4580 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
4581 {
4582 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_NMI_WINDOW_EXIT;
4583 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
4584 AssertRC(rc);
4585 Log4Func(("Disabled NMI-window exiting\n"));
4586 }
4587}
4588
4589
4590/**
4591 * Injects an event into the guest upon VM-entry by updating the relevant fields
4592 * in the VM-entry area in the VMCS.
4593 *
4594 * @returns Strict VBox status code (i.e. informational status codes too).
4595 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
4596 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
4597 *
4598 * @param pVCpu The cross context virtual CPU structure.
4599 * @param pVmcsInfo The VMCS info object.
4600 * @param fIsNestedGuest Flag whether this is for a for a pending nested guest event.
4601 * @param pEvent The event being injected.
4602 * @param pfIntrState Pointer to the VT-x guest-interruptibility-state. This
4603 * will be updated if necessary. This cannot not be NULL.
4604 * @param fStepping Whether we're single-stepping guest execution and should
4605 * return VINF_EM_DBG_STEPPED if the event is injected
4606 * directly (registers modified by us, not by hardware on
4607 * VM-entry).
4608 */
4609static VBOXSTRICTRC vmxHCInjectEventVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNestedGuest, PCHMEVENT pEvent,
4610 bool fStepping, uint32_t *pfIntrState)
4611{
4612 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
4613 AssertMsg(!RT_HI_U32(pEvent->u64IntInfo), ("%#RX64\n", pEvent->u64IntInfo));
4614 Assert(pfIntrState);
4615
4616#ifdef IN_NEM_DARWIN
4617 RT_NOREF(fIsNestedGuest, fStepping, pfIntrState);
4618#endif
4619
4620 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4621 uint32_t u32IntInfo = pEvent->u64IntInfo;
4622 uint32_t const u32ErrCode = pEvent->u32ErrCode;
4623 uint32_t const cbInstr = pEvent->cbInstr;
4624 RTGCUINTPTR const GCPtrFault = pEvent->GCPtrFaultAddress;
4625 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(u32IntInfo);
4626 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(u32IntInfo);
4627
4628#ifdef VBOX_STRICT
4629 /*
4630 * Validate the error-code-valid bit for hardware exceptions.
4631 * No error codes for exceptions in real-mode.
4632 *
4633 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
4634 */
4635 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
4636 && !CPUMIsGuestInRealModeEx(pCtx))
4637 {
4638 switch (uVector)
4639 {
4640 case X86_XCPT_PF:
4641 case X86_XCPT_DF:
4642 case X86_XCPT_TS:
4643 case X86_XCPT_NP:
4644 case X86_XCPT_SS:
4645 case X86_XCPT_GP:
4646 case X86_XCPT_AC:
4647 AssertMsg(VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo),
4648 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
4649 RT_FALL_THRU();
4650 default:
4651 break;
4652 }
4653 }
4654
4655 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
4656 Assert( uIntType != VMX_EXIT_INT_INFO_TYPE_NMI
4657 || !(*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
4658#endif
4659
4660 RT_NOREF(uVector);
4661 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
4662 || uIntType == VMX_EXIT_INT_INFO_TYPE_NMI
4663 || uIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT
4664 || uIntType == VMX_EXIT_INT_INFO_TYPE_SW_XCPT)
4665 {
4666 Assert(uVector <= X86_XCPT_LAST);
4667 Assert(uIntType != VMX_EXIT_INT_INFO_TYPE_NMI || uVector == X86_XCPT_NMI);
4668 Assert(uIntType != VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT || uVector == X86_XCPT_DB);
4669 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).aStatInjectedXcpts[uVector]);
4670 }
4671 else
4672 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).aStatInjectedIrqs[uVector & MASK_INJECT_IRQ_STAT]);
4673
4674 /*
4675 * Hardware interrupts & exceptions cannot be delivered through the software interrupt
4676 * redirection bitmap to the real mode task in virtual-8086 mode. We must jump to the
4677 * interrupt handler in the (real-mode) guest.
4678 *
4679 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode".
4680 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
4681 */
4682 if (CPUMIsGuestInRealModeEx(pCtx)) /* CR0.PE bit changes are always intercepted, so it's up to date. */
4683 {
4684#ifndef IN_NEM_DARWIN
4685 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest)
4686#endif
4687 {
4688 /*
4689 * For CPUs with unrestricted guest execution enabled and with the guest
4690 * in real-mode, we must not set the deliver-error-code bit.
4691 *
4692 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
4693 */
4694 u32IntInfo &= ~VMX_ENTRY_INT_INFO_ERROR_CODE_VALID;
4695 }
4696#ifndef IN_NEM_DARWIN
4697 else
4698 {
4699 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4700 Assert(PDMVmmDevHeapIsEnabled(pVM));
4701 Assert(pVM->hm.s.vmx.pRealModeTSS);
4702 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
4703
4704 /* We require RIP, RSP, RFLAGS, CS, IDTR, import them. */
4705 int rc2 = vmxHCImportGuestStateEx(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TABLE_MASK
4706 | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS);
4707 AssertRCReturn(rc2, rc2);
4708
4709 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
4710 size_t const cbIdtEntry = sizeof(X86IDTR16);
4711 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pCtx->idtr.cbIdt)
4712 {
4713 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
4714 if (uVector == X86_XCPT_DF)
4715 return VINF_EM_RESET;
4716
4717 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault.
4718 No error codes for exceptions in real-mode. */
4719 if (uVector == X86_XCPT_GP)
4720 {
4721 static HMEVENT const s_EventXcptDf
4722 = HMEVENT_INIT_ONLY_INT_INFO( RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
4723 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
4724 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
4725 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1));
4726 return vmxHCInjectEventVmcs(pVCpu, pVmcsInfo, fIsNestedGuest, &s_EventXcptDf, fStepping, pfIntrState);
4727 }
4728
4729 /*
4730 * If we're injecting an event with no valid IDT entry, inject a #GP.
4731 * No error codes for exceptions in real-mode.
4732 *
4733 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
4734 */
4735 static HMEVENT const s_EventXcptGp
4736 = HMEVENT_INIT_ONLY_INT_INFO( RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
4737 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
4738 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
4739 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1));
4740 return vmxHCInjectEventVmcs(pVCpu, pVmcsInfo, fIsNestedGuest, &s_EventXcptGp, fStepping, pfIntrState);
4741 }
4742
4743 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
4744 uint16_t uGuestIp = pCtx->ip;
4745 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT)
4746 {
4747 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
4748 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
4749 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
4750 }
4751 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_INT)
4752 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
4753
4754 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
4755 X86IDTR16 IdtEntry;
4756 RTGCPHYS const GCPhysIdtEntry = (RTGCPHYS)pCtx->idtr.pIdt + uVector * cbIdtEntry;
4757 rc2 = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
4758 AssertRCReturn(rc2, rc2);
4759
4760 /* Construct the stack frame for the interrupt/exception handler. */
4761 VBOXSTRICTRC rcStrict;
4762 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, (uint16_t)pCtx->eflags.u);
4763 if (rcStrict == VINF_SUCCESS)
4764 {
4765 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->cs.Sel);
4766 if (rcStrict == VINF_SUCCESS)
4767 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, uGuestIp);
4768 }
4769
4770 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
4771 if (rcStrict == VINF_SUCCESS)
4772 {
4773 pCtx->eflags.u &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
4774 pCtx->rip = IdtEntry.offSel;
4775 pCtx->cs.Sel = IdtEntry.uSel;
4776 pCtx->cs.ValidSel = IdtEntry.uSel;
4777 pCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
4778 if ( uIntType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
4779 && uVector == X86_XCPT_PF)
4780 pCtx->cr2 = GCPtrFault;
4781
4782 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_CS | HM_CHANGED_GUEST_CR2
4783 | HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
4784 | HM_CHANGED_GUEST_RSP);
4785
4786 /*
4787 * If we delivered a hardware exception (other than an NMI) and if there was
4788 * block-by-STI in effect, we should clear it.
4789 */
4790 if (*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
4791 {
4792 Assert( uIntType != VMX_ENTRY_INT_INFO_TYPE_NMI
4793 && uIntType != VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
4794 Log4Func(("Clearing inhibition due to STI\n"));
4795 *pfIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
4796 }
4797
4798 Log4(("Injected real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
4799 u32IntInfo, u32ErrCode, cbInstr, pCtx->eflags.u, pCtx->cs.Sel, pCtx->eip));
4800
4801 /*
4802 * The event has been truly dispatched to the guest. Mark it as no longer pending so
4803 * we don't attempt to undo it if we are returning to ring-3 before executing guest code.
4804 */
4805 VCPU_2_VMXSTATE(pVCpu).Event.fPending = false;
4806
4807 /*
4808 * If we eventually support nested-guest execution without unrestricted guest execution,
4809 * we should set fInterceptEvents here.
4810 */
4811 Assert(!fIsNestedGuest);
4812
4813 /* If we're stepping and we've changed cs:rip above, bail out of the VMX R0 execution loop. */
4814 if (fStepping)
4815 rcStrict = VINF_EM_DBG_STEPPED;
4816 }
4817 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
4818 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
4819 return rcStrict;
4820 }
4821#else
4822 RT_NOREF(pVmcsInfo);
4823#endif
4824 }
4825
4826 /*
4827 * Validate.
4828 */
4829 Assert(VMX_ENTRY_INT_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
4830 Assert(!(u32IntInfo & VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK)); /* Bits 30:12 MBZ. */
4831
4832 /*
4833 * Inject the event into the VMCS.
4834 */
4835 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
4836 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
4837 rc |= VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
4838 rc |= VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
4839 AssertRC(rc);
4840
4841 /*
4842 * Update guest CR2 if this is a page-fault.
4843 */
4844 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
4845 pCtx->cr2 = GCPtrFault;
4846
4847 Log4(("Injecting u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x CR2=%#RX64\n", u32IntInfo, u32ErrCode, cbInstr, pCtx->cr2));
4848 return VINF_SUCCESS;
4849}
4850
4851
4852/**
4853 * Evaluates the event to be delivered to the guest and sets it as the pending
4854 * event.
4855 *
4856 * Toggling of interrupt force-flags here is safe since we update TRPM on premature
4857 * exits to ring-3 before executing guest code, see vmxHCExitToRing3(). We must
4858 * NOT restore these force-flags.
4859 *
4860 * @returns Strict VBox status code (i.e. informational status codes too).
4861 * @param pVCpu The cross context virtual CPU structure.
4862 * @param pVmcsInfo The VMCS information structure.
4863 * @param pfIntrState Where to store the updated VMX guest-interruptibility
4864 * state.
4865 */
4866static VBOXSTRICTRC vmxHCEvaluatePendingEvent(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t *pfIntrState)
4867{
4868 Assert(pfIntrState);
4869 Assert(!TRPMHasTrap(pVCpu));
4870
4871 *pfIntrState = vmxHCGetGuestIntrStateWithUpdate(pVCpu);
4872
4873 /*
4874 * Evaluate if a new event needs to be injected.
4875 * An event that's already pending has already performed all necessary checks.
4876 */
4877 if ( !VCPU_2_VMXSTATE(pVCpu).Event.fPending
4878 && !CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx))
4879 {
4880 /** @todo SMI. SMIs take priority over NMIs. */
4881
4882 /*
4883 * NMIs.
4884 * NMIs take priority over external interrupts.
4885 */
4886 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
4887 {
4888 if (!CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx))
4889 {
4890 /* Finally, inject the NMI and we're done. */
4891 vmxHCSetPendingXcptNmi(pVCpu);
4892 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
4893 vmxHCClearNmiWindowExitVmcs(pVCpu, pVmcsInfo);
4894 return VINF_SUCCESS;
4895 }
4896 vmxHCSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
4897 }
4898 else
4899 vmxHCClearNmiWindowExitVmcs(pVCpu, pVmcsInfo);
4900
4901 /*
4902 * External interrupts (PIC/APIC).
4903 */
4904 if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
4905 && !VCPU_2_VMXSTATE(pVCpu).fSingleInstruction)
4906 {
4907 Assert(!DBGFIsStepping(pVCpu));
4908 int rc = vmxHCImportGuestStateEx(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
4909 AssertRC(rc);
4910
4911 if (pVCpu->cpum.GstCtx.eflags.u & X86_EFL_IF)
4912 {
4913 /*
4914 * Once PDMGetInterrupt() returns an interrupt we -must- deliver it.
4915 * We cannot re-request the interrupt from the controller again.
4916 */
4917 uint8_t u8Interrupt;
4918 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
4919 if (RT_SUCCESS(rc))
4920 vmxHCSetPendingExtInt(pVCpu, u8Interrupt);
4921 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
4922 {
4923 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatSwitchTprMaskedIrq);
4924 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
4925 vmxHCApicSetTprThreshold(pVCpu, pVmcsInfo, u8Interrupt >> 4);
4926 /*
4927 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
4928 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
4929 * need to re-set this force-flag here.
4930 */
4931 }
4932 else
4933 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatSwitchGuestIrq);
4934
4935 vmxHCClearIntWindowExitVmcs(pVCpu, pVmcsInfo);
4936 return VINF_SUCCESS;
4937 }
4938 vmxHCSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
4939 }
4940 else
4941 vmxHCClearIntWindowExitVmcs(pVCpu, pVmcsInfo);
4942 }
4943 else
4944 {
4945 /*
4946 * An event is being injected or we are in an interrupt shadow.
4947 * If another event is pending currently, instruct VT-x to cause a VM-exit as
4948 * soon as the guest is ready to accept it.
4949 */
4950 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
4951 vmxHCSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
4952 else
4953 {
4954 Assert(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT));
4955 if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
4956 && !VCPU_2_VMXSTATE(pVCpu).fSingleInstruction)
4957 vmxHCSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
4958 else
4959 {
4960 /* It's possible that interrupt-window exiting is still active, clear it as it's now unnecessary. */
4961 vmxHCClearIntWindowExitVmcs(pVCpu, pVmcsInfo);
4962 }
4963 }
4964 }
4965
4966 return VINF_SUCCESS;
4967}
4968
4969
4970#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4971/**
4972 * Evaluates the event to be delivered to the nested-guest and sets it as the
4973 * pending event.
4974 *
4975 * Toggling of interrupt force-flags here is safe since we update TRPM on premature
4976 * exits to ring-3 before executing guest code, see vmxHCExitToRing3(). We must
4977 * NOT restore these force-flags.
4978 *
4979 * @returns Strict VBox status code (i.e. informational status codes too).
4980 * @param pVCpu The cross context virtual CPU structure.
4981 * @param pVmcsInfo The VMCS information structure.
4982 * @param pfIntrState Where to store the updated VMX guest-interruptibility
4983 * state.
4984 *
4985 * @remarks The guest must be in VMX non-root mode.
4986 */
4987static VBOXSTRICTRC vmxHCEvaluatePendingEventNested(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t *pfIntrState)
4988{
4989 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4990
4991 Assert(pfIntrState);
4992 Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
4993 Assert(!TRPMHasTrap(pVCpu));
4994
4995 *pfIntrState = vmxHCGetGuestIntrStateWithUpdate(pVCpu);
4996
4997 /*
4998 * If we are injecting an event, all necessary checks have been performed.
4999 * Any interrupt-window or NMI-window exiting would have been setup by the
5000 * nested-guest while we merged controls.
5001 */
5002 if (VCPU_2_VMXSTATE(pVCpu).Event.fPending)
5003 return VINF_SUCCESS;
5004
5005 /*
5006 * An event injected by VMLAUNCH/VMRESUME instruction emulation should've been
5007 * made pending (TRPM to HM event) and would be handled above if we resumed
5008 * execution in HM. If somehow we fell back to emulation after the
5009 * VMLAUNCH/VMRESUME instruction, it would have been handled in iemRaiseXcptOrInt
5010 * (calling iemVmxVmexitEvent). Thus, if we get here the nested-hypervisor's VMX
5011 * intercepts should be active and any events pending here have been generated
5012 * while executing the guest in VMX non-root mode after virtual VM-entry completed.
5013 */
5014 Assert(CPUMIsGuestVmxInterceptEvents(pCtx));
5015
5016 /*
5017 * Interrupt shadows MAY block NMIs.
5018 * They also blocks external-interrupts and MAY block external-interrupt VM-exits.
5019 *
5020 * See Intel spec. 24.4.2 "Guest Non-Register State".
5021 * See Intel spec. 25.4.1 "Event Blocking".
5022 */
5023 if (!CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx))
5024 { /* likely */ }
5025 else
5026 return VINF_SUCCESS;
5027
5028 /** @todo SMI. SMIs take priority over NMIs. */
5029
5030 /*
5031 * NMIs.
5032 * NMIs take priority over interrupts.
5033 */
5034 if (!CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx))
5035 {
5036 /*
5037 * Nested-guest NMI-window exiting.
5038 * The NMI-window exit must happen regardless of whether an NMI is pending
5039 * provided virtual-NMI blocking is not in effect.
5040 *
5041 * See Intel spec. 25.2 "Other Causes Of VM Exits".
5042 */
5043 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW)
5044 && !CPUMIsGuestVmxVirtNmiBlocking(pCtx))
5045 {
5046 Assert(CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT));
5047 return IEMExecVmxVmexit(pVCpu, VMX_EXIT_NMI_WINDOW, 0 /* u64ExitQual */);
5048 }
5049
5050 /*
5051 * For a nested-guest, the FF always indicates the outer guest's ability to
5052 * receive an NMI while the guest-interruptibility state bit depends on whether
5053 * the nested-hypervisor is using virtual-NMIs.
5054 *
5055 * It is very important that we also clear the force-flag if we are causing
5056 * an NMI VM-exit as it is the responsibility of the nested-hypervisor to deal
5057 * with re-injecting or discarding the NMI. This fixes the bug that showed up
5058 * with SMP Windows Server 2008 R2 with Hyper-V enabled, see @bugref{10318#c19}.
5059 */
5060 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI))
5061 {
5062 if (CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_NMI_EXIT))
5063 return IEMExecVmxVmexitXcptNmi(pVCpu);
5064 vmxHCSetPendingXcptNmi(pVCpu);
5065 return VINF_SUCCESS;
5066 }
5067 }
5068
5069 /*
5070 * Nested-guest interrupt-window exiting.
5071 *
5072 * We must cause the interrupt-window exit regardless of whether an interrupt is pending
5073 * provided virtual interrupts are enabled.
5074 *
5075 * See Intel spec. 25.2 "Other Causes Of VM Exits".
5076 * See Intel spec. 26.7.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
5077 */
5078 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW)
5079 && CPUMIsGuestVmxVirtIntrEnabled(pCtx))
5080 {
5081 Assert(CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT));
5082 return IEMExecVmxVmexit(pVCpu, VMX_EXIT_INT_WINDOW, 0 /* u64ExitQual */);
5083 }
5084
5085 /*
5086 * External interrupts (PIC/APIC).
5087 *
5088 * When "External interrupt exiting" is set the VM-exit happens regardless of RFLAGS.IF.
5089 * When it isn't set, RFLAGS.IF controls delivery of the interrupt as always.
5090 * This fixes a nasty SMP hang while executing nested-guest VCPUs on spinlocks which aren't rescued
5091 * by other VM-exits (like a preemption timer), see @bugref{9562#c18}.
5092 *
5093 * NMIs block external interrupts as they are dispatched through the interrupt gate (vector 2)
5094 * which automatically clears EFLAGS.IF. Also it's possible an NMI handler could enable interrupts
5095 * and thus we should not check for NMI inhibition here.
5096 *
5097 * See Intel spec. 25.4.1 "Event Blocking".
5098 * See Intel spec. 6.8.1 "Masking Maskable Hardware Interrupts".
5099 */
5100 if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
5101 && !VCPU_2_VMXSTATE(pVCpu).fSingleInstruction)
5102 {
5103 Assert(!DBGFIsStepping(pVCpu));
5104 int rc = vmxHCImportGuestStateEx(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
5105 AssertRC(rc);
5106 if (CPUMIsGuestVmxPhysIntrEnabled(pCtx))
5107 {
5108 /* Nested-guest external interrupt VM-exit. */
5109 if ( CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
5110 && !CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
5111 {
5112 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
5113 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
5114 return rcStrict;
5115 }
5116
5117 /*
5118 * Fetch the external interrupt from the interrupt controller.
5119 * Once PDMGetInterrupt() returns an interrupt we -must- deliver it or pass it to
5120 * the nested-hypervisor. We cannot re-request the interrupt from the controller again.
5121 */
5122 uint8_t u8Interrupt;
5123 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
5124 if (RT_SUCCESS(rc))
5125 {
5126 /* Nested-guest external interrupt VM-exit when the "acknowledge interrupt on exit" is enabled. */
5127 if (CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
5128 {
5129 Assert(CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_ACK_EXT_INT));
5130 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, u8Interrupt, false /* fIntPending */);
5131 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
5132 return rcStrict;
5133 }
5134 vmxHCSetPendingExtInt(pVCpu, u8Interrupt);
5135 return VINF_SUCCESS;
5136 }
5137 }
5138 }
5139 return VINF_SUCCESS;
5140}
5141#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
5142
5143
5144/**
5145 * Injects any pending events into the guest if the guest is in a state to
5146 * receive them.
5147 *
5148 * @returns Strict VBox status code (i.e. informational status codes too).
5149 * @param pVCpu The cross context virtual CPU structure.
5150 * @param pVmcsInfo The VMCS information structure.
5151 * @param fIsNestedGuest Flag whether the event injection happens for a nested guest.
5152 * @param fIntrState The VT-x guest-interruptibility state.
5153 * @param fStepping Whether we are single-stepping the guest using the
5154 * hypervisor debugger and should return
5155 * VINF_EM_DBG_STEPPED if the event was dispatched
5156 * directly.
5157 */
5158static VBOXSTRICTRC vmxHCInjectPendingEvent(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNestedGuest,
5159 uint32_t fIntrState, bool fStepping)
5160{
5161 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
5162#ifndef IN_NEM_DARWIN
5163 Assert(VMMRZCallRing3IsEnabled(pVCpu));
5164#endif
5165
5166#ifdef VBOX_STRICT
5167 /*
5168 * Verify guest-interruptibility state.
5169 *
5170 * We put this in a scoped block so we do not accidentally use fBlockSti or fBlockMovSS,
5171 * since injecting an event may modify the interruptibility state and we must thus always
5172 * use fIntrState.
5173 */
5174 {
5175 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
5176 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
5177 Assert(!fBlockSti || !(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_RFLAGS));
5178 Assert(!fBlockSti || pVCpu->cpum.GstCtx.eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
5179 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
5180 Assert(!TRPMHasTrap(pVCpu));
5181 NOREF(fBlockMovSS); NOREF(fBlockSti);
5182 }
5183#endif
5184
5185 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
5186 if (VCPU_2_VMXSTATE(pVCpu).Event.fPending)
5187 {
5188 /*
5189 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
5190 * pending even while injecting an event and in this case, we want a VM-exit as soon as
5191 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
5192 *
5193 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
5194 */
5195 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(VCPU_2_VMXSTATE(pVCpu).Event.u64IntInfo);
5196#ifdef VBOX_STRICT
5197 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
5198 {
5199 Assert(pVCpu->cpum.GstCtx.eflags.u & X86_EFL_IF);
5200 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI));
5201 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
5202 }
5203 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_NMI)
5204 {
5205 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI));
5206 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI));
5207 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
5208 }
5209#endif
5210 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#RX32\n", pVCpu->idCpu, VCPU_2_VMXSTATE(pVCpu).Event.u64IntInfo,
5211 uIntType));
5212
5213 /*
5214 * Inject the event and get any changes to the guest-interruptibility state.
5215 *
5216 * The guest-interruptibility state may need to be updated if we inject the event
5217 * into the guest IDT ourselves (for real-on-v86 guest injecting software interrupts).
5218 */
5219 rcStrict = vmxHCInjectEventVmcs(pVCpu, pVmcsInfo, fIsNestedGuest, &VCPU_2_VMXSTATE(pVCpu).Event, fStepping, &fIntrState);
5220 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
5221
5222 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
5223 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatInjectInterrupt);
5224 else
5225 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatInjectXcpt);
5226 }
5227
5228 /*
5229 * Deliver any pending debug exceptions if the guest is single-stepping using EFLAGS.TF and
5230 * is an interrupt shadow (block-by-STI or block-by-MOV SS).
5231 */
5232 if ( (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
5233 && !fIsNestedGuest)
5234 {
5235 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
5236
5237 if (!VCPU_2_VMXSTATE(pVCpu).fSingleInstruction)
5238 {
5239 /*
5240 * Set or clear the BS bit depending on whether the trap flag is active or not. We need
5241 * to do both since we clear the BS bit from the VMCS while exiting to ring-3.
5242 */
5243 Assert(!DBGFIsStepping(pVCpu));
5244 uint8_t const fTrapFlag = !!(pVCpu->cpum.GstCtx.eflags.u & X86_EFL_TF);
5245 int rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS,
5246 fTrapFlag << VMX_BF_VMCS_PENDING_DBG_XCPT_BS_SHIFT);
5247 AssertRC(rc);
5248 }
5249 else
5250 {
5251 /*
5252 * We must not deliver a debug exception when single-stepping over STI/Mov-SS in the
5253 * hypervisor debugger using EFLAGS.TF but rather clear interrupt inhibition. However,
5254 * we take care of this case in vmxHCExportSharedDebugState and also the case if
5255 * we use MTF, so just make sure it's called before executing guest-code.
5256 */
5257 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_DR_MASK);
5258 }
5259 }
5260 /* else: for nested-guest currently handling while merging controls. */
5261
5262 /*
5263 * Finally, update the guest-interruptibility state.
5264 *
5265 * This is required for the real-on-v86 software interrupt injection, for
5266 * pending debug exceptions as well as updates to the guest state from ring-3 (IEM).
5267 */
5268 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_GUEST_INT_STATE, fIntrState);
5269 AssertRC(rc);
5270
5271 /*
5272 * There's no need to clear the VM-entry interruption-information field here if we're not
5273 * injecting anything. VT-x clears the valid bit on every VM-exit.
5274 *
5275 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
5276 */
5277
5278 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
5279 return rcStrict;
5280}
5281
5282
5283/**
5284 * Tries to determine what part of the guest-state VT-x has deemed as invalid
5285 * and update error record fields accordingly.
5286 *
5287 * @returns VMX_IGS_* error codes.
5288 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
5289 * wrong with the guest state.
5290 *
5291 * @param pVCpu The cross context virtual CPU structure.
5292 * @param pVmcsInfo The VMCS info. object.
5293 *
5294 * @remarks This function assumes our cache of the VMCS controls
5295 * are valid, i.e. vmxHCCheckCachedVmcsCtls() succeeded.
5296 */
5297static uint32_t vmxHCCheckGuestState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
5298{
5299#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
5300#define HMVMX_CHECK_BREAK(expr, err) if (!(expr)) { uError = (err); break; } else do { } while (0)
5301
5302 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5303 uint32_t uError = VMX_IGS_ERROR;
5304 uint32_t u32IntrState = 0;
5305#ifndef IN_NEM_DARWIN
5306 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5307 bool const fUnrestrictedGuest = VM_IS_VMX_UNRESTRICTED_GUEST(pVM);
5308#else
5309 bool const fUnrestrictedGuest = true;
5310#endif
5311 do
5312 {
5313 int rc;
5314
5315 /*
5316 * Guest-interruptibility state.
5317 *
5318 * Read this first so that any check that fails prior to those that actually
5319 * require the guest-interruptibility state would still reflect the correct
5320 * VMCS value and avoids causing further confusion.
5321 */
5322 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_INT_STATE, &u32IntrState);
5323 AssertRC(rc);
5324
5325 uint32_t u32Val;
5326 uint64_t u64Val;
5327
5328 /*
5329 * CR0.
5330 */
5331 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
5332 uint64_t fSetCr0 = (g_HmMsrs.u.vmx.u64Cr0Fixed0 & g_HmMsrs.u.vmx.u64Cr0Fixed1);
5333 uint64_t const fZapCr0 = (g_HmMsrs.u.vmx.u64Cr0Fixed0 | g_HmMsrs.u.vmx.u64Cr0Fixed1);
5334 /* Exceptions for unrestricted guest execution for CR0 fixed bits (PE, PG).
5335 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
5336 if (fUnrestrictedGuest)
5337 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
5338
5339 uint64_t u64GuestCr0;
5340 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_CR0, &u64GuestCr0);
5341 AssertRC(rc);
5342 HMVMX_CHECK_BREAK((u64GuestCr0 & fSetCr0) == fSetCr0, VMX_IGS_CR0_FIXED1);
5343 HMVMX_CHECK_BREAK(!(u64GuestCr0 & ~fZapCr0), VMX_IGS_CR0_FIXED0);
5344 if ( !fUnrestrictedGuest
5345 && (u64GuestCr0 & X86_CR0_PG)
5346 && !(u64GuestCr0 & X86_CR0_PE))
5347 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
5348
5349 /*
5350 * CR4.
5351 */
5352 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
5353 uint64_t const fSetCr4 = (g_HmMsrs.u.vmx.u64Cr4Fixed0 & g_HmMsrs.u.vmx.u64Cr4Fixed1);
5354 uint64_t const fZapCr4 = (g_HmMsrs.u.vmx.u64Cr4Fixed0 | g_HmMsrs.u.vmx.u64Cr4Fixed1);
5355
5356 uint64_t u64GuestCr4;
5357 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_CR4, &u64GuestCr4);
5358 AssertRC(rc);
5359 HMVMX_CHECK_BREAK((u64GuestCr4 & fSetCr4) == fSetCr4, VMX_IGS_CR4_FIXED1);
5360 HMVMX_CHECK_BREAK(!(u64GuestCr4 & ~fZapCr4), VMX_IGS_CR4_FIXED0);
5361
5362 /*
5363 * IA32_DEBUGCTL MSR.
5364 */
5365 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
5366 AssertRC(rc);
5367 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
5368 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
5369 {
5370 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
5371 }
5372 uint64_t u64DebugCtlMsr = u64Val;
5373
5374#ifdef VBOX_STRICT
5375 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_CTRL_ENTRY, &u32Val);
5376 AssertRC(rc);
5377 Assert(u32Val == pVmcsInfo->u32EntryCtls);
5378#endif
5379 bool const fLongModeGuest = RT_BOOL(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
5380
5381 /*
5382 * RIP and RFLAGS.
5383 */
5384 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_RIP, &u64Val);
5385 AssertRC(rc);
5386 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
5387 if ( !fLongModeGuest
5388 || !pCtx->cs.Attr.n.u1Long)
5389 {
5390 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
5391 }
5392 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
5393 * must be identical if the "IA-32e mode guest" VM-entry
5394 * control is 1 and CS.L is 1. No check applies if the
5395 * CPU supports 64 linear-address bits. */
5396
5397 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
5398 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_RFLAGS, &u64Val);
5399 AssertRC(rc);
5400 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
5401 VMX_IGS_RFLAGS_RESERVED);
5402 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
5403 uint32_t const u32Eflags = u64Val;
5404
5405 if ( fLongModeGuest
5406 || ( fUnrestrictedGuest
5407 && !(u64GuestCr0 & X86_CR0_PE)))
5408 {
5409 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
5410 }
5411
5412 uint32_t u32EntryInfo;
5413 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
5414 AssertRC(rc);
5415 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
5416 {
5417 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
5418 }
5419
5420 /*
5421 * 64-bit checks.
5422 */
5423 if (fLongModeGuest)
5424 {
5425 HMVMX_CHECK_BREAK(u64GuestCr0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
5426 HMVMX_CHECK_BREAK(u64GuestCr4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
5427 }
5428
5429 if ( !fLongModeGuest
5430 && (u64GuestCr4 & X86_CR4_PCIDE))
5431 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
5432
5433 /** @todo CR3 field must be such that bits 63:52 and bits in the range
5434 * 51:32 beyond the processor's physical-address width are 0. */
5435
5436 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
5437 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
5438 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
5439
5440#ifndef IN_NEM_DARWIN
5441 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
5442 AssertRC(rc);
5443 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
5444
5445 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
5446 AssertRC(rc);
5447 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
5448#endif
5449
5450 /*
5451 * PERF_GLOBAL MSR.
5452 */
5453 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR)
5454 {
5455 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
5456 AssertRC(rc);
5457 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
5458 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
5459 }
5460
5461 /*
5462 * PAT MSR.
5463 */
5464 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
5465 {
5466 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
5467 AssertRC(rc);
5468 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
5469 for (unsigned i = 0; i < 8; i++)
5470 {
5471 uint8_t u8Val = (u64Val & 0xff);
5472 if ( u8Val > MSR_IA32_PAT_MT_UCD
5473 || u8Val == MSR_IA32_PAT_MT_RSVD_2
5474 || u8Val == MSR_IA32_PAT_MT_RSVD_3)
5475 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
5476 u64Val >>= 8;
5477 }
5478 }
5479
5480 /*
5481 * EFER MSR.
5482 */
5483 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
5484 {
5485 Assert(g_fHmVmxSupportsVmcsEfer);
5486 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
5487 AssertRC(rc);
5488 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
5489 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
5490 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVmcsInfo->u32EntryCtls
5491 & VMX_ENTRY_CTLS_IA32E_MODE_GUEST),
5492 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
5493 /** @todo r=ramshankar: Unrestricted check here is probably wrong, see
5494 * iemVmxVmentryCheckGuestState(). */
5495 HMVMX_CHECK_BREAK( fUnrestrictedGuest
5496 || !(u64GuestCr0 & X86_CR0_PG)
5497 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
5498 VMX_IGS_EFER_LMA_LME_MISMATCH);
5499 }
5500
5501 /*
5502 * Segment registers.
5503 */
5504 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
5505 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
5506 if (!(u32Eflags & X86_EFL_VM))
5507 {
5508 /* CS */
5509 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
5510 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
5511 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
5512 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
5513 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
5514 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
5515 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
5516 /* CS cannot be loaded with NULL in protected mode. */
5517 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
5518 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
5519 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
5520 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
5521 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
5522 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
5523 else if (fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
5524 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
5525 else
5526 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
5527
5528 /* SS */
5529 HMVMX_CHECK_BREAK( fUnrestrictedGuest
5530 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
5531 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
5532 if ( !(pCtx->cr0 & X86_CR0_PE)
5533 || pCtx->cs.Attr.n.u4Type == 3)
5534 {
5535 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
5536 }
5537
5538 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
5539 {
5540 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
5541 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
5542 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
5543 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
5544 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
5545 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
5546 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
5547 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
5548 }
5549
5550 /* DS, ES, FS, GS - only check for usable selectors, see vmxHCExportGuestSReg(). */
5551 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
5552 {
5553 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
5554 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
5555 HMVMX_CHECK_BREAK( fUnrestrictedGuest
5556 || pCtx->ds.Attr.n.u4Type > 11
5557 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
5558 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
5559 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
5560 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
5561 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
5562 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
5563 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
5564 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5565 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
5566 }
5567 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
5568 {
5569 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
5570 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
5571 HMVMX_CHECK_BREAK( fUnrestrictedGuest
5572 || pCtx->es.Attr.n.u4Type > 11
5573 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
5574 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
5575 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
5576 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
5577 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
5578 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
5579 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
5580 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5581 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
5582 }
5583 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
5584 {
5585 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
5586 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
5587 HMVMX_CHECK_BREAK( fUnrestrictedGuest
5588 || pCtx->fs.Attr.n.u4Type > 11
5589 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
5590 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
5591 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
5592 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
5593 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
5594 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
5595 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
5596 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5597 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
5598 }
5599 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
5600 {
5601 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
5602 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
5603 HMVMX_CHECK_BREAK( fUnrestrictedGuest
5604 || pCtx->gs.Attr.n.u4Type > 11
5605 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
5606 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
5607 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
5608 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
5609 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
5610 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
5611 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
5612 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
5613 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
5614 }
5615 /* 64-bit capable CPUs. */
5616 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
5617 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
5618 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
5619 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
5620 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
5621 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
5622 VMX_IGS_LONGMODE_SS_BASE_INVALID);
5623 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
5624 VMX_IGS_LONGMODE_DS_BASE_INVALID);
5625 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
5626 VMX_IGS_LONGMODE_ES_BASE_INVALID);
5627 }
5628 else
5629 {
5630 /* V86 mode checks. */
5631 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
5632 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
5633 {
5634 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
5635 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
5636 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
5637 }
5638 else
5639 {
5640 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
5641 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
5642 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
5643 }
5644
5645 /* CS */
5646 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
5647 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
5648 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
5649 /* SS */
5650 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
5651 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
5652 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
5653 /* DS */
5654 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
5655 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
5656 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
5657 /* ES */
5658 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
5659 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
5660 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
5661 /* FS */
5662 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
5663 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
5664 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
5665 /* GS */
5666 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
5667 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
5668 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
5669 /* 64-bit capable CPUs. */
5670 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
5671 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
5672 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
5673 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
5674 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
5675 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
5676 VMX_IGS_LONGMODE_SS_BASE_INVALID);
5677 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
5678 VMX_IGS_LONGMODE_DS_BASE_INVALID);
5679 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
5680 VMX_IGS_LONGMODE_ES_BASE_INVALID);
5681 }
5682
5683 /*
5684 * TR.
5685 */
5686 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
5687 /* 64-bit capable CPUs. */
5688 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
5689 if (fLongModeGuest)
5690 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
5691 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
5692 else
5693 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
5694 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
5695 VMX_IGS_TR_ATTR_TYPE_INVALID);
5696 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
5697 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
5698 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
5699 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
5700 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
5701 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
5702 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
5703 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
5704
5705 /*
5706 * GDTR and IDTR (64-bit capable checks).
5707 */
5708 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
5709 AssertRC(rc);
5710 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
5711
5712 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
5713 AssertRC(rc);
5714 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
5715
5716 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
5717 AssertRC(rc);
5718 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
5719
5720 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
5721 AssertRC(rc);
5722 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
5723
5724 /*
5725 * Guest Non-Register State.
5726 */
5727 /* Activity State. */
5728 uint32_t u32ActivityState;
5729 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
5730 AssertRC(rc);
5731 HMVMX_CHECK_BREAK( !u32ActivityState
5732 || (u32ActivityState & RT_BF_GET(g_HmMsrs.u.vmx.u64Misc, VMX_BF_MISC_ACTIVITY_STATES)),
5733 VMX_IGS_ACTIVITY_STATE_INVALID);
5734 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
5735 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
5736
5737 if ( u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS
5738 || u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
5739 {
5740 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
5741 }
5742
5743 /** @todo Activity state and injecting interrupts. Left as a todo since we
5744 * currently don't use activity states but ACTIVE. */
5745
5746 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
5747 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
5748
5749 /* Guest interruptibility-state. */
5750 HMVMX_CHECK_BREAK(!(u32IntrState & 0xffffffe0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
5751 HMVMX_CHECK_BREAK((u32IntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
5752 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
5753 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
5754 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
5755 || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
5756 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
5757 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
5758 {
5759 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
5760 && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
5761 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
5762 }
5763 else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
5764 {
5765 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
5766 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
5767 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
5768 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
5769 }
5770 /** @todo Assumes the processor is not in SMM. */
5771 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
5772 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
5773 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
5774 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
5775 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
5776 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
5777 && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
5778 {
5779 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI), VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
5780 }
5781
5782 /* Pending debug exceptions. */
5783 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &u64Val);
5784 AssertRC(rc);
5785 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
5786 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
5787 u32Val = u64Val; /* For pending debug exceptions checks below. */
5788
5789 if ( (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
5790 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
5791 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
5792 {
5793 if ( (u32Eflags & X86_EFL_TF)
5794 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
5795 {
5796 /* Bit 14 is PendingDebug.BS. */
5797 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
5798 }
5799 if ( !(u32Eflags & X86_EFL_TF)
5800 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
5801 {
5802 /* Bit 14 is PendingDebug.BS. */
5803 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
5804 }
5805 }
5806
5807#ifndef IN_NEM_DARWIN
5808 /* VMCS link pointer. */
5809 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
5810 AssertRC(rc);
5811 if (u64Val != UINT64_C(0xffffffffffffffff))
5812 {
5813 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
5814 /** @todo Bits beyond the processor's physical-address width MBZ. */
5815 /** @todo SMM checks. */
5816 Assert(pVmcsInfo->HCPhysShadowVmcs == u64Val);
5817 Assert(pVmcsInfo->pvShadowVmcs);
5818 VMXVMCSREVID VmcsRevId;
5819 VmcsRevId.u = *(uint32_t *)pVmcsInfo->pvShadowVmcs;
5820 HMVMX_CHECK_BREAK(VmcsRevId.n.u31RevisionId == RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID),
5821 VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID);
5822 HMVMX_CHECK_BREAK(VmcsRevId.n.fIsShadowVmcs == (uint32_t)!!(pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING),
5823 VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW);
5824 }
5825
5826 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
5827 * not using nested paging? */
5828 if ( VM_IS_VMX_NESTED_PAGING(pVM)
5829 && !fLongModeGuest
5830 && CPUMIsGuestInPAEModeEx(pCtx))
5831 {
5832 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
5833 AssertRC(rc);
5834 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
5835
5836 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
5837 AssertRC(rc);
5838 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
5839
5840 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
5841 AssertRC(rc);
5842 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
5843
5844 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
5845 AssertRC(rc);
5846 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
5847 }
5848#endif
5849
5850 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
5851 if (uError == VMX_IGS_ERROR)
5852 uError = VMX_IGS_REASON_NOT_FOUND;
5853 } while (0);
5854
5855 VCPU_2_VMXSTATE(pVCpu).u32HMError = uError;
5856 VCPU_2_VMXSTATE(pVCpu).vmx.LastError.u32GuestIntrState = u32IntrState;
5857 return uError;
5858
5859#undef HMVMX_ERROR_BREAK
5860#undef HMVMX_CHECK_BREAK
5861}
5862
5863
5864#ifndef HMVMX_USE_FUNCTION_TABLE
5865/**
5866 * Handles a guest VM-exit from hardware-assisted VMX execution.
5867 *
5868 * @returns Strict VBox status code (i.e. informational status codes too).
5869 * @param pVCpu The cross context virtual CPU structure.
5870 * @param pVmxTransient The VMX-transient structure.
5871 */
5872DECLINLINE(VBOXSTRICTRC) vmxHCHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
5873{
5874#ifdef DEBUG_ramshankar
5875# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) \
5876 do { \
5877 if (a_fSave != 0) \
5878 vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__); \
5879 VBOXSTRICTRC rcStrict = a_CallExpr; \
5880 if (a_fSave != 0) \
5881 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST); \
5882 return rcStrict; \
5883 } while (0)
5884#else
5885# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) return a_CallExpr
5886#endif
5887 uint32_t const uExitReason = pVmxTransient->uExitReason;
5888 switch (uExitReason)
5889 {
5890 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, vmxHCExitEptMisconfig(pVCpu, pVmxTransient));
5891 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, vmxHCExitEptViolation(pVCpu, pVmxTransient));
5892 case VMX_EXIT_IO_INSTR: VMEXIT_CALL_RET(0, vmxHCExitIoInstr(pVCpu, pVmxTransient));
5893 case VMX_EXIT_CPUID: VMEXIT_CALL_RET(0, vmxHCExitCpuid(pVCpu, pVmxTransient));
5894 case VMX_EXIT_RDTSC: VMEXIT_CALL_RET(0, vmxHCExitRdtsc(pVCpu, pVmxTransient));
5895 case VMX_EXIT_RDTSCP: VMEXIT_CALL_RET(0, vmxHCExitRdtscp(pVCpu, pVmxTransient));
5896 case VMX_EXIT_APIC_ACCESS: VMEXIT_CALL_RET(0, vmxHCExitApicAccess(pVCpu, pVmxTransient));
5897 case VMX_EXIT_XCPT_OR_NMI: VMEXIT_CALL_RET(0, vmxHCExitXcptOrNmi(pVCpu, pVmxTransient));
5898 case VMX_EXIT_MOV_CRX: VMEXIT_CALL_RET(0, vmxHCExitMovCRx(pVCpu, pVmxTransient));
5899 case VMX_EXIT_EXT_INT: VMEXIT_CALL_RET(0, vmxHCExitExtInt(pVCpu, pVmxTransient));
5900 case VMX_EXIT_INT_WINDOW: VMEXIT_CALL_RET(0, vmxHCExitIntWindow(pVCpu, pVmxTransient));
5901 case VMX_EXIT_TPR_BELOW_THRESHOLD: VMEXIT_CALL_RET(0, vmxHCExitTprBelowThreshold(pVCpu, pVmxTransient));
5902 case VMX_EXIT_MWAIT: VMEXIT_CALL_RET(0, vmxHCExitMwait(pVCpu, pVmxTransient));
5903 case VMX_EXIT_MONITOR: VMEXIT_CALL_RET(0, vmxHCExitMonitor(pVCpu, pVmxTransient));
5904 case VMX_EXIT_TASK_SWITCH: VMEXIT_CALL_RET(0, vmxHCExitTaskSwitch(pVCpu, pVmxTransient));
5905 case VMX_EXIT_PREEMPT_TIMER: VMEXIT_CALL_RET(0, vmxHCExitPreemptTimer(pVCpu, pVmxTransient));
5906 case VMX_EXIT_RDMSR: VMEXIT_CALL_RET(0, vmxHCExitRdmsr(pVCpu, pVmxTransient));
5907 case VMX_EXIT_WRMSR: VMEXIT_CALL_RET(0, vmxHCExitWrmsr(pVCpu, pVmxTransient));
5908 case VMX_EXIT_VMCALL: VMEXIT_CALL_RET(0, vmxHCExitVmcall(pVCpu, pVmxTransient));
5909 case VMX_EXIT_MOV_DRX: VMEXIT_CALL_RET(0, vmxHCExitMovDRx(pVCpu, pVmxTransient));
5910 case VMX_EXIT_HLT: VMEXIT_CALL_RET(0, vmxHCExitHlt(pVCpu, pVmxTransient));
5911 case VMX_EXIT_INVD: VMEXIT_CALL_RET(0, vmxHCExitInvd(pVCpu, pVmxTransient));
5912 case VMX_EXIT_INVLPG: VMEXIT_CALL_RET(0, vmxHCExitInvlpg(pVCpu, pVmxTransient));
5913 case VMX_EXIT_MTF: VMEXIT_CALL_RET(0, vmxHCExitMtf(pVCpu, pVmxTransient));
5914 case VMX_EXIT_PAUSE: VMEXIT_CALL_RET(0, vmxHCExitPause(pVCpu, pVmxTransient));
5915 case VMX_EXIT_WBINVD: VMEXIT_CALL_RET(0, vmxHCExitWbinvd(pVCpu, pVmxTransient));
5916 case VMX_EXIT_XSETBV: VMEXIT_CALL_RET(0, vmxHCExitXsetbv(pVCpu, pVmxTransient));
5917 case VMX_EXIT_INVPCID: VMEXIT_CALL_RET(0, vmxHCExitInvpcid(pVCpu, pVmxTransient));
5918 case VMX_EXIT_GETSEC: VMEXIT_CALL_RET(0, vmxHCExitGetsec(pVCpu, pVmxTransient));
5919 case VMX_EXIT_RDPMC: VMEXIT_CALL_RET(0, vmxHCExitRdpmc(pVCpu, pVmxTransient));
5920#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5921 case VMX_EXIT_VMCLEAR: VMEXIT_CALL_RET(0, vmxHCExitVmclear(pVCpu, pVmxTransient));
5922 case VMX_EXIT_VMLAUNCH: VMEXIT_CALL_RET(0, vmxHCExitVmlaunch(pVCpu, pVmxTransient));
5923 case VMX_EXIT_VMPTRLD: VMEXIT_CALL_RET(0, vmxHCExitVmptrld(pVCpu, pVmxTransient));
5924 case VMX_EXIT_VMPTRST: VMEXIT_CALL_RET(0, vmxHCExitVmptrst(pVCpu, pVmxTransient));
5925 case VMX_EXIT_VMREAD: VMEXIT_CALL_RET(0, vmxHCExitVmread(pVCpu, pVmxTransient));
5926 case VMX_EXIT_VMRESUME: VMEXIT_CALL_RET(0, vmxHCExitVmwrite(pVCpu, pVmxTransient));
5927 case VMX_EXIT_VMWRITE: VMEXIT_CALL_RET(0, vmxHCExitVmresume(pVCpu, pVmxTransient));
5928 case VMX_EXIT_VMXOFF: VMEXIT_CALL_RET(0, vmxHCExitVmxoff(pVCpu, pVmxTransient));
5929 case VMX_EXIT_VMXON: VMEXIT_CALL_RET(0, vmxHCExitVmxon(pVCpu, pVmxTransient));
5930 case VMX_EXIT_INVVPID: VMEXIT_CALL_RET(0, vmxHCExitInvvpid(pVCpu, pVmxTransient));
5931#else
5932 case VMX_EXIT_VMCLEAR:
5933 case VMX_EXIT_VMLAUNCH:
5934 case VMX_EXIT_VMPTRLD:
5935 case VMX_EXIT_VMPTRST:
5936 case VMX_EXIT_VMREAD:
5937 case VMX_EXIT_VMRESUME:
5938 case VMX_EXIT_VMWRITE:
5939 case VMX_EXIT_VMXOFF:
5940 case VMX_EXIT_VMXON:
5941 case VMX_EXIT_INVVPID:
5942 return vmxHCExitSetPendingXcptUD(pVCpu, pVmxTransient);
5943#endif
5944#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
5945 case VMX_EXIT_INVEPT: VMEXIT_CALL_RET(0, vmxHCExitInvept(pVCpu, pVmxTransient));
5946#else
5947 case VMX_EXIT_INVEPT: return vmxHCExitSetPendingXcptUD(pVCpu, pVmxTransient);
5948#endif
5949
5950 case VMX_EXIT_TRIPLE_FAULT: return vmxHCExitTripleFault(pVCpu, pVmxTransient);
5951 case VMX_EXIT_NMI_WINDOW: return vmxHCExitNmiWindow(pVCpu, pVmxTransient);
5952 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return vmxHCExitErrInvalidGuestState(pVCpu, pVmxTransient);
5953
5954 case VMX_EXIT_INIT_SIGNAL:
5955 case VMX_EXIT_SIPI:
5956 case VMX_EXIT_IO_SMI:
5957 case VMX_EXIT_SMI:
5958 case VMX_EXIT_ERR_MSR_LOAD:
5959 case VMX_EXIT_ERR_MACHINE_CHECK:
5960 case VMX_EXIT_PML_FULL:
5961 case VMX_EXIT_VIRTUALIZED_EOI:
5962 case VMX_EXIT_GDTR_IDTR_ACCESS:
5963 case VMX_EXIT_LDTR_TR_ACCESS:
5964 case VMX_EXIT_APIC_WRITE:
5965 case VMX_EXIT_RDRAND:
5966 case VMX_EXIT_RSM:
5967 case VMX_EXIT_VMFUNC:
5968 case VMX_EXIT_ENCLS:
5969 case VMX_EXIT_RDSEED:
5970 case VMX_EXIT_XSAVES:
5971 case VMX_EXIT_XRSTORS:
5972 case VMX_EXIT_UMWAIT:
5973 case VMX_EXIT_TPAUSE:
5974 case VMX_EXIT_LOADIWKEY:
5975 default:
5976 return vmxHCExitErrUnexpected(pVCpu, pVmxTransient);
5977 }
5978#undef VMEXIT_CALL_RET
5979}
5980#endif /* !HMVMX_USE_FUNCTION_TABLE */
5981
5982
5983#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5984/**
5985 * Handles a nested-guest VM-exit from hardware-assisted VMX execution.
5986 *
5987 * @returns Strict VBox status code (i.e. informational status codes too).
5988 * @param pVCpu The cross context virtual CPU structure.
5989 * @param pVmxTransient The VMX-transient structure.
5990 */
5991DECLINLINE(VBOXSTRICTRC) vmxHCHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
5992{
5993#ifdef DEBUG_ramshankar
5994# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) \
5995 do { \
5996 if (a_fSave != 0) \
5997 vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__); \
5998 VBOXSTRICTRC rcStrict = a_CallExpr; \
5999 return rcStrict; \
6000 } while (0)
6001#else
6002# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) return a_CallExpr
6003#endif
6004
6005 uint32_t const uExitReason = pVmxTransient->uExitReason;
6006 switch (uExitReason)
6007 {
6008# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
6009 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, vmxHCExitEptMisconfigNested(pVCpu, pVmxTransient));
6010 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, vmxHCExitEptViolationNested(pVCpu, pVmxTransient));
6011# else
6012 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, vmxHCExitEptMisconfig(pVCpu, pVmxTransient));
6013 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, vmxHCExitEptViolation(pVCpu, pVmxTransient));
6014# endif
6015 case VMX_EXIT_XCPT_OR_NMI: VMEXIT_CALL_RET(0, vmxHCExitXcptOrNmiNested(pVCpu, pVmxTransient));
6016 case VMX_EXIT_IO_INSTR: VMEXIT_CALL_RET(0, vmxHCExitIoInstrNested(pVCpu, pVmxTransient));
6017 case VMX_EXIT_HLT: VMEXIT_CALL_RET(0, vmxHCExitHltNested(pVCpu, pVmxTransient));
6018
6019 /*
6020 * We shouldn't direct host physical interrupts to the nested-guest.
6021 */
6022 case VMX_EXIT_EXT_INT: VMEXIT_CALL_RET(0, vmxHCExitExtInt(pVCpu, pVmxTransient));
6023
6024 /*
6025 * Instructions that cause VM-exits unconditionally or the condition is
6026 * always taken solely from the nested hypervisor (meaning if the VM-exit
6027 * happens, it's guaranteed to be a nested-guest VM-exit).
6028 *
6029 * - Provides VM-exit instruction length ONLY.
6030 */
6031 case VMX_EXIT_CPUID: /* Unconditional. */
6032 case VMX_EXIT_VMCALL:
6033 case VMX_EXIT_GETSEC:
6034 case VMX_EXIT_INVD:
6035 case VMX_EXIT_XSETBV:
6036 case VMX_EXIT_VMLAUNCH:
6037 case VMX_EXIT_VMRESUME:
6038 case VMX_EXIT_VMXOFF:
6039 case VMX_EXIT_ENCLS: /* Condition specified solely by nested hypervisor. */
6040 case VMX_EXIT_VMFUNC:
6041 VMEXIT_CALL_RET(0, vmxHCExitInstrNested(pVCpu, pVmxTransient));
6042
6043 /*
6044 * Instructions that cause VM-exits unconditionally or the condition is
6045 * always taken solely from the nested hypervisor (meaning if the VM-exit
6046 * happens, it's guaranteed to be a nested-guest VM-exit).
6047 *
6048 * - Provides VM-exit instruction length.
6049 * - Provides VM-exit information.
6050 * - Optionally provides Exit qualification.
6051 *
6052 * Since Exit qualification is 0 for all VM-exits where it is not
6053 * applicable, reading and passing it to the guest should produce
6054 * defined behavior.
6055 *
6056 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
6057 */
6058 case VMX_EXIT_INVEPT: /* Unconditional. */
6059 case VMX_EXIT_INVVPID:
6060 case VMX_EXIT_VMCLEAR:
6061 case VMX_EXIT_VMPTRLD:
6062 case VMX_EXIT_VMPTRST:
6063 case VMX_EXIT_VMXON:
6064 case VMX_EXIT_GDTR_IDTR_ACCESS: /* Condition specified solely by nested hypervisor. */
6065 case VMX_EXIT_LDTR_TR_ACCESS:
6066 case VMX_EXIT_RDRAND:
6067 case VMX_EXIT_RDSEED:
6068 case VMX_EXIT_XSAVES:
6069 case VMX_EXIT_XRSTORS:
6070 case VMX_EXIT_UMWAIT:
6071 case VMX_EXIT_TPAUSE:
6072 VMEXIT_CALL_RET(0, vmxHCExitInstrWithInfoNested(pVCpu, pVmxTransient));
6073
6074 case VMX_EXIT_RDTSC: VMEXIT_CALL_RET(0, vmxHCExitRdtscNested(pVCpu, pVmxTransient));
6075 case VMX_EXIT_RDTSCP: VMEXIT_CALL_RET(0, vmxHCExitRdtscpNested(pVCpu, pVmxTransient));
6076 case VMX_EXIT_RDMSR: VMEXIT_CALL_RET(0, vmxHCExitRdmsrNested(pVCpu, pVmxTransient));
6077 case VMX_EXIT_WRMSR: VMEXIT_CALL_RET(0, vmxHCExitWrmsrNested(pVCpu, pVmxTransient));
6078 case VMX_EXIT_INVLPG: VMEXIT_CALL_RET(0, vmxHCExitInvlpgNested(pVCpu, pVmxTransient));
6079 case VMX_EXIT_INVPCID: VMEXIT_CALL_RET(0, vmxHCExitInvpcidNested(pVCpu, pVmxTransient));
6080 case VMX_EXIT_TASK_SWITCH: VMEXIT_CALL_RET(0, vmxHCExitTaskSwitchNested(pVCpu, pVmxTransient));
6081 case VMX_EXIT_WBINVD: VMEXIT_CALL_RET(0, vmxHCExitWbinvdNested(pVCpu, pVmxTransient));
6082 case VMX_EXIT_MTF: VMEXIT_CALL_RET(0, vmxHCExitMtfNested(pVCpu, pVmxTransient));
6083 case VMX_EXIT_APIC_ACCESS: VMEXIT_CALL_RET(0, vmxHCExitApicAccessNested(pVCpu, pVmxTransient));
6084 case VMX_EXIT_APIC_WRITE: VMEXIT_CALL_RET(0, vmxHCExitApicWriteNested(pVCpu, pVmxTransient));
6085 case VMX_EXIT_VIRTUALIZED_EOI: VMEXIT_CALL_RET(0, vmxHCExitVirtEoiNested(pVCpu, pVmxTransient));
6086 case VMX_EXIT_MOV_CRX: VMEXIT_CALL_RET(0, vmxHCExitMovCRxNested(pVCpu, pVmxTransient));
6087 case VMX_EXIT_INT_WINDOW: VMEXIT_CALL_RET(0, vmxHCExitIntWindowNested(pVCpu, pVmxTransient));
6088 case VMX_EXIT_NMI_WINDOW: VMEXIT_CALL_RET(0, vmxHCExitNmiWindowNested(pVCpu, pVmxTransient));
6089 case VMX_EXIT_TPR_BELOW_THRESHOLD: VMEXIT_CALL_RET(0, vmxHCExitTprBelowThresholdNested(pVCpu, pVmxTransient));
6090 case VMX_EXIT_MWAIT: VMEXIT_CALL_RET(0, vmxHCExitMwaitNested(pVCpu, pVmxTransient));
6091 case VMX_EXIT_MONITOR: VMEXIT_CALL_RET(0, vmxHCExitMonitorNested(pVCpu, pVmxTransient));
6092 case VMX_EXIT_PAUSE: VMEXIT_CALL_RET(0, vmxHCExitPauseNested(pVCpu, pVmxTransient));
6093
6094 case VMX_EXIT_PREEMPT_TIMER:
6095 {
6096 /** @todo NSTVMX: Preempt timer. */
6097 VMEXIT_CALL_RET(0, vmxHCExitPreemptTimer(pVCpu, pVmxTransient));
6098 }
6099
6100 case VMX_EXIT_MOV_DRX: VMEXIT_CALL_RET(0, vmxHCExitMovDRxNested(pVCpu, pVmxTransient));
6101 case VMX_EXIT_RDPMC: VMEXIT_CALL_RET(0, vmxHCExitRdpmcNested(pVCpu, pVmxTransient));
6102
6103 case VMX_EXIT_VMREAD:
6104 case VMX_EXIT_VMWRITE: VMEXIT_CALL_RET(0, vmxHCExitVmreadVmwriteNested(pVCpu, pVmxTransient));
6105
6106 case VMX_EXIT_TRIPLE_FAULT: VMEXIT_CALL_RET(0, vmxHCExitTripleFaultNested(pVCpu, pVmxTransient));
6107 case VMX_EXIT_ERR_INVALID_GUEST_STATE: VMEXIT_CALL_RET(0, vmxHCExitErrInvalidGuestStateNested(pVCpu, pVmxTransient));
6108
6109 case VMX_EXIT_INIT_SIGNAL:
6110 case VMX_EXIT_SIPI:
6111 case VMX_EXIT_IO_SMI:
6112 case VMX_EXIT_SMI:
6113 case VMX_EXIT_ERR_MSR_LOAD:
6114 case VMX_EXIT_ERR_MACHINE_CHECK:
6115 case VMX_EXIT_PML_FULL:
6116 case VMX_EXIT_RSM:
6117 default:
6118 return vmxHCExitErrUnexpected(pVCpu, pVmxTransient);
6119 }
6120#undef VMEXIT_CALL_RET
6121}
6122#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
6123
6124
6125/** @name VM-exit helpers.
6126 * @{
6127 */
6128/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
6129/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= VM-exit helpers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
6130/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
6131
6132/** Macro for VM-exits called unexpectedly. */
6133#define HMVMX_UNEXPECTED_EXIT_RET(a_pVCpu, a_HmError) \
6134 do { \
6135 VCPU_2_VMXSTATE((a_pVCpu)).u32HMError = (a_HmError); \
6136 return VERR_VMX_UNEXPECTED_EXIT; \
6137 } while (0)
6138
6139#ifdef VBOX_STRICT
6140# ifndef IN_NEM_DARWIN
6141/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
6142# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
6143 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
6144
6145# define HMVMX_ASSERT_PREEMPT_CPUID() \
6146 do { \
6147 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
6148 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
6149 } while (0)
6150
6151# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
6152 do { \
6153 AssertPtr((a_pVCpu)); \
6154 AssertPtr((a_pVmxTransient)); \
6155 Assert( (a_pVmxTransient)->fVMEntryFailed == false \
6156 || (a_pVmxTransient)->uExitReason == VMX_EXIT_ERR_INVALID_GUEST_STATE \
6157 || (a_pVmxTransient)->uExitReason == VMX_EXIT_ERR_MSR_LOAD \
6158 || (a_pVmxTransient)->uExitReason == VMX_EXIT_ERR_MACHINE_CHECK); \
6159 Assert((a_pVmxTransient)->pVmcsInfo); \
6160 Assert(ASMIntAreEnabled()); \
6161 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
6162 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
6163 Log4Func(("vcpu[%RU32]\n", (a_pVCpu)->idCpu)); \
6164 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
6165 if (!VMMRZCallRing3IsEnabled((a_pVCpu))) \
6166 HMVMX_ASSERT_PREEMPT_CPUID(); \
6167 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
6168 } while (0)
6169# else
6170# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() do { } while(0)
6171# define HMVMX_ASSERT_PREEMPT_CPUID() do { } while(0)
6172# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
6173 do { \
6174 AssertPtr((a_pVCpu)); \
6175 AssertPtr((a_pVmxTransient)); \
6176 Assert( (a_pVmxTransient)->fVMEntryFailed == false \
6177 || (a_pVmxTransient)->uExitReason == VMX_EXIT_ERR_INVALID_GUEST_STATE \
6178 || (a_pVmxTransient)->uExitReason == VMX_EXIT_ERR_MSR_LOAD \
6179 || (a_pVmxTransient)->uExitReason == VMX_EXIT_ERR_MACHINE_CHECK); \
6180 Assert((a_pVmxTransient)->pVmcsInfo); \
6181 Log4Func(("vcpu[%RU32]\n", (a_pVCpu)->idCpu)); \
6182 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
6183 } while (0)
6184# endif
6185
6186# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
6187 do { \
6188 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); \
6189 Assert((a_pVmxTransient)->fIsNestedGuest); \
6190 } while (0)
6191
6192# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
6193 do { \
6194 Log4Func(("\n")); \
6195 } while (0)
6196#else
6197# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
6198 do { \
6199 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
6200 NOREF((a_pVCpu)); NOREF((a_pVmxTransient)); \
6201 } while (0)
6202
6203# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
6204 do { HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); } while (0)
6205
6206# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) do { } while (0)
6207#endif
6208
6209#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6210/** Macro that does the necessary privilege checks and intercepted VM-exits for
6211 * guests that attempted to execute a VMX instruction. */
6212# define HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(a_pVCpu, a_uExitReason) \
6213 do \
6214 { \
6215 VBOXSTRICTRC rcStrictTmp = vmxHCCheckExitDueToVmxInstr((a_pVCpu), (a_uExitReason)); \
6216 if (rcStrictTmp == VINF_SUCCESS) \
6217 { /* likely */ } \
6218 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
6219 { \
6220 Assert((a_pVCpu)->hm.s.Event.fPending); \
6221 Log4Func(("Privilege checks failed -> %#x\n", VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo))); \
6222 return VINF_SUCCESS; \
6223 } \
6224 else \
6225 { \
6226 int rcTmp = VBOXSTRICTRC_VAL(rcStrictTmp); \
6227 AssertMsgFailedReturn(("Unexpected failure. rc=%Rrc", rcTmp), rcTmp); \
6228 } \
6229 } while (0)
6230
6231/** Macro that decodes a memory operand for an VM-exit caused by an instruction. */
6232# define HMVMX_DECODE_MEM_OPERAND(a_pVCpu, a_uExitInstrInfo, a_uExitQual, a_enmMemAccess, a_pGCPtrEffAddr) \
6233 do \
6234 { \
6235 VBOXSTRICTRC rcStrictTmp = vmxHCDecodeMemOperand((a_pVCpu), (a_uExitInstrInfo), (a_uExitQual), (a_enmMemAccess), \
6236 (a_pGCPtrEffAddr)); \
6237 if (rcStrictTmp == VINF_SUCCESS) \
6238 { /* likely */ } \
6239 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
6240 { \
6241 uint8_t const uXcptTmp = VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo); \
6242 Log4Func(("Memory operand decoding failed, raising xcpt %#x\n", uXcptTmp)); \
6243 NOREF(uXcptTmp); \
6244 return VINF_SUCCESS; \
6245 } \
6246 else \
6247 { \
6248 Log4Func(("vmxHCDecodeMemOperand failed. rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrictTmp))); \
6249 return rcStrictTmp; \
6250 } \
6251 } while (0)
6252#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
6253
6254
6255/**
6256 * Advances the guest RIP by the specified number of bytes.
6257 *
6258 * @param pVCpu The cross context virtual CPU structure.
6259 * @param cbInstr Number of bytes to advance the RIP by.
6260 *
6261 * @remarks No-long-jump zone!!!
6262 */
6263DECLINLINE(void) vmxHCAdvanceGuestRipBy(PVMCPUCC pVCpu, uint32_t cbInstr)
6264{
6265 CPUM_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI);
6266
6267 /*
6268 * Advance RIP.
6269 *
6270 * The upper 32 bits are only set when in 64-bit mode, so we have to detect
6271 * when the addition causes a "carry" into the upper half and check whether
6272 * we're in 64-bit and can go on with it or wether we should zap the top
6273 * half. (Note! The 8086, 80186 and 80286 emulation is done exclusively in
6274 * IEM, so we don't need to bother with pre-386 16-bit wraparound.)
6275 *
6276 * See PC wrap around tests in bs3-cpu-weird-1.
6277 */
6278 uint64_t const uRipPrev = pVCpu->cpum.GstCtx.rip;
6279 uint64_t const uRipNext = uRipPrev + cbInstr;
6280 if (RT_LIKELY( !((uRipNext ^ uRipPrev) & RT_BIT_64(32))
6281 || CPUMIsGuestIn64BitCodeEx(&pVCpu->cpum.GstCtx)))
6282 pVCpu->cpum.GstCtx.rip = uRipNext;
6283 else
6284 pVCpu->cpum.GstCtx.rip = (uint32_t)uRipNext;
6285
6286 /*
6287 * Clear RF and interrupt shadowing.
6288 */
6289 if (RT_LIKELY(!(pVCpu->cpum.GstCtx.eflags.uBoth & (X86_EFL_RF | X86_EFL_TF))))
6290 pVCpu->cpum.GstCtx.eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW;
6291 else
6292 {
6293 if ((pVCpu->cpum.GstCtx.eflags.uBoth & (X86_EFL_RF | X86_EFL_TF)) == X86_EFL_TF)
6294 {
6295 /** @todo \#DB - single step. */
6296 }
6297 pVCpu->cpum.GstCtx.eflags.uBoth &= ~(X86_EFL_RF | CPUMCTX_INHIBIT_SHADOW);
6298 }
6299 AssertCompile(CPUMCTX_INHIBIT_SHADOW < UINT32_MAX);
6300
6301 /* Mark both RIP and RFLAGS as updated. */
6302 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
6303}
6304
6305
6306/**
6307 * Advances the guest RIP after reading it from the VMCS.
6308 *
6309 * @returns VBox status code, no informational status codes.
6310 * @param pVCpu The cross context virtual CPU structure.
6311 * @param pVmxTransient The VMX-transient structure.
6312 *
6313 * @remarks No-long-jump zone!!!
6314 */
6315static int vmxHCAdvanceGuestRip(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6316{
6317 vmxHCReadToTransientSlow<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
6318 /** @todo consider template here after checking callers. */
6319 int rc = vmxHCImportGuestStateEx(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
6320 AssertRCReturn(rc, rc);
6321
6322 vmxHCAdvanceGuestRipBy(pVCpu, pVmxTransient->cbExitInstr);
6323 return VINF_SUCCESS;
6324}
6325
6326
6327/**
6328 * Handle a condition that occurred while delivering an event through the guest or
6329 * nested-guest IDT.
6330 *
6331 * @returns Strict VBox status code (i.e. informational status codes too).
6332 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
6333 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
6334 * to continue execution of the guest which will delivery the \#DF.
6335 * @retval VINF_EM_RESET if we detected a triple-fault condition.
6336 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
6337 *
6338 * @param pVCpu The cross context virtual CPU structure.
6339 * @param pVmxTransient The VMX-transient structure.
6340 *
6341 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
6342 * Additionally, HMVMX_READ_EXIT_QUALIFICATION is required if the VM-exit
6343 * is due to an EPT violation, PML full or SPP-related event.
6344 *
6345 * @remarks No-long-jump zone!!!
6346 */
6347static VBOXSTRICTRC vmxHCCheckExitDueToEventDelivery(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6348{
6349 Assert(!VCPU_2_VMXSTATE(pVCpu).Event.fPending);
6350 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
6351 if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
6352 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
6353 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
6354 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_EXIT_QUALIFICATION);
6355
6356 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
6357 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6358 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo;
6359 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
6360 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo))
6361 {
6362 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo);
6363 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo);
6364
6365 /*
6366 * If the event was a software interrupt (generated with INT n) or a software exception
6367 * (generated by INT3/INTO) or a privileged software exception (generated by INT1), we
6368 * can handle the VM-exit and continue guest execution which will re-execute the
6369 * instruction rather than re-injecting the exception, as that can cause premature
6370 * trips to ring-3 before injection and involve TRPM which currently has no way of
6371 * storing that these exceptions were caused by these instructions (ICEBP's #DB poses
6372 * the problem).
6373 */
6374 IEMXCPTRAISE enmRaise;
6375 IEMXCPTRAISEINFO fRaiseInfo;
6376 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
6377 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
6378 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
6379 {
6380 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
6381 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
6382 }
6383 else if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo))
6384 {
6385 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
6386 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo);
6387 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT);
6388
6389 uint32_t const fIdtVectorFlags = vmxHCGetIemXcptFlags(uIdtVector, uIdtVectorType);
6390 uint32_t const fExitVectorFlags = vmxHCGetIemXcptFlags(uExitVector, uExitVectorType);
6391
6392 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo);
6393
6394 /* Determine a vectoring #PF condition, see comment in vmxHCExitXcptPF(). */
6395 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
6396 {
6397 pVmxTransient->fVectoringPF = true;
6398 enmRaise = IEMXCPTRAISE_PREV_EVENT;
6399 }
6400 }
6401 else
6402 {
6403 /*
6404 * If an exception or hardware interrupt delivery caused an EPT violation/misconfig or APIC access
6405 * VM-exit, then the VM-exit interruption-information will not be valid and we end up here.
6406 * It is sufficient to reflect the original event to the guest after handling the VM-exit.
6407 */
6408 Assert( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
6409 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
6410 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
6411 enmRaise = IEMXCPTRAISE_PREV_EVENT;
6412 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
6413 }
6414
6415 /*
6416 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
6417 * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
6418 * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
6419 * subsequent VM-entry would fail, see @bugref{7445}.
6420 *
6421 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception".
6422 */
6423 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
6424 && enmRaise == IEMXCPTRAISE_PREV_EVENT
6425 && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
6426 && CPUMAreInterruptsInhibitedByNmiEx(&pVCpu->cpum.GstCtx))
6427 CPUMClearInterruptInhibitingByNmiEx(&pVCpu->cpum.GstCtx);
6428
6429 switch (enmRaise)
6430 {
6431 case IEMXCPTRAISE_CURRENT_XCPT:
6432 {
6433 Log4Func(("IDT: Pending secondary Xcpt: idtinfo=%#RX64 exitinfo=%#RX64\n", uIdtVectorInfo, uExitIntInfo));
6434 Assert(rcStrict == VINF_SUCCESS);
6435 break;
6436 }
6437
6438 case IEMXCPTRAISE_PREV_EVENT:
6439 {
6440 uint32_t u32ErrCode;
6441 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo))
6442 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
6443 else
6444 u32ErrCode = 0;
6445
6446 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see vmxHCExitXcptPF(). */
6447 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatInjectReflect);
6448 vmxHCSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(uIdtVectorInfo), 0 /* cbInstr */, u32ErrCode,
6449 pVCpu->cpum.GstCtx.cr2);
6450
6451 Log4Func(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", VCPU_2_VMXSTATE(pVCpu).Event.u64IntInfo,
6452 VCPU_2_VMXSTATE(pVCpu).Event.u32ErrCode));
6453 Assert(rcStrict == VINF_SUCCESS);
6454 break;
6455 }
6456
6457 case IEMXCPTRAISE_REEXEC_INSTR:
6458 Assert(rcStrict == VINF_SUCCESS);
6459 break;
6460
6461 case IEMXCPTRAISE_DOUBLE_FAULT:
6462 {
6463 /*
6464 * Determine a vectoring double #PF condition. Used later, when PGM evaluates the
6465 * second #PF as a guest #PF (and not a shadow #PF) and needs to be converted into a #DF.
6466 */
6467 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
6468 {
6469 pVmxTransient->fVectoringDoublePF = true;
6470 Log4Func(("IDT: Vectoring double #PF %#RX64 cr2=%#RX64\n", VCPU_2_VMXSTATE(pVCpu).Event.u64IntInfo,
6471 pVCpu->cpum.GstCtx.cr2));
6472 rcStrict = VINF_SUCCESS;
6473 }
6474 else
6475 {
6476 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatInjectConvertDF);
6477 vmxHCSetPendingXcptDF(pVCpu);
6478 Log4Func(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", VCPU_2_VMXSTATE(pVCpu).Event.u64IntInfo,
6479 uIdtVector, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
6480 rcStrict = VINF_HM_DOUBLE_FAULT;
6481 }
6482 break;
6483 }
6484
6485 case IEMXCPTRAISE_TRIPLE_FAULT:
6486 {
6487 Log4Func(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector,
6488 VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
6489 rcStrict = VINF_EM_RESET;
6490 break;
6491 }
6492
6493 case IEMXCPTRAISE_CPU_HANG:
6494 {
6495 Log4Func(("IDT: Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", fRaiseInfo));
6496 rcStrict = VERR_EM_GUEST_CPU_HANG;
6497 break;
6498 }
6499
6500 default:
6501 {
6502 AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
6503 rcStrict = VERR_VMX_IPE_2;
6504 break;
6505 }
6506 }
6507 }
6508 else if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
6509 && !CPUMAreInterruptsInhibitedByNmiEx(&pVCpu->cpum.GstCtx))
6510 {
6511 if ( VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)
6512 && VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo) != X86_XCPT_DF
6513 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(uExitIntInfo))
6514 {
6515 /*
6516 * Execution of IRET caused a fault when NMI blocking was in effect (i.e we're in
6517 * the guest or nested-guest NMI handler). We need to set the block-by-NMI field so
6518 * that virtual NMIs remain blocked until the IRET execution is completed.
6519 *
6520 * See Intel spec. 31.7.1.2 "Resuming Guest Software After Handling An Exception".
6521 */
6522 CPUMSetInterruptInhibitingByNmiEx(&pVCpu->cpum.GstCtx);
6523 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
6524 }
6525 else if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
6526 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
6527 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
6528 {
6529 /*
6530 * Execution of IRET caused an EPT violation, page-modification log-full event or
6531 * SPP-related event VM-exit when NMI blocking was in effect (i.e. we're in the
6532 * guest or nested-guest NMI handler). We need to set the block-by-NMI field so
6533 * that virtual NMIs remain blocked until the IRET execution is completed.
6534 *
6535 * See Intel spec. 27.2.3 "Information about NMI unblocking due to IRET"
6536 */
6537 if (VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(pVmxTransient->uExitQual))
6538 {
6539 CPUMSetInterruptInhibitingByNmiEx(&pVCpu->cpum.GstCtx);
6540 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
6541 }
6542 }
6543 }
6544
6545 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
6546 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
6547 return rcStrict;
6548}
6549
6550
6551#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6552/**
6553 * Perform the relevant VMX instruction checks for VM-exits that occurred due to the
6554 * guest attempting to execute a VMX instruction.
6555 *
6556 * @returns Strict VBox status code (i.e. informational status codes too).
6557 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
6558 * @retval VINF_HM_PENDING_XCPT if an exception was raised.
6559 *
6560 * @param pVCpu The cross context virtual CPU structure.
6561 * @param uExitReason The VM-exit reason.
6562 *
6563 * @todo NSTVMX: Document other error codes when VM-exit is implemented.
6564 * @remarks No-long-jump zone!!!
6565 */
6566static VBOXSTRICTRC vmxHCCheckExitDueToVmxInstr(PVMCPUCC pVCpu, uint32_t uExitReason)
6567{
6568 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS
6569 | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
6570
6571 /*
6572 * The physical CPU would have already checked the CPU mode/code segment.
6573 * We shall just assert here for paranoia.
6574 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
6575 */
6576 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
6577 Assert( !CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx)
6578 || CPUMIsGuestIn64BitCodeEx(&pVCpu->cpum.GstCtx));
6579
6580 if (uExitReason == VMX_EXIT_VMXON)
6581 {
6582 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
6583
6584 /*
6585 * We check CR4.VMXE because it is required to be always set while in VMX operation
6586 * by physical CPUs and our CR4 read-shadow is only consulted when executing specific
6587 * instructions (CLTS, LMSW, MOV CR, and SMSW) and thus doesn't affect CPU operation
6588 * otherwise (i.e. physical CPU won't automatically #UD if Cr4Shadow.VMXE is 0).
6589 */
6590 if (!CPUMIsGuestVmxEnabled(&pVCpu->cpum.GstCtx))
6591 {
6592 Log4Func(("CR4.VMXE is not set -> #UD\n"));
6593 vmxHCSetPendingXcptUD(pVCpu);
6594 return VINF_HM_PENDING_XCPT;
6595 }
6596 }
6597 else if (!CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx))
6598 {
6599 /*
6600 * The guest has not entered VMX operation but attempted to execute a VMX instruction
6601 * (other than VMXON), we need to raise a #UD.
6602 */
6603 Log4Func(("Not in VMX root mode -> #UD\n"));
6604 vmxHCSetPendingXcptUD(pVCpu);
6605 return VINF_HM_PENDING_XCPT;
6606 }
6607
6608 /* All other checks (including VM-exit intercepts) are handled by IEM instruction emulation. */
6609 return VINF_SUCCESS;
6610}
6611
6612
6613/**
6614 * Decodes the memory operand of an instruction that caused a VM-exit.
6615 *
6616 * The Exit qualification field provides the displacement field for memory
6617 * operand instructions, if any.
6618 *
6619 * @returns Strict VBox status code (i.e. informational status codes too).
6620 * @retval VINF_SUCCESS if the operand was successfully decoded.
6621 * @retval VINF_HM_PENDING_XCPT if an exception was raised while decoding the
6622 * operand.
6623 * @param pVCpu The cross context virtual CPU structure.
6624 * @param uExitInstrInfo The VM-exit instruction information field.
6625 * @param enmMemAccess The memory operand's access type (read or write).
6626 * @param GCPtrDisp The instruction displacement field, if any. For
6627 * RIP-relative addressing pass RIP + displacement here.
6628 * @param pGCPtrMem Where to store the effective destination memory address.
6629 *
6630 * @remarks Warning! This function ASSUMES the instruction cannot be used in real or
6631 * virtual-8086 mode hence skips those checks while verifying if the
6632 * segment is valid.
6633 */
6634static VBOXSTRICTRC vmxHCDecodeMemOperand(PVMCPUCC pVCpu, uint32_t uExitInstrInfo, RTGCPTR GCPtrDisp, VMXMEMACCESS enmMemAccess,
6635 PRTGCPTR pGCPtrMem)
6636{
6637 Assert(pGCPtrMem);
6638 Assert(!CPUMIsGuestInRealOrV86Mode(pVCpu));
6639 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_EFER
6640 | CPUMCTX_EXTRN_CR0);
6641
6642 static uint64_t const s_auAddrSizeMasks[] = { UINT64_C(0xffff), UINT64_C(0xffffffff), UINT64_C(0xffffffffffffffff) };
6643 static uint64_t const s_auAccessSizeMasks[] = { sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t) };
6644 AssertCompile(RT_ELEMENTS(s_auAccessSizeMasks) == RT_ELEMENTS(s_auAddrSizeMasks));
6645
6646 VMXEXITINSTRINFO ExitInstrInfo;
6647 ExitInstrInfo.u = uExitInstrInfo;
6648 uint8_t const uAddrSize = ExitInstrInfo.All.u3AddrSize;
6649 uint8_t const iSegReg = ExitInstrInfo.All.iSegReg;
6650 bool const fIdxRegValid = !ExitInstrInfo.All.fIdxRegInvalid;
6651 uint8_t const iIdxReg = ExitInstrInfo.All.iIdxReg;
6652 uint8_t const uScale = ExitInstrInfo.All.u2Scaling;
6653 bool const fBaseRegValid = !ExitInstrInfo.All.fBaseRegInvalid;
6654 uint8_t const iBaseReg = ExitInstrInfo.All.iBaseReg;
6655 bool const fIsMemOperand = !ExitInstrInfo.All.fIsRegOperand;
6656 bool const fIsLongMode = CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx);
6657
6658 /*
6659 * Validate instruction information.
6660 * This shouldn't happen on real hardware but useful while testing our nested hardware-virtualization code.
6661 */
6662 AssertLogRelMsgReturn(uAddrSize < RT_ELEMENTS(s_auAddrSizeMasks),
6663 ("Invalid address size. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_1);
6664 AssertLogRelMsgReturn(iSegReg < X86_SREG_COUNT,
6665 ("Invalid segment register. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_2);
6666 AssertLogRelMsgReturn(fIsMemOperand,
6667 ("Expected memory operand. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_3);
6668
6669 /*
6670 * Compute the complete effective address.
6671 *
6672 * See AMD instruction spec. 1.4.2 "SIB Byte Format"
6673 * See AMD spec. 4.5.2 "Segment Registers".
6674 */
6675 RTGCPTR GCPtrMem = GCPtrDisp;
6676 if (fBaseRegValid)
6677 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iBaseReg].u64;
6678 if (fIdxRegValid)
6679 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iIdxReg].u64 << uScale;
6680
6681 RTGCPTR const GCPtrOff = GCPtrMem;
6682 if ( !fIsLongMode
6683 || iSegReg >= X86_SREG_FS)
6684 GCPtrMem += pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
6685 GCPtrMem &= s_auAddrSizeMasks[uAddrSize];
6686
6687 /*
6688 * Validate effective address.
6689 * See AMD spec. 4.5.3 "Segment Registers in 64-Bit Mode".
6690 */
6691 uint8_t const cbAccess = s_auAccessSizeMasks[uAddrSize];
6692 Assert(cbAccess > 0);
6693 if (fIsLongMode)
6694 {
6695 if (X86_IS_CANONICAL(GCPtrMem))
6696 {
6697 *pGCPtrMem = GCPtrMem;
6698 return VINF_SUCCESS;
6699 }
6700
6701 /** @todo r=ramshankar: We should probably raise \#SS or \#GP. See AMD spec. 4.12.2
6702 * "Data Limit Checks in 64-bit Mode". */
6703 Log4Func(("Long mode effective address is not canonical GCPtrMem=%#RX64\n", GCPtrMem));
6704 vmxHCSetPendingXcptGP(pVCpu, 0);
6705 return VINF_HM_PENDING_XCPT;
6706 }
6707
6708 /*
6709 * This is a watered down version of iemMemApplySegment().
6710 * Parts that are not applicable for VMX instructions like real-or-v8086 mode
6711 * and segment CPL/DPL checks are skipped.
6712 */
6713 RTGCPTR32 const GCPtrFirst32 = (RTGCPTR32)GCPtrOff;
6714 RTGCPTR32 const GCPtrLast32 = GCPtrFirst32 + cbAccess - 1;
6715 PCCPUMSELREG pSel = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
6716
6717 /* Check if the segment is present and usable. */
6718 if ( pSel->Attr.n.u1Present
6719 && !pSel->Attr.n.u1Unusable)
6720 {
6721 Assert(pSel->Attr.n.u1DescType);
6722 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
6723 {
6724 /* Check permissions for the data segment. */
6725 if ( enmMemAccess == VMXMEMACCESS_WRITE
6726 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE))
6727 {
6728 Log4Func(("Data segment access invalid. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
6729 vmxHCSetPendingXcptGP(pVCpu, iSegReg);
6730 return VINF_HM_PENDING_XCPT;
6731 }
6732
6733 /* Check limits if it's a normal data segment. */
6734 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
6735 {
6736 if ( GCPtrFirst32 > pSel->u32Limit
6737 || GCPtrLast32 > pSel->u32Limit)
6738 {
6739 Log4Func(("Data segment limit exceeded. "
6740 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
6741 GCPtrLast32, pSel->u32Limit));
6742 if (iSegReg == X86_SREG_SS)
6743 vmxHCSetPendingXcptSS(pVCpu, 0);
6744 else
6745 vmxHCSetPendingXcptGP(pVCpu, 0);
6746 return VINF_HM_PENDING_XCPT;
6747 }
6748 }
6749 else
6750 {
6751 /* Check limits if it's an expand-down data segment.
6752 Note! The upper boundary is defined by the B bit, not the G bit! */
6753 if ( GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
6754 || GCPtrLast32 > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
6755 {
6756 Log4Func(("Expand-down data segment limit exceeded. "
6757 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
6758 GCPtrLast32, pSel->u32Limit));
6759 if (iSegReg == X86_SREG_SS)
6760 vmxHCSetPendingXcptSS(pVCpu, 0);
6761 else
6762 vmxHCSetPendingXcptGP(pVCpu, 0);
6763 return VINF_HM_PENDING_XCPT;
6764 }
6765 }
6766 }
6767 else
6768 {
6769 /* Check permissions for the code segment. */
6770 if ( enmMemAccess == VMXMEMACCESS_WRITE
6771 || ( enmMemAccess == VMXMEMACCESS_READ
6772 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)))
6773 {
6774 Log4Func(("Code segment access invalid. Attr=%#RX32\n", pSel->Attr.u));
6775 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
6776 vmxHCSetPendingXcptGP(pVCpu, 0);
6777 return VINF_HM_PENDING_XCPT;
6778 }
6779
6780 /* Check limits for the code segment (normal/expand-down not applicable for code segments). */
6781 if ( GCPtrFirst32 > pSel->u32Limit
6782 || GCPtrLast32 > pSel->u32Limit)
6783 {
6784 Log4Func(("Code segment limit exceeded. GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n",
6785 GCPtrFirst32, GCPtrLast32, pSel->u32Limit));
6786 if (iSegReg == X86_SREG_SS)
6787 vmxHCSetPendingXcptSS(pVCpu, 0);
6788 else
6789 vmxHCSetPendingXcptGP(pVCpu, 0);
6790 return VINF_HM_PENDING_XCPT;
6791 }
6792 }
6793 }
6794 else
6795 {
6796 Log4Func(("Not present or unusable segment. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
6797 vmxHCSetPendingXcptGP(pVCpu, 0);
6798 return VINF_HM_PENDING_XCPT;
6799 }
6800
6801 *pGCPtrMem = GCPtrMem;
6802 return VINF_SUCCESS;
6803}
6804#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
6805
6806
6807/**
6808 * VM-exit helper for LMSW.
6809 */
6810static VBOXSTRICTRC vmxHCExitLmsw(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst)
6811{
6812 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_MUST_MASK>(pVCpu, pVmcsInfo, __FUNCTION__);
6813 AssertRCReturn(rc, rc);
6814
6815 VBOXSTRICTRC rcStrict = IEMExecDecodedLmsw(pVCpu, cbInstr, uMsw, GCPtrEffDst);
6816 AssertMsg( rcStrict == VINF_SUCCESS
6817 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
6818
6819 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
6820 if (rcStrict == VINF_IEM_RAISED_XCPT)
6821 {
6822 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
6823 rcStrict = VINF_SUCCESS;
6824 }
6825
6826 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitLmsw);
6827 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
6828 return rcStrict;
6829}
6830
6831
6832/**
6833 * VM-exit helper for CLTS.
6834 */
6835static VBOXSTRICTRC vmxHCExitClts(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
6836{
6837 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_MUST_MASK>(pVCpu, pVmcsInfo, __FUNCTION__);
6838 AssertRCReturn(rc, rc);
6839
6840 VBOXSTRICTRC rcStrict = IEMExecDecodedClts(pVCpu, cbInstr);
6841 AssertMsg( rcStrict == VINF_SUCCESS
6842 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
6843
6844 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
6845 if (rcStrict == VINF_IEM_RAISED_XCPT)
6846 {
6847 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
6848 rcStrict = VINF_SUCCESS;
6849 }
6850
6851 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitClts);
6852 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
6853 return rcStrict;
6854}
6855
6856
6857/**
6858 * VM-exit helper for MOV from CRx (CRx read).
6859 */
6860static VBOXSTRICTRC vmxHCExitMovFromCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
6861{
6862 Assert(iCrReg < 16);
6863 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
6864
6865 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_MUST_MASK>(pVCpu, pVmcsInfo, __FUNCTION__);
6866 AssertRCReturn(rc, rc);
6867
6868 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxRead(pVCpu, cbInstr, iGReg, iCrReg);
6869 AssertMsg( rcStrict == VINF_SUCCESS
6870 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
6871
6872 if (iGReg == X86_GREG_xSP)
6873 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_RSP);
6874 else
6875 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
6876#ifdef VBOX_WITH_STATISTICS
6877 switch (iCrReg)
6878 {
6879 case 0: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitCR0Read); break;
6880 case 2: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitCR2Read); break;
6881 case 3: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitCR3Read); break;
6882 case 4: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitCR4Read); break;
6883 case 8: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitCR8Read); break;
6884 }
6885#endif
6886 Log4Func(("CR%d Read access rcStrict=%Rrc\n", iCrReg, VBOXSTRICTRC_VAL(rcStrict)));
6887 return rcStrict;
6888}
6889
6890
6891/**
6892 * VM-exit helper for MOV to CRx (CRx write).
6893 */
6894static VBOXSTRICTRC vmxHCExitMovToCrX(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
6895{
6896 HMVMX_CPUMCTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_MUST_MASK);
6897
6898 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, cbInstr, iCrReg, iGReg);
6899 AssertMsg( rcStrict == VINF_SUCCESS
6900 || rcStrict == VINF_IEM_RAISED_XCPT
6901 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
6902
6903 switch (iCrReg)
6904 {
6905 case 0:
6906 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0
6907 | HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
6908 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitCR0Write);
6909 Log4Func(("CR0 write. rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr0));
6910 break;
6911
6912 case 2:
6913 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitCR2Write);
6914 /* Nothing to do here, CR2 it's not part of the VMCS. */
6915 break;
6916
6917 case 3:
6918 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR3);
6919 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitCR3Write);
6920 Log4Func(("CR3 write. rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr3));
6921 break;
6922
6923 case 4:
6924 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR4);
6925 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitCR4Write);
6926#ifndef IN_NEM_DARWIN
6927 Log4Func(("CR4 write. rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n", VBOXSTRICTRC_VAL(rcStrict),
6928 pVCpu->cpum.GstCtx.cr4, pVCpu->hmr0.s.fLoadSaveGuestXcr0));
6929#else
6930 Log4Func(("CR4 write. rc=%Rrc CR4=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr4));
6931#endif
6932 break;
6933
6934 case 8:
6935 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged,
6936 HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_APIC_TPR);
6937 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitCR8Write);
6938 break;
6939
6940 default:
6941 AssertMsgFailed(("Invalid CRx register %#x\n", iCrReg));
6942 break;
6943 }
6944
6945 if (rcStrict == VINF_IEM_RAISED_XCPT)
6946 {
6947 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
6948 rcStrict = VINF_SUCCESS;
6949 }
6950 return rcStrict;
6951}
6952
6953
6954/**
6955 * VM-exit exception handler for \#PF (Page-fault exception).
6956 *
6957 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
6958 */
6959static VBOXSTRICTRC vmxHCExitXcptPF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6960{
6961 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
6962 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
6963
6964#ifndef IN_NEM_DARWIN
6965 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6966 if (!VM_IS_VMX_NESTED_PAGING(pVM))
6967 { /* likely */ }
6968 else
6969#endif
6970 {
6971#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF) && !defined(IN_NEM_DARWIN)
6972 Assert(pVmxTransient->fIsNestedGuest || pVCpu->hmr0.s.fUsingDebugLoop);
6973#endif
6974 VCPU_2_VMXSTATE(pVCpu).Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
6975 if (!pVmxTransient->fVectoringDoublePF)
6976 {
6977 vmxHCSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
6978 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual);
6979 }
6980 else
6981 {
6982 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
6983 Assert(!pVmxTransient->fIsNestedGuest);
6984 vmxHCSetPendingXcptDF(pVCpu);
6985 Log4Func(("Pending #DF due to vectoring #PF w/ NestedPaging\n"));
6986 }
6987 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestPF);
6988 return VINF_SUCCESS;
6989 }
6990
6991 Assert(!pVmxTransient->fIsNestedGuest);
6992
6993 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
6994 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
6995 if (pVmxTransient->fVectoringPF)
6996 {
6997 Assert(VCPU_2_VMXSTATE(pVCpu).Event.fPending);
6998 return VINF_EM_RAW_INJECT_TRPM_EVENT;
6999 }
7000
7001 int rc = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
7002 AssertRCReturn(rc, rc);
7003
7004 Log4Func(("#PF: cs:rip=%#04x:%08RX64 err_code=%#RX32 exit_qual=%#RX64 cr3=%#RX64\n", pVCpu->cpum.GstCtx.cs.Sel,
7005 pVCpu->cpum.GstCtx.rip, pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual, pVCpu->cpum.GstCtx.cr3));
7006
7007 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQual, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
7008 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, &pVCpu->cpum.GstCtx, (RTGCPTR)pVmxTransient->uExitQual);
7009
7010 Log4Func(("#PF: rc=%Rrc\n", rc));
7011 if (rc == VINF_SUCCESS)
7012 {
7013 /*
7014 * This is typically a shadow page table sync or a MMIO instruction. But we may have
7015 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
7016 */
7017 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST);
7018 TRPMResetTrap(pVCpu);
7019 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitShadowPF);
7020 return rc;
7021 }
7022
7023 if (rc == VINF_EM_RAW_GUEST_TRAP)
7024 {
7025 if (!pVmxTransient->fVectoringDoublePF)
7026 {
7027 /* It's a guest page fault and needs to be reflected to the guest. */
7028 uint32_t const uGstErrorCode = TRPMGetErrorCode(pVCpu);
7029 TRPMResetTrap(pVCpu);
7030 VCPU_2_VMXSTATE(pVCpu).Event.fPending = false; /* In case it's a contributory #PF. */
7031 vmxHCSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
7032 uGstErrorCode, pVmxTransient->uExitQual);
7033 }
7034 else
7035 {
7036 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
7037 TRPMResetTrap(pVCpu);
7038 VCPU_2_VMXSTATE(pVCpu).Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
7039 vmxHCSetPendingXcptDF(pVCpu);
7040 Log4Func(("#PF: Pending #DF due to vectoring #PF\n"));
7041 }
7042
7043 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestPF);
7044 return VINF_SUCCESS;
7045 }
7046
7047 TRPMResetTrap(pVCpu);
7048 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitShadowPFEM);
7049 return rc;
7050}
7051
7052
7053/**
7054 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
7055 *
7056 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
7057 */
7058static VBOXSTRICTRC vmxHCExitXcptMF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7059{
7060 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7061 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestMF);
7062
7063 int rc = vmxHCImportGuestState<CPUMCTX_EXTRN_CR0>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
7064 AssertRCReturn(rc, rc);
7065
7066 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_NE))
7067 {
7068 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
7069 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
7070
7071 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
7072 * provides VM-exit instruction length. If this causes problem later,
7073 * disassemble the instruction like it's done on AMD-V. */
7074 int rc2 = vmxHCAdvanceGuestRip(pVCpu, pVmxTransient);
7075 AssertRCReturn(rc2, rc2);
7076 return rc;
7077 }
7078
7079 vmxHCSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbExitInstr,
7080 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
7081 return VINF_SUCCESS;
7082}
7083
7084
7085/**
7086 * VM-exit exception handler for \#BP (Breakpoint exception).
7087 *
7088 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
7089 */
7090static VBOXSTRICTRC vmxHCExitXcptBP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7091{
7092 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7093 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestBP);
7094
7095 int rc = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
7096 AssertRCReturn(rc, rc);
7097
7098 VBOXSTRICTRC rcStrict;
7099 if (!pVmxTransient->fIsNestedGuest)
7100 rcStrict = DBGFTrap03Handler(pVCpu->CTX_SUFF(pVM), pVCpu, &pVCpu->cpum.GstCtx);
7101 else
7102 rcStrict = VINF_EM_RAW_GUEST_TRAP;
7103
7104 if (rcStrict == VINF_EM_RAW_GUEST_TRAP)
7105 {
7106 vmxHCSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
7107 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
7108 rcStrict = VINF_SUCCESS;
7109 }
7110
7111 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_DBG_BREAKPOINT);
7112 return rcStrict;
7113}
7114
7115
7116/**
7117 * VM-exit exception handler for \#AC (Alignment-check exception).
7118 *
7119 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
7120 */
7121static VBOXSTRICTRC vmxHCExitXcptAC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7122{
7123 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7124
7125 /*
7126 * Detect #ACs caused by host having enabled split-lock detection.
7127 * Emulate such instructions.
7128 */
7129#define VMX_HC_EXIT_XCPT_AC_INITIAL_REGS (CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS)
7130 int rc = vmxHCImportGuestState<VMX_HC_EXIT_XCPT_AC_INITIAL_REGS>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
7131 AssertRCReturn(rc, rc);
7132 /** @todo detect split lock in cpu feature? */
7133 if ( /* 1. If 486-style alignment checks aren't enabled, then this must be a split-lock exception */
7134 !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_AM)
7135 /* 2. #AC cannot happen in rings 0-2 except for split-lock detection. */
7136 || CPUMGetGuestCPL(pVCpu) != 3
7137 /* 3. When the EFLAGS.AC != 0 this can only be a split-lock case. */
7138 || !(pVCpu->cpum.GstCtx.eflags.u & X86_EFL_AC) )
7139 {
7140 /*
7141 * Check for debug/trace events and import state accordingly.
7142 */
7143 STAM_REL_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestACSplitLock);
7144 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7145 if ( !DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_VMX_SPLIT_LOCK)
7146#ifndef IN_NEM_DARWIN
7147 && !VBOXVMM_VMX_SPLIT_LOCK_ENABLED()
7148#endif
7149 )
7150 {
7151 if (pVM->cCpus == 1)
7152 {
7153#if 0 /** @todo r=bird: This is potentially wrong. Might have to just do a whole state sync above and mark everything changed to be safe... */
7154 rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_MUST_MASK,
7155 VMX_HC_EXIT_XCPT_AC_INITIAL_REGS>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
7156#else
7157 rc = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL,
7158 VMX_HC_EXIT_XCPT_AC_INITIAL_REGS>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
7159#endif
7160 AssertRCReturn(rc, rc);
7161 }
7162 }
7163 else
7164 {
7165 rc = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL,
7166 VMX_HC_EXIT_XCPT_AC_INITIAL_REGS>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
7167 AssertRCReturn(rc, rc);
7168
7169 VBOXVMM_XCPT_DF(pVCpu, &pVCpu->cpum.GstCtx);
7170
7171 if (DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_VMX_SPLIT_LOCK))
7172 {
7173 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, DBGFEVENT_VMX_SPLIT_LOCK, DBGFEVENTCTX_HM, 0);
7174 if (rcStrict != VINF_SUCCESS)
7175 return rcStrict;
7176 }
7177 }
7178
7179 /*
7180 * Emulate the instruction.
7181 *
7182 * We have to ignore the LOCK prefix here as we must not retrigger the
7183 * detection on the host. This isn't all that satisfactory, though...
7184 */
7185 if (pVM->cCpus == 1)
7186 {
7187 Log8Func(("cs:rip=%#04x:%08RX64 rflags=%#RX64 cr0=%#RX64 split-lock #AC\n", pVCpu->cpum.GstCtx.cs.Sel,
7188 pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags, pVCpu->cpum.GstCtx.cr0));
7189
7190 /** @todo For SMP configs we should do a rendezvous here. */
7191 VBOXSTRICTRC rcStrict = IEMExecOneIgnoreLock(pVCpu);
7192 if (rcStrict == VINF_SUCCESS)
7193#if 0 /** @todo r=bird: This is potentially wrong. Might have to just do a whole state sync above and mark everything changed to be safe... */
7194 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged,
7195 HM_CHANGED_GUEST_RIP
7196 | HM_CHANGED_GUEST_RFLAGS
7197 | HM_CHANGED_GUEST_GPRS_MASK
7198 | HM_CHANGED_GUEST_CS
7199 | HM_CHANGED_GUEST_SS);
7200#else
7201 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST);
7202#endif
7203 else if (rcStrict == VINF_IEM_RAISED_XCPT)
7204 {
7205 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
7206 rcStrict = VINF_SUCCESS;
7207 }
7208 return rcStrict;
7209 }
7210 Log8Func(("cs:rip=%#04x:%08RX64 rflags=%#RX64 cr0=%#RX64 split-lock #AC -> VINF_EM_EMULATE_SPLIT_LOCK\n",
7211 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags, pVCpu->cpum.GstCtx.cr0));
7212 return VINF_EM_EMULATE_SPLIT_LOCK;
7213 }
7214
7215 STAM_REL_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestAC);
7216 Log8Func(("cs:rip=%#04x:%08RX64 rflags=%#RX64 cr0=%#RX64 cpl=%d -> #AC\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
7217 pVCpu->cpum.GstCtx.rflags, pVCpu->cpum.GstCtx.cr0, CPUMGetGuestCPL(pVCpu) ));
7218
7219 /* Re-inject it. We'll detect any nesting before getting here. */
7220 vmxHCSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
7221 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
7222 return VINF_SUCCESS;
7223}
7224
7225
7226/**
7227 * VM-exit exception handler for \#DB (Debug exception).
7228 *
7229 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
7230 */
7231static VBOXSTRICTRC vmxHCExitXcptDB(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7232{
7233 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7234 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestDB);
7235
7236 /*
7237 * Get the DR6-like values from the Exit qualification and pass it to DBGF for processing.
7238 */
7239 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
7240
7241 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
7242 uint64_t const uDR6 = X86_DR6_INIT_VAL
7243 | (pVmxTransient->uExitQual & ( X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3
7244 | X86_DR6_BD | X86_DR6_BS));
7245 Log6Func(("uDR6=%#RX64 uExitQual=%#RX64\n", uDR6, pVmxTransient->uExitQual));
7246
7247 int rc;
7248 if (!pVmxTransient->fIsNestedGuest)
7249 {
7250 rc = DBGFTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, &pVCpu->cpum.GstCtx, uDR6, VCPU_2_VMXSTATE(pVCpu).fSingleInstruction);
7251
7252 /*
7253 * Prevents stepping twice over the same instruction when the guest is stepping using
7254 * EFLAGS.TF and the hypervisor debugger is stepping using MTF.
7255 * Testcase: DOSQEMM, break (using "ba x 1") at cs:rip 0x70:0x774 and step (using "t").
7256 */
7257 if ( rc == VINF_EM_DBG_STEPPED
7258 && (pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MONITOR_TRAP_FLAG))
7259 {
7260 Assert(VCPU_2_VMXSTATE(pVCpu).fSingleInstruction);
7261 rc = VINF_EM_RAW_GUEST_TRAP;
7262 }
7263 }
7264 else
7265 rc = VINF_EM_RAW_GUEST_TRAP;
7266 Log6Func(("rc=%Rrc\n", rc));
7267 if (rc == VINF_EM_RAW_GUEST_TRAP)
7268 {
7269 /*
7270 * The exception was for the guest. Update DR6, DR7.GD and
7271 * IA32_DEBUGCTL.LBR before forwarding it.
7272 * See Intel spec. 27.1 "Architectural State before a VM-Exit"
7273 * and @sdmv3{077,622,17.2.3,Debug Status Register (DR6)}.
7274 */
7275#ifndef IN_NEM_DARWIN
7276 VMMRZCallRing3Disable(pVCpu);
7277 HM_DISABLE_PREEMPT(pVCpu);
7278
7279 pVCpu->cpum.GstCtx.dr[6] &= ~X86_DR6_B_MASK;
7280 pVCpu->cpum.GstCtx.dr[6] |= uDR6;
7281 if (CPUMIsGuestDebugStateActive(pVCpu))
7282 ASMSetDR6(pVCpu->cpum.GstCtx.dr[6]);
7283
7284 HM_RESTORE_PREEMPT();
7285 VMMRZCallRing3Enable(pVCpu);
7286#else
7287 /** @todo */
7288#endif
7289
7290 rc = vmxHCImportGuestState<CPUMCTX_EXTRN_DR7>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
7291 AssertRCReturn(rc, rc);
7292
7293 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
7294 pVCpu->cpum.GstCtx.dr[7] &= ~(uint64_t)X86_DR7_GD;
7295
7296 /* Paranoia. */
7297 pVCpu->cpum.GstCtx.dr[7] &= ~(uint64_t)X86_DR7_RAZ_MASK;
7298 pVCpu->cpum.GstCtx.dr[7] |= X86_DR7_RA1_MASK;
7299
7300 rc = VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_GUEST_DR7, pVCpu->cpum.GstCtx.dr[7]);
7301 AssertRC(rc);
7302
7303 /*
7304 * Raise #DB in the guest.
7305 *
7306 * It is important to reflect exactly what the VM-exit gave us (preserving the
7307 * interruption-type) rather than use vmxHCSetPendingXcptDB() as the #DB could've
7308 * been raised while executing ICEBP (INT1) and not the regular #DB. Thus it may
7309 * trigger different handling in the CPU (like skipping DPL checks), see @bugref{6398}.
7310 *
7311 * Intel re-documented ICEBP/INT1 on May 2018 previously documented as part of
7312 * Intel 386, see Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
7313 */
7314 vmxHCSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
7315 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
7316 return VINF_SUCCESS;
7317 }
7318
7319 /*
7320 * Not a guest trap, must be a hypervisor related debug event then.
7321 * Update DR6 in case someone is interested in it.
7322 */
7323 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
7324 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
7325 CPUMSetHyperDR6(pVCpu, uDR6);
7326
7327 return rc;
7328}
7329
7330
7331/**
7332 * Hacks its way around the lovely mesa driver's backdoor accesses.
7333 *
7334 * @sa hmR0SvmHandleMesaDrvGp.
7335 */
7336static int vmxHCHandleMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
7337{
7338 LogFunc(("cs:rip=%#04x:%08RX64 rcx=%#RX64 rbx=%#RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->rcx, pCtx->rbx));
7339 RT_NOREF(pCtx);
7340
7341 /* For now we'll just skip the instruction. */
7342 return vmxHCAdvanceGuestRip(pVCpu, pVmxTransient);
7343}
7344
7345
7346/**
7347 * Checks if the \#GP'ing instruction is the mesa driver doing it's lovely
7348 * backdoor logging w/o checking what it is running inside.
7349 *
7350 * This recognizes an "IN EAX,DX" instruction executed in flat ring-3, with the
7351 * backdoor port and magic numbers loaded in registers.
7352 *
7353 * @returns true if it is, false if it isn't.
7354 * @sa hmR0SvmIsMesaDrvGp.
7355 */
7356DECLINLINE(bool) vmxHCIsMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
7357{
7358 /* 0xed: IN eAX,dx */
7359 uint8_t abInstr[1];
7360 if (pVmxTransient->cbExitInstr != sizeof(abInstr))
7361 return false;
7362
7363 /* Check that it is #GP(0). */
7364 if (pVmxTransient->uExitIntErrorCode != 0)
7365 return false;
7366
7367 /* Check magic and port. */
7368 Assert(!(pCtx->fExtrn & (CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX)));
7369 /*Log(("vmxHCIsMesaDrvGp: rax=%RX64 rdx=%RX64\n", pCtx->rax, pCtx->rdx));*/
7370 if (pCtx->rax != UINT32_C(0x564d5868))
7371 return false;
7372 if (pCtx->dx != UINT32_C(0x5658))
7373 return false;
7374
7375 /* Flat ring-3 CS. */
7376 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_CS);
7377 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_CS));
7378 /*Log(("vmxHCIsMesaDrvGp: cs.Attr.n.u2Dpl=%d base=%Rx64\n", pCtx->cs.Attr.n.u2Dpl, pCtx->cs.u64Base));*/
7379 if (pCtx->cs.Attr.n.u2Dpl != 3)
7380 return false;
7381 if (pCtx->cs.u64Base != 0)
7382 return false;
7383
7384 /* Check opcode. */
7385 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_RIP);
7386 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_RIP));
7387 int rc = PGMPhysSimpleReadGCPtr(pVCpu, abInstr, pCtx->rip, sizeof(abInstr));
7388 /*Log(("vmxHCIsMesaDrvGp: PGMPhysSimpleReadGCPtr -> %Rrc %#x\n", rc, abInstr[0]));*/
7389 if (RT_FAILURE(rc))
7390 return false;
7391 if (abInstr[0] != 0xed)
7392 return false;
7393
7394 return true;
7395}
7396
7397
7398/**
7399 * VM-exit exception handler for \#GP (General-protection exception).
7400 *
7401 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
7402 */
7403static VBOXSTRICTRC vmxHCExitXcptGP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7404{
7405 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7406 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestGP);
7407
7408 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7409 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
7410#ifndef IN_NEM_DARWIN
7411 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7412 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
7413 { /* likely */ }
7414 else
7415#endif
7416 {
7417#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
7418# ifndef IN_NEM_DARWIN
7419 Assert(pVCpu->hmr0.s.fUsingDebugLoop || VCPU_2_VMXSTATE(pVCpu).fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
7420# else
7421 Assert(/*pVCpu->hmr0.s.fUsingDebugLoop ||*/ VCPU_2_VMXSTATE(pVCpu).fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
7422# endif
7423#endif
7424 /*
7425 * If the guest is not in real-mode or we have unrestricted guest execution support, or if we are
7426 * executing a nested-guest, reflect #GP to the guest or nested-guest.
7427 */
7428 int rc = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmcsInfo, __FUNCTION__);
7429 AssertRCReturn(rc, rc);
7430 Log4Func(("Gst: cs:rip=%#04x:%08RX64 ErrorCode=%#x cr0=%#RX64 cpl=%u tr=%#04x\n", pCtx->cs.Sel, pCtx->rip,
7431 pVmxTransient->uExitIntErrorCode, pCtx->cr0, CPUMGetGuestCPL(pVCpu), pCtx->tr.Sel));
7432
7433 if ( pVmxTransient->fIsNestedGuest
7434 || !VCPU_2_VMXSTATE(pVCpu).fTrapXcptGpForLovelyMesaDrv
7435 || !vmxHCIsMesaDrvGp(pVCpu, pVmxTransient, pCtx))
7436 vmxHCSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
7437 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
7438 else
7439 rc = vmxHCHandleMesaDrvGp(pVCpu, pVmxTransient, pCtx);
7440 return rc;
7441 }
7442
7443#ifndef IN_NEM_DARWIN
7444 Assert(CPUMIsGuestInRealModeEx(pCtx));
7445 Assert(!pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest);
7446 Assert(!pVmxTransient->fIsNestedGuest);
7447
7448 int rc = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmcsInfo, __FUNCTION__);
7449 AssertRCReturn(rc, rc);
7450
7451 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
7452 if (rcStrict == VINF_SUCCESS)
7453 {
7454 if (!CPUMIsGuestInRealModeEx(pCtx))
7455 {
7456 /*
7457 * The guest is no longer in real-mode, check if we can continue executing the
7458 * guest using hardware-assisted VMX. Otherwise, fall back to emulation.
7459 */
7460 pVmcsInfoShared->RealMode.fRealOnV86Active = false;
7461 if (HMCanExecuteVmxGuest(pVCpu->CTX_SUFF(pVM), pVCpu, pCtx))
7462 {
7463 Log4Func(("Mode changed but guest still suitable for executing using hardware-assisted VMX\n"));
7464 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST);
7465 }
7466 else
7467 {
7468 Log4Func(("Mode changed -> VINF_EM_RESCHEDULE\n"));
7469 rcStrict = VINF_EM_RESCHEDULE;
7470 }
7471 }
7472 else
7473 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST);
7474 }
7475 else if (rcStrict == VINF_IEM_RAISED_XCPT)
7476 {
7477 rcStrict = VINF_SUCCESS;
7478 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
7479 }
7480 return VBOXSTRICTRC_VAL(rcStrict);
7481#endif
7482}
7483
7484
7485/**
7486 * VM-exit exception handler for \#DE (Divide Error).
7487 *
7488 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
7489 */
7490static VBOXSTRICTRC vmxHCExitXcptDE(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7491{
7492 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7493 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestDE);
7494
7495 int rc = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
7496 AssertRCReturn(rc, rc);
7497
7498 VBOXSTRICTRC rcStrict = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
7499 if (VCPU_2_VMXSTATE(pVCpu).fGCMTrapXcptDE)
7500 {
7501 uint8_t cbInstr = 0;
7502 VBOXSTRICTRC rc2 = GCMXcptDE(pVCpu, &pVCpu->cpum.GstCtx, NULL /* pDis */, &cbInstr);
7503 if (rc2 == VINF_SUCCESS)
7504 rcStrict = VINF_SUCCESS; /* Restart instruction with modified guest register context. */
7505 else if (rc2 == VERR_NOT_FOUND)
7506 rcStrict = VERR_NOT_FOUND; /* Deliver the exception. */
7507 else
7508 Assert(RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)));
7509 }
7510 else
7511 rcStrict = VINF_SUCCESS; /* Do nothing. */
7512
7513 /* If the GCM #DE exception handler didn't succeed or wasn't needed, raise #DE. */
7514 if (RT_FAILURE(rcStrict))
7515 {
7516 vmxHCSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
7517 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
7518 rcStrict = VINF_SUCCESS;
7519 }
7520
7521 Assert(rcStrict == VINF_SUCCESS || rcStrict == VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE);
7522 return VBOXSTRICTRC_VAL(rcStrict);
7523}
7524
7525
7526/**
7527 * VM-exit exception handler wrapper for all other exceptions that are not handled
7528 * by a specific handler.
7529 *
7530 * This simply re-injects the exception back into the VM without any special
7531 * processing.
7532 *
7533 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
7534 */
7535static VBOXSTRICTRC vmxHCExitXcptOthers(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7536{
7537 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7538
7539#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
7540# ifndef IN_NEM_DARWIN
7541 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
7542 AssertMsg(pVCpu->hmr0.s.fUsingDebugLoop || pVmcsInfo->pShared->RealMode.fRealOnV86Active || pVmxTransient->fIsNestedGuest,
7543 ("uVector=%#x u32XcptBitmap=%#X32\n",
7544 VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVmcsInfo->u32XcptBitmap));
7545 NOREF(pVmcsInfo);
7546# endif
7547#endif
7548
7549 /*
7550 * Re-inject the exception into the guest. This cannot be a double-fault condition which
7551 * would have been handled while checking exits due to event delivery.
7552 */
7553 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
7554
7555#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
7556 int rc = vmxHCImportGuestState<CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
7557 AssertRCReturn(rc, rc);
7558 Log4Func(("Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%08RX64\n", uVector, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
7559#endif
7560
7561#ifdef VBOX_WITH_STATISTICS
7562 switch (uVector)
7563 {
7564 case X86_XCPT_DE: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestDE); break;
7565 case X86_XCPT_DB: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestDB); break;
7566 case X86_XCPT_BP: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestBP); break;
7567 case X86_XCPT_OF: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestOF); break;
7568 case X86_XCPT_BR: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestBR); break;
7569 case X86_XCPT_UD: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestUD); break;
7570 case X86_XCPT_NM: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestOF); break;
7571 case X86_XCPT_DF: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestDF); break;
7572 case X86_XCPT_TS: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestTS); break;
7573 case X86_XCPT_NP: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestNP); break;
7574 case X86_XCPT_SS: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestSS); break;
7575 case X86_XCPT_GP: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestGP); break;
7576 case X86_XCPT_PF: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestPF); break;
7577 case X86_XCPT_MF: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestMF); break;
7578 case X86_XCPT_AC: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestAC); break;
7579 case X86_XCPT_XF: STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestXF); break;
7580 default:
7581 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitGuestXcpUnk);
7582 break;
7583 }
7584#endif
7585
7586 /* We should never call this function for a page-fault, we'd need to pass on the fault address below otherwise. */
7587 Assert(!VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo));
7588 NOREF(uVector);
7589
7590 /* Re-inject the original exception into the guest. */
7591 vmxHCSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
7592 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
7593 return VINF_SUCCESS;
7594}
7595
7596
7597/**
7598 * VM-exit exception handler for all exceptions (except NMIs!).
7599 *
7600 * @remarks This may be called for both guests and nested-guests. Take care to not
7601 * make assumptions and avoid doing anything that is not relevant when
7602 * executing a nested-guest (e.g., Mesa driver hacks).
7603 */
7604static VBOXSTRICTRC vmxHCExitXcpt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7605{
7606 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
7607
7608 /*
7609 * If this VM-exit occurred while delivering an event through the guest IDT, take
7610 * action based on the return code and additional hints (e.g. for page-faults)
7611 * that will be updated in the VMX transient structure.
7612 */
7613 VBOXSTRICTRC rcStrict = vmxHCCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
7614 if (rcStrict == VINF_SUCCESS)
7615 {
7616 /*
7617 * If an exception caused a VM-exit due to delivery of an event, the original
7618 * event may have to be re-injected into the guest. We shall reinject it and
7619 * continue guest execution. However, page-fault is a complicated case and
7620 * needs additional processing done in vmxHCExitXcptPF().
7621 */
7622 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
7623 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
7624 if ( !VCPU_2_VMXSTATE(pVCpu).Event.fPending
7625 || uVector == X86_XCPT_PF)
7626 {
7627 switch (uVector)
7628 {
7629 case X86_XCPT_PF: return vmxHCExitXcptPF(pVCpu, pVmxTransient);
7630 case X86_XCPT_GP: return vmxHCExitXcptGP(pVCpu, pVmxTransient);
7631 case X86_XCPT_MF: return vmxHCExitXcptMF(pVCpu, pVmxTransient);
7632 case X86_XCPT_DB: return vmxHCExitXcptDB(pVCpu, pVmxTransient);
7633 case X86_XCPT_BP: return vmxHCExitXcptBP(pVCpu, pVmxTransient);
7634 case X86_XCPT_AC: return vmxHCExitXcptAC(pVCpu, pVmxTransient);
7635 case X86_XCPT_DE: return vmxHCExitXcptDE(pVCpu, pVmxTransient);
7636 default:
7637 return vmxHCExitXcptOthers(pVCpu, pVmxTransient);
7638 }
7639 }
7640 /* else: inject pending event before resuming guest execution. */
7641 }
7642 else if (rcStrict == VINF_HM_DOUBLE_FAULT)
7643 {
7644 Assert(VCPU_2_VMXSTATE(pVCpu).Event.fPending);
7645 rcStrict = VINF_SUCCESS;
7646 }
7647
7648 return rcStrict;
7649}
7650/** @} */
7651
7652
7653/** @name VM-exit handlers.
7654 * @{
7655 */
7656/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
7657/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
7658/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
7659
7660/**
7661 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
7662 */
7663HMVMX_EXIT_DECL vmxHCExitExtInt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7664{
7665 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7666 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitExtInt);
7667
7668#ifndef IN_NEM_DARWIN
7669 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
7670 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
7671 return VINF_SUCCESS;
7672 return VINF_EM_RAW_INTERRUPT;
7673#else
7674 return VINF_SUCCESS;
7675#endif
7676}
7677
7678
7679/**
7680 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI). Conditional
7681 * VM-exit.
7682 */
7683HMVMX_EXIT_DECL vmxHCExitXcptOrNmi(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7684{
7685 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7686 STAM_PROFILE_ADV_START(&VCPU_2_VMXSTATS(pVCpu).StatExitXcptNmi, y3);
7687
7688 vmxHCReadToTransient<HMVMX_READ_EXIT_INTERRUPTION_INFO>(pVCpu, pVmxTransient);
7689
7690 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
7691 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
7692 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
7693
7694 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
7695 Assert( !(pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT)
7696 && uExitIntType != VMX_EXIT_INT_INFO_TYPE_EXT_INT);
7697 NOREF(pVmcsInfo);
7698
7699 VBOXSTRICTRC rcStrict;
7700 switch (uExitIntType)
7701 {
7702#ifndef IN_NEM_DARWIN /* NMIs should never reach R3. */
7703 /*
7704 * Host physical NMIs:
7705 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we
7706 * injected it ourselves and anything we inject is not going to cause a VM-exit directly
7707 * for the event being injected[1]. Go ahead and dispatch the NMI to the host[2].
7708 *
7709 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
7710 * See Intel spec. 27.5.5 "Updating Non-Register State".
7711 */
7712 case VMX_EXIT_INT_INFO_TYPE_NMI:
7713 {
7714 rcStrict = hmR0VmxExitHostNmi(pVCpu, pVmcsInfo);
7715 break;
7716 }
7717#endif
7718
7719 /*
7720 * Privileged software exceptions (#DB from ICEBP),
7721 * Software exceptions (#BP and #OF),
7722 * Hardware exceptions:
7723 * Process the required exceptions and resume guest execution if possible.
7724 */
7725 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
7726 Assert(uVector == X86_XCPT_DB);
7727 RT_FALL_THRU();
7728 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
7729 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uExitIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT);
7730 RT_FALL_THRU();
7731 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
7732 {
7733 NOREF(uVector);
7734 vmxHCReadToTransient< HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
7735 | HMVMX_READ_EXIT_INSTR_LEN
7736 | HMVMX_READ_IDT_VECTORING_INFO
7737 | HMVMX_READ_IDT_VECTORING_ERROR_CODE>(pVCpu, pVmxTransient);
7738 rcStrict = vmxHCExitXcpt(pVCpu, pVmxTransient);
7739 break;
7740 }
7741
7742 default:
7743 {
7744 VCPU_2_VMXSTATE(pVCpu).u32HMError = pVmxTransient->uExitIntInfo;
7745 rcStrict = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
7746 AssertMsgFailed(("Invalid/unexpected VM-exit interruption info %#x\n", pVmxTransient->uExitIntInfo));
7747 break;
7748 }
7749 }
7750
7751 STAM_PROFILE_ADV_STOP(&VCPU_2_VMXSTATS(pVCpu).StatExitXcptNmi, y3);
7752 return rcStrict;
7753}
7754
7755
7756/**
7757 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
7758 */
7759HMVMX_EXIT_NSRC_DECL vmxHCExitIntWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7760{
7761 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7762
7763 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
7764 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
7765 vmxHCClearIntWindowExitVmcs(pVCpu, pVmcsInfo);
7766
7767 /* Evaluate and deliver pending events and resume guest execution. */
7768 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitIntWindow);
7769 return VINF_SUCCESS;
7770}
7771
7772
7773/**
7774 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
7775 */
7776HMVMX_EXIT_NSRC_DECL vmxHCExitNmiWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7777{
7778 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7779
7780 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
7781 if (RT_UNLIKELY(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))) /** @todo NSTVMX: Turn this into an assertion. */
7782 {
7783 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
7784 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
7785 }
7786
7787 Assert(!CPUMAreInterruptsInhibitedByNmiEx(&pVCpu->cpum.GstCtx));
7788
7789 /*
7790 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
7791 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
7792 */
7793 uint32_t fIntrState;
7794 int rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
7795 AssertRC(rc);
7796 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
7797 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
7798 {
7799 CPUMClearInterruptShadow(&pVCpu->cpum.GstCtx);
7800
7801 fIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
7802 rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_GUEST_INT_STATE, fIntrState);
7803 AssertRC(rc);
7804 }
7805
7806 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready. */
7807 vmxHCClearNmiWindowExitVmcs(pVCpu, pVmcsInfo);
7808
7809 /* Evaluate and deliver pending events and resume guest execution. */
7810 return VINF_SUCCESS;
7811}
7812
7813
7814/**
7815 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
7816 */
7817HMVMX_EXIT_NSRC_DECL vmxHCExitWbinvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7818{
7819 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7820 return vmxHCAdvanceGuestRip(pVCpu, pVmxTransient);
7821}
7822
7823
7824/**
7825 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
7826 */
7827HMVMX_EXIT_NSRC_DECL vmxHCExitInvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7828{
7829 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7830 return vmxHCAdvanceGuestRip(pVCpu, pVmxTransient);
7831}
7832
7833
7834/**
7835 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
7836 */
7837HMVMX_EXIT_DECL vmxHCExitCpuid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7838{
7839 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7840
7841 /*
7842 * Get the state we need and update the exit history entry.
7843 */
7844 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
7845 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
7846 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK>(pVCpu, pVmcsInfo, __FUNCTION__);
7847 AssertRCReturn(rc, rc);
7848
7849 VBOXSTRICTRC rcStrict;
7850 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
7851 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_CPUID),
7852 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
7853 if (!pExitRec)
7854 {
7855 /*
7856 * Regular CPUID instruction execution.
7857 */
7858 rcStrict = IEMExecDecodedCpuid(pVCpu, pVmxTransient->cbExitInstr);
7859 if (rcStrict == VINF_SUCCESS)
7860 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
7861 else if (rcStrict == VINF_IEM_RAISED_XCPT)
7862 {
7863 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
7864 rcStrict = VINF_SUCCESS;
7865 }
7866 }
7867 else
7868 {
7869 /*
7870 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
7871 */
7872 int rc2 = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL,
7873 IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK>(pVCpu, pVmcsInfo, __FUNCTION__);
7874 AssertRCReturn(rc2, rc2);
7875
7876 Log4(("CpuIdExit/%u: %04x:%08RX64: %#x/%#x -> EMHistoryExec\n",
7877 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx));
7878
7879 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
7880 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST);
7881
7882 Log4(("CpuIdExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
7883 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
7884 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
7885 }
7886 return rcStrict;
7887}
7888
7889
7890/**
7891 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
7892 */
7893HMVMX_EXIT_DECL vmxHCExitGetsec(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7894{
7895 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7896
7897 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
7898 int rc = vmxHCImportGuestState<CPUMCTX_EXTRN_CR4>(pVCpu, pVmcsInfo, __FUNCTION__);
7899 AssertRCReturn(rc, rc);
7900
7901 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_SMXE)
7902 return VINF_EM_RAW_EMULATE_INSTR;
7903
7904 AssertMsgFailed(("vmxHCExitGetsec: Unexpected VM-exit when CR4.SMXE is 0.\n"));
7905 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
7906}
7907
7908
7909/**
7910 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
7911 */
7912HMVMX_EXIT_DECL vmxHCExitRdtsc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7913{
7914 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7915
7916 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
7917 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
7918 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_MUST_MASK>(pVCpu, pVmcsInfo, __FUNCTION__);
7919 AssertRCReturn(rc, rc);
7920
7921 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtsc(pVCpu, pVmxTransient->cbExitInstr);
7922 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
7923 {
7924 /* If we get a spurious VM-exit when TSC offsetting is enabled,
7925 we must reset offsetting on VM-entry. See @bugref{6634}. */
7926 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
7927 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
7928 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
7929 }
7930 else if (rcStrict == VINF_IEM_RAISED_XCPT)
7931 {
7932 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
7933 rcStrict = VINF_SUCCESS;
7934 }
7935 return rcStrict;
7936}
7937
7938
7939/**
7940 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
7941 */
7942HMVMX_EXIT_DECL vmxHCExitRdtscp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7943{
7944 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7945
7946 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
7947 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
7948 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_TSC_AUX>(pVCpu, pVmcsInfo, __FUNCTION__);
7949 AssertRCReturn(rc, rc);
7950
7951 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtscp(pVCpu, pVmxTransient->cbExitInstr);
7952 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
7953 {
7954 /* If we get a spurious VM-exit when TSC offsetting is enabled,
7955 we must reset offsetting on VM-reentry. See @bugref{6634}. */
7956 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
7957 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
7958 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
7959 }
7960 else if (rcStrict == VINF_IEM_RAISED_XCPT)
7961 {
7962 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
7963 rcStrict = VINF_SUCCESS;
7964 }
7965 return rcStrict;
7966}
7967
7968
7969/**
7970 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
7971 */
7972HMVMX_EXIT_DECL vmxHCExitRdpmc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7973{
7974 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7975
7976 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
7977 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
7978 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_CR4>(pVCpu, pVmcsInfo, __FUNCTION__);
7979 AssertRCReturn(rc, rc);
7980
7981 VBOXSTRICTRC rcStrict = IEMExecDecodedRdpmc(pVCpu, pVmxTransient->cbExitInstr);
7982 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
7983 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
7984 else if (rcStrict == VINF_IEM_RAISED_XCPT)
7985 {
7986 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
7987 rcStrict = VINF_SUCCESS;
7988 }
7989 return rcStrict;
7990}
7991
7992
7993/**
7994 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
7995 */
7996HMVMX_EXIT_DECL vmxHCExitVmcall(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7997{
7998 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
7999
8000 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
8001 if (EMAreHypercallInstructionsEnabled(pVCpu))
8002 {
8003 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8004 int rc = vmxHCImportGuestState< CPUMCTX_EXTRN_RIP
8005 | CPUMCTX_EXTRN_RFLAGS
8006 | CPUMCTX_EXTRN_CR0
8007 | CPUMCTX_EXTRN_SS
8008 | CPUMCTX_EXTRN_CS
8009 | CPUMCTX_EXTRN_EFER>(pVCpu, pVmcsInfo, __FUNCTION__);
8010 AssertRCReturn(rc, rc);
8011
8012 /* Perform the hypercall. */
8013 rcStrict = GIMHypercall(pVCpu, &pVCpu->cpum.GstCtx);
8014 if (rcStrict == VINF_SUCCESS)
8015 {
8016 rc = vmxHCAdvanceGuestRip(pVCpu, pVmxTransient);
8017 AssertRCReturn(rc, rc);
8018 }
8019 else
8020 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
8021 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
8022 || RT_FAILURE(rcStrict));
8023
8024 /* If the hypercall changes anything other than guest's general-purpose registers,
8025 we would need to reload the guest changed bits here before VM-entry. */
8026 }
8027 else
8028 Log4Func(("Hypercalls not enabled\n"));
8029
8030 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
8031 if (RT_FAILURE(rcStrict))
8032 {
8033 vmxHCSetPendingXcptUD(pVCpu);
8034 rcStrict = VINF_SUCCESS;
8035 }
8036
8037 return rcStrict;
8038}
8039
8040
8041/**
8042 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
8043 */
8044HMVMX_EXIT_DECL vmxHCExitInvlpg(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8045{
8046 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8047#ifndef IN_NEM_DARWIN
8048 Assert(!pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging || pVCpu->hmr0.s.fUsingDebugLoop);
8049#endif
8050
8051 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8052 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
8053 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
8054 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK>(pVCpu, pVmcsInfo, __FUNCTION__);
8055 AssertRCReturn(rc, rc);
8056
8057 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpg(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->uExitQual);
8058
8059 if (rcStrict == VINF_SUCCESS || rcStrict == VINF_PGM_SYNC_CR3)
8060 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
8061 else if (rcStrict == VINF_IEM_RAISED_XCPT)
8062 {
8063 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
8064 rcStrict = VINF_SUCCESS;
8065 }
8066 else
8067 AssertMsgFailed(("Unexpected IEMExecDecodedInvlpg(%#RX64) status: %Rrc\n", pVmxTransient->uExitQual,
8068 VBOXSTRICTRC_VAL(rcStrict)));
8069 return rcStrict;
8070}
8071
8072
8073/**
8074 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
8075 */
8076HMVMX_EXIT_DECL vmxHCExitMonitor(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8077{
8078 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8079
8080 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8081 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
8082 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_DS>(pVCpu, pVmcsInfo, __FUNCTION__);
8083 AssertRCReturn(rc, rc);
8084
8085 VBOXSTRICTRC rcStrict = IEMExecDecodedMonitor(pVCpu, pVmxTransient->cbExitInstr);
8086 if (rcStrict == VINF_SUCCESS)
8087 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
8088 else if (rcStrict == VINF_IEM_RAISED_XCPT)
8089 {
8090 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
8091 rcStrict = VINF_SUCCESS;
8092 }
8093
8094 return rcStrict;
8095}
8096
8097
8098/**
8099 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
8100 */
8101HMVMX_EXIT_DECL vmxHCExitMwait(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8102{
8103 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8104
8105 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8106 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
8107 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK>(pVCpu, pVmcsInfo, __FUNCTION__);
8108 AssertRCReturn(rc, rc);
8109
8110 VBOXSTRICTRC rcStrict = IEMExecDecodedMwait(pVCpu, pVmxTransient->cbExitInstr);
8111 if (RT_SUCCESS(rcStrict))
8112 {
8113 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
8114 if (EMMonitorWaitShouldContinue(pVCpu, &pVCpu->cpum.GstCtx))
8115 rcStrict = VINF_SUCCESS;
8116 }
8117
8118 return rcStrict;
8119}
8120
8121
8122/**
8123 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
8124 * VM-exit.
8125 */
8126HMVMX_EXIT_DECL vmxHCExitTripleFault(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8127{
8128 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8129 return VINF_EM_RESET;
8130}
8131
8132
8133/**
8134 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
8135 */
8136HMVMX_EXIT_DECL vmxHCExitHlt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8137{
8138 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8139
8140 int rc = vmxHCAdvanceGuestRip(pVCpu, pVmxTransient);
8141 AssertRCReturn(rc, rc);
8142
8143 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS); /* Advancing the RIP above should've imported eflags. */
8144 if (EMShouldContinueAfterHalt(pVCpu, &pVCpu->cpum.GstCtx)) /* Requires eflags. */
8145 rc = VINF_SUCCESS;
8146 else
8147 rc = VINF_EM_HALT;
8148
8149 if (rc != VINF_SUCCESS)
8150 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatSwitchHltToR3);
8151 return rc;
8152}
8153
8154
8155#ifndef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
8156/**
8157 * VM-exit handler for instructions that result in a \#UD exception delivered to
8158 * the guest.
8159 */
8160HMVMX_EXIT_NSRC_DECL vmxHCExitSetPendingXcptUD(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8161{
8162 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8163 vmxHCSetPendingXcptUD(pVCpu);
8164 return VINF_SUCCESS;
8165}
8166#endif
8167
8168
8169/**
8170 * VM-exit handler for expiry of the VMX-preemption timer.
8171 */
8172HMVMX_EXIT_DECL vmxHCExitPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8173{
8174 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8175
8176 /* If the VMX-preemption timer has expired, reinitialize the preemption timer on next VM-entry. */
8177 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
8178Log12(("vmxHCExitPreemptTimer:\n"));
8179
8180 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
8181 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8182 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
8183 STAM_REL_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitPreemptTimer);
8184 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
8185}
8186
8187
8188/**
8189 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
8190 */
8191HMVMX_EXIT_DECL vmxHCExitXsetbv(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8192{
8193 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8194
8195 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8196 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
8197 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_CR4>(pVCpu, pVmcsInfo, __FUNCTION__);
8198 AssertRCReturn(rc, rc);
8199
8200 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbExitInstr);
8201 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
8202 : HM_CHANGED_RAISED_XCPT_MASK);
8203
8204#ifndef IN_NEM_DARWIN
8205 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8206 bool const fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
8207 if (fLoadSaveGuestXcr0 != pVCpu->hmr0.s.fLoadSaveGuestXcr0)
8208 {
8209 pVCpu->hmr0.s.fLoadSaveGuestXcr0 = fLoadSaveGuestXcr0;
8210 hmR0VmxUpdateStartVmFunction(pVCpu);
8211 }
8212#endif
8213
8214 return rcStrict;
8215}
8216
8217
8218/**
8219 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
8220 */
8221HMVMX_EXIT_DECL vmxHCExitInvpcid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8222{
8223 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8224
8225 /** @todo Enable the new code after finding a reliably guest test-case. */
8226#if 1
8227 return VERR_EM_INTERPRETER;
8228#else
8229 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
8230 | HMVMX_READ_EXIT_INSTR_INFO
8231 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
8232 int rc = vmxHCImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
8233 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
8234 AssertRCReturn(rc, rc);
8235
8236 /* Paranoia. Ensure this has a memory operand. */
8237 Assert(!pVmxTransient->ExitInstrInfo.Inv.u1Cleared0);
8238
8239 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
8240 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
8241 uint64_t const uType = CPUMIsGuestIn64BitCode(pVCpu) ? pVCpu->cpum.GstCtx.aGRegs[iGReg].u64
8242 : pVCpu->cpum.GstCtx.aGRegs[iGReg].u32;
8243
8244 RTGCPTR GCPtrDesc;
8245 HMVMX_DECODE_MEM_OPERAND(pVCpu, pVmxTransient->ExitInstrInfo.u, pVmxTransient->uExitQual, VMXMEMACCESS_READ, &GCPtrDesc);
8246
8247 VBOXSTRICTRC rcStrict = IEMExecDecodedInvpcid(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->ExitInstrInfo.Inv.iSegReg,
8248 GCPtrDesc, uType);
8249 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8250 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
8251 else if (rcStrict == VINF_IEM_RAISED_XCPT)
8252 {
8253 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
8254 rcStrict = VINF_SUCCESS;
8255 }
8256 return rcStrict;
8257#endif
8258}
8259
8260
8261/**
8262 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error
8263 * VM-exit.
8264 */
8265HMVMX_EXIT_NSRC_DECL vmxHCExitErrInvalidGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8266{
8267 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8268 int rc = vmxHCImportGuestStateEx(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8269 AssertRCReturn(rc, rc);
8270
8271 rc = vmxHCCheckCachedVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
8272 if (RT_FAILURE(rc))
8273 return rc;
8274
8275 uint32_t const uInvalidReason = vmxHCCheckGuestState(pVCpu, pVmcsInfo);
8276 NOREF(uInvalidReason);
8277
8278#ifdef VBOX_STRICT
8279 uint32_t fIntrState;
8280 uint64_t u64Val;
8281 vmxHCReadToTransient< HMVMX_READ_EXIT_INSTR_INFO
8282 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
8283 vmxHCReadEntryXcptErrorCodeVmcs(pVCpu, pVmxTransient);
8284
8285 Log4(("uInvalidReason %u\n", uInvalidReason));
8286 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
8287 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
8288 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
8289
8290 rc = VMX_VMCS_READ_32(pVCpu, VMX_VMCS32_GUEST_INT_STATE, &fIntrState); AssertRC(rc);
8291 Log4(("VMX_VMCS32_GUEST_INT_STATE %#RX32\n", fIntrState));
8292 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_GUEST_CR0, &u64Val); AssertRC(rc);
8293 Log4(("VMX_VMCS_GUEST_CR0 %#RX64\n", u64Val));
8294 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_CTRL_CR0_MASK, &u64Val); AssertRC(rc);
8295 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RX64\n", u64Val));
8296 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Val); AssertRC(rc);
8297 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
8298 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_CTRL_CR4_MASK, &u64Val); AssertRC(rc);
8299 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RX64\n", u64Val));
8300 rc = VMX_VMCS_READ_NW(pVCpu, VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Val); AssertRC(rc);
8301 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
8302# ifndef IN_NEM_DARWIN
8303 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging)
8304 {
8305 rc = VMX_VMCS_READ_64(pVCpu, VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
8306 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
8307 }
8308
8309 hmR0DumpRegs(pVCpu, HM_DUMP_REG_FLAGS_ALL);
8310# endif
8311#endif
8312
8313 return VERR_VMX_INVALID_GUEST_STATE;
8314}
8315
8316/**
8317 * VM-exit handler for all undefined/unexpected reasons. Should never happen.
8318 */
8319HMVMX_EXIT_NSRC_DECL vmxHCExitErrUnexpected(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8320{
8321 /*
8322 * Cumulative notes of all recognized but unexpected VM-exits.
8323 *
8324 * 1. This does -not- cover scenarios like a page-fault VM-exit occurring when
8325 * nested-paging is used.
8326 *
8327 * 2. Any instruction that causes a VM-exit unconditionally (for e.g. VMXON) must be
8328 * emulated or a #UD must be raised in the guest. Therefore, we should -not- be using
8329 * this function (and thereby stop VM execution) for handling such instructions.
8330 *
8331 *
8332 * VMX_EXIT_INIT_SIGNAL:
8333 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
8334 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these
8335 * VM-exits. However, we should not receive INIT signals VM-exit while executing a VM.
8336 *
8337 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery"
8338 * See Intel spec. 29.3 "VMX Instructions" for "VMXON".
8339 * See Intel spec. "23.8 Restrictions on VMX operation".
8340 *
8341 * VMX_EXIT_SIPI:
8342 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest
8343 * activity state is used. We don't make use of it as our guests don't have direct
8344 * access to the host local APIC.
8345 *
8346 * See Intel spec. 25.3 "Other Causes of VM-exits".
8347 *
8348 * VMX_EXIT_IO_SMI:
8349 * VMX_EXIT_SMI:
8350 * This can only happen if we support dual-monitor treatment of SMI, which can be
8351 * activated by executing VMCALL in VMX root operation. Only an STM (SMM transfer
8352 * monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL in
8353 * VMX root mode or receive an SMI. If we get here, something funny is going on.
8354 *
8355 * See Intel spec. 33.15.6 "Activating the Dual-Monitor Treatment"
8356 * See Intel spec. 25.3 "Other Causes of VM-Exits"
8357 *
8358 * VMX_EXIT_ERR_MSR_LOAD:
8359 * Failures while loading MSRs are part of the VM-entry MSR-load area are unexpected
8360 * and typically indicates a bug in the hypervisor code. We thus cannot not resume
8361 * execution.
8362 *
8363 * See Intel spec. 26.7 "VM-Entry Failures During Or After Loading Guest State".
8364 *
8365 * VMX_EXIT_ERR_MACHINE_CHECK:
8366 * Machine check exceptions indicates a fatal/unrecoverable hardware condition
8367 * including but not limited to system bus, ECC, parity, cache and TLB errors. A
8368 * #MC exception abort class exception is raised. We thus cannot assume a
8369 * reasonable chance of continuing any sort of execution and we bail.
8370 *
8371 * See Intel spec. 15.1 "Machine-check Architecture".
8372 * See Intel spec. 27.1 "Architectural State Before A VM Exit".
8373 *
8374 * VMX_EXIT_PML_FULL:
8375 * VMX_EXIT_VIRTUALIZED_EOI:
8376 * VMX_EXIT_APIC_WRITE:
8377 * We do not currently support any of these features and thus they are all unexpected
8378 * VM-exits.
8379 *
8380 * VMX_EXIT_GDTR_IDTR_ACCESS:
8381 * VMX_EXIT_LDTR_TR_ACCESS:
8382 * VMX_EXIT_RDRAND:
8383 * VMX_EXIT_RSM:
8384 * VMX_EXIT_VMFUNC:
8385 * VMX_EXIT_ENCLS:
8386 * VMX_EXIT_RDSEED:
8387 * VMX_EXIT_XSAVES:
8388 * VMX_EXIT_XRSTORS:
8389 * VMX_EXIT_UMWAIT:
8390 * VMX_EXIT_TPAUSE:
8391 * VMX_EXIT_LOADIWKEY:
8392 * These VM-exits are -not- caused unconditionally by execution of the corresponding
8393 * instruction. Any VM-exit for these instructions indicate a hardware problem,
8394 * unsupported CPU modes (like SMM) or potentially corrupt VMCS controls.
8395 *
8396 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
8397 */
8398 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8399 AssertMsgFailed(("Unexpected VM-exit %u\n", pVmxTransient->uExitReason));
8400 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
8401}
8402
8403
8404/**
8405 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
8406 */
8407HMVMX_EXIT_DECL vmxHCExitRdmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8408{
8409 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8410
8411 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
8412
8413 /** @todo Optimize this: We currently drag in the whole MSR state
8414 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
8415 * MSRs required. That would require changes to IEM and possibly CPUM too.
8416 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
8417 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8418 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
8419 int rc;
8420 switch (idMsr)
8421 {
8422 default:
8423 rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS>(pVCpu, pVmcsInfo,
8424 __FUNCTION__);
8425 AssertRCReturn(rc, rc);
8426 break;
8427 case MSR_K8_FS_BASE:
8428 rc = vmxHCImportGuestState< IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS
8429 | CPUMCTX_EXTRN_FS>(pVCpu, pVmcsInfo, __FUNCTION__);
8430 AssertRCReturn(rc, rc);
8431 break;
8432 case MSR_K8_GS_BASE:
8433 rc = vmxHCImportGuestState< IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS
8434 | CPUMCTX_EXTRN_GS>(pVCpu, pVmcsInfo, __FUNCTION__);
8435 AssertRCReturn(rc, rc);
8436 break;
8437 }
8438
8439 Log4Func(("ecx=%#RX32\n", idMsr));
8440
8441#if defined(VBOX_STRICT) && !defined(IN_NEM_DARWIN)
8442 Assert(!pVmxTransient->fIsNestedGuest);
8443 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
8444 {
8445 if ( hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr)
8446 && idMsr != MSR_K6_EFER)
8447 {
8448 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", idMsr));
8449 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
8450 }
8451 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
8452 {
8453 Assert(pVmcsInfo->pvMsrBitmap);
8454 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
8455 if (fMsrpm & VMXMSRPM_ALLOW_RD)
8456 {
8457 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", idMsr));
8458 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
8459 }
8460 }
8461 }
8462#endif
8463
8464 VBOXSTRICTRC rcStrict = IEMExecDecodedRdmsr(pVCpu, pVmxTransient->cbExitInstr);
8465 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitRdmsr);
8466 if (rcStrict == VINF_SUCCESS)
8467 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
8468 else if (rcStrict == VINF_IEM_RAISED_XCPT)
8469 {
8470 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
8471 rcStrict = VINF_SUCCESS;
8472 }
8473 else
8474 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_READ || rcStrict == VINF_EM_TRIPLE_FAULT,
8475 ("Unexpected IEMExecDecodedRdmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
8476
8477 return rcStrict;
8478}
8479
8480
8481/**
8482 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
8483 */
8484HMVMX_EXIT_DECL vmxHCExitWrmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8485{
8486 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8487
8488 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
8489
8490 /*
8491 * The FS and GS base MSRs are not part of the above all-MSRs mask.
8492 * Although we don't need to fetch the base as it will be overwritten shortly, while
8493 * loading guest-state we would also load the entire segment register including limit
8494 * and attributes and thus we need to load them here.
8495 */
8496 /** @todo Optimize this: We currently drag in the whole MSR state
8497 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
8498 * MSRs required. That would require changes to IEM and possibly CPUM too.
8499 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
8500 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8501 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
8502 int rc;
8503 switch (idMsr)
8504 {
8505 default:
8506 rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS>(pVCpu, pVmcsInfo,
8507 __FUNCTION__);
8508 AssertRCReturn(rc, rc);
8509 break;
8510
8511 case MSR_K8_FS_BASE:
8512 rc = vmxHCImportGuestState< IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS
8513 | CPUMCTX_EXTRN_FS>(pVCpu, pVmcsInfo, __FUNCTION__);
8514 AssertRCReturn(rc, rc);
8515 break;
8516 case MSR_K8_GS_BASE:
8517 rc = vmxHCImportGuestState< IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS
8518 | CPUMCTX_EXTRN_GS>(pVCpu, pVmcsInfo, __FUNCTION__);
8519 AssertRCReturn(rc, rc);
8520 break;
8521 }
8522 Log4Func(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", idMsr, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.eax));
8523
8524 VBOXSTRICTRC rcStrict = IEMExecDecodedWrmsr(pVCpu, pVmxTransient->cbExitInstr);
8525 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitWrmsr);
8526
8527 if (rcStrict == VINF_SUCCESS)
8528 {
8529 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
8530
8531 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
8532 if ( idMsr == MSR_IA32_APICBASE
8533 || ( idMsr >= MSR_IA32_X2APIC_START
8534 && idMsr <= MSR_IA32_X2APIC_END))
8535 {
8536 /*
8537 * We've already saved the APIC related guest-state (TPR) in post-run phase.
8538 * When full APIC register virtualization is implemented we'll have to make
8539 * sure APIC state is saved from the VMCS before IEM changes it.
8540 */
8541 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
8542 }
8543 else if (idMsr == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
8544 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
8545 else if (idMsr == MSR_K6_EFER)
8546 {
8547 /*
8548 * If the guest touches the EFER MSR we need to update the VM-Entry and VM-Exit controls
8549 * as well, even if it is -not- touching bits that cause paging mode changes (LMA/LME).
8550 * We care about the other bits as well, SCE and NXE. See @bugref{7368}.
8551 */
8552 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
8553 }
8554
8555 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not used. */
8556 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
8557 {
8558 switch (idMsr)
8559 {
8560 case MSR_IA32_SYSENTER_CS: ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
8561 case MSR_IA32_SYSENTER_EIP: ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
8562 case MSR_IA32_SYSENTER_ESP: ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
8563 case MSR_K8_FS_BASE: ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_FS); break;
8564 case MSR_K8_GS_BASE: ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_GS); break;
8565 case MSR_K6_EFER: /* Nothing to do, already handled above. */ break;
8566 default:
8567 {
8568#ifndef IN_NEM_DARWIN
8569 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
8570 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_VMX_GUEST_LAZY_MSRS);
8571 else if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
8572 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
8573#else
8574 AssertMsgFailed(("TODO\n"));
8575#endif
8576 break;
8577 }
8578 }
8579 }
8580#if defined(VBOX_STRICT) && !defined(IN_NEM_DARWIN)
8581 else
8582 {
8583 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
8584 switch (idMsr)
8585 {
8586 case MSR_IA32_SYSENTER_CS:
8587 case MSR_IA32_SYSENTER_EIP:
8588 case MSR_IA32_SYSENTER_ESP:
8589 case MSR_K8_FS_BASE:
8590 case MSR_K8_GS_BASE:
8591 {
8592 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", idMsr));
8593 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
8594 }
8595
8596 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
8597 default:
8598 {
8599 if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
8600 {
8601 /* EFER MSR writes are always intercepted. */
8602 if (idMsr != MSR_K6_EFER)
8603 {
8604 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
8605 idMsr));
8606 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
8607 }
8608 }
8609
8610 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
8611 {
8612 Assert(pVmcsInfo->pvMsrBitmap);
8613 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
8614 if (fMsrpm & VMXMSRPM_ALLOW_WR)
8615 {
8616 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", idMsr));
8617 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
8618 }
8619 }
8620 break;
8621 }
8622 }
8623 }
8624#endif /* VBOX_STRICT */
8625 }
8626 else if (rcStrict == VINF_IEM_RAISED_XCPT)
8627 {
8628 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
8629 rcStrict = VINF_SUCCESS;
8630 }
8631 else
8632 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_WRITE || rcStrict == VINF_EM_TRIPLE_FAULT,
8633 ("Unexpected IEMExecDecodedWrmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
8634
8635 return rcStrict;
8636}
8637
8638
8639/**
8640 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
8641 */
8642HMVMX_EXIT_DECL vmxHCExitPause(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8643{
8644 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8645
8646 /** @todo The guest has likely hit a contended spinlock. We might want to
8647 * poke a schedule different guest VCPU. */
8648 int rc = vmxHCAdvanceGuestRip(pVCpu, pVmxTransient);
8649 if (RT_SUCCESS(rc))
8650 return VINF_EM_RAW_INTERRUPT;
8651
8652 AssertMsgFailed(("vmxHCExitPause: Failed to increment RIP. rc=%Rrc\n", rc));
8653 return rc;
8654}
8655
8656
8657/**
8658 * VM-exit handler for when the TPR value is lowered below the specified
8659 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
8660 */
8661HMVMX_EXIT_NSRC_DECL vmxHCExitTprBelowThreshold(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8662{
8663 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8664 Assert(pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
8665
8666 /*
8667 * The TPR shadow would've been synced with the APIC TPR in the post-run phase.
8668 * We'll re-evaluate pending interrupts and inject them before the next VM
8669 * entry so we can just continue execution here.
8670 */
8671 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitTprBelowThreshold);
8672 return VINF_SUCCESS;
8673}
8674
8675
8676/**
8677 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
8678 * VM-exit.
8679 *
8680 * @retval VINF_SUCCESS when guest execution can continue.
8681 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
8682 * @retval VERR_EM_RESCHEDULE_REM when we need to return to ring-3 due to
8683 * incompatible guest state for VMX execution (real-on-v86 case).
8684 */
8685HMVMX_EXIT_DECL vmxHCExitMovCRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8686{
8687 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8688 STAM_PROFILE_ADV_START(&VCPU_2_VMXSTATS(pVCpu).StatExitMovCRx, y2);
8689
8690 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8691 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
8692 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
8693
8694 VBOXSTRICTRC rcStrict;
8695 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8696 uint64_t const uExitQual = pVmxTransient->uExitQual;
8697 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(uExitQual);
8698 switch (uAccessType)
8699 {
8700 /*
8701 * MOV to CRx.
8702 */
8703 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
8704 {
8705 /*
8706 * When PAE paging is used, the CPU will reload PAE PDPTEs from CR3 when the guest
8707 * changes certain bits even in CR0, CR4 (and not just CR3). We are currently fine
8708 * since IEM_CPUMCTX_EXTRN_MUST_MASK (used below) includes CR3 which will import
8709 * PAE PDPTEs as well.
8710 */
8711 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_MUST_MASK>(pVCpu, pVmcsInfo, __FUNCTION__);
8712 AssertRCReturn(rc, rc);
8713
8714 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
8715#ifndef IN_NEM_DARWIN
8716 uint32_t const uOldCr0 = pVCpu->cpum.GstCtx.cr0;
8717#endif
8718 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
8719 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
8720
8721 /*
8722 * MOV to CR3 only cause a VM-exit when one or more of the following are true:
8723 * - When nested paging isn't used.
8724 * - If the guest doesn't have paging enabled (intercept CR3 to update shadow page tables).
8725 * - We are executing in the VM debug loop.
8726 */
8727#ifndef HMVMX_ALWAYS_INTERCEPT_CR3_ACCESS
8728# ifndef IN_NEM_DARWIN
8729 Assert( iCrReg != 3
8730 || !VM_IS_VMX_NESTED_PAGING(pVM)
8731 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
8732 || pVCpu->hmr0.s.fUsingDebugLoop);
8733# else
8734 Assert( iCrReg != 3
8735 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx));
8736# endif
8737#endif
8738
8739 /* MOV to CR8 writes only cause VM-exits when TPR shadow is not used. */
8740 Assert( iCrReg != 8
8741 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
8742
8743 rcStrict = vmxHCExitMovToCrX(pVCpu, pVmxTransient->cbExitInstr, iGReg, iCrReg);
8744 AssertMsg( rcStrict == VINF_SUCCESS
8745 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8746
8747#ifndef IN_NEM_DARWIN
8748 /*
8749 * This is a kludge for handling switches back to real mode when we try to use
8750 * V86 mode to run real mode code directly. Problem is that V86 mode cannot
8751 * deal with special selector values, so we have to return to ring-3 and run
8752 * there till the selector values are V86 mode compatible.
8753 *
8754 * Note! Using VINF_EM_RESCHEDULE_REM here rather than VINF_EM_RESCHEDULE since the
8755 * latter is an alias for VINF_IEM_RAISED_XCPT which is asserted at the end of
8756 * this function.
8757 */
8758 if ( iCrReg == 0
8759 && rcStrict == VINF_SUCCESS
8760 && !VM_IS_VMX_UNRESTRICTED_GUEST(pVM)
8761 && CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx)
8762 && (uOldCr0 & X86_CR0_PE)
8763 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
8764 {
8765 /** @todo Check selectors rather than returning all the time. */
8766 Assert(!pVmxTransient->fIsNestedGuest);
8767 Log4Func(("CR0 write, back to real mode -> VINF_EM_RESCHEDULE_REM\n"));
8768 rcStrict = VINF_EM_RESCHEDULE_REM;
8769 }
8770#endif
8771
8772 break;
8773 }
8774
8775 /*
8776 * MOV from CRx.
8777 */
8778 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
8779 {
8780 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
8781 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
8782
8783 /*
8784 * MOV from CR3 only cause a VM-exit when one or more of the following are true:
8785 * - When nested paging isn't used.
8786 * - If the guest doesn't have paging enabled (pass guest's CR3 rather than our identity mapped CR3).
8787 * - We are executing in the VM debug loop.
8788 */
8789#ifndef HMVMX_ALWAYS_INTERCEPT_CR3_ACCESS
8790# ifndef IN_NEM_DARWIN
8791 Assert( iCrReg != 3
8792 || !VM_IS_VMX_NESTED_PAGING(pVM)
8793 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
8794 || pVCpu->hmr0.s.fLeaveDone);
8795# else
8796 Assert( iCrReg != 3
8797 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx));
8798# endif
8799#endif
8800
8801 /* MOV from CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
8802 Assert( iCrReg != 8
8803 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
8804
8805 rcStrict = vmxHCExitMovFromCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
8806 break;
8807 }
8808
8809 /*
8810 * CLTS (Clear Task-Switch Flag in CR0).
8811 */
8812 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
8813 {
8814 rcStrict = vmxHCExitClts(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr);
8815 break;
8816 }
8817
8818 /*
8819 * LMSW (Load Machine-Status Word into CR0).
8820 * LMSW cannot clear CR0.PE, so no fRealOnV86Active kludge needed here.
8821 */
8822 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW:
8823 {
8824 RTGCPTR GCPtrEffDst;
8825 uint8_t const cbInstr = pVmxTransient->cbExitInstr;
8826 uint16_t const uMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(uExitQual);
8827 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(uExitQual);
8828 if (fMemOperand)
8829 {
8830 vmxHCReadToTransient<HMVMX_READ_GUEST_LINEAR_ADDR>(pVCpu, pVmxTransient);
8831 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
8832 }
8833 else
8834 GCPtrEffDst = NIL_RTGCPTR;
8835 rcStrict = vmxHCExitLmsw(pVCpu, pVmcsInfo, cbInstr, uMsw, GCPtrEffDst);
8836 break;
8837 }
8838
8839 default:
8840 {
8841 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
8842 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
8843 }
8844 }
8845
8846 Assert((VCPU_2_VMXSTATE(pVCpu).fCtxChanged & (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS))
8847 == (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS));
8848 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
8849
8850 STAM_PROFILE_ADV_STOP(&VCPU_2_VMXSTATS(pVCpu).StatExitMovCRx, y2);
8851 NOREF(pVM);
8852 return rcStrict;
8853}
8854
8855
8856/**
8857 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
8858 * VM-exit.
8859 */
8860HMVMX_EXIT_DECL vmxHCExitIoInstr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
8861{
8862 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
8863 STAM_PROFILE_ADV_START(&VCPU_2_VMXSTATS(pVCpu).StatExitIO, y1);
8864
8865 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8866 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8867 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
8868 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
8869#define VMX_HC_EXIT_IO_INSTR_INITIAL_REGS (IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_EFER)
8870 /* EFER MSR also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
8871 int rc = vmxHCImportGuestState<VMX_HC_EXIT_IO_INSTR_INITIAL_REGS>(pVCpu, pVmcsInfo, __FUNCTION__);
8872 AssertRCReturn(rc, rc);
8873
8874 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
8875 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
8876 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
8877 bool const fIOWrite = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
8878 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
8879 bool const fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
8880 bool const fDbgStepping = VCPU_2_VMXSTATE(pVCpu).fSingleInstruction;
8881 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
8882
8883 /*
8884 * Update exit history to see if this exit can be optimized.
8885 */
8886 VBOXSTRICTRC rcStrict;
8887 PCEMEXITREC pExitRec = NULL;
8888 if ( !fGstStepping
8889 && !fDbgStepping)
8890 pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
8891 !fIOString
8892 ? !fIOWrite
8893 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_READ)
8894 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_WRITE)
8895 : !fIOWrite
8896 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_READ)
8897 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_WRITE),
8898 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
8899 if (!pExitRec)
8900 {
8901 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
8902 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving result in AL/AX/EAX. */
8903
8904 uint32_t const cbValue = s_aIOSizes[uIOSize];
8905 uint32_t const cbInstr = pVmxTransient->cbExitInstr;
8906 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
8907 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8908 if (fIOString)
8909 {
8910 /*
8911 * INS/OUTS - I/O String instruction.
8912 *
8913 * Use instruction-information if available, otherwise fall back on
8914 * interpreting the instruction.
8915 */
8916 Log4Func(("cs:rip=%#04x:%08RX64 %#06x/%u %c str\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
8917 AssertReturn(pCtx->dx == uIOPort, VERR_VMX_IPE_2);
8918 bool const fInsOutsInfo = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS);
8919 if (fInsOutsInfo)
8920 {
8921 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_INFO>(pVCpu, pVmxTransient);
8922 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
8923 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
8924 IEMMODE const enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
8925 bool const fRep = VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual);
8926 if (fIOWrite)
8927 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
8928 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
8929 else
8930 {
8931 /*
8932 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
8933 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
8934 * See Intel Instruction spec. for "INS".
8935 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
8936 */
8937 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
8938 }
8939 }
8940 else
8941 rcStrict = IEMExecOne(pVCpu);
8942
8943 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP);
8944 fUpdateRipAlready = true;
8945 }
8946 else
8947 {
8948 /*
8949 * IN/OUT - I/O instruction.
8950 */
8951 Log4Func(("cs:rip=%04x:%08RX64 %#06x/%u %c\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
8952 uint32_t const uAndVal = s_aIOOpAnd[uIOSize];
8953 Assert(!VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual));
8954 if (fIOWrite)
8955 {
8956 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pCtx->eax & uAndVal, cbValue);
8957 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitIOWrite);
8958#ifndef IN_NEM_DARWIN
8959 if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
8960 && !pCtx->eflags.Bits.u1TF)
8961 rcStrict = EMRZSetPendingIoPortWrite(pVCpu, uIOPort, cbInstr, cbValue, pCtx->eax & uAndVal);
8962#endif
8963 }
8964 else
8965 {
8966 uint32_t u32Result = 0;
8967 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
8968 if (IOM_SUCCESS(rcStrict))
8969 {
8970 /* Save result of I/O IN instr. in AL/AX/EAX. */
8971 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Result & uAndVal);
8972 }
8973#ifndef IN_NEM_DARWIN
8974 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
8975 && !pCtx->eflags.Bits.u1TF)
8976 rcStrict = EMRZSetPendingIoPortRead(pVCpu, uIOPort, cbInstr, cbValue);
8977#endif
8978 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitIORead);
8979 }
8980 }
8981
8982 if (IOM_SUCCESS(rcStrict))
8983 {
8984 if (!fUpdateRipAlready)
8985 {
8986 vmxHCAdvanceGuestRipBy(pVCpu, cbInstr);
8987 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP);
8988 }
8989
8990 /*
8991 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru
8992 * while booting Fedora 17 64-bit guest.
8993 *
8994 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
8995 */
8996 if (fIOString)
8997 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RFLAGS);
8998
8999 /*
9000 * If any I/O breakpoints are armed, we need to check if one triggered
9001 * and take appropriate action.
9002 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
9003 */
9004#if 1
9005 AssertCompile(VMX_HC_EXIT_IO_INSTR_INITIAL_REGS & CPUMCTX_EXTRN_DR7);
9006#else
9007 AssertCompile(!(VMX_HC_EXIT_IO_INSTR_INITIAL_REGS & CPUMCTX_EXTRN_DR7));
9008 rc = vmxHCImportGuestState<CPUMCTX_EXTRN_DR7>(pVCpu, pVmcsInfo);
9009 AssertRCReturn(rc, rc);
9010#endif
9011
9012 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
9013 * execution engines about whether hyper BPs and such are pending. */
9014 uint32_t const uDr7 = pCtx->dr[7];
9015 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
9016 && X86_DR7_ANY_RW_IO(uDr7)
9017 && (pCtx->cr4 & X86_CR4_DE))
9018 || DBGFBpIsHwIoArmed(pVM)))
9019 {
9020 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatDRxIoCheck);
9021
9022#ifndef IN_NEM_DARWIN
9023 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
9024 VMMRZCallRing3Disable(pVCpu);
9025 HM_DISABLE_PREEMPT(pVCpu);
9026
9027 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
9028
9029 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, uIOPort, cbValue);
9030 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
9031 {
9032 /* Raise #DB. */
9033 if (fIsGuestDbgActive)
9034 ASMSetDR6(pCtx->dr[6]);
9035 if (pCtx->dr[7] != uDr7)
9036 VCPU_2_VMXSTATE(pVCpu).fCtxChanged |= HM_CHANGED_GUEST_DR7;
9037
9038 vmxHCSetPendingXcptDB(pVCpu);
9039 }
9040 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
9041 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
9042 else if ( rcStrict2 != VINF_SUCCESS
9043 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
9044 rcStrict = rcStrict2;
9045 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
9046
9047 HM_RESTORE_PREEMPT();
9048 VMMRZCallRing3Enable(pVCpu);
9049#else
9050 /** @todo */
9051#endif
9052 }
9053 }
9054
9055#ifdef VBOX_STRICT
9056 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
9057 || rcStrict == VINF_EM_PENDING_R3_IOPORT_READ)
9058 Assert(!fIOWrite);
9059 else if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
9060 || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
9061 || rcStrict == VINF_EM_PENDING_R3_IOPORT_WRITE)
9062 Assert(fIOWrite);
9063 else
9064 {
9065# if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
9066 * statuses, that the VMM device and some others may return. See
9067 * IOM_SUCCESS() for guidance. */
9068 AssertMsg( RT_FAILURE(rcStrict)
9069 || rcStrict == VINF_SUCCESS
9070 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
9071 || rcStrict == VINF_EM_DBG_BREAKPOINT
9072 || rcStrict == VINF_EM_RAW_GUEST_TRAP
9073 || rcStrict == VINF_EM_RAW_TO_R3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
9074# endif
9075 }
9076#endif
9077 STAM_PROFILE_ADV_STOP(&VCPU_2_VMXSTATS(pVCpu).StatExitIO, y1);
9078 }
9079 else
9080 {
9081 /*
9082 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
9083 */
9084 int rc2 = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL,
9085 VMX_HC_EXIT_IO_INSTR_INITIAL_REGS>(pVCpu, pVmcsInfo, __FUNCTION__);
9086 AssertRCReturn(rc2, rc2);
9087 STAM_COUNTER_INC(!fIOString ? fIOWrite ? &VCPU_2_VMXSTATS(pVCpu).StatExitIOWrite : &VCPU_2_VMXSTATS(pVCpu).StatExitIORead
9088 : fIOWrite ? &VCPU_2_VMXSTATS(pVCpu).StatExitIOStringWrite : &VCPU_2_VMXSTATS(pVCpu).StatExitIOStringRead);
9089 Log4(("IOExit/%u: %04x:%08RX64: %s%s%s %#x LB %u -> EMHistoryExec\n",
9090 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
9091 VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual) ? "REP " : "",
9092 fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOSize));
9093
9094 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
9095 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST);
9096
9097 Log4(("IOExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
9098 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
9099 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
9100 }
9101 return rcStrict;
9102}
9103
9104
9105/**
9106 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
9107 * VM-exit.
9108 */
9109HMVMX_EXIT_DECL vmxHCExitTaskSwitch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9110{
9111 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9112
9113 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
9114 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
9115 if (VMX_EXIT_QUAL_TASK_SWITCH_TYPE(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT)
9116 {
9117 vmxHCReadToTransient<HMVMX_READ_IDT_VECTORING_INFO>(pVCpu, pVmxTransient);
9118 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
9119 {
9120 uint32_t uErrCode;
9121 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uIdtVectoringInfo))
9122 {
9123 vmxHCReadToTransient<HMVMX_READ_IDT_VECTORING_ERROR_CODE>(pVCpu, pVmxTransient);
9124 uErrCode = pVmxTransient->uIdtVectoringErrorCode;
9125 }
9126 else
9127 uErrCode = 0;
9128
9129 RTGCUINTPTR GCPtrFaultAddress;
9130 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(pVmxTransient->uIdtVectoringInfo))
9131 GCPtrFaultAddress = pVCpu->cpum.GstCtx.cr2;
9132 else
9133 GCPtrFaultAddress = 0;
9134
9135 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
9136
9137 vmxHCSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
9138 pVmxTransient->cbExitInstr, uErrCode, GCPtrFaultAddress);
9139
9140 Log4Func(("Pending event. uIntType=%#x uVector=%#x\n", VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo),
9141 VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo)));
9142 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitTaskSwitch);
9143 return VINF_EM_RAW_INJECT_TRPM_EVENT;
9144 }
9145 }
9146
9147 /* Fall back to the interpreter to emulate the task-switch. */
9148 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitTaskSwitch);
9149 return VERR_EM_INTERPRETER;
9150}
9151
9152
9153/**
9154 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
9155 */
9156HMVMX_EXIT_DECL vmxHCExitMtf(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9157{
9158 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9159
9160 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
9161 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
9162 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
9163 AssertRC(rc);
9164 return VINF_EM_DBG_STEPPED;
9165}
9166
9167
9168/**
9169 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
9170 */
9171HMVMX_EXIT_DECL vmxHCExitApicAccess(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9172{
9173 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9174 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitApicAccess);
9175
9176 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
9177 | HMVMX_READ_EXIT_INSTR_LEN
9178 | HMVMX_READ_EXIT_INTERRUPTION_INFO
9179 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
9180 | HMVMX_READ_IDT_VECTORING_INFO
9181 | HMVMX_READ_IDT_VECTORING_ERROR_CODE>(pVCpu, pVmxTransient);
9182
9183 /*
9184 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
9185 */
9186 VBOXSTRICTRC rcStrict = vmxHCCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
9187 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9188 {
9189 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
9190 if (RT_UNLIKELY(VCPU_2_VMXSTATE(pVCpu).Event.fPending))
9191 {
9192 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatInjectInterpret);
9193 return VINF_EM_RAW_INJECT_TRPM_EVENT;
9194 }
9195 }
9196 else
9197 {
9198 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
9199 return rcStrict;
9200 }
9201
9202 /* IOMMIOPhysHandler() below may call into IEM, save the necessary state. */
9203 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
9204 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_MUST_MASK>(pVCpu, pVmcsInfo, __FUNCTION__);
9205 AssertRCReturn(rc, rc);
9206
9207 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
9208 uint32_t const uAccessType = VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual);
9209 switch (uAccessType)
9210 {
9211#ifndef IN_NEM_DARWIN
9212 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
9213 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
9214 {
9215 AssertMsg( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
9216 || VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual) != XAPIC_OFF_TPR,
9217 ("vmxHCExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
9218
9219 RTGCPHYS GCPhys = VCPU_2_VMXSTATE(pVCpu).vmx.u64GstMsrApicBase; /* Always up-to-date, as it is not part of the VMCS. */
9220 GCPhys &= ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
9221 GCPhys += VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual);
9222 Log4Func(("Linear access uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
9223 VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual)));
9224
9225 rcStrict = IOMR0MmioPhysHandler(pVCpu->CTX_SUFF(pVM), pVCpu,
9226 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW, GCPhys);
9227 Log4Func(("IOMR0MmioPhysHandler returned %Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
9228 if ( rcStrict == VINF_SUCCESS
9229 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
9230 || rcStrict == VERR_PAGE_NOT_PRESENT)
9231 {
9232 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
9233 | HM_CHANGED_GUEST_APIC_TPR);
9234 rcStrict = VINF_SUCCESS;
9235 }
9236 break;
9237 }
9238#else
9239 /** @todo */
9240#endif
9241
9242 default:
9243 {
9244 Log4Func(("uAccessType=%#x\n", uAccessType));
9245 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
9246 break;
9247 }
9248 }
9249
9250 if (rcStrict != VINF_SUCCESS)
9251 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatSwitchApicAccessToR3);
9252 return rcStrict;
9253}
9254
9255
9256/**
9257 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
9258 * VM-exit.
9259 */
9260HMVMX_EXIT_DECL vmxHCExitMovDRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9261{
9262 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9263 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
9264
9265 /*
9266 * We might also get this VM-exit if the nested-guest isn't intercepting MOV DRx accesses.
9267 * In such a case, rather than disabling MOV DRx intercepts and resuming execution, we
9268 * must emulate the MOV DRx access.
9269 */
9270 if (!pVmxTransient->fIsNestedGuest)
9271 {
9272 /* We should -not- get this VM-exit if the guest's debug registers were active. */
9273 if ( pVmxTransient->fWasGuestDebugStateActive
9274#ifdef VMX_WITH_MAYBE_ALWAYS_INTERCEPT_MOV_DRX
9275 && !pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fAlwaysInterceptMovDRx
9276#endif
9277 )
9278 {
9279 AssertMsgFailed(("Unexpected MOV DRx exit\n"));
9280 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
9281 }
9282
9283 if ( !VCPU_2_VMXSTATE(pVCpu).fSingleInstruction
9284 && !pVmxTransient->fWasHyperDebugStateActive)
9285 {
9286 Assert(!DBGFIsStepping(pVCpu));
9287 Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB));
9288
9289 /* Whether we disable intercepting MOV DRx instructions and resume
9290 the current one, or emulate it and keep intercepting them is
9291 configurable. Though it usually comes down to whether there are
9292 any new DR6 & DR7 bits (RTM) we want to hide from the guest. */
9293#ifdef VMX_WITH_MAYBE_ALWAYS_INTERCEPT_MOV_DRX
9294 bool const fResumeInstruction = !pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fAlwaysInterceptMovDRx;
9295#else
9296 bool const fResumeInstruction = true;
9297#endif
9298 if (fResumeInstruction)
9299 {
9300 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
9301 int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
9302 AssertRC(rc);
9303 }
9304
9305#ifndef IN_NEM_DARWIN
9306 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
9307 VMMRZCallRing3Disable(pVCpu);
9308 HM_DISABLE_PREEMPT(pVCpu);
9309
9310 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
9311 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
9312 Assert(CPUMIsGuestDebugStateActive(pVCpu));
9313
9314 HM_RESTORE_PREEMPT();
9315 VMMRZCallRing3Enable(pVCpu);
9316#else
9317 CPUMR3NemActivateGuestDebugState(pVCpu);
9318 Assert(CPUMIsGuestDebugStateActive(pVCpu));
9319 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
9320#endif
9321
9322 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatDRxContextSwitch);
9323 if (fResumeInstruction)
9324 {
9325#ifdef VBOX_WITH_STATISTICS
9326 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
9327 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
9328 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitDRxWrite);
9329 else
9330 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitDRxRead);
9331#endif
9332 return VINF_SUCCESS;
9333 }
9334 }
9335 }
9336
9337 /*
9338 * Import state. We must have DR7 loaded here as it's always consulted,
9339 * both for reading and writing. The other debug registers are never
9340 * exported as such.
9341 */
9342 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
9343 int rc = vmxHCImportGuestState< IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK
9344 | CPUMCTX_EXTRN_GPRS_MASK
9345 | CPUMCTX_EXTRN_DR7>(pVCpu, pVmcsInfo, __FUNCTION__);
9346 AssertRCReturn(rc, rc);
9347
9348 uint8_t const iGReg = VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual);
9349 uint8_t const iDrReg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
9350 Log4Func(("cs:rip=%#04x:%08RX64 r%d %s dr%d\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, iGReg,
9351 VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE ? "->" : "<-", iDrReg));
9352
9353 VBOXSTRICTRC rcStrict;
9354 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
9355 {
9356 /*
9357 * Write DRx register.
9358 */
9359 rcStrict = IEMExecDecodedMovDRxWrite(pVCpu, pVmxTransient->cbExitInstr, iDrReg, iGReg);
9360 AssertMsg( rcStrict == VINF_SUCCESS
9361 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
9362
9363 if (rcStrict == VINF_SUCCESS)
9364 {
9365 /** @todo r=bird: Not sure why we always flag DR7 as modified here, but I've
9366 * kept it for now to avoid breaking something non-obvious. */
9367 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
9368 | HM_CHANGED_GUEST_DR7);
9369 /* Update the DR6 register if guest debug state is active, otherwise we'll
9370 trash it when calling CPUMR0DebugStateMaybeSaveGuestAndRestoreHost. */
9371 if (iDrReg == 6 && CPUMIsGuestDebugStateActive(pVCpu))
9372 ASMSetDR6(pVCpu->cpum.GstCtx.dr[6]);
9373 Log4Func(("r%d=%#RX64 => dr%d=%#RX64\n", iGReg, pVCpu->cpum.GstCtx.aGRegs[iGReg].u,
9374 iDrReg, pVCpu->cpum.GstCtx.dr[iDrReg]));
9375 }
9376 else if (rcStrict == VINF_IEM_RAISED_XCPT)
9377 {
9378 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
9379 rcStrict = VINF_SUCCESS;
9380 }
9381
9382 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitDRxWrite);
9383 }
9384 else
9385 {
9386 /*
9387 * Read DRx register into a general purpose register.
9388 */
9389 rcStrict = IEMExecDecodedMovDRxRead(pVCpu, pVmxTransient->cbExitInstr, iGReg, iDrReg);
9390 AssertMsg( rcStrict == VINF_SUCCESS
9391 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
9392
9393 if (rcStrict == VINF_SUCCESS)
9394 {
9395 if (iGReg == X86_GREG_xSP)
9396 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
9397 | HM_CHANGED_GUEST_RSP);
9398 else
9399 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
9400 }
9401 else if (rcStrict == VINF_IEM_RAISED_XCPT)
9402 {
9403 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
9404 rcStrict = VINF_SUCCESS;
9405 }
9406
9407 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitDRxRead);
9408 }
9409
9410 return rcStrict;
9411}
9412
9413
9414/**
9415 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
9416 * Conditional VM-exit.
9417 */
9418HMVMX_EXIT_DECL vmxHCExitEptMisconfig(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9419{
9420 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9421
9422#ifndef IN_NEM_DARWIN
9423 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
9424
9425 vmxHCReadToTransient< HMVMX_READ_EXIT_INSTR_LEN
9426 | HMVMX_READ_EXIT_INTERRUPTION_INFO
9427 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
9428 | HMVMX_READ_IDT_VECTORING_INFO
9429 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
9430 | HMVMX_READ_GUEST_PHYSICAL_ADDR>(pVCpu, pVmxTransient);
9431
9432 /*
9433 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
9434 */
9435 VBOXSTRICTRC rcStrict = vmxHCCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
9436 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9437 {
9438 /*
9439 * In the unlikely case where delivering an event causes an EPT misconfig (MMIO), go back to
9440 * instruction emulation to inject the original event. Otherwise, injecting the original event
9441 * using hardware-assisted VMX would trigger the same EPT misconfig VM-exit again.
9442 */
9443 if (!VCPU_2_VMXSTATE(pVCpu).Event.fPending)
9444 { /* likely */ }
9445 else
9446 {
9447 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatInjectInterpret);
9448# ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9449 /** @todo NSTVMX: Think about how this should be handled. */
9450 if (pVmxTransient->fIsNestedGuest)
9451 return VERR_VMX_IPE_3;
9452# endif
9453 return VINF_EM_RAW_INJECT_TRPM_EVENT;
9454 }
9455 }
9456 else
9457 {
9458 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
9459 return rcStrict;
9460 }
9461
9462 /*
9463 * Get sufficient state and update the exit history entry.
9464 */
9465 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
9466 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_MUST_MASK>(pVCpu, pVmcsInfo, __FUNCTION__);
9467 AssertRCReturn(rc, rc);
9468
9469 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
9470 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
9471 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_MMIO),
9472 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
9473 if (!pExitRec)
9474 {
9475 /*
9476 * If we succeed, resume guest execution.
9477 * If we fail in interpreting the instruction because we couldn't get the guest physical address
9478 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
9479 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
9480 * weird case. See @bugref{6043}.
9481 */
9482 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9483/** @todo bird: We can probably just go straight to IOM here and assume that
9484 * it's MMIO, then fall back on PGM if that hunch didn't work out so
9485 * well. However, we need to address that aliasing workarounds that
9486 * PGMR0Trap0eHandlerNPMisconfig implements. So, some care is needed.
9487 *
9488 * Might also be interesting to see if we can get this done more or
9489 * less locklessly inside IOM. Need to consider the lookup table
9490 * updating and use a bit more carefully first (or do all updates via
9491 * rendezvous) */
9492 rcStrict = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, &pVCpu->cpum.GstCtx, GCPhys, UINT32_MAX);
9493 Log4Func(("At %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pVCpu->cpum.GstCtx.rip, VBOXSTRICTRC_VAL(rcStrict)));
9494 if ( rcStrict == VINF_SUCCESS
9495 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
9496 || rcStrict == VERR_PAGE_NOT_PRESENT)
9497 {
9498 /* Successfully handled MMIO operation. */
9499 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
9500 | HM_CHANGED_GUEST_APIC_TPR);
9501 rcStrict = VINF_SUCCESS;
9502 }
9503 }
9504 else
9505 {
9506 /*
9507 * Frequent exit or something needing probing. Call EMHistoryExec.
9508 */
9509 Log4(("EptMisscfgExit/%u: %04x:%08RX64: %RGp -> EMHistoryExec\n",
9510 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPhys));
9511
9512 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
9513 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST);
9514
9515 Log4(("EptMisscfgExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
9516 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
9517 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
9518 }
9519 return rcStrict;
9520#else
9521 AssertFailed();
9522 return VERR_VMX_IPE_3; /* Should never happen with Apple HV in R3. */
9523#endif
9524}
9525
9526
9527/**
9528 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
9529 * VM-exit.
9530 */
9531HMVMX_EXIT_DECL vmxHCExitEptViolation(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9532{
9533 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9534#ifndef IN_NEM_DARWIN
9535 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
9536
9537 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
9538 | HMVMX_READ_EXIT_INSTR_LEN
9539 | HMVMX_READ_EXIT_INTERRUPTION_INFO
9540 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
9541 | HMVMX_READ_IDT_VECTORING_INFO
9542 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
9543 | HMVMX_READ_GUEST_PHYSICAL_ADDR>(pVCpu, pVmxTransient);
9544
9545 /*
9546 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
9547 */
9548 VBOXSTRICTRC rcStrict = vmxHCCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
9549 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9550 {
9551 /*
9552 * If delivery of an event causes an EPT violation (true nested #PF and not MMIO),
9553 * we shall resolve the nested #PF and re-inject the original event.
9554 */
9555 if (VCPU_2_VMXSTATE(pVCpu).Event.fPending)
9556 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatInjectReflectNPF);
9557 }
9558 else
9559 {
9560 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
9561 return rcStrict;
9562 }
9563
9564 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
9565 int rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_MUST_MASK>(pVCpu, pVmcsInfo, __FUNCTION__);
9566 AssertRCReturn(rc, rc);
9567
9568 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
9569 uint64_t const uExitQual = pVmxTransient->uExitQual;
9570 AssertMsg(((pVmxTransient->uExitQual >> 7) & 3) != 2, ("%#RX64", uExitQual));
9571
9572 RTGCUINT uErrorCode = 0;
9573 if (uExitQual & VMX_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH)
9574 uErrorCode |= X86_TRAP_PF_ID;
9575 if (uExitQual & VMX_EXIT_QUAL_EPT_ACCESS_WRITE)
9576 uErrorCode |= X86_TRAP_PF_RW;
9577 if (uExitQual & (VMX_EXIT_QUAL_EPT_ENTRY_READ | VMX_EXIT_QUAL_EPT_ENTRY_WRITE | VMX_EXIT_QUAL_EPT_ENTRY_EXECUTE))
9578 uErrorCode |= X86_TRAP_PF_P;
9579
9580 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9581 Log4Func(("at %#RX64 (%#RX64 errcode=%#x) cs:rip=%#04x:%08RX64\n", GCPhys, uExitQual, uErrorCode, pCtx->cs.Sel, pCtx->rip));
9582
9583 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9584
9585 /*
9586 * Handle the pagefault trap for the nested shadow table.
9587 */
9588 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
9589 rcStrict = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, pCtx, GCPhys);
9590 TRPMResetTrap(pVCpu);
9591
9592 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
9593 if ( rcStrict == VINF_SUCCESS
9594 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
9595 || rcStrict == VERR_PAGE_NOT_PRESENT)
9596 {
9597 /* Successfully synced our nested page tables. */
9598 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitReasonNpf);
9599 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS);
9600 return VINF_SUCCESS;
9601 }
9602 Log4Func(("EPT return to ring-3 rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
9603 return rcStrict;
9604
9605#else /* IN_NEM_DARWIN */
9606 PVM pVM = pVCpu->CTX_SUFF(pVM);
9607 uint64_t const uHostTsc = ASMReadTSC(); RT_NOREF(uHostTsc);
9608 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
9609 | HMVMX_READ_GUEST_PHYSICAL_ADDR>(pVCpu, pVmxTransient);
9610 vmxHCImportGuestRip(pVCpu);
9611 vmxHCImportGuestSegReg<X86_SREG_CS>(pVCpu);
9612
9613 /*
9614 * Ask PGM for information about the given GCPhys. We need to check if we're
9615 * out of sync first.
9616 */
9617 NEMHCDARWINHMACPCCSTATE State = { RT_BOOL(pVmxTransient->uExitQual & VMX_EXIT_QUAL_EPT_ACCESS_WRITE),
9618 false,
9619 false };
9620 PGMPHYSNEMPAGEINFO Info;
9621 int rc = PGMPhysNemPageInfoChecker(pVM, pVCpu, pVmxTransient->uGuestPhysicalAddr, State.fWriteAccess, &Info,
9622 nemR3DarwinHandleMemoryAccessPageCheckerCallback, &State);
9623 if (RT_SUCCESS(rc))
9624 {
9625 if (Info.fNemProt & ( RT_BOOL(pVmxTransient->uExitQual & VMX_EXIT_QUAL_EPT_ACCESS_WRITE)
9626 ? NEM_PAGE_PROT_WRITE : NEM_PAGE_PROT_READ))
9627 {
9628 if (State.fCanResume)
9629 {
9630 Log4(("MemExit/%u: %04x:%08RX64: %RGp (=>%RHp) %s fProt=%u%s%s%s; restarting\n",
9631 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
9632 pVmxTransient->uGuestPhysicalAddr, Info.HCPhys, g_apszPageStates[Info.u2NemState], Info.fNemProt,
9633 Info.fHasHandlers ? " handlers" : "", Info.fZeroPage ? " zero-pg" : "",
9634 State.fDidSomething ? "" : " no-change"));
9635 EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_NEM, NEMEXITTYPE_MEMORY_ACCESS),
9636 pVCpu->cpum.GstCtx.cs.u64Base + pVCpu->cpum.GstCtx.rip, uHostTsc);
9637 return VINF_SUCCESS;
9638 }
9639 }
9640
9641 Log4(("MemExit/%u: %04x:%08RX64: %RGp (=>%RHp) %s fProt=%u%s%s%s; emulating\n",
9642 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
9643 pVmxTransient->uGuestPhysicalAddr, Info.HCPhys, g_apszPageStates[Info.u2NemState], Info.fNemProt,
9644 Info.fHasHandlers ? " handlers" : "", Info.fZeroPage ? " zero-pg" : "",
9645 State.fDidSomething ? "" : " no-change"));
9646 }
9647 else
9648 Log4(("MemExit/%u: %04x:%08RX64: %RGp rc=%Rrc%s; emulating\n",
9649 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
9650 pVmxTransient->uGuestPhysicalAddr, rc, State.fDidSomething ? " modified-backing" : ""));
9651
9652 /*
9653 * Emulate the memory access, either access handler or special memory.
9654 */
9655 PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu,
9656 RT_BOOL(pVmxTransient->uExitQual & VMX_EXIT_QUAL_EPT_ACCESS_WRITE)
9657 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_MMIO_WRITE)
9658 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_MMIO_READ),
9659 pVCpu->cpum.GstCtx.cs.u64Base + pVCpu->cpum.GstCtx.rip, uHostTsc);
9660
9661 rc = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
9662 AssertRCReturn(rc, rc);
9663
9664 VBOXSTRICTRC rcStrict;
9665 if (!pExitRec)
9666 rcStrict = IEMExecOne(pVCpu);
9667 else
9668 {
9669 /* Frequent access or probing. */
9670 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
9671 Log4(("MemExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
9672 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
9673 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
9674 }
9675
9676 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST);
9677
9678 Log4Func(("EPT return rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
9679 return rcStrict;
9680#endif /* IN_NEM_DARWIN */
9681}
9682
9683#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9684
9685/**
9686 * VM-exit handler for VMCLEAR (VMX_EXIT_VMCLEAR). Unconditional VM-exit.
9687 */
9688HMVMX_EXIT_DECL vmxHCExitVmclear(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9689{
9690 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9691
9692 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
9693 | HMVMX_READ_EXIT_INSTR_INFO
9694 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
9695 int rc = vmxHCImportGuestState< CPUMCTX_EXTRN_RSP
9696 | CPUMCTX_EXTRN_SREG_MASK
9697 | CPUMCTX_EXTRN_HWVIRT
9698 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
9699 AssertRCReturn(rc, rc);
9700
9701 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
9702
9703 VMXVEXITINFO ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(pVmxTransient);
9704 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
9705
9706 VBOXSTRICTRC rcStrict = IEMExecDecodedVmclear(pVCpu, &ExitInfo);
9707 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9708 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
9709 else if (rcStrict == VINF_IEM_RAISED_XCPT)
9710 {
9711 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
9712 rcStrict = VINF_SUCCESS;
9713 }
9714 return rcStrict;
9715}
9716
9717
9718/**
9719 * VM-exit handler for VMLAUNCH (VMX_EXIT_VMLAUNCH). Unconditional VM-exit.
9720 */
9721HMVMX_EXIT_DECL vmxHCExitVmlaunch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9722{
9723 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9724
9725 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMLAUNCH,
9726 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
9727 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
9728 int rc = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
9729 AssertRCReturn(rc, rc);
9730
9731 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
9732
9733 STAM_PROFILE_ADV_START(&VCPU_2_VMXSTATS(pVCpu).StatExitVmentry, z);
9734 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMLAUNCH);
9735 STAM_PROFILE_ADV_STOP(&VCPU_2_VMXSTATS(pVCpu).StatExitVmentry, z);
9736 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9737 {
9738 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST);
9739 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
9740 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
9741 }
9742 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
9743 return rcStrict;
9744}
9745
9746
9747/**
9748 * VM-exit handler for VMPTRLD (VMX_EXIT_VMPTRLD). Unconditional VM-exit.
9749 */
9750HMVMX_EXIT_DECL vmxHCExitVmptrld(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9751{
9752 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9753
9754 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
9755 | HMVMX_READ_EXIT_INSTR_INFO
9756 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
9757 int rc = vmxHCImportGuestState< CPUMCTX_EXTRN_RSP
9758 | CPUMCTX_EXTRN_SREG_MASK
9759 | CPUMCTX_EXTRN_HWVIRT
9760 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
9761 AssertRCReturn(rc, rc);
9762
9763 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
9764
9765 VMXVEXITINFO ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(pVmxTransient);
9766 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
9767
9768 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrld(pVCpu, &ExitInfo);
9769 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9770 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
9771 else if (rcStrict == VINF_IEM_RAISED_XCPT)
9772 {
9773 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
9774 rcStrict = VINF_SUCCESS;
9775 }
9776 return rcStrict;
9777}
9778
9779
9780/**
9781 * VM-exit handler for VMPTRST (VMX_EXIT_VMPTRST). Unconditional VM-exit.
9782 */
9783HMVMX_EXIT_DECL vmxHCExitVmptrst(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9784{
9785 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9786
9787 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
9788 | HMVMX_READ_EXIT_INSTR_INFO
9789 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
9790 int rc = vmxHCImportGuestState< CPUMCTX_EXTRN_RSP
9791 | CPUMCTX_EXTRN_SREG_MASK
9792 | CPUMCTX_EXTRN_HWVIRT
9793 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
9794 AssertRCReturn(rc, rc);
9795
9796 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
9797
9798 VMXVEXITINFO ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(pVmxTransient);
9799 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
9800
9801 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrst(pVCpu, &ExitInfo);
9802 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9803 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
9804 else if (rcStrict == VINF_IEM_RAISED_XCPT)
9805 {
9806 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
9807 rcStrict = VINF_SUCCESS;
9808 }
9809 return rcStrict;
9810}
9811
9812
9813/**
9814 * VM-exit handler for VMREAD (VMX_EXIT_VMREAD). Conditional VM-exit.
9815 */
9816HMVMX_EXIT_DECL vmxHCExitVmread(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9817{
9818 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9819
9820 /*
9821 * Strictly speaking we should not get VMREAD VM-exits for shadow VMCS fields and
9822 * thus might not need to import the shadow VMCS state, it's safer just in case
9823 * code elsewhere dares look at unsynced VMCS fields.
9824 */
9825 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
9826 | HMVMX_READ_EXIT_INSTR_INFO
9827 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
9828 int rc = vmxHCImportGuestState< CPUMCTX_EXTRN_RSP
9829 | CPUMCTX_EXTRN_SREG_MASK
9830 | CPUMCTX_EXTRN_HWVIRT
9831 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
9832 AssertRCReturn(rc, rc);
9833
9834 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
9835
9836 VMXVEXITINFO ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(pVmxTransient);
9837 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
9838 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
9839
9840 VBOXSTRICTRC rcStrict = IEMExecDecodedVmread(pVCpu, &ExitInfo);
9841 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9842 {
9843 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
9844
9845# if 0 //ndef IN_NEM_DARWIN /** @todo this needs serious tuning still, slows down things enormously. */
9846 /* Try for exit optimization. This is on the following instruction
9847 because it would be a waste of time to have to reinterpret the
9848 already decoded vmwrite instruction. */
9849 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndType(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_VMREAD));
9850 if (pExitRec)
9851 {
9852 /* Frequent access or probing. */
9853 rc = vmxHCImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
9854 AssertRCReturn(rc, rc);
9855
9856 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
9857 Log4(("vmread/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
9858 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
9859 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
9860 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST);
9861 }
9862# endif
9863 }
9864 else if (rcStrict == VINF_IEM_RAISED_XCPT)
9865 {
9866 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
9867 rcStrict = VINF_SUCCESS;
9868 }
9869 return rcStrict;
9870}
9871
9872
9873/**
9874 * VM-exit handler for VMRESUME (VMX_EXIT_VMRESUME). Unconditional VM-exit.
9875 */
9876HMVMX_EXIT_DECL vmxHCExitVmresume(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9877{
9878 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9879
9880 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMRESUME,
9881 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
9882 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
9883 int rc = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
9884 AssertRCReturn(rc, rc);
9885
9886 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
9887
9888 STAM_PROFILE_ADV_START(&VCPU_2_VMXSTATS(pVCpu).StatExitVmentry, z);
9889 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMRESUME);
9890 STAM_PROFILE_ADV_STOP(&VCPU_2_VMXSTATS(pVCpu).StatExitVmentry, z);
9891 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9892 {
9893 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST);
9894 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
9895 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
9896 }
9897 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
9898 return rcStrict;
9899}
9900
9901
9902/**
9903 * VM-exit handler for VMWRITE (VMX_EXIT_VMWRITE). Conditional VM-exit.
9904 */
9905HMVMX_EXIT_DECL vmxHCExitVmwrite(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9906{
9907 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9908
9909 /*
9910 * Although we should not get VMWRITE VM-exits for shadow VMCS fields, since our HM hook
9911 * gets invoked when IEM's VMWRITE instruction emulation modifies the current VMCS and it
9912 * flags re-loading the entire shadow VMCS, we should save the entire shadow VMCS here.
9913 */
9914 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
9915 | HMVMX_READ_EXIT_INSTR_INFO
9916 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
9917 int rc = vmxHCImportGuestState< CPUMCTX_EXTRN_RSP
9918 | CPUMCTX_EXTRN_SREG_MASK
9919 | CPUMCTX_EXTRN_HWVIRT
9920 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
9921 AssertRCReturn(rc, rc);
9922
9923 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
9924
9925 VMXVEXITINFO ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(pVmxTransient);
9926 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
9927 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
9928
9929 VBOXSTRICTRC rcStrict = IEMExecDecodedVmwrite(pVCpu, &ExitInfo);
9930 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9931 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
9932 else if (rcStrict == VINF_IEM_RAISED_XCPT)
9933 {
9934 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
9935 rcStrict = VINF_SUCCESS;
9936 }
9937 return rcStrict;
9938}
9939
9940
9941/**
9942 * VM-exit handler for VMXOFF (VMX_EXIT_VMXOFF). Unconditional VM-exit.
9943 */
9944HMVMX_EXIT_DECL vmxHCExitVmxoff(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9945{
9946 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9947
9948 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
9949 int rc = vmxHCImportGuestState< CPUMCTX_EXTRN_CR4
9950 | CPUMCTX_EXTRN_HWVIRT
9951 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
9952 AssertRCReturn(rc, rc);
9953
9954 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
9955
9956 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxoff(pVCpu, pVmxTransient->cbExitInstr);
9957 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9958 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_HWVIRT);
9959 else if (rcStrict == VINF_IEM_RAISED_XCPT)
9960 {
9961 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
9962 rcStrict = VINF_SUCCESS;
9963 }
9964 return rcStrict;
9965}
9966
9967
9968/**
9969 * VM-exit handler for VMXON (VMX_EXIT_VMXON). Unconditional VM-exit.
9970 */
9971HMVMX_EXIT_DECL vmxHCExitVmxon(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9972{
9973 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
9974
9975 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
9976 | HMVMX_READ_EXIT_INSTR_INFO
9977 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
9978 int rc = vmxHCImportGuestState< CPUMCTX_EXTRN_RSP
9979 | CPUMCTX_EXTRN_SREG_MASK
9980 | CPUMCTX_EXTRN_HWVIRT
9981 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
9982 AssertRCReturn(rc, rc);
9983
9984 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
9985
9986 VMXVEXITINFO ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(pVmxTransient);
9987 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
9988
9989 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxon(pVCpu, &ExitInfo);
9990 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9991 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
9992 else if (rcStrict == VINF_IEM_RAISED_XCPT)
9993 {
9994 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
9995 rcStrict = VINF_SUCCESS;
9996 }
9997 return rcStrict;
9998}
9999
10000
10001/**
10002 * VM-exit handler for INVVPID (VMX_EXIT_INVVPID). Unconditional VM-exit.
10003 */
10004HMVMX_EXIT_DECL vmxHCExitInvvpid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10005{
10006 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10007
10008 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
10009 | HMVMX_READ_EXIT_INSTR_INFO
10010 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10011 int rc = vmxHCImportGuestState< CPUMCTX_EXTRN_RSP
10012 | CPUMCTX_EXTRN_SREG_MASK
10013 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
10014 AssertRCReturn(rc, rc);
10015
10016 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
10017
10018 VMXVEXITINFO ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(pVmxTransient);
10019 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
10020
10021 VBOXSTRICTRC rcStrict = IEMExecDecodedInvvpid(pVCpu, &ExitInfo);
10022 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10023 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
10024 else if (rcStrict == VINF_IEM_RAISED_XCPT)
10025 {
10026 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
10027 rcStrict = VINF_SUCCESS;
10028 }
10029 return rcStrict;
10030}
10031
10032
10033# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
10034/**
10035 * VM-exit handler for INVEPT (VMX_EXIT_INVEPT). Unconditional VM-exit.
10036 */
10037HMVMX_EXIT_DECL vmxHCExitInvept(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10038{
10039 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10040
10041 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
10042 | HMVMX_READ_EXIT_INSTR_INFO
10043 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10044 int rc = vmxHCImportGuestState< CPUMCTX_EXTRN_RSP
10045 | CPUMCTX_EXTRN_SREG_MASK
10046 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
10047 AssertRCReturn(rc, rc);
10048
10049 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
10050
10051 VMXVEXITINFO ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(pVmxTransient);
10052 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
10053
10054 VBOXSTRICTRC rcStrict = IEMExecDecodedInvept(pVCpu, &ExitInfo);
10055 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10056 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
10057 else if (rcStrict == VINF_IEM_RAISED_XCPT)
10058 {
10059 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
10060 rcStrict = VINF_SUCCESS;
10061 }
10062 return rcStrict;
10063}
10064# endif /* VBOX_WITH_NESTED_HWVIRT_VMX_EPT */
10065#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10066/** @} */
10067
10068
10069#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10070/** @name Nested-guest VM-exit handlers.
10071 * @{
10072 */
10073/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
10074/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Nested-guest VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
10075/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
10076
10077/**
10078 * Nested-guest VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
10079 * Conditional VM-exit.
10080 */
10081HMVMX_EXIT_DECL vmxHCExitXcptOrNmiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10082{
10083 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10084
10085 vmxHCReadToTransient<HMVMX_READ_EXIT_INTERRUPTION_INFO>(pVCpu, pVmxTransient);
10086
10087 uint64_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
10088 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
10089 Assert(VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo));
10090
10091 switch (uExitIntType)
10092 {
10093# ifndef IN_NEM_DARWIN
10094 /*
10095 * Physical NMIs:
10096 * We shouldn't direct host physical NMIs to the nested-guest. Dispatch it to the host.
10097 */
10098 case VMX_EXIT_INT_INFO_TYPE_NMI:
10099 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
10100# endif
10101
10102 /*
10103 * Hardware exceptions,
10104 * Software exceptions,
10105 * Privileged software exceptions:
10106 * Figure out if the exception must be delivered to the guest or the nested-guest.
10107 */
10108 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
10109 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
10110 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
10111 {
10112 vmxHCReadToTransient< HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
10113 | HMVMX_READ_EXIT_INSTR_LEN
10114 | HMVMX_READ_IDT_VECTORING_INFO
10115 | HMVMX_READ_IDT_VECTORING_ERROR_CODE>(pVCpu, pVmxTransient);
10116
10117 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
10118 if (CPUMIsGuestVmxXcptInterceptSet(pCtx, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo), pVmxTransient->uExitIntErrorCode))
10119 {
10120 /* Exit qualification is required for debug and page-fault exceptions. */
10121 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
10122
10123 /*
10124 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged
10125 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
10126 * length. However, if delivery of a software interrupt, software exception or privileged
10127 * software exception causes a VM-exit, that too provides the VM-exit instruction length.
10128 */
10129 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_FROM_TRANSIENT(pVmxTransient);
10130 VMXVEXITEVENTINFO const ExitEventInfo = VMXVEXITEVENTINFO_INIT(pVmxTransient->uExitIntInfo,
10131 pVmxTransient->uExitIntErrorCode,
10132 pVmxTransient->uIdtVectoringInfo,
10133 pVmxTransient->uIdtVectoringErrorCode);
10134#ifdef DEBUG_ramshankar
10135 vmxHCImportGuestStateEx(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
10136 Log4Func(("exit_int_info=%#RX32 err_code=%#RX32 exit_qual=%#RX64\n",
10137 pVmxTransient->uExitIntInfo, pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual));
10138 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
10139 Log4Func(("idt_info=%#RX32 idt_errcode=%#RX32 cr2=%#RX64\n",
10140 pVmxTransient->uIdtVectoringInfo, pVmxTransient->uIdtVectoringErrorCode, pCtx->cr2));
10141#endif
10142 return IEMExecVmxVmexitXcpt(pVCpu, &ExitInfo, &ExitEventInfo);
10143 }
10144
10145 /* Nested paging is currently a requirement, otherwise we would need to handle shadow #PFs in vmxHCExitXcptPF. */
10146 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
10147 return vmxHCExitXcpt(pVCpu, pVmxTransient);
10148 }
10149
10150 /*
10151 * Software interrupts:
10152 * VM-exits cannot be caused by software interrupts.
10153 *
10154 * External interrupts:
10155 * This should only happen when "acknowledge external interrupts on VM-exit"
10156 * control is set. However, we never set this when executing a guest or
10157 * nested-guest. For nested-guests it is emulated while injecting interrupts into
10158 * the guest.
10159 */
10160 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
10161 case VMX_EXIT_INT_INFO_TYPE_EXT_INT:
10162 default:
10163 {
10164 VCPU_2_VMXSTATE(pVCpu).u32HMError = pVmxTransient->uExitIntInfo;
10165 return VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
10166 }
10167 }
10168}
10169
10170
10171/**
10172 * Nested-guest VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT).
10173 * Unconditional VM-exit.
10174 */
10175HMVMX_EXIT_DECL vmxHCExitTripleFaultNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10176{
10177 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10178 return IEMExecVmxVmexitTripleFault(pVCpu);
10179}
10180
10181
10182/**
10183 * Nested-guest VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
10184 */
10185HMVMX_EXIT_NSRC_DECL vmxHCExitIntWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10186{
10187 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10188
10189 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
10190 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
10191 return vmxHCExitIntWindow(pVCpu, pVmxTransient);
10192}
10193
10194
10195/**
10196 * Nested-guest VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
10197 */
10198HMVMX_EXIT_NSRC_DECL vmxHCExitNmiWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10199{
10200 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10201
10202 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT))
10203 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
10204 return vmxHCExitNmiWindow(pVCpu, pVmxTransient);
10205}
10206
10207
10208/**
10209 * Nested-guest VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH).
10210 * Unconditional VM-exit.
10211 */
10212HMVMX_EXIT_DECL vmxHCExitTaskSwitchNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10213{
10214 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10215
10216 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
10217 | HMVMX_READ_EXIT_INSTR_LEN
10218 | HMVMX_READ_IDT_VECTORING_INFO
10219 | HMVMX_READ_IDT_VECTORING_ERROR_CODE>(pVCpu, pVmxTransient);
10220
10221 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_FROM_TRANSIENT(pVmxTransient);
10222 VMXVEXITEVENTINFO const ExitEventInfo = VMXVEXITEVENTINFO_INIT_ONLY_IDT(pVmxTransient->uIdtVectoringInfo,
10223 pVmxTransient->uIdtVectoringErrorCode);
10224 return IEMExecVmxVmexitTaskSwitch(pVCpu, &ExitInfo, &ExitEventInfo);
10225}
10226
10227
10228/**
10229 * Nested-guest VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
10230 */
10231HMVMX_EXIT_DECL vmxHCExitHltNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10232{
10233 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10234
10235 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_HLT_EXIT))
10236 {
10237 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10238 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
10239 }
10240 return vmxHCExitHlt(pVCpu, pVmxTransient);
10241}
10242
10243
10244/**
10245 * Nested-guest VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
10246 */
10247HMVMX_EXIT_DECL vmxHCExitInvlpgNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10248{
10249 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10250
10251 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
10252 {
10253 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
10254 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10255 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_FROM_TRANSIENT(pVmxTransient);
10256 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
10257 }
10258 return vmxHCExitInvlpg(pVCpu, pVmxTransient);
10259}
10260
10261
10262/**
10263 * Nested-guest VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
10264 */
10265HMVMX_EXIT_DECL vmxHCExitRdpmcNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10266{
10267 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10268
10269 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDPMC_EXIT))
10270 {
10271 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10272 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
10273 }
10274 return vmxHCExitRdpmc(pVCpu, pVmxTransient);
10275}
10276
10277
10278/**
10279 * Nested-guest VM-exit handler for VMREAD (VMX_EXIT_VMREAD) and VMWRITE
10280 * (VMX_EXIT_VMWRITE). Conditional VM-exit.
10281 */
10282HMVMX_EXIT_DECL vmxHCExitVmreadVmwriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10283{
10284 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10285
10286 Assert( pVmxTransient->uExitReason == VMX_EXIT_VMREAD
10287 || pVmxTransient->uExitReason == VMX_EXIT_VMWRITE);
10288
10289 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_INFO>(pVCpu, pVmxTransient);
10290
10291 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
10292 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
10293 uint64_t u64VmcsField = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
10294
10295 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
10296 if (!CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
10297 u64VmcsField &= UINT64_C(0xffffffff);
10298
10299 if (CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, pVmxTransient->uExitReason, u64VmcsField))
10300 {
10301 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
10302 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10303 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(pVmxTransient);
10304 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
10305 }
10306
10307 if (pVmxTransient->uExitReason == VMX_EXIT_VMREAD)
10308 return vmxHCExitVmread(pVCpu, pVmxTransient);
10309 return vmxHCExitVmwrite(pVCpu, pVmxTransient);
10310}
10311
10312
10313/**
10314 * Nested-guest VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
10315 */
10316HMVMX_EXIT_DECL vmxHCExitRdtscNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10317{
10318 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10319
10320 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
10321 {
10322 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10323 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
10324 }
10325
10326 return vmxHCExitRdtsc(pVCpu, pVmxTransient);
10327}
10328
10329
10330/**
10331 * Nested-guest VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX).
10332 * Conditional VM-exit.
10333 */
10334HMVMX_EXIT_DECL vmxHCExitMovCRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10335{
10336 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10337
10338 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
10339 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10340
10341 VBOXSTRICTRC rcStrict;
10342 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual);
10343 switch (uAccessType)
10344 {
10345 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
10346 {
10347 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
10348 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
10349 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
10350 uint64_t const uNewCrX = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
10351
10352 bool fIntercept;
10353 switch (iCrReg)
10354 {
10355 case 0:
10356 case 4:
10357 fIntercept = CPUMIsGuestVmxMovToCr0Cr4InterceptSet(&pVCpu->cpum.GstCtx, iCrReg, uNewCrX);
10358 break;
10359
10360 case 3:
10361 fIntercept = CPUMIsGuestVmxMovToCr3InterceptSet(pVCpu, uNewCrX);
10362 break;
10363
10364 case 8:
10365 fIntercept = CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_CR8_LOAD_EXIT);
10366 break;
10367
10368 default:
10369 fIntercept = false;
10370 break;
10371 }
10372 if (fIntercept)
10373 {
10374 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_FROM_TRANSIENT(pVmxTransient);
10375 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
10376 }
10377 else
10378 {
10379 int const rc = vmxHCImportGuestState<IEM_CPUMCTX_EXTRN_MUST_MASK>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
10380 AssertRCReturn(rc, rc);
10381 rcStrict = vmxHCExitMovToCrX(pVCpu, pVmxTransient->cbExitInstr, iGReg, iCrReg);
10382 }
10383 break;
10384 }
10385
10386 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
10387 {
10388 /*
10389 * CR0/CR4 reads do not cause VM-exits, the read-shadow is used (subject to masking).
10390 * CR2 reads do not cause a VM-exit.
10391 * CR3 reads cause a VM-exit depending on the "CR3 store exiting" control.
10392 * CR8 reads cause a VM-exit depending on the "CR8 store exiting" control.
10393 */
10394 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
10395 if ( iCrReg == 3
10396 || iCrReg == 8)
10397 {
10398 static const uint32_t s_auCrXReadIntercepts[] = { 0, 0, 0, VMX_PROC_CTLS_CR3_STORE_EXIT, 0,
10399 0, 0, 0, VMX_PROC_CTLS_CR8_STORE_EXIT };
10400 uint32_t const uIntercept = s_auCrXReadIntercepts[iCrReg];
10401 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, uIntercept))
10402 {
10403 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_FROM_TRANSIENT(pVmxTransient);
10404 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
10405 }
10406 else
10407 {
10408 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
10409 rcStrict = vmxHCExitMovFromCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
10410 }
10411 }
10412 else
10413 {
10414 AssertMsgFailed(("MOV from CR%d VM-exit must not happen\n", iCrReg));
10415 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, iCrReg);
10416 }
10417 break;
10418 }
10419
10420 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
10421 {
10422 PCVMXVVMCS const pVmcsNstGst = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
10423 uint64_t const uGstHostMask = pVmcsNstGst->u64Cr0Mask.u;
10424 uint64_t const uReadShadow = pVmcsNstGst->u64Cr0ReadShadow.u;
10425 if ( (uGstHostMask & X86_CR0_TS)
10426 && (uReadShadow & X86_CR0_TS))
10427 {
10428 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_FROM_TRANSIENT(pVmxTransient);
10429 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
10430 }
10431 else
10432 rcStrict = vmxHCExitClts(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr);
10433 break;
10434 }
10435
10436 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
10437 {
10438 RTGCPTR GCPtrEffDst;
10439 uint16_t const uNewMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(pVmxTransient->uExitQual);
10440 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(pVmxTransient->uExitQual);
10441 if (fMemOperand)
10442 {
10443 vmxHCReadToTransient<HMVMX_READ_GUEST_LINEAR_ADDR>(pVCpu, pVmxTransient);
10444 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
10445 }
10446 else
10447 GCPtrEffDst = NIL_RTGCPTR;
10448
10449 if (CPUMIsGuestVmxLmswInterceptSet(&pVCpu->cpum.GstCtx, uNewMsw))
10450 {
10451 VMXVEXITINFO ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_FROM_TRANSIENT(pVmxTransient);
10452 ExitInfo.u64GuestLinearAddr = GCPtrEffDst;
10453 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
10454 }
10455 else
10456 rcStrict = vmxHCExitLmsw(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, uNewMsw, GCPtrEffDst);
10457 break;
10458 }
10459
10460 default:
10461 {
10462 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
10463 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
10464 }
10465 }
10466
10467 if (rcStrict == VINF_IEM_RAISED_XCPT)
10468 {
10469 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
10470 rcStrict = VINF_SUCCESS;
10471 }
10472 return rcStrict;
10473}
10474
10475
10476/**
10477 * Nested-guest VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX).
10478 * Conditional VM-exit.
10479 */
10480HMVMX_EXIT_DECL vmxHCExitMovDRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10481{
10482 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10483
10484 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MOV_DR_EXIT))
10485 {
10486 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
10487 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10488 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_FROM_TRANSIENT(pVmxTransient);
10489 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
10490 }
10491 return vmxHCExitMovDRx(pVCpu, pVmxTransient);
10492}
10493
10494
10495/**
10496 * Nested-guest VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR).
10497 * Conditional VM-exit.
10498 */
10499HMVMX_EXIT_DECL vmxHCExitIoInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10500{
10501 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10502
10503 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
10504
10505 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
10506 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
10507 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
10508
10509 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
10510 uint8_t const cbAccess = s_aIOSizes[uIOSize];
10511 if (CPUMIsGuestVmxIoInterceptSet(pVCpu, uIOPort, cbAccess))
10512 {
10513 /*
10514 * IN/OUT instruction:
10515 * - Provides VM-exit instruction length.
10516 *
10517 * INS/OUTS instruction:
10518 * - Provides VM-exit instruction length.
10519 * - Provides Guest-linear address.
10520 * - Optionally provides VM-exit instruction info (depends on CPU feature).
10521 */
10522 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10523 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10524
10525 /* Make sure we don't use stale/uninitialized VMX-transient info. below. */
10526 pVmxTransient->ExitInstrInfo.u = 0;
10527 pVmxTransient->uGuestLinearAddr = 0;
10528
10529 bool const fVmxInsOutsInfo = pVM->cpum.ro.GuestFeatures.fVmxInsOutInfo;
10530 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
10531 if (fIOString)
10532 {
10533 vmxHCReadToTransient<HMVMX_READ_GUEST_LINEAR_ADDR>(pVCpu, pVmxTransient);
10534 if (fVmxInsOutsInfo)
10535 {
10536 Assert(RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS)); /* Paranoia. */
10537 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_INFO>(pVCpu, pVmxTransient);
10538 }
10539 }
10540
10541 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_AND_LIN_ADDR_FROM_TRANSIENT(pVmxTransient);
10542 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
10543 }
10544 return vmxHCExitIoInstr(pVCpu, pVmxTransient);
10545}
10546
10547
10548/**
10549 * Nested-guest VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
10550 */
10551HMVMX_EXIT_DECL vmxHCExitRdmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10552{
10553 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10554
10555 uint32_t fMsrpm;
10556 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
10557 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap, pVCpu->cpum.GstCtx.ecx);
10558 else
10559 fMsrpm = VMXMSRPM_EXIT_RD;
10560
10561 if (fMsrpm & VMXMSRPM_EXIT_RD)
10562 {
10563 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10564 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
10565 }
10566 return vmxHCExitRdmsr(pVCpu, pVmxTransient);
10567}
10568
10569
10570/**
10571 * Nested-guest VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
10572 */
10573HMVMX_EXIT_DECL vmxHCExitWrmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10574{
10575 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10576
10577 uint32_t fMsrpm;
10578 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
10579 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap, pVCpu->cpum.GstCtx.ecx);
10580 else
10581 fMsrpm = VMXMSRPM_EXIT_WR;
10582
10583 if (fMsrpm & VMXMSRPM_EXIT_WR)
10584 {
10585 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10586 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
10587 }
10588 return vmxHCExitWrmsr(pVCpu, pVmxTransient);
10589}
10590
10591
10592/**
10593 * Nested-guest VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
10594 */
10595HMVMX_EXIT_DECL vmxHCExitMwaitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10596{
10597 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10598
10599 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MWAIT_EXIT))
10600 {
10601 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10602 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
10603 }
10604 return vmxHCExitMwait(pVCpu, pVmxTransient);
10605}
10606
10607
10608/**
10609 * Nested-guest VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional
10610 * VM-exit.
10611 */
10612HMVMX_EXIT_DECL vmxHCExitMtfNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10613{
10614 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10615
10616 /** @todo NSTVMX: Should consider debugging nested-guests using VM debugger. */
10617 vmxHCReadToTransient<HMVMX_READ_GUEST_PENDING_DBG_XCPTS>(pVCpu, pVmxTransient);
10618 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_DBG_XCPTS_FROM_TRANSIENT(pVmxTransient);
10619 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
10620}
10621
10622
10623/**
10624 * Nested-guest VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
10625 */
10626HMVMX_EXIT_DECL vmxHCExitMonitorNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10627{
10628 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10629
10630 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MONITOR_EXIT))
10631 {
10632 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10633 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
10634 }
10635 return vmxHCExitMonitor(pVCpu, pVmxTransient);
10636}
10637
10638
10639/**
10640 * Nested-guest VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
10641 */
10642HMVMX_EXIT_DECL vmxHCExitPauseNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10643{
10644 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10645
10646 /** @todo NSTVMX: Think about this more. Does the outer guest need to intercept
10647 * PAUSE when executing a nested-guest? If it does not, we would not need
10648 * to check for the intercepts here. Just call VM-exit... */
10649
10650 /* The CPU would have already performed the necessary CPL checks for PAUSE-loop exiting. */
10651 if ( CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_PAUSE_EXIT)
10652 || CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
10653 {
10654 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10655 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
10656 }
10657 return vmxHCExitPause(pVCpu, pVmxTransient);
10658}
10659
10660
10661/**
10662 * Nested-guest VM-exit handler for when the TPR value is lowered below the
10663 * specified threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
10664 */
10665HMVMX_EXIT_NSRC_DECL vmxHCExitTprBelowThresholdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10666{
10667 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10668
10669 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_TPR_SHADOW))
10670 {
10671 vmxHCReadToTransient<HMVMX_READ_GUEST_PENDING_DBG_XCPTS>(pVCpu, pVmxTransient);
10672 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_DBG_XCPTS_FROM_TRANSIENT(pVmxTransient);
10673 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
10674 }
10675 return vmxHCExitTprBelowThreshold(pVCpu, pVmxTransient);
10676}
10677
10678
10679/**
10680 * Nested-guest VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional
10681 * VM-exit.
10682 */
10683HMVMX_EXIT_DECL vmxHCExitApicAccessNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10684{
10685 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10686
10687 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
10688 | HMVMX_READ_EXIT_INSTR_LEN
10689 | HMVMX_READ_IDT_VECTORING_INFO
10690 | HMVMX_READ_IDT_VECTORING_ERROR_CODE>(pVCpu, pVmxTransient);
10691
10692 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
10693
10694 Log4Func(("at offset %#x type=%u\n", VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual),
10695 VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual)));
10696
10697 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_FROM_TRANSIENT(pVmxTransient);
10698 VMXVEXITEVENTINFO const ExitEventInfo = VMXVEXITEVENTINFO_INIT_ONLY_IDT(pVmxTransient->uIdtVectoringInfo,
10699 pVmxTransient->uIdtVectoringErrorCode);
10700 return IEMExecVmxVmexitApicAccess(pVCpu, &ExitInfo, &ExitEventInfo);
10701}
10702
10703
10704/**
10705 * Nested-guest VM-exit handler for APIC write emulation (VMX_EXIT_APIC_WRITE).
10706 * Conditional VM-exit.
10707 */
10708HMVMX_EXIT_DECL vmxHCExitApicWriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10709{
10710 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10711
10712 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_APIC_REG_VIRT));
10713 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
10714 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
10715}
10716
10717
10718/**
10719 * Nested-guest VM-exit handler for virtualized EOI (VMX_EXIT_VIRTUALIZED_EOI).
10720 * Conditional VM-exit.
10721 */
10722HMVMX_EXIT_DECL vmxHCExitVirtEoiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10723{
10724 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10725
10726 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_INT_DELIVERY));
10727 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
10728 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
10729}
10730
10731
10732/**
10733 * Nested-guest VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
10734 */
10735HMVMX_EXIT_DECL vmxHCExitRdtscpNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10736{
10737 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10738
10739 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
10740 {
10741 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_RDTSCP));
10742 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10743 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
10744 }
10745 return vmxHCExitRdtscp(pVCpu, pVmxTransient);
10746}
10747
10748
10749/**
10750 * Nested-guest VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
10751 */
10752HMVMX_EXIT_NSRC_DECL vmxHCExitWbinvdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10753{
10754 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10755
10756 if (CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_WBINVD_EXIT))
10757 {
10758 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10759 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
10760 }
10761 return vmxHCExitWbinvd(pVCpu, pVmxTransient);
10762}
10763
10764
10765/**
10766 * Nested-guest VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
10767 */
10768HMVMX_EXIT_DECL vmxHCExitInvpcidNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10769{
10770 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10771
10772 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
10773 {
10774 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_INVPCID));
10775 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
10776 | HMVMX_READ_EXIT_INSTR_INFO
10777 | HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10778 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(pVmxTransient);
10779 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
10780 }
10781 return vmxHCExitInvpcid(pVCpu, pVmxTransient);
10782}
10783
10784
10785/**
10786 * Nested-guest VM-exit handler for invalid-guest state
10787 * (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error VM-exit.
10788 */
10789HMVMX_EXIT_DECL vmxHCExitErrInvalidGuestStateNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10790{
10791 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10792
10793 /*
10794 * Currently this should never happen because we fully emulate VMLAUNCH/VMRESUME in IEM.
10795 * So if it does happen, it indicates a bug possibly in the hardware-assisted VMX code.
10796 * Handle it like it's in an invalid guest state of the outer guest.
10797 *
10798 * When the fast path is implemented, this should be changed to cause the corresponding
10799 * nested-guest VM-exit.
10800 */
10801 return vmxHCExitErrInvalidGuestState(pVCpu, pVmxTransient);
10802}
10803
10804
10805/**
10806 * Nested-guest VM-exit handler for instructions that cause VM-exits unconditionally
10807 * and only provide the instruction length.
10808 *
10809 * Unconditional VM-exit.
10810 */
10811HMVMX_EXIT_DECL vmxHCExitInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10812{
10813 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10814
10815#ifdef VBOX_STRICT
10816 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
10817 switch (pVmxTransient->uExitReason)
10818 {
10819 case VMX_EXIT_ENCLS:
10820 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_ENCLS_EXIT));
10821 break;
10822
10823 case VMX_EXIT_VMFUNC:
10824 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_VMFUNC));
10825 break;
10826 }
10827#endif
10828
10829 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_LEN>(pVCpu, pVmxTransient);
10830 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
10831}
10832
10833
10834/**
10835 * Nested-guest VM-exit handler for instructions that provide instruction length as
10836 * well as more information.
10837 *
10838 * Unconditional VM-exit.
10839 */
10840HMVMX_EXIT_DECL vmxHCExitInstrWithInfoNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10841{
10842 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10843
10844# ifdef VBOX_STRICT
10845 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
10846 switch (pVmxTransient->uExitReason)
10847 {
10848 case VMX_EXIT_GDTR_IDTR_ACCESS:
10849 case VMX_EXIT_LDTR_TR_ACCESS:
10850 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_DESC_TABLE_EXIT));
10851 break;
10852
10853 case VMX_EXIT_RDRAND:
10854 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_RDRAND_EXIT));
10855 break;
10856
10857 case VMX_EXIT_RDSEED:
10858 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_RDSEED_EXIT));
10859 break;
10860
10861 case VMX_EXIT_XSAVES:
10862 case VMX_EXIT_XRSTORS:
10863 /** @todo NSTVMX: Verify XSS-bitmap. */
10864 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_XSAVES_XRSTORS));
10865 break;
10866
10867 case VMX_EXIT_UMWAIT:
10868 case VMX_EXIT_TPAUSE:
10869 Assert(CPUMIsGuestVmxProcCtlsSet(pCtx, VMX_PROC_CTLS_RDTSC_EXIT));
10870 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_USER_WAIT_PAUSE));
10871 break;
10872
10873 case VMX_EXIT_LOADIWKEY:
10874 Assert(CPUMIsGuestVmxProcCtls3Set(pCtx, VMX_PROC_CTLS3_LOADIWKEY_EXIT));
10875 break;
10876 }
10877# endif
10878
10879 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
10880 | HMVMX_READ_EXIT_INSTR_LEN
10881 | HMVMX_READ_EXIT_INSTR_INFO>(pVCpu, pVmxTransient);
10882 VMXVEXITINFO const ExitInfo = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(pVmxTransient);
10883 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
10884}
10885
10886# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
10887
10888/**
10889 * Nested-guest VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION).
10890 * Conditional VM-exit.
10891 */
10892HMVMX_EXIT_DECL vmxHCExitEptViolationNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10893{
10894 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10895 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
10896
10897 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10898 if (CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_EPT))
10899 {
10900 vmxHCReadToTransient< HMVMX_READ_EXIT_QUALIFICATION
10901 | HMVMX_READ_EXIT_INSTR_LEN
10902 | HMVMX_READ_EXIT_INTERRUPTION_INFO
10903 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
10904 | HMVMX_READ_IDT_VECTORING_INFO
10905 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
10906 | HMVMX_READ_GUEST_PHYSICAL_ADDR>(pVCpu, pVmxTransient);
10907 int rc = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmcsInfo, __FUNCTION__);
10908 AssertRCReturn(rc, rc);
10909
10910 /*
10911 * If it's our VMEXIT, we're responsible for re-injecting any event which delivery
10912 * might have triggered this VMEXIT. If we forward the problem to the inner VMM,
10913 * it's its problem to deal with that issue and we'll clear the recovered event.
10914 */
10915 VBOXSTRICTRC rcStrict = vmxHCCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
10916 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10917 { /*likely*/ }
10918 else
10919 {
10920 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
10921 return rcStrict;
10922 }
10923 uint32_t const fClearEventOnForward = VCPU_2_VMXSTATE(pVCpu).Event.fPending; /* paranoia. should not inject events below. */
10924
10925 RTGCPHYS const GCPhysNestedFault = pVmxTransient->uGuestPhysicalAddr;
10926 uint64_t const uExitQual = pVmxTransient->uExitQual;
10927
10928 RTGCPTR GCPtrNestedFault;
10929 bool const fIsLinearAddrValid = RT_BOOL(uExitQual & VMX_EXIT_QUAL_EPT_LINEAR_ADDR_VALID);
10930 if (fIsLinearAddrValid)
10931 {
10932 vmxHCReadToTransient<HMVMX_READ_GUEST_LINEAR_ADDR>(pVCpu, pVmxTransient);
10933 GCPtrNestedFault = pVmxTransient->uGuestLinearAddr;
10934 }
10935 else
10936 GCPtrNestedFault = 0;
10937
10938 RTGCUINT const uErr = ((uExitQual & VMX_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH) ? X86_TRAP_PF_ID : 0)
10939 | ((uExitQual & VMX_EXIT_QUAL_EPT_ACCESS_WRITE) ? X86_TRAP_PF_RW : 0)
10940 | ((uExitQual & ( VMX_EXIT_QUAL_EPT_ENTRY_READ
10941 | VMX_EXIT_QUAL_EPT_ENTRY_WRITE
10942 | VMX_EXIT_QUAL_EPT_ENTRY_EXECUTE)) ? X86_TRAP_PF_P : 0);
10943
10944 PGMPTWALK Walk;
10945 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
10946 rcStrict = PGMR0NestedTrap0eHandlerNestedPaging(pVCpu, PGMMODE_EPT, uErr, pCtx, GCPhysNestedFault,
10947 fIsLinearAddrValid, GCPtrNestedFault, &Walk);
10948 Log7Func(("PGM (uExitQual=%#RX64, %RGp, %RGv) -> %Rrc (fFailed=%d)\n",
10949 uExitQual, GCPhysNestedFault, GCPtrNestedFault, VBOXSTRICTRC_VAL(rcStrict), Walk.fFailed));
10950 if (RT_SUCCESS(rcStrict))
10951 {
10952 if (rcStrict == VINF_IOM_R3_MMIO_COMMIT_WRITE)
10953 {
10954 Assert(!fClearEventOnForward);
10955 Assert(VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_IOM));
10956 rcStrict = VINF_EM_RESCHEDULE_REM;
10957 }
10958 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_ALL_GUEST);
10959 return rcStrict;
10960 }
10961
10962 if (fClearEventOnForward)
10963 VCPU_2_VMXSTATE(pVCpu).Event.fPending = false;
10964
10965 VMXVEXITEVENTINFO const ExitEventInfo = VMXVEXITEVENTINFO_INIT_ONLY_IDT(pVmxTransient->uIdtVectoringInfo,
10966 pVmxTransient->uIdtVectoringErrorCode);
10967 if (Walk.fFailed & PGM_WALKFAIL_EPT_VIOLATION)
10968 {
10969 VMXVEXITINFO const ExitInfo
10970 = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_AND_GST_ADDRESSES(VMX_EXIT_EPT_VIOLATION,
10971 pVmxTransient->uExitQual,
10972 pVmxTransient->cbExitInstr,
10973 pVmxTransient->uGuestLinearAddr,
10974 pVmxTransient->uGuestPhysicalAddr);
10975 return IEMExecVmxVmexitEptViolation(pVCpu, &ExitInfo, &ExitEventInfo);
10976 }
10977
10978 AssertMsgReturn(Walk.fFailed & PGM_WALKFAIL_EPT_MISCONFIG,
10979 ("uErr=%#RX32 uExitQual=%#RX64 GCPhysNestedFault=%#RGp GCPtrNestedFault=%#RGv\n",
10980 (uint32_t)uErr, uExitQual, GCPhysNestedFault, GCPtrNestedFault),
10981 rcStrict);
10982 return IEMExecVmxVmexitEptMisconfig(pVCpu, pVmxTransient->uGuestPhysicalAddr, &ExitEventInfo);
10983 }
10984
10985 return vmxHCExitEptViolation(pVCpu, pVmxTransient);
10986}
10987
10988
10989/**
10990 * Nested-guest VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
10991 * Conditional VM-exit.
10992 */
10993HMVMX_EXIT_DECL vmxHCExitEptMisconfigNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10994{
10995 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
10996 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
10997
10998 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10999 if (CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_EPT))
11000 {
11001 vmxHCReadToTransient<HMVMX_READ_GUEST_PHYSICAL_ADDR>(pVCpu, pVmxTransient);
11002 int rc = vmxHCImportGuestState<CPUMCTX_EXTRN_ALL>(pVCpu, pVmcsInfo, __FUNCTION__);
11003 AssertRCReturn(rc, rc);
11004
11005 PGMPTWALK Walk;
11006 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
11007 RTGCPHYS const GCPhysNestedFault = pVmxTransient->uGuestPhysicalAddr;
11008 VBOXSTRICTRC rcStrict = PGMR0NestedTrap0eHandlerNestedPaging(pVCpu, PGMMODE_EPT, X86_TRAP_PF_RSVD, pCtx,
11009 GCPhysNestedFault, false /* fIsLinearAddrValid */,
11010 0 /* GCPtrNestedFault */, &Walk);
11011 if (RT_SUCCESS(rcStrict))
11012 {
11013 AssertMsgFailed(("Shouldn't happen with the way we have programmed the EPT shadow tables\n"));
11014 return rcStrict;
11015 }
11016
11017 AssertMsg(Walk.fFailed & PGM_WALKFAIL_EPT_MISCONFIG, ("GCPhysNestedFault=%#RGp\n", GCPhysNestedFault));
11018 vmxHCReadToTransient< HMVMX_READ_IDT_VECTORING_INFO
11019 | HMVMX_READ_IDT_VECTORING_ERROR_CODE>(pVCpu, pVmxTransient);
11020
11021 VMXVEXITEVENTINFO const ExitEventInfo = VMXVEXITEVENTINFO_INIT_ONLY_IDT(pVmxTransient->uIdtVectoringInfo,
11022 pVmxTransient->uIdtVectoringErrorCode);
11023 return IEMExecVmxVmexitEptMisconfig(pVCpu, pVmxTransient->uGuestPhysicalAddr, &ExitEventInfo);
11024 }
11025
11026 return vmxHCExitEptMisconfig(pVCpu, pVmxTransient);
11027}
11028
11029# endif /* VBOX_WITH_NESTED_HWVIRT_VMX_EPT */
11030
11031/** @} */
11032#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
11033
11034
11035/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
11036 * probes.
11037 *
11038 * The following few functions and associated structure contains the bloat
11039 * necessary for providing detailed debug events and dtrace probes as well as
11040 * reliable host side single stepping. This works on the principle of
11041 * "subclassing" the normal execution loop and workers. We replace the loop
11042 * method completely and override selected helpers to add necessary adjustments
11043 * to their core operation.
11044 *
11045 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
11046 * any performance for debug and analysis features.
11047 *
11048 * @{
11049 */
11050
11051/**
11052 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
11053 * the debug run loop.
11054 */
11055typedef struct VMXRUNDBGSTATE
11056{
11057 /** The RIP we started executing at. This is for detecting that we stepped. */
11058 uint64_t uRipStart;
11059 /** The CS we started executing with. */
11060 uint16_t uCsStart;
11061
11062 /** Whether we've actually modified the 1st execution control field. */
11063 bool fModifiedProcCtls : 1;
11064 /** Whether we've actually modified the 2nd execution control field. */
11065 bool fModifiedProcCtls2 : 1;
11066 /** Whether we've actually modified the exception bitmap. */
11067 bool fModifiedXcptBitmap : 1;
11068
11069 /** We desire the modified the CR0 mask to be cleared. */
11070 bool fClearCr0Mask : 1;
11071 /** We desire the modified the CR4 mask to be cleared. */
11072 bool fClearCr4Mask : 1;
11073 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
11074 uint32_t fCpe1Extra;
11075 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
11076 uint32_t fCpe1Unwanted;
11077 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
11078 uint32_t fCpe2Extra;
11079 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
11080 uint32_t bmXcptExtra;
11081 /** The sequence number of the Dtrace provider settings the state was
11082 * configured against. */
11083 uint32_t uDtraceSettingsSeqNo;
11084 /** VM-exits to check (one bit per VM-exit). */
11085 uint32_t bmExitsToCheck[3];
11086
11087 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
11088 uint32_t fProcCtlsInitial;
11089 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
11090 uint32_t fProcCtls2Initial;
11091 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
11092 uint32_t bmXcptInitial;
11093} VMXRUNDBGSTATE;
11094AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
11095typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
11096
11097
11098/**
11099 * Initializes the VMXRUNDBGSTATE structure.
11100 *
11101 * @param pVCpu The cross context virtual CPU structure of the
11102 * calling EMT.
11103 * @param pVmxTransient The VMX-transient structure.
11104 * @param pDbgState The debug state to initialize.
11105 */
11106static void vmxHCRunDebugStateInit(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11107{
11108 pDbgState->uRipStart = pVCpu->cpum.GstCtx.rip;
11109 pDbgState->uCsStart = pVCpu->cpum.GstCtx.cs.Sel;
11110
11111 pDbgState->fModifiedProcCtls = false;
11112 pDbgState->fModifiedProcCtls2 = false;
11113 pDbgState->fModifiedXcptBitmap = false;
11114 pDbgState->fClearCr0Mask = false;
11115 pDbgState->fClearCr4Mask = false;
11116 pDbgState->fCpe1Extra = 0;
11117 pDbgState->fCpe1Unwanted = 0;
11118 pDbgState->fCpe2Extra = 0;
11119 pDbgState->bmXcptExtra = 0;
11120 pDbgState->fProcCtlsInitial = pVmxTransient->pVmcsInfo->u32ProcCtls;
11121 pDbgState->fProcCtls2Initial = pVmxTransient->pVmcsInfo->u32ProcCtls2;
11122 pDbgState->bmXcptInitial = pVmxTransient->pVmcsInfo->u32XcptBitmap;
11123}
11124
11125
11126/**
11127 * Updates the VMSC fields with changes requested by @a pDbgState.
11128 *
11129 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
11130 * immediately before executing guest code, i.e. when interrupts are disabled.
11131 * We don't check status codes here as we cannot easily assert or return in the
11132 * latter case.
11133 *
11134 * @param pVCpu The cross context virtual CPU structure.
11135 * @param pVmxTransient The VMX-transient structure.
11136 * @param pDbgState The debug state.
11137 */
11138static void vmxHCPreRunGuestDebugStateApply(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11139{
11140 /*
11141 * Ensure desired flags in VMCS control fields are set.
11142 * (Ignoring write failure here, as we're committed and it's just debug extras.)
11143 *
11144 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
11145 * there should be no stale data in pCtx at this point.
11146 */
11147 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11148 if ( (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
11149 || (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Unwanted))
11150 {
11151 pVmcsInfo->u32ProcCtls |= pDbgState->fCpe1Extra;
11152 pVmcsInfo->u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
11153 VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
11154 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVmcsInfo->u32ProcCtls));
11155 pDbgState->fModifiedProcCtls = true;
11156 }
11157
11158 if ((pVmcsInfo->u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
11159 {
11160 pVmcsInfo->u32ProcCtls2 |= pDbgState->fCpe2Extra;
11161 VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC2, pVmcsInfo->u32ProcCtls2);
11162 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVmcsInfo->u32ProcCtls2));
11163 pDbgState->fModifiedProcCtls2 = true;
11164 }
11165
11166 if ((pVmcsInfo->u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
11167 {
11168 pVmcsInfo->u32XcptBitmap |= pDbgState->bmXcptExtra;
11169 VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVmcsInfo->u32XcptBitmap);
11170 Log6Func(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVmcsInfo->u32XcptBitmap));
11171 pDbgState->fModifiedXcptBitmap = true;
11172 }
11173
11174 if (pDbgState->fClearCr0Mask && pVmcsInfo->u64Cr0Mask != 0)
11175 {
11176 pVmcsInfo->u64Cr0Mask = 0;
11177 VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_CTRL_CR0_MASK, 0);
11178 Log6Func(("VMX_VMCS_CTRL_CR0_MASK: 0\n"));
11179 }
11180
11181 if (pDbgState->fClearCr4Mask && pVmcsInfo->u64Cr4Mask != 0)
11182 {
11183 pVmcsInfo->u64Cr4Mask = 0;
11184 VMX_VMCS_WRITE_NW(pVCpu, VMX_VMCS_CTRL_CR4_MASK, 0);
11185 Log6Func(("VMX_VMCS_CTRL_CR4_MASK: 0\n"));
11186 }
11187
11188 NOREF(pVCpu);
11189}
11190
11191
11192/**
11193 * Restores VMCS fields that were changed by hmR0VmxPreRunGuestDebugStateApply for
11194 * re-entry next time around.
11195 *
11196 * @returns Strict VBox status code (i.e. informational status codes too).
11197 * @param pVCpu The cross context virtual CPU structure.
11198 * @param pVmxTransient The VMX-transient structure.
11199 * @param pDbgState The debug state.
11200 * @param rcStrict The return code from executing the guest using single
11201 * stepping.
11202 */
11203static VBOXSTRICTRC vmxHCRunDebugStateRevert(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState,
11204 VBOXSTRICTRC rcStrict)
11205{
11206 /*
11207 * Restore VM-exit control settings as we may not reenter this function the
11208 * next time around.
11209 */
11210 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11211
11212 /* We reload the initial value, trigger what we can of recalculations the
11213 next time around. From the looks of things, that's all that's required atm. */
11214 if (pDbgState->fModifiedProcCtls)
11215 {
11216 if (!(pDbgState->fProcCtlsInitial & VMX_PROC_CTLS_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
11217 pDbgState->fProcCtlsInitial |= VMX_PROC_CTLS_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
11218 int rc2 = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
11219 AssertRC(rc2);
11220 pVmcsInfo->u32ProcCtls = pDbgState->fProcCtlsInitial;
11221 }
11222
11223 /* We're currently the only ones messing with this one, so just restore the
11224 cached value and reload the field. */
11225 if ( pDbgState->fModifiedProcCtls2
11226 && pVmcsInfo->u32ProcCtls2 != pDbgState->fProcCtls2Initial)
11227 {
11228 int rc2 = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
11229 AssertRC(rc2);
11230 pVmcsInfo->u32ProcCtls2 = pDbgState->fProcCtls2Initial;
11231 }
11232
11233 /* If we've modified the exception bitmap, we restore it and trigger
11234 reloading and partial recalculation the next time around. */
11235 if (pDbgState->fModifiedXcptBitmap)
11236 {
11237 int rc2 = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pDbgState->bmXcptInitial);
11238 AssertRC(rc2);
11239 pVmcsInfo->u32XcptBitmap = pDbgState->bmXcptInitial;
11240 }
11241
11242 return rcStrict;
11243}
11244
11245
11246/**
11247 * Configures VM-exit controls for current DBGF and DTrace settings.
11248 *
11249 * This updates @a pDbgState and the VMCS execution control fields to reflect
11250 * the necessary VM-exits demanded by DBGF and DTrace.
11251 *
11252 * @param pVCpu The cross context virtual CPU structure.
11253 * @param pVmxTransient The VMX-transient structure. May update
11254 * fUpdatedTscOffsettingAndPreemptTimer.
11255 * @param pDbgState The debug state.
11256 */
11257static void vmxHCPreRunGuestDebugStateUpdate(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11258{
11259#ifndef IN_NEM_DARWIN
11260 /*
11261 * Take down the dtrace serial number so we can spot changes.
11262 */
11263 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
11264 ASMCompilerBarrier();
11265#endif
11266
11267 /*
11268 * We'll rebuild most of the middle block of data members (holding the
11269 * current settings) as we go along here, so start by clearing it all.
11270 */
11271 pDbgState->bmXcptExtra = 0;
11272 pDbgState->fCpe1Extra = 0;
11273 pDbgState->fCpe1Unwanted = 0;
11274 pDbgState->fCpe2Extra = 0;
11275 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
11276 pDbgState->bmExitsToCheck[i] = 0;
11277
11278 /*
11279 * Software interrupts (INT XXh) - no idea how to trigger these...
11280 */
11281 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11282 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
11283 || VBOXVMM_INT_SOFTWARE_ENABLED())
11284 {
11285 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11286 }
11287
11288 /*
11289 * INT3 breakpoints - triggered by #BP exceptions.
11290 */
11291 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
11292 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11293
11294 /*
11295 * Exception bitmap and XCPT events+probes.
11296 */
11297 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
11298 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
11299 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
11300
11301 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
11302 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
11303 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11304 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
11305 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
11306 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
11307 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
11308 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
11309 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
11310 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
11311 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
11312 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
11313 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
11314 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
11315 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
11316 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
11317 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
11318 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
11319
11320 if (pDbgState->bmXcptExtra)
11321 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11322
11323 /*
11324 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
11325 *
11326 * Note! This is the reverse of what hmR0VmxHandleExitDtraceEvents does.
11327 * So, when adding/changing/removing please don't forget to update it.
11328 *
11329 * Some of the macros are picking up local variables to save horizontal space,
11330 * (being able to see it in a table is the lesser evil here).
11331 */
11332#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
11333 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
11334 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
11335#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
11336 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11337 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11338 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11339 } else do { } while (0)
11340#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
11341 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11342 { \
11343 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
11344 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11345 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11346 } else do { } while (0)
11347#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
11348 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11349 { \
11350 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
11351 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11352 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11353 } else do { } while (0)
11354#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
11355 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11356 { \
11357 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
11358 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11359 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11360 } else do { } while (0)
11361
11362 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
11363 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
11364 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
11365 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
11366 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
11367
11368 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
11369 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
11370 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
11371 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
11372 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_PROC_CTLS_HLT_EXIT); /* paranoia */
11373 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
11374 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
11375 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
11376 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_PROC_CTLS_INVLPG_EXIT);
11377 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
11378 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_PROC_CTLS_RDPMC_EXIT);
11379 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
11380 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_PROC_CTLS_RDTSC_EXIT);
11381 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
11382 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
11383 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
11384 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
11385 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
11386 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
11387 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
11388 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
11389 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
11390 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
11391 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
11392 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
11393 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
11394 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
11395 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
11396 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
11397 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
11398 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
11399 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
11400 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
11401 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
11402 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
11403 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
11404
11405 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
11406 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11407 {
11408 int rc = vmxHCImportGuestStateEx(pVCpu, pVmxTransient->pVmcsInfo,
11409 CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_APIC_TPR);
11410 AssertRC(rc);
11411
11412#if 0 /** @todo fix me */
11413 pDbgState->fClearCr0Mask = true;
11414 pDbgState->fClearCr4Mask = true;
11415#endif
11416 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
11417 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_STORE_EXIT | VMX_PROC_CTLS_CR8_STORE_EXIT;
11418 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11419 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_LOAD_EXIT | VMX_PROC_CTLS_CR8_LOAD_EXIT;
11420 pDbgState->fCpe1Unwanted |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* risky? */
11421 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
11422 require clearing here and in the loop if we start using it. */
11423 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
11424 }
11425 else
11426 {
11427 if (pDbgState->fClearCr0Mask)
11428 {
11429 pDbgState->fClearCr0Mask = false;
11430 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_CR0);
11431 }
11432 if (pDbgState->fClearCr4Mask)
11433 {
11434 pDbgState->fClearCr4Mask = false;
11435 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_CR4);
11436 }
11437 }
11438 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
11439 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
11440
11441 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
11442 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
11443 {
11444 /** @todo later, need to fix handler as it assumes this won't usually happen. */
11445 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
11446 }
11447 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
11448 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
11449
11450 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS); /* risky clearing this? */
11451 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
11452 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS);
11453 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
11454 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_PROC_CTLS_MWAIT_EXIT); /* paranoia */
11455 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
11456 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_PROC_CTLS_MONITOR_EXIT); /* paranoia */
11457 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
11458#if 0 /** @todo too slow, fix handler. */
11459 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_PROC_CTLS_PAUSE_EXIT);
11460#endif
11461 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
11462
11463 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
11464 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
11465 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
11466 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
11467 {
11468 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11469 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_GDTR_IDTR_ACCESS);
11470 }
11471 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11472 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11473 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11474 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11475
11476 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
11477 || IS_EITHER_ENABLED(pVM, INSTR_STR)
11478 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
11479 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
11480 {
11481 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11482 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_LDTR_TR_ACCESS);
11483 }
11484 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_LDTR_TR_ACCESS);
11485 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_LDTR_TR_ACCESS);
11486 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_LDTR_TR_ACCESS);
11487 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_LDTR_TR_ACCESS);
11488
11489 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
11490 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
11491 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_PROC_CTLS_RDTSC_EXIT);
11492 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
11493 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
11494 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
11495 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_PROC_CTLS2_WBINVD_EXIT);
11496 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
11497 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
11498 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
11499 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_PROC_CTLS2_RDRAND_EXIT);
11500 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
11501 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_PROC_CTLS_INVLPG_EXIT);
11502 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
11503 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
11504 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
11505 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_PROC_CTLS2_RDSEED_EXIT);
11506 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
11507 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
11508 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
11509 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
11510 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
11511
11512#undef IS_EITHER_ENABLED
11513#undef SET_ONLY_XBM_IF_EITHER_EN
11514#undef SET_CPE1_XBM_IF_EITHER_EN
11515#undef SET_CPEU_XBM_IF_EITHER_EN
11516#undef SET_CPE2_XBM_IF_EITHER_EN
11517
11518 /*
11519 * Sanitize the control stuff.
11520 */
11521 pDbgState->fCpe2Extra &= g_HmMsrs.u.vmx.ProcCtls2.n.allowed1;
11522 if (pDbgState->fCpe2Extra)
11523 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
11524 pDbgState->fCpe1Extra &= g_HmMsrs.u.vmx.ProcCtls.n.allowed1;
11525 pDbgState->fCpe1Unwanted &= ~g_HmMsrs.u.vmx.ProcCtls.n.allowed0;
11526#ifndef IN_NEM_DARWIN
11527 if (pVCpu->hmr0.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_PROC_CTLS_RDTSC_EXIT))
11528 {
11529 pVCpu->hmr0.s.fDebugWantRdTscExit ^= true;
11530 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
11531 }
11532#else
11533 if (pVCpu->nem.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_PROC_CTLS_RDTSC_EXIT))
11534 {
11535 pVCpu->nem.s.fDebugWantRdTscExit ^= true;
11536 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
11537 }
11538#endif
11539
11540 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
11541 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
11542 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
11543 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
11544}
11545
11546
11547/**
11548 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
11549 * appropriate.
11550 *
11551 * The caller has checked the VM-exit against the
11552 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
11553 * already, so we don't have to do that either.
11554 *
11555 * @returns Strict VBox status code (i.e. informational status codes too).
11556 * @param pVCpu The cross context virtual CPU structure.
11557 * @param pVmxTransient The VMX-transient structure.
11558 * @param uExitReason The VM-exit reason.
11559 *
11560 * @remarks The name of this function is displayed by dtrace, so keep it short
11561 * and to the point. No longer than 33 chars long, please.
11562 */
11563static VBOXSTRICTRC vmxHCHandleExitDtraceEvents(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
11564{
11565 /*
11566 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
11567 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
11568 *
11569 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
11570 * does. Must add/change/remove both places. Same ordering, please.
11571 *
11572 * Added/removed events must also be reflected in the next section
11573 * where we dispatch dtrace events.
11574 */
11575 bool fDtrace1 = false;
11576 bool fDtrace2 = false;
11577 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
11578 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
11579 uint32_t uEventArg = 0;
11580#define SET_EXIT(a_EventSubName) \
11581 do { \
11582 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11583 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11584 } while (0)
11585#define SET_BOTH(a_EventSubName) \
11586 do { \
11587 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
11588 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
11589 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
11590 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
11591 } while (0)
11592 switch (uExitReason)
11593 {
11594 case VMX_EXIT_MTF:
11595 return vmxHCExitMtf(pVCpu, pVmxTransient);
11596
11597 case VMX_EXIT_XCPT_OR_NMI:
11598 {
11599 uint8_t const idxVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
11600 switch (VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo))
11601 {
11602 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
11603 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
11604 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
11605 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
11606 {
11607 if (VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uExitIntInfo))
11608 {
11609 vmxHCReadToTransient<HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE>(pVCpu, pVmxTransient);
11610 uEventArg = pVmxTransient->uExitIntErrorCode;
11611 }
11612 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
11613 switch (enmEvent1)
11614 {
11615 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
11616 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
11617 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
11618 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
11619 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
11620 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
11621 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
11622 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
11623 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
11624 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
11625 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
11626 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
11627 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
11628 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
11629 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
11630 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
11631 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
11632 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
11633 default: break;
11634 }
11635 }
11636 else
11637 AssertFailed();
11638 break;
11639
11640 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
11641 uEventArg = idxVector;
11642 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
11643 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
11644 break;
11645 }
11646 break;
11647 }
11648
11649 case VMX_EXIT_TRIPLE_FAULT:
11650 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
11651 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
11652 break;
11653 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
11654 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
11655 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
11656 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
11657 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
11658
11659 /* Instruction specific VM-exits: */
11660 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
11661 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
11662 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
11663 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
11664 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
11665 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
11666 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
11667 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
11668 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
11669 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
11670 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
11671 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
11672 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
11673 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
11674 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
11675 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
11676 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
11677 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
11678 case VMX_EXIT_MOV_CRX:
11679 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
11680 if (VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_CRX_ACCESS_READ)
11681 SET_BOTH(CRX_READ);
11682 else
11683 SET_BOTH(CRX_WRITE);
11684 uEventArg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
11685 break;
11686 case VMX_EXIT_MOV_DRX:
11687 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
11688 if ( VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual)
11689 == VMX_EXIT_QUAL_DRX_DIRECTION_READ)
11690 SET_BOTH(DRX_READ);
11691 else
11692 SET_BOTH(DRX_WRITE);
11693 uEventArg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
11694 break;
11695 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
11696 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
11697 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
11698 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
11699 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
11700 case VMX_EXIT_GDTR_IDTR_ACCESS:
11701 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_INFO>(pVCpu, pVmxTransient);
11702 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_XDTR_INSINFO_INSTR_ID))
11703 {
11704 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
11705 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
11706 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
11707 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
11708 }
11709 break;
11710
11711 case VMX_EXIT_LDTR_TR_ACCESS:
11712 vmxHCReadToTransient<HMVMX_READ_EXIT_INSTR_INFO>(pVCpu, pVmxTransient);
11713 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_YYTR_INSINFO_INSTR_ID))
11714 {
11715 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
11716 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
11717 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
11718 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
11719 }
11720 break;
11721
11722 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
11723 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
11724 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
11725 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
11726 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
11727 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
11728 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
11729 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
11730 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
11731 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
11732 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
11733
11734 /* Events that aren't relevant at this point. */
11735 case VMX_EXIT_EXT_INT:
11736 case VMX_EXIT_INT_WINDOW:
11737 case VMX_EXIT_NMI_WINDOW:
11738 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11739 case VMX_EXIT_PREEMPT_TIMER:
11740 case VMX_EXIT_IO_INSTR:
11741 break;
11742
11743 /* Errors and unexpected events. */
11744 case VMX_EXIT_INIT_SIGNAL:
11745 case VMX_EXIT_SIPI:
11746 case VMX_EXIT_IO_SMI:
11747 case VMX_EXIT_SMI:
11748 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
11749 case VMX_EXIT_ERR_MSR_LOAD:
11750 case VMX_EXIT_ERR_MACHINE_CHECK:
11751 case VMX_EXIT_PML_FULL:
11752 case VMX_EXIT_VIRTUALIZED_EOI:
11753 break;
11754
11755 default:
11756 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
11757 break;
11758 }
11759#undef SET_BOTH
11760#undef SET_EXIT
11761
11762 /*
11763 * Dtrace tracepoints go first. We do them here at once so we don't
11764 * have to copy the guest state saving and stuff a few dozen times.
11765 * Down side is that we've got to repeat the switch, though this time
11766 * we use enmEvent since the probes are a subset of what DBGF does.
11767 */
11768 if (fDtrace1 || fDtrace2)
11769 {
11770 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
11771 vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
11772 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx; RT_NOREF(pCtx); /* Shut up Clang 13. */
11773 switch (enmEvent1)
11774 {
11775 /** @todo consider which extra parameters would be helpful for each probe. */
11776 case DBGFEVENT_END: break;
11777 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pCtx); break;
11778 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pCtx, pCtx->dr[6]); break;
11779 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pCtx); break;
11780 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pCtx); break;
11781 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pCtx); break;
11782 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pCtx); break;
11783 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pCtx); break;
11784 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pCtx); break;
11785 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pCtx, uEventArg); break;
11786 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pCtx, uEventArg); break;
11787 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pCtx, uEventArg); break;
11788 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pCtx, uEventArg); break;
11789 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pCtx, uEventArg, pCtx->cr2); break;
11790 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pCtx); break;
11791 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pCtx); break;
11792 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pCtx); break;
11793 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pCtx); break;
11794 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pCtx, uEventArg); break;
11795 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11796 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11797 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pCtx); break;
11798 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pCtx); break;
11799 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pCtx); break;
11800 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pCtx); break;
11801 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pCtx); break;
11802 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pCtx); break;
11803 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pCtx); break;
11804 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11805 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11806 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11807 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11808 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11809 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pCtx, pCtx->ecx,
11810 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11811 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pCtx); break;
11812 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pCtx); break;
11813 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pCtx); break;
11814 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pCtx); break;
11815 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pCtx); break;
11816 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pCtx); break;
11817 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pCtx); break;
11818 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pCtx); break;
11819 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pCtx); break;
11820 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pCtx); break;
11821 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pCtx); break;
11822 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pCtx); break;
11823 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pCtx); break;
11824 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pCtx); break;
11825 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pCtx); break;
11826 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pCtx); break;
11827 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pCtx); break;
11828 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pCtx); break;
11829 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pCtx); break;
11830 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pCtx); break;
11831 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pCtx); break;
11832 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pCtx); break;
11833 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pCtx); break;
11834 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pCtx); break;
11835 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pCtx); break;
11836 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pCtx); break;
11837 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pCtx); break;
11838 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pCtx); break;
11839 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pCtx); break;
11840 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pCtx); break;
11841 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pCtx); break;
11842 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pCtx); break;
11843 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
11844 }
11845 switch (enmEvent2)
11846 {
11847 /** @todo consider which extra parameters would be helpful for each probe. */
11848 case DBGFEVENT_END: break;
11849 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pCtx); break;
11850 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
11851 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pCtx); break;
11852 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pCtx); break;
11853 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pCtx); break;
11854 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pCtx); break;
11855 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pCtx); break;
11856 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pCtx); break;
11857 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pCtx); break;
11858 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11859 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11860 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
11861 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
11862 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
11863 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pCtx, pCtx->ecx,
11864 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
11865 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pCtx); break;
11866 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pCtx); break;
11867 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pCtx); break;
11868 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pCtx); break;
11869 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pCtx); break;
11870 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pCtx); break;
11871 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pCtx); break;
11872 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pCtx); break;
11873 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pCtx); break;
11874 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pCtx); break;
11875 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pCtx); break;
11876 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pCtx); break;
11877 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pCtx); break;
11878 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pCtx); break;
11879 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pCtx); break;
11880 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pCtx); break;
11881 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pCtx); break;
11882 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pCtx); break;
11883 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pCtx); break;
11884 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pCtx); break;
11885 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pCtx); break;
11886 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pCtx); break;
11887 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pCtx); break;
11888 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pCtx); break;
11889 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pCtx); break;
11890 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pCtx); break;
11891 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pCtx); break;
11892 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pCtx); break;
11893 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pCtx); break;
11894 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pCtx); break;
11895 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pCtx); break;
11896 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pCtx); break;
11897 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pCtx); break;
11898 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pCtx); break;
11899 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pCtx); break;
11900 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pCtx); break;
11901 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
11902 }
11903 }
11904
11905 /*
11906 * Fire of the DBGF event, if enabled (our check here is just a quick one,
11907 * the DBGF call will do a full check).
11908 *
11909 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
11910 * Note! If we have to events, we prioritize the first, i.e. the instruction
11911 * one, in order to avoid event nesting.
11912 */
11913 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11914 if ( enmEvent1 != DBGFEVENT_END
11915 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
11916 {
11917 vmxHCImportGuestState<CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
11918 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent1, DBGFEVENTCTX_HM, 1, uEventArg);
11919 if (rcStrict != VINF_SUCCESS)
11920 return rcStrict;
11921 }
11922 else if ( enmEvent2 != DBGFEVENT_END
11923 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
11924 {
11925 vmxHCImportGuestState<CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
11926 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent2, DBGFEVENTCTX_HM, 1, uEventArg);
11927 if (rcStrict != VINF_SUCCESS)
11928 return rcStrict;
11929 }
11930
11931 return VINF_SUCCESS;
11932}
11933
11934
11935/**
11936 * Single-stepping VM-exit filtering.
11937 *
11938 * This is preprocessing the VM-exits and deciding whether we've gotten far
11939 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
11940 * handling is performed.
11941 *
11942 * @returns Strict VBox status code (i.e. informational status codes too).
11943 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
11944 * @param pVmxTransient The VMX-transient structure.
11945 * @param pDbgState The debug state.
11946 */
11947DECLINLINE(VBOXSTRICTRC) vmxHCRunDebugHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11948{
11949 /*
11950 * Expensive (saves context) generic dtrace VM-exit probe.
11951 */
11952 uint32_t const uExitReason = pVmxTransient->uExitReason;
11953 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
11954 { /* more likely */ }
11955 else
11956 {
11957 vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
11958 int rc = vmxHCImportGuestState<HMVMX_CPUMCTX_EXTRN_ALL>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
11959 AssertRC(rc);
11960 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, &pVCpu->cpum.GstCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
11961 }
11962
11963#ifndef IN_NEM_DARWIN
11964 /*
11965 * Check for host NMI, just to get that out of the way.
11966 */
11967 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
11968 { /* normally likely */ }
11969 else
11970 {
11971 vmxHCReadToTransient<HMVMX_READ_EXIT_INTERRUPTION_INFO>(pVCpu, pVmxTransient);
11972 uint32_t const uIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
11973 if (uIntType == VMX_EXIT_INT_INFO_TYPE_NMI)
11974 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
11975 }
11976#endif
11977
11978 /*
11979 * Check for single stepping event if we're stepping.
11980 */
11981 if (VCPU_2_VMXSTATE(pVCpu).fSingleInstruction)
11982 {
11983 switch (uExitReason)
11984 {
11985 case VMX_EXIT_MTF:
11986 return vmxHCExitMtf(pVCpu, pVmxTransient);
11987
11988 /* Various events: */
11989 case VMX_EXIT_XCPT_OR_NMI:
11990 case VMX_EXIT_EXT_INT:
11991 case VMX_EXIT_TRIPLE_FAULT:
11992 case VMX_EXIT_INT_WINDOW:
11993 case VMX_EXIT_NMI_WINDOW:
11994 case VMX_EXIT_TASK_SWITCH:
11995 case VMX_EXIT_TPR_BELOW_THRESHOLD:
11996 case VMX_EXIT_APIC_ACCESS:
11997 case VMX_EXIT_EPT_VIOLATION:
11998 case VMX_EXIT_EPT_MISCONFIG:
11999 case VMX_EXIT_PREEMPT_TIMER:
12000
12001 /* Instruction specific VM-exits: */
12002 case VMX_EXIT_CPUID:
12003 case VMX_EXIT_GETSEC:
12004 case VMX_EXIT_HLT:
12005 case VMX_EXIT_INVD:
12006 case VMX_EXIT_INVLPG:
12007 case VMX_EXIT_RDPMC:
12008 case VMX_EXIT_RDTSC:
12009 case VMX_EXIT_RSM:
12010 case VMX_EXIT_VMCALL:
12011 case VMX_EXIT_VMCLEAR:
12012 case VMX_EXIT_VMLAUNCH:
12013 case VMX_EXIT_VMPTRLD:
12014 case VMX_EXIT_VMPTRST:
12015 case VMX_EXIT_VMREAD:
12016 case VMX_EXIT_VMRESUME:
12017 case VMX_EXIT_VMWRITE:
12018 case VMX_EXIT_VMXOFF:
12019 case VMX_EXIT_VMXON:
12020 case VMX_EXIT_MOV_CRX:
12021 case VMX_EXIT_MOV_DRX:
12022 case VMX_EXIT_IO_INSTR:
12023 case VMX_EXIT_RDMSR:
12024 case VMX_EXIT_WRMSR:
12025 case VMX_EXIT_MWAIT:
12026 case VMX_EXIT_MONITOR:
12027 case VMX_EXIT_PAUSE:
12028 case VMX_EXIT_GDTR_IDTR_ACCESS:
12029 case VMX_EXIT_LDTR_TR_ACCESS:
12030 case VMX_EXIT_INVEPT:
12031 case VMX_EXIT_RDTSCP:
12032 case VMX_EXIT_INVVPID:
12033 case VMX_EXIT_WBINVD:
12034 case VMX_EXIT_XSETBV:
12035 case VMX_EXIT_RDRAND:
12036 case VMX_EXIT_INVPCID:
12037 case VMX_EXIT_VMFUNC:
12038 case VMX_EXIT_RDSEED:
12039 case VMX_EXIT_XSAVES:
12040 case VMX_EXIT_XRSTORS:
12041 {
12042 int rc = vmxHCImportGuestState<CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP>(pVCpu, pVmxTransient->pVmcsInfo, __FUNCTION__);
12043 AssertRCReturn(rc, rc);
12044 if ( pVCpu->cpum.GstCtx.rip != pDbgState->uRipStart
12045 || pVCpu->cpum.GstCtx.cs.Sel != pDbgState->uCsStart)
12046 return VINF_EM_DBG_STEPPED;
12047 break;
12048 }
12049
12050 /* Errors and unexpected events: */
12051 case VMX_EXIT_INIT_SIGNAL:
12052 case VMX_EXIT_SIPI:
12053 case VMX_EXIT_IO_SMI:
12054 case VMX_EXIT_SMI:
12055 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
12056 case VMX_EXIT_ERR_MSR_LOAD:
12057 case VMX_EXIT_ERR_MACHINE_CHECK:
12058 case VMX_EXIT_PML_FULL:
12059 case VMX_EXIT_VIRTUALIZED_EOI:
12060 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
12061 break;
12062
12063 default:
12064 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12065 break;
12066 }
12067 }
12068
12069 /*
12070 * Check for debugger event breakpoints and dtrace probes.
12071 */
12072 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
12073 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
12074 {
12075 VBOXSTRICTRC rcStrict = vmxHCHandleExitDtraceEvents(pVCpu, pVmxTransient, uExitReason);
12076 if (rcStrict != VINF_SUCCESS)
12077 return rcStrict;
12078 }
12079
12080 /*
12081 * Normal processing.
12082 */
12083#ifdef HMVMX_USE_FUNCTION_TABLE
12084 return g_aVMExitHandlers[uExitReason].pfn(pVCpu, pVmxTransient);
12085#else
12086 return vmxHCHandleExit(pVCpu, pVmxTransient, uExitReason);
12087#endif
12088}
12089
12090/** @} */
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