VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h@ 93628

Last change on this file since 93628 was 93554, checked in by vboxsync, 3 years ago

VMM: Changed PAGE_SIZE -> GUEST_PAGE_SIZE / HOST_PAGE_SIZE, PAGE_SHIFT -> GUEST_PAGE_SHIFT / HOST_PAGE_SHIFT, and PAGE_OFFSET_MASK -> GUEST_PAGE_OFFSET_MASK / HOST_PAGE_OFFSET_MASK. Also removed most usage of ASMMemIsZeroPage and ASMMemZeroPage since the host and guest page size doesn't need to be the same any more. Some work left to do in the page pool code. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 370.1 KB
Line 
1/* $Id: IEMAllCImplVmxInstr.cpp.h 93554 2022-02-02 22:57:02Z vboxsync $ */
2/** @file
3 * IEM - VT-x instruction implementation.
4 */
5
6/*
7 * Copyright (C) 2011-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Defined Constants And Macros *
21*********************************************************************************************************************************/
22#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
23/**
24 * Gets the ModR/M, SIB and displacement byte(s) from decoded opcodes given their
25 * relative offsets.
26 */
27# ifdef IEM_WITH_CODE_TLB
28# define IEM_MODRM_GET_U8(a_pVCpu, a_bModRm, a_offModRm) do { } while (0)
29# define IEM_SIB_GET_U8(a_pVCpu, a_bSib, a_offSib) do { } while (0)
30# define IEM_DISP_GET_U16(a_pVCpu, a_u16Disp, a_offDisp) do { } while (0)
31# define IEM_DISP_GET_S8_SX_U16(a_pVCpu, a_u16Disp, a_offDisp) do { } while (0)
32# define IEM_DISP_GET_U32(a_pVCpu, a_u32Disp, a_offDisp) do { } while (0)
33# define IEM_DISP_GET_S8_SX_U32(a_pVCpu, a_u32Disp, a_offDisp) do { } while (0)
34# define IEM_DISP_GET_S32_SX_U64(a_pVCpu, a_u64Disp, a_offDisp) do { } while (0)
35# define IEM_DISP_GET_S8_SX_U64(a_pVCpu, a_u64Disp, a_offDisp) do { } while (0)
36# error "Implement me: Getting ModR/M, SIB, displacement needs to work even when instruction crosses a page boundary."
37# else /* !IEM_WITH_CODE_TLB */
38# define IEM_MODRM_GET_U8(a_pVCpu, a_bModRm, a_offModRm) \
39 do \
40 { \
41 Assert((a_offModRm) < (a_pVCpu)->iem.s.cbOpcode); \
42 (a_bModRm) = (a_pVCpu)->iem.s.abOpcode[(a_offModRm)]; \
43 } while (0)
44
45# define IEM_SIB_GET_U8(a_pVCpu, a_bSib, a_offSib) IEM_MODRM_GET_U8(a_pVCpu, a_bSib, a_offSib)
46
47# define IEM_DISP_GET_U16(a_pVCpu, a_u16Disp, a_offDisp) \
48 do \
49 { \
50 Assert((a_offDisp) + 1 < (a_pVCpu)->iem.s.cbOpcode); \
51 uint8_t const bTmpLo = (a_pVCpu)->iem.s.abOpcode[(a_offDisp)]; \
52 uint8_t const bTmpHi = (a_pVCpu)->iem.s.abOpcode[(a_offDisp) + 1]; \
53 (a_u16Disp) = RT_MAKE_U16(bTmpLo, bTmpHi); \
54 } while (0)
55
56# define IEM_DISP_GET_S8_SX_U16(a_pVCpu, a_u16Disp, a_offDisp) \
57 do \
58 { \
59 Assert((a_offDisp) < (a_pVCpu)->iem.s.cbOpcode); \
60 (a_u16Disp) = (int8_t)((a_pVCpu)->iem.s.abOpcode[(a_offDisp)]); \
61 } while (0)
62
63# define IEM_DISP_GET_U32(a_pVCpu, a_u32Disp, a_offDisp) \
64 do \
65 { \
66 Assert((a_offDisp) + 3 < (a_pVCpu)->iem.s.cbOpcode); \
67 uint8_t const bTmp0 = (a_pVCpu)->iem.s.abOpcode[(a_offDisp)]; \
68 uint8_t const bTmp1 = (a_pVCpu)->iem.s.abOpcode[(a_offDisp) + 1]; \
69 uint8_t const bTmp2 = (a_pVCpu)->iem.s.abOpcode[(a_offDisp) + 2]; \
70 uint8_t const bTmp3 = (a_pVCpu)->iem.s.abOpcode[(a_offDisp) + 3]; \
71 (a_u32Disp) = RT_MAKE_U32_FROM_U8(bTmp0, bTmp1, bTmp2, bTmp3); \
72 } while (0)
73
74# define IEM_DISP_GET_S8_SX_U32(a_pVCpu, a_u32Disp, a_offDisp) \
75 do \
76 { \
77 Assert((a_offDisp) + 1 < (a_pVCpu)->iem.s.cbOpcode); \
78 (a_u32Disp) = (int8_t)((a_pVCpu)->iem.s.abOpcode[(a_offDisp)]); \
79 } while (0)
80
81# define IEM_DISP_GET_S8_SX_U64(a_pVCpu, a_u64Disp, a_offDisp) \
82 do \
83 { \
84 Assert((a_offDisp) + 1 < (a_pVCpu)->iem.s.cbOpcode); \
85 (a_u64Disp) = (int8_t)((a_pVCpu)->iem.s.abOpcode[(a_offDisp)]); \
86 } while (0)
87
88# define IEM_DISP_GET_S32_SX_U64(a_pVCpu, a_u64Disp, a_offDisp) \
89 do \
90 { \
91 Assert((a_offDisp) + 3 < (a_pVCpu)->iem.s.cbOpcode); \
92 uint8_t const bTmp0 = (a_pVCpu)->iem.s.abOpcode[(a_offDisp)]; \
93 uint8_t const bTmp1 = (a_pVCpu)->iem.s.abOpcode[(a_offDisp) + 1]; \
94 uint8_t const bTmp2 = (a_pVCpu)->iem.s.abOpcode[(a_offDisp) + 2]; \
95 uint8_t const bTmp3 = (a_pVCpu)->iem.s.abOpcode[(a_offDisp) + 3]; \
96 (a_u64Disp) = (int32_t)RT_MAKE_U32_FROM_U8(bTmp0, bTmp1, bTmp2, bTmp3); \
97 } while (0)
98# endif /* !IEM_WITH_CODE_TLB */
99
100/** Gets the guest-physical address of the shadows VMCS for the given VCPU. */
101# define IEM_VMX_GET_SHADOW_VMCS(a_pVCpu) ((a_pVCpu)->cpum.GstCtx.hwvirt.vmx.GCPhysShadowVmcs)
102
103/** Whether a shadow VMCS is present for the given VCPU. */
104# define IEM_VMX_HAS_SHADOW_VMCS(a_pVCpu) RT_BOOL(IEM_VMX_GET_SHADOW_VMCS(a_pVCpu) != NIL_RTGCPHYS)
105
106/** Gets the VMXON region pointer. */
107# define IEM_VMX_GET_VMXON_PTR(a_pVCpu) ((a_pVCpu)->cpum.GstCtx.hwvirt.vmx.GCPhysVmxon)
108
109/** Gets the guest-physical address of the current VMCS for the given VCPU. */
110# define IEM_VMX_GET_CURRENT_VMCS(a_pVCpu) ((a_pVCpu)->cpum.GstCtx.hwvirt.vmx.GCPhysVmcs)
111
112/** Whether a current VMCS is present for the given VCPU. */
113# define IEM_VMX_HAS_CURRENT_VMCS(a_pVCpu) RT_BOOL(IEM_VMX_GET_CURRENT_VMCS(a_pVCpu) != NIL_RTGCPHYS)
114
115/** Assigns the guest-physical address of the current VMCS for the given VCPU. */
116# define IEM_VMX_SET_CURRENT_VMCS(a_pVCpu, a_GCPhysVmcs) \
117 do \
118 { \
119 Assert((a_GCPhysVmcs) != NIL_RTGCPHYS); \
120 (a_pVCpu)->cpum.GstCtx.hwvirt.vmx.GCPhysVmcs = (a_GCPhysVmcs); \
121 } while (0)
122
123/** Clears any current VMCS for the given VCPU. */
124# define IEM_VMX_CLEAR_CURRENT_VMCS(a_pVCpu) \
125 do \
126 { \
127 (a_pVCpu)->cpum.GstCtx.hwvirt.vmx.GCPhysVmcs = NIL_RTGCPHYS; \
128 } while (0)
129
130/** Check for VMX instructions requiring to be in VMX operation.
131 * @note Any changes here, check if IEMOP_HLP_IN_VMX_OPERATION needs updating. */
132# define IEM_VMX_IN_VMX_OPERATION(a_pVCpu, a_szInstr, a_InsDiagPrefix) \
133 do \
134 { \
135 if (IEM_VMX_IS_ROOT_MODE(a_pVCpu)) \
136 { /* likely */ } \
137 else \
138 { \
139 Log((a_szInstr ": Not in VMX operation (root mode) -> #UD\n")); \
140 (a_pVCpu)->cpum.GstCtx.hwvirt.vmx.enmDiag = a_InsDiagPrefix##_VmxRoot; \
141 return iemRaiseUndefinedOpcode(a_pVCpu); \
142 } \
143 } while (0)
144
145/** Marks a VM-entry failure with a diagnostic reason, logs and returns. */
146# define IEM_VMX_VMENTRY_FAILED_RET(a_pVCpu, a_pszInstr, a_pszFailure, a_VmxDiag) \
147 do \
148 { \
149 LogRel(("%s: VM-entry failed! enmDiag=%u (%s) -> %s\n", (a_pszInstr), (a_VmxDiag), \
150 HMGetVmxDiagDesc(a_VmxDiag), (a_pszFailure))); \
151 (a_pVCpu)->cpum.GstCtx.hwvirt.vmx.enmDiag = (a_VmxDiag); \
152 return VERR_VMX_VMENTRY_FAILED; \
153 } while (0)
154
155/** Marks a VM-exit failure with a diagnostic reason and logs. */
156# define IEM_VMX_VMEXIT_FAILED(a_pVCpu, a_uExitReason, a_pszFailure, a_VmxDiag) \
157 do \
158 { \
159 LogRel(("VM-exit failed! uExitReason=%u enmDiag=%u (%s) -> %s\n", (a_uExitReason), (a_VmxDiag), \
160 HMGetVmxDiagDesc(a_VmxDiag), (a_pszFailure))); \
161 (a_pVCpu)->cpum.GstCtx.hwvirt.vmx.enmDiag = (a_VmxDiag); \
162 } while (0)
163
164/** Marks a VM-exit failure with a diagnostic reason, logs and returns. */
165# define IEM_VMX_VMEXIT_FAILED_RET(a_pVCpu, a_uExitReason, a_pszFailure, a_VmxDiag) \
166 do \
167 { \
168 IEM_VMX_VMEXIT_FAILED(a_pVCpu, a_uExitReason, a_pszFailure, a_VmxDiag); \
169 return VERR_VMX_VMEXIT_FAILED; \
170 } while (0)
171
172
173/*********************************************************************************************************************************
174* Global Variables *
175*********************************************************************************************************************************/
176/** @todo NSTVMX: The following VM-exit intercepts are pending:
177 * VMX_EXIT_IO_SMI
178 * VMX_EXIT_SMI
179 * VMX_EXIT_GETSEC
180 * VMX_EXIT_RSM
181 * VMX_EXIT_MONITOR (APIC access VM-exit caused by MONITOR pending)
182 * VMX_EXIT_ERR_MACHINE_CHECK (we never need to raise this?)
183 * VMX_EXIT_INVEPT
184 * VMX_EXIT_RDRAND
185 * VMX_EXIT_VMFUNC
186 * VMX_EXIT_ENCLS
187 * VMX_EXIT_RDSEED
188 * VMX_EXIT_PML_FULL
189 * VMX_EXIT_XSAVES
190 * VMX_EXIT_XRSTORS
191 */
192/**
193 * Map of VMCS field encodings to their virtual-VMCS structure offsets.
194 *
195 * The first array dimension is VMCS field encoding of Width OR'ed with Type and the
196 * second dimension is the Index, see VMXVMCSFIELD.
197 */
198uint16_t const g_aoffVmcsMap[16][VMX_V_VMCS_MAX_INDEX + 1] =
199{
200 /* VMX_VMCSFIELD_WIDTH_16BIT | VMX_VMCSFIELD_TYPE_CONTROL: */
201 {
202 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u16Vpid),
203 /* 1 */ RT_UOFFSETOF(VMXVVMCS, u16PostIntNotifyVector),
204 /* 2 */ RT_UOFFSETOF(VMXVVMCS, u16EptpIndex),
205 /* 3-10 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
206 /* 11-18 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
207 /* 19-26 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
208 /* 27 */ UINT16_MAX,
209 },
210 /* VMX_VMCSFIELD_WIDTH_16BIT | VMX_VMCSFIELD_TYPE_VMEXIT_INFO: */
211 {
212 /* 0-7 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
213 /* 8-15 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
214 /* 16-23 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
215 /* 24-27 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX
216 },
217 /* VMX_VMCSFIELD_WIDTH_16BIT | VMX_VMCSFIELD_TYPE_GUEST_STATE: */
218 {
219 /* 0 */ RT_UOFFSETOF(VMXVVMCS, GuestEs),
220 /* 1 */ RT_UOFFSETOF(VMXVVMCS, GuestCs),
221 /* 2 */ RT_UOFFSETOF(VMXVVMCS, GuestSs),
222 /* 3 */ RT_UOFFSETOF(VMXVVMCS, GuestDs),
223 /* 4 */ RT_UOFFSETOF(VMXVVMCS, GuestFs),
224 /* 5 */ RT_UOFFSETOF(VMXVVMCS, GuestGs),
225 /* 6 */ RT_UOFFSETOF(VMXVVMCS, GuestLdtr),
226 /* 7 */ RT_UOFFSETOF(VMXVVMCS, GuestTr),
227 /* 8 */ RT_UOFFSETOF(VMXVVMCS, u16GuestIntStatus),
228 /* 9 */ RT_UOFFSETOF(VMXVVMCS, u16PmlIndex),
229 /* 10-17 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
230 /* 18-25 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
231 /* 26-27 */ UINT16_MAX, UINT16_MAX
232 },
233 /* VMX_VMCSFIELD_WIDTH_16BIT | VMX_VMCSFIELD_TYPE_HOST_STATE: */
234 {
235 /* 0 */ RT_UOFFSETOF(VMXVVMCS, HostEs),
236 /* 1 */ RT_UOFFSETOF(VMXVVMCS, HostCs),
237 /* 2 */ RT_UOFFSETOF(VMXVVMCS, HostSs),
238 /* 3 */ RT_UOFFSETOF(VMXVVMCS, HostDs),
239 /* 4 */ RT_UOFFSETOF(VMXVVMCS, HostFs),
240 /* 5 */ RT_UOFFSETOF(VMXVVMCS, HostGs),
241 /* 6 */ RT_UOFFSETOF(VMXVVMCS, HostTr),
242 /* 7-14 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
243 /* 15-22 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
244 /* 23-27 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX
245 },
246 /* VMX_VMCSFIELD_WIDTH_64BIT | VMX_VMCSFIELD_TYPE_CONTROL: */
247 {
248 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u64AddrIoBitmapA),
249 /* 1 */ RT_UOFFSETOF(VMXVVMCS, u64AddrIoBitmapB),
250 /* 2 */ RT_UOFFSETOF(VMXVVMCS, u64AddrMsrBitmap),
251 /* 3 */ RT_UOFFSETOF(VMXVVMCS, u64AddrExitMsrStore),
252 /* 4 */ RT_UOFFSETOF(VMXVVMCS, u64AddrExitMsrLoad),
253 /* 5 */ RT_UOFFSETOF(VMXVVMCS, u64AddrEntryMsrLoad),
254 /* 6 */ RT_UOFFSETOF(VMXVVMCS, u64ExecVmcsPtr),
255 /* 7 */ RT_UOFFSETOF(VMXVVMCS, u64AddrPml),
256 /* 8 */ RT_UOFFSETOF(VMXVVMCS, u64TscOffset),
257 /* 9 */ RT_UOFFSETOF(VMXVVMCS, u64AddrVirtApic),
258 /* 10 */ RT_UOFFSETOF(VMXVVMCS, u64AddrApicAccess),
259 /* 11 */ RT_UOFFSETOF(VMXVVMCS, u64AddrPostedIntDesc),
260 /* 12 */ RT_UOFFSETOF(VMXVVMCS, u64VmFuncCtls),
261 /* 13 */ RT_UOFFSETOF(VMXVVMCS, u64EptPtr),
262 /* 14 */ RT_UOFFSETOF(VMXVVMCS, u64EoiExitBitmap0),
263 /* 15 */ RT_UOFFSETOF(VMXVVMCS, u64EoiExitBitmap1),
264 /* 16 */ RT_UOFFSETOF(VMXVVMCS, u64EoiExitBitmap2),
265 /* 17 */ RT_UOFFSETOF(VMXVVMCS, u64EoiExitBitmap3),
266 /* 18 */ RT_UOFFSETOF(VMXVVMCS, u64AddrEptpList),
267 /* 19 */ RT_UOFFSETOF(VMXVVMCS, u64AddrVmreadBitmap),
268 /* 20 */ RT_UOFFSETOF(VMXVVMCS, u64AddrVmwriteBitmap),
269 /* 21 */ RT_UOFFSETOF(VMXVVMCS, u64AddrXcptVeInfo),
270 /* 22 */ RT_UOFFSETOF(VMXVVMCS, u64XssExitBitmap),
271 /* 23 */ RT_UOFFSETOF(VMXVVMCS, u64EnclsExitBitmap),
272 /* 24 */ RT_UOFFSETOF(VMXVVMCS, u64SppTablePtr),
273 /* 25 */ RT_UOFFSETOF(VMXVVMCS, u64TscMultiplier),
274 /* 26 */ RT_UOFFSETOF(VMXVVMCS, u64ProcCtls3),
275 /* 27 */ RT_UOFFSETOF(VMXVVMCS, u64EnclvExitBitmap)
276 },
277 /* VMX_VMCSFIELD_WIDTH_64BIT | VMX_VMCSFIELD_TYPE_VMEXIT_INFO: */
278 {
279 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u64RoGuestPhysAddr),
280 /* 1-8 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
281 /* 9-16 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
282 /* 17-24 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
283 /* 25-27 */ UINT16_MAX, UINT16_MAX, UINT16_MAX
284 },
285 /* VMX_VMCSFIELD_WIDTH_64BIT | VMX_VMCSFIELD_TYPE_GUEST_STATE: */
286 {
287 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u64VmcsLinkPtr),
288 /* 1 */ RT_UOFFSETOF(VMXVVMCS, u64GuestDebugCtlMsr),
289 /* 2 */ RT_UOFFSETOF(VMXVVMCS, u64GuestPatMsr),
290 /* 3 */ RT_UOFFSETOF(VMXVVMCS, u64GuestEferMsr),
291 /* 4 */ RT_UOFFSETOF(VMXVVMCS, u64GuestPerfGlobalCtlMsr),
292 /* 5 */ RT_UOFFSETOF(VMXVVMCS, u64GuestPdpte0),
293 /* 6 */ RT_UOFFSETOF(VMXVVMCS, u64GuestPdpte1),
294 /* 7 */ RT_UOFFSETOF(VMXVVMCS, u64GuestPdpte2),
295 /* 8 */ RT_UOFFSETOF(VMXVVMCS, u64GuestPdpte3),
296 /* 9 */ RT_UOFFSETOF(VMXVVMCS, u64GuestBndcfgsMsr),
297 /* 10 */ RT_UOFFSETOF(VMXVVMCS, u64GuestRtitCtlMsr),
298 /* 11 */ UINT16_MAX,
299 /* 12 */ RT_UOFFSETOF(VMXVVMCS, u64GuestPkrsMsr),
300 /* 13-20 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
301 /* 21-27 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX
302 },
303 /* VMX_VMCSFIELD_WIDTH_64BIT | VMX_VMCSFIELD_TYPE_HOST_STATE: */
304 {
305 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u64HostPatMsr),
306 /* 1 */ RT_UOFFSETOF(VMXVVMCS, u64HostEferMsr),
307 /* 2 */ RT_UOFFSETOF(VMXVVMCS, u64HostPerfGlobalCtlMsr),
308 /* 3 */ RT_UOFFSETOF(VMXVVMCS, u64HostPkrsMsr),
309 /* 4-11 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
310 /* 12-19 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
311 /* 20-27 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX
312 },
313 /* VMX_VMCSFIELD_WIDTH_32BIT | VMX_VMCSFIELD_TYPE_CONTROL: */
314 {
315 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u32PinCtls),
316 /* 1 */ RT_UOFFSETOF(VMXVVMCS, u32ProcCtls),
317 /* 2 */ RT_UOFFSETOF(VMXVVMCS, u32XcptBitmap),
318 /* 3 */ RT_UOFFSETOF(VMXVVMCS, u32XcptPFMask),
319 /* 4 */ RT_UOFFSETOF(VMXVVMCS, u32XcptPFMatch),
320 /* 5 */ RT_UOFFSETOF(VMXVVMCS, u32Cr3TargetCount),
321 /* 6 */ RT_UOFFSETOF(VMXVVMCS, u32ExitCtls),
322 /* 7 */ RT_UOFFSETOF(VMXVVMCS, u32ExitMsrStoreCount),
323 /* 8 */ RT_UOFFSETOF(VMXVVMCS, u32ExitMsrLoadCount),
324 /* 9 */ RT_UOFFSETOF(VMXVVMCS, u32EntryCtls),
325 /* 10 */ RT_UOFFSETOF(VMXVVMCS, u32EntryMsrLoadCount),
326 /* 11 */ RT_UOFFSETOF(VMXVVMCS, u32EntryIntInfo),
327 /* 12 */ RT_UOFFSETOF(VMXVVMCS, u32EntryXcptErrCode),
328 /* 13 */ RT_UOFFSETOF(VMXVVMCS, u32EntryInstrLen),
329 /* 14 */ RT_UOFFSETOF(VMXVVMCS, u32TprThreshold),
330 /* 15 */ RT_UOFFSETOF(VMXVVMCS, u32ProcCtls2),
331 /* 16 */ RT_UOFFSETOF(VMXVVMCS, u32PleGap),
332 /* 17 */ RT_UOFFSETOF(VMXVVMCS, u32PleWindow),
333 /* 18-25 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
334 /* 26-27 */ UINT16_MAX, UINT16_MAX
335 },
336 /* VMX_VMCSFIELD_WIDTH_32BIT | VMX_VMCSFIELD_TYPE_VMEXIT_INFO: */
337 {
338 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u32RoVmInstrError),
339 /* 1 */ RT_UOFFSETOF(VMXVVMCS, u32RoExitReason),
340 /* 2 */ RT_UOFFSETOF(VMXVVMCS, u32RoExitIntInfo),
341 /* 3 */ RT_UOFFSETOF(VMXVVMCS, u32RoExitIntErrCode),
342 /* 4 */ RT_UOFFSETOF(VMXVVMCS, u32RoIdtVectoringInfo),
343 /* 5 */ RT_UOFFSETOF(VMXVVMCS, u32RoIdtVectoringErrCode),
344 /* 6 */ RT_UOFFSETOF(VMXVVMCS, u32RoExitInstrLen),
345 /* 7 */ RT_UOFFSETOF(VMXVVMCS, u32RoExitInstrInfo),
346 /* 8-15 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
347 /* 16-23 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
348 /* 24-27 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX
349 },
350 /* VMX_VMCSFIELD_WIDTH_32BIT | VMX_VMCSFIELD_TYPE_GUEST_STATE: */
351 {
352 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u32GuestEsLimit),
353 /* 1 */ RT_UOFFSETOF(VMXVVMCS, u32GuestCsLimit),
354 /* 2 */ RT_UOFFSETOF(VMXVVMCS, u32GuestSsLimit),
355 /* 3 */ RT_UOFFSETOF(VMXVVMCS, u32GuestDsLimit),
356 /* 4 */ RT_UOFFSETOF(VMXVVMCS, u32GuestFsLimit),
357 /* 5 */ RT_UOFFSETOF(VMXVVMCS, u32GuestGsLimit),
358 /* 6 */ RT_UOFFSETOF(VMXVVMCS, u32GuestLdtrLimit),
359 /* 7 */ RT_UOFFSETOF(VMXVVMCS, u32GuestTrLimit),
360 /* 8 */ RT_UOFFSETOF(VMXVVMCS, u32GuestGdtrLimit),
361 /* 9 */ RT_UOFFSETOF(VMXVVMCS, u32GuestIdtrLimit),
362 /* 10 */ RT_UOFFSETOF(VMXVVMCS, u32GuestEsAttr),
363 /* 11 */ RT_UOFFSETOF(VMXVVMCS, u32GuestCsAttr),
364 /* 12 */ RT_UOFFSETOF(VMXVVMCS, u32GuestSsAttr),
365 /* 13 */ RT_UOFFSETOF(VMXVVMCS, u32GuestDsAttr),
366 /* 14 */ RT_UOFFSETOF(VMXVVMCS, u32GuestFsAttr),
367 /* 15 */ RT_UOFFSETOF(VMXVVMCS, u32GuestGsAttr),
368 /* 16 */ RT_UOFFSETOF(VMXVVMCS, u32GuestLdtrAttr),
369 /* 17 */ RT_UOFFSETOF(VMXVVMCS, u32GuestTrAttr),
370 /* 18 */ RT_UOFFSETOF(VMXVVMCS, u32GuestIntrState),
371 /* 19 */ RT_UOFFSETOF(VMXVVMCS, u32GuestActivityState),
372 /* 20 */ RT_UOFFSETOF(VMXVVMCS, u32GuestSmBase),
373 /* 21 */ RT_UOFFSETOF(VMXVVMCS, u32GuestSysenterCS),
374 /* 22 */ UINT16_MAX,
375 /* 23 */ RT_UOFFSETOF(VMXVVMCS, u32PreemptTimer),
376 /* 24-27 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX
377 },
378 /* VMX_VMCSFIELD_WIDTH_32BIT | VMX_VMCSFIELD_TYPE_HOST_STATE: */
379 {
380 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u32HostSysenterCs),
381 /* 1-8 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
382 /* 9-16 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
383 /* 17-24 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
384 /* 25-27 */ UINT16_MAX, UINT16_MAX, UINT16_MAX
385 },
386 /* VMX_VMCSFIELD_WIDTH_NATURAL | VMX_VMCSFIELD_TYPE_CONTROL: */
387 {
388 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u64Cr0Mask),
389 /* 1 */ RT_UOFFSETOF(VMXVVMCS, u64Cr4Mask),
390 /* 2 */ RT_UOFFSETOF(VMXVVMCS, u64Cr0ReadShadow),
391 /* 3 */ RT_UOFFSETOF(VMXVVMCS, u64Cr4ReadShadow),
392 /* 4 */ RT_UOFFSETOF(VMXVVMCS, u64Cr3Target0),
393 /* 5 */ RT_UOFFSETOF(VMXVVMCS, u64Cr3Target1),
394 /* 6 */ RT_UOFFSETOF(VMXVVMCS, u64Cr3Target2),
395 /* 7 */ RT_UOFFSETOF(VMXVVMCS, u64Cr3Target3),
396 /* 8-15 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
397 /* 16-23 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
398 /* 24-27 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX
399 },
400 /* VMX_VMCSFIELD_WIDTH_NATURAL | VMX_VMCSFIELD_TYPE_VMEXIT_INFO: */
401 {
402 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u64RoExitQual),
403 /* 1 */ RT_UOFFSETOF(VMXVVMCS, u64RoIoRcx),
404 /* 2 */ RT_UOFFSETOF(VMXVVMCS, u64RoIoRsi),
405 /* 3 */ RT_UOFFSETOF(VMXVVMCS, u64RoIoRdi),
406 /* 4 */ RT_UOFFSETOF(VMXVVMCS, u64RoIoRip),
407 /* 5 */ RT_UOFFSETOF(VMXVVMCS, u64RoGuestLinearAddr),
408 /* 6-13 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
409 /* 14-21 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
410 /* 22-27 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX
411 },
412 /* VMX_VMCSFIELD_WIDTH_NATURAL | VMX_VMCSFIELD_TYPE_GUEST_STATE: */
413 {
414 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u64GuestCr0),
415 /* 1 */ RT_UOFFSETOF(VMXVVMCS, u64GuestCr3),
416 /* 2 */ RT_UOFFSETOF(VMXVVMCS, u64GuestCr4),
417 /* 3 */ RT_UOFFSETOF(VMXVVMCS, u64GuestEsBase),
418 /* 4 */ RT_UOFFSETOF(VMXVVMCS, u64GuestCsBase),
419 /* 5 */ RT_UOFFSETOF(VMXVVMCS, u64GuestSsBase),
420 /* 6 */ RT_UOFFSETOF(VMXVVMCS, u64GuestDsBase),
421 /* 7 */ RT_UOFFSETOF(VMXVVMCS, u64GuestFsBase),
422 /* 8 */ RT_UOFFSETOF(VMXVVMCS, u64GuestGsBase),
423 /* 9 */ RT_UOFFSETOF(VMXVVMCS, u64GuestLdtrBase),
424 /* 10 */ RT_UOFFSETOF(VMXVVMCS, u64GuestTrBase),
425 /* 11 */ RT_UOFFSETOF(VMXVVMCS, u64GuestGdtrBase),
426 /* 12 */ RT_UOFFSETOF(VMXVVMCS, u64GuestIdtrBase),
427 /* 13 */ RT_UOFFSETOF(VMXVVMCS, u64GuestDr7),
428 /* 14 */ RT_UOFFSETOF(VMXVVMCS, u64GuestRsp),
429 /* 15 */ RT_UOFFSETOF(VMXVVMCS, u64GuestRip),
430 /* 16 */ RT_UOFFSETOF(VMXVVMCS, u64GuestRFlags),
431 /* 17 */ RT_UOFFSETOF(VMXVVMCS, u64GuestPendingDbgXcpts),
432 /* 18 */ RT_UOFFSETOF(VMXVVMCS, u64GuestSysenterEsp),
433 /* 19 */ RT_UOFFSETOF(VMXVVMCS, u64GuestSysenterEip),
434 /* 20 */ RT_UOFFSETOF(VMXVVMCS, u64GuestSCetMsr),
435 /* 21 */ RT_UOFFSETOF(VMXVVMCS, u64GuestSsp),
436 /* 22 */ RT_UOFFSETOF(VMXVVMCS, u64GuestIntrSspTableAddrMsr),
437 /* 23-27 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX
438 },
439 /* VMX_VMCSFIELD_WIDTH_NATURAL | VMX_VMCSFIELD_TYPE_HOST_STATE: */
440 {
441 /* 0 */ RT_UOFFSETOF(VMXVVMCS, u64HostCr0),
442 /* 1 */ RT_UOFFSETOF(VMXVVMCS, u64HostCr3),
443 /* 2 */ RT_UOFFSETOF(VMXVVMCS, u64HostCr4),
444 /* 3 */ RT_UOFFSETOF(VMXVVMCS, u64HostFsBase),
445 /* 4 */ RT_UOFFSETOF(VMXVVMCS, u64HostGsBase),
446 /* 5 */ RT_UOFFSETOF(VMXVVMCS, u64HostTrBase),
447 /* 6 */ RT_UOFFSETOF(VMXVVMCS, u64HostGdtrBase),
448 /* 7 */ RT_UOFFSETOF(VMXVVMCS, u64HostIdtrBase),
449 /* 8 */ RT_UOFFSETOF(VMXVVMCS, u64HostSysenterEsp),
450 /* 9 */ RT_UOFFSETOF(VMXVVMCS, u64HostSysenterEip),
451 /* 10 */ RT_UOFFSETOF(VMXVVMCS, u64HostRsp),
452 /* 11 */ RT_UOFFSETOF(VMXVVMCS, u64HostRip),
453 /* 12 */ RT_UOFFSETOF(VMXVVMCS, u64HostSCetMsr),
454 /* 13 */ RT_UOFFSETOF(VMXVVMCS, u64HostSsp),
455 /* 14 */ RT_UOFFSETOF(VMXVVMCS, u64HostIntrSspTableAddrMsr),
456 /* 15-22 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX,
457 /* 23-27 */ UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX
458 }
459};
460
461
462/**
463 * Gets CR0 fixed-0 bits in VMX non-root mode.
464 *
465 * We do this rather than fetching what we report to the guest (in
466 * IA32_VMX_CR0_FIXED0 MSR) because real hardware (and so do we) report the same
467 * values regardless of whether unrestricted-guest feature is available on the CPU.
468 *
469 * @returns CR0 fixed-0 bits.
470 * @param pVCpu The cross context virtual CPU structure.
471 */
472DECLINLINE(uint64_t) iemVmxGetCr0Fixed0(PCVMCPUCC pVCpu)
473{
474 Assert(IEM_VMX_IS_ROOT_MODE(pVCpu));
475 Assert(IEM_VMX_HAS_CURRENT_VMCS(pVCpu));
476
477 static uint64_t const s_auCr0Fixed0[2] = { VMX_V_CR0_FIXED0, VMX_V_CR0_FIXED0_UX };
478 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
479 uint8_t const fUnrestrictedGuest = !!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST);
480 uint64_t const uCr0Fixed0 = s_auCr0Fixed0[fUnrestrictedGuest];
481 Assert(!(uCr0Fixed0 & (X86_CR0_NW | X86_CR0_CD)));
482 return uCr0Fixed0;
483}
484
485
486/**
487 * Gets a host selector from the VMCS.
488 *
489 * @param pVmcs Pointer to the virtual VMCS.
490 * @param iSelReg The index of the segment register (X86_SREG_XXX).
491 */
492DECLINLINE(RTSEL) iemVmxVmcsGetHostSelReg(PCVMXVVMCS pVmcs, uint8_t iSegReg)
493{
494 Assert(iSegReg < X86_SREG_COUNT);
495 RTSEL HostSel;
496 uint8_t const uWidth = VMX_VMCSFIELD_WIDTH_16BIT;
497 uint8_t const uType = VMX_VMCSFIELD_TYPE_HOST_STATE;
498 uint8_t const uWidthType = (uWidth << 2) | uType;
499 uint8_t const uIndex = iSegReg + RT_BF_GET(VMX_VMCS16_HOST_ES_SEL, VMX_BF_VMCSFIELD_INDEX);
500 Assert(uIndex <= VMX_V_VMCS_MAX_INDEX);
501 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
502 uint8_t const *pbVmcs = (uint8_t *)pVmcs;
503 uint8_t const *pbField = pbVmcs + offField;
504 HostSel = *(uint16_t *)pbField;
505 return HostSel;
506}
507
508
509/**
510 * Sets a guest segment register in the VMCS.
511 *
512 * @param pVmcs Pointer to the virtual VMCS.
513 * @param iSegReg The index of the segment register (X86_SREG_XXX).
514 * @param pSelReg Pointer to the segment register.
515 */
516IEM_STATIC void iemVmxVmcsSetGuestSegReg(PCVMXVVMCS pVmcs, uint8_t iSegReg, PCCPUMSELREG pSelReg)
517{
518 Assert(pSelReg);
519 Assert(iSegReg < X86_SREG_COUNT);
520
521 /* Selector. */
522 {
523 uint8_t const uWidth = VMX_VMCSFIELD_WIDTH_16BIT;
524 uint8_t const uType = VMX_VMCSFIELD_TYPE_GUEST_STATE;
525 uint8_t const uWidthType = (uWidth << 2) | uType;
526 uint8_t const uIndex = iSegReg + RT_BF_GET(VMX_VMCS16_GUEST_ES_SEL, VMX_BF_VMCSFIELD_INDEX);
527 Assert(uIndex <= VMX_V_VMCS_MAX_INDEX);
528 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
529 uint8_t *pbVmcs = (uint8_t *)pVmcs;
530 uint8_t *pbField = pbVmcs + offField;
531 *(uint16_t *)pbField = pSelReg->Sel;
532 }
533
534 /* Limit. */
535 {
536 uint8_t const uWidth = VMX_VMCSFIELD_WIDTH_32BIT;
537 uint8_t const uType = VMX_VMCSFIELD_TYPE_GUEST_STATE;
538 uint8_t const uWidthType = (uWidth << 2) | uType;
539 uint8_t const uIndex = iSegReg + RT_BF_GET(VMX_VMCS32_GUEST_ES_LIMIT, VMX_BF_VMCSFIELD_INDEX);
540 Assert(uIndex <= VMX_V_VMCS_MAX_INDEX);
541 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
542 uint8_t *pbVmcs = (uint8_t *)pVmcs;
543 uint8_t *pbField = pbVmcs + offField;
544 *(uint32_t *)pbField = pSelReg->u32Limit;
545 }
546
547 /* Base. */
548 {
549 uint8_t const uWidth = VMX_VMCSFIELD_WIDTH_NATURAL;
550 uint8_t const uType = VMX_VMCSFIELD_TYPE_GUEST_STATE;
551 uint8_t const uWidthType = (uWidth << 2) | uType;
552 uint8_t const uIndex = iSegReg + RT_BF_GET(VMX_VMCS_GUEST_ES_BASE, VMX_BF_VMCSFIELD_INDEX);
553 Assert(uIndex <= VMX_V_VMCS_MAX_INDEX);
554 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
555 uint8_t const *pbVmcs = (uint8_t *)pVmcs;
556 uint8_t const *pbField = pbVmcs + offField;
557 *(uint64_t *)pbField = pSelReg->u64Base;
558 }
559
560 /* Attributes. */
561 {
562 uint32_t const fValidAttrMask = X86DESCATTR_TYPE | X86DESCATTR_DT | X86DESCATTR_DPL | X86DESCATTR_P
563 | X86DESCATTR_AVL | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
564 | X86DESCATTR_UNUSABLE;
565 uint8_t const uWidth = VMX_VMCSFIELD_WIDTH_32BIT;
566 uint8_t const uType = VMX_VMCSFIELD_TYPE_GUEST_STATE;
567 uint8_t const uWidthType = (uWidth << 2) | uType;
568 uint8_t const uIndex = iSegReg + RT_BF_GET(VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS, VMX_BF_VMCSFIELD_INDEX);
569 Assert(uIndex <= VMX_V_VMCS_MAX_INDEX);
570 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
571 uint8_t *pbVmcs = (uint8_t *)pVmcs;
572 uint8_t *pbField = pbVmcs + offField;
573 *(uint32_t *)pbField = pSelReg->Attr.u & fValidAttrMask;
574 }
575}
576
577
578/**
579 * Gets a guest segment register from the VMCS.
580 *
581 * @returns VBox status code.
582 * @param pVmcs Pointer to the virtual VMCS.
583 * @param iSegReg The index of the segment register (X86_SREG_XXX).
584 * @param pSelReg Where to store the segment register (only updated when
585 * VINF_SUCCESS is returned).
586 *
587 * @remarks Warning! This does not validate the contents of the retrieved segment
588 * register.
589 */
590IEM_STATIC int iemVmxVmcsGetGuestSegReg(PCVMXVVMCS pVmcs, uint8_t iSegReg, PCPUMSELREG pSelReg)
591{
592 Assert(pSelReg);
593 Assert(iSegReg < X86_SREG_COUNT);
594
595 /* Selector. */
596 uint16_t u16Sel;
597 {
598 uint8_t const uWidth = VMX_VMCSFIELD_WIDTH_16BIT;
599 uint8_t const uType = VMX_VMCSFIELD_TYPE_GUEST_STATE;
600 uint8_t const uWidthType = (uWidth << 2) | uType;
601 uint8_t const uIndex = iSegReg + RT_BF_GET(VMX_VMCS16_GUEST_ES_SEL, VMX_BF_VMCSFIELD_INDEX);
602 AssertReturn(uIndex <= VMX_V_VMCS_MAX_INDEX, VERR_IEM_IPE_3);
603 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
604 uint8_t const *pbVmcs = (uint8_t *)pVmcs;
605 uint8_t const *pbField = pbVmcs + offField;
606 u16Sel = *(uint16_t *)pbField;
607 }
608
609 /* Limit. */
610 uint32_t u32Limit;
611 {
612 uint8_t const uWidth = VMX_VMCSFIELD_WIDTH_32BIT;
613 uint8_t const uType = VMX_VMCSFIELD_TYPE_GUEST_STATE;
614 uint8_t const uWidthType = (uWidth << 2) | uType;
615 uint8_t const uIndex = iSegReg + RT_BF_GET(VMX_VMCS32_GUEST_ES_LIMIT, VMX_BF_VMCSFIELD_INDEX);
616 AssertReturn(uIndex <= VMX_V_VMCS_MAX_INDEX, VERR_IEM_IPE_3);
617 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
618 uint8_t const *pbVmcs = (uint8_t *)pVmcs;
619 uint8_t const *pbField = pbVmcs + offField;
620 u32Limit = *(uint32_t *)pbField;
621 }
622
623 /* Base. */
624 uint64_t u64Base;
625 {
626 uint8_t const uWidth = VMX_VMCSFIELD_WIDTH_NATURAL;
627 uint8_t const uType = VMX_VMCSFIELD_TYPE_GUEST_STATE;
628 uint8_t const uWidthType = (uWidth << 2) | uType;
629 uint8_t const uIndex = iSegReg + RT_BF_GET(VMX_VMCS_GUEST_ES_BASE, VMX_BF_VMCSFIELD_INDEX);
630 AssertReturn(uIndex <= VMX_V_VMCS_MAX_INDEX, VERR_IEM_IPE_3);
631 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
632 uint8_t const *pbVmcs = (uint8_t *)pVmcs;
633 uint8_t const *pbField = pbVmcs + offField;
634 u64Base = *(uint64_t *)pbField;
635 /** @todo NSTVMX: Should we zero out high bits here for 32-bit virtual CPUs? */
636 }
637
638 /* Attributes. */
639 uint32_t u32Attr;
640 {
641 uint8_t const uWidth = VMX_VMCSFIELD_WIDTH_32BIT;
642 uint8_t const uType = VMX_VMCSFIELD_TYPE_GUEST_STATE;
643 uint8_t const uWidthType = (uWidth << 2) | uType;
644 uint8_t const uIndex = iSegReg + RT_BF_GET(VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS, VMX_BF_VMCSFIELD_INDEX);
645 AssertReturn(uIndex <= VMX_V_VMCS_MAX_INDEX, VERR_IEM_IPE_3);
646 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
647 uint8_t const *pbVmcs = (uint8_t *)pVmcs;
648 uint8_t const *pbField = pbVmcs + offField;
649 u32Attr = *(uint32_t *)pbField;
650 }
651
652 pSelReg->Sel = u16Sel;
653 pSelReg->ValidSel = u16Sel;
654 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
655 pSelReg->u32Limit = u32Limit;
656 pSelReg->u64Base = u64Base;
657 pSelReg->Attr.u = u32Attr;
658 return VINF_SUCCESS;
659}
660
661
662/**
663 * Converts an IEM exception event type to a VMX event type.
664 *
665 * @returns The VMX event type.
666 * @param uVector The interrupt / exception vector.
667 * @param fFlags The IEM event flag (see IEM_XCPT_FLAGS_XXX).
668 */
669DECLINLINE(uint8_t) iemVmxGetEventType(uint32_t uVector, uint32_t fFlags)
670{
671 /* Paranoia (callers may use these interchangeably). */
672 AssertCompile(VMX_EXIT_INT_INFO_TYPE_NMI == VMX_IDT_VECTORING_INFO_TYPE_NMI);
673 AssertCompile(VMX_EXIT_INT_INFO_TYPE_HW_XCPT == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT);
674 AssertCompile(VMX_EXIT_INT_INFO_TYPE_EXT_INT == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
675 AssertCompile(VMX_EXIT_INT_INFO_TYPE_SW_XCPT == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT);
676 AssertCompile(VMX_EXIT_INT_INFO_TYPE_SW_INT == VMX_IDT_VECTORING_INFO_TYPE_SW_INT);
677 AssertCompile(VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT);
678 AssertCompile(VMX_EXIT_INT_INFO_TYPE_NMI == VMX_ENTRY_INT_INFO_TYPE_NMI);
679 AssertCompile(VMX_EXIT_INT_INFO_TYPE_HW_XCPT == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT);
680 AssertCompile(VMX_EXIT_INT_INFO_TYPE_EXT_INT == VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
681 AssertCompile(VMX_EXIT_INT_INFO_TYPE_SW_XCPT == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT);
682 AssertCompile(VMX_EXIT_INT_INFO_TYPE_SW_INT == VMX_ENTRY_INT_INFO_TYPE_SW_INT);
683 AssertCompile(VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT == VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT);
684
685 if (fFlags & IEM_XCPT_FLAGS_T_CPU_XCPT)
686 {
687 if (uVector == X86_XCPT_NMI)
688 return VMX_EXIT_INT_INFO_TYPE_NMI;
689 return VMX_EXIT_INT_INFO_TYPE_HW_XCPT;
690 }
691
692 if (fFlags & IEM_XCPT_FLAGS_T_SOFT_INT)
693 {
694 if (fFlags & (IEM_XCPT_FLAGS_BP_INSTR | IEM_XCPT_FLAGS_OF_INSTR))
695 return VMX_EXIT_INT_INFO_TYPE_SW_XCPT;
696 if (fFlags & IEM_XCPT_FLAGS_ICEBP_INSTR)
697 return VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT;
698 return VMX_EXIT_INT_INFO_TYPE_SW_INT;
699 }
700
701 Assert(fFlags & IEM_XCPT_FLAGS_T_EXT_INT);
702 return VMX_EXIT_INT_INFO_TYPE_EXT_INT;
703}
704
705
706/**
707 * Determines whether the guest is using PAE paging given the VMCS.
708 *
709 * @returns @c true if PAE paging mode is used, @c false otherwise.
710 * @param pVmcs Pointer to the virtual VMCS.
711 */
712DECL_FORCE_INLINE(bool) iemVmxVmcsIsGuestPaePagingEnabled(PCVMXVVMCS pVmcs)
713{
714 return ( !(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST)
715 && (pVmcs->u64GuestCr4.u & X86_CR4_PAE)
716 && (pVmcs->u64GuestCr0.u & X86_CR0_PG));
717}
718
719
720/**
721 * Sets the Exit qualification VMCS field.
722 *
723 * @param pVCpu The cross context virtual CPU structure.
724 * @param u64ExitQual The Exit qualification.
725 */
726DECL_FORCE_INLINE(void) iemVmxVmcsSetExitQual(PVMCPUCC pVCpu, uint64_t u64ExitQual)
727{
728 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64RoExitQual.u = u64ExitQual;
729}
730
731
732/**
733 * Sets the VM-exit interruption information field.
734 *
735 * @param pVCpu The cross context virtual CPU structure.
736 * @param uExitIntInfo The VM-exit interruption information.
737 */
738DECL_FORCE_INLINE(void) iemVmxVmcsSetExitIntInfo(PVMCPUCC pVCpu, uint32_t uExitIntInfo)
739{
740 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32RoExitIntInfo = uExitIntInfo;
741}
742
743
744/**
745 * Sets the VM-exit interruption error code.
746 *
747 * @param pVCpu The cross context virtual CPU structure.
748 * @param uErrCode The error code.
749 */
750DECL_FORCE_INLINE(void) iemVmxVmcsSetExitIntErrCode(PVMCPUCC pVCpu, uint32_t uErrCode)
751{
752 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32RoExitIntErrCode = uErrCode;
753}
754
755
756/**
757 * Sets the IDT-vectoring information field.
758 *
759 * @param pVCpu The cross context virtual CPU structure.
760 * @param uIdtVectorInfo The IDT-vectoring information.
761 */
762DECL_FORCE_INLINE(void) iemVmxVmcsSetIdtVectoringInfo(PVMCPUCC pVCpu, uint32_t uIdtVectorInfo)
763{
764 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32RoIdtVectoringInfo = uIdtVectorInfo;
765}
766
767
768/**
769 * Sets the IDT-vectoring error code field.
770 *
771 * @param pVCpu The cross context virtual CPU structure.
772 * @param uErrCode The error code.
773 */
774DECL_FORCE_INLINE(void) iemVmxVmcsSetIdtVectoringErrCode(PVMCPUCC pVCpu, uint32_t uErrCode)
775{
776 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32RoIdtVectoringErrCode = uErrCode;
777}
778
779
780/**
781 * Sets the VM-exit guest-linear address VMCS field.
782 *
783 * @param pVCpu The cross context virtual CPU structure.
784 * @param uGuestLinearAddr The VM-exit guest-linear address.
785 */
786DECL_FORCE_INLINE(void) iemVmxVmcsSetExitGuestLinearAddr(PVMCPUCC pVCpu, uint64_t uGuestLinearAddr)
787{
788 /* Bits 63:32 of guest-linear address MBZ if the guest isn't in long mode prior to the VM-exit. */
789 Assert(CPUMIsGuestInLongModeEx(IEM_GET_CTX(pVCpu)) || !(uGuestLinearAddr & UINT64_C(0xffffffff00000000)));
790 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64RoGuestLinearAddr.u = uGuestLinearAddr;
791}
792
793
794/**
795 * Sets the VM-exit guest-physical address VMCS field.
796 *
797 * @param pVCpu The cross context virtual CPU structure.
798 * @param uGuestPhysAddr The VM-exit guest-physical address.
799 */
800DECL_FORCE_INLINE(void) iemVmxVmcsSetExitGuestPhysAddr(PVMCPUCC pVCpu, uint64_t uGuestPhysAddr)
801{
802 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64RoGuestPhysAddr.u = uGuestPhysAddr;
803}
804
805
806/**
807 * Sets the VM-exit instruction length VMCS field.
808 *
809 * @param pVCpu The cross context virtual CPU structure.
810 * @param cbInstr The VM-exit instruction length in bytes.
811 *
812 * @remarks Callers may clear this field to 0. Hence, this function does not check
813 * the validity of the instruction length.
814 */
815DECL_FORCE_INLINE(void) iemVmxVmcsSetExitInstrLen(PVMCPUCC pVCpu, uint32_t cbInstr)
816{
817 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32RoExitInstrLen = cbInstr;
818}
819
820
821/**
822 * Sets the VM-exit instruction info. VMCS field.
823 *
824 * @param pVCpu The cross context virtual CPU structure.
825 * @param uExitInstrInfo The VM-exit instruction information.
826 */
827DECL_FORCE_INLINE(void) iemVmxVmcsSetExitInstrInfo(PVMCPUCC pVCpu, uint32_t uExitInstrInfo)
828{
829 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32RoExitInstrInfo = uExitInstrInfo;
830}
831
832
833/**
834 * Sets the guest pending-debug exceptions field.
835 *
836 * @param pVCpu The cross context virtual CPU structure.
837 * @param uGuestPendingDbgXcpts The guest pending-debug exceptions.
838 */
839DECL_FORCE_INLINE(void) iemVmxVmcsSetGuestPendingDbgXcpts(PVMCPUCC pVCpu, uint64_t uGuestPendingDbgXcpts)
840{
841 Assert(!(uGuestPendingDbgXcpts & VMX_VMCS_GUEST_PENDING_DEBUG_VALID_MASK));
842 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64GuestPendingDbgXcpts.u = uGuestPendingDbgXcpts;
843}
844
845
846/**
847 * Implements VMSucceed for VMX instruction success.
848 *
849 * @param pVCpu The cross context virtual CPU structure.
850 */
851DECL_FORCE_INLINE(void) iemVmxVmSucceed(PVMCPUCC pVCpu)
852{
853 return CPUMSetGuestVmxVmSucceed(&pVCpu->cpum.GstCtx);
854}
855
856
857/**
858 * Implements VMFailInvalid for VMX instruction failure.
859 *
860 * @param pVCpu The cross context virtual CPU structure.
861 */
862DECL_FORCE_INLINE(void) iemVmxVmFailInvalid(PVMCPUCC pVCpu)
863{
864 return CPUMSetGuestVmxVmFailInvalid(&pVCpu->cpum.GstCtx);
865}
866
867
868/**
869 * Implements VMFail for VMX instruction failure.
870 *
871 * @param pVCpu The cross context virtual CPU structure.
872 * @param enmInsErr The VM instruction error.
873 */
874DECL_FORCE_INLINE(void) iemVmxVmFail(PVMCPUCC pVCpu, VMXINSTRERR enmInsErr)
875{
876 return CPUMSetGuestVmxVmFail(&pVCpu->cpum.GstCtx, enmInsErr);
877}
878
879
880/**
881 * Checks if the given auto-load/store MSR area count is valid for the
882 * implementation.
883 *
884 * @returns @c true if it's within the valid limit, @c false otherwise.
885 * @param pVCpu The cross context virtual CPU structure.
886 * @param uMsrCount The MSR area count to check.
887 */
888DECL_FORCE_INLINE(bool) iemVmxIsAutoMsrCountValid(PCVMCPU pVCpu, uint32_t uMsrCount)
889{
890 uint64_t const u64VmxMiscMsr = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Misc;
891 uint32_t const cMaxSupportedMsrs = VMX_MISC_MAX_MSRS(u64VmxMiscMsr);
892 Assert(cMaxSupportedMsrs <= VMX_V_AUTOMSR_AREA_SIZE / sizeof(VMXAUTOMSR));
893 if (uMsrCount <= cMaxSupportedMsrs)
894 return true;
895 return false;
896}
897
898
899/**
900 * Flushes the current VMCS contents back to guest memory.
901 *
902 * @returns VBox status code.
903 * @param pVCpu The cross context virtual CPU structure.
904 */
905DECL_FORCE_INLINE(int) iemVmxWriteCurrentVmcsToGstMem(PVMCPUCC pVCpu)
906{
907 Assert(IEM_VMX_HAS_CURRENT_VMCS(pVCpu));
908 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), IEM_VMX_GET_CURRENT_VMCS(pVCpu),
909 &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs, sizeof(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs));
910 return rc;
911}
912
913
914/**
915 * Populates the current VMCS contents from guest memory.
916 *
917 * @returns VBox status code.
918 * @param pVCpu The cross context virtual CPU structure.
919 */
920DECL_FORCE_INLINE(int) iemVmxReadCurrentVmcsFromGstMem(PVMCPUCC pVCpu)
921{
922 Assert(IEM_VMX_HAS_CURRENT_VMCS(pVCpu));
923 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs,
924 IEM_VMX_GET_CURRENT_VMCS(pVCpu), sizeof(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs));
925 return rc;
926}
927
928
929/**
930 * Gets the instruction diagnostic for segment base checks during VM-entry of a
931 * nested-guest.
932 *
933 * @param iSegReg The segment index (X86_SREG_XXX).
934 */
935IEM_STATIC VMXVDIAG iemVmxGetDiagVmentrySegBase(unsigned iSegReg)
936{
937 switch (iSegReg)
938 {
939 case X86_SREG_CS: return kVmxVDiag_Vmentry_GuestSegBaseCs;
940 case X86_SREG_DS: return kVmxVDiag_Vmentry_GuestSegBaseDs;
941 case X86_SREG_ES: return kVmxVDiag_Vmentry_GuestSegBaseEs;
942 case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegBaseFs;
943 case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegBaseGs;
944 case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegBaseSs;
945 IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_1);
946 }
947}
948
949
950/**
951 * Gets the instruction diagnostic for segment base checks during VM-entry of a
952 * nested-guest that is in Virtual-8086 mode.
953 *
954 * @param iSegReg The segment index (X86_SREG_XXX).
955 */
956IEM_STATIC VMXVDIAG iemVmxGetDiagVmentrySegBaseV86(unsigned iSegReg)
957{
958 switch (iSegReg)
959 {
960 case X86_SREG_CS: return kVmxVDiag_Vmentry_GuestSegBaseV86Cs;
961 case X86_SREG_DS: return kVmxVDiag_Vmentry_GuestSegBaseV86Ds;
962 case X86_SREG_ES: return kVmxVDiag_Vmentry_GuestSegBaseV86Es;
963 case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegBaseV86Fs;
964 case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegBaseV86Gs;
965 case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegBaseV86Ss;
966 IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_2);
967 }
968}
969
970
971/**
972 * Gets the instruction diagnostic for segment limit checks during VM-entry of a
973 * nested-guest that is in Virtual-8086 mode.
974 *
975 * @param iSegReg The segment index (X86_SREG_XXX).
976 */
977IEM_STATIC VMXVDIAG iemVmxGetDiagVmentrySegLimitV86(unsigned iSegReg)
978{
979 switch (iSegReg)
980 {
981 case X86_SREG_CS: return kVmxVDiag_Vmentry_GuestSegLimitV86Cs;
982 case X86_SREG_DS: return kVmxVDiag_Vmentry_GuestSegLimitV86Ds;
983 case X86_SREG_ES: return kVmxVDiag_Vmentry_GuestSegLimitV86Es;
984 case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegLimitV86Fs;
985 case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegLimitV86Gs;
986 case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegLimitV86Ss;
987 IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_3);
988 }
989}
990
991
992/**
993 * Gets the instruction diagnostic for segment attribute checks during VM-entry of a
994 * nested-guest that is in Virtual-8086 mode.
995 *
996 * @param iSegReg The segment index (X86_SREG_XXX).
997 */
998IEM_STATIC VMXVDIAG iemVmxGetDiagVmentrySegAttrV86(unsigned iSegReg)
999{
1000 switch (iSegReg)
1001 {
1002 case X86_SREG_CS: return kVmxVDiag_Vmentry_GuestSegAttrV86Cs;
1003 case X86_SREG_DS: return kVmxVDiag_Vmentry_GuestSegAttrV86Ds;
1004 case X86_SREG_ES: return kVmxVDiag_Vmentry_GuestSegAttrV86Es;
1005 case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrV86Fs;
1006 case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrV86Gs;
1007 case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrV86Ss;
1008 IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_4);
1009 }
1010}
1011
1012
1013/**
1014 * Gets the instruction diagnostic for segment attributes reserved bits failure
1015 * during VM-entry of a nested-guest.
1016 *
1017 * @param iSegReg The segment index (X86_SREG_XXX).
1018 */
1019IEM_STATIC VMXVDIAG iemVmxGetDiagVmentrySegAttrRsvd(unsigned iSegReg)
1020{
1021 switch (iSegReg)
1022 {
1023 case X86_SREG_CS: return kVmxVDiag_Vmentry_GuestSegAttrRsvdCs;
1024 case X86_SREG_DS: return kVmxVDiag_Vmentry_GuestSegAttrRsvdDs;
1025 case X86_SREG_ES: return kVmxVDiag_Vmentry_GuestSegAttrRsvdEs;
1026 case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrRsvdFs;
1027 case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrRsvdGs;
1028 case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrRsvdSs;
1029 IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_5);
1030 }
1031}
1032
1033
1034/**
1035 * Gets the instruction diagnostic for segment attributes descriptor-type
1036 * (code/segment or system) failure during VM-entry of a nested-guest.
1037 *
1038 * @param iSegReg The segment index (X86_SREG_XXX).
1039 */
1040IEM_STATIC VMXVDIAG iemVmxGetDiagVmentrySegAttrDescType(unsigned iSegReg)
1041{
1042 switch (iSegReg)
1043 {
1044 case X86_SREG_CS: return kVmxVDiag_Vmentry_GuestSegAttrDescTypeCs;
1045 case X86_SREG_DS: return kVmxVDiag_Vmentry_GuestSegAttrDescTypeDs;
1046 case X86_SREG_ES: return kVmxVDiag_Vmentry_GuestSegAttrDescTypeEs;
1047 case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrDescTypeFs;
1048 case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrDescTypeGs;
1049 case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrDescTypeSs;
1050 IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_6);
1051 }
1052}
1053
1054
1055/**
1056 * Gets the instruction diagnostic for segment attributes descriptor-type
1057 * (code/segment or system) failure during VM-entry of a nested-guest.
1058 *
1059 * @param iSegReg The segment index (X86_SREG_XXX).
1060 */
1061IEM_STATIC VMXVDIAG iemVmxGetDiagVmentrySegAttrPresent(unsigned iSegReg)
1062{
1063 switch (iSegReg)
1064 {
1065 case X86_SREG_CS: return kVmxVDiag_Vmentry_GuestSegAttrPresentCs;
1066 case X86_SREG_DS: return kVmxVDiag_Vmentry_GuestSegAttrPresentDs;
1067 case X86_SREG_ES: return kVmxVDiag_Vmentry_GuestSegAttrPresentEs;
1068 case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrPresentFs;
1069 case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrPresentGs;
1070 case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrPresentSs;
1071 IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_7);
1072 }
1073}
1074
1075
1076/**
1077 * Gets the instruction diagnostic for segment attribute granularity failure during
1078 * VM-entry of a nested-guest.
1079 *
1080 * @param iSegReg The segment index (X86_SREG_XXX).
1081 */
1082IEM_STATIC VMXVDIAG iemVmxGetDiagVmentrySegAttrGran(unsigned iSegReg)
1083{
1084 switch (iSegReg)
1085 {
1086 case X86_SREG_CS: return kVmxVDiag_Vmentry_GuestSegAttrGranCs;
1087 case X86_SREG_DS: return kVmxVDiag_Vmentry_GuestSegAttrGranDs;
1088 case X86_SREG_ES: return kVmxVDiag_Vmentry_GuestSegAttrGranEs;
1089 case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrGranFs;
1090 case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrGranGs;
1091 case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrGranSs;
1092 IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_8);
1093 }
1094}
1095
1096/**
1097 * Gets the instruction diagnostic for segment attribute DPL/RPL failure during
1098 * VM-entry of a nested-guest.
1099 *
1100 * @param iSegReg The segment index (X86_SREG_XXX).
1101 */
1102IEM_STATIC VMXVDIAG iemVmxGetDiagVmentrySegAttrDplRpl(unsigned iSegReg)
1103{
1104 switch (iSegReg)
1105 {
1106 case X86_SREG_CS: return kVmxVDiag_Vmentry_GuestSegAttrDplRplCs;
1107 case X86_SREG_DS: return kVmxVDiag_Vmentry_GuestSegAttrDplRplDs;
1108 case X86_SREG_ES: return kVmxVDiag_Vmentry_GuestSegAttrDplRplEs;
1109 case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrDplRplFs;
1110 case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrDplRplGs;
1111 case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrDplRplSs;
1112 IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_9);
1113 }
1114}
1115
1116
1117/**
1118 * Gets the instruction diagnostic for segment attribute type accessed failure
1119 * during VM-entry of a nested-guest.
1120 *
1121 * @param iSegReg The segment index (X86_SREG_XXX).
1122 */
1123IEM_STATIC VMXVDIAG iemVmxGetDiagVmentrySegAttrTypeAcc(unsigned iSegReg)
1124{
1125 switch (iSegReg)
1126 {
1127 case X86_SREG_CS: return kVmxVDiag_Vmentry_GuestSegAttrTypeAccCs;
1128 case X86_SREG_DS: return kVmxVDiag_Vmentry_GuestSegAttrTypeAccDs;
1129 case X86_SREG_ES: return kVmxVDiag_Vmentry_GuestSegAttrTypeAccEs;
1130 case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrTypeAccFs;
1131 case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrTypeAccGs;
1132 case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrTypeAccSs;
1133 IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_10);
1134 }
1135}
1136
1137
1138/**
1139 * Saves the guest control registers, debug registers and some MSRs are part of
1140 * VM-exit.
1141 *
1142 * @param pVCpu The cross context virtual CPU structure.
1143 */
1144IEM_STATIC void iemVmxVmexitSaveGuestControlRegsMsrs(PVMCPUCC pVCpu)
1145{
1146 /*
1147 * Saves the guest control registers, debug registers and some MSRs.
1148 * See Intel spec. 27.3.1 "Saving Control Registers, Debug Registers and MSRs".
1149 */
1150 PVMXVVMCS pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
1151
1152 /* Save control registers. */
1153 pVmcs->u64GuestCr0.u = pVCpu->cpum.GstCtx.cr0;
1154 pVmcs->u64GuestCr3.u = pVCpu->cpum.GstCtx.cr3;
1155 pVmcs->u64GuestCr4.u = pVCpu->cpum.GstCtx.cr4;
1156
1157 /* Save SYSENTER CS, ESP, EIP. */
1158 pVmcs->u32GuestSysenterCS = pVCpu->cpum.GstCtx.SysEnter.cs;
1159 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
1160 {
1161 pVmcs->u64GuestSysenterEsp.u = pVCpu->cpum.GstCtx.SysEnter.esp;
1162 pVmcs->u64GuestSysenterEip.u = pVCpu->cpum.GstCtx.SysEnter.eip;
1163 }
1164 else
1165 {
1166 pVmcs->u64GuestSysenterEsp.s.Lo = pVCpu->cpum.GstCtx.SysEnter.esp;
1167 pVmcs->u64GuestSysenterEip.s.Lo = pVCpu->cpum.GstCtx.SysEnter.eip;
1168 }
1169
1170 /* Save debug registers (DR7 and IA32_DEBUGCTL MSR). */
1171 if (pVmcs->u32ExitCtls & VMX_EXIT_CTLS_SAVE_DEBUG)
1172 {
1173 pVmcs->u64GuestDr7.u = pVCpu->cpum.GstCtx.dr[7];
1174 /** @todo NSTVMX: Support IA32_DEBUGCTL MSR */
1175 }
1176
1177 /* Save PAT MSR. */
1178 if (pVmcs->u32ExitCtls & VMX_EXIT_CTLS_SAVE_PAT_MSR)
1179 pVmcs->u64GuestPatMsr.u = pVCpu->cpum.GstCtx.msrPAT;
1180
1181 /* Save EFER MSR. */
1182 if (pVmcs->u32ExitCtls & VMX_EXIT_CTLS_SAVE_EFER_MSR)
1183 pVmcs->u64GuestEferMsr.u = pVCpu->cpum.GstCtx.msrEFER;
1184
1185 /* We don't support clearing IA32_BNDCFGS MSR yet. */
1186 Assert(!(pVmcs->u32ExitCtls & VMX_EXIT_CTLS_CLEAR_BNDCFGS_MSR));
1187
1188 /* Nothing to do for SMBASE register - We don't support SMM yet. */
1189}
1190
1191
1192/**
1193 * Saves the guest force-flags in preparation of entering the nested-guest.
1194 *
1195 * @param pVCpu The cross context virtual CPU structure.
1196 */
1197IEM_STATIC void iemVmxVmentrySaveNmiBlockingFF(PVMCPUCC pVCpu)
1198{
1199 /* We shouldn't be called multiple times during VM-entry. */
1200 Assert(pVCpu->cpum.GstCtx.hwvirt.fLocalForcedActions == 0);
1201
1202 /* MTF should not be set outside VMX non-root mode. */
1203 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF));
1204
1205 /*
1206 * Preserve the required force-flags.
1207 *
1208 * We cache and clear force-flags that would affect the execution of the
1209 * nested-guest. Cached flags are then restored while returning to the guest
1210 * if necessary.
1211 *
1212 * - VMCPU_FF_INHIBIT_INTERRUPTS need not be cached as it only affects
1213 * interrupts until the completion of the current VMLAUNCH/VMRESUME
1214 * instruction. Interrupt inhibition for any nested-guest instruction
1215 * is supplied by the guest-interruptibility state VMCS field and will
1216 * be set up as part of loading the guest state.
1217 *
1218 * - VMCPU_FF_BLOCK_NMIS needs to be cached as VM-exits caused before
1219 * successful VM-entry (due to invalid guest-state) need to continue
1220 * blocking NMIs if it was in effect before VM-entry.
1221 *
1222 * - MTF need not be preserved as it's used only in VMX non-root mode and
1223 * is supplied through the VM-execution controls.
1224 *
1225 * The remaining FFs (e.g. timers, APIC updates) can stay in place so that
1226 * we will be able to generate interrupts that may cause VM-exits for
1227 * the nested-guest.
1228 */
1229 pVCpu->cpum.GstCtx.hwvirt.fLocalForcedActions = pVCpu->fLocalForcedActions & VMCPU_FF_BLOCK_NMIS;
1230}
1231
1232
1233/**
1234 * Restores the guest force-flags in preparation of exiting the nested-guest.
1235 *
1236 * @param pVCpu The cross context virtual CPU structure.
1237 */
1238IEM_STATIC void iemVmxVmexitRestoreNmiBlockingFF(PVMCPUCC pVCpu)
1239{
1240 if (pVCpu->cpum.GstCtx.hwvirt.fLocalForcedActions)
1241 {
1242 VMCPU_FF_SET_MASK(pVCpu, pVCpu->cpum.GstCtx.hwvirt.fLocalForcedActions);
1243 pVCpu->cpum.GstCtx.hwvirt.fLocalForcedActions = 0;
1244 }
1245}
1246
1247
1248/**
1249 * Performs the VMX transition to/from VMX non-root mode.
1250 *
1251 * @param pVCpu The cross context virtual CPU structure.
1252*/
1253IEM_STATIC int iemVmxTransition(PVMCPUCC pVCpu)
1254{
1255 /*
1256 * Inform PGM about paging mode changes.
1257 * We include X86_CR0_PE because PGM doesn't handle paged-real mode yet,
1258 * see comment in iemMemPageTranslateAndCheckAccess().
1259 */
1260 int rc = PGMChangeMode(pVCpu, pVCpu->cpum.GstCtx.cr0 | X86_CR0_PE, pVCpu->cpum.GstCtx.cr4, pVCpu->cpum.GstCtx.msrEFER,
1261 true /* fForce */);
1262 AssertRCReturn(rc, rc);
1263
1264 /* Invalidate IEM TLBs now that we've forced a PGM mode change. */
1265 IEMTlbInvalidateAll(pVCpu, false /*fVmm*/);
1266
1267 /* Inform CPUM (recompiler), can later be removed. */
1268 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_ALL);
1269
1270 /* Re-initialize IEM cache/state after the drastic mode switch. */
1271 iemReInitExec(pVCpu);
1272 return rc;
1273}
1274
1275
1276/**
1277 * Calculates the current VMX-preemption timer value.
1278 *
1279 * @returns The current VMX-preemption timer value.
1280 * @param pVCpu The cross context virtual CPU structure.
1281 */
1282IEM_STATIC uint32_t iemVmxCalcPreemptTimer(PVMCPUCC pVCpu)
1283{
1284 /*
1285 * Assume the following:
1286 * PreemptTimerShift = 5
1287 * VmcsPreemptTimer = 2 (i.e. need to decrement by 1 every 2 * RT_BIT(5) = 20000 TSC ticks)
1288 * EntryTick = 50000 (TSC at time of VM-entry)
1289 *
1290 * CurTick Delta PreemptTimerVal
1291 * ----------------------------------
1292 * 60000 10000 2
1293 * 80000 30000 1
1294 * 90000 40000 0 -> VM-exit.
1295 *
1296 * If Delta >= VmcsPreemptTimer * RT_BIT(PreemptTimerShift) cause a VMX-preemption timer VM-exit.
1297 * The saved VMX-preemption timer value is calculated as follows:
1298 * PreemptTimerVal = VmcsPreemptTimer - (Delta / (VmcsPreemptTimer * RT_BIT(PreemptTimerShift)))
1299 * E.g.:
1300 * Delta = 10000
1301 * Tmp = 10000 / (2 * 10000) = 0.5
1302 * NewPt = 2 - 0.5 = 2
1303 * Delta = 30000
1304 * Tmp = 30000 / (2 * 10000) = 1.5
1305 * NewPt = 2 - 1.5 = 1
1306 * Delta = 40000
1307 * Tmp = 40000 / 20000 = 2
1308 * NewPt = 2 - 2 = 0
1309 */
1310 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_HWVIRT);
1311 uint32_t const uVmcsPreemptVal = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32PreemptTimer;
1312 if (uVmcsPreemptVal > 0)
1313 {
1314 uint64_t const uCurTick = TMCpuTickGetNoCheck(pVCpu);
1315 uint64_t const uEntryTick = pVCpu->cpum.GstCtx.hwvirt.vmx.uEntryTick;
1316 uint64_t const uDelta = uCurTick - uEntryTick;
1317 uint32_t const uPreemptTimer = uVmcsPreemptVal
1318 - ASMDivU64ByU32RetU32(uDelta, uVmcsPreemptVal * RT_BIT(VMX_V_PREEMPT_TIMER_SHIFT));
1319 return uPreemptTimer;
1320 }
1321 return 0;
1322}
1323
1324
1325/**
1326 * Saves guest segment registers, GDTR, IDTR, LDTR, TR as part of VM-exit.
1327 *
1328 * @param pVCpu The cross context virtual CPU structure.
1329 */
1330IEM_STATIC void iemVmxVmexitSaveGuestSegRegs(PVMCPUCC pVCpu)
1331{
1332 /*
1333 * Save guest segment registers, GDTR, IDTR, LDTR, TR.
1334 * See Intel spec 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
1335 */
1336 /* CS, SS, ES, DS, FS, GS. */
1337 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
1338 for (unsigned iSegReg = 0; iSegReg < X86_SREG_COUNT; iSegReg++)
1339 {
1340 PCCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
1341 if (!pSelReg->Attr.n.u1Unusable)
1342 iemVmxVmcsSetGuestSegReg(pVmcs, iSegReg, pSelReg);
1343 else
1344 {
1345 /*
1346 * For unusable segments the attributes are undefined except for CS and SS.
1347 * For the rest we don't bother preserving anything but the unusable bit.
1348 */
1349 switch (iSegReg)
1350 {
1351 case X86_SREG_CS:
1352 pVmcs->GuestCs = pSelReg->Sel;
1353 pVmcs->u64GuestCsBase.u = pSelReg->u64Base;
1354 pVmcs->u32GuestCsLimit = pSelReg->u32Limit;
1355 pVmcs->u32GuestCsAttr = pSelReg->Attr.u & ( X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
1356 | X86DESCATTR_UNUSABLE);
1357 break;
1358
1359 case X86_SREG_SS:
1360 pVmcs->GuestSs = pSelReg->Sel;
1361 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
1362 pVmcs->u64GuestSsBase.u &= UINT32_C(0xffffffff);
1363 pVmcs->u32GuestSsAttr = pSelReg->Attr.u & (X86DESCATTR_DPL | X86DESCATTR_UNUSABLE);
1364 break;
1365
1366 case X86_SREG_DS:
1367 pVmcs->GuestDs = pSelReg->Sel;
1368 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
1369 pVmcs->u64GuestDsBase.u &= UINT32_C(0xffffffff);
1370 pVmcs->u32GuestDsAttr = X86DESCATTR_UNUSABLE;
1371 break;
1372
1373 case X86_SREG_ES:
1374 pVmcs->GuestEs = pSelReg->Sel;
1375 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
1376 pVmcs->u64GuestEsBase.u &= UINT32_C(0xffffffff);
1377 pVmcs->u32GuestEsAttr = X86DESCATTR_UNUSABLE;
1378 break;
1379
1380 case X86_SREG_FS:
1381 pVmcs->GuestFs = pSelReg->Sel;
1382 pVmcs->u64GuestFsBase.u = pSelReg->u64Base;
1383 pVmcs->u32GuestFsAttr = X86DESCATTR_UNUSABLE;
1384 break;
1385
1386 case X86_SREG_GS:
1387 pVmcs->GuestGs = pSelReg->Sel;
1388 pVmcs->u64GuestGsBase.u = pSelReg->u64Base;
1389 pVmcs->u32GuestGsAttr = X86DESCATTR_UNUSABLE;
1390 break;
1391 }
1392 }
1393 }
1394
1395 /* Segment attribute bits 31:17 and 11:8 MBZ. */
1396 uint32_t const fValidAttrMask = X86DESCATTR_TYPE | X86DESCATTR_DT | X86DESCATTR_DPL | X86DESCATTR_P
1397 | X86DESCATTR_AVL | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
1398 | X86DESCATTR_UNUSABLE;
1399 /* LDTR. */
1400 {
1401 PCCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.ldtr;
1402 pVmcs->GuestLdtr = pSelReg->Sel;
1403 pVmcs->u64GuestLdtrBase.u = pSelReg->u64Base;
1404 Assert(X86_IS_CANONICAL(pSelReg->u64Base));
1405 pVmcs->u32GuestLdtrLimit = pSelReg->u32Limit;
1406 pVmcs->u32GuestLdtrAttr = pSelReg->Attr.u & fValidAttrMask;
1407 }
1408
1409 /* TR. */
1410 {
1411 PCCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.tr;
1412 pVmcs->GuestTr = pSelReg->Sel;
1413 pVmcs->u64GuestTrBase.u = pSelReg->u64Base;
1414 pVmcs->u32GuestTrLimit = pSelReg->u32Limit;
1415 pVmcs->u32GuestTrAttr = pSelReg->Attr.u & fValidAttrMask;
1416 }
1417
1418 /* GDTR. */
1419 pVmcs->u64GuestGdtrBase.u = pVCpu->cpum.GstCtx.gdtr.pGdt;
1420 pVmcs->u32GuestGdtrLimit = pVCpu->cpum.GstCtx.gdtr.cbGdt;
1421
1422 /* IDTR. */
1423 pVmcs->u64GuestIdtrBase.u = pVCpu->cpum.GstCtx.idtr.pIdt;
1424 pVmcs->u32GuestIdtrLimit = pVCpu->cpum.GstCtx.idtr.cbIdt;
1425}
1426
1427
1428/**
1429 * Saves guest non-register state as part of VM-exit.
1430 *
1431 * @param pVCpu The cross context virtual CPU structure.
1432 * @param uExitReason The VM-exit reason.
1433 */
1434IEM_STATIC void iemVmxVmexitSaveGuestNonRegState(PVMCPUCC pVCpu, uint32_t uExitReason)
1435{
1436 /*
1437 * Save guest non-register state.
1438 * See Intel spec. 27.3.4 "Saving Non-Register State".
1439 */
1440 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
1441
1442 /*
1443 * Activity state.
1444 * Most VM-exits will occur in the active state. However, if the first instruction
1445 * following the VM-entry is a HLT instruction, and the MTF VM-execution control is set,
1446 * the VM-exit will be from the HLT activity state.
1447 *
1448 * See Intel spec. 25.5.2 "Monitor Trap Flag".
1449 */
1450 /** @todo NSTVMX: Does triple-fault VM-exit reflect a shutdown activity state or
1451 * not? */
1452 EMSTATE const enmActivityState = EMGetState(pVCpu);
1453 switch (enmActivityState)
1454 {
1455 case EMSTATE_HALTED: pVmcs->u32GuestActivityState = VMX_VMCS_GUEST_ACTIVITY_HLT; break;
1456 default: pVmcs->u32GuestActivityState = VMX_VMCS_GUEST_ACTIVITY_ACTIVE; break;
1457 }
1458
1459 /*
1460 * Interruptibility-state.
1461 */
1462 /* NMI. */
1463 pVmcs->u32GuestIntrState = 0;
1464 if (pVmcs->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
1465 {
1466 if (pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtNmiBlocking)
1467 pVmcs->u32GuestIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
1468 }
1469 else
1470 {
1471 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
1472 pVmcs->u32GuestIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
1473 }
1474
1475 /* Blocking-by-STI. */
1476 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
1477 && pVCpu->cpum.GstCtx.rip == EMGetInhibitInterruptsPC(pVCpu))
1478 {
1479 /** @todo NSTVMX: We can't distinguish between blocking-by-MovSS and blocking-by-STI
1480 * currently. */
1481 pVmcs->u32GuestIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
1482 }
1483 /* Nothing to do for SMI/enclave. We don't support enclaves or SMM yet. */
1484
1485 /*
1486 * Pending debug exceptions.
1487 *
1488 * For VM-exits where it is not applicable, we can safely zero out the field.
1489 * For VM-exits where it is applicable, it's expected to be updated by the caller already.
1490 */
1491 if ( uExitReason != VMX_EXIT_INIT_SIGNAL
1492 && uExitReason != VMX_EXIT_SMI
1493 && uExitReason != VMX_EXIT_ERR_MACHINE_CHECK
1494 && !VMXIsVmexitTrapLike(uExitReason))
1495 {
1496 /** @todo NSTVMX: also must exclude VM-exits caused by debug exceptions when
1497 * block-by-MovSS is in effect. */
1498 pVmcs->u64GuestPendingDbgXcpts.u = 0;
1499 }
1500
1501 /*
1502 * Save the VMX-preemption timer value back into the VMCS if the feature is enabled.
1503 *
1504 * For VMX-preemption timer VM-exits, we should have already written back 0 if the
1505 * feature is supported back into the VMCS, and thus there is nothing further to do here.
1506 */
1507 if ( uExitReason != VMX_EXIT_PREEMPT_TIMER
1508 && (pVmcs->u32ExitCtls & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER))
1509 pVmcs->u32PreemptTimer = iemVmxCalcPreemptTimer(pVCpu);
1510
1511 /*
1512 * PAE PDPTEs.
1513 *
1514 * If EPT is enabled and PAE paging was used at the time of the VM-exit,
1515 * the PDPTEs are saved from the VMCS. Otherwise they're undefined but
1516 * we zero them for consistency.
1517 */
1518 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT)
1519 {
1520 if ( !(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST)
1521 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE)
1522 && (pVCpu->cpum.GstCtx.cr0 & X86_CR0_PG))
1523 {
1524 pVmcs->u64GuestPdpte0.u = pVCpu->cpum.GstCtx.aPaePdpes[0].u;
1525 pVmcs->u64GuestPdpte1.u = pVCpu->cpum.GstCtx.aPaePdpes[1].u;
1526 pVmcs->u64GuestPdpte2.u = pVCpu->cpum.GstCtx.aPaePdpes[2].u;
1527 pVmcs->u64GuestPdpte3.u = pVCpu->cpum.GstCtx.aPaePdpes[3].u;
1528 }
1529 else
1530 {
1531 pVmcs->u64GuestPdpte0.u = 0;
1532 pVmcs->u64GuestPdpte1.u = 0;
1533 pVmcs->u64GuestPdpte2.u = 0;
1534 pVmcs->u64GuestPdpte3.u = 0;
1535 }
1536
1537 /* Clear PGM's copy of the EPT pointer for added safety. */
1538 PGMSetGuestEptPtr(pVCpu, 0 /* uEptPtr */);
1539 }
1540 else
1541 {
1542 pVmcs->u64GuestPdpte0.u = 0;
1543 pVmcs->u64GuestPdpte1.u = 0;
1544 pVmcs->u64GuestPdpte2.u = 0;
1545 pVmcs->u64GuestPdpte3.u = 0;
1546 }
1547}
1548
1549
1550/**
1551 * Saves the guest-state as part of VM-exit.
1552 *
1553 * @returns VBox status code.
1554 * @param pVCpu The cross context virtual CPU structure.
1555 * @param uExitReason The VM-exit reason.
1556 */
1557IEM_STATIC void iemVmxVmexitSaveGuestState(PVMCPUCC pVCpu, uint32_t uExitReason)
1558{
1559 iemVmxVmexitSaveGuestControlRegsMsrs(pVCpu);
1560 iemVmxVmexitSaveGuestSegRegs(pVCpu);
1561
1562 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64GuestRip.u = pVCpu->cpum.GstCtx.rip;
1563 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64GuestRsp.u = pVCpu->cpum.GstCtx.rsp;
1564 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64GuestRFlags.u = pVCpu->cpum.GstCtx.rflags.u; /** @todo NSTVMX: Check RFLAGS.RF handling. */
1565
1566 iemVmxVmexitSaveGuestNonRegState(pVCpu, uExitReason);
1567}
1568
1569
1570/**
1571 * Saves the guest MSRs into the VM-exit MSR-store area as part of VM-exit.
1572 *
1573 * @returns VBox status code.
1574 * @param pVCpu The cross context virtual CPU structure.
1575 * @param uExitReason The VM-exit reason (for diagnostic purposes).
1576 */
1577IEM_STATIC int iemVmxVmexitSaveGuestAutoMsrs(PVMCPUCC pVCpu, uint32_t uExitReason)
1578{
1579 /*
1580 * Save guest MSRs.
1581 * See Intel spec. 27.4 "Saving MSRs".
1582 */
1583 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
1584 const char * const pszFailure = "VMX-abort";
1585
1586 /*
1587 * The VM-exit MSR-store area address need not be a valid guest-physical address if the
1588 * VM-exit MSR-store count is 0. If this is the case, bail early without reading it.
1589 * See Intel spec. 24.7.2 "VM-Exit Controls for MSRs".
1590 */
1591 uint32_t const cMsrs = RT_MIN(pVmcs->u32ExitMsrStoreCount, RT_ELEMENTS(pVCpu->cpum.GstCtx.hwvirt.vmx.aExitMsrStoreArea));
1592 if (!cMsrs)
1593 return VINF_SUCCESS;
1594
1595 /*
1596 * Verify the MSR auto-store count. Physical CPUs can behave unpredictably if the count
1597 * is exceeded including possibly raising #MC exceptions during VMX transition. Our
1598 * implementation causes a VMX-abort followed by a triple-fault.
1599 */
1600 bool const fIsMsrCountValid = iemVmxIsAutoMsrCountValid(pVCpu, cMsrs);
1601 if (fIsMsrCountValid)
1602 { /* likely */ }
1603 else
1604 IEM_VMX_VMEXIT_FAILED_RET(pVCpu, uExitReason, pszFailure, kVmxVDiag_Vmexit_MsrStoreCount);
1605
1606 /*
1607 * Optimization if the nested hypervisor is using the same guest-physical page for both
1608 * the VM-entry MSR-load area as well as the VM-exit MSR store area.
1609 */
1610 PVMXAUTOMSR pMsrArea;
1611 RTGCPHYS const GCPhysVmEntryMsrLoadArea = pVmcs->u64AddrEntryMsrLoad.u;
1612 RTGCPHYS const GCPhysVmExitMsrStoreArea = pVmcs->u64AddrExitMsrStore.u;
1613 if (GCPhysVmEntryMsrLoadArea == GCPhysVmExitMsrStoreArea)
1614 pMsrArea = pVCpu->cpum.GstCtx.hwvirt.vmx.aEntryMsrLoadArea;
1615 else
1616 {
1617 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.aExitMsrStoreArea[0],
1618 GCPhysVmExitMsrStoreArea, cMsrs * sizeof(VMXAUTOMSR));
1619 if (RT_SUCCESS(rc))
1620 pMsrArea = pVCpu->cpum.GstCtx.hwvirt.vmx.aExitMsrStoreArea;
1621 else
1622 {
1623 AssertMsgFailed(("VM-exit: Failed to read MSR auto-store area at %#RGp, rc=%Rrc\n", GCPhysVmExitMsrStoreArea, rc));
1624 IEM_VMX_VMEXIT_FAILED_RET(pVCpu, uExitReason, pszFailure, kVmxVDiag_Vmexit_MsrStorePtrReadPhys);
1625 }
1626 }
1627
1628 /*
1629 * Update VM-exit MSR store area.
1630 */
1631 PVMXAUTOMSR pMsr = pMsrArea;
1632 for (uint32_t idxMsr = 0; idxMsr < cMsrs; idxMsr++, pMsr++)
1633 {
1634 if ( !pMsr->u32Reserved
1635 && pMsr->u32Msr != MSR_IA32_SMBASE
1636 && pMsr->u32Msr >> 8 != MSR_IA32_X2APIC_START >> 8)
1637 {
1638 VBOXSTRICTRC rcStrict = CPUMQueryGuestMsr(pVCpu, pMsr->u32Msr, &pMsr->u64Value);
1639 if (rcStrict == VINF_SUCCESS)
1640 continue;
1641
1642 /*
1643 * If we're in ring-0, we cannot handle returns to ring-3 at this point and continue VM-exit.
1644 * If any nested hypervisor loads MSRs that require ring-3 handling, we cause a VMX-abort
1645 * recording the MSR index in the auxiliary info. field and indicated further by our
1646 * own, specific diagnostic code. Later, we can try implement handling of the MSR in ring-0
1647 * if possible, or come up with a better, generic solution.
1648 */
1649 pVCpu->cpum.GstCtx.hwvirt.vmx.uAbortAux = pMsr->u32Msr;
1650 VMXVDIAG const enmDiag = rcStrict == VINF_CPUM_R3_MSR_READ
1651 ? kVmxVDiag_Vmexit_MsrStoreRing3
1652 : kVmxVDiag_Vmexit_MsrStore;
1653 IEM_VMX_VMEXIT_FAILED_RET(pVCpu, uExitReason, pszFailure, enmDiag);
1654 }
1655 else
1656 {
1657 pVCpu->cpum.GstCtx.hwvirt.vmx.uAbortAux = pMsr->u32Msr;
1658 IEM_VMX_VMEXIT_FAILED_RET(pVCpu, uExitReason, pszFailure, kVmxVDiag_Vmexit_MsrStoreRsvd);
1659 }
1660 }
1661
1662 /*
1663 * Commit the VM-exit MSR store are to guest memory.
1664 */
1665 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVmExitMsrStoreArea, pMsrArea, cMsrs * sizeof(VMXAUTOMSR));
1666 if (RT_SUCCESS(rc))
1667 return VINF_SUCCESS;
1668
1669 NOREF(uExitReason);
1670 NOREF(pszFailure);
1671
1672 AssertMsgFailed(("VM-exit: Failed to write MSR auto-store area at %#RGp, rc=%Rrc\n", GCPhysVmExitMsrStoreArea, rc));
1673 IEM_VMX_VMEXIT_FAILED_RET(pVCpu, uExitReason, pszFailure, kVmxVDiag_Vmexit_MsrStorePtrWritePhys);
1674}
1675
1676
1677/**
1678 * Performs a VMX abort (due to an fatal error during VM-exit).
1679 *
1680 * @returns Strict VBox status code.
1681 * @param pVCpu The cross context virtual CPU structure.
1682 * @param enmAbort The VMX abort reason.
1683 */
1684IEM_STATIC VBOXSTRICTRC iemVmxAbort(PVMCPUCC pVCpu, VMXABORT enmAbort)
1685{
1686 /*
1687 * Perform the VMX abort.
1688 * See Intel spec. 27.7 "VMX Aborts".
1689 */
1690 LogFunc(("enmAbort=%u (%s) -> RESET\n", enmAbort, VMXGetAbortDesc(enmAbort)));
1691
1692 /* We don't support SMX yet. */
1693 pVCpu->cpum.GstCtx.hwvirt.vmx.enmAbort = enmAbort;
1694 if (IEM_VMX_HAS_CURRENT_VMCS(pVCpu))
1695 {
1696 RTGCPHYS const GCPhysVmcs = IEM_VMX_GET_CURRENT_VMCS(pVCpu);
1697 uint32_t const offVmxAbort = RT_UOFFSETOF(VMXVVMCS, enmVmxAbort);
1698 PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVmcs + offVmxAbort, &enmAbort, sizeof(enmAbort));
1699 }
1700
1701 return VINF_EM_TRIPLE_FAULT;
1702}
1703
1704
1705/**
1706 * Loads host control registers, debug registers and MSRs as part of VM-exit.
1707 *
1708 * @param pVCpu The cross context virtual CPU structure.
1709 */
1710IEM_STATIC void iemVmxVmexitLoadHostControlRegsMsrs(PVMCPUCC pVCpu)
1711{
1712 /*
1713 * Load host control registers, debug registers and MSRs.
1714 * See Intel spec. 27.5.1 "Loading Host Control Registers, Debug Registers, MSRs".
1715 */
1716 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
1717 bool const fHostInLongMode = RT_BOOL(pVmcs->u32ExitCtls & VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE);
1718
1719 /* CR0. */
1720 {
1721 /* Bits 63:32, 28:19, 17, 15:6, ET, CD, NW and CR0 fixed bits are not modified. */
1722 uint64_t const uCr0Mb1 = iemVmxGetCr0Fixed0(pVCpu);
1723 uint64_t const uCr0Mb0 = VMX_V_CR0_FIXED1;
1724 uint64_t const fCr0IgnMask = VMX_EXIT_HOST_CR0_IGNORE_MASK | uCr0Mb1 | ~uCr0Mb0;
1725 uint64_t const uHostCr0 = pVmcs->u64HostCr0.u;
1726 uint64_t const uGuestCr0 = pVCpu->cpum.GstCtx.cr0;
1727 uint64_t const uValidHostCr0 = (uHostCr0 & ~fCr0IgnMask) | (uGuestCr0 & fCr0IgnMask);
1728
1729 /* Verify we have not modified CR0 fixed bits in VMX non-root operation. */
1730 Assert((uGuestCr0 & uCr0Mb1) == uCr0Mb1);
1731 Assert((uGuestCr0 & ~uCr0Mb0) == 0);
1732 CPUMSetGuestCR0(pVCpu, uValidHostCr0);
1733 }
1734
1735 /* CR4. */
1736 {
1737 /* CR4 fixed bits are not modified. */
1738 uint64_t const uCr4Mb1 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed0;
1739 uint64_t const uCr4Mb0 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed1;
1740 uint64_t const fCr4IgnMask = uCr4Mb1 | ~uCr4Mb0;
1741 uint64_t const uHostCr4 = pVmcs->u64HostCr4.u;
1742 uint64_t const uGuestCr4 = pVCpu->cpum.GstCtx.cr4;
1743 uint64_t uValidHostCr4 = (uHostCr4 & ~fCr4IgnMask) | (uGuestCr4 & fCr4IgnMask);
1744 if (fHostInLongMode)
1745 uValidHostCr4 |= X86_CR4_PAE;
1746 else
1747 uValidHostCr4 &= ~(uint64_t)X86_CR4_PCIDE;
1748
1749 /* Verify we have not modified CR4 fixed bits in VMX non-root operation. */
1750 Assert((uGuestCr4 & uCr4Mb1) == uCr4Mb1);
1751 Assert((uGuestCr4 & ~uCr4Mb0) == 0);
1752 CPUMSetGuestCR4(pVCpu, uValidHostCr4);
1753 }
1754
1755 /* CR3 (host value validated while checking host-state during VM-entry). */
1756 pVCpu->cpum.GstCtx.cr3 = pVmcs->u64HostCr3.u;
1757
1758 /* DR7. */
1759 pVCpu->cpum.GstCtx.dr[7] = X86_DR7_INIT_VAL;
1760
1761 /** @todo NSTVMX: Support IA32_DEBUGCTL MSR */
1762
1763 /* Save SYSENTER CS, ESP, EIP (host value validated while checking host-state during VM-entry). */
1764 pVCpu->cpum.GstCtx.SysEnter.eip = pVmcs->u64HostSysenterEip.u;
1765 pVCpu->cpum.GstCtx.SysEnter.esp = pVmcs->u64HostSysenterEsp.u;
1766 pVCpu->cpum.GstCtx.SysEnter.cs = pVmcs->u32HostSysenterCs;
1767
1768 /* FS, GS bases are loaded later while we load host segment registers. */
1769
1770 /* EFER MSR (host value validated while checking host-state during VM-entry). */
1771 if (pVmcs->u32ExitCtls & VMX_EXIT_CTLS_LOAD_EFER_MSR)
1772 pVCpu->cpum.GstCtx.msrEFER = pVmcs->u64HostEferMsr.u;
1773 else if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
1774 {
1775 if (fHostInLongMode)
1776 pVCpu->cpum.GstCtx.msrEFER |= (MSR_K6_EFER_LMA | MSR_K6_EFER_LME);
1777 else
1778 pVCpu->cpum.GstCtx.msrEFER &= ~(MSR_K6_EFER_LMA | MSR_K6_EFER_LME);
1779 }
1780
1781 /* We don't support IA32_PERF_GLOBAL_CTRL MSR yet. */
1782
1783 /* PAT MSR (host value is validated while checking host-state during VM-entry). */
1784 if (pVmcs->u32ExitCtls & VMX_EXIT_CTLS_LOAD_PAT_MSR)
1785 pVCpu->cpum.GstCtx.msrPAT = pVmcs->u64HostPatMsr.u;
1786
1787 /* We don't support IA32_BNDCFGS MSR yet. */
1788}
1789
1790
1791/**
1792 * Loads host segment registers, GDTR, IDTR, LDTR and TR as part of VM-exit.
1793 *
1794 * @param pVCpu The cross context virtual CPU structure.
1795 */
1796IEM_STATIC void iemVmxVmexitLoadHostSegRegs(PVMCPUCC pVCpu)
1797{
1798 /*
1799 * Load host segment registers, GDTR, IDTR, LDTR and TR.
1800 * See Intel spec. 27.5.2 "Loading Host Segment and Descriptor-Table Registers".
1801 *
1802 * Warning! Be careful to not touch fields that are reserved by VT-x,
1803 * e.g. segment limit high bits stored in segment attributes (in bits 11:8).
1804 */
1805 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
1806 bool const fHostInLongMode = RT_BOOL(pVmcs->u32ExitCtls & VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE);
1807
1808 /* CS, SS, ES, DS, FS, GS. */
1809 for (unsigned iSegReg = 0; iSegReg < X86_SREG_COUNT; iSegReg++)
1810 {
1811 RTSEL const HostSel = iemVmxVmcsGetHostSelReg(pVmcs, iSegReg);
1812 bool const fUnusable = RT_BOOL(HostSel == 0);
1813 PCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
1814
1815 /* Selector. */
1816 pSelReg->Sel = HostSel;
1817 pSelReg->ValidSel = HostSel;
1818 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
1819
1820 /* Limit. */
1821 pSelReg->u32Limit = 0xffffffff;
1822
1823 /* Base. */
1824 pSelReg->u64Base = 0;
1825
1826 /* Attributes. */
1827 if (iSegReg == X86_SREG_CS)
1828 {
1829 pSelReg->Attr.n.u4Type = X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ | X86_SEL_TYPE_ACCESSED;
1830 pSelReg->Attr.n.u1DescType = 1;
1831 pSelReg->Attr.n.u2Dpl = 0;
1832 pSelReg->Attr.n.u1Present = 1;
1833 pSelReg->Attr.n.u1Long = fHostInLongMode;
1834 pSelReg->Attr.n.u1DefBig = !fHostInLongMode;
1835 pSelReg->Attr.n.u1Granularity = 1;
1836 Assert(!pSelReg->Attr.n.u1Unusable);
1837 Assert(!fUnusable);
1838 }
1839 else
1840 {
1841 pSelReg->Attr.n.u4Type = X86_SEL_TYPE_RW | X86_SEL_TYPE_ACCESSED;
1842 pSelReg->Attr.n.u1DescType = 1;
1843 pSelReg->Attr.n.u2Dpl = 0;
1844 pSelReg->Attr.n.u1Present = 1;
1845 pSelReg->Attr.n.u1DefBig = 1;
1846 pSelReg->Attr.n.u1Granularity = 1;
1847 pSelReg->Attr.n.u1Unusable = fUnusable;
1848 }
1849 }
1850
1851 /* FS base. */
1852 if ( !pVCpu->cpum.GstCtx.fs.Attr.n.u1Unusable
1853 || fHostInLongMode)
1854 {
1855 Assert(X86_IS_CANONICAL(pVmcs->u64HostFsBase.u));
1856 pVCpu->cpum.GstCtx.fs.u64Base = pVmcs->u64HostFsBase.u;
1857 }
1858
1859 /* GS base. */
1860 if ( !pVCpu->cpum.GstCtx.gs.Attr.n.u1Unusable
1861 || fHostInLongMode)
1862 {
1863 Assert(X86_IS_CANONICAL(pVmcs->u64HostGsBase.u));
1864 pVCpu->cpum.GstCtx.gs.u64Base = pVmcs->u64HostGsBase.u;
1865 }
1866
1867 /* TR. */
1868 Assert(X86_IS_CANONICAL(pVmcs->u64HostTrBase.u));
1869 Assert(!pVCpu->cpum.GstCtx.tr.Attr.n.u1Unusable);
1870 pVCpu->cpum.GstCtx.tr.Sel = pVmcs->HostTr;
1871 pVCpu->cpum.GstCtx.tr.ValidSel = pVmcs->HostTr;
1872 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
1873 pVCpu->cpum.GstCtx.tr.u32Limit = X86_SEL_TYPE_SYS_386_TSS_LIMIT_MIN;
1874 pVCpu->cpum.GstCtx.tr.u64Base = pVmcs->u64HostTrBase.u;
1875 pVCpu->cpum.GstCtx.tr.Attr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
1876 pVCpu->cpum.GstCtx.tr.Attr.n.u1DescType = 0;
1877 pVCpu->cpum.GstCtx.tr.Attr.n.u2Dpl = 0;
1878 pVCpu->cpum.GstCtx.tr.Attr.n.u1Present = 1;
1879 pVCpu->cpum.GstCtx.tr.Attr.n.u1DefBig = 0;
1880 pVCpu->cpum.GstCtx.tr.Attr.n.u1Granularity = 0;
1881
1882 /* LDTR (Warning! do not touch the base and limits here). */
1883 pVCpu->cpum.GstCtx.ldtr.Sel = 0;
1884 pVCpu->cpum.GstCtx.ldtr.ValidSel = 0;
1885 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
1886 pVCpu->cpum.GstCtx.ldtr.Attr.u = X86DESCATTR_UNUSABLE;
1887
1888 /* GDTR. */
1889 Assert(X86_IS_CANONICAL(pVmcs->u64HostGdtrBase.u));
1890 pVCpu->cpum.GstCtx.gdtr.pGdt = pVmcs->u64HostGdtrBase.u;
1891 pVCpu->cpum.GstCtx.gdtr.cbGdt = 0xffff;
1892
1893 /* IDTR.*/
1894 Assert(X86_IS_CANONICAL(pVmcs->u64HostIdtrBase.u));
1895 pVCpu->cpum.GstCtx.idtr.pIdt = pVmcs->u64HostIdtrBase.u;
1896 pVCpu->cpum.GstCtx.idtr.cbIdt = 0xffff;
1897}
1898
1899
1900/**
1901 * Loads the host MSRs from the VM-exit MSR-load area as part of VM-exit.
1902 *
1903 * @returns VBox status code.
1904 * @param pVCpu The cross context virtual CPU structure.
1905 * @param uExitReason The VMX instruction name (for logging purposes).
1906 */
1907IEM_STATIC int iemVmxVmexitLoadHostAutoMsrs(PVMCPUCC pVCpu, uint32_t uExitReason)
1908{
1909 /*
1910 * Load host MSRs.
1911 * See Intel spec. 27.6 "Loading MSRs".
1912 */
1913 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
1914 const char * const pszFailure = "VMX-abort";
1915
1916 /*
1917 * The VM-exit MSR-load area address need not be a valid guest-physical address if the
1918 * VM-exit MSR load count is 0. If this is the case, bail early without reading it.
1919 * See Intel spec. 24.7.2 "VM-Exit Controls for MSRs".
1920 */
1921 uint32_t const cMsrs = RT_MIN(pVmcs->u32ExitMsrLoadCount, RT_ELEMENTS(pVCpu->cpum.GstCtx.hwvirt.vmx.aExitMsrLoadArea));
1922 if (!cMsrs)
1923 return VINF_SUCCESS;
1924
1925 /*
1926 * Verify the MSR auto-load count. Physical CPUs can behave unpredictably if the count
1927 * is exceeded including possibly raising #MC exceptions during VMX transition. Our
1928 * implementation causes a VMX-abort followed by a triple-fault.
1929 */
1930 bool const fIsMsrCountValid = iemVmxIsAutoMsrCountValid(pVCpu, cMsrs);
1931 if (fIsMsrCountValid)
1932 { /* likely */ }
1933 else
1934 IEM_VMX_VMEXIT_FAILED_RET(pVCpu, uExitReason, pszFailure, kVmxVDiag_Vmexit_MsrLoadCount);
1935
1936 RTGCPHYS const GCPhysVmExitMsrLoadArea = pVmcs->u64AddrExitMsrLoad.u;
1937 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.aExitMsrLoadArea[0],
1938 GCPhysVmExitMsrLoadArea, cMsrs * sizeof(VMXAUTOMSR));
1939 if (RT_SUCCESS(rc))
1940 {
1941 PCVMXAUTOMSR pMsr = pVCpu->cpum.GstCtx.hwvirt.vmx.aExitMsrLoadArea;
1942 for (uint32_t idxMsr = 0; idxMsr < cMsrs; idxMsr++, pMsr++)
1943 {
1944 if ( !pMsr->u32Reserved
1945 && pMsr->u32Msr != MSR_K8_FS_BASE
1946 && pMsr->u32Msr != MSR_K8_GS_BASE
1947 && pMsr->u32Msr != MSR_K6_EFER
1948 && pMsr->u32Msr != MSR_IA32_SMM_MONITOR_CTL
1949 && pMsr->u32Msr >> 8 != MSR_IA32_X2APIC_START >> 8)
1950 {
1951 VBOXSTRICTRC rcStrict = CPUMSetGuestMsr(pVCpu, pMsr->u32Msr, pMsr->u64Value);
1952 if (rcStrict == VINF_SUCCESS)
1953 continue;
1954
1955 /*
1956 * If we're in ring-0, we cannot handle returns to ring-3 at this point and continue VM-exit.
1957 * If any nested hypervisor loads MSRs that require ring-3 handling, we cause a VMX-abort
1958 * recording the MSR index in the auxiliary info. field and indicated further by our
1959 * own, specific diagnostic code. Later, we can try implement handling of the MSR in ring-0
1960 * if possible, or come up with a better, generic solution.
1961 */
1962 pVCpu->cpum.GstCtx.hwvirt.vmx.uAbortAux = pMsr->u32Msr;
1963 VMXVDIAG const enmDiag = rcStrict == VINF_CPUM_R3_MSR_WRITE
1964 ? kVmxVDiag_Vmexit_MsrLoadRing3
1965 : kVmxVDiag_Vmexit_MsrLoad;
1966 IEM_VMX_VMEXIT_FAILED_RET(pVCpu, uExitReason, pszFailure, enmDiag);
1967 }
1968 else
1969 IEM_VMX_VMEXIT_FAILED_RET(pVCpu, uExitReason, pszFailure, kVmxVDiag_Vmexit_MsrLoadRsvd);
1970 }
1971 }
1972 else
1973 {
1974 AssertMsgFailed(("VM-exit: Failed to read MSR auto-load area at %#RGp, rc=%Rrc\n", GCPhysVmExitMsrLoadArea, rc));
1975 IEM_VMX_VMEXIT_FAILED_RET(pVCpu, uExitReason, pszFailure, kVmxVDiag_Vmexit_MsrLoadPtrReadPhys);
1976 }
1977
1978 NOREF(uExitReason);
1979 NOREF(pszFailure);
1980 return VINF_SUCCESS;
1981}
1982
1983
1984/**
1985 * Loads the host state as part of VM-exit.
1986 *
1987 * @returns Strict VBox status code.
1988 * @param pVCpu The cross context virtual CPU structure.
1989 * @param uExitReason The VM-exit reason (for logging purposes).
1990 */
1991IEM_STATIC VBOXSTRICTRC iemVmxVmexitLoadHostState(PVMCPUCC pVCpu, uint32_t uExitReason)
1992{
1993 /*
1994 * Load host state.
1995 * See Intel spec. 27.5 "Loading Host State".
1996 */
1997 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
1998 bool const fHostInLongMode = RT_BOOL(pVmcs->u32ExitCtls & VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE);
1999
2000 /* We cannot return from a long-mode guest to a host that is not in long mode. */
2001 if ( CPUMIsGuestInLongMode(pVCpu)
2002 && !fHostInLongMode)
2003 {
2004 Log(("VM-exit from long-mode guest to host not in long-mode -> VMX-Abort\n"));
2005 return iemVmxAbort(pVCpu, VMXABORT_HOST_NOT_IN_LONG_MODE);
2006 }
2007
2008 /*
2009 * Check host PAE PDPTEs prior to loading the host state.
2010 * See Intel spec. 26.5.4 "Checking and Loading Host Page-Directory-Pointer-Table Entries".
2011 */
2012 if ( (pVmcs->u64HostCr4.u & X86_CR4_PAE)
2013 && !fHostInLongMode
2014 && ( !CPUMIsGuestInPAEModeEx(&pVCpu->cpum.GstCtx)
2015 || pVmcs->u64HostCr3.u != pVCpu->cpum.GstCtx.cr3))
2016 {
2017 int const rc = PGMGstMapPaePdpesAtCr3(pVCpu, pVmcs->u64HostCr3.u);
2018 if (RT_SUCCESS(rc))
2019 { /* likely*/ }
2020 else
2021 {
2022 IEM_VMX_VMEXIT_FAILED(pVCpu, uExitReason, "VMX-abort", kVmxVDiag_Vmexit_HostPdpte);
2023 return iemVmxAbort(pVCpu, VMXBOART_HOST_PDPTE);
2024 }
2025 }
2026
2027 iemVmxVmexitLoadHostControlRegsMsrs(pVCpu);
2028 iemVmxVmexitLoadHostSegRegs(pVCpu);
2029
2030 /*
2031 * Load host RIP, RSP and RFLAGS.
2032 * See Intel spec. 27.5.3 "Loading Host RIP, RSP and RFLAGS"
2033 */
2034 pVCpu->cpum.GstCtx.rip = pVmcs->u64HostRip.u;
2035 pVCpu->cpum.GstCtx.rsp = pVmcs->u64HostRsp.u;
2036 pVCpu->cpum.GstCtx.rflags.u = X86_EFL_1;
2037
2038 /* Clear address range monitoring. */
2039 EMMonitorWaitClear(pVCpu);
2040
2041 /* Perform the VMX transition (PGM updates). */
2042 VBOXSTRICTRC rcStrict = iemVmxTransition(pVCpu);
2043 if (rcStrict == VINF_SUCCESS)
2044 { /* likely */ }
2045 else if (RT_SUCCESS(rcStrict))
2046 {
2047 Log3(("VM-exit: iemVmxTransition returns %Rrc (uExitReason=%u) -> Setting passup status\n", VBOXSTRICTRC_VAL(rcStrict),
2048 uExitReason));
2049 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
2050 }
2051 else
2052 {
2053 Log3(("VM-exit: iemVmxTransition failed! rc=%Rrc (uExitReason=%u)\n", VBOXSTRICTRC_VAL(rcStrict), uExitReason));
2054 return VBOXSTRICTRC_VAL(rcStrict);
2055 }
2056
2057 Assert(rcStrict == VINF_SUCCESS);
2058
2059 /* Load MSRs from the VM-exit auto-load MSR area. */
2060 int rc = iemVmxVmexitLoadHostAutoMsrs(pVCpu, uExitReason);
2061 if (RT_FAILURE(rc))
2062 {
2063 Log(("VM-exit failed while loading host MSRs -> VMX-Abort\n"));
2064 return iemVmxAbort(pVCpu, VMXABORT_LOAD_HOST_MSR);
2065 }
2066 return VINF_SUCCESS;
2067}
2068
2069
2070/**
2071 * Gets VM-exit instruction information along with any displacement for an
2072 * instruction VM-exit.
2073 *
2074 * @returns The VM-exit instruction information.
2075 * @param pVCpu The cross context virtual CPU structure.
2076 * @param uExitReason The VM-exit reason.
2077 * @param uInstrId The VM-exit instruction identity (VMXINSTRID_XXX).
2078 * @param pGCPtrDisp Where to store the displacement field. Optional, can be
2079 * NULL.
2080 */
2081IEM_STATIC uint32_t iemVmxGetExitInstrInfo(PVMCPUCC pVCpu, uint32_t uExitReason, VMXINSTRID uInstrId, PRTGCPTR pGCPtrDisp)
2082{
2083 RTGCPTR GCPtrDisp;
2084 VMXEXITINSTRINFO ExitInstrInfo;
2085 ExitInstrInfo.u = 0;
2086
2087 /*
2088 * Get and parse the ModR/M byte from our decoded opcodes.
2089 */
2090 uint8_t bRm;
2091 uint8_t const offModRm = pVCpu->iem.s.offModRm;
2092 IEM_MODRM_GET_U8(pVCpu, bRm, offModRm);
2093 if ((bRm & X86_MODRM_MOD_MASK) == (3 << X86_MODRM_MOD_SHIFT))
2094 {
2095 /*
2096 * ModR/M indicates register addressing.
2097 *
2098 * The primary/secondary register operands are reported in the iReg1 or iReg2
2099 * fields depending on whether it is a read/write form.
2100 */
2101 uint8_t idxReg1;
2102 uint8_t idxReg2;
2103 if (!VMXINSTRID_IS_MODRM_PRIMARY_OP_W(uInstrId))
2104 {
2105 idxReg1 = ((bRm >> X86_MODRM_REG_SHIFT) & X86_MODRM_REG_SMASK) | pVCpu->iem.s.uRexReg;
2106 idxReg2 = (bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB;
2107 }
2108 else
2109 {
2110 idxReg1 = (bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB;
2111 idxReg2 = ((bRm >> X86_MODRM_REG_SHIFT) & X86_MODRM_REG_SMASK) | pVCpu->iem.s.uRexReg;
2112 }
2113 ExitInstrInfo.All.u2Scaling = 0;
2114 ExitInstrInfo.All.iReg1 = idxReg1;
2115 ExitInstrInfo.All.u3AddrSize = pVCpu->iem.s.enmEffAddrMode;
2116 ExitInstrInfo.All.fIsRegOperand = 1;
2117 ExitInstrInfo.All.uOperandSize = pVCpu->iem.s.enmEffOpSize;
2118 ExitInstrInfo.All.iSegReg = 0;
2119 ExitInstrInfo.All.iIdxReg = 0;
2120 ExitInstrInfo.All.fIdxRegInvalid = 1;
2121 ExitInstrInfo.All.iBaseReg = 0;
2122 ExitInstrInfo.All.fBaseRegInvalid = 1;
2123 ExitInstrInfo.All.iReg2 = idxReg2;
2124
2125 /* Displacement not applicable for register addressing. */
2126 GCPtrDisp = 0;
2127 }
2128 else
2129 {
2130 /*
2131 * ModR/M indicates memory addressing.
2132 */
2133 uint8_t uScale = 0;
2134 bool fBaseRegValid = false;
2135 bool fIdxRegValid = false;
2136 uint8_t iBaseReg = 0;
2137 uint8_t iIdxReg = 0;
2138 if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_16BIT)
2139 {
2140 /*
2141 * Parse the ModR/M, displacement for 16-bit addressing mode.
2142 * See Intel instruction spec. Table 2-1. "16-Bit Addressing Forms with the ModR/M Byte".
2143 */
2144 uint16_t u16Disp = 0;
2145 uint8_t const offDisp = offModRm + sizeof(bRm);
2146 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)
2147 {
2148 /* Displacement without any registers. */
2149 IEM_DISP_GET_U16(pVCpu, u16Disp, offDisp);
2150 }
2151 else
2152 {
2153 /* Register (index and base). */
2154 switch (bRm & X86_MODRM_RM_MASK)
2155 {
2156 case 0: fBaseRegValid = true; iBaseReg = X86_GREG_xBX; fIdxRegValid = true; iIdxReg = X86_GREG_xSI; break;
2157 case 1: fBaseRegValid = true; iBaseReg = X86_GREG_xBX; fIdxRegValid = true; iIdxReg = X86_GREG_xDI; break;
2158 case 2: fBaseRegValid = true; iBaseReg = X86_GREG_xBP; fIdxRegValid = true; iIdxReg = X86_GREG_xSI; break;
2159 case 3: fBaseRegValid = true; iBaseReg = X86_GREG_xBP; fIdxRegValid = true; iIdxReg = X86_GREG_xDI; break;
2160 case 4: fIdxRegValid = true; iIdxReg = X86_GREG_xSI; break;
2161 case 5: fIdxRegValid = true; iIdxReg = X86_GREG_xDI; break;
2162 case 6: fBaseRegValid = true; iBaseReg = X86_GREG_xBP; break;
2163 case 7: fBaseRegValid = true; iBaseReg = X86_GREG_xBX; break;
2164 }
2165
2166 /* Register + displacement. */
2167 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
2168 {
2169 case 0: break;
2170 case 1: IEM_DISP_GET_S8_SX_U16(pVCpu, u16Disp, offDisp); break;
2171 case 2: IEM_DISP_GET_U16(pVCpu, u16Disp, offDisp); break;
2172 default:
2173 {
2174 /* Register addressing, handled at the beginning. */
2175 AssertMsgFailed(("ModR/M %#x implies register addressing, memory addressing expected!", bRm));
2176 break;
2177 }
2178 }
2179 }
2180
2181 Assert(!uScale); /* There's no scaling/SIB byte for 16-bit addressing. */
2182 GCPtrDisp = (int16_t)u16Disp; /* Sign-extend the displacement. */
2183 }
2184 else if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT)
2185 {
2186 /*
2187 * Parse the ModR/M, SIB, displacement for 32-bit addressing mode.
2188 * See Intel instruction spec. Table 2-2. "32-Bit Addressing Forms with the ModR/M Byte".
2189 */
2190 uint32_t u32Disp = 0;
2191 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
2192 {
2193 /* Displacement without any registers. */
2194 uint8_t const offDisp = offModRm + sizeof(bRm);
2195 IEM_DISP_GET_U32(pVCpu, u32Disp, offDisp);
2196 }
2197 else
2198 {
2199 /* Register (and perhaps scale, index and base). */
2200 uint8_t offDisp = offModRm + sizeof(bRm);
2201 iBaseReg = (bRm & X86_MODRM_RM_MASK);
2202 if (iBaseReg == 4)
2203 {
2204 /* An SIB byte follows the ModR/M byte, parse it. */
2205 uint8_t bSib;
2206 uint8_t const offSib = offModRm + sizeof(bRm);
2207 IEM_SIB_GET_U8(pVCpu, bSib, offSib);
2208
2209 /* A displacement may follow SIB, update its offset. */
2210 offDisp += sizeof(bSib);
2211
2212 /* Get the scale. */
2213 uScale = (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
2214
2215 /* Get the index register. */
2216 iIdxReg = (bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK;
2217 fIdxRegValid = RT_BOOL(iIdxReg != 4);
2218
2219 /* Get the base register. */
2220 iBaseReg = bSib & X86_SIB_BASE_MASK;
2221 fBaseRegValid = true;
2222 if (iBaseReg == 5)
2223 {
2224 if ((bRm & X86_MODRM_MOD_MASK) == 0)
2225 {
2226 /* Mod is 0 implies a 32-bit displacement with no base. */
2227 fBaseRegValid = false;
2228 IEM_DISP_GET_U32(pVCpu, u32Disp, offDisp);
2229 }
2230 else
2231 {
2232 /* Mod is not 0 implies an 8-bit/32-bit displacement (handled below) with an EBP base. */
2233 iBaseReg = X86_GREG_xBP;
2234 }
2235 }
2236 }
2237
2238 /* Register + displacement. */
2239 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
2240 {
2241 case 0: /* Handled above */ break;
2242 case 1: IEM_DISP_GET_S8_SX_U32(pVCpu, u32Disp, offDisp); break;
2243 case 2: IEM_DISP_GET_U32(pVCpu, u32Disp, offDisp); break;
2244 default:
2245 {
2246 /* Register addressing, handled at the beginning. */
2247 AssertMsgFailed(("ModR/M %#x implies register addressing, memory addressing expected!", bRm));
2248 break;
2249 }
2250 }
2251 }
2252
2253 GCPtrDisp = (int32_t)u32Disp; /* Sign-extend the displacement. */
2254 }
2255 else
2256 {
2257 Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT);
2258
2259 /*
2260 * Parse the ModR/M, SIB, displacement for 64-bit addressing mode.
2261 * See Intel instruction spec. 2.2 "IA-32e Mode".
2262 */
2263 uint64_t u64Disp = 0;
2264 bool const fRipRelativeAddr = RT_BOOL((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5);
2265 if (fRipRelativeAddr)
2266 {
2267 /*
2268 * RIP-relative addressing mode.
2269 *
2270 * The displacement is 32-bit signed implying an offset range of +/-2G.
2271 * See Intel instruction spec. 2.2.1.6 "RIP-Relative Addressing".
2272 */
2273 uint8_t const offDisp = offModRm + sizeof(bRm);
2274 IEM_DISP_GET_S32_SX_U64(pVCpu, u64Disp, offDisp);
2275 }
2276 else
2277 {
2278 uint8_t offDisp = offModRm + sizeof(bRm);
2279
2280 /*
2281 * Register (and perhaps scale, index and base).
2282 *
2283 * REX.B extends the most-significant bit of the base register. However, REX.B
2284 * is ignored while determining whether an SIB follows the opcode. Hence, we
2285 * shall OR any REX.B bit -after- inspecting for an SIB byte below.
2286 *
2287 * See Intel instruction spec. Table 2-5. "Special Cases of REX Encodings".
2288 */
2289 iBaseReg = (bRm & X86_MODRM_RM_MASK);
2290 if (iBaseReg == 4)
2291 {
2292 /* An SIB byte follows the ModR/M byte, parse it. Displacement (if any) follows SIB. */
2293 uint8_t bSib;
2294 uint8_t const offSib = offModRm + sizeof(bRm);
2295 IEM_SIB_GET_U8(pVCpu, bSib, offSib);
2296
2297 /* Displacement may follow SIB, update its offset. */
2298 offDisp += sizeof(bSib);
2299
2300 /* Get the scale. */
2301 uScale = (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
2302
2303 /* Get the index. */
2304 iIdxReg = ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) | pVCpu->iem.s.uRexIndex;
2305 fIdxRegValid = RT_BOOL(iIdxReg != 4); /* R12 -can- be used as an index register. */
2306
2307 /* Get the base. */
2308 iBaseReg = (bSib & X86_SIB_BASE_MASK);
2309 fBaseRegValid = true;
2310 if (iBaseReg == 5)
2311 {
2312 if ((bRm & X86_MODRM_MOD_MASK) == 0)
2313 {
2314 /* Mod is 0 implies a signed 32-bit displacement with no base. */
2315 IEM_DISP_GET_S32_SX_U64(pVCpu, u64Disp, offDisp);
2316 }
2317 else
2318 {
2319 /* Mod is non-zero implies an 8-bit/32-bit displacement (handled below) with RBP or R13 as base. */
2320 iBaseReg = pVCpu->iem.s.uRexB ? X86_GREG_x13 : X86_GREG_xBP;
2321 }
2322 }
2323 }
2324 iBaseReg |= pVCpu->iem.s.uRexB;
2325
2326 /* Register + displacement. */
2327 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
2328 {
2329 case 0: /* Handled above */ break;
2330 case 1: IEM_DISP_GET_S8_SX_U64(pVCpu, u64Disp, offDisp); break;
2331 case 2: IEM_DISP_GET_S32_SX_U64(pVCpu, u64Disp, offDisp); break;
2332 default:
2333 {
2334 /* Register addressing, handled at the beginning. */
2335 AssertMsgFailed(("ModR/M %#x implies register addressing, memory addressing expected!", bRm));
2336 break;
2337 }
2338 }
2339 }
2340
2341 GCPtrDisp = fRipRelativeAddr ? pVCpu->cpum.GstCtx.rip + u64Disp : u64Disp;
2342 }
2343
2344 /*
2345 * The primary or secondary register operand is reported in iReg2 depending
2346 * on whether the primary operand is in read/write form.
2347 */
2348 uint8_t idxReg2;
2349 if (!VMXINSTRID_IS_MODRM_PRIMARY_OP_W(uInstrId))
2350 {
2351 idxReg2 = bRm & X86_MODRM_RM_MASK;
2352 if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)
2353 idxReg2 |= pVCpu->iem.s.uRexB;
2354 }
2355 else
2356 {
2357 idxReg2 = (bRm >> X86_MODRM_REG_SHIFT) & X86_MODRM_REG_SMASK;
2358 if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)
2359 idxReg2 |= pVCpu->iem.s.uRexReg;
2360 }
2361 ExitInstrInfo.All.u2Scaling = uScale;
2362 ExitInstrInfo.All.iReg1 = 0; /* Not applicable for memory addressing. */
2363 ExitInstrInfo.All.u3AddrSize = pVCpu->iem.s.enmEffAddrMode;
2364 ExitInstrInfo.All.fIsRegOperand = 0;
2365 ExitInstrInfo.All.uOperandSize = pVCpu->iem.s.enmEffOpSize;
2366 ExitInstrInfo.All.iSegReg = pVCpu->iem.s.iEffSeg;
2367 ExitInstrInfo.All.iIdxReg = iIdxReg;
2368 ExitInstrInfo.All.fIdxRegInvalid = !fIdxRegValid;
2369 ExitInstrInfo.All.iBaseReg = iBaseReg;
2370 ExitInstrInfo.All.iIdxReg = !fBaseRegValid;
2371 ExitInstrInfo.All.iReg2 = idxReg2;
2372 }
2373
2374 /*
2375 * Handle exceptions to the norm for certain instructions.
2376 * (e.g. some instructions convey an instruction identity in place of iReg2).
2377 */
2378 switch (uExitReason)
2379 {
2380 case VMX_EXIT_GDTR_IDTR_ACCESS:
2381 {
2382 Assert(VMXINSTRID_IS_VALID(uInstrId));
2383 Assert(VMXINSTRID_GET_ID(uInstrId) == (uInstrId & 0x3));
2384 ExitInstrInfo.GdtIdt.u2InstrId = VMXINSTRID_GET_ID(uInstrId);
2385 ExitInstrInfo.GdtIdt.u2Undef0 = 0;
2386 break;
2387 }
2388
2389 case VMX_EXIT_LDTR_TR_ACCESS:
2390 {
2391 Assert(VMXINSTRID_IS_VALID(uInstrId));
2392 Assert(VMXINSTRID_GET_ID(uInstrId) == (uInstrId & 0x3));
2393 ExitInstrInfo.LdtTr.u2InstrId = VMXINSTRID_GET_ID(uInstrId);
2394 ExitInstrInfo.LdtTr.u2Undef0 = 0;
2395 break;
2396 }
2397
2398 case VMX_EXIT_RDRAND:
2399 case VMX_EXIT_RDSEED:
2400 {
2401 Assert(ExitInstrInfo.RdrandRdseed.u2OperandSize != 3);
2402 break;
2403 }
2404 }
2405
2406 /* Update displacement and return the constructed VM-exit instruction information field. */
2407 if (pGCPtrDisp)
2408 *pGCPtrDisp = GCPtrDisp;
2409
2410 return ExitInstrInfo.u;
2411}
2412
2413
2414/**
2415 * VMX VM-exit handler.
2416 *
2417 * @returns Strict VBox status code.
2418 * @retval VINF_VMX_VMEXIT when the VM-exit is successful.
2419 * @retval VINF_EM_TRIPLE_FAULT when VM-exit is unsuccessful and leads to a
2420 * triple-fault.
2421 *
2422 * @param pVCpu The cross context virtual CPU structure.
2423 * @param uExitReason The VM-exit reason.
2424 * @param u64ExitQual The Exit qualification.
2425 *
2426 * @remarks We need not necessarily have completed VM-entry before a VM-exit is
2427 * called. Failures during VM-entry can cause VM-exits as well, so we
2428 * -cannot- assert we're in VMX non-root mode here.
2429 */
2430IEM_STATIC VBOXSTRICTRC iemVmxVmexit(PVMCPUCC pVCpu, uint32_t uExitReason, uint64_t u64ExitQual)
2431{
2432# if defined(VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM) && !defined(IN_RING3)
2433 RT_NOREF3(pVCpu, uExitReason, u64ExitQual);
2434 AssertMsgFailed(("VM-exit should only be invoked from ring-3 when nested-guest executes only in ring-3!\n"));
2435 return VERR_IEM_IPE_7;
2436# else
2437 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
2438
2439 /*
2440 * Import all the guest-CPU state.
2441 *
2442 * HM on returning to guest execution would have to reset up a whole lot of state
2443 * anyway, (e.g., VM-entry/VM-exit controls) and we do not ever import a part of
2444 * the state and flag reloading the entire state on re-entry. So import the entire
2445 * state here, see HMNotifyVmxNstGstVmexit() for more comments.
2446 */
2447 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_ALL);
2448
2449 /*
2450 * Ensure VM-entry interruption information valid bit is cleared.
2451 *
2452 * We do it here on every VM-exit so that even premature VM-exits (e.g. those caused
2453 * by invalid-guest state or machine-check exceptions) also clear this bit.
2454 *
2455 * See Intel spec. 27.2 "Recording VM-exit Information And Updating VM-entry control fields".
2456 */
2457 if (VMX_ENTRY_INT_INFO_IS_VALID(pVmcs->u32EntryIntInfo))
2458 pVmcs->u32EntryIntInfo &= ~VMX_ENTRY_INT_INFO_VALID;
2459
2460 /*
2461 * Update the VM-exit reason and Exit qualification.
2462 * Other VMCS read-only data fields are expected to be updated by the caller already.
2463 */
2464 pVmcs->u32RoExitReason = uExitReason;
2465 pVmcs->u64RoExitQual.u = u64ExitQual;
2466
2467 Log3(("vmexit: reason=%#RX32 qual=%#RX64 cs:rip=%04x:%#RX64 cr0=%#RX64 cr3=%#RX64 cr4=%#RX64\n", uExitReason,
2468 pVmcs->u64RoExitQual.u, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.cr0,
2469 pVCpu->cpum.GstCtx.cr3, pVCpu->cpum.GstCtx.cr4));
2470
2471 /*
2472 * Update the IDT-vectoring information fields if the VM-exit is triggered during delivery of an event.
2473 * See Intel spec. 27.2.4 "Information for VM Exits During Event Delivery".
2474 */
2475 {
2476 uint8_t uVector;
2477 uint32_t fFlags;
2478 uint32_t uErrCode;
2479 bool const fInEventDelivery = IEMGetCurrentXcpt(pVCpu, &uVector, &fFlags, &uErrCode, NULL /* puCr2 */);
2480 if (fInEventDelivery)
2481 {
2482 /*
2483 * A VM-exit is not considered to occur during event delivery when the VM-exit is
2484 * caused by a triple-fault or the original event results in a double-fault that
2485 * causes the VM exit directly (exception bitmap). Therefore, we must not set the
2486 * original event information into the IDT-vectoring information fields.
2487 *
2488 * See Intel spec. 27.2.4 "Information for VM Exits During Event Delivery".
2489 */
2490 if ( uExitReason != VMX_EXIT_TRIPLE_FAULT
2491 && ( uExitReason != VMX_EXIT_XCPT_OR_NMI
2492 || !VMX_EXIT_INT_INFO_IS_XCPT_DF(pVmcs->u32RoExitIntInfo)))
2493 {
2494 uint8_t const uIdtVectoringType = iemVmxGetEventType(uVector, fFlags);
2495 uint8_t const fErrCodeValid = RT_BOOL(fFlags & IEM_XCPT_FLAGS_ERR);
2496 uint32_t const uIdtVectoringInfo = RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VECTOR, uVector)
2497 | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_TYPE, uIdtVectoringType)
2498 | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_ERR_CODE_VALID, fErrCodeValid)
2499 | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VALID, 1);
2500 iemVmxVmcsSetIdtVectoringInfo(pVCpu, uIdtVectoringInfo);
2501 iemVmxVmcsSetIdtVectoringErrCode(pVCpu, uErrCode);
2502 LogFlow(("vmexit: idt_info=%#RX32 idt_err_code=%#RX32 cr2=%#RX64\n", uIdtVectoringInfo, uErrCode,
2503 pVCpu->cpum.GstCtx.cr2));
2504 }
2505 }
2506 }
2507
2508 /* The following VMCS fields should always be zero since we don't support injecting SMIs into a guest. */
2509 Assert(pVmcs->u64RoIoRcx.u == 0);
2510 Assert(pVmcs->u64RoIoRsi.u == 0);
2511 Assert(pVmcs->u64RoIoRdi.u == 0);
2512 Assert(pVmcs->u64RoIoRip.u == 0);
2513
2514 /*
2515 * Save the guest state back into the VMCS.
2516 * We only need to save the state when the VM-entry was successful.
2517 */
2518 bool const fVmentryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
2519 if (!fVmentryFailed)
2520 {
2521 /* We should not cause an NMI-window/interrupt-window VM-exit when injecting events as part of VM-entry. */
2522 if (!CPUMIsGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx))
2523 {
2524 Assert(uExitReason != VMX_EXIT_NMI_WINDOW);
2525 Assert(uExitReason != VMX_EXIT_INT_WINDOW);
2526 }
2527
2528 /* For exception or NMI VM-exits the VM-exit interruption info. field must be valid. */
2529 Assert(uExitReason != VMX_EXIT_XCPT_OR_NMI || VMX_EXIT_INT_INFO_IS_VALID(pVmcs->u32RoExitIntInfo));
2530
2531 /*
2532 * If we support storing EFER.LMA into IA32e-mode guest field on VM-exit, we need to do that now.
2533 * See Intel spec. 27.2 "Recording VM-exit Information And Updating VM-entry Control".
2534 *
2535 * It is not clear from the Intel spec. if this is done only when VM-entry succeeds.
2536 * If a VM-exit happens before loading guest EFER, we risk restoring the host EFER.LMA
2537 * as guest-CPU state would not been modified. Hence for now, we do this only when
2538 * the VM-entry succeeded.
2539 */
2540 /** @todo r=ramshankar: Figure out if this bit gets set to host EFER.LMA on real
2541 * hardware when VM-exit fails during VM-entry (e.g. VERR_VMX_INVALID_GUEST_STATE). */
2542 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxExitSaveEferLma)
2543 {
2544 if (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LMA)
2545 pVmcs->u32EntryCtls |= VMX_ENTRY_CTLS_IA32E_MODE_GUEST;
2546 else
2547 pVmcs->u32EntryCtls &= ~VMX_ENTRY_CTLS_IA32E_MODE_GUEST;
2548 }
2549
2550 /*
2551 * The rest of the high bits of the VM-exit reason are only relevant when the VM-exit
2552 * occurs in enclave mode/SMM which we don't support yet.
2553 *
2554 * If we ever add support for it, we can pass just the lower bits to the functions
2555 * below, till then an assert should suffice.
2556 */
2557 Assert(!RT_HI_U16(uExitReason));
2558
2559 /* Save the guest state into the VMCS and restore guest MSRs from the auto-store guest MSR area. */
2560 iemVmxVmexitSaveGuestState(pVCpu, uExitReason);
2561 int rc = iemVmxVmexitSaveGuestAutoMsrs(pVCpu, uExitReason);
2562 if (RT_SUCCESS(rc))
2563 { /* likely */ }
2564 else
2565 return iemVmxAbort(pVCpu, VMXABORT_SAVE_GUEST_MSRS);
2566
2567 /* Clear any saved NMI-blocking state so we don't assert on next VM-entry (if it was in effect on the previous one). */
2568 pVCpu->cpum.GstCtx.hwvirt.fLocalForcedActions &= ~VMCPU_FF_BLOCK_NMIS;
2569 }
2570 else
2571 {
2572 /* Restore the NMI-blocking state if VM-entry failed due to invalid guest state or while loading MSRs. */
2573 uint32_t const uExitReasonBasic = VMX_EXIT_REASON_BASIC(uExitReason);
2574 if ( uExitReasonBasic == VMX_EXIT_ERR_INVALID_GUEST_STATE
2575 || uExitReasonBasic == VMX_EXIT_ERR_MSR_LOAD)
2576 iemVmxVmexitRestoreNmiBlockingFF(pVCpu);
2577 }
2578
2579 /*
2580 * Stop any running VMX-preemption timer if necessary.
2581 */
2582 if (pVmcs->u32PinCtls & VMX_PIN_CTLS_PREEMPT_TIMER)
2583 CPUMStopGuestVmxPremptTimer(pVCpu);
2584
2585 /*
2586 * Clear any pending VMX nested-guest force-flags.
2587 * These force-flags have no effect on (outer) guest execution and will
2588 * be re-evaluated and setup on the next nested-guest VM-entry.
2589 */
2590 VMCPU_FF_CLEAR_MASK(pVCpu, VMCPU_FF_VMX_ALL_MASK);
2591
2592 /*
2593 * We're no longer in nested-guest execution mode.
2594 *
2595 * It is important to do this prior to loading the host state because
2596 * PGM looks at fInVmxNonRootMode to determine if it needs to perform
2597 * second-level address translation while switching to host CR3.
2598 */
2599 pVCpu->cpum.GstCtx.hwvirt.vmx.fInVmxNonRootMode = false;
2600
2601 /* Restore the host (outer guest) state. */
2602 VBOXSTRICTRC rcStrict = iemVmxVmexitLoadHostState(pVCpu, uExitReason);
2603 if (RT_SUCCESS(rcStrict))
2604 {
2605 Assert(rcStrict == VINF_SUCCESS);
2606 rcStrict = VINF_VMX_VMEXIT;
2607 }
2608 else
2609 Log3(("vmexit: Loading host-state failed. uExitReason=%u rc=%Rrc\n", uExitReason, VBOXSTRICTRC_VAL(rcStrict)));
2610
2611 if (VM_IS_HM_ENABLED(pVCpu->CTX_SUFF(pVM)))
2612 {
2613 /* Notify HM that the current VMCS fields have been modified. */
2614 HMNotifyVmxNstGstCurrentVmcsChanged(pVCpu);
2615
2616 /* Notify HM that we've completed the VM-exit. */
2617 HMNotifyVmxNstGstVmexit(pVCpu);
2618 }
2619
2620# if defined(VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM) && defined(IN_RING3)
2621 /* Revert any IEM-only nested-guest execution policy, otherwise return rcStrict. */
2622 Log(("vmexit: Disabling IEM-only EM execution policy!\n"));
2623 int rcSched = EMR3SetExecutionPolicy(pVCpu->CTX_SUFF(pVM)->pUVM, EMEXECPOLICY_IEM_ALL, false);
2624 if (rcSched != VINF_SUCCESS)
2625 iemSetPassUpStatus(pVCpu, rcSched);
2626# endif
2627 return rcStrict;
2628# endif
2629}
2630
2631
2632/**
2633 * VMX VM-exit handler for VM-exits due to instruction execution.
2634 *
2635 * This is intended for instructions where the caller provides all the relevant
2636 * VM-exit information.
2637 *
2638 * @returns Strict VBox status code.
2639 * @param pVCpu The cross context virtual CPU structure.
2640 * @param pExitInfo Pointer to the VM-exit information.
2641 */
2642IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrWithInfo(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo)
2643{
2644 /*
2645 * For instructions where any of the following fields are not applicable:
2646 * - Exit qualification must be cleared.
2647 * - VM-exit instruction info. is undefined.
2648 * - Guest-linear address is undefined.
2649 * - Guest-physical address is undefined.
2650 *
2651 * The VM-exit instruction length is mandatory for all VM-exits that are caused by
2652 * instruction execution. For VM-exits that are not due to instruction execution this
2653 * field is undefined.
2654 *
2655 * In our implementation in IEM, all undefined fields are generally cleared. However,
2656 * if the caller supplies information (from say the physical CPU directly) it is
2657 * then possible that the undefined fields are not cleared.
2658 *
2659 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
2660 * See Intel spec. 27.2.4 "Information for VM Exits Due to Instruction Execution".
2661 */
2662 Assert(pExitInfo);
2663 AssertMsg(pExitInfo->uReason <= VMX_EXIT_MAX, ("uReason=%u\n", pExitInfo->uReason));
2664 AssertMsg(pExitInfo->cbInstr >= 1 && pExitInfo->cbInstr <= 15,
2665 ("uReason=%u cbInstr=%u\n", pExitInfo->uReason, pExitInfo->cbInstr));
2666
2667 /* Update all the relevant fields from the VM-exit instruction information struct. */
2668 iemVmxVmcsSetExitInstrInfo(pVCpu, pExitInfo->InstrInfo.u);
2669 iemVmxVmcsSetExitGuestLinearAddr(pVCpu, pExitInfo->u64GuestLinearAddr);
2670 iemVmxVmcsSetExitGuestPhysAddr(pVCpu, pExitInfo->u64GuestPhysAddr);
2671 iemVmxVmcsSetExitInstrLen(pVCpu, pExitInfo->cbInstr);
2672
2673 /* Perform the VM-exit. */
2674 return iemVmxVmexit(pVCpu, pExitInfo->uReason, pExitInfo->u64Qual);
2675}
2676
2677
2678/**
2679 * VMX VM-exit handler for VM-exits due to instruction execution.
2680 *
2681 * This is intended for instructions that only provide the VM-exit instruction
2682 * length.
2683 *
2684 * @param pVCpu The cross context virtual CPU structure.
2685 * @param uExitReason The VM-exit reason.
2686 * @param cbInstr The instruction length in bytes.
2687 */
2688IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstr(PVMCPUCC pVCpu, uint32_t uExitReason, uint8_t cbInstr)
2689{
2690 VMXVEXITINFO ExitInfo;
2691 RT_ZERO(ExitInfo);
2692 ExitInfo.uReason = uExitReason;
2693 ExitInfo.cbInstr = cbInstr;
2694
2695#ifdef VBOX_STRICT
2696 /*
2697 * To prevent us from shooting ourselves in the foot.
2698 * The follow instructions should convey more than just the instruction length.
2699 */
2700 switch (uExitReason)
2701 {
2702 case VMX_EXIT_INVEPT:
2703 case VMX_EXIT_INVPCID:
2704 case VMX_EXIT_INVVPID:
2705 case VMX_EXIT_LDTR_TR_ACCESS:
2706 case VMX_EXIT_GDTR_IDTR_ACCESS:
2707 case VMX_EXIT_VMCLEAR:
2708 case VMX_EXIT_VMPTRLD:
2709 case VMX_EXIT_VMPTRST:
2710 case VMX_EXIT_VMREAD:
2711 case VMX_EXIT_VMWRITE:
2712 case VMX_EXIT_VMXON:
2713 case VMX_EXIT_XRSTORS:
2714 case VMX_EXIT_XSAVES:
2715 case VMX_EXIT_RDRAND:
2716 case VMX_EXIT_RDSEED:
2717 case VMX_EXIT_IO_INSTR:
2718 AssertMsgFailedReturn(("Use iemVmxVmexitInstrNeedsInfo for uExitReason=%u\n", uExitReason), VERR_IEM_IPE_5);
2719 break;
2720 }
2721#endif
2722
2723 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
2724}
2725
2726
2727/**
2728 * VMX VM-exit handler for VM-exits due to instruction execution.
2729 *
2730 * This is intended for instructions that have a ModR/M byte and update the VM-exit
2731 * instruction information and Exit qualification fields.
2732 *
2733 * @param pVCpu The cross context virtual CPU structure.
2734 * @param uExitReason The VM-exit reason.
2735 * @param uInstrid The instruction identity (VMXINSTRID_XXX).
2736 * @param cbInstr The instruction length in bytes.
2737 *
2738 * @remarks Do not use this for INS/OUTS instruction.
2739 */
2740IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrNeedsInfo(PVMCPUCC pVCpu, uint32_t uExitReason, VMXINSTRID uInstrId, uint8_t cbInstr)
2741{
2742 VMXVEXITINFO ExitInfo;
2743 RT_ZERO(ExitInfo);
2744 ExitInfo.uReason = uExitReason;
2745 ExitInfo.cbInstr = cbInstr;
2746
2747 /*
2748 * Update the Exit qualification field with displacement bytes.
2749 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
2750 */
2751 switch (uExitReason)
2752 {
2753 case VMX_EXIT_INVEPT:
2754 case VMX_EXIT_INVPCID:
2755 case VMX_EXIT_INVVPID:
2756 case VMX_EXIT_LDTR_TR_ACCESS:
2757 case VMX_EXIT_GDTR_IDTR_ACCESS:
2758 case VMX_EXIT_VMCLEAR:
2759 case VMX_EXIT_VMPTRLD:
2760 case VMX_EXIT_VMPTRST:
2761 case VMX_EXIT_VMREAD:
2762 case VMX_EXIT_VMWRITE:
2763 case VMX_EXIT_VMXON:
2764 case VMX_EXIT_XRSTORS:
2765 case VMX_EXIT_XSAVES:
2766 case VMX_EXIT_RDRAND:
2767 case VMX_EXIT_RDSEED:
2768 {
2769 /* Construct the VM-exit instruction information. */
2770 RTGCPTR GCPtrDisp;
2771 uint32_t const uInstrInfo = iemVmxGetExitInstrInfo(pVCpu, uExitReason, uInstrId, &GCPtrDisp);
2772
2773 /* Update the VM-exit instruction information. */
2774 ExitInfo.InstrInfo.u = uInstrInfo;
2775
2776 /* Update the Exit qualification. */
2777 ExitInfo.u64Qual = GCPtrDisp;
2778 break;
2779 }
2780
2781 default:
2782 AssertMsgFailedReturn(("Use instruction-specific handler\n"), VERR_IEM_IPE_5);
2783 break;
2784 }
2785
2786 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
2787}
2788
2789
2790/**
2791 * VMX VM-exit handler for VM-exits due to INVLPG.
2792 *
2793 * @returns Strict VBox status code.
2794 * @param pVCpu The cross context virtual CPU structure.
2795 * @param GCPtrPage The guest-linear address of the page being invalidated.
2796 * @param cbInstr The instruction length in bytes.
2797 */
2798IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrInvlpg(PVMCPUCC pVCpu, RTGCPTR GCPtrPage, uint8_t cbInstr)
2799{
2800 VMXVEXITINFO ExitInfo;
2801 RT_ZERO(ExitInfo);
2802 ExitInfo.uReason = VMX_EXIT_INVLPG;
2803 ExitInfo.cbInstr = cbInstr;
2804 ExitInfo.u64Qual = GCPtrPage;
2805 Assert(IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode || !RT_HI_U32(ExitInfo.u64Qual));
2806
2807 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
2808}
2809
2810
2811/**
2812 * VMX VM-exit handler for VM-exits due to LMSW.
2813 *
2814 * @returns Strict VBox status code.
2815 * @param pVCpu The cross context virtual CPU structure.
2816 * @param uGuestCr0 The current guest CR0.
2817 * @param pu16NewMsw The machine-status word specified in LMSW's source
2818 * operand. This will be updated depending on the VMX
2819 * guest/host CR0 mask if LMSW is not intercepted.
2820 * @param GCPtrEffDst The guest-linear address of the source operand in case
2821 * of a memory operand. For register operand, pass
2822 * NIL_RTGCPTR.
2823 * @param cbInstr The instruction length in bytes.
2824 */
2825IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrLmsw(PVMCPUCC pVCpu, uint32_t uGuestCr0, uint16_t *pu16NewMsw, RTGCPTR GCPtrEffDst,
2826 uint8_t cbInstr)
2827{
2828 Assert(pu16NewMsw);
2829
2830 uint16_t const uNewMsw = *pu16NewMsw;
2831 if (CPUMIsGuestVmxLmswInterceptSet(&pVCpu->cpum.GstCtx, uNewMsw))
2832 {
2833 Log2(("lmsw: Guest intercept -> VM-exit\n"));
2834
2835 VMXVEXITINFO ExitInfo;
2836 RT_ZERO(ExitInfo);
2837 ExitInfo.uReason = VMX_EXIT_MOV_CRX;
2838 ExitInfo.cbInstr = cbInstr;
2839
2840 bool const fMemOperand = RT_BOOL(GCPtrEffDst != NIL_RTGCPTR);
2841 if (fMemOperand)
2842 {
2843 Assert(IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode || !RT_HI_U32(GCPtrEffDst));
2844 ExitInfo.u64GuestLinearAddr = GCPtrEffDst;
2845 }
2846
2847 ExitInfo.u64Qual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_REGISTER, 0) /* CR0 */
2848 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_ACCESS, VMX_EXIT_QUAL_CRX_ACCESS_LMSW)
2849 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_LMSW_OP, fMemOperand)
2850 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_LMSW_DATA, uNewMsw);
2851
2852 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
2853 }
2854
2855 /*
2856 * If LMSW did not cause a VM-exit, any CR0 bits in the range 0:3 that is set in the
2857 * CR0 guest/host mask must be left unmodified.
2858 *
2859 * See Intel Spec. 25.3 "Changes To Instruction Behavior In VMX Non-root Operation".
2860 */
2861 uint32_t const fGstHostMask = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64Cr0Mask.u;
2862 uint32_t const fGstHostLmswMask = fGstHostMask & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
2863 *pu16NewMsw = (uGuestCr0 & fGstHostLmswMask) | (uNewMsw & ~fGstHostLmswMask);
2864
2865 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
2866}
2867
2868
2869/**
2870 * VMX VM-exit handler for VM-exits due to CLTS.
2871 *
2872 * @returns Strict VBox status code.
2873 * @retval VINF_VMX_MODIFIES_BEHAVIOR if the CLTS instruction did not cause a
2874 * VM-exit but must not modify the guest CR0.TS bit.
2875 * @retval VINF_VMX_INTERCEPT_NOT_ACTIVE if the CLTS instruction did not cause a
2876 * VM-exit and modification to the guest CR0.TS bit is allowed (subject to
2877 * CR0 fixed bits in VMX operation).
2878 * @param pVCpu The cross context virtual CPU structure.
2879 * @param cbInstr The instruction length in bytes.
2880 */
2881IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrClts(PVMCPUCC pVCpu, uint8_t cbInstr)
2882{
2883 uint32_t const fGstHostMask = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64Cr0Mask.u;
2884 uint32_t const fReadShadow = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64Cr0ReadShadow.u;
2885
2886 /*
2887 * If CR0.TS is owned by the host:
2888 * - If CR0.TS is set in the read-shadow, we must cause a VM-exit.
2889 * - If CR0.TS is cleared in the read-shadow, no VM-exit is caused and the
2890 * CLTS instruction completes without clearing CR0.TS.
2891 *
2892 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
2893 */
2894 if (fGstHostMask & X86_CR0_TS)
2895 {
2896 if (fReadShadow & X86_CR0_TS)
2897 {
2898 Log2(("clts: Guest intercept -> VM-exit\n"));
2899
2900 VMXVEXITINFO ExitInfo;
2901 RT_ZERO(ExitInfo);
2902 ExitInfo.uReason = VMX_EXIT_MOV_CRX;
2903 ExitInfo.cbInstr = cbInstr;
2904 ExitInfo.u64Qual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_REGISTER, 0) /* CR0 */
2905 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_ACCESS, VMX_EXIT_QUAL_CRX_ACCESS_CLTS);
2906 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
2907 }
2908
2909 return VINF_VMX_MODIFIES_BEHAVIOR;
2910 }
2911
2912 /*
2913 * If CR0.TS is not owned by the host, the CLTS instructions operates normally
2914 * and may modify CR0.TS (subject to CR0 fixed bits in VMX operation).
2915 */
2916 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
2917}
2918
2919
2920/**
2921 * VMX VM-exit handler for VM-exits due to 'Mov CR0,GReg' and 'Mov CR4,GReg'
2922 * (CR0/CR4 write).
2923 *
2924 * @returns Strict VBox status code.
2925 * @param pVCpu The cross context virtual CPU structure.
2926 * @param iCrReg The control register (either CR0 or CR4).
2927 * @param uGuestCrX The current guest CR0/CR4.
2928 * @param puNewCrX Pointer to the new CR0/CR4 value. Will be updated if no
2929 * VM-exit is caused.
2930 * @param iGReg The general register from which the CR0/CR4 value is being
2931 * loaded.
2932 * @param cbInstr The instruction length in bytes.
2933 */
2934IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrMovToCr0Cr4(PVMCPUCC pVCpu, uint8_t iCrReg, uint64_t *puNewCrX, uint8_t iGReg,
2935 uint8_t cbInstr)
2936{
2937 Assert(puNewCrX);
2938 Assert(iCrReg == 0 || iCrReg == 4);
2939 Assert(iGReg < X86_GREG_COUNT);
2940
2941 uint64_t const uNewCrX = *puNewCrX;
2942 if (CPUMIsGuestVmxMovToCr0Cr4InterceptSet(&pVCpu->cpum.GstCtx, iCrReg, uNewCrX))
2943 {
2944 Log2(("mov_Cr_Rd: (CR%u) Guest intercept -> VM-exit\n", iCrReg));
2945
2946 VMXVEXITINFO ExitInfo;
2947 RT_ZERO(ExitInfo);
2948 ExitInfo.uReason = VMX_EXIT_MOV_CRX;
2949 ExitInfo.cbInstr = cbInstr;
2950 ExitInfo.u64Qual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_REGISTER, iCrReg)
2951 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_ACCESS, VMX_EXIT_QUAL_CRX_ACCESS_WRITE)
2952 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_GENREG, iGReg);
2953 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
2954 }
2955
2956 /*
2957 * If the Mov-to-CR0/CR4 did not cause a VM-exit, any bits owned by the host
2958 * must not be modified the instruction.
2959 *
2960 * See Intel Spec. 25.3 "Changes To Instruction Behavior In VMX Non-root Operation".
2961 */
2962 uint64_t uGuestCrX;
2963 uint64_t fGstHostMask;
2964 if (iCrReg == 0)
2965 {
2966 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
2967 uGuestCrX = pVCpu->cpum.GstCtx.cr0;
2968 fGstHostMask = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64Cr0Mask.u;
2969 }
2970 else
2971 {
2972 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
2973 uGuestCrX = pVCpu->cpum.GstCtx.cr4;
2974 fGstHostMask = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64Cr4Mask.u;
2975 }
2976
2977 *puNewCrX = (uGuestCrX & fGstHostMask) | (*puNewCrX & ~fGstHostMask);
2978 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
2979}
2980
2981
2982/**
2983 * VMX VM-exit handler for VM-exits due to 'Mov GReg,CR3' (CR3 read).
2984 *
2985 * @returns VBox strict status code.
2986 * @param pVCpu The cross context virtual CPU structure.
2987 * @param iGReg The general register to which the CR3 value is being stored.
2988 * @param cbInstr The instruction length in bytes.
2989 */
2990IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrMovFromCr3(PVMCPUCC pVCpu, uint8_t iGReg, uint8_t cbInstr)
2991{
2992 Assert(iGReg < X86_GREG_COUNT);
2993 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
2994
2995 /*
2996 * If the CR3-store exiting control is set, we must cause a VM-exit.
2997 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
2998 */
2999 if (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls & VMX_PROC_CTLS_CR3_STORE_EXIT)
3000 {
3001 Log2(("mov_Rd_Cr: (CR3) Guest intercept -> VM-exit\n"));
3002
3003 VMXVEXITINFO ExitInfo;
3004 RT_ZERO(ExitInfo);
3005 ExitInfo.uReason = VMX_EXIT_MOV_CRX;
3006 ExitInfo.cbInstr = cbInstr;
3007 ExitInfo.u64Qual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_REGISTER, 3) /* CR3 */
3008 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_ACCESS, VMX_EXIT_QUAL_CRX_ACCESS_READ)
3009 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_GENREG, iGReg);
3010 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
3011 }
3012
3013 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3014}
3015
3016
3017/**
3018 * VMX VM-exit handler for VM-exits due to 'Mov CR3,GReg' (CR3 write).
3019 *
3020 * @returns VBox strict status code.
3021 * @param pVCpu The cross context virtual CPU structure.
3022 * @param uNewCr3 The new CR3 value.
3023 * @param iGReg The general register from which the CR3 value is being
3024 * loaded.
3025 * @param cbInstr The instruction length in bytes.
3026 */
3027IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrMovToCr3(PVMCPUCC pVCpu, uint64_t uNewCr3, uint8_t iGReg, uint8_t cbInstr)
3028{
3029 Assert(iGReg < X86_GREG_COUNT);
3030
3031 /*
3032 * If the CR3-load exiting control is set and the new CR3 value does not
3033 * match any of the CR3-target values in the VMCS, we must cause a VM-exit.
3034 *
3035 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
3036 */
3037 if (CPUMIsGuestVmxMovToCr3InterceptSet(pVCpu, uNewCr3))
3038 {
3039 Log2(("mov_Cr_Rd: (CR3) Guest intercept -> VM-exit\n"));
3040
3041 VMXVEXITINFO ExitInfo;
3042 RT_ZERO(ExitInfo);
3043 ExitInfo.uReason = VMX_EXIT_MOV_CRX;
3044 ExitInfo.cbInstr = cbInstr;
3045 ExitInfo.u64Qual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_REGISTER, 3) /* CR3 */
3046 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_ACCESS, VMX_EXIT_QUAL_CRX_ACCESS_WRITE)
3047 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_GENREG, iGReg);
3048 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
3049 }
3050
3051 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3052}
3053
3054
3055/**
3056 * VMX VM-exit handler for VM-exits due to 'Mov GReg,CR8' (CR8 read).
3057 *
3058 * @returns VBox strict status code.
3059 * @param pVCpu The cross context virtual CPU structure.
3060 * @param iGReg The general register to which the CR8 value is being stored.
3061 * @param cbInstr The instruction length in bytes.
3062 */
3063IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrMovFromCr8(PVMCPUCC pVCpu, uint8_t iGReg, uint8_t cbInstr)
3064{
3065 Assert(iGReg < X86_GREG_COUNT);
3066
3067 /*
3068 * If the CR8-store exiting control is set, we must cause a VM-exit.
3069 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
3070 */
3071 if (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls & VMX_PROC_CTLS_CR8_STORE_EXIT)
3072 {
3073 Log2(("mov_Rd_Cr: (CR8) Guest intercept -> VM-exit\n"));
3074
3075 VMXVEXITINFO ExitInfo;
3076 RT_ZERO(ExitInfo);
3077 ExitInfo.uReason = VMX_EXIT_MOV_CRX;
3078 ExitInfo.cbInstr = cbInstr;
3079 ExitInfo.u64Qual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_REGISTER, 8) /* CR8 */
3080 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_ACCESS, VMX_EXIT_QUAL_CRX_ACCESS_READ)
3081 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_GENREG, iGReg);
3082 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
3083 }
3084
3085 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3086}
3087
3088
3089/**
3090 * VMX VM-exit handler for VM-exits due to 'Mov CR8,GReg' (CR8 write).
3091 *
3092 * @returns VBox strict status code.
3093 * @param pVCpu The cross context virtual CPU structure.
3094 * @param iGReg The general register from which the CR8 value is being
3095 * loaded.
3096 * @param cbInstr The instruction length in bytes.
3097 */
3098IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrMovToCr8(PVMCPUCC pVCpu, uint8_t iGReg, uint8_t cbInstr)
3099{
3100 Assert(iGReg < X86_GREG_COUNT);
3101
3102 /*
3103 * If the CR8-load exiting control is set, we must cause a VM-exit.
3104 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
3105 */
3106 if (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls & VMX_PROC_CTLS_CR8_LOAD_EXIT)
3107 {
3108 Log2(("mov_Cr_Rd: (CR8) Guest intercept -> VM-exit\n"));
3109
3110 VMXVEXITINFO ExitInfo;
3111 RT_ZERO(ExitInfo);
3112 ExitInfo.uReason = VMX_EXIT_MOV_CRX;
3113 ExitInfo.cbInstr = cbInstr;
3114 ExitInfo.u64Qual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_REGISTER, 8) /* CR8 */
3115 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_ACCESS, VMX_EXIT_QUAL_CRX_ACCESS_WRITE)
3116 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_GENREG, iGReg);
3117 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
3118 }
3119
3120 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3121}
3122
3123
3124/**
3125 * VMX VM-exit handler for VM-exits due to 'Mov DRx,GReg' (DRx write) and 'Mov
3126 * GReg,DRx' (DRx read).
3127 *
3128 * @returns VBox strict status code.
3129 * @param pVCpu The cross context virtual CPU structure.
3130 * @param uInstrid The instruction identity (VMXINSTRID_MOV_TO_DRX or
3131 * VMXINSTRID_MOV_FROM_DRX).
3132 * @param iDrReg The debug register being accessed.
3133 * @param iGReg The general register to/from which the DRx value is being
3134 * store/loaded.
3135 * @param cbInstr The instruction length in bytes.
3136 */
3137IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrMovDrX(PVMCPUCC pVCpu, VMXINSTRID uInstrId, uint8_t iDrReg, uint8_t iGReg,
3138 uint8_t cbInstr)
3139{
3140 Assert(iDrReg <= 7);
3141 Assert(uInstrId == VMXINSTRID_MOV_TO_DRX || uInstrId == VMXINSTRID_MOV_FROM_DRX);
3142 Assert(iGReg < X86_GREG_COUNT);
3143
3144 if (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT)
3145 {
3146 uint32_t const uDirection = uInstrId == VMXINSTRID_MOV_TO_DRX ? VMX_EXIT_QUAL_DRX_DIRECTION_WRITE
3147 : VMX_EXIT_QUAL_DRX_DIRECTION_READ;
3148 VMXVEXITINFO ExitInfo;
3149 RT_ZERO(ExitInfo);
3150 ExitInfo.uReason = VMX_EXIT_MOV_DRX;
3151 ExitInfo.cbInstr = cbInstr;
3152 ExitInfo.u64Qual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_DRX_REGISTER, iDrReg)
3153 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_DRX_DIRECTION, uDirection)
3154 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_DRX_GENREG, iGReg);
3155 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
3156 }
3157
3158 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3159}
3160
3161
3162/**
3163 * VMX VM-exit handler for VM-exits due to I/O instructions (IN and OUT).
3164 *
3165 * @returns VBox strict status code.
3166 * @param pVCpu The cross context virtual CPU structure.
3167 * @param uInstrId The VM-exit instruction identity (VMXINSTRID_IO_IN or
3168 * VMXINSTRID_IO_OUT).
3169 * @param u16Port The I/O port being accessed.
3170 * @param fImm Whether the I/O port was encoded using an immediate operand
3171 * or the implicit DX register.
3172 * @param cbAccess The size of the I/O access in bytes (1, 2 or 4 bytes).
3173 * @param cbInstr The instruction length in bytes.
3174 */
3175IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrIo(PVMCPUCC pVCpu, VMXINSTRID uInstrId, uint16_t u16Port, bool fImm, uint8_t cbAccess,
3176 uint8_t cbInstr)
3177{
3178 Assert(uInstrId == VMXINSTRID_IO_IN || uInstrId == VMXINSTRID_IO_OUT);
3179 Assert(cbAccess == 1 || cbAccess == 2 || cbAccess == 4);
3180
3181 bool const fIntercept = CPUMIsGuestVmxIoInterceptSet(pVCpu, u16Port, cbAccess);
3182 if (fIntercept)
3183 {
3184 uint32_t const uDirection = uInstrId == VMXINSTRID_IO_IN ? VMX_EXIT_QUAL_IO_DIRECTION_IN
3185 : VMX_EXIT_QUAL_IO_DIRECTION_OUT;
3186 VMXVEXITINFO ExitInfo;
3187 RT_ZERO(ExitInfo);
3188 ExitInfo.uReason = VMX_EXIT_IO_INSTR;
3189 ExitInfo.cbInstr = cbInstr;
3190 ExitInfo.u64Qual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_IO_WIDTH, cbAccess - 1)
3191 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_IO_DIRECTION, uDirection)
3192 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_IO_ENCODING, fImm)
3193 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_IO_PORT, u16Port);
3194 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
3195 }
3196
3197 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3198}
3199
3200
3201/**
3202 * VMX VM-exit handler for VM-exits due to string I/O instructions (INS and OUTS).
3203 *
3204 * @returns VBox strict status code.
3205 * @param pVCpu The cross context virtual CPU structure.
3206 * @param uInstrId The VM-exit instruction identity (VMXINSTRID_IO_INS or
3207 * VMXINSTRID_IO_OUTS).
3208 * @param u16Port The I/O port being accessed.
3209 * @param cbAccess The size of the I/O access in bytes (1, 2 or 4 bytes).
3210 * @param fRep Whether the instruction has a REP prefix or not.
3211 * @param ExitInstrInfo The VM-exit instruction info. field.
3212 * @param cbInstr The instruction length in bytes.
3213 */
3214IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrStrIo(PVMCPUCC pVCpu, VMXINSTRID uInstrId, uint16_t u16Port, uint8_t cbAccess, bool fRep,
3215 VMXEXITINSTRINFO ExitInstrInfo, uint8_t cbInstr)
3216{
3217 Assert(uInstrId == VMXINSTRID_IO_INS || uInstrId == VMXINSTRID_IO_OUTS);
3218 Assert(cbAccess == 1 || cbAccess == 2 || cbAccess == 4);
3219 Assert(ExitInstrInfo.StrIo.iSegReg < X86_SREG_COUNT);
3220 Assert(ExitInstrInfo.StrIo.u3AddrSize == 0 || ExitInstrInfo.StrIo.u3AddrSize == 1 || ExitInstrInfo.StrIo.u3AddrSize == 2);
3221 Assert(uInstrId != VMXINSTRID_IO_INS || ExitInstrInfo.StrIo.iSegReg == X86_SREG_ES);
3222
3223 bool const fIntercept = CPUMIsGuestVmxIoInterceptSet(pVCpu, u16Port, cbAccess);
3224 if (fIntercept)
3225 {
3226 /*
3227 * Figure out the guest-linear address and the direction bit (INS/OUTS).
3228 */
3229 /** @todo r=ramshankar: Is there something in IEM that already does this? */
3230 static uint64_t const s_auAddrSizeMasks[] = { UINT64_C(0xffff), UINT64_C(0xffffffff), UINT64_C(0xffffffffffffffff) };
3231 uint8_t const iSegReg = ExitInstrInfo.StrIo.iSegReg;
3232 uint8_t const uAddrSize = ExitInstrInfo.StrIo.u3AddrSize;
3233 uint64_t const uAddrSizeMask = s_auAddrSizeMasks[uAddrSize];
3234
3235 uint32_t uDirection;
3236 uint64_t uGuestLinearAddr;
3237 if (uInstrId == VMXINSTRID_IO_INS)
3238 {
3239 uDirection = VMX_EXIT_QUAL_IO_DIRECTION_IN;
3240 uGuestLinearAddr = pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base + (pVCpu->cpum.GstCtx.rdi & uAddrSizeMask);
3241 }
3242 else
3243 {
3244 uDirection = VMX_EXIT_QUAL_IO_DIRECTION_OUT;
3245 uGuestLinearAddr = pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base + (pVCpu->cpum.GstCtx.rsi & uAddrSizeMask);
3246 }
3247
3248 /*
3249 * If the segment is unusable, the guest-linear address in undefined.
3250 * We shall clear it for consistency.
3251 *
3252 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
3253 */
3254 if (pVCpu->cpum.GstCtx.aSRegs[iSegReg].Attr.n.u1Unusable)
3255 uGuestLinearAddr = 0;
3256
3257 VMXVEXITINFO ExitInfo;
3258 RT_ZERO(ExitInfo);
3259 ExitInfo.uReason = VMX_EXIT_IO_INSTR;
3260 ExitInfo.cbInstr = cbInstr;
3261 ExitInfo.u64GuestLinearAddr = uGuestLinearAddr;
3262 ExitInfo.u64Qual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_IO_WIDTH, cbAccess - 1)
3263 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_IO_DIRECTION, uDirection)
3264 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_IO_IS_STRING, 1)
3265 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_IO_IS_REP, fRep)
3266 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_IO_ENCODING, VMX_EXIT_QUAL_IO_ENCODING_DX)
3267 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_IO_PORT, u16Port);
3268 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxInsOutInfo)
3269 ExitInfo.InstrInfo = ExitInstrInfo;
3270 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
3271 }
3272
3273 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3274}
3275
3276
3277/**
3278 * VMX VM-exit handler for VM-exits due to MWAIT.
3279 *
3280 * @returns VBox strict status code.
3281 * @param pVCpu The cross context virtual CPU structure.
3282 * @param fMonitorHwArmed Whether the address-range monitor hardware is armed.
3283 * @param cbInstr The instruction length in bytes.
3284 */
3285IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrMwait(PVMCPUCC pVCpu, bool fMonitorHwArmed, uint8_t cbInstr)
3286{
3287 VMXVEXITINFO ExitInfo;
3288 RT_ZERO(ExitInfo);
3289 ExitInfo.uReason = VMX_EXIT_MWAIT;
3290 ExitInfo.cbInstr = cbInstr;
3291 ExitInfo.u64Qual = fMonitorHwArmed;
3292 return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
3293}
3294
3295
3296/**
3297 * VMX VM-exit handler for VM-exits due to PAUSE.
3298 *
3299 * @returns VBox strict status code.
3300 * @param pVCpu The cross context virtual CPU structure.
3301 * @param cbInstr The instruction length in bytes.
3302 */
3303IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrPause(PVMCPUCC pVCpu, uint8_t cbInstr)
3304{
3305 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
3306
3307 /*
3308 * The PAUSE VM-exit is controlled by the "PAUSE exiting" control and the
3309 * "PAUSE-loop exiting" control.
3310 *
3311 * The PLE-Gap is the maximum number of TSC ticks between two successive executions of
3312 * the PAUSE instruction before we cause a VM-exit. The PLE-Window is the maximum amount
3313 * of TSC ticks the guest is allowed to execute in a pause loop before we must cause
3314 * a VM-exit.
3315 *
3316 * See Intel spec. 24.6.13 "Controls for PAUSE-Loop Exiting".
3317 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
3318 */
3319 bool fIntercept = false;
3320 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_PAUSE_EXIT)
3321 fIntercept = true;
3322 else if ( (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)
3323 && pVCpu->iem.s.uCpl == 0)
3324 {
3325 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_HWVIRT);
3326
3327 /*
3328 * A previous-PAUSE-tick value of 0 is used to identify the first time
3329 * execution of a PAUSE instruction after VM-entry at CPL 0. We must
3330 * consider this to be the first execution of PAUSE in a loop according
3331 * to the Intel.
3332 *
3333 * All subsequent records for the previous-PAUSE-tick we ensure that it
3334 * cannot be zero by OR'ing 1 to rule out the TSC wrap-around cases at 0.
3335 */
3336 uint64_t *puFirstPauseLoopTick = &pVCpu->cpum.GstCtx.hwvirt.vmx.uFirstPauseLoopTick;
3337 uint64_t *puPrevPauseTick = &pVCpu->cpum.GstCtx.hwvirt.vmx.uPrevPauseTick;
3338 uint64_t const uTick = TMCpuTickGet(pVCpu);
3339 uint32_t const uPleGap = pVmcs->u32PleGap;
3340 uint32_t const uPleWindow = pVmcs->u32PleWindow;
3341 if ( *puPrevPauseTick == 0
3342 || uTick - *puPrevPauseTick > uPleGap)
3343 *puFirstPauseLoopTick = uTick;
3344 else if (uTick - *puFirstPauseLoopTick > uPleWindow)
3345 fIntercept = true;
3346
3347 *puPrevPauseTick = uTick | 1;
3348 }
3349
3350 if (fIntercept)
3351 return iemVmxVmexitInstr(pVCpu, VMX_EXIT_PAUSE, cbInstr);
3352
3353 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3354}
3355
3356
3357/**
3358 * VMX VM-exit handler for VM-exits due to task switches.
3359 *
3360 * @returns VBox strict status code.
3361 * @param pVCpu The cross context virtual CPU structure.
3362 * @param enmTaskSwitch The cause of the task switch.
3363 * @param SelNewTss The selector of the new TSS.
3364 * @param cbInstr The instruction length in bytes.
3365 */
3366IEM_STATIC VBOXSTRICTRC iemVmxVmexitTaskSwitch(PVMCPUCC pVCpu, IEMTASKSWITCH enmTaskSwitch, RTSEL SelNewTss, uint8_t cbInstr)
3367{
3368 /*
3369 * Task-switch VM-exits are unconditional and provide the Exit qualification.
3370 *
3371 * If the cause of the task switch is due to execution of CALL, IRET or the JMP
3372 * instruction or delivery of the exception generated by one of these instructions
3373 * lead to a task switch through a task gate in the IDT, we need to provide the
3374 * VM-exit instruction length. Any other means of invoking a task switch VM-exit
3375 * leaves the VM-exit instruction length field undefined.
3376 *
3377 * See Intel spec. 25.2 "Other Causes Of VM Exits".
3378 * See Intel spec. 27.2.4 "Information for VM Exits Due to Instruction Execution".
3379 */
3380 Assert(cbInstr <= 15);
3381
3382 uint8_t uType;
3383 switch (enmTaskSwitch)
3384 {
3385 case IEMTASKSWITCH_CALL: uType = VMX_EXIT_QUAL_TASK_SWITCH_TYPE_CALL; break;
3386 case IEMTASKSWITCH_IRET: uType = VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IRET; break;
3387 case IEMTASKSWITCH_JUMP: uType = VMX_EXIT_QUAL_TASK_SWITCH_TYPE_JMP; break;
3388 case IEMTASKSWITCH_INT_XCPT: uType = VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT; break;
3389 IEM_NOT_REACHED_DEFAULT_CASE_RET();
3390 }
3391
3392 uint64_t const u64ExitQual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_TASK_SWITCH_NEW_TSS, SelNewTss)
3393 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_TASK_SWITCH_SOURCE, uType);
3394 iemVmxVmcsSetExitInstrLen(pVCpu, cbInstr);
3395 return iemVmxVmexit(pVCpu, VMX_EXIT_TASK_SWITCH, u64ExitQual);
3396}
3397
3398
3399/**
3400 * VMX VM-exit handler for trap-like VM-exits.
3401 *
3402 * @returns VBox strict status code.
3403 * @param pVCpu The cross context virtual CPU structure.
3404 * @param pExitInfo Pointer to the VM-exit information.
3405 * @param pExitEventInfo Pointer to the VM-exit event information.
3406 */
3407IEM_STATIC VBOXSTRICTRC iemVmxVmexitTrapLikeWithInfo(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo)
3408{
3409 Assert(VMXIsVmexitTrapLike(pExitInfo->uReason));
3410 iemVmxVmcsSetGuestPendingDbgXcpts(pVCpu, pExitInfo->u64GuestPendingDbgXcpts);
3411 return iemVmxVmexit(pVCpu, pExitInfo->uReason, pExitInfo->u64Qual);
3412}
3413
3414
3415/**
3416 * VMX VM-exit handler for VM-exits due to task switches.
3417 *
3418 * This is intended for task switches where the caller provides all the relevant
3419 * VM-exit information.
3420 *
3421 * @returns VBox strict status code.
3422 * @param pVCpu The cross context virtual CPU structure.
3423 * @param pExitInfo Pointer to the VM-exit information.
3424 * @param pExitEventInfo Pointer to the VM-exit event information.
3425 */
3426IEM_STATIC VBOXSTRICTRC iemVmxVmexitTaskSwitchWithInfo(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo,
3427 PCVMXVEXITEVENTINFO pExitEventInfo)
3428{
3429 Assert(pExitInfo->uReason == VMX_EXIT_TASK_SWITCH);
3430 iemVmxVmcsSetExitInstrLen(pVCpu, pExitInfo->cbInstr);
3431 iemVmxVmcsSetIdtVectoringInfo(pVCpu, pExitEventInfo->uIdtVectoringInfo);
3432 iemVmxVmcsSetIdtVectoringErrCode(pVCpu, pExitEventInfo->uIdtVectoringErrCode);
3433 return iemVmxVmexit(pVCpu, VMX_EXIT_TASK_SWITCH, pExitInfo->u64Qual);
3434}
3435
3436
3437/**
3438 * VMX VM-exit handler for VM-exits due to expiring of the preemption timer.
3439 *
3440 * @returns VBox strict status code.
3441 * @param pVCpu The cross context virtual CPU structure.
3442 */
3443IEM_STATIC VBOXSTRICTRC iemVmxVmexitPreemptTimer(PVMCPUCC pVCpu)
3444{
3445 Assert(VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER));
3446 Assert(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32PinCtls & VMX_PIN_CTLS_PREEMPT_TIMER);
3447
3448 /* Import the hardware virtualization state (for nested-guest VM-entry TSC-tick). */
3449 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_HWVIRT);
3450
3451 /* Save the VMX-preemption timer value (of 0) back in to the VMCS if the CPU supports this feature. */
3452 if (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ExitCtls & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER)
3453 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32PreemptTimer = 0;
3454
3455 /* Cause the VMX-preemption timer VM-exit. The Exit qualification MBZ. */
3456 return iemVmxVmexit(pVCpu, VMX_EXIT_PREEMPT_TIMER, 0 /* u64ExitQual */);
3457}
3458
3459
3460/**
3461 * VMX VM-exit handler for VM-exits due to external interrupts.
3462 *
3463 * @returns VBox strict status code.
3464 * @param pVCpu The cross context virtual CPU structure.
3465 * @param uVector The external interrupt vector (pass 0 if the interrupt
3466 * is still pending since we typically won't know the
3467 * vector).
3468 * @param fIntPending Whether the external interrupt is pending or
3469 * acknowledged in the interrupt controller.
3470 */
3471IEM_STATIC VBOXSTRICTRC iemVmxVmexitExtInt(PVMCPUCC pVCpu, uint8_t uVector, bool fIntPending)
3472{
3473 Assert(!fIntPending || uVector == 0);
3474
3475 /* The VM-exit is subject to "External interrupt exiting" being set. */
3476 if (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32PinCtls & VMX_PIN_CTLS_EXT_INT_EXIT)
3477 {
3478 if (fIntPending)
3479 {
3480 /*
3481 * If the interrupt is pending and we don't need to acknowledge the
3482 * interrupt on VM-exit, cause the VM-exit immediately.
3483 *
3484 * See Intel spec 25.2 "Other Causes Of VM Exits".
3485 */
3486 if (!(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT))
3487 return iemVmxVmexit(pVCpu, VMX_EXIT_EXT_INT, 0 /* u64ExitQual */);
3488
3489 /*
3490 * If the interrupt is pending and we -do- need to acknowledge the interrupt
3491 * on VM-exit, postpone VM-exit till after the interrupt controller has been
3492 * acknowledged that the interrupt has been consumed. Callers would have to call
3493 * us again after getting the vector (and ofc, with fIntPending with false).
3494 */
3495 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3496 }
3497
3498 /*
3499 * If the interrupt is no longer pending (i.e. it has been acknowledged) and the
3500 * "External interrupt exiting" and "Acknowledge interrupt on VM-exit" controls are
3501 * all set, we need to record the vector of the external interrupt in the
3502 * VM-exit interruption information field. Otherwise, mark this field as invalid.
3503 *
3504 * See Intel spec. 27.2.2 "Information for VM Exits Due to Vectored Events".
3505 */
3506 uint32_t uExitIntInfo;
3507 if (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT)
3508 {
3509 bool const fNmiUnblocking = pVCpu->cpum.GstCtx.hwvirt.vmx.fNmiUnblockingIret;
3510 uExitIntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, uVector)
3511 | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_EXT_INT)
3512 | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_NMI_UNBLOCK_IRET, fNmiUnblocking)
3513 | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID, 1);
3514 }
3515 else
3516 uExitIntInfo = 0;
3517 iemVmxVmcsSetExitIntInfo(pVCpu, uExitIntInfo);
3518
3519 /*
3520 * Cause the VM-exit whether or not the vector has been stored
3521 * in the VM-exit interruption-information field.
3522 */
3523 return iemVmxVmexit(pVCpu, VMX_EXIT_EXT_INT, 0 /* u64ExitQual */);
3524 }
3525
3526 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3527}
3528
3529
3530/**
3531 * VMX VM-exit handler for VM-exits due to a double fault caused during delivery of
3532 * an event.
3533 *
3534 * @returns VBox strict status code.
3535 * @param pVCpu The cross context virtual CPU structure.
3536 */
3537IEM_STATIC VBOXSTRICTRC iemVmxVmexitEventDoubleFault(PVMCPUCC pVCpu)
3538{
3539 uint32_t const fXcptBitmap = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32XcptBitmap;
3540 if (fXcptBitmap & RT_BIT(X86_XCPT_DF))
3541 {
3542 /*
3543 * The NMI-unblocking due to IRET field need not be set for double faults.
3544 * See Intel spec. 31.7.1.2 "Resuming Guest Software After Handling An Exception".
3545 */
3546 uint32_t const uExitIntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, X86_XCPT_DF)
3547 | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
3548 | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_ERR_CODE_VALID, 1)
3549 | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_NMI_UNBLOCK_IRET, 0)
3550 | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID, 1);
3551 iemVmxVmcsSetExitIntInfo(pVCpu, uExitIntInfo);
3552 return iemVmxVmexit(pVCpu, VMX_EXIT_XCPT_OR_NMI, 0 /* u64ExitQual */);
3553 }
3554
3555 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3556}
3557
3558
3559/**
3560 * VMX VM-exit handler for VM-exit due to delivery of an events.
3561 *
3562 * This is intended for VM-exit due to exceptions or NMIs where the caller provides
3563 * all the relevant VM-exit information.
3564 *
3565 * @returns VBox strict status code.
3566 * @param pVCpu The cross context virtual CPU structure.
3567 * @param pExitInfo Pointer to the VM-exit information.
3568 * @param pExitEventInfo Pointer to the VM-exit event information.
3569 */
3570IEM_STATIC VBOXSTRICTRC iemVmxVmexitEventWithInfo(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo)
3571{
3572 Assert(pExitInfo);
3573 Assert(pExitEventInfo);
3574 Assert(pExitInfo->uReason == VMX_EXIT_XCPT_OR_NMI);
3575 Assert(VMX_EXIT_INT_INFO_IS_VALID(pExitEventInfo->uExitIntInfo));
3576
3577 iemVmxVmcsSetExitInstrLen(pVCpu, pExitInfo->cbInstr);
3578 iemVmxVmcsSetExitIntInfo(pVCpu, pExitEventInfo->uExitIntInfo);
3579 iemVmxVmcsSetExitIntErrCode(pVCpu, pExitEventInfo->uExitIntErrCode);
3580 iemVmxVmcsSetIdtVectoringInfo(pVCpu, pExitEventInfo->uIdtVectoringInfo);
3581 iemVmxVmcsSetIdtVectoringErrCode(pVCpu, pExitEventInfo->uIdtVectoringErrCode);
3582 return iemVmxVmexit(pVCpu, VMX_EXIT_XCPT_OR_NMI, pExitInfo->u64Qual);
3583}
3584
3585
3586/**
3587 * VMX VM-exit handler for VM-exits due to delivery of an event.
3588 *
3589 * @returns VBox strict status code.
3590 * @param pVCpu The cross context virtual CPU structure.
3591 * @param uVector The interrupt / exception vector.
3592 * @param fFlags The flags (see IEM_XCPT_FLAGS_XXX).
3593 * @param uErrCode The error code associated with the event.
3594 * @param uCr2 The CR2 value in case of a \#PF exception.
3595 * @param cbInstr The instruction length in bytes.
3596 */
3597IEM_STATIC VBOXSTRICTRC iemVmxVmexitEvent(PVMCPUCC pVCpu, uint8_t uVector, uint32_t fFlags, uint32_t uErrCode, uint64_t uCr2,
3598 uint8_t cbInstr)
3599{
3600 /*
3601 * If the event is being injected as part of VM-entry, it is -not- subject to event
3602 * intercepts in the nested-guest. However, secondary exceptions that occur during
3603 * injection of any event -are- subject to event interception.
3604 *
3605 * See Intel spec. 26.5.1.2 "VM Exits During Event Injection".
3606 */
3607 if (!CPUMIsGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx))
3608 {
3609 /*
3610 * If the event is a virtual-NMI (which is an NMI being inject during VM-entry)
3611 * virtual-NMI blocking must be set in effect rather than physical NMI blocking.
3612 *
3613 * See Intel spec. 24.6.1 "Pin-Based VM-Execution Controls".
3614 */
3615 if ( uVector == X86_XCPT_NMI
3616 && (fFlags & IEM_XCPT_FLAGS_T_CPU_XCPT)
3617 && (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32PinCtls & VMX_PIN_CTLS_VIRT_NMI))
3618 pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtNmiBlocking = true;
3619 else
3620 Assert(!pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtNmiBlocking);
3621
3622 CPUMSetGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx, true);
3623 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3624 }
3625
3626 /*
3627 * We are injecting an external interrupt, check if we need to cause a VM-exit now.
3628 * If not, the caller will continue delivery of the external interrupt as it would
3629 * normally. The interrupt is no longer pending in the interrupt controller at this
3630 * point.
3631 */
3632 if (fFlags & IEM_XCPT_FLAGS_T_EXT_INT)
3633 {
3634 Assert(!VMX_IDT_VECTORING_INFO_IS_VALID(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32RoIdtVectoringInfo));
3635 return iemVmxVmexitExtInt(pVCpu, uVector, false /* fIntPending */);
3636 }
3637
3638 /*
3639 * Evaluate intercepts for hardware exceptions, software exceptions (#BP, #OF),
3640 * and privileged software exceptions (#DB generated by INT1/ICEBP) and software
3641 * interrupts.
3642 */
3643 Assert(fFlags & (IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_T_SOFT_INT));
3644 bool fIntercept;
3645 if ( !(fFlags & IEM_XCPT_FLAGS_T_SOFT_INT)
3646 || (fFlags & (IEM_XCPT_FLAGS_BP_INSTR | IEM_XCPT_FLAGS_OF_INSTR | IEM_XCPT_FLAGS_ICEBP_INSTR)))
3647 fIntercept = CPUMIsGuestVmxXcptInterceptSet(&pVCpu->cpum.GstCtx, uVector, uErrCode);
3648 else
3649 {
3650 /* Software interrupts cannot be intercepted and therefore do not cause a VM-exit. */
3651 fIntercept = false;
3652 }
3653
3654 /*
3655 * Now that we've determined whether the event causes a VM-exit, we need to construct the
3656 * relevant VM-exit information and cause the VM-exit.
3657 */
3658 if (fIntercept)
3659 {
3660 Assert(!(fFlags & IEM_XCPT_FLAGS_T_EXT_INT));
3661
3662 /* Construct the rest of the event related information fields and cause the VM-exit. */
3663 uint64_t u64ExitQual;
3664 if (uVector == X86_XCPT_PF)
3665 {
3666 Assert(fFlags & IEM_XCPT_FLAGS_CR2);
3667 u64ExitQual = uCr2;
3668 }
3669 else if (uVector == X86_XCPT_DB)
3670 {
3671 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR6);
3672 u64ExitQual = pVCpu->cpum.GstCtx.dr[6] & VMX_VMCS_EXIT_QUAL_VALID_MASK;
3673 }
3674 else
3675 u64ExitQual = 0;
3676
3677 uint8_t const fNmiUnblocking = pVCpu->cpum.GstCtx.hwvirt.vmx.fNmiUnblockingIret;
3678 bool const fErrCodeValid = RT_BOOL(fFlags & IEM_XCPT_FLAGS_ERR);
3679 uint8_t const uIntInfoType = iemVmxGetEventType(uVector, fFlags);
3680 uint32_t const uExitIntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, uVector)
3681 | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE, uIntInfoType)
3682 | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_ERR_CODE_VALID, fErrCodeValid)
3683 | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_NMI_UNBLOCK_IRET, fNmiUnblocking)
3684 | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID, 1);
3685 iemVmxVmcsSetExitIntInfo(pVCpu, uExitIntInfo);
3686 iemVmxVmcsSetExitIntErrCode(pVCpu, uErrCode);
3687
3688 /*
3689 * For VM-exits due to software exceptions (those generated by INT3 or INTO) or privileged
3690 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
3691 * length.
3692 */
3693 if ( (fFlags & IEM_XCPT_FLAGS_T_SOFT_INT)
3694 || (fFlags & (IEM_XCPT_FLAGS_BP_INSTR | IEM_XCPT_FLAGS_OF_INSTR | IEM_XCPT_FLAGS_ICEBP_INSTR)))
3695 iemVmxVmcsSetExitInstrLen(pVCpu, cbInstr);
3696 else
3697 iemVmxVmcsSetExitInstrLen(pVCpu, 0);
3698
3699 return iemVmxVmexit(pVCpu, VMX_EXIT_XCPT_OR_NMI, u64ExitQual);
3700 }
3701
3702 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
3703}
3704
3705
3706/**
3707 * VMX VM-exit handler for EPT misconfiguration.
3708 *
3709 * @param pVCpu The cross context virtual CPU structure.
3710 * @param GCPhysAddr The physical address causing the EPT misconfiguration.
3711 * This need not be page aligned (e.g. nested-guest in real
3712 * mode).
3713 * @param pExitEventInfo Pointer to the VM-exit event information. Optional, can
3714 * be NULL.
3715 */
3716IEM_STATIC VBOXSTRICTRC iemVmxVmexitEptMisconfig(PVMCPUCC pVCpu, RTGCPHYS GCPhysAddr, PCVMXVEXITEVENTINFO pExitEventInfo)
3717{
3718 if (pExitEventInfo)
3719 {
3720 iemVmxVmcsSetExitIntInfo(pVCpu, pExitEventInfo->uExitIntInfo);
3721 iemVmxVmcsSetExitIntErrCode(pVCpu, pExitEventInfo->uExitIntErrCode);
3722 iemVmxVmcsSetIdtVectoringInfo(pVCpu, pExitEventInfo->uIdtVectoringInfo);
3723 iemVmxVmcsSetIdtVectoringErrCode(pVCpu, pExitEventInfo->uIdtVectoringErrCode);
3724 }
3725
3726 iemVmxVmcsSetExitGuestPhysAddr(pVCpu, GCPhysAddr);
3727 return iemVmxVmexit(pVCpu, VMX_EXIT_EPT_MISCONFIG, 0 /* u64ExitQual */);
3728}
3729
3730
3731/**
3732 * VMX VM-exit handler for EPT violation.
3733 *
3734 * @param pVCpu The cross context virtual CPU structure.
3735 * @param fAccess The access causing the EPT violation, IEM_ACCESS_XXX.
3736 * @param fSlatFail The SLAT failure info, IEM_SLAT_FAIL_XXX.
3737 * @param fEptAccess The EPT paging structure bits.
3738 * @param GCPhysAddr The physical address causing the EPT violation. This
3739 * need not be page aligned (e.g. nested-guest in real
3740 * mode).
3741 * @param fIsLinearAddrValid Whether translation of a linear address caused this
3742 * EPT violation. If @c false, GCPtrAddr must be 0.
3743 * @param GCPtrAddr The linear address causing the EPT violation.
3744 * @param cbInstr The VM-exit instruction length.
3745 */
3746IEM_STATIC VBOXSTRICTRC iemVmxVmexitEptViolation(PVMCPUCC pVCpu, uint32_t fAccess, uint32_t fSlatFail, uint64_t fEptAccess,
3747 RTGCPHYS GCPhysAddr, bool fLinearAddrValid, uint64_t GCPtrAddr, uint8_t cbInstr)
3748{
3749 /*
3750 * If the linear address isn't valid (can happen when loading PDPTEs
3751 * as part of MOV CR execution) the linear address field is undefined.
3752 * While we can leave it this way, it's preferrable to zero it for consistency.
3753 */
3754 Assert(fLinearAddrValid || GCPtrAddr == 0);
3755
3756 uint64_t const fCaps = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64EptVpidCaps;
3757 uint8_t const fSupportsAccessDirty = fCaps & MSR_IA32_VMX_EPT_VPID_CAP_ACCESS_DIRTY;
3758
3759 uint8_t const fDataRead = ((fAccess & IEM_ACCESS_DATA_R) == IEM_ACCESS_DATA_R) | fSupportsAccessDirty;
3760 uint8_t const fDataWrite = ((fAccess & IEM_ACCESS_DATA_RW) == IEM_ACCESS_DATA_RW) | fSupportsAccessDirty;
3761 uint8_t const fInstrFetch = (fAccess & IEM_ACCESS_INSTRUCTION) == IEM_ACCESS_INSTRUCTION;
3762 bool const fEptRead = RT_BOOL(fEptAccess & EPT_E_READ);
3763 bool const fEptWrite = RT_BOOL(fEptAccess & EPT_E_WRITE);
3764 bool const fEptExec = RT_BOOL(fEptAccess & EPT_E_EXECUTE);
3765 bool const fNmiUnblocking = pVCpu->cpum.GstCtx.hwvirt.vmx.fNmiUnblockingIret;
3766 bool const fLinearToPhysAddr = fLinearAddrValid & RT_BOOL(fSlatFail & IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR);
3767
3768 uint64_t const u64ExitQual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_EPT_ACCESS_READ, fDataRead)
3769 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_EPT_ACCESS_WRITE, fDataWrite)
3770 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH, fInstrFetch)
3771 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_EPT_ENTRY_READ, fEptRead)
3772 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_EPT_ENTRY_WRITE, fEptWrite)
3773 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE, fEptExec)
3774 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_VALID, fLinearAddrValid)
3775 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_EPT_LINEAR_TO_PHYS_ADDR, fLinearToPhysAddr)
3776 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_EPT_NMI_UNBLOCK_IRET, fNmiUnblocking);
3777
3778#ifdef VBOX_STRICT
3779 uint64_t const fMiscCaps = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Misc;
3780 uint32_t const fProcCtls2 = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls2;
3781 Assert(!(fCaps & MSR_IA32_VMX_EPT_VPID_CAP_ADVEXITINFO_EPT_VIOLATION)); /* Advanced VM-exit info. not supported */
3782 Assert(!(fCaps & MSR_IA32_VMX_EPT_VPID_CAP_SUPER_SHW_STACK)); /* Supervisor shadow stack control not supported. */
3783 Assert(!(RT_BF_GET(fMiscCaps, VMX_BF_MISC_INTEL_PT))); /* Intel PT not supported. */
3784 Assert(!(fProcCtls2 & VMX_PROC_CTLS2_MODE_BASED_EPT_PERM)); /* Mode-based execute control not supported. */
3785#endif
3786
3787 iemVmxVmcsSetExitGuestPhysAddr(pVCpu, GCPhysAddr);
3788 iemVmxVmcsSetExitGuestLinearAddr(pVCpu, GCPtrAddr);
3789 iemVmxVmcsSetExitInstrLen(pVCpu, cbInstr);
3790
3791 return iemVmxVmexit(pVCpu, VMX_EXIT_EPT_VIOLATION, u64ExitQual);
3792}
3793
3794
3795/**
3796 * VMX VM-exit handler for EPT violation.
3797 *
3798 * This is intended for EPT violations where the caller provides all the
3799 * relevant VM-exit information.
3800 *
3801 * @returns VBox strict status code.
3802 * @param pVCpu The cross context virtual CPU structure.
3803 * @param pExitInfo Pointer to the VM-exit information.
3804 * @param pExitEventInfo Pointer to the VM-exit event information.
3805 */
3806IEM_STATIC VBOXSTRICTRC iemVmxVmexitEptViolationWithInfo(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo,
3807 PCVMXVEXITEVENTINFO pExitEventInfo)
3808{
3809 Assert(pExitInfo->uReason == VMX_EXIT_EPT_VIOLATION);
3810
3811 iemVmxVmcsSetExitIntInfo(pVCpu, pExitEventInfo->uExitIntInfo);
3812 iemVmxVmcsSetExitIntErrCode(pVCpu, pExitEventInfo->uExitIntErrCode);
3813 iemVmxVmcsSetIdtVectoringInfo(pVCpu, pExitEventInfo->uIdtVectoringInfo);
3814 iemVmxVmcsSetIdtVectoringErrCode(pVCpu, pExitEventInfo->uIdtVectoringErrCode);
3815
3816 iemVmxVmcsSetExitGuestPhysAddr(pVCpu, pExitInfo->u64GuestPhysAddr);
3817 if (pExitInfo->u64Qual & VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_VALID_MASK)
3818 iemVmxVmcsSetExitGuestLinearAddr(pVCpu, pExitInfo->u64GuestLinearAddr);
3819 else
3820 iemVmxVmcsSetExitGuestLinearAddr(pVCpu, 0);
3821 iemVmxVmcsSetExitInstrLen(pVCpu, pExitInfo->cbInstr);
3822 return iemVmxVmexit(pVCpu, VMX_EXIT_EPT_VIOLATION, pExitInfo->u64Qual);
3823}
3824
3825
3826/**
3827 * VMX VM-exit handler for EPT-induced VM-exits.
3828 *
3829 * @param pVCpu The cross context virtual CPU structure.
3830 * @param pWalk The page walk info.
3831 * @param fAccess The access causing the EPT event, IEM_ACCESS_XXX.
3832 * @param fSlatFail Additional SLAT info, IEM_SLAT_FAIL_XXX.
3833 * @param cbInstr The VM-exit instruction length if applicable. Pass 0 if not
3834 * applicable.
3835 */
3836IEM_STATIC VBOXSTRICTRC iemVmxVmexitEpt(PVMCPUCC pVCpu, PPGMPTWALK pWalk, uint32_t fAccess, uint32_t fSlatFail,
3837 uint8_t cbInstr)
3838{
3839 Assert(pWalk->fIsSlat);
3840 Assert(pWalk->fFailed & PGM_WALKFAIL_EPT);
3841 Assert(!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxEptXcptVe); /* #VE exceptions not supported. */
3842 Assert(!(pWalk->fFailed & PGM_WALKFAIL_EPT_VIOLATION_CONVERTIBLE)); /* Without #VE, convertible violations not possible. */
3843
3844 if (pWalk->fFailed & PGM_WALKFAIL_EPT_VIOLATION)
3845 {
3846 Log(("EptViolation: cs:rip=%x:%#RX64 fAccess=%#RX32\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, fAccess));
3847 uint64_t const fEptAccess = (pWalk->fEffective & PGM_PTATTRS_EPT_MASK) >> PGM_PTATTRS_EPT_SHIFT;
3848 return iemVmxVmexitEptViolation(pVCpu, fAccess, fSlatFail, fEptAccess, pWalk->GCPhysNested, pWalk->fIsLinearAddrValid,
3849 pWalk->GCPtr, cbInstr);
3850 }
3851
3852 Log(("EptMisconfig: cs:rip=%x:%#RX64 fAccess=%#RX32\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, fAccess));
3853 Assert(pWalk->fFailed & PGM_WALKFAIL_EPT_MISCONFIG);
3854 return iemVmxVmexitEptMisconfig(pVCpu, pWalk->GCPhysNested, NULL /* pExitEventInfo */);
3855}
3856
3857
3858/**
3859 * VMX VM-exit handler for APIC accesses.
3860 *
3861 * @param pVCpu The cross context virtual CPU structure.
3862 * @param offAccess The offset of the register being accessed.
3863 * @param fAccess The type of access (must contain IEM_ACCESS_TYPE_READ or
3864 * IEM_ACCESS_TYPE_WRITE or IEM_ACCESS_INSTRUCTION).
3865 */
3866IEM_STATIC VBOXSTRICTRC iemVmxVmexitApicAccess(PVMCPUCC pVCpu, uint16_t offAccess, uint32_t fAccess)
3867{
3868 Assert((fAccess & IEM_ACCESS_TYPE_READ) || (fAccess & IEM_ACCESS_TYPE_WRITE) || (fAccess & IEM_ACCESS_INSTRUCTION));
3869
3870 VMXAPICACCESS enmAccess;
3871 bool const fInEventDelivery = IEMGetCurrentXcpt(pVCpu, NULL, NULL, NULL, NULL);
3872 if (fInEventDelivery)
3873 enmAccess = VMXAPICACCESS_LINEAR_EVENT_DELIVERY;
3874 else if (fAccess & IEM_ACCESS_INSTRUCTION)
3875 enmAccess = VMXAPICACCESS_LINEAR_INSTR_FETCH;
3876 else if (fAccess & IEM_ACCESS_TYPE_WRITE)
3877 enmAccess = VMXAPICACCESS_LINEAR_WRITE;
3878 else
3879 enmAccess = VMXAPICACCESS_LINEAR_READ;
3880
3881 uint64_t const u64ExitQual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_APIC_ACCESS_OFFSET, offAccess)
3882 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_APIC_ACCESS_TYPE, enmAccess);
3883 return iemVmxVmexit(pVCpu, VMX_EXIT_APIC_ACCESS, u64ExitQual);
3884}
3885
3886
3887/**
3888 * VMX VM-exit handler for APIC accesses.
3889 *
3890 * This is intended for APIC accesses where the caller provides all the
3891 * relevant VM-exit information.
3892 *
3893 * @returns VBox strict status code.
3894 * @param pVCpu The cross context virtual CPU structure.
3895 * @param pExitInfo Pointer to the VM-exit information.
3896 * @param pExitEventInfo Pointer to the VM-exit event information.
3897 */
3898IEM_STATIC VBOXSTRICTRC iemVmxVmexitApicAccessWithInfo(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo,
3899 PCVMXVEXITEVENTINFO pExitEventInfo)
3900{
3901 /* VM-exit interruption information should not be valid for APIC-access VM-exits. */
3902 Assert(!VMX_EXIT_INT_INFO_IS_VALID(pExitEventInfo->uExitIntInfo));
3903 Assert(pExitInfo->uReason == VMX_EXIT_APIC_ACCESS);
3904 iemVmxVmcsSetExitIntInfo(pVCpu, 0);
3905 iemVmxVmcsSetExitIntErrCode(pVCpu, 0);
3906 iemVmxVmcsSetExitInstrLen(pVCpu, pExitInfo->cbInstr);
3907 iemVmxVmcsSetIdtVectoringInfo(pVCpu, pExitEventInfo->uIdtVectoringInfo);
3908 iemVmxVmcsSetIdtVectoringErrCode(pVCpu, pExitEventInfo->uIdtVectoringErrCode);
3909 return iemVmxVmexit(pVCpu, VMX_EXIT_APIC_ACCESS, pExitInfo->u64Qual);
3910}
3911
3912
3913/**
3914 * VMX VM-exit handler for APIC-write VM-exits.
3915 *
3916 * @param pVCpu The cross context virtual CPU structure.
3917 * @param offApic The write to the virtual-APIC page offset that caused this
3918 * VM-exit.
3919 */
3920IEM_STATIC VBOXSTRICTRC iemVmxVmexitApicWrite(PVMCPUCC pVCpu, uint16_t offApic)
3921{
3922 Assert(offApic < XAPIC_OFF_END + 4);
3923 /* Write only bits 11:0 of the APIC offset into the Exit qualification field. */
3924 offApic &= UINT16_C(0xfff);
3925 return iemVmxVmexit(pVCpu, VMX_EXIT_APIC_WRITE, offApic);
3926}
3927
3928
3929/**
3930 * Sets virtual-APIC write emulation as pending.
3931 *
3932 * @param pVCpu The cross context virtual CPU structure.
3933 * @param offApic The offset in the virtual-APIC page that was written.
3934 */
3935DECLINLINE(void) iemVmxVirtApicSetPendingWrite(PVMCPUCC pVCpu, uint16_t offApic)
3936{
3937 Assert(offApic < XAPIC_OFF_END + 4);
3938
3939 /*
3940 * Record the currently updated APIC offset, as we need this later for figuring
3941 * out whether to perform TPR, EOI or self-IPI virtualization as well as well
3942 * as for supplying the exit qualification when causing an APIC-write VM-exit.
3943 */
3944 pVCpu->cpum.GstCtx.hwvirt.vmx.offVirtApicWrite = offApic;
3945
3946 /*
3947 * Flag that we need to perform virtual-APIC write emulation (TPR/PPR/EOI/Self-IPI
3948 * virtualization or APIC-write emulation).
3949 */
3950 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
3951 VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE);
3952}
3953
3954
3955/**
3956 * Clears any pending virtual-APIC write emulation.
3957 *
3958 * @returns The virtual-APIC offset that was written before clearing it.
3959 * @param pVCpu The cross context virtual CPU structure.
3960 */
3961DECLINLINE(uint16_t) iemVmxVirtApicClearPendingWrite(PVMCPUCC pVCpu)
3962{
3963 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_HWVIRT);
3964 uint8_t const offVirtApicWrite = pVCpu->cpum.GstCtx.hwvirt.vmx.offVirtApicWrite;
3965 pVCpu->cpum.GstCtx.hwvirt.vmx.offVirtApicWrite = 0;
3966 Assert(VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE));
3967 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_VMX_APIC_WRITE);
3968 return offVirtApicWrite;
3969}
3970
3971
3972/**
3973 * Reads a 32-bit register from the virtual-APIC page at the given offset.
3974 *
3975 * @returns The register from the virtual-APIC page.
3976 * @param pVCpu The cross context virtual CPU structure.
3977 * @param offReg The offset of the register being read.
3978 */
3979IEM_STATIC uint32_t iemVmxVirtApicReadRaw32(PVMCPUCC pVCpu, uint16_t offReg)
3980{
3981 Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uint32_t));
3982
3983 uint32_t uReg = 0;
3984 RTGCPHYS const GCPhysVirtApic = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64AddrVirtApic.u;
3985 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &uReg, GCPhysVirtApic + offReg, sizeof(uReg));
3986 AssertMsgStmt(RT_SUCCESS(rc),
3987 ("Failed to read %u bytes at offset %#x of the virtual-APIC page at %#RGp: %Rrc\n",
3988 sizeof(uReg), offReg, GCPhysVirtApic, rc),
3989 uReg = 0);
3990 return uReg;
3991}
3992
3993
3994/**
3995 * Reads a 64-bit register from the virtual-APIC page at the given offset.
3996 *
3997 * @returns The register from the virtual-APIC page.
3998 * @param pVCpu The cross context virtual CPU structure.
3999 * @param offReg The offset of the register being read.
4000 */
4001IEM_STATIC uint64_t iemVmxVirtApicReadRaw64(PVMCPUCC pVCpu, uint16_t offReg)
4002{
4003 Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uint64_t));
4004
4005 uint64_t uReg = 0;
4006 RTGCPHYS const GCPhysVirtApic = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64AddrVirtApic.u;
4007 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &uReg, GCPhysVirtApic + offReg, sizeof(uReg));
4008 AssertMsgStmt(RT_SUCCESS(rc),
4009 ("Failed to read %u bytes at offset %#x of the virtual-APIC page at %#RGp: %Rrc\n",
4010 sizeof(uReg), offReg, GCPhysVirtApic, rc),
4011 uReg = 0);
4012 return uReg;
4013}
4014
4015
4016/**
4017 * Writes a 32-bit register to the virtual-APIC page at the given offset.
4018 *
4019 * @param pVCpu The cross context virtual CPU structure.
4020 * @param offReg The offset of the register being written.
4021 * @param uReg The register value to write.
4022 */
4023IEM_STATIC void iemVmxVirtApicWriteRaw32(PVMCPUCC pVCpu, uint16_t offReg, uint32_t uReg)
4024{
4025 Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uint32_t));
4026
4027 RTGCPHYS const GCPhysVirtApic = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64AddrVirtApic.u;
4028 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVirtApic + offReg, &uReg, sizeof(uReg));
4029 AssertMsgRC(rc, ("Failed to write %u bytes at offset %#x of the virtual-APIC page at %#RGp: %Rrc\n",
4030 sizeof(uReg), offReg, GCPhysVirtApic, rc));
4031}
4032
4033
4034/**
4035 * Writes a 64-bit register to the virtual-APIC page at the given offset.
4036 *
4037 * @param pVCpu The cross context virtual CPU structure.
4038 * @param offReg The offset of the register being written.
4039 * @param uReg The register value to write.
4040 */
4041IEM_STATIC void iemVmxVirtApicWriteRaw64(PVMCPUCC pVCpu, uint16_t offReg, uint64_t uReg)
4042{
4043 Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uint64_t));
4044
4045 RTGCPHYS const GCPhysVirtApic = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64AddrVirtApic.u;
4046 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVirtApic + offReg, &uReg, sizeof(uReg));
4047 AssertMsgRC(rc, ("Failed to write %u bytes at offset %#x of the virtual-APIC page at %#RGp: %Rrc\n",
4048 sizeof(uReg), offReg, GCPhysVirtApic, rc));
4049}
4050
4051
4052/**
4053 * Sets the vector in a virtual-APIC 256-bit sparse register.
4054 *
4055 * @param pVCpu The cross context virtual CPU structure.
4056 * @param offReg The offset of the 256-bit spare register.
4057 * @param uVector The vector to set.
4058 *
4059 * @remarks This is based on our APIC device code.
4060 */
4061IEM_STATIC void iemVmxVirtApicSetVectorInReg(PVMCPUCC pVCpu, uint16_t offReg, uint8_t uVector)
4062{
4063 /* Determine the vector offset within the chunk. */
4064 uint16_t const offVector = (uVector & UINT32_C(0xe0)) >> 1;
4065
4066 /* Read the chunk at the offset. */
4067 uint32_t uReg;
4068 RTGCPHYS const GCPhysVirtApic = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64AddrVirtApic.u;
4069 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &uReg, GCPhysVirtApic + offReg + offVector, sizeof(uReg));
4070 if (RT_SUCCESS(rc))
4071 {
4072 /* Modify the chunk. */
4073 uint16_t const idxVectorBit = uVector & UINT32_C(0x1f);
4074 uReg |= RT_BIT(idxVectorBit);
4075
4076 /* Write the chunk. */
4077 rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVirtApic + offReg + offVector, &uReg, sizeof(uReg));
4078 AssertMsgRC(rc, ("Failed to set vector %#x in 256-bit register at %#x of the virtual-APIC page at %#RGp: %Rrc\n",
4079 uVector, offReg, GCPhysVirtApic, rc));
4080 }
4081 else
4082 AssertMsgFailed(("Failed to get vector %#x in 256-bit register at %#x of the virtual-APIC page at %#RGp: %Rrc\n",
4083 uVector, offReg, GCPhysVirtApic, rc));
4084}
4085
4086
4087/**
4088 * Clears the vector in a virtual-APIC 256-bit sparse register.
4089 *
4090 * @param pVCpu The cross context virtual CPU structure.
4091 * @param offReg The offset of the 256-bit spare register.
4092 * @param uVector The vector to clear.
4093 *
4094 * @remarks This is based on our APIC device code.
4095 */
4096IEM_STATIC void iemVmxVirtApicClearVectorInReg(PVMCPUCC pVCpu, uint16_t offReg, uint8_t uVector)
4097{
4098 /* Determine the vector offset within the chunk. */
4099 uint16_t const offVector = (uVector & UINT32_C(0xe0)) >> 1;
4100
4101 /* Read the chunk at the offset. */
4102 uint32_t uReg;
4103 RTGCPHYS const GCPhysVirtApic = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64AddrVirtApic.u;
4104 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &uReg, GCPhysVirtApic + offReg + offVector, sizeof(uReg));
4105 if (RT_SUCCESS(rc))
4106 {
4107 /* Modify the chunk. */
4108 uint16_t const idxVectorBit = uVector & UINT32_C(0x1f);
4109 uReg &= ~RT_BIT(idxVectorBit);
4110
4111 /* Write the chunk. */
4112 rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVirtApic + offReg + offVector, &uReg, sizeof(uReg));
4113 AssertMsgRC(rc, ("Failed to clear vector %#x in 256-bit register at %#x of the virtual-APIC page at %#RGp: %Rrc\n",
4114 uVector, offReg, GCPhysVirtApic, rc));
4115 }
4116 else
4117 AssertMsgFailed(("Failed to get vector %#x in 256-bit register at %#x of the virtual-APIC page at %#RGp: %Rrc\n",
4118 uVector, offReg, GCPhysVirtApic, rc));
4119}
4120
4121
4122/**
4123 * Checks if a memory access to the APIC-access page must causes an APIC-access
4124 * VM-exit.
4125 *
4126 * @param pVCpu The cross context virtual CPU structure.
4127 * @param offAccess The offset of the register being accessed.
4128 * @param cbAccess The size of the access in bytes.
4129 * @param fAccess The type of access (must be IEM_ACCESS_TYPE_READ or
4130 * IEM_ACCESS_TYPE_WRITE).
4131 *
4132 * @remarks This must not be used for MSR-based APIC-access page accesses!
4133 * @sa iemVmxVirtApicAccessMsrWrite, iemVmxVirtApicAccessMsrRead.
4134 */
4135IEM_STATIC bool iemVmxVirtApicIsMemAccessIntercepted(PVMCPUCC pVCpu, uint16_t offAccess, size_t cbAccess, uint32_t fAccess)
4136{
4137 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
4138 Assert(fAccess == IEM_ACCESS_TYPE_READ || fAccess == IEM_ACCESS_TYPE_WRITE);
4139
4140 /*
4141 * We must cause a VM-exit if any of the following are true:
4142 * - TPR shadowing isn't active.
4143 * - The access size exceeds 32-bits.
4144 * - The access is not contained within low 4 bytes of a 16-byte aligned offset.
4145 *
4146 * See Intel spec. 29.4.2 "Virtualizing Reads from the APIC-Access Page".
4147 * See Intel spec. 29.4.3.1 "Determining Whether a Write Access is Virtualized".
4148 */
4149 if ( !(pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
4150 || cbAccess > sizeof(uint32_t)
4151 || ((offAccess + cbAccess - 1) & 0xc)
4152 || offAccess >= XAPIC_OFF_END + 4)
4153 return true;
4154
4155 /*
4156 * If the access is part of an operation where we have already
4157 * virtualized a virtual-APIC write, we must cause a VM-exit.
4158 */
4159 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
4160 return true;
4161
4162 /*
4163 * Check write accesses to the APIC-access page that cause VM-exits.
4164 */
4165 if (fAccess & IEM_ACCESS_TYPE_WRITE)
4166 {
4167 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_APIC_REG_VIRT)
4168 {
4169 /*
4170 * With APIC-register virtualization, a write access to any of the
4171 * following registers are virtualized. Accessing any other register
4172 * causes a VM-exit.
4173 */
4174 uint16_t const offAlignedAccess = offAccess & 0xfffc;
4175 switch (offAlignedAccess)
4176 {
4177 case XAPIC_OFF_ID:
4178 case XAPIC_OFF_TPR:
4179 case XAPIC_OFF_EOI:
4180 case XAPIC_OFF_LDR:
4181 case XAPIC_OFF_DFR:
4182 case XAPIC_OFF_SVR:
4183 case XAPIC_OFF_ESR:
4184 case XAPIC_OFF_ICR_LO:
4185 case XAPIC_OFF_ICR_HI:
4186 case XAPIC_OFF_LVT_TIMER:
4187 case XAPIC_OFF_LVT_THERMAL:
4188 case XAPIC_OFF_LVT_PERF:
4189 case XAPIC_OFF_LVT_LINT0:
4190 case XAPIC_OFF_LVT_LINT1:
4191 case XAPIC_OFF_LVT_ERROR:
4192 case XAPIC_OFF_TIMER_ICR:
4193 case XAPIC_OFF_TIMER_DCR:
4194 break;
4195 default:
4196 return true;
4197 }
4198 }
4199 else if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY)
4200 {
4201 /*
4202 * With virtual-interrupt delivery, a write access to any of the
4203 * following registers are virtualized. Accessing any other register
4204 * causes a VM-exit.
4205 *
4206 * Note! The specification does not allow writing to offsets in-between
4207 * these registers (e.g. TPR + 1 byte) unlike read accesses.
4208 */
4209 switch (offAccess)
4210 {
4211 case XAPIC_OFF_TPR:
4212 case XAPIC_OFF_EOI:
4213 case XAPIC_OFF_ICR_LO:
4214 break;
4215 default:
4216 return true;
4217 }
4218 }
4219 else
4220 {
4221 /*
4222 * Without APIC-register virtualization or virtual-interrupt delivery,
4223 * only TPR accesses are virtualized.
4224 */
4225 if (offAccess == XAPIC_OFF_TPR)
4226 { /* likely */ }
4227 else
4228 return true;
4229 }
4230 }
4231 else
4232 {
4233 /*
4234 * Check read accesses to the APIC-access page that cause VM-exits.
4235 */
4236 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_APIC_REG_VIRT)
4237 {
4238 /*
4239 * With APIC-register virtualization, a read access to any of the
4240 * following registers are virtualized. Accessing any other register
4241 * causes a VM-exit.
4242 */
4243 uint16_t const offAlignedAccess = offAccess & 0xfffc;
4244 switch (offAlignedAccess)
4245 {
4246 /** @todo r=ramshankar: What about XAPIC_OFF_LVT_CMCI? */
4247 case XAPIC_OFF_ID:
4248 case XAPIC_OFF_VERSION:
4249 case XAPIC_OFF_TPR:
4250 case XAPIC_OFF_EOI:
4251 case XAPIC_OFF_LDR:
4252 case XAPIC_OFF_DFR:
4253 case XAPIC_OFF_SVR:
4254 case XAPIC_OFF_ISR0: case XAPIC_OFF_ISR1: case XAPIC_OFF_ISR2: case XAPIC_OFF_ISR3:
4255 case XAPIC_OFF_ISR4: case XAPIC_OFF_ISR5: case XAPIC_OFF_ISR6: case XAPIC_OFF_ISR7:
4256 case XAPIC_OFF_TMR0: case XAPIC_OFF_TMR1: case XAPIC_OFF_TMR2: case XAPIC_OFF_TMR3:
4257 case XAPIC_OFF_TMR4: case XAPIC_OFF_TMR5: case XAPIC_OFF_TMR6: case XAPIC_OFF_TMR7:
4258 case XAPIC_OFF_IRR0: case XAPIC_OFF_IRR1: case XAPIC_OFF_IRR2: case XAPIC_OFF_IRR3:
4259 case XAPIC_OFF_IRR4: case XAPIC_OFF_IRR5: case XAPIC_OFF_IRR6: case XAPIC_OFF_IRR7:
4260 case XAPIC_OFF_ESR:
4261 case XAPIC_OFF_ICR_LO:
4262 case XAPIC_OFF_ICR_HI:
4263 case XAPIC_OFF_LVT_TIMER:
4264 case XAPIC_OFF_LVT_THERMAL:
4265 case XAPIC_OFF_LVT_PERF:
4266 case XAPIC_OFF_LVT_LINT0:
4267 case XAPIC_OFF_LVT_LINT1:
4268 case XAPIC_OFF_LVT_ERROR:
4269 case XAPIC_OFF_TIMER_ICR:
4270 case XAPIC_OFF_TIMER_DCR:
4271 break;
4272 default:
4273 return true;
4274 }
4275 }
4276 else
4277 {
4278 /* Without APIC-register virtualization, only TPR accesses are virtualized. */
4279 if (offAccess == XAPIC_OFF_TPR)
4280 { /* likely */ }
4281 else
4282 return true;
4283 }
4284 }
4285
4286 /* The APIC access is virtualized, does not cause a VM-exit. */
4287 return false;
4288}
4289
4290
4291/**
4292 * Virtualizes a memory-based APIC access where the address is not used to access
4293 * memory.
4294 *
4295 * This is for instructions like MONITOR, CLFLUSH, CLFLUSHOPT, ENTER which may cause
4296 * page-faults but do not use the address to access memory.
4297 *
4298 * @param pVCpu The cross context virtual CPU structure.
4299 * @param pGCPhysAccess Pointer to the guest-physical address used.
4300 */
4301IEM_STATIC VBOXSTRICTRC iemVmxVirtApicAccessUnused(PVMCPUCC pVCpu, PRTGCPHYS pGCPhysAccess)
4302{
4303 Assert(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
4304 Assert(pGCPhysAccess);
4305
4306 RTGCPHYS const GCPhysAccess = *pGCPhysAccess & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
4307 RTGCPHYS const GCPhysApic = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64AddrApicAccess.u;
4308 Assert(!(GCPhysApic & GUEST_PAGE_OFFSET_MASK));
4309
4310 if (GCPhysAccess == GCPhysApic)
4311 {
4312 uint16_t const offAccess = *pGCPhysAccess & GUEST_PAGE_OFFSET_MASK;
4313 uint32_t const fAccess = IEM_ACCESS_TYPE_READ;
4314 uint16_t const cbAccess = 1;
4315 bool const fIntercept = iemVmxVirtApicIsMemAccessIntercepted(pVCpu, offAccess, cbAccess, fAccess);
4316 if (fIntercept)
4317 return iemVmxVmexitApicAccess(pVCpu, offAccess, fAccess);
4318
4319 *pGCPhysAccess = GCPhysApic | offAccess;
4320 return VINF_VMX_MODIFIES_BEHAVIOR;
4321 }
4322
4323 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
4324}
4325
4326
4327/**
4328 * Virtualizes a memory-based APIC access.
4329 *
4330 * @returns VBox strict status code.
4331 * @retval VINF_VMX_MODIFIES_BEHAVIOR if the access was virtualized.
4332 * @retval VINF_VMX_VMEXIT if the access causes a VM-exit.
4333 *
4334 * @param pVCpu The cross context virtual CPU structure.
4335 * @param offAccess The offset of the register being accessed (within the
4336 * APIC-access page).
4337 * @param cbAccess The size of the access in bytes.
4338 * @param pvData Pointer to the data being written or where to store the data
4339 * being read.
4340 * @param fAccess The type of access (must contain IEM_ACCESS_TYPE_READ or
4341 * IEM_ACCESS_TYPE_WRITE or IEM_ACCESS_INSTRUCTION).
4342 */
4343IEM_STATIC VBOXSTRICTRC iemVmxVirtApicAccessMem(PVMCPUCC pVCpu, uint16_t offAccess, size_t cbAccess, void *pvData,
4344 uint32_t fAccess)
4345{
4346 Assert(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
4347 Assert(pvData);
4348 Assert( (fAccess & IEM_ACCESS_TYPE_READ)
4349 || (fAccess & IEM_ACCESS_TYPE_WRITE)
4350 || (fAccess & IEM_ACCESS_INSTRUCTION));
4351
4352 bool const fIntercept = iemVmxVirtApicIsMemAccessIntercepted(pVCpu, offAccess, cbAccess, fAccess);
4353 if (fIntercept)
4354 return iemVmxVmexitApicAccess(pVCpu, offAccess, fAccess);
4355
4356 if (fAccess & IEM_ACCESS_TYPE_WRITE)
4357 {
4358 /*
4359 * A write access to the APIC-access page that is virtualized (rather than
4360 * causing a VM-exit) writes data to the virtual-APIC page.
4361 */
4362 uint32_t const u32Data = *(uint32_t *)pvData;
4363 iemVmxVirtApicWriteRaw32(pVCpu, offAccess, u32Data);
4364
4365 /*
4366 * Record the currently updated APIC offset, as we need this later for figuring
4367 * out whether to perform TPR, EOI or self-IPI virtualization as well as well
4368 * as for supplying the exit qualification when causing an APIC-write VM-exit.
4369 *
4370 * After completion of the current operation, we need to perform TPR virtualization,
4371 * EOI virtualization or APIC-write VM-exit depending on which register was written.
4372 *
4373 * The current operation may be a REP-prefixed string instruction, execution of any
4374 * other instruction, or delivery of an event through the IDT.
4375 *
4376 * Thus things like clearing bytes 3:1 of the VTPR, clearing VEOI are not to be
4377 * performed now but later after completion of the current operation.
4378 *
4379 * See Intel spec. 29.4.3.2 "APIC-Write Emulation".
4380 */
4381 iemVmxVirtApicSetPendingWrite(pVCpu, offAccess);
4382 }
4383 else
4384 {
4385 /*
4386 * A read access from the APIC-access page that is virtualized (rather than
4387 * causing a VM-exit) returns data from the virtual-APIC page.
4388 *
4389 * See Intel spec. 29.4.2 "Virtualizing Reads from the APIC-Access Page".
4390 */
4391 Assert(cbAccess <= 4);
4392 Assert(offAccess < XAPIC_OFF_END + 4);
4393 static uint32_t const s_auAccessSizeMasks[] = { 0, 0xff, 0xffff, 0xffffff, 0xffffffff };
4394
4395 uint32_t u32Data = iemVmxVirtApicReadRaw32(pVCpu, offAccess);
4396 u32Data &= s_auAccessSizeMasks[cbAccess];
4397 *(uint32_t *)pvData = u32Data;
4398 }
4399
4400 return VINF_VMX_MODIFIES_BEHAVIOR;
4401}
4402
4403
4404/**
4405 * Virtualizes an MSR-based APIC read access.
4406 *
4407 * @returns VBox strict status code.
4408 * @retval VINF_VMX_MODIFIES_BEHAVIOR if the MSR read was virtualized.
4409 * @retval VINF_VMX_INTERCEPT_NOT_ACTIVE if the MSR read access must be
4410 * handled by the x2APIC device.
4411 * @retval VERR_OUT_RANGE if the MSR read was supposed to be virtualized but was
4412 * not within the range of valid MSRs, caller must raise \#GP(0).
4413 * @param pVCpu The cross context virtual CPU structure.
4414 * @param idMsr The x2APIC MSR being read.
4415 * @param pu64Value Where to store the read x2APIC MSR value (only valid when
4416 * VINF_VMX_MODIFIES_BEHAVIOR is returned).
4417 */
4418IEM_STATIC VBOXSTRICTRC iemVmxVirtApicAccessMsrRead(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t *pu64Value)
4419{
4420 Assert(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_X2APIC_MODE);
4421 Assert(pu64Value);
4422
4423 if (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls2 & VMX_PROC_CTLS2_APIC_REG_VIRT)
4424 {
4425 if ( idMsr >= MSR_IA32_X2APIC_START
4426 && idMsr <= MSR_IA32_X2APIC_END)
4427 {
4428 uint16_t const offReg = (idMsr & 0xff) << 4;
4429 uint64_t const u64Value = iemVmxVirtApicReadRaw64(pVCpu, offReg);
4430 *pu64Value = u64Value;
4431 return VINF_VMX_MODIFIES_BEHAVIOR;
4432 }
4433 return VERR_OUT_OF_RANGE;
4434 }
4435
4436 if (idMsr == MSR_IA32_X2APIC_TPR)
4437 {
4438 uint16_t const offReg = (idMsr & 0xff) << 4;
4439 uint64_t const u64Value = iemVmxVirtApicReadRaw64(pVCpu, offReg);
4440 *pu64Value = u64Value;
4441 return VINF_VMX_MODIFIES_BEHAVIOR;
4442 }
4443
4444 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
4445}
4446
4447
4448/**
4449 * Virtualizes an MSR-based APIC write access.
4450 *
4451 * @returns VBox strict status code.
4452 * @retval VINF_VMX_MODIFIES_BEHAVIOR if the MSR write was virtualized.
4453 * @retval VERR_OUT_RANGE if the MSR read was supposed to be virtualized but was
4454 * not within the range of valid MSRs, caller must raise \#GP(0).
4455 * @retval VINF_VMX_INTERCEPT_NOT_ACTIVE if the MSR must be written normally.
4456 *
4457 * @param pVCpu The cross context virtual CPU structure.
4458 * @param idMsr The x2APIC MSR being written.
4459 * @param u64Value The value of the x2APIC MSR being written.
4460 */
4461IEM_STATIC VBOXSTRICTRC iemVmxVirtApicAccessMsrWrite(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t u64Value)
4462{
4463 /*
4464 * Check if the access is to be virtualized.
4465 * See Intel spec. 29.5 "Virtualizing MSR-based APIC Accesses".
4466 */
4467 if ( idMsr == MSR_IA32_X2APIC_TPR
4468 || ( (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY)
4469 && ( idMsr == MSR_IA32_X2APIC_EOI
4470 || idMsr == MSR_IA32_X2APIC_SELF_IPI)))
4471 {
4472 /* Validate the MSR write depending on the register. */
4473 switch (idMsr)
4474 {
4475 case MSR_IA32_X2APIC_TPR:
4476 case MSR_IA32_X2APIC_SELF_IPI:
4477 {
4478 if (u64Value & UINT64_C(0xffffffffffffff00))
4479 return VERR_OUT_OF_RANGE;
4480 break;
4481 }
4482 case MSR_IA32_X2APIC_EOI:
4483 {
4484 if (u64Value != 0)
4485 return VERR_OUT_OF_RANGE;
4486 break;
4487 }
4488 }
4489
4490 /* Write the MSR to the virtual-APIC page. */
4491 uint16_t const offReg = (idMsr & 0xff) << 4;
4492 iemVmxVirtApicWriteRaw64(pVCpu, offReg, u64Value);
4493
4494 /*
4495 * Record the currently updated APIC offset, as we need this later for figuring
4496 * out whether to perform TPR, EOI or self-IPI virtualization as well as well
4497 * as for supplying the exit qualification when causing an APIC-write VM-exit.
4498 */
4499 iemVmxVirtApicSetPendingWrite(pVCpu, offReg);
4500
4501 return VINF_VMX_MODIFIES_BEHAVIOR;
4502 }
4503
4504 return VINF_VMX_INTERCEPT_NOT_ACTIVE;
4505}
4506
4507
4508/**
4509 * Finds the most significant set bit in a virtual-APIC 256-bit sparse register.
4510 *
4511 * @returns VBox status code.
4512 * @retval VINF_SUCCESS when the highest set bit is found.
4513 * @retval VERR_NOT_FOUND when no bit is set.
4514 *
4515 * @param pVCpu The cross context virtual CPU structure.
4516 * @param offReg The offset of the APIC 256-bit sparse register.
4517 * @param pidxHighestBit Where to store the highest bit (most significant bit)
4518 * set in the register. Only valid when VINF_SUCCESS is
4519 * returned.
4520 *
4521 * @remarks The format of the 256-bit sparse register here mirrors that found in
4522 * real APIC hardware.
4523 */
4524static int iemVmxVirtApicGetHighestSetBitInReg(PVMCPUCC pVCpu, uint16_t offReg, uint8_t *pidxHighestBit)
4525{
4526 Assert(offReg < XAPIC_OFF_END + 4);
4527 Assert(pidxHighestBit);
4528
4529 /*
4530 * There are 8 contiguous fragments (of 16-bytes each) in the sparse register.
4531 * However, in each fragment only the first 4 bytes are used.
4532 */
4533 uint8_t const cFrags = 8;
4534 for (int8_t iFrag = cFrags; iFrag >= 0; iFrag--)
4535 {
4536 uint16_t const offFrag = iFrag * 16;
4537 uint32_t const u32Frag = iemVmxVirtApicReadRaw32(pVCpu, offReg + offFrag);
4538 if (!u32Frag)
4539 continue;
4540
4541 unsigned idxHighestBit = ASMBitLastSetU32(u32Frag);
4542 Assert(idxHighestBit > 0);
4543 --idxHighestBit;
4544 Assert(idxHighestBit <= UINT8_MAX);
4545 *pidxHighestBit = idxHighestBit;
4546 return VINF_SUCCESS;
4547 }
4548 return VERR_NOT_FOUND;
4549}
4550
4551
4552/**
4553 * Evaluates pending virtual interrupts.
4554 *
4555 * @param pVCpu The cross context virtual CPU structure.
4556 */
4557IEM_STATIC void iemVmxEvalPendingVirtIntrs(PVMCPUCC pVCpu)
4558{
4559 Assert(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY);
4560
4561 if (!(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
4562 {
4563 uint8_t const uRvi = RT_LO_U8(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u16GuestIntStatus);
4564 uint8_t const uPpr = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_PPR);
4565
4566 if ((uRvi >> 4) > (uPpr >> 4))
4567 {
4568 Log2(("eval_virt_intrs: uRvi=%#x uPpr=%#x - Signalling pending interrupt\n", uRvi, uPpr));
4569 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);
4570 }
4571 else
4572 Log2(("eval_virt_intrs: uRvi=%#x uPpr=%#x - Nothing to do\n", uRvi, uPpr));
4573 }
4574}
4575
4576
4577/**
4578 * Performs PPR virtualization.
4579 *
4580 * @returns VBox strict status code.
4581 * @param pVCpu The cross context virtual CPU structure.
4582 */
4583IEM_STATIC void iemVmxPprVirtualization(PVMCPUCC pVCpu)
4584{
4585 Assert(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
4586 Assert(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY);
4587
4588 /*
4589 * PPR virtualization is caused in response to a VM-entry, TPR-virtualization,
4590 * or EOI-virtualization.
4591 *
4592 * See Intel spec. 29.1.3 "PPR Virtualization".
4593 */
4594 uint32_t const uTpr = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
4595 uint32_t const uSvi = RT_HI_U8(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u16GuestIntStatus);
4596
4597 uint32_t uPpr;
4598 if (((uTpr >> 4) & 0xf) >= ((uSvi >> 4) & 0xf))
4599 uPpr = uTpr & 0xff;
4600 else
4601 uPpr = uSvi & 0xf0;
4602
4603 Log2(("ppr_virt: uTpr=%#x uSvi=%#x uPpr=%#x\n", uTpr, uSvi, uPpr));
4604 iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_PPR, uPpr);
4605}
4606
4607
4608/**
4609 * Performs VMX TPR virtualization.
4610 *
4611 * @returns VBox strict status code.
4612 * @param pVCpu The cross context virtual CPU structure.
4613 */
4614IEM_STATIC VBOXSTRICTRC iemVmxTprVirtualization(PVMCPUCC pVCpu)
4615{
4616 Assert(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
4617
4618 /*
4619 * We should have already performed the virtual-APIC write to the TPR offset
4620 * in the virtual-APIC page. We now perform TPR virtualization.
4621 *
4622 * See Intel spec. 29.1.2 "TPR Virtualization".
4623 */
4624 if (!(pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY))
4625 {
4626 uint32_t const uTprThreshold = pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32TprThreshold;
4627 uint32_t const uTpr = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
4628
4629 /*
4630 * If the VTPR falls below the TPR threshold, we must cause a VM-exit.
4631 * See Intel spec. 29.1.2 "TPR Virtualization".
4632 */
4633 if (((uTpr >> 4) & 0xf) < uTprThreshold)
4634 {
4635 Log2(("tpr_virt: uTpr=%u uTprThreshold=%u -> VM-exit\n", uTpr, uTprThreshold));
4636 return iemVmxVmexit(pVCpu, VMX_EXIT_TPR_BELOW_THRESHOLD, 0 /* u64ExitQual */);
4637 }
4638 }
4639 else
4640 {
4641 iemVmxPprVirtualization(pVCpu);
4642 iemVmxEvalPendingVirtIntrs(pVCpu);
4643 }
4644
4645 return VINF_SUCCESS;
4646}
4647
4648
4649/**
4650 * Checks whether an EOI write for the given interrupt vector causes a VM-exit or
4651 * not.
4652 *
4653 * @returns @c true if the EOI write is intercepted, @c false otherwise.
4654 * @param pVCpu The cross context virtual CPU structure.
4655 * @param uVector The interrupt that was acknowledged using an EOI.
4656 */
4657IEM_STATIC bool iemVmxIsEoiInterceptSet(PCVMCPU pVCpu, uint8_t uVector)
4658{
4659 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
4660 Assert(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY);
4661
4662 if (uVector < 64)
4663 return RT_BOOL(pVmcs->u64EoiExitBitmap0.u & RT_BIT_64(uVector));
4664 if (uVector < 128)
4665 return RT_BOOL(pVmcs->u64EoiExitBitmap1.u & RT_BIT_64(uVector));
4666 if (uVector < 192)
4667 return RT_BOOL(pVmcs->u64EoiExitBitmap2.u & RT_BIT_64(uVector));
4668 return RT_BOOL(pVmcs->u64EoiExitBitmap3.u & RT_BIT_64(uVector));
4669}
4670
4671
4672/**
4673 * Performs EOI virtualization.
4674 *
4675 * @returns VBox strict status code.
4676 * @param pVCpu The cross context virtual CPU structure.
4677 */
4678IEM_STATIC VBOXSTRICTRC iemVmxEoiVirtualization(PVMCPUCC pVCpu)
4679{
4680 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
4681 Assert(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY);
4682
4683 /*
4684 * Clear the interrupt guest-interrupt as no longer in-service (ISR)
4685 * and get the next guest-interrupt that's in-service (if any).
4686 *
4687 * See Intel spec. 29.1.4 "EOI Virtualization".
4688 */
4689 uint8_t const uRvi = RT_LO_U8(pVmcs->u16GuestIntStatus);
4690 uint8_t const uSvi = RT_HI_U8(pVmcs->u16GuestIntStatus);
4691 Log2(("eoi_virt: uRvi=%#x uSvi=%#x\n", uRvi, uSvi));
4692
4693 uint8_t uVector = uSvi;
4694 iemVmxVirtApicClearVectorInReg(pVCpu, XAPIC_OFF_ISR0, uVector);
4695
4696 uVector = 0;
4697 iemVmxVirtApicGetHighestSetBitInReg(pVCpu, XAPIC_OFF_ISR0, &uVector);
4698
4699 if (uVector)
4700 Log2(("eoi_virt: next interrupt %#x\n", uVector));
4701 else
4702 Log2(("eoi_virt: no interrupt pending in ISR\n"));
4703
4704 /* Update guest-interrupt status SVI (leave RVI portion as it is) in the VMCS. */
4705 pVmcs->u16GuestIntStatus = RT_MAKE_U16(uRvi, uVector);
4706
4707 iemVmxPprVirtualization(pVCpu);
4708 if (iemVmxIsEoiInterceptSet(pVCpu, uVector))
4709 return iemVmxVmexit(pVCpu, VMX_EXIT_VIRTUALIZED_EOI, uVector);
4710 iemVmxEvalPendingVirtIntrs(pVCpu);
4711 return VINF_SUCCESS;
4712}
4713
4714
4715/**
4716 * Performs self-IPI virtualization.
4717 *
4718 * @returns VBox strict status code.
4719 * @param pVCpu The cross context virtual CPU structure.
4720 */
4721IEM_STATIC VBOXSTRICTRC iemVmxSelfIpiVirtualization(PVMCPUCC pVCpu)
4722{
4723 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
4724 Assert(pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
4725
4726 /*
4727 * We should have already performed the virtual-APIC write to the self-IPI offset
4728 * in the virtual-APIC page. We now perform self-IPI virtualization.
4729 *
4730 * See Intel spec. 29.1.5 "Self-IPI Virtualization".
4731 */
4732 uint8_t const uVector = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_ICR_LO);
4733 Log2(("self_ipi_virt: uVector=%#x\n", uVector));
4734 iemVmxVirtApicSetVectorInReg(pVCpu, XAPIC_OFF_IRR0, uVector);
4735 uint8_t const uRvi = RT_LO_U8(pVmcs->u16GuestIntStatus);
4736 uint8_t const uSvi = RT_HI_U8(pVmcs->u16GuestIntStatus);
4737 if (uVector > uRvi)
4738 pVmcs->u16GuestIntStatus = RT_MAKE_U16(uVector, uSvi);
4739 iemVmxEvalPendingVirtIntrs(pVCpu);
4740 return VINF_SUCCESS;
4741}
4742
4743
4744/**
4745 * Performs VMX APIC-write emulation.
4746 *
4747 * @returns VBox strict status code.
4748 * @param pVCpu The cross context virtual CPU structure.
4749 */
4750IEM_STATIC VBOXSTRICTRC iemVmxApicWriteEmulation(PVMCPUCC pVCpu)
4751{
4752 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
4753
4754 /* Import the virtual-APIC write offset (part of the hardware-virtualization state). */
4755 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_HWVIRT);
4756
4757 /*
4758 * Perform APIC-write emulation based on the virtual-APIC register written.
4759 * See Intel spec. 29.4.3.2 "APIC-Write Emulation".
4760 */
4761 uint16_t const offApicWrite = iemVmxVirtApicClearPendingWrite(pVCpu);
4762 VBOXSTRICTRC rcStrict;
4763 switch (offApicWrite)
4764 {
4765 case XAPIC_OFF_TPR:
4766 {
4767 /* Clear bytes 3:1 of the VTPR and perform TPR virtualization. */
4768 uint32_t uTpr = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
4769 uTpr &= UINT32_C(0x000000ff);
4770 iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_TPR, uTpr);
4771 Log2(("iemVmxApicWriteEmulation: TPR write %#x\n", uTpr));
4772 rcStrict = iemVmxTprVirtualization(pVCpu);
4773 break;
4774 }
4775
4776 case XAPIC_OFF_EOI:
4777 {
4778 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY)
4779 {
4780 /* Clear VEOI and perform EOI virtualization. */
4781 iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_EOI, 0);
4782 Log2(("iemVmxApicWriteEmulation: EOI write\n"));
4783 rcStrict = iemVmxEoiVirtualization(pVCpu);
4784 }
4785 else
4786 rcStrict = iemVmxVmexitApicWrite(pVCpu, offApicWrite);
4787 break;
4788 }
4789
4790 case XAPIC_OFF_ICR_LO:
4791 {
4792 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY)
4793 {
4794 /* If the ICR_LO is valid, write it and perform self-IPI virtualization. */
4795 uint32_t const uIcrLo = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
4796 uint32_t const fIcrLoMb0 = UINT32_C(0xfffbb700);
4797 uint32_t const fIcrLoMb1 = UINT32_C(0x000000f0);
4798 if ( !(uIcrLo & fIcrLoMb0)
4799 && (uIcrLo & fIcrLoMb1))
4800 {
4801 Log2(("iemVmxApicWriteEmulation: Self-IPI virtualization with vector %#x\n", (uIcrLo & 0xff)));
4802 rcStrict = iemVmxSelfIpiVirtualization(pVCpu);
4803 }
4804 else
4805 rcStrict = iemVmxVmexitApicWrite(pVCpu, offApicWrite);
4806 }
4807 else
4808 rcStrict = iemVmxVmexitApicWrite(pVCpu, offApicWrite);
4809 break;
4810 }
4811
4812 case XAPIC_OFF_ICR_HI:
4813 {
4814 /* Clear bytes 2:0 of VICR_HI. No other virtualization or VM-exit must occur. */
4815 uint32_t uIcrHi = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_ICR_HI);
4816 uIcrHi &= UINT32_C(0xff000000);
4817 iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_ICR_HI, uIcrHi);
4818 rcStrict = VINF_SUCCESS;
4819 break;
4820 }
4821
4822 default:
4823 {
4824 /* Writes to any other virtual-APIC register causes an APIC-write VM-exit. */
4825 rcStrict = iemVmxVmexitApicWrite(pVCpu, offApicWrite);
4826 break;
4827 }
4828 }
4829
4830 return rcStrict;
4831}
4832
4833
4834/**
4835 * Checks guest control registers, debug registers and MSRs as part of VM-entry.
4836 *
4837 * @param pVCpu The cross context virtual CPU structure.
4838 * @param pszInstr The VMX instruction name (for logging purposes).
4839 */
4840DECLINLINE(int) iemVmxVmentryCheckGuestControlRegsMsrs(PVMCPUCC pVCpu, const char *pszInstr)
4841{
4842 /*
4843 * Guest Control Registers, Debug Registers, and MSRs.
4844 * See Intel spec. 26.3.1.1 "Checks on Guest Control Registers, Debug Registers, and MSRs".
4845 */
4846 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
4847 const char * const pszFailure = "VM-exit";
4848 bool const fUnrestrictedGuest = RT_BOOL(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST);
4849
4850 /* CR0 reserved bits. */
4851 {
4852 /* CR0 MB1 bits. */
4853 uint64_t const u64Cr0Fixed0 = iemVmxGetCr0Fixed0(pVCpu);
4854 if ((pVmcs->u64GuestCr0.u & u64Cr0Fixed0) == u64Cr0Fixed0)
4855 { /* likely */ }
4856 else
4857 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestCr0Fixed0);
4858
4859 /* CR0 MBZ bits. */
4860 uint64_t const u64Cr0Fixed1 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr0Fixed1;
4861 if (!(pVmcs->u64GuestCr0.u & ~u64Cr0Fixed1))
4862 { /* likely */ }
4863 else
4864 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestCr0Fixed1);
4865
4866 /* Without unrestricted guest support, VT-x supports does not support unpaged protected mode. */
4867 if ( !fUnrestrictedGuest
4868 && (pVmcs->u64GuestCr0.u & X86_CR0_PG)
4869 && !(pVmcs->u64GuestCr0.u & X86_CR0_PE))
4870 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestCr0PgPe);
4871 }
4872
4873 /* CR4 reserved bits. */
4874 {
4875 /* CR4 MB1 bits. */
4876 uint64_t const u64Cr4Fixed0 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed0;
4877 if ((pVmcs->u64GuestCr4.u & u64Cr4Fixed0) == u64Cr4Fixed0)
4878 { /* likely */ }
4879 else
4880 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestCr4Fixed0);
4881
4882 /* CR4 MBZ bits. */
4883 uint64_t const u64Cr4Fixed1 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed1;
4884 if (!(pVmcs->u64GuestCr4.u & ~u64Cr4Fixed1))
4885 { /* likely */ }
4886 else
4887 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestCr4Fixed1);
4888 }
4889
4890 /* DEBUGCTL MSR. */
4891 if ( !(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
4892 || !(pVmcs->u64GuestDebugCtlMsr.u & ~MSR_IA32_DEBUGCTL_VALID_MASK_INTEL))
4893 { /* likely */ }
4894 else
4895 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestDebugCtl);
4896
4897 /* 64-bit CPU checks. */
4898 bool const fGstInLongMode = RT_BOOL(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
4899 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
4900 {
4901 if (fGstInLongMode)
4902 {
4903 /* PAE must be set. */
4904 if ( (pVmcs->u64GuestCr0.u & X86_CR0_PG)
4905 && (pVmcs->u64GuestCr0.u & X86_CR4_PAE))
4906 { /* likely */ }
4907 else
4908 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPae);
4909 }
4910 else
4911 {
4912 /* PCIDE should not be set. */
4913 if (!(pVmcs->u64GuestCr4.u & X86_CR4_PCIDE))
4914 { /* likely */ }
4915 else
4916 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPcide);
4917 }
4918
4919 /* CR3. */
4920 if (!(pVmcs->u64GuestCr3.u >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cMaxPhysAddrWidth))
4921 { /* likely */ }
4922 else
4923 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestCr3);
4924
4925 /* DR7. */
4926 if ( !(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
4927 || !(pVmcs->u64GuestDr7.u & X86_DR7_MBZ_MASK))
4928 { /* likely */ }
4929 else
4930 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestDr7);
4931
4932 /* SYSENTER ESP and SYSENTER EIP. */
4933 if ( X86_IS_CANONICAL(pVmcs->u64GuestSysenterEsp.u)
4934 && X86_IS_CANONICAL(pVmcs->u64GuestSysenterEip.u))
4935 { /* likely */ }
4936 else
4937 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSysenterEspEip);
4938 }
4939
4940 /* We don't support IA32_PERF_GLOBAL_CTRL MSR yet. */
4941 Assert(!(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR));
4942
4943 /* PAT MSR. */
4944 if ( !(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
4945 || CPUMIsPatMsrValid(pVmcs->u64GuestPatMsr.u))
4946 { /* likely */ }
4947 else
4948 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPatMsr);
4949
4950 /* EFER MSR. */
4951 if (pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
4952 {
4953 uint64_t const uValidEferMask = CPUMGetGuestEferMsrValidMask(pVCpu->CTX_SUFF(pVM));
4954 if (!(pVmcs->u64GuestEferMsr.u & ~uValidEferMask))
4955 { /* likely */ }
4956 else
4957 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestEferMsrRsvd);
4958
4959 bool const fGstLma = RT_BOOL(pVmcs->u64GuestEferMsr.u & MSR_K6_EFER_LMA);
4960 bool const fGstLme = RT_BOOL(pVmcs->u64GuestEferMsr.u & MSR_K6_EFER_LME);
4961 if ( fGstLma == fGstInLongMode
4962 && ( !(pVmcs->u64GuestCr0.u & X86_CR0_PG)
4963 || fGstLma == fGstLme))
4964 { /* likely */ }
4965 else
4966 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestEferMsr);
4967 }
4968
4969 /* We don't support IA32_BNDCFGS MSR yet. */
4970 Assert(!(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_BNDCFGS_MSR));
4971
4972 NOREF(pszInstr);
4973 NOREF(pszFailure);
4974 return VINF_SUCCESS;
4975}
4976
4977
4978/**
4979 * Checks guest segment registers, LDTR and TR as part of VM-entry.
4980 *
4981 * @param pVCpu The cross context virtual CPU structure.
4982 * @param pszInstr The VMX instruction name (for logging purposes).
4983 */
4984DECLINLINE(int) iemVmxVmentryCheckGuestSegRegs(PVMCPUCC pVCpu, const char *pszInstr)
4985{
4986 /*
4987 * Segment registers.
4988 * See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
4989 */
4990 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
4991 const char * const pszFailure = "VM-exit";
4992 bool const fGstInV86Mode = RT_BOOL(pVmcs->u64GuestRFlags.u & X86_EFL_VM);
4993 bool const fUnrestrictedGuest = RT_BOOL(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST);
4994 bool const fGstInLongMode = RT_BOOL(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
4995
4996 /* Selectors. */
4997 if ( !fGstInV86Mode
4998 && !fUnrestrictedGuest
4999 && (pVmcs->GuestSs & X86_SEL_RPL) != (pVmcs->GuestCs & X86_SEL_RPL))
5000 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegSelCsSsRpl);
5001
5002 for (unsigned iSegReg = 0; iSegReg < X86_SREG_COUNT; iSegReg++)
5003 {
5004 CPUMSELREG SelReg;
5005 int rc = iemVmxVmcsGetGuestSegReg(pVmcs, iSegReg, &SelReg);
5006 if (RT_LIKELY(rc == VINF_SUCCESS))
5007 { /* likely */ }
5008 else
5009 return rc;
5010
5011 /*
5012 * Virtual-8086 mode checks.
5013 */
5014 if (fGstInV86Mode)
5015 {
5016 /* Base address. */
5017 if (SelReg.u64Base == (uint64_t)SelReg.Sel << 4)
5018 { /* likely */ }
5019 else
5020 {
5021 VMXVDIAG const enmDiag = iemVmxGetDiagVmentrySegBaseV86(iSegReg);
5022 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
5023 }
5024
5025 /* Limit. */
5026 if (SelReg.u32Limit == 0xffff)
5027 { /* likely */ }
5028 else
5029 {
5030 VMXVDIAG const enmDiag = iemVmxGetDiagVmentrySegLimitV86(iSegReg);
5031 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
5032 }
5033
5034 /* Attribute. */
5035 if (SelReg.Attr.u == 0xf3)
5036 { /* likely */ }
5037 else
5038 {
5039 VMXVDIAG const enmDiag = iemVmxGetDiagVmentrySegAttrV86(iSegReg);
5040 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
5041 }
5042
5043 /* We're done; move to checking the next segment. */
5044 continue;
5045 }
5046
5047 /* Checks done by 64-bit CPUs. */
5048 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
5049 {
5050 /* Base address. */
5051 if ( iSegReg == X86_SREG_FS
5052 || iSegReg == X86_SREG_GS)
5053 {
5054 if (X86_IS_CANONICAL(SelReg.u64Base))
5055 { /* likely */ }
5056 else
5057 {
5058 VMXVDIAG const enmDiag = iemVmxGetDiagVmentrySegBase(iSegReg);
5059 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
5060 }
5061 }
5062 else if (iSegReg == X86_SREG_CS)
5063 {
5064 if (!RT_HI_U32(SelReg.u64Base))
5065 { /* likely */ }
5066 else
5067 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegBaseCs);
5068 }
5069 else
5070 {
5071 if ( SelReg.Attr.n.u1Unusable
5072 || !RT_HI_U32(SelReg.u64Base))
5073 { /* likely */ }
5074 else
5075 {
5076 VMXVDIAG const enmDiag = iemVmxGetDiagVmentrySegBase(iSegReg);
5077 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
5078 }
5079 }
5080 }
5081
5082 /*
5083 * Checks outside Virtual-8086 mode.
5084 */
5085 uint8_t const uSegType = SelReg.Attr.n.u4Type;
5086 uint8_t const fCodeDataSeg = SelReg.Attr.n.u1DescType;
5087 uint8_t const fUsable = !SelReg.Attr.n.u1Unusable;
5088 uint8_t const uDpl = SelReg.Attr.n.u2Dpl;
5089 uint8_t const fPresent = SelReg.Attr.n.u1Present;
5090 uint8_t const uGranularity = SelReg.Attr.n.u1Granularity;
5091 uint8_t const uDefBig = SelReg.Attr.n.u1DefBig;
5092 uint8_t const fSegLong = SelReg.Attr.n.u1Long;
5093
5094 /* Code or usable segment. */
5095 if ( iSegReg == X86_SREG_CS
5096 || fUsable)
5097 {
5098 /* Reserved bits (bits 31:17 and bits 11:8). */
5099 if (!(SelReg.Attr.u & 0xfffe0f00))
5100 { /* likely */ }
5101 else
5102 {
5103 VMXVDIAG const enmDiag = iemVmxGetDiagVmentrySegAttrRsvd(iSegReg);
5104 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
5105 }
5106
5107 /* Descriptor type. */
5108 if (fCodeDataSeg)
5109 { /* likely */ }
5110 else
5111 {
5112 VMXVDIAG const enmDiag = iemVmxGetDiagVmentrySegAttrDescType(iSegReg);
5113 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
5114 }
5115
5116 /* Present. */
5117 if (fPresent)
5118 { /* likely */ }
5119 else
5120 {
5121 VMXVDIAG const enmDiag = iemVmxGetDiagVmentrySegAttrPresent(iSegReg);
5122 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
5123 }
5124
5125 /* Granularity. */
5126 if ( ((SelReg.u32Limit & 0x00000fff) == 0x00000fff || !uGranularity)
5127 && ((SelReg.u32Limit & 0xfff00000) == 0x00000000 || uGranularity))
5128 { /* likely */ }
5129 else
5130 {
5131 VMXVDIAG const enmDiag = iemVmxGetDiagVmentrySegAttrGran(iSegReg);
5132 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
5133 }
5134 }
5135
5136 if (iSegReg == X86_SREG_CS)
5137 {
5138 /* Segment Type and DPL. */
5139 if ( uSegType == (X86_SEL_TYPE_RW | X86_SEL_TYPE_ACCESSED)
5140 && fUnrestrictedGuest)
5141 {
5142 if (uDpl == 0)
5143 { /* likely */ }
5144 else
5145 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrCsDplZero);
5146 }
5147 else if ( uSegType == (X86_SEL_TYPE_CODE | X86_SEL_TYPE_ACCESSED)
5148 || uSegType == (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ | X86_SEL_TYPE_ACCESSED))
5149 {
5150 X86DESCATTR AttrSs; AttrSs.u = pVmcs->u32GuestSsAttr;
5151 if (uDpl == AttrSs.n.u2Dpl)
5152 { /* likely */ }
5153 else
5154 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrCsDplEqSs);
5155 }
5156 else if ((uSegType & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF | X86_SEL_TYPE_ACCESSED))
5157 == (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF | X86_SEL_TYPE_ACCESSED))
5158 {
5159 X86DESCATTR AttrSs; AttrSs.u = pVmcs->u32GuestSsAttr;
5160 if (uDpl <= AttrSs.n.u2Dpl)
5161 { /* likely */ }
5162 else
5163 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrCsDplLtSs);
5164 }
5165 else
5166 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrCsType);
5167
5168 /* Def/Big. */
5169 if ( fGstInLongMode
5170 && fSegLong)
5171 {
5172 if (uDefBig == 0)
5173 { /* likely */ }
5174 else
5175 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrCsDefBig);
5176 }
5177 }
5178 else if (iSegReg == X86_SREG_SS)
5179 {
5180 /* Segment Type. */
5181 if ( !fUsable
5182 || uSegType == (X86_SEL_TYPE_RW | X86_SEL_TYPE_ACCESSED)
5183 || uSegType == (X86_SEL_TYPE_DOWN | X86_SEL_TYPE_RW | X86_SEL_TYPE_ACCESSED))
5184 { /* likely */ }
5185 else
5186 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrSsType);
5187
5188 /* DPL. */
5189 if (!fUnrestrictedGuest)
5190 {
5191 if (uDpl == (SelReg.Sel & X86_SEL_RPL))
5192 { /* likely */ }
5193 else
5194 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrSsDplEqRpl);
5195 }
5196 X86DESCATTR AttrCs; AttrCs.u = pVmcs->u32GuestCsAttr;
5197 if ( AttrCs.n.u4Type == (X86_SEL_TYPE_RW | X86_SEL_TYPE_ACCESSED)
5198 || !(pVmcs->u64GuestCr0.u & X86_CR0_PE))
5199 {
5200 if (uDpl == 0)
5201 { /* likely */ }
5202 else
5203 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrSsDplZero);
5204 }
5205 }
5206 else
5207 {
5208 /* DS, ES, FS, GS. */
5209 if (fUsable)
5210 {
5211 /* Segment type. */
5212 if (uSegType & X86_SEL_TYPE_ACCESSED)
5213 { /* likely */ }
5214 else
5215 {
5216 VMXVDIAG const enmDiag = iemVmxGetDiagVmentrySegAttrTypeAcc(iSegReg);
5217 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
5218 }
5219
5220 if ( !(uSegType & X86_SEL_TYPE_CODE)
5221 || (uSegType & X86_SEL_TYPE_READ))
5222 { /* likely */ }
5223 else
5224 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrCsTypeRead);
5225
5226 /* DPL. */
5227 if ( !fUnrestrictedGuest
5228 && uSegType <= (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ | X86_SEL_TYPE_ACCESSED))
5229 {
5230 if (uDpl >= (SelReg.Sel & X86_SEL_RPL))
5231 { /* likely */ }
5232 else
5233 {
5234 VMXVDIAG const enmDiag = iemVmxGetDiagVmentrySegAttrDplRpl(iSegReg);
5235 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
5236 }
5237 }
5238 }
5239 }
5240 }
5241
5242 /*
5243 * LDTR.
5244 */
5245 {
5246 CPUMSELREG Ldtr;
5247 Ldtr.Sel = pVmcs->GuestLdtr;
5248 Ldtr.u32Limit = pVmcs->u32GuestLdtrLimit;
5249 Ldtr.u64Base = pVmcs->u64GuestLdtrBase.u;
5250 Ldtr.Attr.u = pVmcs->u32GuestLdtrAttr;
5251
5252 if (!Ldtr.Attr.n.u1Unusable)
5253 {
5254 /* Selector. */
5255 if (!(Ldtr.Sel & X86_SEL_LDT))
5256 { /* likely */ }
5257 else
5258 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegSelLdtr);
5259
5260 /* Base. */
5261 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
5262 {
5263 if (X86_IS_CANONICAL(Ldtr.u64Base))
5264 { /* likely */ }
5265 else
5266 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegBaseLdtr);
5267 }
5268
5269 /* Attributes. */
5270 /* Reserved bits (bits 31:17 and bits 11:8). */
5271 if (!(Ldtr.Attr.u & 0xfffe0f00))
5272 { /* likely */ }
5273 else
5274 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrLdtrRsvd);
5275
5276 if (Ldtr.Attr.n.u4Type == X86_SEL_TYPE_SYS_LDT)
5277 { /* likely */ }
5278 else
5279 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrLdtrType);
5280
5281 if (!Ldtr.Attr.n.u1DescType)
5282 { /* likely */ }
5283 else
5284 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrLdtrDescType);
5285
5286 if (Ldtr.Attr.n.u1Present)
5287 { /* likely */ }
5288 else
5289 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrLdtrPresent);
5290
5291 if ( ((Ldtr.u32Limit & 0x00000fff) == 0x00000fff || !Ldtr.Attr.n.u1Granularity)
5292 && ((Ldtr.u32Limit & 0xfff00000) == 0x00000000 || Ldtr.Attr.n.u1Granularity))
5293 { /* likely */ }
5294 else
5295 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrLdtrGran);
5296 }
5297 }
5298
5299 /*
5300 * TR.
5301 */
5302 {
5303 CPUMSELREG Tr;
5304 Tr.Sel = pVmcs->GuestTr;
5305 Tr.u32Limit = pVmcs->u32GuestTrLimit;
5306 Tr.u64Base = pVmcs->u64GuestTrBase.u;
5307 Tr.Attr.u = pVmcs->u32GuestTrAttr;
5308
5309 /* Selector. */
5310 if (!(Tr.Sel & X86_SEL_LDT))
5311 { /* likely */ }
5312 else
5313 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegSelTr);
5314
5315 /* Base. */
5316 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
5317 {
5318 if (X86_IS_CANONICAL(Tr.u64Base))
5319 { /* likely */ }
5320 else
5321 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegBaseTr);
5322 }
5323
5324 /* Attributes. */
5325 /* Reserved bits (bits 31:17 and bits 11:8). */
5326 if (!(Tr.Attr.u & 0xfffe0f00))
5327 { /* likely */ }
5328 else
5329 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrTrRsvd);
5330
5331 if (!Tr.Attr.n.u1Unusable)
5332 { /* likely */ }
5333 else
5334 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrTrUnusable);
5335
5336 if ( Tr.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_BUSY
5337 || ( !fGstInLongMode
5338 && Tr.Attr.n.u4Type == X86_SEL_TYPE_SYS_286_TSS_BUSY))
5339 { /* likely */ }
5340 else
5341 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrTrType);
5342
5343 if (!Tr.Attr.n.u1DescType)
5344 { /* likely */ }
5345 else
5346 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrTrDescType);
5347
5348 if (Tr.Attr.n.u1Present)
5349 { /* likely */ }
5350 else
5351 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrTrPresent);
5352
5353 if ( ((Tr.u32Limit & 0x00000fff) == 0x00000fff || !Tr.Attr.n.u1Granularity)
5354 && ((Tr.u32Limit & 0xfff00000) == 0x00000000 || Tr.Attr.n.u1Granularity))
5355 { /* likely */ }
5356 else
5357 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestSegAttrTrGran);
5358 }
5359
5360 NOREF(pszInstr);
5361 NOREF(pszFailure);
5362 return VINF_SUCCESS;
5363}
5364
5365
5366/**
5367 * Checks guest GDTR and IDTR as part of VM-entry.
5368 *
5369 * @param pVCpu The cross context virtual CPU structure.
5370 * @param pszInstr The VMX instruction name (for logging purposes).
5371 */
5372DECLINLINE(int) iemVmxVmentryCheckGuestGdtrIdtr(PVMCPUCC pVCpu, const char *pszInstr)
5373{
5374 /*
5375 * GDTR and IDTR.
5376 * See Intel spec. 26.3.1.3 "Checks on Guest Descriptor-Table Registers".
5377 */
5378 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
5379 const char *const pszFailure = "VM-exit";
5380
5381 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
5382 {
5383 /* Base. */
5384 if (X86_IS_CANONICAL(pVmcs->u64GuestGdtrBase.u))
5385 { /* likely */ }
5386 else
5387 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestGdtrBase);
5388
5389 if (X86_IS_CANONICAL(pVmcs->u64GuestIdtrBase.u))
5390 { /* likely */ }
5391 else
5392 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestIdtrBase);
5393 }
5394
5395 /* Limit. */
5396 if (!RT_HI_U16(pVmcs->u32GuestGdtrLimit))
5397 { /* likely */ }
5398 else
5399 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestGdtrLimit);
5400
5401 if (!RT_HI_U16(pVmcs->u32GuestIdtrLimit))
5402 { /* likely */ }
5403 else
5404 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestIdtrLimit);
5405
5406 NOREF(pszInstr);
5407 NOREF(pszFailure);
5408 return VINF_SUCCESS;
5409}
5410
5411
5412/**
5413 * Checks guest RIP and RFLAGS as part of VM-entry.
5414 *
5415 * @param pVCpu The cross context virtual CPU structure.
5416 * @param pszInstr The VMX instruction name (for logging purposes).
5417 */
5418DECLINLINE(int) iemVmxVmentryCheckGuestRipRFlags(PVMCPUCC pVCpu, const char *pszInstr)
5419{
5420 /*
5421 * RIP and RFLAGS.
5422 * See Intel spec. 26.3.1.4 "Checks on Guest RIP and RFLAGS".
5423 */
5424 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
5425 const char *const pszFailure = "VM-exit";
5426 bool const fGstInLongMode = RT_BOOL(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
5427
5428 /* RIP. */
5429 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
5430 {
5431 X86DESCATTR AttrCs;
5432 AttrCs.u = pVmcs->u32GuestCsAttr;
5433 if ( !fGstInLongMode
5434 || !AttrCs.n.u1Long)
5435 {
5436 if (!RT_HI_U32(pVmcs->u64GuestRip.u))
5437 { /* likely */ }
5438 else
5439 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestRipRsvd);
5440 }
5441
5442 if ( fGstInLongMode
5443 && AttrCs.n.u1Long)
5444 {
5445 Assert(IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cMaxLinearAddrWidth == 48); /* Canonical. */
5446 if ( IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cMaxLinearAddrWidth < 64
5447 && X86_IS_CANONICAL(pVmcs->u64GuestRip.u))
5448 { /* likely */ }
5449 else
5450 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestRip);
5451 }
5452 }
5453
5454 /* RFLAGS (bits 63:22 (or 31:22), bits 15, 5, 3 are reserved, bit 1 MB1). */
5455 uint64_t const uGuestRFlags = IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode ? pVmcs->u64GuestRFlags.u
5456 : pVmcs->u64GuestRFlags.s.Lo;
5457 if ( !(uGuestRFlags & ~(X86_EFL_LIVE_MASK | X86_EFL_RA1_MASK))
5458 && (uGuestRFlags & X86_EFL_RA1_MASK) == X86_EFL_RA1_MASK)
5459 { /* likely */ }
5460 else
5461 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestRFlagsRsvd);
5462
5463 if (!(uGuestRFlags & X86_EFL_VM))
5464 { /* likely */ }
5465 else
5466 {
5467 if ( fGstInLongMode
5468 || !(pVmcs->u64GuestCr0.u & X86_CR0_PE))
5469 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestRFlagsVm);
5470 }
5471
5472 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(pVmcs->u32EntryIntInfo))
5473 {
5474 if (uGuestRFlags & X86_EFL_IF)
5475 { /* likely */ }
5476 else
5477 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestRFlagsIf);
5478 }
5479
5480 NOREF(pszInstr);
5481 NOREF(pszFailure);
5482 return VINF_SUCCESS;
5483}
5484
5485
5486/**
5487 * Checks guest non-register state as part of VM-entry.
5488 *
5489 * @param pVCpu The cross context virtual CPU structure.
5490 * @param pszInstr The VMX instruction name (for logging purposes).
5491 */
5492DECLINLINE(int) iemVmxVmentryCheckGuestNonRegState(PVMCPUCC pVCpu, const char *pszInstr)
5493{
5494 /*
5495 * Guest non-register state.
5496 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5497 */
5498 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
5499 const char *const pszFailure = "VM-exit";
5500
5501 /*
5502 * Activity state.
5503 */
5504 uint64_t const u64GuestVmxMiscMsr = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Misc;
5505 uint32_t const fActivityStateMask = RT_BF_GET(u64GuestVmxMiscMsr, VMX_BF_MISC_ACTIVITY_STATES);
5506 if (!(pVmcs->u32GuestActivityState & fActivityStateMask))
5507 { /* likely */ }
5508 else
5509 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestActStateRsvd);
5510
5511 X86DESCATTR AttrSs; AttrSs.u = pVmcs->u32GuestSsAttr;
5512 if ( !AttrSs.n.u2Dpl
5513 || pVmcs->u32GuestActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT)
5514 { /* likely */ }
5515 else
5516 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestActStateSsDpl);
5517
5518 if ( pVmcs->u32GuestIntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_STI
5519 || pVmcs->u32GuestIntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
5520 {
5521 if (pVmcs->u32GuestActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE)
5522 { /* likely */ }
5523 else
5524 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestActStateStiMovSs);
5525 }
5526
5527 if (VMX_ENTRY_INT_INFO_IS_VALID(pVmcs->u32EntryIntInfo))
5528 {
5529 uint8_t const uType = VMX_ENTRY_INT_INFO_TYPE(pVmcs->u32EntryIntInfo);
5530 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(pVmcs->u32EntryIntInfo);
5531 AssertCompile(VMX_V_GUEST_ACTIVITY_STATE_MASK == (VMX_VMCS_GUEST_ACTIVITY_HLT | VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN));
5532 switch (pVmcs->u32GuestActivityState)
5533 {
5534 case VMX_VMCS_GUEST_ACTIVITY_HLT:
5535 {
5536 if ( uType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT
5537 || uType == VMX_ENTRY_INT_INFO_TYPE_NMI
5538 || ( uType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
5539 && ( uVector == X86_XCPT_DB
5540 || uVector == X86_XCPT_MC))
5541 || ( uType == VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT
5542 && uVector == VMX_ENTRY_INT_INFO_VECTOR_MTF))
5543 { /* likely */ }
5544 else
5545 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestActStateHlt);
5546 break;
5547 }
5548
5549 case VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN:
5550 {
5551 if ( uType == VMX_ENTRY_INT_INFO_TYPE_NMI
5552 || ( uType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
5553 && uVector == X86_XCPT_MC))
5554 { /* likely */ }
5555 else
5556 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestActStateShutdown);
5557 break;
5558 }
5559
5560 case VMX_VMCS_GUEST_ACTIVITY_ACTIVE:
5561 default:
5562 break;
5563 }
5564 }
5565
5566 /*
5567 * Interruptibility state.
5568 */
5569 if (!(pVmcs->u32GuestIntrState & ~VMX_VMCS_GUEST_INT_STATE_MASK))
5570 { /* likely */ }
5571 else
5572 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestIntStateRsvd);
5573
5574 if ((pVmcs->u32GuestIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
5575 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
5576 { /* likely */ }
5577 else
5578 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestIntStateStiMovSs);
5579
5580 if ( (pVmcs->u64GuestRFlags.u & X86_EFL_IF)
5581 || !(pVmcs->u32GuestIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
5582 { /* likely */ }
5583 else
5584 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestIntStateRFlagsSti);
5585
5586 if (VMX_ENTRY_INT_INFO_IS_VALID(pVmcs->u32EntryIntInfo))
5587 {
5588 uint8_t const uType = VMX_ENTRY_INT_INFO_TYPE(pVmcs->u32EntryIntInfo);
5589 if (uType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
5590 {
5591 if (!(pVmcs->u32GuestIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)))
5592 { /* likely */ }
5593 else
5594 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestIntStateExtInt);
5595 }
5596 else if (uType == VMX_ENTRY_INT_INFO_TYPE_NMI)
5597 {
5598 if (!(pVmcs->u32GuestIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)))
5599 { /* likely */ }
5600 else
5601 {
5602 /*
5603 * We don't support injecting NMIs when blocking-by-STI would be in effect.
5604 * We update the Exit qualification only when blocking-by-STI is set
5605 * without blocking-by-MovSS being set. Although in practise it does not
5606 * make much difference since the order of checks are implementation defined.
5607 */
5608 if (!(pVmcs->u32GuestIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
5609 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_NMI_INJECT);
5610 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestIntStateNmi);
5611 }
5612
5613 if ( !(pVmcs->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
5614 || !(pVmcs->u32GuestIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI))
5615 { /* likely */ }
5616 else
5617 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestIntStateVirtNmi);
5618 }
5619 }
5620
5621 /* We don't support SMM yet. So blocking-by-SMIs must not be set. */
5622 if (!(pVmcs->u32GuestIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI))
5623 { /* likely */ }
5624 else
5625 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestIntStateSmi);
5626
5627 /* We don't support SGX yet. So enclave-interruption must not be set. */
5628 if (!(pVmcs->u32GuestIntrState & VMX_VMCS_GUEST_INT_STATE_ENCLAVE))
5629 { /* likely */ }
5630 else
5631 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestIntStateEnclave);
5632
5633 /*
5634 * Pending debug exceptions.
5635 */
5636 uint64_t const uPendingDbgXcpts = IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode
5637 ? pVmcs->u64GuestPendingDbgXcpts.u
5638 : pVmcs->u64GuestPendingDbgXcpts.s.Lo;
5639 if (!(uPendingDbgXcpts & ~VMX_VMCS_GUEST_PENDING_DEBUG_VALID_MASK))
5640 { /* likely */ }
5641 else
5642 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPndDbgXcptRsvd);
5643
5644 if ( (pVmcs->u32GuestIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
5645 || pVmcs->u32GuestActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
5646 {
5647 if ( (pVmcs->u64GuestRFlags.u & X86_EFL_TF)
5648 && !(pVmcs->u64GuestDebugCtlMsr.u & MSR_IA32_DEBUGCTL_BTF)
5649 && !(uPendingDbgXcpts & VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS))
5650 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPndDbgXcptBsTf);
5651
5652 if ( ( !(pVmcs->u64GuestRFlags.u & X86_EFL_TF)
5653 || (pVmcs->u64GuestDebugCtlMsr.u & MSR_IA32_DEBUGCTL_BTF))
5654 && (uPendingDbgXcpts & VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS))
5655 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPndDbgXcptBsNoTf);
5656 }
5657
5658 /* We don't support RTM (Real-time Transactional Memory) yet. */
5659 if (!(uPendingDbgXcpts & VMX_VMCS_GUEST_PENDING_DEBUG_RTM))
5660 { /* likely */ }
5661 else
5662 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPndDbgXcptRtm);
5663
5664 /*
5665 * VMCS link pointer.
5666 */
5667 if (pVmcs->u64VmcsLinkPtr.u != UINT64_C(0xffffffffffffffff))
5668 {
5669 RTGCPHYS const GCPhysShadowVmcs = pVmcs->u64VmcsLinkPtr.u;
5670 /* We don't support SMM yet (so VMCS link pointer cannot be the current VMCS). */
5671 if (GCPhysShadowVmcs != IEM_VMX_GET_CURRENT_VMCS(pVCpu))
5672 { /* likely */ }
5673 else
5674 {
5675 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_VMCS_LINK_PTR);
5676 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VmcsLinkPtrCurVmcs);
5677 }
5678
5679 /* Validate the address. */
5680 if ( !(GCPhysShadowVmcs & X86_PAGE_4K_OFFSET_MASK)
5681 && !(GCPhysShadowVmcs >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
5682 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysShadowVmcs))
5683 { /* likely */ }
5684 else
5685 {
5686 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_VMCS_LINK_PTR);
5687 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrVmcsLinkPtr);
5688 }
5689 }
5690
5691 NOREF(pszInstr);
5692 NOREF(pszFailure);
5693 return VINF_SUCCESS;
5694}
5695
5696
5697#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
5698/**
5699 * Checks guest PDPTEs as part of VM-entry.
5700 *
5701 * @param pVCpu The cross context virtual CPU structure.
5702 * @param pszInstr The VMX instruction name (for logging purposes).
5703 */
5704IEM_STATIC int iemVmxVmentryCheckGuestPdptes(PVMCPUCC pVCpu, const char *pszInstr)
5705{
5706 /*
5707 * Guest PDPTEs.
5708 * See Intel spec. 26.3.1.5 "Checks on Guest Page-Directory-Pointer-Table Entries".
5709 */
5710 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
5711 const char * const pszFailure = "VM-exit";
5712
5713 /*
5714 * When EPT is used, we only validate the PAE PDPTEs provided in the VMCS.
5715 * Otherwise, we load any PAE PDPTEs referenced by CR3 at a later point.
5716 */
5717 if ( iemVmxVmcsIsGuestPaePagingEnabled(pVmcs)
5718 && (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT))
5719 {
5720 /* Get PDPTEs from the VMCS. */
5721 X86PDPE aPaePdptes[X86_PG_PAE_PDPE_ENTRIES];
5722 aPaePdptes[0].u = pVmcs->u64GuestPdpte0.u;
5723 aPaePdptes[1].u = pVmcs->u64GuestPdpte1.u;
5724 aPaePdptes[2].u = pVmcs->u64GuestPdpte2.u;
5725 aPaePdptes[3].u = pVmcs->u64GuestPdpte3.u;
5726
5727 /* Check validity of the PDPTEs. */
5728 bool const fValid = PGMGstArePaePdpesValid(pVCpu, &aPaePdptes[0]);
5729 if (fValid)
5730 { /* likely */ }
5731 else
5732 {
5733 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_PDPTE);
5734 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPdpte);
5735 }
5736 }
5737
5738 NOREF(pszFailure);
5739 NOREF(pszInstr);
5740 return VINF_SUCCESS;
5741}
5742#endif /* VBOX_WITH_NESTED_HWVIRT_VMX_EPT */
5743
5744
5745/**
5746 * Checks guest-state as part of VM-entry.
5747 *
5748 * @returns VBox status code.
5749 * @param pVCpu The cross context virtual CPU structure.
5750 * @param pszInstr The VMX instruction name (for logging purposes).
5751 */
5752IEM_STATIC int iemVmxVmentryCheckGuestState(PVMCPUCC pVCpu, const char *pszInstr)
5753{
5754 int rc = iemVmxVmentryCheckGuestControlRegsMsrs(pVCpu, pszInstr);
5755 if (RT_SUCCESS(rc))
5756 {
5757 rc = iemVmxVmentryCheckGuestSegRegs(pVCpu, pszInstr);
5758 if (RT_SUCCESS(rc))
5759 {
5760 rc = iemVmxVmentryCheckGuestGdtrIdtr(pVCpu, pszInstr);
5761 if (RT_SUCCESS(rc))
5762 {
5763 rc = iemVmxVmentryCheckGuestRipRFlags(pVCpu, pszInstr);
5764 if (RT_SUCCESS(rc))
5765 {
5766 rc = iemVmxVmentryCheckGuestNonRegState(pVCpu, pszInstr);
5767#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
5768 if (RT_SUCCESS(rc))
5769 rc = iemVmxVmentryCheckGuestPdptes(pVCpu, pszInstr);
5770#endif
5771 }
5772 }
5773 }
5774 }
5775 return rc;
5776}
5777
5778
5779/**
5780 * Checks host-state as part of VM-entry.
5781 *
5782 * @returns VBox status code.
5783 * @param pVCpu The cross context virtual CPU structure.
5784 * @param pszInstr The VMX instruction name (for logging purposes).
5785 */
5786IEM_STATIC int iemVmxVmentryCheckHostState(PVMCPUCC pVCpu, const char *pszInstr)
5787{
5788 /*
5789 * Host Control Registers and MSRs.
5790 * See Intel spec. 26.2.2 "Checks on Host Control Registers and MSRs".
5791 */
5792 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
5793 const char * const pszFailure = "VMFail";
5794
5795 /* CR0 reserved bits. */
5796 {
5797 /* CR0 MB1 bits. */
5798 uint64_t const u64Cr0Fixed0 = iemVmxGetCr0Fixed0(pVCpu);
5799 if ((pVmcs->u64HostCr0.u & u64Cr0Fixed0) == u64Cr0Fixed0)
5800 { /* likely */ }
5801 else
5802 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostCr0Fixed0);
5803
5804 /* CR0 MBZ bits. */
5805 uint64_t const u64Cr0Fixed1 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr0Fixed1;
5806 if (!(pVmcs->u64HostCr0.u & ~u64Cr0Fixed1))
5807 { /* likely */ }
5808 else
5809 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostCr0Fixed1);
5810 }
5811
5812 /* CR4 reserved bits. */
5813 {
5814 /* CR4 MB1 bits. */
5815 uint64_t const u64Cr4Fixed0 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed0;
5816 if ((pVmcs->u64HostCr4.u & u64Cr4Fixed0) == u64Cr4Fixed0)
5817 { /* likely */ }
5818 else
5819 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostCr4Fixed0);
5820
5821 /* CR4 MBZ bits. */
5822 uint64_t const u64Cr4Fixed1 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed1;
5823 if (!(pVmcs->u64HostCr4.u & ~u64Cr4Fixed1))
5824 { /* likely */ }
5825 else
5826 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostCr4Fixed1);
5827 }
5828
5829 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
5830 {
5831 /* CR3 reserved bits. */
5832 if (!(pVmcs->u64HostCr3.u >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cMaxPhysAddrWidth))
5833 { /* likely */ }
5834 else
5835 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostCr3);
5836
5837 /* SYSENTER ESP and SYSENTER EIP. */
5838 if ( X86_IS_CANONICAL(pVmcs->u64HostSysenterEsp.u)
5839 && X86_IS_CANONICAL(pVmcs->u64HostSysenterEip.u))
5840 { /* likely */ }
5841 else
5842 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostSysenterEspEip);
5843 }
5844
5845 /* We don't support IA32_PERF_GLOBAL_CTRL MSR yet. */
5846 Assert(!(pVmcs->u32ExitCtls & VMX_EXIT_CTLS_LOAD_PERF_MSR));
5847
5848 /* PAT MSR. */
5849 if ( !(pVmcs->u32ExitCtls & VMX_EXIT_CTLS_LOAD_PAT_MSR)
5850 || CPUMIsPatMsrValid(pVmcs->u64HostPatMsr.u))
5851 { /* likely */ }
5852 else
5853 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostPatMsr);
5854
5855 /* EFER MSR. */
5856 uint64_t const uValidEferMask = CPUMGetGuestEferMsrValidMask(pVCpu->CTX_SUFF(pVM));
5857 if ( !(pVmcs->u32ExitCtls & VMX_EXIT_CTLS_LOAD_EFER_MSR)
5858 || !(pVmcs->u64HostEferMsr.u & ~uValidEferMask))
5859 { /* likely */ }
5860 else
5861 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostEferMsrRsvd);
5862
5863 bool const fHostInLongMode = RT_BOOL(pVmcs->u32ExitCtls & VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE);
5864 bool const fHostLma = RT_BOOL(pVmcs->u64HostEferMsr.u & MSR_K6_EFER_LMA);
5865 bool const fHostLme = RT_BOOL(pVmcs->u64HostEferMsr.u & MSR_K6_EFER_LME);
5866 if ( fHostInLongMode == fHostLma
5867 && fHostInLongMode == fHostLme)
5868 { /* likely */ }
5869 else
5870 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostEferMsr);
5871
5872 /*
5873 * Host Segment and Descriptor-Table Registers.
5874 * See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
5875 */
5876 /* Selector RPL and TI. */
5877 if ( !(pVmcs->HostCs & (X86_SEL_RPL | X86_SEL_LDT))
5878 && !(pVmcs->HostSs & (X86_SEL_RPL | X86_SEL_LDT))
5879 && !(pVmcs->HostDs & (X86_SEL_RPL | X86_SEL_LDT))
5880 && !(pVmcs->HostEs & (X86_SEL_RPL | X86_SEL_LDT))
5881 && !(pVmcs->HostFs & (X86_SEL_RPL | X86_SEL_LDT))
5882 && !(pVmcs->HostGs & (X86_SEL_RPL | X86_SEL_LDT))
5883 && !(pVmcs->HostTr & (X86_SEL_RPL | X86_SEL_LDT)))
5884 { /* likely */ }
5885 else
5886 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostSel);
5887
5888 /* CS and TR selectors cannot be 0. */
5889 if ( pVmcs->HostCs
5890 && pVmcs->HostTr)
5891 { /* likely */ }
5892 else
5893 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostCsTr);
5894
5895 /* SS cannot be 0 if 32-bit host. */
5896 if ( fHostInLongMode
5897 || pVmcs->HostSs)
5898 { /* likely */ }
5899 else
5900 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostSs);
5901
5902 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
5903 {
5904 /* FS, GS, GDTR, IDTR, TR base address. */
5905 if ( X86_IS_CANONICAL(pVmcs->u64HostFsBase.u)
5906 && X86_IS_CANONICAL(pVmcs->u64HostFsBase.u)
5907 && X86_IS_CANONICAL(pVmcs->u64HostGdtrBase.u)
5908 && X86_IS_CANONICAL(pVmcs->u64HostIdtrBase.u)
5909 && X86_IS_CANONICAL(pVmcs->u64HostTrBase.u))
5910 { /* likely */ }
5911 else
5912 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostSegBase);
5913 }
5914
5915 /*
5916 * Host address-space size for 64-bit CPUs.
5917 * See Intel spec. 26.2.4 "Checks Related to Address-Space Size".
5918 */
5919 bool const fGstInLongMode = RT_BOOL(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
5920 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
5921 {
5922 bool const fCpuInLongMode = CPUMIsGuestInLongMode(pVCpu);
5923
5924 /* Logical processor in IA-32e mode. */
5925 if (fCpuInLongMode)
5926 {
5927 if (fHostInLongMode)
5928 {
5929 /* PAE must be set. */
5930 if (pVmcs->u64HostCr4.u & X86_CR4_PAE)
5931 { /* likely */ }
5932 else
5933 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostCr4Pae);
5934
5935 /* RIP must be canonical. */
5936 if (X86_IS_CANONICAL(pVmcs->u64HostRip.u))
5937 { /* likely */ }
5938 else
5939 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostRip);
5940 }
5941 else
5942 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostLongMode);
5943 }
5944 else
5945 {
5946 /* Logical processor is outside IA-32e mode. */
5947 if ( !fGstInLongMode
5948 && !fHostInLongMode)
5949 {
5950 /* PCIDE should not be set. */
5951 if (!(pVmcs->u64HostCr4.u & X86_CR4_PCIDE))
5952 { /* likely */ }
5953 else
5954 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostCr4Pcide);
5955
5956 /* The high 32-bits of RIP MBZ. */
5957 if (!pVmcs->u64HostRip.s.Hi)
5958 { /* likely */ }
5959 else
5960 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostRipRsvd);
5961 }
5962 else
5963 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostGuestLongMode);
5964 }
5965 }
5966 else
5967 {
5968 /* Host address-space size for 32-bit CPUs. */
5969 if ( !fGstInLongMode
5970 && !fHostInLongMode)
5971 { /* likely */ }
5972 else
5973 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostGuestLongModeNoCpu);
5974 }
5975
5976 NOREF(pszInstr);
5977 NOREF(pszFailure);
5978 return VINF_SUCCESS;
5979}
5980
5981
5982#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
5983/**
5984 * Checks the EPT pointer VMCS field as part of VM-entry.
5985 *
5986 * @returns VBox status code.
5987 * @param pVCpu The cross context virtual CPU structure.
5988 * @param uEptPtr The EPT pointer to check.
5989 * @param penmVmxDiag Where to store the diagnostic reason on failure (not
5990 * updated on success). Optional, can be NULL.
5991 */
5992IEM_STATIC int iemVmxVmentryCheckEptPtr(PVMCPUCC pVCpu, uint64_t uEptPtr, VMXVDIAG *penmVmxDiag)
5993{
5994 VMXVDIAG enmVmxDiag;
5995
5996 /* Reserved bits. */
5997 uint8_t const cMaxPhysAddrWidth = IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cMaxPhysAddrWidth;
5998 uint64_t const fValidMask = VMX_EPTP_VALID_MASK & ~(UINT64_MAX << cMaxPhysAddrWidth);
5999 if (uEptPtr & fValidMask)
6000 {
6001 /* Memory Type. */
6002 uint64_t const fCaps = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64EptVpidCaps;
6003 uint8_t const fMemType = RT_BF_GET(uEptPtr, VMX_BF_EPTP_MEMTYPE);
6004 if ( ( fMemType == VMX_EPTP_MEMTYPE_WB
6005 && RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_MEMTYPE_WB))
6006 || ( fMemType == VMX_EPTP_MEMTYPE_UC
6007 && RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_MEMTYPE_UC)))
6008 {
6009 /*
6010 * Page walk length (PML4).
6011 * Intel used to specify bit 7 of IA32_VMX_EPT_VPID_CAP as page walk length
6012 * of 5 but that seems to be removed from the latest specs. leaving only PML4
6013 * as the maximum supported page-walk level hence we hardcode it as 3 (1 less than 4)
6014 */
6015 Assert(RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_PAGE_WALK_LENGTH_4));
6016 if (RT_BF_GET(uEptPtr, VMX_BF_EPTP_PAGE_WALK_LENGTH) == 3)
6017 {
6018 /* Access and dirty bits support in EPT structures. */
6019 if ( !RT_BF_GET(uEptPtr, VMX_BF_EPTP_ACCESS_DIRTY)
6020 || RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY))
6021 return VINF_SUCCESS;
6022
6023 enmVmxDiag = kVmxVDiag_Vmentry_EptpAccessDirty;
6024 }
6025 else
6026 enmVmxDiag = kVmxVDiag_Vmentry_EptpPageWalkLength;
6027 }
6028 else
6029 enmVmxDiag = kVmxVDiag_Vmentry_EptpMemType;
6030 }
6031 else
6032 enmVmxDiag = kVmxVDiag_Vmentry_EptpRsvd;
6033
6034 if (penmVmxDiag)
6035 *penmVmxDiag = enmVmxDiag;
6036 return VERR_VMX_VMENTRY_FAILED;
6037}
6038#endif
6039
6040
6041/**
6042 * Checks VMCS controls fields as part of VM-entry.
6043 *
6044 * @returns VBox status code.
6045 * @param pVCpu The cross context virtual CPU structure.
6046 * @param pszInstr The VMX instruction name (for logging purposes).
6047 *
6048 * @remarks This may update secondary-processor based VM-execution control fields
6049 * in the current VMCS if necessary.
6050 */
6051IEM_STATIC int iemVmxVmentryCheckCtls(PVMCPUCC pVCpu, const char *pszInstr)
6052{
6053 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
6054 const char * const pszFailure = "VMFail";
6055 bool const fVmxTrueMsrs = RT_BOOL(pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Basic & VMX_BF_BASIC_TRUE_CTLS_MASK);
6056
6057 /*
6058 * VM-execution controls.
6059 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
6060 */
6061 {
6062 /* Pin-based VM-execution controls. */
6063 {
6064 VMXCTLSMSR const PinCtls = fVmxTrueMsrs ? pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.TruePinCtls
6065 : pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.PinCtls;
6066 if (!(~pVmcs->u32PinCtls & PinCtls.n.allowed0))
6067 { /* likely */ }
6068 else
6069 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_PinCtlsDisallowed0);
6070
6071 if (!(pVmcs->u32PinCtls & ~PinCtls.n.allowed1))
6072 { /* likely */ }
6073 else
6074 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_PinCtlsAllowed1);
6075 }
6076
6077 /* Processor-based VM-execution controls. */
6078 {
6079 VMXCTLSMSR const ProcCtls = fVmxTrueMsrs ? pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.TrueProcCtls
6080 : pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.ProcCtls;
6081 if (!(~pVmcs->u32ProcCtls & ProcCtls.n.allowed0))
6082 { /* likely */ }
6083 else
6084 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ProcCtlsDisallowed0);
6085
6086 if (!(pVmcs->u32ProcCtls & ~ProcCtls.n.allowed1))
6087 { /* likely */ }
6088 else
6089 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ProcCtlsAllowed1);
6090 }
6091
6092 /* Secondary processor-based VM-execution controls. */
6093 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
6094 {
6095 VMXCTLSMSR const ProcCtls2 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.ProcCtls2;
6096 if (!(~pVmcs->u32ProcCtls2 & ProcCtls2.n.allowed0))
6097 { /* likely */ }
6098 else
6099 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ProcCtls2Disallowed0);
6100
6101 if (!(pVmcs->u32ProcCtls2 & ~ProcCtls2.n.allowed1))
6102 { /* likely */ }
6103 else
6104 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ProcCtls2Allowed1);
6105 }
6106 else
6107 Assert(!pVmcs->u32ProcCtls2);
6108
6109 /* CR3-target count. */
6110 if (pVmcs->u32Cr3TargetCount <= VMX_V_CR3_TARGET_COUNT)
6111 { /* likely */ }
6112 else
6113 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_Cr3TargetCount);
6114
6115 /* I/O bitmaps physical addresses. */
6116 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_IO_BITMAPS)
6117 {
6118 RTGCPHYS const GCPhysIoBitmapA = pVmcs->u64AddrIoBitmapA.u;
6119 if ( !(GCPhysIoBitmapA & X86_PAGE_4K_OFFSET_MASK)
6120 && !(GCPhysIoBitmapA >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6121 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysIoBitmapA))
6122 { /* likely */ }
6123 else
6124 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrIoBitmapA);
6125
6126 RTGCPHYS const GCPhysIoBitmapB = pVmcs->u64AddrIoBitmapB.u;
6127 if ( !(GCPhysIoBitmapB & X86_PAGE_4K_OFFSET_MASK)
6128 && !(GCPhysIoBitmapB >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6129 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysIoBitmapB))
6130 { /* likely */ }
6131 else
6132 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrIoBitmapB);
6133 }
6134
6135 /* MSR bitmap physical address. */
6136 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
6137 {
6138 RTGCPHYS const GCPhysMsrBitmap = pVmcs->u64AddrMsrBitmap.u;
6139 if ( !(GCPhysMsrBitmap & X86_PAGE_4K_OFFSET_MASK)
6140 && !(GCPhysMsrBitmap >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6141 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysMsrBitmap))
6142 { /* likely */ }
6143 else
6144 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrMsrBitmap);
6145 }
6146
6147 /* TPR shadow related controls. */
6148 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
6149 {
6150 /* Virtual-APIC page physical address. */
6151 RTGCPHYS const GCPhysVirtApic = pVmcs->u64AddrVirtApic.u;
6152 if ( !(GCPhysVirtApic & X86_PAGE_4K_OFFSET_MASK)
6153 && !(GCPhysVirtApic >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6154 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysVirtApic))
6155 { /* likely */ }
6156 else
6157 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrVirtApicPage);
6158
6159 /* TPR threshold bits 31:4 MBZ without virtual-interrupt delivery. */
6160 if ( !(pVmcs->u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)
6161 || (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY))
6162 { /* likely */ }
6163 else
6164 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_TprThresholdRsvd);
6165
6166 /* The rest done XXX document */
6167 }
6168 else
6169 {
6170 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_X2APIC_MODE)
6171 && !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_APIC_REG_VIRT)
6172 && !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY))
6173 { /* likely */ }
6174 else
6175 {
6176 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_X2APIC_MODE)
6177 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtX2ApicTprShadow);
6178 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_APIC_REG_VIRT)
6179 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ApicRegVirt);
6180 Assert(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY);
6181 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtIntDelivery);
6182 }
6183 }
6184
6185 /* NMI exiting and virtual-NMIs. */
6186 if ( (pVmcs->u32PinCtls & VMX_PIN_CTLS_NMI_EXIT)
6187 || !(pVmcs->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI))
6188 { /* likely */ }
6189 else
6190 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtNmi);
6191
6192 /* Virtual-NMIs and NMI-window exiting. */
6193 if ( (pVmcs->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
6194 || !(pVmcs->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
6195 { /* likely */ }
6196 else
6197 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_NmiWindowExit);
6198
6199 /* Virtualize APIC accesses. */
6200 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
6201 {
6202 /* APIC-access physical address. */
6203 RTGCPHYS const GCPhysApicAccess = pVmcs->u64AddrApicAccess.u;
6204 if ( !(GCPhysApicAccess & X86_PAGE_4K_OFFSET_MASK)
6205 && !(GCPhysApicAccess >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6206 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysApicAccess))
6207 { /* likely */ }
6208 else
6209 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrApicAccess);
6210
6211 /*
6212 * Disallow APIC-access page and virtual-APIC page from being the same address.
6213 * Note! This is not an Intel requirement, but one imposed by our implementation.
6214 */
6215 /** @todo r=ramshankar: This is done primarily to simplify recursion scenarios while
6216 * redirecting accesses between the APIC-access page and the virtual-APIC
6217 * page. If any nested hypervisor requires this, we can implement it later. */
6218 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
6219 {
6220 RTGCPHYS const GCPhysVirtApic = pVmcs->u64AddrVirtApic.u;
6221 if (GCPhysVirtApic != GCPhysApicAccess)
6222 { /* likely */ }
6223 else
6224 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrApicAccessEqVirtApic);
6225 }
6226 }
6227
6228 /* Virtualize-x2APIC mode is mutually exclusive with virtualize-APIC accesses. */
6229 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_X2APIC_MODE)
6230 || !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS))
6231 { /* likely */ }
6232 else
6233 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtX2ApicVirtApic);
6234
6235 /* Virtual-interrupt delivery requires external interrupt exiting. */
6236 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY)
6237 || (pVmcs->u32PinCtls & VMX_PIN_CTLS_EXT_INT_EXIT))
6238 { /* likely */ }
6239 else
6240 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtX2ApicVirtApic);
6241
6242 /* VPID. */
6243 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VPID)
6244 || pVmcs->u16Vpid != 0)
6245 { /* likely */ }
6246 else
6247 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_Vpid);
6248
6249#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
6250 /* Extended-Page-Table Pointer (EPTP). */
6251 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT)
6252 {
6253 VMXVDIAG enmVmxDiag;
6254 int const rc = iemVmxVmentryCheckEptPtr(pVCpu, pVmcs->u64EptPtr.u, &enmVmxDiag);
6255 if (RT_SUCCESS(rc))
6256 { /* likely */ }
6257 else
6258 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmVmxDiag);
6259 }
6260#else
6261 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT));
6262 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST));
6263#endif
6264 Assert(!(pVmcs->u32PinCtls & VMX_PIN_CTLS_POSTED_INT)); /* We don't support posted interrupts yet. */
6265 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_PML)); /* We don't support PML yet. */
6266 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VMFUNC)); /* We don't support VM functions yet. */
6267 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT_XCPT_VE)); /* We don't support EPT-violation #VE yet. */
6268 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)); /* We don't support Pause-loop exiting yet. */
6269 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_TSC_SCALING)); /* We don't support TSC-scaling yet. */
6270
6271 /* VMCS shadowing. */
6272 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
6273 {
6274 /* VMREAD-bitmap physical address. */
6275 RTGCPHYS const GCPhysVmreadBitmap = pVmcs->u64AddrVmreadBitmap.u;
6276 if ( !(GCPhysVmreadBitmap & X86_PAGE_4K_OFFSET_MASK)
6277 && !(GCPhysVmreadBitmap >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6278 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysVmreadBitmap))
6279 { /* likely */ }
6280 else
6281 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrVmreadBitmap);
6282
6283 /* VMWRITE-bitmap physical address. */
6284 RTGCPHYS const GCPhysVmwriteBitmap = pVmcs->u64AddrVmreadBitmap.u;
6285 if ( !(GCPhysVmwriteBitmap & X86_PAGE_4K_OFFSET_MASK)
6286 && !(GCPhysVmwriteBitmap >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6287 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysVmwriteBitmap))
6288 { /* likely */ }
6289 else
6290 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrVmwriteBitmap);
6291 }
6292 }
6293
6294 /*
6295 * VM-exit controls.
6296 * See Intel spec. 26.2.1.2 "VM-Exit Control Fields".
6297 */
6298 {
6299 VMXCTLSMSR const ExitCtls = fVmxTrueMsrs ? pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.TrueExitCtls
6300 : pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.ExitCtls;
6301 if (!(~pVmcs->u32ExitCtls & ExitCtls.n.allowed0))
6302 { /* likely */ }
6303 else
6304 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ExitCtlsDisallowed0);
6305
6306 if (!(pVmcs->u32ExitCtls & ~ExitCtls.n.allowed1))
6307 { /* likely */ }
6308 else
6309 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ExitCtlsAllowed1);
6310
6311 /* Save preemption timer without activating it. */
6312 if ( (pVmcs->u32PinCtls & VMX_PIN_CTLS_PREEMPT_TIMER)
6313 || !(pVmcs->u32ProcCtls & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER))
6314 { /* likely */ }
6315 else
6316 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_SavePreemptTimer);
6317
6318 /* VM-exit MSR-store count and VM-exit MSR-store area address. */
6319 if (pVmcs->u32ExitMsrStoreCount)
6320 {
6321 if ( !(pVmcs->u64AddrExitMsrStore.u & VMX_AUTOMSR_OFFSET_MASK)
6322 && !(pVmcs->u64AddrExitMsrStore.u >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6323 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), pVmcs->u64AddrExitMsrStore.u))
6324 { /* likely */ }
6325 else
6326 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrExitMsrStore);
6327 }
6328
6329 /* VM-exit MSR-load count and VM-exit MSR-load area address. */
6330 if (pVmcs->u32ExitMsrLoadCount)
6331 {
6332 if ( !(pVmcs->u64AddrExitMsrLoad.u & VMX_AUTOMSR_OFFSET_MASK)
6333 && !(pVmcs->u64AddrExitMsrLoad.u >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6334 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), pVmcs->u64AddrExitMsrLoad.u))
6335 { /* likely */ }
6336 else
6337 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrExitMsrLoad);
6338 }
6339 }
6340
6341 /*
6342 * VM-entry controls.
6343 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
6344 */
6345 {
6346 VMXCTLSMSR const EntryCtls = fVmxTrueMsrs ? pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.TrueEntryCtls
6347 : pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.EntryCtls;
6348 if (!(~pVmcs->u32EntryCtls & EntryCtls.n.allowed0))
6349 { /* likely */ }
6350 else
6351 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryCtlsDisallowed0);
6352
6353 if (!(pVmcs->u32EntryCtls & ~EntryCtls.n.allowed1))
6354 { /* likely */ }
6355 else
6356 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryCtlsAllowed1);
6357
6358 /* Event injection. */
6359 uint32_t const uIntInfo = pVmcs->u32EntryIntInfo;
6360 if (RT_BF_GET(uIntInfo, VMX_BF_ENTRY_INT_INFO_VALID))
6361 {
6362 /* Type and vector. */
6363 uint8_t const uType = RT_BF_GET(uIntInfo, VMX_BF_ENTRY_INT_INFO_TYPE);
6364 uint8_t const uVector = RT_BF_GET(uIntInfo, VMX_BF_ENTRY_INT_INFO_VECTOR);
6365 uint8_t const uRsvd = RT_BF_GET(uIntInfo, VMX_BF_ENTRY_INT_INFO_RSVD_12_30);
6366 if ( !uRsvd
6367 && VMXIsEntryIntInfoTypeValid(IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxMonitorTrapFlag, uType)
6368 && VMXIsEntryIntInfoVectorValid(uVector, uType))
6369 { /* likely */ }
6370 else
6371 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryIntInfoTypeVecRsvd);
6372
6373 /* Exception error code. */
6374 if (RT_BF_GET(uIntInfo, VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID))
6375 {
6376 /* Delivery possible only in Unrestricted-guest mode when CR0.PE is set. */
6377 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST)
6378 || (pVmcs->u64GuestCr0.s.Lo & X86_CR0_PE))
6379 { /* likely */ }
6380 else
6381 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryIntInfoErrCodePe);
6382
6383 /* Exceptions that provide an error code. */
6384 if ( uType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
6385 && ( uVector == X86_XCPT_DF
6386 || uVector == X86_XCPT_TS
6387 || uVector == X86_XCPT_NP
6388 || uVector == X86_XCPT_SS
6389 || uVector == X86_XCPT_GP
6390 || uVector == X86_XCPT_PF
6391 || uVector == X86_XCPT_AC))
6392 { /* likely */ }
6393 else
6394 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryIntInfoErrCodeVec);
6395
6396 /* Exception error-code reserved bits. */
6397 if (!(pVmcs->u32EntryXcptErrCode & ~VMX_ENTRY_INT_XCPT_ERR_CODE_VALID_MASK))
6398 { /* likely */ }
6399 else
6400 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryXcptErrCodeRsvd);
6401
6402 /* Injecting a software interrupt, software exception or privileged software exception. */
6403 if ( uType == VMX_ENTRY_INT_INFO_TYPE_SW_INT
6404 || uType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT
6405 || uType == VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT)
6406 {
6407 /* Instruction length must be in the range 0-15. */
6408 if (pVmcs->u32EntryInstrLen <= VMX_ENTRY_INSTR_LEN_MAX)
6409 { /* likely */ }
6410 else
6411 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryInstrLen);
6412
6413 /* However, instruction length of 0 is allowed only when its CPU feature is present. */
6414 if ( pVmcs->u32EntryInstrLen != 0
6415 || IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxEntryInjectSoftInt)
6416 { /* likely */ }
6417 else
6418 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryInstrLenZero);
6419 }
6420 }
6421 }
6422
6423 /* VM-entry MSR-load count and VM-entry MSR-load area address. */
6424 if (pVmcs->u32EntryMsrLoadCount)
6425 {
6426 if ( !(pVmcs->u64AddrEntryMsrLoad.u & VMX_AUTOMSR_OFFSET_MASK)
6427 && !(pVmcs->u64AddrEntryMsrLoad.u >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6428 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), pVmcs->u64AddrEntryMsrLoad.u))
6429 { /* likely */ }
6430 else
6431 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrEntryMsrLoad);
6432 }
6433
6434 Assert(!(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)); /* We don't support SMM yet. */
6435 Assert(!(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON)); /* We don't support dual-monitor treatment yet. */
6436 }
6437
6438 NOREF(pszInstr);
6439 NOREF(pszFailure);
6440 return VINF_SUCCESS;
6441}
6442
6443
6444/**
6445 * Loads the guest control registers, debug register and some MSRs as part of
6446 * VM-entry.
6447 *
6448 * @param pVCpu The cross context virtual CPU structure.
6449 */
6450IEM_STATIC void iemVmxVmentryLoadGuestControlRegsMsrs(PVMCPUCC pVCpu)
6451{
6452 /*
6453 * Load guest control registers, debug registers and MSRs.
6454 * See Intel spec. 26.3.2.1 "Loading Guest Control Registers, Debug Registers and MSRs".
6455 */
6456 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
6457
6458 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
6459 uint64_t const uGstCr0 = (pVmcs->u64GuestCr0.u & ~VMX_ENTRY_GUEST_CR0_IGNORE_MASK)
6460 | (pVCpu->cpum.GstCtx.cr0 & VMX_ENTRY_GUEST_CR0_IGNORE_MASK);
6461 pVCpu->cpum.GstCtx.cr0 = uGstCr0;
6462 pVCpu->cpum.GstCtx.cr4 = pVmcs->u64GuestCr4.u;
6463 pVCpu->cpum.GstCtx.cr3 = pVmcs->u64GuestCr3.u;
6464
6465 if (pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
6466 pVCpu->cpum.GstCtx.dr[7] = (pVmcs->u64GuestDr7.u & ~VMX_ENTRY_GUEST_DR7_MBZ_MASK) | VMX_ENTRY_GUEST_DR7_MB1_MASK;
6467
6468 pVCpu->cpum.GstCtx.SysEnter.eip = pVmcs->u64GuestSysenterEip.s.Lo;
6469 pVCpu->cpum.GstCtx.SysEnter.esp = pVmcs->u64GuestSysenterEsp.s.Lo;
6470 pVCpu->cpum.GstCtx.SysEnter.cs = pVmcs->u32GuestSysenterCS;
6471
6472 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
6473 {
6474 /* FS base and GS base are loaded while loading the rest of the guest segment registers. */
6475
6476 /* EFER MSR. */
6477 if (!(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR))
6478 {
6479 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
6480 uint64_t const uHostEfer = pVCpu->cpum.GstCtx.msrEFER;
6481 bool const fGstInLongMode = RT_BOOL(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
6482 bool const fGstPaging = RT_BOOL(uGstCr0 & X86_CR0_PG);
6483 if (fGstInLongMode)
6484 {
6485 /* If the nested-guest is in long mode, LMA and LME are both set. */
6486 Assert(fGstPaging);
6487 pVCpu->cpum.GstCtx.msrEFER = uHostEfer | (MSR_K6_EFER_LMA | MSR_K6_EFER_LME);
6488 }
6489 else
6490 {
6491 /*
6492 * If the nested-guest is outside long mode:
6493 * - With paging: LMA is cleared, LME is cleared.
6494 * - Without paging: LMA is cleared, LME is left unmodified.
6495 */
6496 uint64_t const fLmaLmeMask = MSR_K6_EFER_LMA | (fGstPaging ? MSR_K6_EFER_LME : 0);
6497 pVCpu->cpum.GstCtx.msrEFER = uHostEfer & ~fLmaLmeMask;
6498 }
6499 }
6500 /* else: see below. */
6501 }
6502
6503 /* PAT MSR. */
6504 if (pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
6505 pVCpu->cpum.GstCtx.msrPAT = pVmcs->u64GuestPatMsr.u;
6506
6507 /* EFER MSR. */
6508 if (pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
6509 pVCpu->cpum.GstCtx.msrEFER = pVmcs->u64GuestEferMsr.u;
6510
6511 /* We don't support IA32_PERF_GLOBAL_CTRL MSR yet. */
6512 Assert(!(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR));
6513
6514 /* We don't support IA32_BNDCFGS MSR yet. */
6515 Assert(!(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_BNDCFGS_MSR));
6516
6517 /* Nothing to do for SMBASE register - We don't support SMM yet. */
6518}
6519
6520
6521/**
6522 * Loads the guest segment registers, GDTR, IDTR, LDTR and TR as part of VM-entry.
6523 *
6524 * @param pVCpu The cross context virtual CPU structure.
6525 */
6526IEM_STATIC void iemVmxVmentryLoadGuestSegRegs(PVMCPUCC pVCpu)
6527{
6528 /*
6529 * Load guest segment registers, GDTR, IDTR, LDTR and TR.
6530 * See Intel spec. 26.3.2.2 "Loading Guest Segment Registers and Descriptor-Table Registers".
6531 */
6532 /* CS, SS, ES, DS, FS, GS. */
6533 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
6534 for (unsigned iSegReg = 0; iSegReg < X86_SREG_COUNT; iSegReg++)
6535 {
6536 PCPUMSELREG pGstSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
6537 CPUMSELREG VmcsSelReg;
6538 int rc = iemVmxVmcsGetGuestSegReg(pVmcs, iSegReg, &VmcsSelReg);
6539 AssertRC(rc); NOREF(rc);
6540 if (!(VmcsSelReg.Attr.u & X86DESCATTR_UNUSABLE))
6541 {
6542 pGstSelReg->Sel = VmcsSelReg.Sel;
6543 pGstSelReg->ValidSel = VmcsSelReg.Sel;
6544 pGstSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
6545 pGstSelReg->u64Base = VmcsSelReg.u64Base;
6546 pGstSelReg->u32Limit = VmcsSelReg.u32Limit;
6547 pGstSelReg->Attr.u = VmcsSelReg.Attr.u;
6548 }
6549 else
6550 {
6551 pGstSelReg->Sel = VmcsSelReg.Sel;
6552 pGstSelReg->ValidSel = VmcsSelReg.Sel;
6553 pGstSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
6554 switch (iSegReg)
6555 {
6556 case X86_SREG_CS:
6557 pGstSelReg->u64Base = VmcsSelReg.u64Base;
6558 pGstSelReg->u32Limit = VmcsSelReg.u32Limit;
6559 pGstSelReg->Attr.u = VmcsSelReg.Attr.u;
6560 break;
6561
6562 case X86_SREG_SS:
6563 pGstSelReg->u64Base = VmcsSelReg.u64Base & UINT32_C(0xfffffff0);
6564 pGstSelReg->u32Limit = 0;
6565 pGstSelReg->Attr.u = (VmcsSelReg.Attr.u & X86DESCATTR_DPL) | X86DESCATTR_D | X86DESCATTR_UNUSABLE;
6566 break;
6567
6568 case X86_SREG_ES:
6569 case X86_SREG_DS:
6570 pGstSelReg->u64Base = 0;
6571 pGstSelReg->u32Limit = 0;
6572 pGstSelReg->Attr.u = X86DESCATTR_UNUSABLE;
6573 break;
6574
6575 case X86_SREG_FS:
6576 case X86_SREG_GS:
6577 pGstSelReg->u64Base = VmcsSelReg.u64Base;
6578 pGstSelReg->u32Limit = 0;
6579 pGstSelReg->Attr.u = X86DESCATTR_UNUSABLE;
6580 break;
6581 }
6582 Assert(pGstSelReg->Attr.n.u1Unusable);
6583 }
6584 }
6585
6586 /* LDTR. */
6587 pVCpu->cpum.GstCtx.ldtr.Sel = pVmcs->GuestLdtr;
6588 pVCpu->cpum.GstCtx.ldtr.ValidSel = pVmcs->GuestLdtr;
6589 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
6590 if (!(pVmcs->u32GuestLdtrAttr & X86DESCATTR_UNUSABLE))
6591 {
6592 pVCpu->cpum.GstCtx.ldtr.u64Base = pVmcs->u64GuestLdtrBase.u;
6593 pVCpu->cpum.GstCtx.ldtr.u32Limit = pVmcs->u32GuestLdtrLimit;
6594 pVCpu->cpum.GstCtx.ldtr.Attr.u = pVmcs->u32GuestLdtrAttr;
6595 }
6596 else
6597 {
6598 pVCpu->cpum.GstCtx.ldtr.u64Base = 0;
6599 pVCpu->cpum.GstCtx.ldtr.u32Limit = 0;
6600 pVCpu->cpum.GstCtx.ldtr.Attr.u = X86DESCATTR_UNUSABLE;
6601 }
6602
6603 /* TR. */
6604 Assert(!(pVmcs->u32GuestTrAttr & X86DESCATTR_UNUSABLE));
6605 pVCpu->cpum.GstCtx.tr.Sel = pVmcs->GuestTr;
6606 pVCpu->cpum.GstCtx.tr.ValidSel = pVmcs->GuestTr;
6607 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
6608 pVCpu->cpum.GstCtx.tr.u64Base = pVmcs->u64GuestTrBase.u;
6609 pVCpu->cpum.GstCtx.tr.u32Limit = pVmcs->u32GuestTrLimit;
6610 pVCpu->cpum.GstCtx.tr.Attr.u = pVmcs->u32GuestTrAttr;
6611
6612 /* GDTR. */
6613 pVCpu->cpum.GstCtx.gdtr.cbGdt = pVmcs->u32GuestGdtrLimit;
6614 pVCpu->cpum.GstCtx.gdtr.pGdt = pVmcs->u64GuestGdtrBase.u;
6615
6616 /* IDTR. */
6617 pVCpu->cpum.GstCtx.idtr.cbIdt = pVmcs->u32GuestIdtrLimit;
6618 pVCpu->cpum.GstCtx.idtr.pIdt = pVmcs->u64GuestIdtrBase.u;
6619}
6620
6621
6622/**
6623 * Loads the guest MSRs from the VM-entry MSR-load area as part of VM-entry.
6624 *
6625 * @returns VBox status code.
6626 * @param pVCpu The cross context virtual CPU structure.
6627 * @param pszInstr The VMX instruction name (for logging purposes).
6628 */
6629IEM_STATIC int iemVmxVmentryLoadGuestAutoMsrs(PVMCPUCC pVCpu, const char *pszInstr)
6630{
6631 /*
6632 * Load guest MSRs.
6633 * See Intel spec. 26.4 "Loading MSRs".
6634 */
6635 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
6636 const char *const pszFailure = "VM-exit";
6637
6638 /*
6639 * The VM-entry MSR-load area address need not be a valid guest-physical address if the
6640 * VM-entry MSR load count is 0. If this is the case, bail early without reading it.
6641 * See Intel spec. 24.8.2 "VM-Entry Controls for MSRs".
6642 */
6643 uint32_t const cMsrs = RT_MIN(pVmcs->u32EntryMsrLoadCount, RT_ELEMENTS(pVCpu->cpum.GstCtx.hwvirt.vmx.aEntryMsrLoadArea));
6644 if (!cMsrs)
6645 return VINF_SUCCESS;
6646
6647 /*
6648 * Verify the MSR auto-load count. Physical CPUs can behave unpredictably if the count is
6649 * exceeded including possibly raising #MC exceptions during VMX transition. Our
6650 * implementation shall fail VM-entry with an VMX_EXIT_ERR_MSR_LOAD VM-exit.
6651 */
6652 bool const fIsMsrCountValid = iemVmxIsAutoMsrCountValid(pVCpu, cMsrs);
6653 if (fIsMsrCountValid)
6654 { /* likely */ }
6655 else
6656 {
6657 iemVmxVmcsSetExitQual(pVCpu, VMX_V_AUTOMSR_AREA_SIZE / sizeof(VMXAUTOMSR));
6658 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_MsrLoadCount);
6659 }
6660
6661 RTGCPHYS const GCPhysVmEntryMsrLoadArea = pVmcs->u64AddrEntryMsrLoad.u;
6662 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.aEntryMsrLoadArea[0],
6663 GCPhysVmEntryMsrLoadArea, cMsrs * sizeof(VMXAUTOMSR));
6664 if (RT_SUCCESS(rc))
6665 {
6666 PCVMXAUTOMSR pMsr = &pVCpu->cpum.GstCtx.hwvirt.vmx.aEntryMsrLoadArea[0];
6667 for (uint32_t idxMsr = 0; idxMsr < cMsrs; idxMsr++, pMsr++)
6668 {
6669 if ( !pMsr->u32Reserved
6670 && pMsr->u32Msr != MSR_K8_FS_BASE
6671 && pMsr->u32Msr != MSR_K8_GS_BASE
6672 && pMsr->u32Msr != MSR_K6_EFER
6673 && pMsr->u32Msr != MSR_IA32_SMM_MONITOR_CTL
6674 && pMsr->u32Msr >> 8 != MSR_IA32_X2APIC_START >> 8)
6675 {
6676 VBOXSTRICTRC rcStrict = CPUMSetGuestMsr(pVCpu, pMsr->u32Msr, pMsr->u64Value);
6677 if (rcStrict == VINF_SUCCESS)
6678 continue;
6679
6680 /*
6681 * If we're in ring-0, we cannot handle returns to ring-3 at this point and continue VM-entry.
6682 * If any nested hypervisor loads MSRs that require ring-3 handling, we cause a VM-entry failure
6683 * recording the MSR index in the Exit qualification (as per the Intel spec.) and indicated
6684 * further by our own, specific diagnostic code. Later, we can try implement handling of the
6685 * MSR in ring-0 if possible, or come up with a better, generic solution.
6686 */
6687 iemVmxVmcsSetExitQual(pVCpu, idxMsr);
6688 VMXVDIAG const enmDiag = rcStrict == VINF_CPUM_R3_MSR_WRITE
6689 ? kVmxVDiag_Vmentry_MsrLoadRing3
6690 : kVmxVDiag_Vmentry_MsrLoad;
6691 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
6692 }
6693 else
6694 {
6695 iemVmxVmcsSetExitQual(pVCpu, idxMsr);
6696 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_MsrLoadRsvd);
6697 }
6698 }
6699 }
6700 else
6701 {
6702 AssertMsgFailed(("%s: Failed to read MSR auto-load area at %#RGp, rc=%Rrc\n", pszInstr, GCPhysVmEntryMsrLoadArea, rc));
6703 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_MsrLoadPtrReadPhys);
6704 }
6705
6706 NOREF(pszInstr);
6707 NOREF(pszFailure);
6708 return VINF_SUCCESS;
6709}
6710
6711
6712/**
6713 * Loads the guest-state non-register state as part of VM-entry.
6714 *
6715 * @returns VBox status code.
6716 * @param pVCpu The cross context virtual CPU structure.
6717 * @param pszInstr The VMX instruction name (for logging purposes).
6718 *
6719 * @remarks This must be called only after loading the nested-guest register state
6720 * (especially nested-guest RIP).
6721 */
6722IEM_STATIC int iemVmxVmentryLoadGuestNonRegState(PVMCPUCC pVCpu, const char *pszInstr)
6723{
6724 /*
6725 * Load guest non-register state.
6726 * See Intel spec. 26.6 "Special Features of VM Entry"
6727 */
6728 const char *const pszFailure = "VM-exit";
6729 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
6730
6731 /*
6732 * If VM-entry is not vectoring, block-by-STI and block-by-MovSS state must be loaded.
6733 * If VM-entry is vectoring, there is no block-by-STI or block-by-MovSS.
6734 *
6735 * See Intel spec. 26.6.1 "Interruptibility State".
6736 */
6737 bool const fEntryVectoring = VMXIsVmentryVectoring(pVmcs->u32EntryIntInfo, NULL /* puEntryIntInfoType */);
6738 if ( !fEntryVectoring
6739 && (pVmcs->u32GuestIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)))
6740 EMSetInhibitInterruptsPC(pVCpu, pVmcs->u64GuestRip.u);
6741 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
6742 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
6743
6744 /* NMI blocking. */
6745 if (pVmcs->u32GuestIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI)
6746 {
6747 if (pVmcs->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
6748 pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtNmiBlocking = true;
6749 else
6750 {
6751 pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtNmiBlocking = false;
6752 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
6753 VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
6754 }
6755 }
6756 else
6757 pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtNmiBlocking = false;
6758
6759 /* SMI blocking is irrelevant. We don't support SMIs yet. */
6760
6761 /*
6762 * Set PGM's copy of the EPT pointer.
6763 * The EPTP has already been validated while checking guest state.
6764 *
6765 * It is important to do this prior to mapping PAE PDPTEs (below).
6766 */
6767 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT)
6768 PGMSetGuestEptPtr(pVCpu, pVmcs->u64EptPtr.u);
6769
6770 /*
6771 * Load the guest's PAE PDPTEs.
6772 */
6773 if (iemVmxVmcsIsGuestPaePagingEnabled(pVmcs))
6774 {
6775 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT)
6776 {
6777 /*
6778 * With EPT, we've already validated these while checking the guest state.
6779 * Just load them directly from the VMCS here.
6780 */
6781 X86PDPE aPaePdptes[X86_PG_PAE_PDPE_ENTRIES];
6782 aPaePdptes[0].u = pVmcs->u64GuestPdpte0.u;
6783 aPaePdptes[1].u = pVmcs->u64GuestPdpte1.u;
6784 aPaePdptes[2].u = pVmcs->u64GuestPdpte2.u;
6785 aPaePdptes[3].u = pVmcs->u64GuestPdpte3.u;
6786 AssertCompile(RT_ELEMENTS(aPaePdptes) == RT_ELEMENTS(pVCpu->cpum.GstCtx.aPaePdpes));
6787 for (unsigned i = 0; i < RT_ELEMENTS(pVCpu->cpum.GstCtx.aPaePdpes); i++)
6788 pVCpu->cpum.GstCtx.aPaePdpes[i].u = aPaePdptes[i].u;
6789 }
6790 else
6791 {
6792 /*
6793 * Without EPT, we must load the PAE PDPTEs referenced by CR3.
6794 * This involves loading (and mapping) CR3 and validating them now.
6795 */
6796 int const rc = PGMGstMapPaePdpesAtCr3(pVCpu, pVmcs->u64GuestCr3.u);
6797 if (RT_SUCCESS(rc))
6798 { /* likely */ }
6799 else
6800 {
6801 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_PDPTE);
6802 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPdpte);
6803 }
6804 }
6805 }
6806
6807 /* VPID is irrelevant. We don't support VPID yet. */
6808
6809 /* Clear address-range monitoring. */
6810 EMMonitorWaitClear(pVCpu);
6811
6812 return VINF_SUCCESS;
6813}
6814
6815
6816/**
6817 * Loads the guest VMCS referenced state (such as MSR bitmaps, I/O bitmaps etc).
6818 *
6819 * @param pVCpu The cross context virtual CPU structure.
6820 * @param pszInstr The VMX instruction name (for logging purposes).
6821 *
6822 * @remarks This assumes various VMCS related data structure pointers have already
6823 * been verified prior to calling this function.
6824 */
6825IEM_STATIC int iemVmxVmentryLoadGuestVmcsRefState(PVMCPUCC pVCpu, const char *pszInstr)
6826{
6827 const char *const pszFailure = "VM-exit";
6828 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
6829
6830 /*
6831 * Virtualize APIC accesses.
6832 */
6833 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
6834 {
6835 /* APIC-access physical address. */
6836 RTGCPHYS const GCPhysApicAccess = pVmcs->u64AddrApicAccess.u;
6837
6838 /*
6839 * Register the handler for the APIC-access page.
6840 *
6841 * We don't deregister the APIC-access page handler during the VM-exit as a different
6842 * nested-VCPU might be using the same guest-physical address for its APIC-access page.
6843 *
6844 * We leave the page registered until the first access that happens outside VMX non-root
6845 * mode. Guest software is allowed to access structures such as the APIC-access page
6846 * only when no logical processor with a current VMCS references it in VMX non-root mode,
6847 * otherwise it can lead to unpredictable behavior including guest triple-faults.
6848 *
6849 * See Intel spec. 24.11.4 "Software Access to Related Structures".
6850 */
6851 if (!PGMHandlerPhysicalIsRegistered(pVCpu->CTX_SUFF(pVM), GCPhysApicAccess))
6852 {
6853 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6854 PVMCPUCC pVCpu0 = VMCC_GET_CPU_0(pVM);
6855 int rc = PGMHandlerPhysicalRegister(pVM, GCPhysApicAccess, GCPhysApicAccess + X86_PAGE_4K_SIZE - 1,
6856 pVCpu0->iem.s.hVmxApicAccessPage, NIL_RTR3PTR /* pvUserR3 */,
6857 NIL_RTR0PTR /* pvUserR0 */, NIL_RTRCPTR /* pvUserRC */, NULL /* pszDesc */);
6858 if (RT_SUCCESS(rc))
6859 { /* likely */ }
6860 else
6861 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrApicAccessHandlerReg);
6862 }
6863 }
6864
6865 /*
6866 * VMCS shadowing.
6867 */
6868 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
6869 {
6870 /* Read the VMREAD-bitmap. */
6871 RTGCPHYS const GCPhysVmreadBitmap = pVmcs->u64AddrVmreadBitmap.u;
6872 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.abVmreadBitmap[0],
6873 GCPhysVmreadBitmap, sizeof(pVCpu->cpum.GstCtx.hwvirt.vmx.abVmreadBitmap));
6874 if (RT_SUCCESS(rc))
6875 { /* likely */ }
6876 else
6877 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VmreadBitmapPtrReadPhys);
6878
6879 /* Read the VMWRITE-bitmap. */
6880 RTGCPHYS const GCPhysVmwriteBitmap = pVmcs->u64AddrVmwriteBitmap.u;
6881 rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.abVmwriteBitmap[0],
6882 GCPhysVmwriteBitmap, sizeof(pVCpu->cpum.GstCtx.hwvirt.vmx.abVmwriteBitmap));
6883 if (RT_SUCCESS(rc))
6884 { /* likely */ }
6885 else
6886 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VmwriteBitmapPtrReadPhys);
6887 }
6888
6889 /*
6890 * I/O bitmaps.
6891 */
6892 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_IO_BITMAPS)
6893 {
6894 /* Read the IO bitmap A. */
6895 RTGCPHYS const GCPhysIoBitmapA = pVmcs->u64AddrIoBitmapA.u;
6896 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.abIoBitmap[0],
6897 GCPhysIoBitmapA, VMX_V_IO_BITMAP_A_SIZE);
6898 if (RT_SUCCESS(rc))
6899 { /* likely */ }
6900 else
6901 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_IoBitmapAPtrReadPhys);
6902
6903 /* Read the IO bitmap B. */
6904 RTGCPHYS const GCPhysIoBitmapB = pVmcs->u64AddrIoBitmapB.u;
6905 rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.abIoBitmap[VMX_V_IO_BITMAP_A_SIZE],
6906 GCPhysIoBitmapB, VMX_V_IO_BITMAP_B_SIZE);
6907 if (RT_SUCCESS(rc))
6908 { /* likely */ }
6909 else
6910 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_IoBitmapBPtrReadPhys);
6911 }
6912
6913 /*
6914 * TPR shadow and Virtual-APIC page.
6915 */
6916 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
6917 {
6918 /* Verify TPR threshold and VTPR when both virtualize-APIC accesses and virtual-interrupt delivery aren't used. */
6919 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
6920 && !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY))
6921 {
6922 /* Read the VTPR from the virtual-APIC page. */
6923 RTGCPHYS const GCPhysVirtApic = pVmcs->u64AddrVirtApic.u;
6924 uint8_t u8VTpr;
6925 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &u8VTpr, GCPhysVirtApic + XAPIC_OFF_TPR, sizeof(u8VTpr));
6926 if (RT_SUCCESS(rc))
6927 { /* likely */ }
6928 else
6929 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtApicPagePtrReadPhys);
6930
6931 /* Bits 3:0 of the TPR-threshold must not be greater than bits 7:4 of VTPR. */
6932 if ((uint8_t)RT_BF_GET(pVmcs->u32TprThreshold, VMX_BF_TPR_THRESHOLD_TPR) <= (u8VTpr & 0xf0))
6933 { /* likely */ }
6934 else
6935 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_TprThresholdVTpr);
6936 }
6937 }
6938
6939 /*
6940 * VMCS link pointer.
6941 */
6942 if (pVmcs->u64VmcsLinkPtr.u != UINT64_C(0xffffffffffffffff))
6943 {
6944 /* Read the VMCS-link pointer from guest memory. */
6945 RTGCPHYS const GCPhysShadowVmcs = pVmcs->u64VmcsLinkPtr.u;
6946 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.ShadowVmcs,
6947 GCPhysShadowVmcs, sizeof(pVCpu->cpum.GstCtx.hwvirt.vmx.ShadowVmcs));
6948 if (RT_SUCCESS(rc))
6949 { /* likely */ }
6950 else
6951 {
6952 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_VMCS_LINK_PTR);
6953 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VmcsLinkPtrReadPhys);
6954 }
6955
6956 /* Verify the VMCS revision specified by the guest matches what we reported to the guest. */
6957 if (pVCpu->cpum.GstCtx.hwvirt.vmx.ShadowVmcs.u32VmcsRevId.n.u31RevisionId == VMX_V_VMCS_REVISION_ID)
6958 { /* likely */ }
6959 else
6960 {
6961 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_VMCS_LINK_PTR);
6962 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VmcsLinkPtrRevId);
6963 }
6964
6965 /* Verify the shadow bit is set if VMCS shadowing is enabled . */
6966 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
6967 || pVCpu->cpum.GstCtx.hwvirt.vmx.ShadowVmcs.u32VmcsRevId.n.fIsShadowVmcs)
6968 { /* likely */ }
6969 else
6970 {
6971 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_VMCS_LINK_PTR);
6972 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VmcsLinkPtrShadow);
6973 }
6974
6975 /* Update our cache of the guest physical address of the shadow VMCS. */
6976 pVCpu->cpum.GstCtx.hwvirt.vmx.GCPhysShadowVmcs = GCPhysShadowVmcs;
6977 }
6978
6979 /*
6980 * MSR bitmap.
6981 */
6982 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
6983 {
6984 /* Read the MSR bitmap. */
6985 RTGCPHYS const GCPhysMsrBitmap = pVmcs->u64AddrMsrBitmap.u;
6986 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap[0],
6987 GCPhysMsrBitmap, sizeof(pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap));
6988 if (RT_SUCCESS(rc))
6989 { /* likely */ }
6990 else
6991 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_MsrBitmapPtrReadPhys);
6992 }
6993
6994 NOREF(pszFailure);
6995 NOREF(pszInstr);
6996 return VINF_SUCCESS;
6997}
6998
6999
7000/**
7001 * Loads the guest-state as part of VM-entry.
7002 *
7003 * @returns VBox status code.
7004 * @param pVCpu The cross context virtual CPU structure.
7005 * @param pszInstr The VMX instruction name (for logging purposes).
7006 *
7007 * @remarks This must be done after all the necessary steps prior to loading of
7008 * guest-state (e.g. checking various VMCS state).
7009 */
7010IEM_STATIC int iemVmxVmentryLoadGuestState(PVMCPUCC pVCpu, const char *pszInstr)
7011{
7012 /* Load guest control registers, MSRs (that are directly part of the VMCS). */
7013 iemVmxVmentryLoadGuestControlRegsMsrs(pVCpu);
7014
7015 /* Load guest segment registers. */
7016 iemVmxVmentryLoadGuestSegRegs(pVCpu);
7017
7018 /*
7019 * Load guest RIP, RSP and RFLAGS.
7020 * See Intel spec. 26.3.2.3 "Loading Guest RIP, RSP and RFLAGS".
7021 */
7022 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7023 pVCpu->cpum.GstCtx.rsp = pVmcs->u64GuestRsp.u;
7024 pVCpu->cpum.GstCtx.rip = pVmcs->u64GuestRip.u;
7025 pVCpu->cpum.GstCtx.rflags.u = pVmcs->u64GuestRFlags.u;
7026
7027 /* Initialize the PAUSE-loop controls as part of VM-entry. */
7028 pVCpu->cpum.GstCtx.hwvirt.vmx.uFirstPauseLoopTick = 0;
7029 pVCpu->cpum.GstCtx.hwvirt.vmx.uPrevPauseTick = 0;
7030
7031 /* Load guest non-register state (such as interrupt shadows, NMI blocking etc). */
7032 int rc = iemVmxVmentryLoadGuestNonRegState(pVCpu, pszInstr);
7033 if (rc == VINF_SUCCESS)
7034 { /* likely */ }
7035 else
7036 return rc;
7037
7038 /* Load VMX related structures and state referenced by the VMCS. */
7039 rc = iemVmxVmentryLoadGuestVmcsRefState(pVCpu, pszInstr);
7040 if (rc == VINF_SUCCESS)
7041 { /* likely */ }
7042 else
7043 return rc;
7044
7045 NOREF(pszInstr);
7046 return VINF_SUCCESS;
7047}
7048
7049
7050/**
7051 * Returns whether there are is a pending debug exception on VM-entry.
7052 *
7053 * @param pVCpu The cross context virtual CPU structure.
7054 * @param pszInstr The VMX instruction name (for logging purposes).
7055 */
7056IEM_STATIC bool iemVmxVmentryIsPendingDebugXcpt(PVMCPUCC pVCpu, const char *pszInstr)
7057{
7058 /*
7059 * Pending debug exceptions.
7060 * See Intel spec. 26.6.3 "Delivery of Pending Debug Exceptions after VM Entry".
7061 */
7062 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7063 Assert(pVmcs);
7064
7065 bool fPendingDbgXcpt = RT_BOOL(pVmcs->u64GuestPendingDbgXcpts.u & ( VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS
7066 | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_EN_BP));
7067 if (fPendingDbgXcpt)
7068 {
7069 uint8_t uEntryIntInfoType;
7070 bool const fEntryVectoring = VMXIsVmentryVectoring(pVmcs->u32EntryIntInfo, &uEntryIntInfoType);
7071 if (fEntryVectoring)
7072 {
7073 switch (uEntryIntInfoType)
7074 {
7075 case VMX_ENTRY_INT_INFO_TYPE_EXT_INT:
7076 case VMX_ENTRY_INT_INFO_TYPE_NMI:
7077 case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT:
7078 case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT:
7079 fPendingDbgXcpt = false;
7080 break;
7081
7082 case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT:
7083 {
7084 /*
7085 * Whether the pending debug exception for software exceptions other than
7086 * #BP and #OF is delivered after injecting the exception or is discard
7087 * is CPU implementation specific. We will discard them (easier).
7088 */
7089 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(pVmcs->u32EntryIntInfo);
7090 if ( uVector != X86_XCPT_BP
7091 && uVector != X86_XCPT_OF)
7092 fPendingDbgXcpt = false;
7093 RT_FALL_THRU();
7094 }
7095 case VMX_ENTRY_INT_INFO_TYPE_SW_INT:
7096 {
7097 if (!(pVmcs->u32GuestIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
7098 fPendingDbgXcpt = false;
7099 break;
7100 }
7101 }
7102 }
7103 else
7104 {
7105 /*
7106 * When the VM-entry is not vectoring but there is blocking-by-MovSS, whether the
7107 * pending debug exception is held pending or is discarded is CPU implementation
7108 * specific. We will discard them (easier).
7109 */
7110 if (pVmcs->u32GuestIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
7111 fPendingDbgXcpt = false;
7112
7113 /* There's no pending debug exception in the shutdown or wait-for-SIPI state. */
7114 if (pVmcs->u32GuestActivityState & (VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN | VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT))
7115 fPendingDbgXcpt = false;
7116 }
7117 }
7118
7119 NOREF(pszInstr);
7120 return fPendingDbgXcpt;
7121}
7122
7123
7124/**
7125 * Set up the monitor-trap flag (MTF).
7126 *
7127 * @param pVCpu The cross context virtual CPU structure.
7128 * @param pszInstr The VMX instruction name (for logging purposes).
7129 */
7130IEM_STATIC void iemVmxVmentrySetupMtf(PVMCPUCC pVCpu, const char *pszInstr)
7131{
7132 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7133 Assert(pVmcs);
7134 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
7135 {
7136 VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_MTF);
7137 Log(("%s: Monitor-trap flag set on VM-entry\n", pszInstr));
7138 }
7139 else
7140 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF));
7141 NOREF(pszInstr);
7142}
7143
7144
7145/**
7146 * Sets up NMI-window exiting.
7147 *
7148 * @param pVCpu The cross context virtual CPU structure.
7149 * @param pszInstr The VMX instruction name (for logging purposes).
7150 */
7151IEM_STATIC void iemVmxVmentrySetupNmiWindow(PVMCPUCC pVCpu, const char *pszInstr)
7152{
7153 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7154 Assert(pVmcs);
7155 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7156 {
7157 Assert(pVmcs->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI);
7158 VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW);
7159 Log(("%s: NMI-window set on VM-entry\n", pszInstr));
7160 }
7161 else
7162 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW));
7163 NOREF(pszInstr);
7164}
7165
7166
7167/**
7168 * Sets up interrupt-window exiting.
7169 *
7170 * @param pVCpu The cross context virtual CPU structure.
7171 * @param pszInstr The VMX instruction name (for logging purposes).
7172 */
7173IEM_STATIC void iemVmxVmentrySetupIntWindow(PVMCPUCC pVCpu, const char *pszInstr)
7174{
7175 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7176 Assert(pVmcs);
7177 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7178 {
7179 VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW);
7180 Log(("%s: Interrupt-window set on VM-entry\n", pszInstr));
7181 }
7182 else
7183 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW));
7184 NOREF(pszInstr);
7185}
7186
7187
7188/**
7189 * Set up the VMX-preemption timer.
7190 *
7191 * @param pVCpu The cross context virtual CPU structure.
7192 * @param pszInstr The VMX instruction name (for logging purposes).
7193 */
7194IEM_STATIC void iemVmxVmentrySetupPreemptTimer(PVMCPUCC pVCpu, const char *pszInstr)
7195{
7196 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7197 Assert(pVmcs);
7198 if (pVmcs->u32PinCtls & VMX_PIN_CTLS_PREEMPT_TIMER)
7199 {
7200 /*
7201 * If the timer is 0, we must cause a VM-exit before executing the first
7202 * nested-guest instruction. So we can flag as though the timer has already
7203 * expired and we will check and cause a VM-exit at the right priority elsewhere
7204 * in the code.
7205 */
7206 uint64_t uEntryTick;
7207 uint32_t const uPreemptTimer = pVmcs->u32PreemptTimer;
7208 if (uPreemptTimer)
7209 {
7210 int rc = CPUMStartGuestVmxPremptTimer(pVCpu, uPreemptTimer, VMX_V_PREEMPT_TIMER_SHIFT, &uEntryTick);
7211 AssertRC(rc);
7212 Log(("%s: VM-entry set up VMX-preemption timer at %#RX64\n", pszInstr, uEntryTick));
7213 }
7214 else
7215 {
7216 uEntryTick = TMCpuTickGetNoCheck(pVCpu);
7217 VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER);
7218 Log(("%s: VM-entry set up VMX-preemption timer at %#RX64 to expire immediately!\n", pszInstr, uEntryTick));
7219 }
7220
7221 pVCpu->cpum.GstCtx.hwvirt.vmx.uEntryTick = uEntryTick;
7222 }
7223 else
7224 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER));
7225
7226 NOREF(pszInstr);
7227}
7228
7229
7230/**
7231 * Injects an event using TRPM given a VM-entry interruption info. and related
7232 * fields.
7233 *
7234 * @param pVCpu The cross context virtual CPU structure.
7235 * @param pszInstr The VMX instruction name (for logging purposes).
7236 * @param uEntryIntInfo The VM-entry interruption info.
7237 * @param uErrCode The error code associated with the event if any.
7238 * @param cbInstr The VM-entry instruction length (for software
7239 * interrupts and software exceptions). Pass 0
7240 * otherwise.
7241 * @param GCPtrFaultAddress The guest CR2 if this is a \#PF event.
7242 */
7243IEM_STATIC void iemVmxVmentryInjectTrpmEvent(PVMCPUCC pVCpu, const char *pszInstr, uint32_t uEntryIntInfo, uint32_t uErrCode,
7244 uint32_t cbInstr, RTGCUINTPTR GCPtrFaultAddress)
7245{
7246 Assert(VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo));
7247
7248 uint8_t const uType = VMX_ENTRY_INT_INFO_TYPE(uEntryIntInfo);
7249 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(uEntryIntInfo);
7250 TRPMEVENT const enmTrpmEvent = HMVmxEventTypeToTrpmEventType(uEntryIntInfo);
7251
7252 Assert(uType != VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT);
7253
7254 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrpmEvent);
7255 AssertRC(rc);
7256 Log(("%s: Injecting: vector=%#x type=%#x (%s)\n", pszInstr, uVector, uType, VMXGetEntryIntInfoTypeDesc(uType)));
7257
7258 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(uEntryIntInfo))
7259 {
7260 TRPMSetErrorCode(pVCpu, uErrCode);
7261 Log(("%s: Injecting: err_code=%#x\n", pszInstr, uErrCode));
7262 }
7263
7264 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(uEntryIntInfo))
7265 {
7266 TRPMSetFaultAddress(pVCpu, GCPtrFaultAddress);
7267 Log(("%s: Injecting: fault_addr=%RGp\n", pszInstr, GCPtrFaultAddress));
7268 }
7269 else
7270 {
7271 if ( uType == VMX_ENTRY_INT_INFO_TYPE_SW_INT
7272 || uType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT
7273 || uType == VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT)
7274 {
7275 TRPMSetInstrLength(pVCpu, cbInstr);
7276 Log(("%s: Injecting: instr_len=%u\n", pszInstr, cbInstr));
7277 }
7278 }
7279
7280 if (VMX_ENTRY_INT_INFO_TYPE(uEntryIntInfo) == VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT)
7281 {
7282 TRPMSetTrapDueToIcebp(pVCpu);
7283 Log(("%s: Injecting: icebp\n", pszInstr));
7284 }
7285
7286 NOREF(pszInstr);
7287}
7288
7289
7290/**
7291 * Performs event injection (if any) as part of VM-entry.
7292 *
7293 * @param pVCpu The cross context virtual CPU structure.
7294 * @param pszInstr The VMX instruction name (for logging purposes).
7295 */
7296IEM_STATIC void iemVmxVmentryInjectEvent(PVMCPUCC pVCpu, const char *pszInstr)
7297{
7298 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7299
7300 /*
7301 * Inject events.
7302 * The event that is going to be made pending for injection is not subject to VMX intercepts,
7303 * thus we flag ignoring of intercepts. However, recursive exceptions if any during delivery
7304 * of the current event -are- subject to intercepts, hence this flag will be flipped during
7305 * the actually delivery of this event.
7306 *
7307 * See Intel spec. 26.5 "Event Injection".
7308 */
7309 uint32_t const uEntryIntInfo = pVmcs->u32EntryIntInfo;
7310 bool const fEntryIntInfoValid = VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo);
7311
7312 CPUMSetGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx, !fEntryIntInfoValid);
7313 if (fEntryIntInfoValid)
7314 {
7315 if (VMX_ENTRY_INT_INFO_TYPE(uEntryIntInfo) == VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT)
7316 {
7317 Assert(VMX_ENTRY_INT_INFO_VECTOR(uEntryIntInfo) == VMX_ENTRY_INT_INFO_VECTOR_MTF);
7318 VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_MTF);
7319 }
7320 else
7321 iemVmxVmentryInjectTrpmEvent(pVCpu, pszInstr, uEntryIntInfo, pVmcs->u32EntryXcptErrCode, pVmcs->u32EntryInstrLen,
7322 pVCpu->cpum.GstCtx.cr2);
7323
7324 /*
7325 * We need to clear the VM-entry interruption information field's valid bit on VM-exit.
7326 *
7327 * However, we do it here on VM-entry as well because while it isn't visible to guest
7328 * software until VM-exit, when and if HM looks at the VMCS to continue nested-guest
7329 * execution using hardware-assisted VMX, it will not be try to inject the event again.
7330 *
7331 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
7332 */
7333 pVmcs->u32EntryIntInfo &= ~VMX_ENTRY_INT_INFO_VALID;
7334 }
7335 else
7336 {
7337 /*
7338 * Inject any pending guest debug exception.
7339 * Unlike injecting events, this #DB injection on VM-entry is subject to #DB VMX intercept.
7340 * See Intel spec. 26.6.3 "Delivery of Pending Debug Exceptions after VM Entry".
7341 */
7342 bool const fPendingDbgXcpt = iemVmxVmentryIsPendingDebugXcpt(pVCpu, pszInstr);
7343 if (fPendingDbgXcpt)
7344 {
7345 uint32_t const uDbgXcptInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
7346 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
7347 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7348 iemVmxVmentryInjectTrpmEvent(pVCpu, pszInstr, uDbgXcptInfo, 0 /* uErrCode */, pVmcs->u32EntryInstrLen,
7349 0 /* GCPtrFaultAddress */);
7350 }
7351 }
7352
7353 NOREF(pszInstr);
7354}
7355
7356
7357/**
7358 * Initializes all read-only VMCS fields as part of VM-entry.
7359 *
7360 * @param pVCpu The cross context virtual CPU structure.
7361 */
7362IEM_STATIC void iemVmxVmentryInitReadOnlyFields(PVMCPUCC pVCpu)
7363{
7364 /*
7365 * Any VMCS field which we do not establish on every VM-exit but may potentially
7366 * be used on the VM-exit path of a nested hypervisor -and- is not explicitly
7367 * specified to be undefined, needs to be initialized here.
7368 *
7369 * Thus, it is especially important to clear the Exit qualification field
7370 * since it must be zero for VM-exits where it is not used. Similarly, the
7371 * VM-exit interruption information field's valid bit needs to be cleared for
7372 * the same reasons.
7373 */
7374 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7375 Assert(pVmcs);
7376
7377 /* 16-bit (none currently). */
7378 /* 32-bit. */
7379 pVmcs->u32RoVmInstrError = 0;
7380 pVmcs->u32RoExitReason = 0;
7381 pVmcs->u32RoExitIntInfo = 0;
7382 pVmcs->u32RoExitIntErrCode = 0;
7383 pVmcs->u32RoIdtVectoringInfo = 0;
7384 pVmcs->u32RoIdtVectoringErrCode = 0;
7385 pVmcs->u32RoExitInstrLen = 0;
7386 pVmcs->u32RoExitInstrInfo = 0;
7387
7388 /* 64-bit. */
7389 pVmcs->u64RoGuestPhysAddr.u = 0;
7390
7391 /* Natural-width. */
7392 pVmcs->u64RoExitQual.u = 0;
7393 pVmcs->u64RoIoRcx.u = 0;
7394 pVmcs->u64RoIoRsi.u = 0;
7395 pVmcs->u64RoIoRdi.u = 0;
7396 pVmcs->u64RoIoRip.u = 0;
7397 pVmcs->u64RoGuestLinearAddr.u = 0;
7398}
7399
7400
7401/**
7402 * VMLAUNCH/VMRESUME instruction execution worker.
7403 *
7404 * @returns Strict VBox status code.
7405 * @param pVCpu The cross context virtual CPU structure.
7406 * @param cbInstr The instruction length in bytes.
7407 * @param uInstrId The instruction identity (VMXINSTRID_VMLAUNCH or
7408 * VMXINSTRID_VMRESUME).
7409 *
7410 * @remarks Common VMX instruction checks are already expected to by the caller,
7411 * i.e. CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
7412 */
7413IEM_STATIC VBOXSTRICTRC iemVmxVmlaunchVmresume(PVMCPUCC pVCpu, uint8_t cbInstr, VMXINSTRID uInstrId)
7414{
7415# if defined(VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM) && !defined(IN_RING3)
7416 RT_NOREF3(pVCpu, cbInstr, uInstrId);
7417 return VINF_EM_RAW_EMULATE_INSTR;
7418# else
7419 Assert( uInstrId == VMXINSTRID_VMLAUNCH
7420 || uInstrId == VMXINSTRID_VMRESUME);
7421 const char *pszInstr = uInstrId == VMXINSTRID_VMRESUME ? "vmresume" : "vmlaunch";
7422
7423 /* Nested-guest intercept. */
7424 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
7425 return iemVmxVmexitInstr(pVCpu, uInstrId == VMXINSTRID_VMRESUME ? VMX_EXIT_VMRESUME : VMX_EXIT_VMLAUNCH, cbInstr);
7426
7427 Assert(IEM_VMX_IS_ROOT_MODE(pVCpu));
7428
7429 /*
7430 * Basic VM-entry checks.
7431 * The order of the CPL, current and shadow VMCS and block-by-MovSS are important.
7432 * The checks following that do not have to follow a specific order.
7433 *
7434 * See Intel spec. 26.1 "Basic VM-entry Checks".
7435 */
7436
7437 /* CPL. */
7438 if (pVCpu->iem.s.uCpl == 0)
7439 { /* likely */ }
7440 else
7441 {
7442 Log(("%s: CPL %u -> #GP(0)\n", pszInstr, pVCpu->iem.s.uCpl));
7443 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmentry_Cpl;
7444 return iemRaiseGeneralProtectionFault0(pVCpu);
7445 }
7446
7447 /* Current VMCS valid. */
7448 if (IEM_VMX_HAS_CURRENT_VMCS(pVCpu))
7449 { /* likely */ }
7450 else
7451 {
7452 Log(("%s: VMCS pointer %#RGp invalid -> VMFailInvalid\n", pszInstr, IEM_VMX_GET_CURRENT_VMCS(pVCpu)));
7453 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmentry_PtrInvalid;
7454 iemVmxVmFailInvalid(pVCpu);
7455 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7456 return VINF_SUCCESS;
7457 }
7458
7459 /* Current VMCS is not a shadow VMCS. */
7460 if (!pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32VmcsRevId.n.fIsShadowVmcs)
7461 { /* likely */ }
7462 else
7463 {
7464 Log(("%s: VMCS pointer %#RGp is a shadow VMCS -> VMFailInvalid\n", pszInstr, IEM_VMX_GET_CURRENT_VMCS(pVCpu)));
7465 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmentry_PtrShadowVmcs;
7466 iemVmxVmFailInvalid(pVCpu);
7467 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7468 return VINF_SUCCESS;
7469 }
7470
7471 /** @todo Distinguish block-by-MovSS from block-by-STI. Currently we
7472 * use block-by-STI here which is not quite correct. */
7473 if ( !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
7474 || pVCpu->cpum.GstCtx.rip != EMGetInhibitInterruptsPC(pVCpu))
7475 { /* likely */ }
7476 else
7477 {
7478 Log(("%s: VM entry with events blocked by MOV SS -> VMFail\n", pszInstr));
7479 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmentry_BlocKMovSS;
7480 iemVmxVmFail(pVCpu, VMXINSTRERR_VMENTRY_BLOCK_MOVSS);
7481 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7482 return VINF_SUCCESS;
7483 }
7484
7485 if (uInstrId == VMXINSTRID_VMLAUNCH)
7486 {
7487 /* VMLAUNCH with non-clear VMCS. */
7488 if (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.fVmcsState == VMX_V_VMCS_LAUNCH_STATE_CLEAR)
7489 { /* likely */ }
7490 else
7491 {
7492 Log(("vmlaunch: VMLAUNCH with non-clear VMCS -> VMFail\n"));
7493 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmentry_VmcsClear;
7494 iemVmxVmFail(pVCpu, VMXINSTRERR_VMLAUNCH_NON_CLEAR_VMCS);
7495 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7496 return VINF_SUCCESS;
7497 }
7498 }
7499 else
7500 {
7501 /* VMRESUME with non-launched VMCS. */
7502 if (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.fVmcsState == VMX_V_VMCS_LAUNCH_STATE_LAUNCHED)
7503 { /* likely */ }
7504 else
7505 {
7506 Log(("vmresume: VMRESUME with non-launched VMCS -> VMFail\n"));
7507 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmentry_VmcsLaunch;
7508 iemVmxVmFail(pVCpu, VMXINSTRERR_VMRESUME_NON_LAUNCHED_VMCS);
7509 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7510 return VINF_SUCCESS;
7511 }
7512 }
7513
7514 /*
7515 * We are allowed to cache VMCS related data structures (such as I/O bitmaps, MSR bitmaps)
7516 * while entering VMX non-root mode. We do some of this while checking VM-execution
7517 * controls. The nested hypervisor should not make assumptions and cannot expect
7518 * predictable behavior if changes to these structures are made in guest memory while
7519 * executing in VMX non-root mode. As far as VirtualBox is concerned, the guest cannot
7520 * modify them anyway as we cache them in host memory.
7521 *
7522 * See Intel spec. 24.11.4 "Software Access to Related Structures".
7523 */
7524 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7525 Assert(pVmcs);
7526 Assert(IEM_VMX_HAS_CURRENT_VMCS(pVCpu));
7527
7528 int rc = iemVmxVmentryCheckCtls(pVCpu, pszInstr);
7529 if (RT_SUCCESS(rc))
7530 {
7531 rc = iemVmxVmentryCheckHostState(pVCpu, pszInstr);
7532 if (RT_SUCCESS(rc))
7533 {
7534 /*
7535 * Initialize read-only VMCS fields before VM-entry since we don't update all of them
7536 * for every VM-exit. This needs to be done before invoking a VM-exit (even those
7537 * ones that may occur during VM-entry below).
7538 */
7539 iemVmxVmentryInitReadOnlyFields(pVCpu);
7540
7541 /*
7542 * Blocking of NMIs need to be restored if VM-entry fails due to invalid-guest state.
7543 * So we save the VMCPU_FF_BLOCK_NMI force-flag here so we can restore it on
7544 * VM-exit when required.
7545 * See Intel spec. 26.7 "VM-entry Failures During or After Loading Guest State"
7546 */
7547 iemVmxVmentrySaveNmiBlockingFF(pVCpu);
7548
7549 rc = iemVmxVmentryCheckGuestState(pVCpu, pszInstr);
7550 if (RT_SUCCESS(rc))
7551 {
7552 /*
7553 * We've now entered nested-guest execution.
7554 *
7555 * It is important do this prior to loading the guest state because
7556 * as part of loading the guest state, PGM (and perhaps other components
7557 * in the future) relies on detecting whether VMX non-root mode has been
7558 * entered.
7559 */
7560 pVCpu->cpum.GstCtx.hwvirt.vmx.fInVmxNonRootMode = true;
7561
7562 rc = iemVmxVmentryLoadGuestState(pVCpu, pszInstr);
7563 if (RT_SUCCESS(rc))
7564 {
7565 rc = iemVmxVmentryLoadGuestAutoMsrs(pVCpu, pszInstr);
7566 if (RT_SUCCESS(rc))
7567 {
7568 Assert(rc != VINF_CPUM_R3_MSR_WRITE);
7569
7570 /* VMLAUNCH instruction must update the VMCS launch state. */
7571 if (uInstrId == VMXINSTRID_VMLAUNCH)
7572 pVmcs->fVmcsState = VMX_V_VMCS_LAUNCH_STATE_LAUNCHED;
7573
7574 /* Perform the VMX transition (PGM updates). */
7575 VBOXSTRICTRC rcStrict = iemVmxTransition(pVCpu);
7576 if (rcStrict == VINF_SUCCESS)
7577 { /* likely */ }
7578 else if (RT_SUCCESS(rcStrict))
7579 {
7580 Log3(("%s: iemVmxTransition returns %Rrc -> Setting passup status\n", pszInstr,
7581 VBOXSTRICTRC_VAL(rcStrict)));
7582 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
7583 }
7584 else
7585 {
7586 Log3(("%s: iemVmxTransition failed! rc=%Rrc\n", pszInstr, VBOXSTRICTRC_VAL(rcStrict)));
7587 return rcStrict;
7588 }
7589
7590 /* Paranoia. */
7591 Assert(rcStrict == VINF_SUCCESS);
7592
7593 /*
7594 * The priority of potential VM-exits during VM-entry is important.
7595 * The priorities of VM-exits and events are listed from highest
7596 * to lowest as follows:
7597 *
7598 * 1. Event injection.
7599 * 2. Trap on task-switch (T flag set in TSS).
7600 * 3. TPR below threshold / APIC-write.
7601 * 4. SMI, INIT.
7602 * 5. MTF exit.
7603 * 6. Debug-trap exceptions (EFLAGS.TF), pending debug exceptions.
7604 * 7. VMX-preemption timer.
7605 * 9. NMI-window exit.
7606 * 10. NMI injection.
7607 * 11. Interrupt-window exit.
7608 * 12. Virtual-interrupt injection.
7609 * 13. Interrupt injection.
7610 * 14. Process next instruction (fetch, decode, execute).
7611 */
7612
7613 /* Setup VMX-preemption timer. */
7614 iemVmxVmentrySetupPreemptTimer(pVCpu, pszInstr);
7615
7616 /* Setup monitor-trap flag. */
7617 iemVmxVmentrySetupMtf(pVCpu, pszInstr);
7618
7619 /* Setup NMI-window exiting. */
7620 iemVmxVmentrySetupNmiWindow(pVCpu, pszInstr);
7621
7622 /* Setup interrupt-window exiting. */
7623 iemVmxVmentrySetupIntWindow(pVCpu, pszInstr);
7624
7625 /*
7626 * Inject any event that the nested hypervisor wants to inject.
7627 * Note! We cannot immediately perform the event injection here as we may have
7628 * pending PGM operations to perform due to switching page tables and/or
7629 * mode.
7630 */
7631 iemVmxVmentryInjectEvent(pVCpu, pszInstr);
7632
7633# if defined(VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM) && defined(IN_RING3)
7634 /* Reschedule to IEM-only execution of the nested-guest. */
7635 Log(("%s: Enabling IEM-only EM execution policy!\n", pszInstr));
7636 int rcSched = EMR3SetExecutionPolicy(pVCpu->CTX_SUFF(pVM)->pUVM, EMEXECPOLICY_IEM_ALL, true);
7637 if (rcSched != VINF_SUCCESS)
7638 iemSetPassUpStatus(pVCpu, rcSched);
7639# endif
7640
7641 /* Finally, done. */
7642 Log3(("%s: cs:rip=%#04x:%#RX64 cr0=%#RX64 (%#RX64) cr4=%#RX64 (%#RX64) efer=%#RX64\n",
7643 pszInstr, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.cr0,
7644 pVmcs->u64Cr0ReadShadow.u, pVCpu->cpum.GstCtx.cr4, pVmcs->u64Cr4ReadShadow.u,
7645 pVCpu->cpum.GstCtx.msrEFER));
7646 return VINF_SUCCESS;
7647 }
7648 return iemVmxVmexit(pVCpu, VMX_EXIT_ERR_MSR_LOAD | VMX_EXIT_REASON_ENTRY_FAILED, pVmcs->u64RoExitQual.u);
7649 }
7650 }
7651 return iemVmxVmexit(pVCpu, VMX_EXIT_ERR_INVALID_GUEST_STATE | VMX_EXIT_REASON_ENTRY_FAILED, pVmcs->u64RoExitQual.u);
7652 }
7653
7654 iemVmxVmFail(pVCpu, VMXINSTRERR_VMENTRY_INVALID_HOST_STATE);
7655 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7656 return VINF_SUCCESS;
7657 }
7658
7659 iemVmxVmFail(pVCpu, VMXINSTRERR_VMENTRY_INVALID_CTLS);
7660 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7661 return VINF_SUCCESS;
7662# endif
7663}
7664
7665
7666/**
7667 * Checks whether an RDMSR or WRMSR instruction for the given MSR is intercepted
7668 * (causes a VM-exit) or not.
7669 *
7670 * @returns @c true if the instruction is intercepted, @c false otherwise.
7671 * @param pVCpu The cross context virtual CPU structure.
7672 * @param uExitReason The VM-exit reason (VMX_EXIT_RDMSR or
7673 * VMX_EXIT_WRMSR).
7674 * @param idMsr The MSR.
7675 */
7676IEM_STATIC bool iemVmxIsRdmsrWrmsrInterceptSet(PCVMCPU pVCpu, uint32_t uExitReason, uint32_t idMsr)
7677{
7678 Assert(IEM_VMX_IS_NON_ROOT_MODE(pVCpu));
7679 Assert( uExitReason == VMX_EXIT_RDMSR
7680 || uExitReason == VMX_EXIT_WRMSR);
7681
7682 /* Consult the MSR bitmap if the feature is supported. */
7683 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7684 Assert(pVmcs);
7685 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
7686 {
7687 uint32_t const fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap, idMsr);
7688 if (uExitReason == VMX_EXIT_RDMSR)
7689 return RT_BOOL(fMsrpm & VMXMSRPM_EXIT_RD);
7690 return RT_BOOL(fMsrpm & VMXMSRPM_EXIT_WR);
7691 }
7692
7693 /* Without MSR bitmaps, all MSR accesses are intercepted. */
7694 return true;
7695}
7696
7697
7698/**
7699 * VMREAD instruction execution worker that does not perform any validation checks.
7700 *
7701 * Callers are expected to have performed the necessary checks and to ensure the
7702 * VMREAD will succeed.
7703 *
7704 * @param pVmcs Pointer to the virtual VMCS.
7705 * @param pu64Dst Where to write the VMCS value.
7706 * @param u64VmcsField The VMCS field.
7707 *
7708 * @remarks May be called with interrupts disabled.
7709 */
7710IEM_STATIC void iemVmxVmreadNoCheck(PCVMXVVMCS pVmcs, uint64_t *pu64Dst, uint64_t u64VmcsField)
7711{
7712 VMXVMCSFIELD VmcsField;
7713 VmcsField.u = u64VmcsField;
7714 uint8_t const uWidth = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_WIDTH);
7715 uint8_t const uType = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_TYPE);
7716 uint8_t const uWidthType = (uWidth << 2) | uType;
7717 uint8_t const uIndex = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_INDEX);
7718 Assert(uIndex <= VMX_V_VMCS_MAX_INDEX);
7719 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
7720 AssertMsg(offField < VMX_V_VMCS_SIZE, ("off=%u field=%#RX64 width=%#x type=%#x index=%#x (%u)\n", offField, u64VmcsField,
7721 uWidth, uType, uIndex, uIndex));
7722 AssertCompile(VMX_V_SHADOW_VMCS_SIZE == VMX_V_VMCS_SIZE);
7723
7724 /*
7725 * Read the VMCS component based on the field's effective width.
7726 *
7727 * The effective width is 64-bit fields adjusted to 32-bits if the access-type
7728 * indicates high bits (little endian).
7729 *
7730 * Note! The caller is responsible to trim the result and update registers
7731 * or memory locations are required. Here we just zero-extend to the largest
7732 * type (i.e. 64-bits).
7733 */
7734 uint8_t const *pbVmcs = (uint8_t const *)pVmcs;
7735 uint8_t const *pbField = pbVmcs + offField;
7736 uint8_t const uEffWidth = VMXGetVmcsFieldWidthEff(VmcsField.u);
7737 switch (uEffWidth)
7738 {
7739 case VMX_VMCSFIELD_WIDTH_64BIT:
7740 case VMX_VMCSFIELD_WIDTH_NATURAL: *pu64Dst = *(uint64_t const *)pbField; break;
7741 case VMX_VMCSFIELD_WIDTH_32BIT: *pu64Dst = *(uint32_t const *)pbField; break;
7742 case VMX_VMCSFIELD_WIDTH_16BIT: *pu64Dst = *(uint16_t const *)pbField; break;
7743 }
7744}
7745
7746
7747/**
7748 * VMREAD common (memory/register) instruction execution worker.
7749 *
7750 * @returns Strict VBox status code.
7751 * @param pVCpu The cross context virtual CPU structure.
7752 * @param cbInstr The instruction length in bytes.
7753 * @param pu64Dst Where to write the VMCS value (only updated when
7754 * VINF_SUCCESS is returned).
7755 * @param u64VmcsField The VMCS field.
7756 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
7757 * NULL.
7758 */
7759IEM_STATIC VBOXSTRICTRC iemVmxVmreadCommon(PVMCPUCC pVCpu, uint8_t cbInstr, uint64_t *pu64Dst, uint64_t u64VmcsField,
7760 PCVMXVEXITINFO pExitInfo)
7761{
7762 /* Nested-guest intercept. */
7763 if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7764 && CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, VMX_EXIT_VMREAD, u64VmcsField))
7765 {
7766 if (pExitInfo)
7767 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
7768 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_VMREAD, VMXINSTRID_VMREAD, cbInstr);
7769 }
7770
7771 /* CPL. */
7772 if (pVCpu->iem.s.uCpl == 0)
7773 { /* likely */ }
7774 else
7775 {
7776 Log(("vmread: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
7777 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmread_Cpl;
7778 return iemRaiseGeneralProtectionFault0(pVCpu);
7779 }
7780
7781 /* VMCS pointer in root mode. */
7782 if ( !IEM_VMX_IS_ROOT_MODE(pVCpu)
7783 || IEM_VMX_HAS_CURRENT_VMCS(pVCpu))
7784 { /* likely */ }
7785 else
7786 {
7787 Log(("vmread: VMCS pointer %#RGp invalid -> VMFailInvalid\n", IEM_VMX_GET_CURRENT_VMCS(pVCpu)));
7788 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmread_PtrInvalid;
7789 iemVmxVmFailInvalid(pVCpu);
7790 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7791 return VINF_SUCCESS;
7792 }
7793
7794 /* VMCS-link pointer in non-root mode. */
7795 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7796 || IEM_VMX_HAS_SHADOW_VMCS(pVCpu))
7797 { /* likely */ }
7798 else
7799 {
7800 Log(("vmread: VMCS-link pointer %#RGp invalid -> VMFailInvalid\n", IEM_VMX_GET_SHADOW_VMCS(pVCpu)));
7801 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmread_LinkPtrInvalid;
7802 iemVmxVmFailInvalid(pVCpu);
7803 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7804 return VINF_SUCCESS;
7805 }
7806
7807 /* Supported VMCS field. */
7808 if (CPUMIsGuestVmxVmcsFieldValid(pVCpu->CTX_SUFF(pVM), u64VmcsField))
7809 { /* likely */ }
7810 else
7811 {
7812 Log(("vmread: VMCS field %#RX64 invalid -> VMFail\n", u64VmcsField));
7813 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmread_FieldInvalid;
7814 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64VmcsField;
7815 iemVmxVmFail(pVCpu, VMXINSTRERR_VMREAD_INVALID_COMPONENT);
7816 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7817 return VINF_SUCCESS;
7818 }
7819
7820 /*
7821 * Reading from the current or shadow VMCS.
7822 */
7823 PCVMXVVMCS pVmcs = !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7824 ? &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs
7825 : &pVCpu->cpum.GstCtx.hwvirt.vmx.ShadowVmcs;
7826 iemVmxVmreadNoCheck(pVmcs, pu64Dst, u64VmcsField);
7827 return VINF_SUCCESS;
7828}
7829
7830
7831/**
7832 * VMREAD (64-bit register) instruction execution worker.
7833 *
7834 * @returns Strict VBox status code.
7835 * @param pVCpu The cross context virtual CPU structure.
7836 * @param cbInstr The instruction length in bytes.
7837 * @param pu64Dst Where to store the VMCS field's value.
7838 * @param u64VmcsField The VMCS field.
7839 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
7840 * NULL.
7841 */
7842IEM_STATIC VBOXSTRICTRC iemVmxVmreadReg64(PVMCPUCC pVCpu, uint8_t cbInstr, uint64_t *pu64Dst, uint64_t u64VmcsField,
7843 PCVMXVEXITINFO pExitInfo)
7844{
7845 VBOXSTRICTRC rcStrict = iemVmxVmreadCommon(pVCpu, cbInstr, pu64Dst, u64VmcsField, pExitInfo);
7846 if (rcStrict == VINF_SUCCESS)
7847 {
7848 iemVmxVmSucceed(pVCpu);
7849 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7850 return VINF_SUCCESS;
7851 }
7852
7853 Log(("vmread/reg: iemVmxVmreadCommon failed rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
7854 return rcStrict;
7855}
7856
7857
7858/**
7859 * VMREAD (32-bit register) instruction execution worker.
7860 *
7861 * @returns Strict VBox status code.
7862 * @param pVCpu The cross context virtual CPU structure.
7863 * @param cbInstr The instruction length in bytes.
7864 * @param pu32Dst Where to store the VMCS field's value.
7865 * @param u32VmcsField The VMCS field.
7866 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
7867 * NULL.
7868 */
7869IEM_STATIC VBOXSTRICTRC iemVmxVmreadReg32(PVMCPUCC pVCpu, uint8_t cbInstr, uint32_t *pu32Dst, uint64_t u32VmcsField,
7870 PCVMXVEXITINFO pExitInfo)
7871{
7872 uint64_t u64Dst;
7873 VBOXSTRICTRC rcStrict = iemVmxVmreadCommon(pVCpu, cbInstr, &u64Dst, u32VmcsField, pExitInfo);
7874 if (rcStrict == VINF_SUCCESS)
7875 {
7876 *pu32Dst = u64Dst;
7877 iemVmxVmSucceed(pVCpu);
7878 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7879 return VINF_SUCCESS;
7880 }
7881
7882 Log(("vmread/reg: iemVmxVmreadCommon failed rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
7883 return rcStrict;
7884}
7885
7886
7887/**
7888 * VMREAD (memory) instruction execution worker.
7889 *
7890 * @returns Strict VBox status code.
7891 * @param pVCpu The cross context virtual CPU structure.
7892 * @param cbInstr The instruction length in bytes.
7893 * @param iEffSeg The effective segment register to use with @a u64Val.
7894 * Pass UINT8_MAX if it is a register access.
7895 * @param GCPtrDst The guest linear address to store the VMCS field's
7896 * value.
7897 * @param u64VmcsField The VMCS field.
7898 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
7899 * NULL.
7900 */
7901IEM_STATIC VBOXSTRICTRC iemVmxVmreadMem(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrDst, uint64_t u64VmcsField,
7902 PCVMXVEXITINFO pExitInfo)
7903{
7904 uint64_t u64Dst;
7905 VBOXSTRICTRC rcStrict = iemVmxVmreadCommon(pVCpu, cbInstr, &u64Dst, u64VmcsField, pExitInfo);
7906 if (rcStrict == VINF_SUCCESS)
7907 {
7908 /*
7909 * Write the VMCS field's value to the location specified in guest-memory.
7910 */
7911 if (pVCpu->iem.s.enmCpuMode == IEMMODE_64BIT)
7912 rcStrict = iemMemStoreDataU64(pVCpu, iEffSeg, GCPtrDst, u64Dst);
7913 else
7914 rcStrict = iemMemStoreDataU32(pVCpu, iEffSeg, GCPtrDst, u64Dst);
7915 if (rcStrict == VINF_SUCCESS)
7916 {
7917 iemVmxVmSucceed(pVCpu);
7918 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
7919 return VINF_SUCCESS;
7920 }
7921
7922 Log(("vmread/mem: Failed to write to memory operand at %#RGv, rc=%Rrc\n", GCPtrDst, VBOXSTRICTRC_VAL(rcStrict)));
7923 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmread_PtrMap;
7924 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrDst;
7925 return rcStrict;
7926 }
7927
7928 Log(("vmread/mem: iemVmxVmreadCommon failed rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
7929 return rcStrict;
7930}
7931
7932
7933/**
7934 * VMWRITE instruction execution worker that does not perform any validation
7935 * checks.
7936 *
7937 * Callers are expected to have performed the necessary checks and to ensure the
7938 * VMWRITE will succeed.
7939 *
7940 * @param pVmcs Pointer to the virtual VMCS.
7941 * @param u64Val The value to write.
7942 * @param u64VmcsField The VMCS field.
7943 *
7944 * @remarks May be called with interrupts disabled.
7945 */
7946IEM_STATIC void iemVmxVmwriteNoCheck(PVMXVVMCS pVmcs, uint64_t u64Val, uint64_t u64VmcsField)
7947{
7948 VMXVMCSFIELD VmcsField;
7949 VmcsField.u = u64VmcsField;
7950 uint8_t const uWidth = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_WIDTH);
7951 uint8_t const uType = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_TYPE);
7952 uint8_t const uWidthType = (uWidth << 2) | uType;
7953 uint8_t const uIndex = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_INDEX);
7954 Assert(uIndex <= VMX_V_VMCS_MAX_INDEX);
7955 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
7956 Assert(offField < VMX_V_VMCS_SIZE);
7957 AssertCompile(VMX_V_SHADOW_VMCS_SIZE == VMX_V_VMCS_SIZE);
7958
7959 /*
7960 * Write the VMCS component based on the field's effective width.
7961 *
7962 * The effective width is 64-bit fields adjusted to 32-bits if the access-type
7963 * indicates high bits (little endian).
7964 */
7965 uint8_t *pbVmcs = (uint8_t *)pVmcs;
7966 uint8_t *pbField = pbVmcs + offField;
7967 uint8_t const uEffWidth = VMXGetVmcsFieldWidthEff(VmcsField.u);
7968 switch (uEffWidth)
7969 {
7970 case VMX_VMCSFIELD_WIDTH_64BIT:
7971 case VMX_VMCSFIELD_WIDTH_NATURAL: *(uint64_t *)pbField = u64Val; break;
7972 case VMX_VMCSFIELD_WIDTH_32BIT: *(uint32_t *)pbField = u64Val; break;
7973 case VMX_VMCSFIELD_WIDTH_16BIT: *(uint16_t *)pbField = u64Val; break;
7974 }
7975}
7976
7977
7978/**
7979 * VMWRITE instruction execution worker.
7980 *
7981 * @returns Strict VBox status code.
7982 * @param pVCpu The cross context virtual CPU structure.
7983 * @param cbInstr The instruction length in bytes.
7984 * @param iEffSeg The effective segment register to use with @a u64Val.
7985 * Pass UINT8_MAX if it is a register access.
7986 * @param u64Val The value to write (or guest linear address to the
7987 * value), @a iEffSeg will indicate if it's a memory
7988 * operand.
7989 * @param u64VmcsField The VMCS field.
7990 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
7991 * NULL.
7992 */
7993IEM_STATIC VBOXSTRICTRC iemVmxVmwrite(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, uint64_t u64Val, uint64_t u64VmcsField,
7994 PCVMXVEXITINFO pExitInfo)
7995{
7996 /* Nested-guest intercept. */
7997 if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7998 && CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, VMX_EXIT_VMWRITE, u64VmcsField))
7999 {
8000 if (pExitInfo)
8001 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
8002 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_VMWRITE, VMXINSTRID_VMWRITE, cbInstr);
8003 }
8004
8005 /* CPL. */
8006 if (pVCpu->iem.s.uCpl == 0)
8007 { /* likely */ }
8008 else
8009 {
8010 Log(("vmwrite: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
8011 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmwrite_Cpl;
8012 return iemRaiseGeneralProtectionFault0(pVCpu);
8013 }
8014
8015 /* VMCS pointer in root mode. */
8016 if ( !IEM_VMX_IS_ROOT_MODE(pVCpu)
8017 || IEM_VMX_HAS_CURRENT_VMCS(pVCpu))
8018 { /* likely */ }
8019 else
8020 {
8021 Log(("vmwrite: VMCS pointer %#RGp invalid -> VMFailInvalid\n", IEM_VMX_GET_CURRENT_VMCS(pVCpu)));
8022 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmwrite_PtrInvalid;
8023 iemVmxVmFailInvalid(pVCpu);
8024 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8025 return VINF_SUCCESS;
8026 }
8027
8028 /* VMCS-link pointer in non-root mode. */
8029 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
8030 || IEM_VMX_HAS_SHADOW_VMCS(pVCpu))
8031 { /* likely */ }
8032 else
8033 {
8034 Log(("vmwrite: VMCS-link pointer %#RGp invalid -> VMFailInvalid\n", IEM_VMX_GET_SHADOW_VMCS(pVCpu)));
8035 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmwrite_LinkPtrInvalid;
8036 iemVmxVmFailInvalid(pVCpu);
8037 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8038 return VINF_SUCCESS;
8039 }
8040
8041 /* If the VMWRITE instruction references memory, access the specified memory operand. */
8042 bool const fIsRegOperand = iEffSeg == UINT8_MAX;
8043 if (!fIsRegOperand)
8044 {
8045 /* Read the value from the specified guest memory location. */
8046 VBOXSTRICTRC rcStrict;
8047 RTGCPTR const GCPtrVal = u64Val;
8048 if (pVCpu->iem.s.enmCpuMode == IEMMODE_64BIT)
8049 rcStrict = iemMemFetchDataU64(pVCpu, &u64Val, iEffSeg, GCPtrVal);
8050 else
8051 rcStrict = iemMemFetchDataU32_ZX_U64(pVCpu, &u64Val, iEffSeg, GCPtrVal);
8052 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
8053 {
8054 Log(("vmwrite: Failed to read value from memory operand at %#RGv, rc=%Rrc\n", GCPtrVal, VBOXSTRICTRC_VAL(rcStrict)));
8055 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmwrite_PtrMap;
8056 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrVal;
8057 return rcStrict;
8058 }
8059 }
8060 else
8061 Assert(!pExitInfo || pExitInfo->InstrInfo.VmreadVmwrite.fIsRegOperand);
8062
8063 /* Supported VMCS field. */
8064 if (CPUMIsGuestVmxVmcsFieldValid(pVCpu->CTX_SUFF(pVM), u64VmcsField))
8065 { /* likely */ }
8066 else
8067 {
8068 Log(("vmwrite: VMCS field %#RX64 invalid -> VMFail\n", u64VmcsField));
8069 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmwrite_FieldInvalid;
8070 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64VmcsField;
8071 iemVmxVmFail(pVCpu, VMXINSTRERR_VMWRITE_INVALID_COMPONENT);
8072 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8073 return VINF_SUCCESS;
8074 }
8075
8076 /* Read-only VMCS field. */
8077 bool const fIsFieldReadOnly = VMXIsVmcsFieldReadOnly(u64VmcsField);
8078 if ( !fIsFieldReadOnly
8079 || IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxVmwriteAll)
8080 { /* likely */ }
8081 else
8082 {
8083 Log(("vmwrite: Write to read-only VMCS component %#RX64 -> VMFail\n", u64VmcsField));
8084 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmwrite_FieldRo;
8085 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64VmcsField;
8086 iemVmxVmFail(pVCpu, VMXINSTRERR_VMWRITE_RO_COMPONENT);
8087 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8088 return VINF_SUCCESS;
8089 }
8090
8091 /*
8092 * Write to the current or shadow VMCS.
8093 */
8094 bool const fInVmxNonRootMode = IEM_VMX_IS_NON_ROOT_MODE(pVCpu);
8095 PVMXVVMCS pVmcs = !fInVmxNonRootMode
8096 ? &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs
8097 : &pVCpu->cpum.GstCtx.hwvirt.vmx.ShadowVmcs;
8098 iemVmxVmwriteNoCheck(pVmcs, u64Val, u64VmcsField);
8099
8100 if ( !fInVmxNonRootMode
8101 && VM_IS_HM_ENABLED(pVCpu->CTX_SUFF(pVM)))
8102 {
8103 /* Notify HM that the VMCS content might have changed. */
8104 HMNotifyVmxNstGstCurrentVmcsChanged(pVCpu);
8105 }
8106
8107 iemVmxVmSucceed(pVCpu);
8108 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8109 return VINF_SUCCESS;
8110}
8111
8112
8113/**
8114 * VMCLEAR instruction execution worker.
8115 *
8116 * @returns Strict VBox status code.
8117 * @param pVCpu The cross context virtual CPU structure.
8118 * @param cbInstr The instruction length in bytes.
8119 * @param iEffSeg The effective segment register to use with @a GCPtrVmcs.
8120 * @param GCPtrVmcs The linear address of the VMCS pointer.
8121 * @param pExitInfo Pointer to the VM-exit information. Optional, can be NULL.
8122 *
8123 * @remarks Common VMX instruction checks are already expected to by the caller,
8124 * i.e. VMX operation, CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
8125 */
8126IEM_STATIC VBOXSTRICTRC iemVmxVmclear(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPHYS GCPtrVmcs,
8127 PCVMXVEXITINFO pExitInfo)
8128{
8129 /* Nested-guest intercept. */
8130 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8131 {
8132 if (pExitInfo)
8133 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
8134 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_VMCLEAR, VMXINSTRID_NONE, cbInstr);
8135 }
8136
8137 Assert(IEM_VMX_IS_ROOT_MODE(pVCpu));
8138
8139 /* CPL. */
8140 if (pVCpu->iem.s.uCpl == 0)
8141 { /* likely */ }
8142 else
8143 {
8144 Log(("vmclear: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
8145 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmclear_Cpl;
8146 return iemRaiseGeneralProtectionFault0(pVCpu);
8147 }
8148
8149 /* Get the VMCS pointer from the location specified by the source memory operand. */
8150 RTGCPHYS GCPhysVmcs;
8151 VBOXSTRICTRC rcStrict = iemMemFetchDataU64(pVCpu, &GCPhysVmcs, iEffSeg, GCPtrVmcs);
8152 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8153 { /* likely */ }
8154 else
8155 {
8156 Log(("vmclear: Failed to read VMCS physaddr from %#RGv, rc=%Rrc\n", GCPtrVmcs, VBOXSTRICTRC_VAL(rcStrict)));
8157 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmclear_PtrMap;
8158 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrVmcs;
8159 return rcStrict;
8160 }
8161
8162 /* VMCS pointer alignment. */
8163 if (!(GCPhysVmcs & X86_PAGE_4K_OFFSET_MASK))
8164 { /* likely */ }
8165 else
8166 {
8167 Log(("vmclear: VMCS pointer not page-aligned -> VMFail()\n"));
8168 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmclear_PtrAlign;
8169 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8170 iemVmxVmFail(pVCpu, VMXINSTRERR_VMCLEAR_INVALID_PHYSADDR);
8171 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8172 return VINF_SUCCESS;
8173 }
8174
8175 /* VMCS physical-address width limits. */
8176 if (!(GCPhysVmcs >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth))
8177 { /* likely */ }
8178 else
8179 {
8180 Log(("vmclear: VMCS pointer extends beyond physical-address width -> VMFail()\n"));
8181 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmclear_PtrWidth;
8182 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8183 iemVmxVmFail(pVCpu, VMXINSTRERR_VMCLEAR_INVALID_PHYSADDR);
8184 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8185 return VINF_SUCCESS;
8186 }
8187
8188 /* VMCS is not the VMXON region. */
8189 if (GCPhysVmcs != pVCpu->cpum.GstCtx.hwvirt.vmx.GCPhysVmxon)
8190 { /* likely */ }
8191 else
8192 {
8193 Log(("vmclear: VMCS pointer cannot be identical to VMXON region pointer -> VMFail()\n"));
8194 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmclear_PtrVmxon;
8195 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8196 iemVmxVmFail(pVCpu, VMXINSTRERR_VMCLEAR_VMXON_PTR);
8197 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8198 return VINF_SUCCESS;
8199 }
8200
8201 /* Ensure VMCS is not MMIO, ROM etc. This is not an Intel requirement but a
8202 restriction imposed by our implementation. */
8203 if (PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysVmcs))
8204 { /* likely */ }
8205 else
8206 {
8207 Log(("vmclear: VMCS not normal memory -> VMFail()\n"));
8208 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmclear_PtrAbnormal;
8209 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8210 iemVmxVmFail(pVCpu, VMXINSTRERR_VMCLEAR_INVALID_PHYSADDR);
8211 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8212 return VINF_SUCCESS;
8213 }
8214
8215 /*
8216 * VMCLEAR allows committing and clearing any valid VMCS pointer.
8217 *
8218 * If the current VMCS is the one being cleared, set its state to 'clear' and commit
8219 * to guest memory. Otherwise, set the state of the VMCS referenced in guest memory
8220 * to 'clear'.
8221 */
8222 uint8_t const fVmcsLaunchStateClear = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
8223 if ( IEM_VMX_HAS_CURRENT_VMCS(pVCpu)
8224 && IEM_VMX_GET_CURRENT_VMCS(pVCpu) == GCPhysVmcs)
8225 {
8226 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.fVmcsState = fVmcsLaunchStateClear;
8227 iemVmxWriteCurrentVmcsToGstMem(pVCpu);
8228 IEM_VMX_CLEAR_CURRENT_VMCS(pVCpu);
8229 }
8230 else
8231 {
8232 AssertCompileMemberSize(VMXVVMCS, fVmcsState, sizeof(fVmcsLaunchStateClear));
8233 rcStrict = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVmcs + RT_UOFFSETOF(VMXVVMCS, fVmcsState),
8234 (const void *)&fVmcsLaunchStateClear, sizeof(fVmcsLaunchStateClear));
8235 if (RT_FAILURE(rcStrict))
8236 return rcStrict;
8237 }
8238
8239 iemVmxVmSucceed(pVCpu);
8240 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8241 return VINF_SUCCESS;
8242}
8243
8244
8245/**
8246 * VMPTRST instruction execution worker.
8247 *
8248 * @returns Strict VBox status code.
8249 * @param pVCpu The cross context virtual CPU structure.
8250 * @param cbInstr The instruction length in bytes.
8251 * @param iEffSeg The effective segment register to use with @a GCPtrVmcs.
8252 * @param GCPtrVmcs The linear address of where to store the current VMCS
8253 * pointer.
8254 * @param pExitInfo Pointer to the VM-exit information. Optional, can be NULL.
8255 *
8256 * @remarks Common VMX instruction checks are already expected to by the caller,
8257 * i.e. VMX operation, CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
8258 */
8259IEM_STATIC VBOXSTRICTRC iemVmxVmptrst(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPHYS GCPtrVmcs,
8260 PCVMXVEXITINFO pExitInfo)
8261{
8262 /* Nested-guest intercept. */
8263 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8264 {
8265 if (pExitInfo)
8266 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
8267 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_VMPTRST, VMXINSTRID_NONE, cbInstr);
8268 }
8269
8270 Assert(IEM_VMX_IS_ROOT_MODE(pVCpu));
8271
8272 /* CPL. */
8273 if (pVCpu->iem.s.uCpl == 0)
8274 { /* likely */ }
8275 else
8276 {
8277 Log(("vmptrst: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
8278 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrst_Cpl;
8279 return iemRaiseGeneralProtectionFault0(pVCpu);
8280 }
8281
8282 /* Set the VMCS pointer to the location specified by the destination memory operand. */
8283 AssertCompile(NIL_RTGCPHYS == ~(RTGCPHYS)0U);
8284 VBOXSTRICTRC rcStrict = iemMemStoreDataU64(pVCpu, iEffSeg, GCPtrVmcs, IEM_VMX_GET_CURRENT_VMCS(pVCpu));
8285 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8286 {
8287 iemVmxVmSucceed(pVCpu);
8288 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8289 return rcStrict;
8290 }
8291
8292 Log(("vmptrst: Failed to store VMCS pointer to memory at destination operand %#Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8293 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrst_PtrMap;
8294 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrVmcs;
8295 return rcStrict;
8296}
8297
8298
8299/**
8300 * VMPTRLD instruction execution worker.
8301 *
8302 * @returns Strict VBox status code.
8303 * @param pVCpu The cross context virtual CPU structure.
8304 * @param cbInstr The instruction length in bytes.
8305 * @param GCPtrVmcs The linear address of the current VMCS pointer.
8306 * @param pExitInfo Pointer to the VM-exit information. Optional, can be NULL.
8307 *
8308 * @remarks Common VMX instruction checks are already expected to by the caller,
8309 * i.e. VMX operation, CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
8310 */
8311IEM_STATIC VBOXSTRICTRC iemVmxVmptrld(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPHYS GCPtrVmcs,
8312 PCVMXVEXITINFO pExitInfo)
8313{
8314 /* Nested-guest intercept. */
8315 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8316 {
8317 if (pExitInfo)
8318 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
8319 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_VMPTRLD, VMXINSTRID_NONE, cbInstr);
8320 }
8321
8322 Assert(IEM_VMX_IS_ROOT_MODE(pVCpu));
8323
8324 /* CPL. */
8325 if (pVCpu->iem.s.uCpl == 0)
8326 { /* likely */ }
8327 else
8328 {
8329 Log(("vmptrld: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
8330 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_Cpl;
8331 return iemRaiseGeneralProtectionFault0(pVCpu);
8332 }
8333
8334 /* Get the VMCS pointer from the location specified by the source memory operand. */
8335 RTGCPHYS GCPhysVmcs;
8336 VBOXSTRICTRC rcStrict = iemMemFetchDataU64(pVCpu, &GCPhysVmcs, iEffSeg, GCPtrVmcs);
8337 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8338 { /* likely */ }
8339 else
8340 {
8341 Log(("vmptrld: Failed to read VMCS physaddr from %#RGv, rc=%Rrc\n", GCPtrVmcs, VBOXSTRICTRC_VAL(rcStrict)));
8342 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_PtrMap;
8343 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrVmcs;
8344 return rcStrict;
8345 }
8346
8347 /* VMCS pointer alignment. */
8348 if (!(GCPhysVmcs & X86_PAGE_4K_OFFSET_MASK))
8349 { /* likely */ }
8350 else
8351 {
8352 Log(("vmptrld: VMCS pointer not page-aligned -> VMFail()\n"));
8353 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_PtrAlign;
8354 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8355 iemVmxVmFail(pVCpu, VMXINSTRERR_VMPTRLD_INVALID_PHYSADDR);
8356 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8357 return VINF_SUCCESS;
8358 }
8359
8360 /* VMCS physical-address width limits. */
8361 if (!(GCPhysVmcs >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth))
8362 { /* likely */ }
8363 else
8364 {
8365 Log(("vmptrld: VMCS pointer extends beyond physical-address width -> VMFail()\n"));
8366 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_PtrWidth;
8367 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8368 iemVmxVmFail(pVCpu, VMXINSTRERR_VMPTRLD_INVALID_PHYSADDR);
8369 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8370 return VINF_SUCCESS;
8371 }
8372
8373 /* VMCS is not the VMXON region. */
8374 if (GCPhysVmcs != pVCpu->cpum.GstCtx.hwvirt.vmx.GCPhysVmxon)
8375 { /* likely */ }
8376 else
8377 {
8378 Log(("vmptrld: VMCS pointer cannot be identical to VMXON region pointer -> VMFail()\n"));
8379 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_PtrVmxon;
8380 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8381 iemVmxVmFail(pVCpu, VMXINSTRERR_VMPTRLD_VMXON_PTR);
8382 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8383 return VINF_SUCCESS;
8384 }
8385
8386 /* Ensure VMCS is not MMIO, ROM etc. This is not an Intel requirement but a
8387 restriction imposed by our implementation. */
8388 if (PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysVmcs))
8389 { /* likely */ }
8390 else
8391 {
8392 Log(("vmptrld: VMCS not normal memory -> VMFail()\n"));
8393 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_PtrAbnormal;
8394 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8395 iemVmxVmFail(pVCpu, VMXINSTRERR_VMPTRLD_INVALID_PHYSADDR);
8396 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8397 return VINF_SUCCESS;
8398 }
8399
8400 /* Read just the VMCS revision from the VMCS. */
8401 VMXVMCSREVID VmcsRevId;
8402 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &VmcsRevId, GCPhysVmcs, sizeof(VmcsRevId));
8403 if (RT_SUCCESS(rc))
8404 { /* likely */ }
8405 else
8406 {
8407 Log(("vmptrld: Failed to read revision identifier from VMCS at %#RGp, rc=%Rrc\n", GCPhysVmcs, rc));
8408 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_RevPtrReadPhys;
8409 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8410 return rc;
8411 }
8412
8413 /*
8414 * Verify the VMCS revision specified by the guest matches what we reported to the guest.
8415 * Verify the VMCS is not a shadow VMCS, if the VMCS shadowing feature is supported.
8416 */
8417 if ( VmcsRevId.n.u31RevisionId == VMX_V_VMCS_REVISION_ID
8418 && ( !VmcsRevId.n.fIsShadowVmcs
8419 || IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxVmcsShadowing))
8420 { /* likely */ }
8421 else
8422 {
8423 if (VmcsRevId.n.u31RevisionId != VMX_V_VMCS_REVISION_ID)
8424 {
8425 Log(("vmptrld: VMCS revision mismatch, expected %#RX32 got %#RX32, GCPtrVmcs=%#RGv GCPhysVmcs=%#RGp -> VMFail()\n",
8426 VMX_V_VMCS_REVISION_ID, VmcsRevId.n.u31RevisionId, GCPtrVmcs, GCPhysVmcs));
8427 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_VmcsRevId;
8428 iemVmxVmFail(pVCpu, VMXINSTRERR_VMPTRLD_INCORRECT_VMCS_REV);
8429 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8430 return VINF_SUCCESS;
8431 }
8432
8433 Log(("vmptrld: Shadow VMCS -> VMFail()\n"));
8434 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_ShadowVmcs;
8435 iemVmxVmFail(pVCpu, VMXINSTRERR_VMPTRLD_INCORRECT_VMCS_REV);
8436 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8437 return VINF_SUCCESS;
8438 }
8439
8440 /*
8441 * We cache only the current VMCS in CPUMCTX. Therefore, VMPTRLD should always flush
8442 * the cache of an existing, current VMCS back to guest memory before loading a new,
8443 * different current VMCS.
8444 */
8445 if (IEM_VMX_GET_CURRENT_VMCS(pVCpu) != GCPhysVmcs)
8446 {
8447 if (IEM_VMX_HAS_CURRENT_VMCS(pVCpu))
8448 {
8449 iemVmxWriteCurrentVmcsToGstMem(pVCpu);
8450 IEM_VMX_CLEAR_CURRENT_VMCS(pVCpu);
8451 }
8452
8453 /* Set the new VMCS as the current VMCS and read it from guest memory. */
8454 IEM_VMX_SET_CURRENT_VMCS(pVCpu, GCPhysVmcs);
8455 rc = iemVmxReadCurrentVmcsFromGstMem(pVCpu);
8456 if (RT_SUCCESS(rc))
8457 {
8458 /* Notify HM that a new, current VMCS is loaded. */
8459 if (VM_IS_HM_ENABLED(pVCpu->CTX_SUFF(pVM)))
8460 HMNotifyVmxNstGstCurrentVmcsChanged(pVCpu);
8461 }
8462 else
8463 {
8464 Log(("vmptrld: Failed to read VMCS at %#RGp, rc=%Rrc\n", GCPhysVmcs, rc));
8465 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_PtrReadPhys;
8466 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8467 return rc;
8468 }
8469 }
8470
8471 Assert(IEM_VMX_HAS_CURRENT_VMCS(pVCpu));
8472 iemVmxVmSucceed(pVCpu);
8473 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8474 return VINF_SUCCESS;
8475}
8476
8477
8478/**
8479 * INVVPID instruction execution worker.
8480 *
8481 * @returns Strict VBox status code.
8482 * @param pVCpu The cross context virtual CPU structure.
8483 * @param cbInstr The instruction length in bytes.
8484 * @param iEffSeg The segment of the invvpid descriptor.
8485 * @param GCPtrInvvpidDesc The address of invvpid descriptor.
8486 * @param u64InvvpidType The invalidation type.
8487 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
8488 * NULL.
8489 *
8490 * @remarks Common VMX instruction checks are already expected to by the caller,
8491 * i.e. VMX operation, CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
8492 */
8493IEM_STATIC VBOXSTRICTRC iemVmxInvvpid(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrInvvpidDesc,
8494 uint64_t u64InvvpidType, PCVMXVEXITINFO pExitInfo)
8495{
8496 /* Check if INVVPID instruction is supported, otherwise raise #UD. */
8497 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxVpid)
8498 return iemRaiseUndefinedOpcode(pVCpu);
8499
8500 /* Nested-guest intercept. */
8501 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8502 {
8503 if (pExitInfo)
8504 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
8505 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_INVVPID, VMXINSTRID_NONE, cbInstr);
8506 }
8507
8508 /* CPL. */
8509 if (pVCpu->iem.s.uCpl != 0)
8510 {
8511 Log(("invvpid: CPL != 0 -> #GP(0)\n"));
8512 return iemRaiseGeneralProtectionFault0(pVCpu);
8513 }
8514
8515 /*
8516 * Validate INVVPID invalidation type.
8517 *
8518 * The instruction specifies exactly ONE of the supported invalidation types.
8519 *
8520 * Each of the types has a bit in IA32_VMX_EPT_VPID_CAP MSR specifying if it is
8521 * supported. In theory, it's possible for a CPU to not support flushing individual
8522 * addresses but all the other types or any other combination. We do not take any
8523 * shortcuts here by assuming the types we currently expose to the guest.
8524 */
8525 uint64_t const fCaps = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64EptVpidCaps;
8526 bool const fInvvpidSupported = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVVPID);
8527 bool const fTypeIndivAddr = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVVPID_INDIV_ADDR);
8528 bool const fTypeSingleCtx = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX);
8529 bool const fTypeAllCtx = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVVPID_ALL_CTX);
8530 bool const fTypeSingleCtxRetainGlobals = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_RETAIN_GLOBALS);
8531
8532 bool afSupportedTypes[4];
8533 afSupportedTypes[0] = fTypeIndivAddr;
8534 afSupportedTypes[1] = fTypeSingleCtx;
8535 afSupportedTypes[2] = fTypeAllCtx;
8536 afSupportedTypes[3] = fTypeSingleCtxRetainGlobals;
8537
8538 if ( fInvvpidSupported
8539 && !(u64InvvpidType & ~(uint64_t)VMX_INVVPID_VALID_MASK)
8540 && afSupportedTypes[u64InvvpidType & 3])
8541 { /* likely */ }
8542 else
8543 {
8544 Log(("invvpid: invalid/unsupported invvpid type %#x -> VMFail\n", u64InvvpidType));
8545 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invvpid_TypeInvalid;
8546 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64InvvpidType;
8547 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
8548 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8549 return VINF_SUCCESS;
8550 }
8551
8552 /*
8553 * Fetch the invvpid descriptor from guest memory.
8554 */
8555 RTUINT128U uDesc;
8556 VBOXSTRICTRC rcStrict = iemMemFetchDataU128(pVCpu, &uDesc, iEffSeg, GCPtrInvvpidDesc);
8557 if (rcStrict == VINF_SUCCESS)
8558 {
8559 /*
8560 * Validate the descriptor.
8561 */
8562 if (uDesc.s.Lo <= 0xffff)
8563 { /* likely */ }
8564 else
8565 {
8566 Log(("invvpid: reserved bits set in invvpid descriptor %#RX64 -> #GP(0)\n", uDesc.s.Lo));
8567 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invvpid_DescRsvd;
8568 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = uDesc.s.Lo;
8569 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
8570 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8571 return VINF_SUCCESS;
8572 }
8573
8574 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
8575 RTGCUINTPTR64 const GCPtrInvAddr = uDesc.s.Hi;
8576 uint8_t const uVpid = uDesc.s.Lo & UINT64_C(0xfff);
8577 uint64_t const uCr3 = pVCpu->cpum.GstCtx.cr3;
8578 switch (u64InvvpidType)
8579 {
8580 case VMXTLBFLUSHVPID_INDIV_ADDR:
8581 {
8582 if (uVpid != 0)
8583 {
8584 if (IEM_IS_CANONICAL(GCPtrInvAddr))
8585 {
8586 /* Invalidate mappings for the linear address tagged with VPID. */
8587 /** @todo PGM support for VPID? Currently just flush everything. */
8588 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
8589 iemVmxVmSucceed(pVCpu);
8590 }
8591 else
8592 {
8593 Log(("invvpid: invalidation address %#RGP is not canonical -> VMFail\n", GCPtrInvAddr));
8594 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invvpid_Type0InvalidAddr;
8595 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrInvAddr;
8596 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
8597 }
8598 }
8599 else
8600 {
8601 Log(("invvpid: invalid VPID %#x for invalidation type %u -> VMFail\n", uVpid, u64InvvpidType));
8602 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invvpid_Type0InvalidVpid;
8603 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64InvvpidType;
8604 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
8605 }
8606 break;
8607 }
8608
8609 case VMXTLBFLUSHVPID_SINGLE_CONTEXT:
8610 {
8611 if (uVpid != 0)
8612 {
8613 /* Invalidate all mappings with VPID. */
8614 /** @todo PGM support for VPID? Currently just flush everything. */
8615 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
8616 iemVmxVmSucceed(pVCpu);
8617 }
8618 else
8619 {
8620 Log(("invvpid: invalid VPID %#x for invalidation type %u -> VMFail\n", uVpid, u64InvvpidType));
8621 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invvpid_Type1InvalidVpid;
8622 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64InvvpidType;
8623 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
8624 }
8625 break;
8626 }
8627
8628 case VMXTLBFLUSHVPID_ALL_CONTEXTS:
8629 {
8630 /* Invalidate all mappings with non-zero VPIDs. */
8631 /** @todo PGM support for VPID? Currently just flush everything. */
8632 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
8633 iemVmxVmSucceed(pVCpu);
8634 break;
8635 }
8636
8637 case VMXTLBFLUSHVPID_SINGLE_CONTEXT_RETAIN_GLOBALS:
8638 {
8639 if (uVpid != 0)
8640 {
8641 /* Invalidate all mappings with VPID except global translations. */
8642 /** @todo PGM support for VPID? Currently just flush everything. */
8643 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
8644 iemVmxVmSucceed(pVCpu);
8645 }
8646 else
8647 {
8648 Log(("invvpid: invalid VPID %#x for invalidation type %u -> VMFail\n", uVpid, u64InvvpidType));
8649 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invvpid_Type3InvalidVpid;
8650 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = uVpid;
8651 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
8652 }
8653 break;
8654 }
8655 IEM_NOT_REACHED_DEFAULT_CASE_RET();
8656 }
8657 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8658 }
8659 return rcStrict;
8660}
8661
8662
8663#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
8664/**
8665 * INVEPT instruction execution worker.
8666 *
8667 * @returns Strict VBox status code.
8668 * @param pVCpu The cross context virtual CPU structure.
8669 * @param cbInstr The instruction length in bytes.
8670 * @param iEffSeg The segment of the invept descriptor.
8671 * @param GCPtrInveptDesc The address of invept descriptor.
8672 * @param u64InveptType The invalidation type.
8673 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
8674 * NULL.
8675 *
8676 * @remarks Common VMX instruction checks are already expected to by the caller,
8677 * i.e. VMX operation, CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
8678 */
8679IEM_STATIC VBOXSTRICTRC iemVmxInvept(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrInveptDesc,
8680 uint64_t u64InveptType, PCVMXVEXITINFO pExitInfo)
8681{
8682 /* Check if EPT is supported, otherwise raise #UD. */
8683 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxEpt)
8684 return iemRaiseUndefinedOpcode(pVCpu);
8685
8686 /* Nested-guest intercept. */
8687 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8688 {
8689 if (pExitInfo)
8690 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
8691 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_INVEPT, VMXINSTRID_NONE, cbInstr);
8692 }
8693
8694 /* CPL. */
8695 if (pVCpu->iem.s.uCpl != 0)
8696 {
8697 Log(("invept: CPL != 0 -> #GP(0)\n"));
8698 return iemRaiseGeneralProtectionFault0(pVCpu);
8699 }
8700
8701 /*
8702 * Validate INVEPT invalidation type.
8703 *
8704 * The instruction specifies exactly ONE of the supported invalidation types.
8705 *
8706 * Each of the types has a bit in IA32_VMX_EPT_VPID_CAP MSR specifying if it is
8707 * supported. In theory, it's possible for a CPU to not support flushing individual
8708 * addresses but all the other types or any other combination. We do not take any
8709 * shortcuts here by assuming the types we currently expose to the guest.
8710 */
8711 uint64_t const fCaps = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64EptVpidCaps;
8712 bool const fInveptSupported = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVEPT);
8713 bool const fTypeSingleCtx = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVEPT_SINGLE_CTX);
8714 bool const fTypeAllCtx = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVEPT_ALL_CTX);
8715
8716 bool afSupportedTypes[4];
8717 afSupportedTypes[0] = false;
8718 afSupportedTypes[1] = fTypeSingleCtx;
8719 afSupportedTypes[2] = fTypeAllCtx;
8720 afSupportedTypes[3] = false;
8721
8722 if ( fInveptSupported
8723 && !(u64InveptType & ~(uint64_t)VMX_INVEPT_VALID_MASK)
8724 && afSupportedTypes[u64InveptType & 3])
8725 { /* likely */ }
8726 else
8727 {
8728 Log(("invept: invalid/unsupported invvpid type %#x -> VMFail\n", u64InveptType));
8729 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invept_TypeInvalid;
8730 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64InveptType;
8731 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
8732 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8733 return VINF_SUCCESS;
8734 }
8735
8736 /*
8737 * Fetch the invept descriptor from guest memory.
8738 */
8739 RTUINT128U uDesc;
8740 VBOXSTRICTRC rcStrict = iemMemFetchDataU128(pVCpu, &uDesc, iEffSeg, GCPtrInveptDesc);
8741 if (rcStrict == VINF_SUCCESS)
8742 {
8743 /*
8744 * Validate the descriptor.
8745 *
8746 * The Intel spec. does not explicit say the INVEPT instruction fails when reserved
8747 * bits in the descriptor are set, but it -does- for INVVPID. Until we test on real
8748 * hardware, it's assumed INVEPT behaves the same as INVVPID in this regard. It's
8749 * better to be strict in our emulation until proven otherwise.
8750 */
8751 if (uDesc.s.Hi)
8752 {
8753 Log(("invept: reserved bits set in invept descriptor %#RX64 -> VMFail\n", uDesc.s.Hi));
8754 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invept_DescRsvd;
8755 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = uDesc.s.Hi;
8756 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
8757 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8758 return VINF_SUCCESS;
8759 }
8760
8761 /*
8762 * Flush TLB mappings based on the EPT type.
8763 */
8764 if (u64InveptType == VMXTLBFLUSHEPT_SINGLE_CONTEXT)
8765 {
8766 uint64_t const GCPhysEptPtr = uDesc.s.Lo;
8767 int const rc = iemVmxVmentryCheckEptPtr(pVCpu, GCPhysEptPtr, NULL /* enmDiag */);
8768 if (RT_SUCCESS(rc))
8769 { /* likely */ }
8770 else
8771 {
8772 Log(("invept: EPTP invalid %#RX64 -> VMFail\n", GCPhysEptPtr));
8773 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invept_EptpInvalid;
8774 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysEptPtr;
8775 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
8776 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8777 return VINF_SUCCESS;
8778 }
8779 }
8780
8781 /** @todo PGM support for EPT tags? Currently just flush everything. */
8782 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
8783 uint64_t const uCr3 = pVCpu->cpum.GstCtx.cr3;
8784 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
8785
8786 iemVmxVmSucceed(pVCpu);
8787 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8788 }
8789
8790 return rcStrict;
8791}
8792#endif /* VBOX_WITH_NESTED_HWVIRT_VMX_EPT */
8793
8794
8795/**
8796 * VMXON instruction execution worker.
8797 *
8798 * @returns Strict VBox status code.
8799 * @param pVCpu The cross context virtual CPU structure.
8800 * @param cbInstr The instruction length in bytes.
8801 * @param iEffSeg The effective segment register to use with @a
8802 * GCPtrVmxon.
8803 * @param GCPtrVmxon The linear address of the VMXON pointer.
8804 * @param pExitInfo Pointer to the VM-exit information. Optional, can be NULL.
8805 *
8806 * @remarks Common VMX instruction checks are already expected to by the caller,
8807 * i.e. CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
8808 */
8809IEM_STATIC VBOXSTRICTRC iemVmxVmxon(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPHYS GCPtrVmxon,
8810 PCVMXVEXITINFO pExitInfo)
8811{
8812 if (!IEM_VMX_IS_ROOT_MODE(pVCpu))
8813 {
8814 /* CPL. */
8815 if (pVCpu->iem.s.uCpl == 0)
8816 { /* likely */ }
8817 else
8818 {
8819 Log(("vmxon: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
8820 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_Cpl;
8821 return iemRaiseGeneralProtectionFault0(pVCpu);
8822 }
8823
8824 /* A20M (A20 Masked) mode. */
8825 if (PGMPhysIsA20Enabled(pVCpu))
8826 { /* likely */ }
8827 else
8828 {
8829 Log(("vmxon: A20M mode -> #GP(0)\n"));
8830 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_A20M;
8831 return iemRaiseGeneralProtectionFault0(pVCpu);
8832 }
8833
8834 /* CR0. */
8835 {
8836 /*
8837 * CR0 MB1 bits.
8838 *
8839 * We use VMX_V_CR0_FIXED0 below to ensure CR0.PE and CR0.PG are always set
8840 * while executing VMXON. CR0.PE and CR0.PG are only allowed to be clear
8841 * when the guest running in VMX non-root mode with unrestricted-guest control
8842 * enabled in the VMCS.
8843 */
8844 uint64_t const uCr0Fixed0 = VMX_V_CR0_FIXED0;
8845 if ((pVCpu->cpum.GstCtx.cr0 & uCr0Fixed0) == uCr0Fixed0)
8846 { /* likely */ }
8847 else
8848 {
8849 Log(("vmxon: CR0 fixed0 bits cleared -> #GP(0)\n"));
8850 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_Cr0Fixed0;
8851 return iemRaiseGeneralProtectionFault0(pVCpu);
8852 }
8853
8854 /* CR0 MBZ bits. */
8855 uint64_t const uCr0Fixed1 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr0Fixed1;
8856 if (!(pVCpu->cpum.GstCtx.cr0 & ~uCr0Fixed1))
8857 { /* likely */ }
8858 else
8859 {
8860 Log(("vmxon: CR0 fixed1 bits set -> #GP(0)\n"));
8861 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_Cr0Fixed1;
8862 return iemRaiseGeneralProtectionFault0(pVCpu);
8863 }
8864 }
8865
8866 /* CR4. */
8867 {
8868 /* CR4 MB1 bits. */
8869 uint64_t const uCr4Fixed0 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed0;
8870 if ((pVCpu->cpum.GstCtx.cr4 & uCr4Fixed0) == uCr4Fixed0)
8871 { /* likely */ }
8872 else
8873 {
8874 Log(("vmxon: CR4 fixed0 bits cleared -> #GP(0)\n"));
8875 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_Cr4Fixed0;
8876 return iemRaiseGeneralProtectionFault0(pVCpu);
8877 }
8878
8879 /* CR4 MBZ bits. */
8880 uint64_t const uCr4Fixed1 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed1;
8881 if (!(pVCpu->cpum.GstCtx.cr4 & ~uCr4Fixed1))
8882 { /* likely */ }
8883 else
8884 {
8885 Log(("vmxon: CR4 fixed1 bits set -> #GP(0)\n"));
8886 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_Cr4Fixed1;
8887 return iemRaiseGeneralProtectionFault0(pVCpu);
8888 }
8889 }
8890
8891 /* Feature control MSR's LOCK and VMXON bits. */
8892 uint64_t const uMsrFeatCtl = CPUMGetGuestIa32FeatCtrl(pVCpu);
8893 if ((uMsrFeatCtl & (MSR_IA32_FEATURE_CONTROL_LOCK | MSR_IA32_FEATURE_CONTROL_VMXON))
8894 == (MSR_IA32_FEATURE_CONTROL_LOCK | MSR_IA32_FEATURE_CONTROL_VMXON))
8895 { /* likely */ }
8896 else
8897 {
8898 Log(("vmxon: Feature control lock bit or VMXON bit cleared -> #GP(0)\n"));
8899 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_MsrFeatCtl;
8900 return iemRaiseGeneralProtectionFault0(pVCpu);
8901 }
8902
8903 /* Get the VMXON pointer from the location specified by the source memory operand. */
8904 RTGCPHYS GCPhysVmxon;
8905 VBOXSTRICTRC rcStrict = iemMemFetchDataU64(pVCpu, &GCPhysVmxon, iEffSeg, GCPtrVmxon);
8906 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8907 { /* likely */ }
8908 else
8909 {
8910 Log(("vmxon: Failed to read VMXON region physaddr from %#RGv, rc=%Rrc\n", GCPtrVmxon, VBOXSTRICTRC_VAL(rcStrict)));
8911 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_PtrMap;
8912 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrVmxon;
8913 return rcStrict;
8914 }
8915
8916 /* VMXON region pointer alignment. */
8917 if (!(GCPhysVmxon & X86_PAGE_4K_OFFSET_MASK))
8918 { /* likely */ }
8919 else
8920 {
8921 Log(("vmxon: VMXON region pointer not page-aligned -> VMFailInvalid\n"));
8922 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_PtrAlign;
8923 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmxon;
8924 iemVmxVmFailInvalid(pVCpu);
8925 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8926 return VINF_SUCCESS;
8927 }
8928
8929 /* VMXON physical-address width limits. */
8930 if (!(GCPhysVmxon >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth))
8931 { /* likely */ }
8932 else
8933 {
8934 Log(("vmxon: VMXON region pointer extends beyond physical-address width -> VMFailInvalid\n"));
8935 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_PtrWidth;
8936 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmxon;
8937 iemVmxVmFailInvalid(pVCpu);
8938 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8939 return VINF_SUCCESS;
8940 }
8941
8942 /* Ensure VMXON region is not MMIO, ROM etc. This is not an Intel requirement but a
8943 restriction imposed by our implementation. */
8944 if (PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysVmxon))
8945 { /* likely */ }
8946 else
8947 {
8948 Log(("vmxon: VMXON region not normal memory -> VMFailInvalid\n"));
8949 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_PtrAbnormal;
8950 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmxon;
8951 iemVmxVmFailInvalid(pVCpu);
8952 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8953 return VINF_SUCCESS;
8954 }
8955
8956 /* Read the VMCS revision ID from the VMXON region. */
8957 VMXVMCSREVID VmcsRevId;
8958 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &VmcsRevId, GCPhysVmxon, sizeof(VmcsRevId));
8959 if (RT_SUCCESS(rc))
8960 { /* likely */ }
8961 else
8962 {
8963 Log(("vmxon: Failed to read VMXON region at %#RGp, rc=%Rrc\n", GCPhysVmxon, rc));
8964 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_PtrReadPhys;
8965 return rc;
8966 }
8967
8968 /* Verify the VMCS revision specified by the guest matches what we reported to the guest. */
8969 if (RT_LIKELY(VmcsRevId.u == VMX_V_VMCS_REVISION_ID))
8970 { /* likely */ }
8971 else
8972 {
8973 /* Revision ID mismatch. */
8974 if (!VmcsRevId.n.fIsShadowVmcs)
8975 {
8976 Log(("vmxon: VMCS revision mismatch, expected %#RX32 got %#RX32 -> VMFailInvalid\n", VMX_V_VMCS_REVISION_ID,
8977 VmcsRevId.n.u31RevisionId));
8978 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_VmcsRevId;
8979 iemVmxVmFailInvalid(pVCpu);
8980 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8981 return VINF_SUCCESS;
8982 }
8983
8984 /* Shadow VMCS disallowed. */
8985 Log(("vmxon: Shadow VMCS -> VMFailInvalid\n"));
8986 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_ShadowVmcs;
8987 iemVmxVmFailInvalid(pVCpu);
8988 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
8989 return VINF_SUCCESS;
8990 }
8991
8992 /*
8993 * Record that we're in VMX operation, block INIT, block and disable A20M.
8994 */
8995 pVCpu->cpum.GstCtx.hwvirt.vmx.GCPhysVmxon = GCPhysVmxon;
8996 IEM_VMX_CLEAR_CURRENT_VMCS(pVCpu);
8997 pVCpu->cpum.GstCtx.hwvirt.vmx.fInVmxRootMode = true;
8998
8999 /* Clear address-range monitoring. */
9000 EMMonitorWaitClear(pVCpu);
9001 /** @todo NSTVMX: Intel PT. */
9002
9003 iemVmxVmSucceed(pVCpu);
9004 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
9005 return VINF_SUCCESS;
9006 }
9007 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
9008 {
9009 /* Nested-guest intercept. */
9010 if (pExitInfo)
9011 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
9012 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_VMXON, VMXINSTRID_NONE, cbInstr);
9013 }
9014
9015 Assert(IEM_VMX_IS_ROOT_MODE(pVCpu));
9016
9017 /* CPL. */
9018 if (pVCpu->iem.s.uCpl > 0)
9019 {
9020 Log(("vmxon: In VMX root mode: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
9021 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_VmxRootCpl;
9022 return iemRaiseGeneralProtectionFault0(pVCpu);
9023 }
9024
9025 /* VMXON when already in VMX root mode. */
9026 iemVmxVmFail(pVCpu, VMXINSTRERR_VMXON_IN_VMXROOTMODE);
9027 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_VmxAlreadyRoot;
9028 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
9029 return VINF_SUCCESS;
9030}
9031
9032
9033/**
9034 * Implements 'VMXOFF'.
9035 *
9036 * @remarks Common VMX instruction checks are already expected to by the caller,
9037 * i.e. CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
9038 */
9039IEM_CIMPL_DEF_0(iemCImpl_vmxoff)
9040{
9041 /* Nested-guest intercept. */
9042 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
9043 return iemVmxVmexitInstr(pVCpu, VMX_EXIT_VMXOFF, cbInstr);
9044
9045 /* CPL. */
9046 if (pVCpu->iem.s.uCpl == 0)
9047 { /* likely */ }
9048 else
9049 {
9050 Log(("vmxoff: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
9051 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxoff_Cpl;
9052 return iemRaiseGeneralProtectionFault0(pVCpu);
9053 }
9054
9055 /* Dual monitor treatment of SMIs and SMM. */
9056 uint64_t const fSmmMonitorCtl = CPUMGetGuestIa32SmmMonitorCtl(pVCpu);
9057 if (!(fSmmMonitorCtl & MSR_IA32_SMM_MONITOR_VALID))
9058 { /* likely */ }
9059 else
9060 {
9061 iemVmxVmFail(pVCpu, VMXINSTRERR_VMXOFF_DUAL_MON);
9062 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
9063 return VINF_SUCCESS;
9064 }
9065
9066 /* Record that we're no longer in VMX root operation, block INIT, block and disable A20M. */
9067 pVCpu->cpum.GstCtx.hwvirt.vmx.fInVmxRootMode = false;
9068 Assert(!pVCpu->cpum.GstCtx.hwvirt.vmx.fInVmxNonRootMode);
9069
9070 if (fSmmMonitorCtl & MSR_IA32_SMM_MONITOR_VMXOFF_UNBLOCK_SMI)
9071 { /** @todo NSTVMX: Unblock SMI. */ }
9072
9073 EMMonitorWaitClear(pVCpu);
9074 /** @todo NSTVMX: Unblock and enable A20M. */
9075
9076 iemVmxVmSucceed(pVCpu);
9077 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
9078 return VINF_SUCCESS;
9079}
9080
9081
9082/**
9083 * Implements 'VMXON'.
9084 */
9085IEM_CIMPL_DEF_2(iemCImpl_vmxon, uint8_t, iEffSeg, RTGCPTR, GCPtrVmxon)
9086{
9087 return iemVmxVmxon(pVCpu, cbInstr, iEffSeg, GCPtrVmxon, NULL /* pExitInfo */);
9088}
9089
9090
9091/**
9092 * Implements 'VMLAUNCH'.
9093 */
9094IEM_CIMPL_DEF_0(iemCImpl_vmlaunch)
9095{
9096 return iemVmxVmlaunchVmresume(pVCpu, cbInstr, VMXINSTRID_VMLAUNCH);
9097}
9098
9099
9100/**
9101 * Implements 'VMRESUME'.
9102 */
9103IEM_CIMPL_DEF_0(iemCImpl_vmresume)
9104{
9105 return iemVmxVmlaunchVmresume(pVCpu, cbInstr, VMXINSTRID_VMRESUME);
9106}
9107
9108
9109/**
9110 * Implements 'VMPTRLD'.
9111 */
9112IEM_CIMPL_DEF_2(iemCImpl_vmptrld, uint8_t, iEffSeg, RTGCPTR, GCPtrVmcs)
9113{
9114 return iemVmxVmptrld(pVCpu, cbInstr, iEffSeg, GCPtrVmcs, NULL /* pExitInfo */);
9115}
9116
9117
9118/**
9119 * Implements 'VMPTRST'.
9120 */
9121IEM_CIMPL_DEF_2(iemCImpl_vmptrst, uint8_t, iEffSeg, RTGCPTR, GCPtrVmcs)
9122{
9123 return iemVmxVmptrst(pVCpu, cbInstr, iEffSeg, GCPtrVmcs, NULL /* pExitInfo */);
9124}
9125
9126
9127/**
9128 * Implements 'VMCLEAR'.
9129 */
9130IEM_CIMPL_DEF_2(iemCImpl_vmclear, uint8_t, iEffSeg, RTGCPTR, GCPtrVmcs)
9131{
9132 return iemVmxVmclear(pVCpu, cbInstr, iEffSeg, GCPtrVmcs, NULL /* pExitInfo */);
9133}
9134
9135
9136/**
9137 * Implements 'VMWRITE' register.
9138 */
9139IEM_CIMPL_DEF_2(iemCImpl_vmwrite_reg, uint64_t, u64Val, uint64_t, u64VmcsField)
9140{
9141 return iemVmxVmwrite(pVCpu, cbInstr, UINT8_MAX /* iEffSeg */, u64Val, u64VmcsField, NULL /* pExitInfo */);
9142}
9143
9144
9145/**
9146 * Implements 'VMWRITE' memory.
9147 */
9148IEM_CIMPL_DEF_3(iemCImpl_vmwrite_mem, uint8_t, iEffSeg, RTGCPTR, GCPtrVal, uint32_t, u64VmcsField)
9149{
9150 return iemVmxVmwrite(pVCpu, cbInstr, iEffSeg, GCPtrVal, u64VmcsField, NULL /* pExitInfo */);
9151}
9152
9153
9154/**
9155 * Implements 'VMREAD' register (64-bit).
9156 */
9157IEM_CIMPL_DEF_2(iemCImpl_vmread_reg64, uint64_t *, pu64Dst, uint64_t, u64VmcsField)
9158{
9159 return iemVmxVmreadReg64(pVCpu, cbInstr, pu64Dst, u64VmcsField, NULL /* pExitInfo */);
9160}
9161
9162
9163/**
9164 * Implements 'VMREAD' register (32-bit).
9165 */
9166IEM_CIMPL_DEF_2(iemCImpl_vmread_reg32, uint32_t *, pu32Dst, uint32_t, u32VmcsField)
9167{
9168 return iemVmxVmreadReg32(pVCpu, cbInstr, pu32Dst, u32VmcsField, NULL /* pExitInfo */);
9169}
9170
9171
9172/**
9173 * Implements 'VMREAD' memory, 64-bit register.
9174 */
9175IEM_CIMPL_DEF_3(iemCImpl_vmread_mem_reg64, uint8_t, iEffSeg, RTGCPTR, GCPtrDst, uint32_t, u64VmcsField)
9176{
9177 return iemVmxVmreadMem(pVCpu, cbInstr, iEffSeg, GCPtrDst, u64VmcsField, NULL /* pExitInfo */);
9178}
9179
9180
9181/**
9182 * Implements 'VMREAD' memory, 32-bit register.
9183 */
9184IEM_CIMPL_DEF_3(iemCImpl_vmread_mem_reg32, uint8_t, iEffSeg, RTGCPTR, GCPtrDst, uint32_t, u32VmcsField)
9185{
9186 return iemVmxVmreadMem(pVCpu, cbInstr, iEffSeg, GCPtrDst, u32VmcsField, NULL /* pExitInfo */);
9187}
9188
9189
9190/**
9191 * Implements 'INVVPID'.
9192 */
9193IEM_CIMPL_DEF_3(iemCImpl_invvpid, uint8_t, iEffSeg, RTGCPTR, GCPtrInvvpidDesc, uint64_t, uInvvpidType)
9194{
9195 return iemVmxInvvpid(pVCpu, cbInstr, iEffSeg, GCPtrInvvpidDesc, uInvvpidType, NULL /* pExitInfo */);
9196}
9197
9198
9199#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
9200/**
9201 * Implements 'INVEPT'.
9202 */
9203IEM_CIMPL_DEF_3(iemCImpl_invept, uint8_t, iEffSeg, RTGCPTR, GCPtrInveptDesc, uint64_t, uInveptType)
9204{
9205 return iemVmxInvept(pVCpu, cbInstr, iEffSeg, GCPtrInveptDesc, uInveptType, NULL /* pExitInfo */);
9206}
9207#endif
9208
9209
9210/**
9211 * Implements VMX's implementation of PAUSE.
9212 */
9213IEM_CIMPL_DEF_0(iemCImpl_vmx_pause)
9214{
9215 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
9216 {
9217 VBOXSTRICTRC rcStrict = iemVmxVmexitInstrPause(pVCpu, cbInstr);
9218 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
9219 return rcStrict;
9220 }
9221
9222 /*
9223 * Outside VMX non-root operation or if the PAUSE instruction does not cause
9224 * a VM-exit, the instruction operates normally.
9225 */
9226 iemRegAddToRipAndClearRF(pVCpu, cbInstr);
9227 return VINF_SUCCESS;
9228}
9229
9230#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
9231
9232
9233/**
9234 * Implements 'VMCALL'.
9235 */
9236IEM_CIMPL_DEF_0(iemCImpl_vmcall)
9237{
9238#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9239 /* Nested-guest intercept. */
9240 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
9241 return iemVmxVmexitInstr(pVCpu, VMX_EXIT_VMCALL, cbInstr);
9242#endif
9243
9244 /* Join forces with vmmcall. */
9245 return IEM_CIMPL_CALL_1(iemCImpl_Hypercall, OP_VMCALL);
9246}
9247
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