VirtualBox

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

Last change on this file since 96789 was 96762, checked in by vboxsync, 2 years ago

VMM/IEM: Nested VMX: bugref:10092 Minor optimization to iemVmxPprVirtualization.

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