VirtualBox

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

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

VMM/IEM: Whitespace fix in VMX code. bugref:10092

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