VirtualBox

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

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

VMM/IEM: iemRegAddToRipAndClearRF -> iemRegUpdateRipAndFinishClearingRF and made callers use the return code. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 407.3 KB
Line 
1/* $Id: IEMAllCImplVmxInstr.cpp 97370 2022-11-02 00:53:30Z 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 uint64_t const uValidEferMask = CPUMGetGuestEferMsrValidMask(pVCpu->CTX_SUFF(pVM));
6139 if ( !(pVmcs->u32ExitCtls & VMX_EXIT_CTLS_LOAD_EFER_MSR)
6140 || !(pVmcs->u64HostEferMsr.u & ~uValidEferMask))
6141 { /* likely */ }
6142 else
6143 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostEferMsrRsvd);
6144
6145 bool const fHostInLongMode = RT_BOOL(pVmcs->u32ExitCtls & VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE);
6146 bool const fHostLma = RT_BOOL(pVmcs->u64HostEferMsr.u & MSR_K6_EFER_LMA);
6147 bool const fHostLme = RT_BOOL(pVmcs->u64HostEferMsr.u & MSR_K6_EFER_LME);
6148 if ( fHostInLongMode == fHostLma
6149 && fHostInLongMode == fHostLme)
6150 { /* likely */ }
6151 else
6152 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostEferMsr);
6153
6154 /*
6155 * Host Segment and Descriptor-Table Registers.
6156 * See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
6157 */
6158 /* Selector RPL and TI. */
6159 if ( !(pVmcs->HostCs & (X86_SEL_RPL | X86_SEL_LDT))
6160 && !(pVmcs->HostSs & (X86_SEL_RPL | X86_SEL_LDT))
6161 && !(pVmcs->HostDs & (X86_SEL_RPL | X86_SEL_LDT))
6162 && !(pVmcs->HostEs & (X86_SEL_RPL | X86_SEL_LDT))
6163 && !(pVmcs->HostFs & (X86_SEL_RPL | X86_SEL_LDT))
6164 && !(pVmcs->HostGs & (X86_SEL_RPL | X86_SEL_LDT))
6165 && !(pVmcs->HostTr & (X86_SEL_RPL | X86_SEL_LDT)))
6166 { /* likely */ }
6167 else
6168 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostSel);
6169
6170 /* CS and TR selectors cannot be 0. */
6171 if ( pVmcs->HostCs
6172 && pVmcs->HostTr)
6173 { /* likely */ }
6174 else
6175 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostCsTr);
6176
6177 /* SS cannot be 0 if 32-bit host. */
6178 if ( fHostInLongMode
6179 || pVmcs->HostSs)
6180 { /* likely */ }
6181 else
6182 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostSs);
6183
6184 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
6185 {
6186 /* FS, GS, GDTR, IDTR, TR base address. */
6187 if ( X86_IS_CANONICAL(pVmcs->u64HostFsBase.u)
6188 && X86_IS_CANONICAL(pVmcs->u64HostFsBase.u)
6189 && X86_IS_CANONICAL(pVmcs->u64HostGdtrBase.u)
6190 && X86_IS_CANONICAL(pVmcs->u64HostIdtrBase.u)
6191 && X86_IS_CANONICAL(pVmcs->u64HostTrBase.u))
6192 { /* likely */ }
6193 else
6194 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostSegBase);
6195 }
6196
6197 /*
6198 * Host address-space size for 64-bit CPUs.
6199 * See Intel spec. 26.2.4 "Checks Related to Address-Space Size".
6200 */
6201 bool const fGstInLongMode = RT_BOOL(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
6202 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
6203 {
6204 bool const fCpuInLongMode = CPUMIsGuestInLongMode(pVCpu);
6205
6206 /* Logical processor in IA-32e mode. */
6207 if (fCpuInLongMode)
6208 {
6209 if (fHostInLongMode)
6210 {
6211 /* PAE must be set. */
6212 if (pVmcs->u64HostCr4.u & X86_CR4_PAE)
6213 { /* likely */ }
6214 else
6215 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostCr4Pae);
6216
6217 /* RIP must be canonical. */
6218 if (X86_IS_CANONICAL(pVmcs->u64HostRip.u))
6219 { /* likely */ }
6220 else
6221 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostRip);
6222 }
6223 else
6224 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostLongMode);
6225 }
6226 else
6227 {
6228 /* Logical processor is outside IA-32e mode. */
6229 if ( !fGstInLongMode
6230 && !fHostInLongMode)
6231 {
6232 /* PCIDE should not be set. */
6233 if (!(pVmcs->u64HostCr4.u & X86_CR4_PCIDE))
6234 { /* likely */ }
6235 else
6236 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostCr4Pcide);
6237
6238 /* The high 32-bits of RIP MBZ. */
6239 if (!pVmcs->u64HostRip.s.Hi)
6240 { /* likely */ }
6241 else
6242 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostRipRsvd);
6243 }
6244 else
6245 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostGuestLongMode);
6246 }
6247 }
6248 else
6249 {
6250 /* Host address-space size for 32-bit CPUs. */
6251 if ( !fGstInLongMode
6252 && !fHostInLongMode)
6253 { /* likely */ }
6254 else
6255 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_HostGuestLongModeNoCpu);
6256 }
6257
6258 NOREF(pszInstr);
6259 NOREF(pszFailure);
6260 return VINF_SUCCESS;
6261}
6262
6263
6264#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
6265/**
6266 * Checks the EPT pointer VMCS field as part of VM-entry.
6267 *
6268 * @returns VBox status code.
6269 * @param pVCpu The cross context virtual CPU structure.
6270 * @param uEptPtr The EPT pointer to check.
6271 * @param penmVmxDiag Where to store the diagnostic reason on failure (not
6272 * updated on success). Optional, can be NULL.
6273 */
6274static int iemVmxVmentryCheckEptPtr(PVMCPUCC pVCpu, uint64_t uEptPtr, VMXVDIAG *penmVmxDiag) RT_NOEXCEPT
6275{
6276 VMXVDIAG enmVmxDiag;
6277
6278 /* Reserved bits. */
6279 uint8_t const cMaxPhysAddrWidth = IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cMaxPhysAddrWidth;
6280 uint64_t const fValidMask = VMX_EPTP_VALID_MASK & ~(UINT64_MAX << cMaxPhysAddrWidth);
6281 if (uEptPtr & fValidMask)
6282 {
6283 /* Memory Type. */
6284 uint64_t const fCaps = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64EptVpidCaps;
6285 uint8_t const fMemType = RT_BF_GET(uEptPtr, VMX_BF_EPTP_MEMTYPE);
6286 if ( ( fMemType == VMX_EPTP_MEMTYPE_WB
6287 && RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_MEMTYPE_WB))
6288 || ( fMemType == VMX_EPTP_MEMTYPE_UC
6289 && RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_MEMTYPE_UC)))
6290 {
6291 /*
6292 * Page walk length (PML4).
6293 * Intel used to specify bit 7 of IA32_VMX_EPT_VPID_CAP as page walk length
6294 * of 5 but that seems to be removed from the latest specs. leaving only PML4
6295 * as the maximum supported page-walk level hence we hardcode it as 3 (1 less than 4)
6296 */
6297 Assert(RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_PAGE_WALK_LENGTH_4));
6298 if (RT_BF_GET(uEptPtr, VMX_BF_EPTP_PAGE_WALK_LENGTH) == 3)
6299 {
6300 /* Access and dirty bits support in EPT structures. */
6301 if ( !RT_BF_GET(uEptPtr, VMX_BF_EPTP_ACCESS_DIRTY)
6302 || RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY))
6303 return VINF_SUCCESS;
6304
6305 enmVmxDiag = kVmxVDiag_Vmentry_EptpAccessDirty;
6306 }
6307 else
6308 enmVmxDiag = kVmxVDiag_Vmentry_EptpPageWalkLength;
6309 }
6310 else
6311 enmVmxDiag = kVmxVDiag_Vmentry_EptpMemType;
6312 }
6313 else
6314 enmVmxDiag = kVmxVDiag_Vmentry_EptpRsvd;
6315
6316 if (penmVmxDiag)
6317 *penmVmxDiag = enmVmxDiag;
6318 return VERR_VMX_VMENTRY_FAILED;
6319}
6320#endif
6321
6322
6323/**
6324 * Checks VMCS controls fields as part of VM-entry.
6325 *
6326 * @returns VBox status code.
6327 * @param pVCpu The cross context virtual CPU structure.
6328 * @param pszInstr The VMX instruction name (for logging purposes).
6329 *
6330 * @remarks This may update secondary-processor based VM-execution control fields
6331 * in the current VMCS if necessary.
6332 */
6333static int iemVmxVmentryCheckCtls(PVMCPUCC pVCpu, const char *pszInstr) RT_NOEXCEPT
6334{
6335 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
6336 const char * const pszFailure = "VMFail";
6337 bool const fVmxTrueMsrs = RT_BOOL(pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Basic & VMX_BF_BASIC_TRUE_CTLS_MASK);
6338
6339 /*
6340 * VM-execution controls.
6341 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
6342 */
6343 {
6344 /* Pin-based VM-execution controls. */
6345 {
6346 VMXCTLSMSR const PinCtls = fVmxTrueMsrs ? pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.TruePinCtls
6347 : pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.PinCtls;
6348 if (!(~pVmcs->u32PinCtls & PinCtls.n.allowed0))
6349 { /* likely */ }
6350 else
6351 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_PinCtlsDisallowed0);
6352
6353 if (!(pVmcs->u32PinCtls & ~PinCtls.n.allowed1))
6354 { /* likely */ }
6355 else
6356 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_PinCtlsAllowed1);
6357 }
6358
6359 /* Processor-based VM-execution controls. */
6360 {
6361 VMXCTLSMSR const ProcCtls = fVmxTrueMsrs ? pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.TrueProcCtls
6362 : pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.ProcCtls;
6363 if (!(~pVmcs->u32ProcCtls & ProcCtls.n.allowed0))
6364 { /* likely */ }
6365 else
6366 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ProcCtlsDisallowed0);
6367
6368 if (!(pVmcs->u32ProcCtls & ~ProcCtls.n.allowed1))
6369 { /* likely */ }
6370 else
6371 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ProcCtlsAllowed1);
6372 }
6373
6374 /* Secondary processor-based VM-execution controls. */
6375 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
6376 {
6377 VMXCTLSMSR const ProcCtls2 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.ProcCtls2;
6378 if (!(~pVmcs->u32ProcCtls2 & ProcCtls2.n.allowed0))
6379 { /* likely */ }
6380 else
6381 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ProcCtls2Disallowed0);
6382
6383 if (!(pVmcs->u32ProcCtls2 & ~ProcCtls2.n.allowed1))
6384 { /* likely */ }
6385 else
6386 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ProcCtls2Allowed1);
6387 }
6388 else
6389 Assert(!pVmcs->u32ProcCtls2);
6390
6391 /* CR3-target count. */
6392 if (pVmcs->u32Cr3TargetCount <= VMX_V_CR3_TARGET_COUNT)
6393 { /* likely */ }
6394 else
6395 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_Cr3TargetCount);
6396
6397 /* I/O bitmaps physical addresses. */
6398 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_IO_BITMAPS)
6399 {
6400 RTGCPHYS const GCPhysIoBitmapA = pVmcs->u64AddrIoBitmapA.u;
6401 if ( !(GCPhysIoBitmapA & X86_PAGE_4K_OFFSET_MASK)
6402 && !(GCPhysIoBitmapA >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6403 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysIoBitmapA))
6404 { /* likely */ }
6405 else
6406 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrIoBitmapA);
6407
6408 RTGCPHYS const GCPhysIoBitmapB = pVmcs->u64AddrIoBitmapB.u;
6409 if ( !(GCPhysIoBitmapB & X86_PAGE_4K_OFFSET_MASK)
6410 && !(GCPhysIoBitmapB >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6411 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysIoBitmapB))
6412 { /* likely */ }
6413 else
6414 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrIoBitmapB);
6415 }
6416
6417 /* MSR bitmap physical address. */
6418 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
6419 {
6420 RTGCPHYS const GCPhysMsrBitmap = pVmcs->u64AddrMsrBitmap.u;
6421 if ( !(GCPhysMsrBitmap & X86_PAGE_4K_OFFSET_MASK)
6422 && !(GCPhysMsrBitmap >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6423 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysMsrBitmap))
6424 { /* likely */ }
6425 else
6426 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrMsrBitmap);
6427 }
6428
6429 /* TPR shadow related controls. */
6430 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
6431 {
6432 /* Virtual-APIC page physical address. */
6433 RTGCPHYS const GCPhysVirtApic = pVmcs->u64AddrVirtApic.u;
6434 if ( !(GCPhysVirtApic & X86_PAGE_4K_OFFSET_MASK)
6435 && !(GCPhysVirtApic >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6436 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysVirtApic))
6437 { /* likely */ }
6438 else
6439 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrVirtApicPage);
6440
6441 /* TPR threshold bits 31:4 MBZ without virtual-interrupt delivery. */
6442 if ( !(pVmcs->u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)
6443 || (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY))
6444 { /* likely */ }
6445 else
6446 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_TprThresholdRsvd);
6447
6448 /* The rest done XXX document */
6449 }
6450 else
6451 {
6452 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_X2APIC_MODE)
6453 && !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_APIC_REG_VIRT)
6454 && !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY))
6455 { /* likely */ }
6456 else
6457 {
6458 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_X2APIC_MODE)
6459 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtX2ApicTprShadow);
6460 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_APIC_REG_VIRT)
6461 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ApicRegVirt);
6462 Assert(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY);
6463 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtIntDelivery);
6464 }
6465 }
6466
6467 /* NMI exiting and virtual-NMIs. */
6468 if ( (pVmcs->u32PinCtls & VMX_PIN_CTLS_NMI_EXIT)
6469 || !(pVmcs->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI))
6470 { /* likely */ }
6471 else
6472 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtNmi);
6473
6474 /* Virtual-NMIs and NMI-window exiting. */
6475 if ( (pVmcs->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
6476 || !(pVmcs->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
6477 { /* likely */ }
6478 else
6479 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_NmiWindowExit);
6480
6481 /* Virtualize APIC accesses. */
6482 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
6483 {
6484 /* APIC-access physical address. */
6485 RTGCPHYS const GCPhysApicAccess = pVmcs->u64AddrApicAccess.u;
6486 if ( !(GCPhysApicAccess & X86_PAGE_4K_OFFSET_MASK)
6487 && !(GCPhysApicAccess >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6488 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysApicAccess))
6489 { /* likely */ }
6490 else
6491 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrApicAccess);
6492
6493 /*
6494 * Disallow APIC-access page and virtual-APIC page from being the same address.
6495 * Note! This is not an Intel requirement, but one imposed by our implementation.
6496 */
6497 /** @todo r=ramshankar: This is done primarily to simplify recursion scenarios while
6498 * redirecting accesses between the APIC-access page and the virtual-APIC
6499 * page. If any nested hypervisor requires this, we can implement it later. */
6500 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
6501 {
6502 RTGCPHYS const GCPhysVirtApic = pVmcs->u64AddrVirtApic.u;
6503 if (GCPhysVirtApic != GCPhysApicAccess)
6504 { /* likely */ }
6505 else
6506 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrApicAccessEqVirtApic);
6507 }
6508 }
6509
6510 /* Virtualize-x2APIC mode is mutually exclusive with virtualize-APIC accesses. */
6511 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_X2APIC_MODE)
6512 || !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS))
6513 { /* likely */ }
6514 else
6515 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtX2ApicVirtApic);
6516
6517 /* Virtual-interrupt delivery requires external interrupt exiting. */
6518 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY)
6519 || (pVmcs->u32PinCtls & VMX_PIN_CTLS_EXT_INT_EXIT))
6520 { /* likely */ }
6521 else
6522 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtX2ApicVirtApic);
6523
6524 /* VPID. */
6525 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VPID)
6526 || pVmcs->u16Vpid != 0)
6527 { /* likely */ }
6528 else
6529 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_Vpid);
6530
6531#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
6532 /* Extended-Page-Table Pointer (EPTP). */
6533 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT)
6534 {
6535 VMXVDIAG enmVmxDiag;
6536 int const rc = iemVmxVmentryCheckEptPtr(pVCpu, pVmcs->u64EptPtr.u, &enmVmxDiag);
6537 if (RT_SUCCESS(rc))
6538 { /* likely */ }
6539 else
6540 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmVmxDiag);
6541 }
6542#else
6543 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT));
6544 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST));
6545#endif
6546 Assert(!(pVmcs->u32PinCtls & VMX_PIN_CTLS_POSTED_INT)); /* We don't support posted interrupts yet. */
6547 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_PML)); /* We don't support PML yet. */
6548 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VMFUNC)); /* We don't support VM functions yet. */
6549 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT_XCPT_VE)); /* We don't support EPT-violation #VE yet. */
6550 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)); /* We don't support Pause-loop exiting yet. */
6551 Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_TSC_SCALING)); /* We don't support TSC-scaling yet. */
6552
6553 /* VMCS shadowing. */
6554 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
6555 {
6556 /* VMREAD-bitmap physical address. */
6557 RTGCPHYS const GCPhysVmreadBitmap = pVmcs->u64AddrVmreadBitmap.u;
6558 if ( !(GCPhysVmreadBitmap & X86_PAGE_4K_OFFSET_MASK)
6559 && !(GCPhysVmreadBitmap >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6560 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysVmreadBitmap))
6561 { /* likely */ }
6562 else
6563 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrVmreadBitmap);
6564
6565 /* VMWRITE-bitmap physical address. */
6566 RTGCPHYS const GCPhysVmwriteBitmap = pVmcs->u64AddrVmreadBitmap.u;
6567 if ( !(GCPhysVmwriteBitmap & X86_PAGE_4K_OFFSET_MASK)
6568 && !(GCPhysVmwriteBitmap >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6569 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysVmwriteBitmap))
6570 { /* likely */ }
6571 else
6572 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrVmwriteBitmap);
6573 }
6574 }
6575
6576 /*
6577 * VM-exit controls.
6578 * See Intel spec. 26.2.1.2 "VM-Exit Control Fields".
6579 */
6580 {
6581 VMXCTLSMSR const ExitCtls = fVmxTrueMsrs ? pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.TrueExitCtls
6582 : pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.ExitCtls;
6583 if (!(~pVmcs->u32ExitCtls & ExitCtls.n.allowed0))
6584 { /* likely */ }
6585 else
6586 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ExitCtlsDisallowed0);
6587
6588 if (!(pVmcs->u32ExitCtls & ~ExitCtls.n.allowed1))
6589 { /* likely */ }
6590 else
6591 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_ExitCtlsAllowed1);
6592
6593 /* Save preemption timer without activating it. */
6594 if ( (pVmcs->u32PinCtls & VMX_PIN_CTLS_PREEMPT_TIMER)
6595 || !(pVmcs->u32ProcCtls & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER))
6596 { /* likely */ }
6597 else
6598 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_SavePreemptTimer);
6599
6600 /* VM-exit MSR-store count and VM-exit MSR-store area address. */
6601 if (pVmcs->u32ExitMsrStoreCount)
6602 {
6603 if ( !(pVmcs->u64AddrExitMsrStore.u & VMX_AUTOMSR_OFFSET_MASK)
6604 && !(pVmcs->u64AddrExitMsrStore.u >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6605 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), pVmcs->u64AddrExitMsrStore.u))
6606 { /* likely */ }
6607 else
6608 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrExitMsrStore);
6609 }
6610
6611 /* VM-exit MSR-load count and VM-exit MSR-load area address. */
6612 if (pVmcs->u32ExitMsrLoadCount)
6613 {
6614 if ( !(pVmcs->u64AddrExitMsrLoad.u & VMX_AUTOMSR_OFFSET_MASK)
6615 && !(pVmcs->u64AddrExitMsrLoad.u >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6616 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), pVmcs->u64AddrExitMsrLoad.u))
6617 { /* likely */ }
6618 else
6619 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrExitMsrLoad);
6620 }
6621 }
6622
6623 /*
6624 * VM-entry controls.
6625 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
6626 */
6627 {
6628 VMXCTLSMSR const EntryCtls = fVmxTrueMsrs ? pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.TrueEntryCtls
6629 : pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.EntryCtls;
6630 if (!(~pVmcs->u32EntryCtls & EntryCtls.n.allowed0))
6631 { /* likely */ }
6632 else
6633 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryCtlsDisallowed0);
6634
6635 if (!(pVmcs->u32EntryCtls & ~EntryCtls.n.allowed1))
6636 { /* likely */ }
6637 else
6638 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryCtlsAllowed1);
6639
6640 /* Event injection. */
6641 uint32_t const uIntInfo = pVmcs->u32EntryIntInfo;
6642 if (RT_BF_GET(uIntInfo, VMX_BF_ENTRY_INT_INFO_VALID))
6643 {
6644 /* Type and vector. */
6645 uint8_t const uType = RT_BF_GET(uIntInfo, VMX_BF_ENTRY_INT_INFO_TYPE);
6646 uint8_t const uVector = RT_BF_GET(uIntInfo, VMX_BF_ENTRY_INT_INFO_VECTOR);
6647 uint8_t const uRsvd = RT_BF_GET(uIntInfo, VMX_BF_ENTRY_INT_INFO_RSVD_12_30);
6648 if ( !uRsvd
6649 && VMXIsEntryIntInfoTypeValid(IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxMonitorTrapFlag, uType)
6650 && VMXIsEntryIntInfoVectorValid(uVector, uType))
6651 { /* likely */ }
6652 else
6653 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryIntInfoTypeVecRsvd);
6654
6655 /* Exception error code. */
6656 if (RT_BF_GET(uIntInfo, VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID))
6657 {
6658 /* Delivery possible only in Unrestricted-guest mode when CR0.PE is set. */
6659 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST)
6660 || (pVmcs->u64GuestCr0.s.Lo & X86_CR0_PE))
6661 { /* likely */ }
6662 else
6663 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryIntInfoErrCodePe);
6664
6665 /* Exceptions that provide an error code. */
6666 if ( uType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
6667 && ( uVector == X86_XCPT_DF
6668 || uVector == X86_XCPT_TS
6669 || uVector == X86_XCPT_NP
6670 || uVector == X86_XCPT_SS
6671 || uVector == X86_XCPT_GP
6672 || uVector == X86_XCPT_PF
6673 || uVector == X86_XCPT_AC))
6674 { /* likely */ }
6675 else
6676 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryIntInfoErrCodeVec);
6677
6678 /* Exception error-code reserved bits. */
6679 if (!(pVmcs->u32EntryXcptErrCode & ~VMX_ENTRY_INT_XCPT_ERR_CODE_VALID_MASK))
6680 { /* likely */ }
6681 else
6682 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryXcptErrCodeRsvd);
6683
6684 /* Injecting a software interrupt, software exception or privileged software exception. */
6685 if ( uType == VMX_ENTRY_INT_INFO_TYPE_SW_INT
6686 || uType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT
6687 || uType == VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT)
6688 {
6689 /* Instruction length must be in the range 0-15. */
6690 if (pVmcs->u32EntryInstrLen <= VMX_ENTRY_INSTR_LEN_MAX)
6691 { /* likely */ }
6692 else
6693 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryInstrLen);
6694
6695 /* However, instruction length of 0 is allowed only when its CPU feature is present. */
6696 if ( pVmcs->u32EntryInstrLen != 0
6697 || IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxEntryInjectSoftInt)
6698 { /* likely */ }
6699 else
6700 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EntryInstrLenZero);
6701 }
6702 }
6703 }
6704
6705 /* VM-entry MSR-load count and VM-entry MSR-load area address. */
6706 if (pVmcs->u32EntryMsrLoadCount)
6707 {
6708 if ( !(pVmcs->u64AddrEntryMsrLoad.u & VMX_AUTOMSR_OFFSET_MASK)
6709 && !(pVmcs->u64AddrEntryMsrLoad.u >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth)
6710 && PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), pVmcs->u64AddrEntryMsrLoad.u))
6711 { /* likely */ }
6712 else
6713 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrEntryMsrLoad);
6714 }
6715
6716 Assert(!(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)); /* We don't support SMM yet. */
6717 Assert(!(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON)); /* We don't support dual-monitor treatment yet. */
6718 }
6719
6720 NOREF(pszInstr);
6721 NOREF(pszFailure);
6722 return VINF_SUCCESS;
6723}
6724
6725
6726/**
6727 * Loads the guest control registers, debug register and some MSRs as part of
6728 * VM-entry.
6729 *
6730 * @param pVCpu The cross context virtual CPU structure.
6731 */
6732static void iemVmxVmentryLoadGuestControlRegsMsrs(PVMCPUCC pVCpu) RT_NOEXCEPT
6733{
6734 /*
6735 * Load guest control registers, debug registers and MSRs.
6736 * See Intel spec. 26.3.2.1 "Loading Guest Control Registers, Debug Registers and MSRs".
6737 */
6738 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
6739
6740 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
6741 uint64_t const uGstCr0 = (pVmcs->u64GuestCr0.u & ~VMX_ENTRY_GUEST_CR0_IGNORE_MASK)
6742 | (pVCpu->cpum.GstCtx.cr0 & VMX_ENTRY_GUEST_CR0_IGNORE_MASK);
6743 pVCpu->cpum.GstCtx.cr0 = uGstCr0;
6744 pVCpu->cpum.GstCtx.cr4 = pVmcs->u64GuestCr4.u;
6745 pVCpu->cpum.GstCtx.cr3 = pVmcs->u64GuestCr3.u;
6746
6747 if (pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
6748 pVCpu->cpum.GstCtx.dr[7] = (pVmcs->u64GuestDr7.u & ~VMX_ENTRY_GUEST_DR7_MBZ_MASK) | VMX_ENTRY_GUEST_DR7_MB1_MASK;
6749
6750 pVCpu->cpum.GstCtx.SysEnter.eip = pVmcs->u64GuestSysenterEip.s.Lo;
6751 pVCpu->cpum.GstCtx.SysEnter.esp = pVmcs->u64GuestSysenterEsp.s.Lo;
6752 pVCpu->cpum.GstCtx.SysEnter.cs = pVmcs->u32GuestSysenterCS;
6753
6754 if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fLongMode)
6755 {
6756 /* FS base and GS base are loaded while loading the rest of the guest segment registers. */
6757
6758 /* EFER MSR. */
6759 if (!(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR))
6760 {
6761 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
6762 uint64_t const uHostEfer = pVCpu->cpum.GstCtx.msrEFER;
6763 bool const fGstInLongMode = RT_BOOL(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
6764 bool const fGstPaging = RT_BOOL(uGstCr0 & X86_CR0_PG);
6765 if (fGstInLongMode)
6766 {
6767 /* If the nested-guest is in long mode, LMA and LME are both set. */
6768 Assert(fGstPaging);
6769 pVCpu->cpum.GstCtx.msrEFER = uHostEfer | (MSR_K6_EFER_LMA | MSR_K6_EFER_LME);
6770 }
6771 else
6772 {
6773 /*
6774 * If the nested-guest is outside long mode:
6775 * - With paging: LMA is cleared, LME is cleared.
6776 * - Without paging: LMA is cleared, LME is left unmodified.
6777 */
6778 uint64_t const fLmaLmeMask = MSR_K6_EFER_LMA | (fGstPaging ? MSR_K6_EFER_LME : 0);
6779 pVCpu->cpum.GstCtx.msrEFER = uHostEfer & ~fLmaLmeMask;
6780 }
6781 }
6782 /* else: see below. */
6783 }
6784
6785 /* PAT MSR. */
6786 if (pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
6787 pVCpu->cpum.GstCtx.msrPAT = pVmcs->u64GuestPatMsr.u;
6788
6789 /* EFER MSR. */
6790 if (pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
6791 pVCpu->cpum.GstCtx.msrEFER = pVmcs->u64GuestEferMsr.u;
6792
6793 /* We don't support IA32_PERF_GLOBAL_CTRL MSR yet. */
6794 Assert(!(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR));
6795
6796 /* We don't support IA32_BNDCFGS MSR yet. */
6797 Assert(!(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_BNDCFGS_MSR));
6798
6799 /* Nothing to do for SMBASE register - We don't support SMM yet. */
6800}
6801
6802
6803/**
6804 * Loads the guest segment registers, GDTR, IDTR, LDTR and TR as part of VM-entry.
6805 *
6806 * @param pVCpu The cross context virtual CPU structure.
6807 */
6808static void iemVmxVmentryLoadGuestSegRegs(PVMCPUCC pVCpu) RT_NOEXCEPT
6809{
6810 /*
6811 * Load guest segment registers, GDTR, IDTR, LDTR and TR.
6812 * See Intel spec. 26.3.2.2 "Loading Guest Segment Registers and Descriptor-Table Registers".
6813 */
6814 /* CS, SS, ES, DS, FS, GS. */
6815 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
6816 for (unsigned iSegReg = 0; iSegReg < X86_SREG_COUNT; iSegReg++)
6817 {
6818 PCPUMSELREG pGstSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
6819 CPUMSELREG VmcsSelReg;
6820 int rc = iemVmxVmcsGetGuestSegReg(pVmcs, iSegReg, &VmcsSelReg);
6821 AssertRC(rc); NOREF(rc);
6822 if (!(VmcsSelReg.Attr.u & X86DESCATTR_UNUSABLE))
6823 {
6824 pGstSelReg->Sel = VmcsSelReg.Sel;
6825 pGstSelReg->ValidSel = VmcsSelReg.Sel;
6826 pGstSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
6827 pGstSelReg->u64Base = VmcsSelReg.u64Base;
6828 pGstSelReg->u32Limit = VmcsSelReg.u32Limit;
6829 pGstSelReg->Attr.u = VmcsSelReg.Attr.u;
6830 }
6831 else
6832 {
6833 pGstSelReg->Sel = VmcsSelReg.Sel;
6834 pGstSelReg->ValidSel = VmcsSelReg.Sel;
6835 pGstSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
6836 switch (iSegReg)
6837 {
6838 case X86_SREG_CS:
6839 pGstSelReg->u64Base = VmcsSelReg.u64Base;
6840 pGstSelReg->u32Limit = VmcsSelReg.u32Limit;
6841 pGstSelReg->Attr.u = VmcsSelReg.Attr.u;
6842 break;
6843
6844 case X86_SREG_SS:
6845 pGstSelReg->u64Base = VmcsSelReg.u64Base & UINT32_C(0xfffffff0);
6846 pGstSelReg->u32Limit = 0;
6847 pGstSelReg->Attr.u = (VmcsSelReg.Attr.u & X86DESCATTR_DPL) | X86DESCATTR_D | X86DESCATTR_UNUSABLE;
6848 break;
6849
6850 case X86_SREG_ES:
6851 case X86_SREG_DS:
6852 pGstSelReg->u64Base = 0;
6853 pGstSelReg->u32Limit = 0;
6854 pGstSelReg->Attr.u = X86DESCATTR_UNUSABLE;
6855 break;
6856
6857 case X86_SREG_FS:
6858 case X86_SREG_GS:
6859 pGstSelReg->u64Base = VmcsSelReg.u64Base;
6860 pGstSelReg->u32Limit = 0;
6861 pGstSelReg->Attr.u = X86DESCATTR_UNUSABLE;
6862 break;
6863 }
6864 Assert(pGstSelReg->Attr.n.u1Unusable);
6865 }
6866 }
6867
6868 /* LDTR. */
6869 pVCpu->cpum.GstCtx.ldtr.Sel = pVmcs->GuestLdtr;
6870 pVCpu->cpum.GstCtx.ldtr.ValidSel = pVmcs->GuestLdtr;
6871 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
6872 if (!(pVmcs->u32GuestLdtrAttr & X86DESCATTR_UNUSABLE))
6873 {
6874 pVCpu->cpum.GstCtx.ldtr.u64Base = pVmcs->u64GuestLdtrBase.u;
6875 pVCpu->cpum.GstCtx.ldtr.u32Limit = pVmcs->u32GuestLdtrLimit;
6876 pVCpu->cpum.GstCtx.ldtr.Attr.u = pVmcs->u32GuestLdtrAttr;
6877 }
6878 else
6879 {
6880 pVCpu->cpum.GstCtx.ldtr.u64Base = 0;
6881 pVCpu->cpum.GstCtx.ldtr.u32Limit = 0;
6882 pVCpu->cpum.GstCtx.ldtr.Attr.u = X86DESCATTR_UNUSABLE;
6883 }
6884
6885 /* TR. */
6886 Assert(!(pVmcs->u32GuestTrAttr & X86DESCATTR_UNUSABLE));
6887 pVCpu->cpum.GstCtx.tr.Sel = pVmcs->GuestTr;
6888 pVCpu->cpum.GstCtx.tr.ValidSel = pVmcs->GuestTr;
6889 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
6890 pVCpu->cpum.GstCtx.tr.u64Base = pVmcs->u64GuestTrBase.u;
6891 pVCpu->cpum.GstCtx.tr.u32Limit = pVmcs->u32GuestTrLimit;
6892 pVCpu->cpum.GstCtx.tr.Attr.u = pVmcs->u32GuestTrAttr;
6893
6894 /* GDTR. */
6895 pVCpu->cpum.GstCtx.gdtr.cbGdt = pVmcs->u32GuestGdtrLimit;
6896 pVCpu->cpum.GstCtx.gdtr.pGdt = pVmcs->u64GuestGdtrBase.u;
6897
6898 /* IDTR. */
6899 pVCpu->cpum.GstCtx.idtr.cbIdt = pVmcs->u32GuestIdtrLimit;
6900 pVCpu->cpum.GstCtx.idtr.pIdt = pVmcs->u64GuestIdtrBase.u;
6901}
6902
6903
6904/**
6905 * Loads the guest MSRs from the VM-entry MSR-load area as part of VM-entry.
6906 *
6907 * @returns VBox status code.
6908 * @param pVCpu The cross context virtual CPU structure.
6909 * @param pszInstr The VMX instruction name (for logging purposes).
6910 */
6911static int iemVmxVmentryLoadGuestAutoMsrs(PVMCPUCC pVCpu, const char *pszInstr) RT_NOEXCEPT
6912{
6913 /*
6914 * Load guest MSRs.
6915 * See Intel spec. 26.4 "Loading MSRs".
6916 */
6917 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
6918 const char *const pszFailure = "VM-exit";
6919
6920 /*
6921 * The VM-entry MSR-load area address need not be a valid guest-physical address if the
6922 * VM-entry MSR load count is 0. If this is the case, bail early without reading it.
6923 * See Intel spec. 24.8.2 "VM-Entry Controls for MSRs".
6924 */
6925 uint32_t const cMsrs = RT_MIN(pVmcs->u32EntryMsrLoadCount, RT_ELEMENTS(pVCpu->cpum.GstCtx.hwvirt.vmx.aEntryMsrLoadArea));
6926 if (!cMsrs)
6927 return VINF_SUCCESS;
6928
6929 /*
6930 * Verify the MSR auto-load count. Physical CPUs can behave unpredictably if the count is
6931 * exceeded including possibly raising #MC exceptions during VMX transition. Our
6932 * implementation shall fail VM-entry with an VMX_EXIT_ERR_MSR_LOAD VM-exit.
6933 */
6934 bool const fIsMsrCountValid = iemVmxIsAutoMsrCountValid(pVCpu, cMsrs);
6935 if (fIsMsrCountValid)
6936 { /* likely */ }
6937 else
6938 {
6939 iemVmxVmcsSetExitQual(pVCpu, VMX_V_AUTOMSR_AREA_SIZE / sizeof(VMXAUTOMSR));
6940 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_MsrLoadCount);
6941 }
6942
6943 RTGCPHYS const GCPhysVmEntryMsrLoadArea = pVmcs->u64AddrEntryMsrLoad.u;
6944 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.aEntryMsrLoadArea[0],
6945 GCPhysVmEntryMsrLoadArea, cMsrs * sizeof(VMXAUTOMSR));
6946 if (RT_SUCCESS(rc))
6947 {
6948 PCVMXAUTOMSR pMsr = &pVCpu->cpum.GstCtx.hwvirt.vmx.aEntryMsrLoadArea[0];
6949 for (uint32_t idxMsr = 0; idxMsr < cMsrs; idxMsr++, pMsr++)
6950 {
6951 if ( !pMsr->u32Reserved
6952 && pMsr->u32Msr != MSR_K8_FS_BASE
6953 && pMsr->u32Msr != MSR_K8_GS_BASE
6954 && pMsr->u32Msr != MSR_K6_EFER
6955 && pMsr->u32Msr != MSR_IA32_SMM_MONITOR_CTL
6956 && pMsr->u32Msr >> 8 != MSR_IA32_X2APIC_START >> 8)
6957 {
6958 VBOXSTRICTRC rcStrict = CPUMSetGuestMsr(pVCpu, pMsr->u32Msr, pMsr->u64Value);
6959 if (rcStrict == VINF_SUCCESS)
6960 continue;
6961
6962 /*
6963 * If we're in ring-0, we cannot handle returns to ring-3 at this point and continue VM-entry.
6964 * If any nested hypervisor loads MSRs that require ring-3 handling, we cause a VM-entry failure
6965 * recording the MSR index in the Exit qualification (as per the Intel spec.) and indicated
6966 * further by our own, specific diagnostic code. Later, we can try implement handling of the
6967 * MSR in ring-0 if possible, or come up with a better, generic solution.
6968 */
6969 iemVmxVmcsSetExitQual(pVCpu, idxMsr);
6970 VMXVDIAG const enmDiag = rcStrict == VINF_CPUM_R3_MSR_WRITE
6971 ? kVmxVDiag_Vmentry_MsrLoadRing3
6972 : kVmxVDiag_Vmentry_MsrLoad;
6973 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
6974 }
6975 else
6976 {
6977 iemVmxVmcsSetExitQual(pVCpu, idxMsr);
6978 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_MsrLoadRsvd);
6979 }
6980 }
6981 }
6982 else
6983 {
6984 AssertMsgFailed(("%s: Failed to read MSR auto-load area at %#RGp, rc=%Rrc\n", pszInstr, GCPhysVmEntryMsrLoadArea, rc));
6985 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_MsrLoadPtrReadPhys);
6986 }
6987
6988 NOREF(pszInstr);
6989 NOREF(pszFailure);
6990 return VINF_SUCCESS;
6991}
6992
6993
6994/**
6995 * Loads the guest-state non-register state as part of VM-entry.
6996 *
6997 * @returns VBox status code.
6998 * @param pVCpu The cross context virtual CPU structure.
6999 * @param pszInstr The VMX instruction name (for logging purposes).
7000 *
7001 * @remarks This must be called only after loading the nested-guest register state
7002 * (especially nested-guest RIP).
7003 */
7004static int iemVmxVmentryLoadGuestNonRegState(PVMCPUCC pVCpu, const char *pszInstr) RT_NOEXCEPT
7005{
7006 /*
7007 * Load guest non-register state.
7008 * See Intel spec. 26.6 "Special Features of VM Entry"
7009 */
7010 const char *const pszFailure = "VM-exit";
7011 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7012
7013 /*
7014 * If VM-entry is not vectoring, block-by-STI and block-by-MovSS state must be loaded.
7015 * If VM-entry is vectoring, there is no block-by-STI or block-by-MovSS.
7016 *
7017 * See Intel spec. 26.6.1 "Interruptibility State".
7018 */
7019 bool const fEntryVectoring = VMXIsVmentryVectoring(pVmcs->u32EntryIntInfo, NULL /* puEntryIntInfoType */);
7020 if ( !fEntryVectoring
7021 && (pVmcs->u32GuestIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)))
7022 CPUMSetInInterruptShadowEx(&pVCpu->cpum.GstCtx, pVmcs->u64GuestRip.u);
7023 else
7024 Assert(!CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx));
7025
7026 /* NMI blocking. */
7027 if (pVmcs->u32GuestIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI)
7028 {
7029 if (pVmcs->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
7030 pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtNmiBlocking = true;
7031 else
7032 {
7033 pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtNmiBlocking = false;
7034 CPUMSetInterruptInhibitingByNmi(&pVCpu->cpum.GstCtx);
7035 }
7036 }
7037 else
7038 pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtNmiBlocking = false;
7039
7040 /* SMI blocking is irrelevant. We don't support SMIs yet. */
7041
7042 /*
7043 * Set PGM's copy of the EPT pointer.
7044 * The EPTP has already been validated while checking guest state.
7045 *
7046 * It is important to do this prior to mapping PAE PDPTEs (below).
7047 */
7048 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT)
7049 PGMSetGuestEptPtr(pVCpu, pVmcs->u64EptPtr.u);
7050
7051 /*
7052 * Load the guest's PAE PDPTEs.
7053 */
7054 if (!iemVmxVmcsIsGuestPaePagingEnabled(pVmcs))
7055 {
7056 /*
7057 * When PAE paging is not used we clear the PAE PDPTEs for safety
7058 * in case we might be switching from a PAE host to a non-PAE guest.
7059 */
7060 pVCpu->cpum.GstCtx.aPaePdpes[0].u = 0;
7061 pVCpu->cpum.GstCtx.aPaePdpes[1].u = 0;
7062 pVCpu->cpum.GstCtx.aPaePdpes[2].u = 0;
7063 pVCpu->cpum.GstCtx.aPaePdpes[3].u = 0;
7064 }
7065 else if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT)
7066 {
7067 /*
7068 * With EPT and the nested-guest using PAE paging, we've already validated the PAE PDPTEs
7069 * while checking the guest state. We can load them into the nested-guest CPU state now.
7070 * They'll later be used while mapping CR3 and the PAE PDPTEs.
7071 */
7072 pVCpu->cpum.GstCtx.aPaePdpes[0].u = pVmcs->u64GuestPdpte0.u;
7073 pVCpu->cpum.GstCtx.aPaePdpes[1].u = pVmcs->u64GuestPdpte1.u;
7074 pVCpu->cpum.GstCtx.aPaePdpes[2].u = pVmcs->u64GuestPdpte2.u;
7075 pVCpu->cpum.GstCtx.aPaePdpes[3].u = pVmcs->u64GuestPdpte3.u;
7076 }
7077 else
7078 {
7079 /*
7080 * Without EPT and the nested-guest using PAE paging, we must load the PAE PDPTEs
7081 * referenced by CR3. This involves loading (and mapping) CR3 and validating them now.
7082 */
7083 int const rc = PGMGstMapPaePdpesAtCr3(pVCpu, pVmcs->u64GuestCr3.u);
7084 if (RT_SUCCESS(rc))
7085 { /* likely */ }
7086 else
7087 {
7088 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_PDPTE);
7089 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPdpte);
7090 }
7091 }
7092
7093 /* VPID is irrelevant. We don't support VPID yet. */
7094
7095 /* Clear address-range monitoring. */
7096 EMMonitorWaitClear(pVCpu);
7097
7098 return VINF_SUCCESS;
7099}
7100
7101
7102/**
7103 * Loads the guest VMCS referenced state (such as MSR bitmaps, I/O bitmaps etc).
7104 *
7105 * @param pVCpu The cross context virtual CPU structure.
7106 * @param pszInstr The VMX instruction name (for logging purposes).
7107 *
7108 * @remarks This assumes various VMCS related data structure pointers have already
7109 * been verified prior to calling this function.
7110 */
7111static int iemVmxVmentryLoadGuestVmcsRefState(PVMCPUCC pVCpu, const char *pszInstr) RT_NOEXCEPT
7112{
7113 const char *const pszFailure = "VM-exit";
7114 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7115
7116 /*
7117 * Virtualize APIC accesses.
7118 */
7119 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
7120 {
7121 /* APIC-access physical address. */
7122 RTGCPHYS const GCPhysApicAccess = pVmcs->u64AddrApicAccess.u;
7123
7124 /*
7125 * Register the handler for the APIC-access page.
7126 *
7127 * We don't deregister the APIC-access page handler during the VM-exit as a different
7128 * nested-VCPU might be using the same guest-physical address for its APIC-access page.
7129 *
7130 * We leave the page registered until the first access that happens outside VMX non-root
7131 * mode. Guest software is allowed to access structures such as the APIC-access page
7132 * only when no logical processor with a current VMCS references it in VMX non-root mode,
7133 * otherwise it can lead to unpredictable behavior including guest triple-faults.
7134 *
7135 * See Intel spec. 24.11.4 "Software Access to Related Structures".
7136 */
7137 if (!PGMHandlerPhysicalIsRegistered(pVCpu->CTX_SUFF(pVM), GCPhysApicAccess))
7138 {
7139 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7140 int rc = PGMHandlerPhysicalRegister(pVM, GCPhysApicAccess, GCPhysApicAccess | X86_PAGE_4K_OFFSET_MASK,
7141 pVM->iem.s.hVmxApicAccessPage, 0 /*uUser*/, NULL /*pszDesc*/);
7142 if (RT_SUCCESS(rc))
7143 { /* likely */ }
7144 else
7145 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrApicAccessHandlerReg);
7146 }
7147 }
7148
7149 /*
7150 * VMCS shadowing.
7151 */
7152 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
7153 {
7154 /* Read the VMREAD-bitmap. */
7155 RTGCPHYS const GCPhysVmreadBitmap = pVmcs->u64AddrVmreadBitmap.u;
7156 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.abVmreadBitmap[0],
7157 GCPhysVmreadBitmap, sizeof(pVCpu->cpum.GstCtx.hwvirt.vmx.abVmreadBitmap));
7158 if (RT_SUCCESS(rc))
7159 { /* likely */ }
7160 else
7161 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VmreadBitmapPtrReadPhys);
7162
7163 /* Read the VMWRITE-bitmap. */
7164 RTGCPHYS const GCPhysVmwriteBitmap = pVmcs->u64AddrVmwriteBitmap.u;
7165 rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.abVmwriteBitmap[0],
7166 GCPhysVmwriteBitmap, sizeof(pVCpu->cpum.GstCtx.hwvirt.vmx.abVmwriteBitmap));
7167 if (RT_SUCCESS(rc))
7168 { /* likely */ }
7169 else
7170 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VmwriteBitmapPtrReadPhys);
7171 }
7172
7173 /*
7174 * I/O bitmaps.
7175 */
7176 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_IO_BITMAPS)
7177 {
7178 /* Read the IO bitmap A. */
7179 RTGCPHYS const GCPhysIoBitmapA = pVmcs->u64AddrIoBitmapA.u;
7180 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.abIoBitmap[0],
7181 GCPhysIoBitmapA, VMX_V_IO_BITMAP_A_SIZE);
7182 if (RT_SUCCESS(rc))
7183 { /* likely */ }
7184 else
7185 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_IoBitmapAPtrReadPhys);
7186
7187 /* Read the IO bitmap B. */
7188 RTGCPHYS const GCPhysIoBitmapB = pVmcs->u64AddrIoBitmapB.u;
7189 rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.abIoBitmap[VMX_V_IO_BITMAP_A_SIZE],
7190 GCPhysIoBitmapB, VMX_V_IO_BITMAP_B_SIZE);
7191 if (RT_SUCCESS(rc))
7192 { /* likely */ }
7193 else
7194 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_IoBitmapBPtrReadPhys);
7195 }
7196
7197 /*
7198 * TPR shadow and Virtual-APIC page.
7199 */
7200 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
7201 {
7202 /* Verify TPR threshold and VTPR when both virtualize-APIC accesses and virtual-interrupt delivery aren't used. */
7203 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
7204 && !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY))
7205 {
7206 /* Read the VTPR from the virtual-APIC page. */
7207 RTGCPHYS const GCPhysVirtApic = pVmcs->u64AddrVirtApic.u;
7208 uint8_t u8VTpr;
7209 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &u8VTpr, GCPhysVirtApic + XAPIC_OFF_TPR, sizeof(u8VTpr));
7210 if (RT_SUCCESS(rc))
7211 { /* likely */ }
7212 else
7213 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtApicPagePtrReadPhys);
7214
7215 /* Bits 3:0 of the TPR-threshold must not be greater than bits 7:4 of VTPR. */
7216 if ((uint8_t)RT_BF_GET(pVmcs->u32TprThreshold, VMX_BF_TPR_THRESHOLD_TPR) <= (u8VTpr & 0xf0))
7217 { /* likely */ }
7218 else
7219 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_TprThresholdVTpr);
7220 }
7221 }
7222
7223 /*
7224 * VMCS link pointer.
7225 */
7226 if (pVmcs->u64VmcsLinkPtr.u != UINT64_C(0xffffffffffffffff))
7227 {
7228 /* Read the VMCS-link pointer from guest memory. */
7229 RTGCPHYS const GCPhysShadowVmcs = pVmcs->u64VmcsLinkPtr.u;
7230 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.ShadowVmcs,
7231 GCPhysShadowVmcs, sizeof(pVCpu->cpum.GstCtx.hwvirt.vmx.ShadowVmcs));
7232 if (RT_SUCCESS(rc))
7233 { /* likely */ }
7234 else
7235 {
7236 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_VMCS_LINK_PTR);
7237 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VmcsLinkPtrReadPhys);
7238 }
7239
7240 /* Verify the VMCS revision specified by the guest matches what we reported to the guest. */
7241 if (pVCpu->cpum.GstCtx.hwvirt.vmx.ShadowVmcs.u32VmcsRevId.n.u31RevisionId == VMX_V_VMCS_REVISION_ID)
7242 { /* likely */ }
7243 else
7244 {
7245 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_VMCS_LINK_PTR);
7246 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VmcsLinkPtrRevId);
7247 }
7248
7249 /* Verify the shadow bit is set if VMCS shadowing is enabled . */
7250 if ( !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
7251 || pVCpu->cpum.GstCtx.hwvirt.vmx.ShadowVmcs.u32VmcsRevId.n.fIsShadowVmcs)
7252 { /* likely */ }
7253 else
7254 {
7255 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_VMCS_LINK_PTR);
7256 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VmcsLinkPtrShadow);
7257 }
7258
7259 /* Update our cache of the guest physical address of the shadow VMCS. */
7260 pVCpu->cpum.GstCtx.hwvirt.vmx.GCPhysShadowVmcs = GCPhysShadowVmcs;
7261 }
7262
7263 /*
7264 * MSR bitmap.
7265 */
7266 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
7267 {
7268 /* Read the MSR bitmap. */
7269 RTGCPHYS const GCPhysMsrBitmap = pVmcs->u64AddrMsrBitmap.u;
7270 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap[0],
7271 GCPhysMsrBitmap, sizeof(pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap));
7272 if (RT_SUCCESS(rc))
7273 { /* likely */ }
7274 else
7275 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_MsrBitmapPtrReadPhys);
7276 }
7277
7278 NOREF(pszFailure);
7279 NOREF(pszInstr);
7280 return VINF_SUCCESS;
7281}
7282
7283
7284/**
7285 * Loads the guest-state as part of VM-entry.
7286 *
7287 * @returns VBox status code.
7288 * @param pVCpu The cross context virtual CPU structure.
7289 * @param pszInstr The VMX instruction name (for logging purposes).
7290 *
7291 * @remarks This must be done after all the necessary steps prior to loading of
7292 * guest-state (e.g. checking various VMCS state).
7293 */
7294static int iemVmxVmentryLoadGuestState(PVMCPUCC pVCpu, const char *pszInstr) RT_NOEXCEPT
7295{
7296 /* Load guest control registers, MSRs (that are directly part of the VMCS). */
7297 iemVmxVmentryLoadGuestControlRegsMsrs(pVCpu);
7298
7299 /* Load guest segment registers. */
7300 iemVmxVmentryLoadGuestSegRegs(pVCpu);
7301
7302 /*
7303 * Load guest RIP, RSP and RFLAGS.
7304 * See Intel spec. 26.3.2.3 "Loading Guest RIP, RSP and RFLAGS".
7305 */
7306 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7307 pVCpu->cpum.GstCtx.rsp = pVmcs->u64GuestRsp.u;
7308 pVCpu->cpum.GstCtx.rip = pVmcs->u64GuestRip.u;
7309 pVCpu->cpum.GstCtx.rflags.u = pVmcs->u64GuestRFlags.u;
7310
7311 /* Initialize the PAUSE-loop controls as part of VM-entry. */
7312 pVCpu->cpum.GstCtx.hwvirt.vmx.uFirstPauseLoopTick = 0;
7313 pVCpu->cpum.GstCtx.hwvirt.vmx.uPrevPauseTick = 0;
7314
7315 /* Load guest non-register state (such as interrupt shadows, NMI blocking etc). */
7316 int rc = iemVmxVmentryLoadGuestNonRegState(pVCpu, pszInstr);
7317 if (rc == VINF_SUCCESS)
7318 { /* likely */ }
7319 else
7320 return rc;
7321
7322 /* Load VMX related structures and state referenced by the VMCS. */
7323 rc = iemVmxVmentryLoadGuestVmcsRefState(pVCpu, pszInstr);
7324 if (rc == VINF_SUCCESS)
7325 { /* likely */ }
7326 else
7327 return rc;
7328
7329 NOREF(pszInstr);
7330 return VINF_SUCCESS;
7331}
7332
7333
7334/**
7335 * Returns whether there are is a pending debug exception on VM-entry.
7336 *
7337 * @param pVCpu The cross context virtual CPU structure.
7338 * @param pszInstr The VMX instruction name (for logging purposes).
7339 */
7340static bool iemVmxVmentryIsPendingDebugXcpt(PVMCPUCC pVCpu, const char *pszInstr) RT_NOEXCEPT
7341{
7342 /*
7343 * Pending debug exceptions.
7344 * See Intel spec. 26.6.3 "Delivery of Pending Debug Exceptions after VM Entry".
7345 */
7346 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7347 Assert(pVmcs);
7348
7349 bool fPendingDbgXcpt = RT_BOOL(pVmcs->u64GuestPendingDbgXcpts.u & ( VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS
7350 | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_EN_BP));
7351 if (fPendingDbgXcpt)
7352 {
7353 uint8_t uEntryIntInfoType;
7354 bool const fEntryVectoring = VMXIsVmentryVectoring(pVmcs->u32EntryIntInfo, &uEntryIntInfoType);
7355 if (fEntryVectoring)
7356 {
7357 switch (uEntryIntInfoType)
7358 {
7359 case VMX_ENTRY_INT_INFO_TYPE_EXT_INT:
7360 case VMX_ENTRY_INT_INFO_TYPE_NMI:
7361 case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT:
7362 case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT:
7363 fPendingDbgXcpt = false;
7364 break;
7365
7366 case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT:
7367 {
7368 /*
7369 * Whether the pending debug exception for software exceptions other than
7370 * #BP and #OF is delivered after injecting the exception or is discard
7371 * is CPU implementation specific. We will discard them (easier).
7372 */
7373 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(pVmcs->u32EntryIntInfo);
7374 if ( uVector != X86_XCPT_BP
7375 && uVector != X86_XCPT_OF)
7376 fPendingDbgXcpt = false;
7377 RT_FALL_THRU();
7378 }
7379 case VMX_ENTRY_INT_INFO_TYPE_SW_INT:
7380 {
7381 if (!(pVmcs->u32GuestIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
7382 fPendingDbgXcpt = false;
7383 break;
7384 }
7385 }
7386 }
7387 else
7388 {
7389 /*
7390 * When the VM-entry is not vectoring but there is blocking-by-MovSS, whether the
7391 * pending debug exception is held pending or is discarded is CPU implementation
7392 * specific. We will discard them (easier).
7393 */
7394 if (pVmcs->u32GuestIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
7395 fPendingDbgXcpt = false;
7396
7397 /* There's no pending debug exception in the shutdown or wait-for-SIPI state. */
7398 if (pVmcs->u32GuestActivityState & (VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN | VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT))
7399 fPendingDbgXcpt = false;
7400 }
7401 }
7402
7403 NOREF(pszInstr);
7404 return fPendingDbgXcpt;
7405}
7406
7407
7408/**
7409 * Set up the monitor-trap flag (MTF).
7410 *
7411 * @param pVCpu The cross context virtual CPU structure.
7412 * @param pszInstr The VMX instruction name (for logging purposes).
7413 */
7414static void iemVmxVmentrySetupMtf(PVMCPUCC pVCpu, const char *pszInstr) RT_NOEXCEPT
7415{
7416 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7417 Assert(pVmcs);
7418 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
7419 {
7420 VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_MTF);
7421 Log(("%s: Monitor-trap flag set on VM-entry\n", pszInstr));
7422 }
7423 else
7424 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF));
7425 NOREF(pszInstr);
7426}
7427
7428
7429/**
7430 * Sets up NMI-window exiting.
7431 *
7432 * @param pVCpu The cross context virtual CPU structure.
7433 * @param pszInstr The VMX instruction name (for logging purposes).
7434 */
7435static void iemVmxVmentrySetupNmiWindow(PVMCPUCC pVCpu, const char *pszInstr) RT_NOEXCEPT
7436{
7437 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7438 Assert(pVmcs);
7439 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
7440 {
7441 Assert(pVmcs->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI);
7442 VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW);
7443 Log(("%s: NMI-window set on VM-entry\n", pszInstr));
7444 }
7445 else
7446 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW));
7447 NOREF(pszInstr);
7448}
7449
7450
7451/**
7452 * Sets up interrupt-window exiting.
7453 *
7454 * @param pVCpu The cross context virtual CPU structure.
7455 * @param pszInstr The VMX instruction name (for logging purposes).
7456 */
7457static void iemVmxVmentrySetupIntWindow(PVMCPUCC pVCpu, const char *pszInstr) RT_NOEXCEPT
7458{
7459 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7460 Assert(pVmcs);
7461 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
7462 {
7463 VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW);
7464 Log(("%s: Interrupt-window set on VM-entry\n", pszInstr));
7465 }
7466 else
7467 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW));
7468 NOREF(pszInstr);
7469}
7470
7471
7472/**
7473 * Set up the VMX-preemption timer.
7474 *
7475 * @param pVCpu The cross context virtual CPU structure.
7476 * @param pszInstr The VMX instruction name (for logging purposes).
7477 */
7478static void iemVmxVmentrySetupPreemptTimer(PVMCPUCC pVCpu, const char *pszInstr) RT_NOEXCEPT
7479{
7480 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7481 Assert(pVmcs);
7482 if (pVmcs->u32PinCtls & VMX_PIN_CTLS_PREEMPT_TIMER)
7483 {
7484 /*
7485 * If the timer is 0, we must cause a VM-exit before executing the first
7486 * nested-guest instruction. So we can flag as though the timer has already
7487 * expired and we will check and cause a VM-exit at the right priority elsewhere
7488 * in the code.
7489 */
7490 uint64_t uEntryTick;
7491 uint32_t const uPreemptTimer = pVmcs->u32PreemptTimer;
7492 if (uPreemptTimer)
7493 {
7494 int rc = CPUMStartGuestVmxPremptTimer(pVCpu, uPreemptTimer, VMX_V_PREEMPT_TIMER_SHIFT, &uEntryTick);
7495 AssertRC(rc);
7496 Log(("%s: VM-entry set up VMX-preemption timer at %#RX64\n", pszInstr, uEntryTick));
7497 }
7498 else
7499 {
7500 uEntryTick = TMCpuTickGetNoCheck(pVCpu);
7501 VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER);
7502 Log(("%s: VM-entry set up VMX-preemption timer at %#RX64 to expire immediately!\n", pszInstr, uEntryTick));
7503 }
7504
7505 pVCpu->cpum.GstCtx.hwvirt.vmx.uEntryTick = uEntryTick;
7506 }
7507 else
7508 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER));
7509
7510 NOREF(pszInstr);
7511}
7512
7513
7514/**
7515 * Injects an event using TRPM given a VM-entry interruption info and related
7516 * fields.
7517 *
7518 * @param pVCpu The cross context virtual CPU structure.
7519 * @param pszInstr The VMX instruction name (for logging purposes).
7520 * @param uEntryIntInfo The VM-entry interruption info.
7521 * @param uErrCode The error code associated with the event if any.
7522 * @param cbInstr The VM-entry instruction length (for software
7523 * interrupts and software exceptions). Pass 0
7524 * otherwise.
7525 * @param GCPtrFaultAddress The guest CR2 if this is a \#PF event.
7526 */
7527static void iemVmxVmentryInjectTrpmEvent(PVMCPUCC pVCpu, const char *pszInstr, uint32_t uEntryIntInfo, uint32_t uErrCode,
7528 uint32_t cbInstr, RTGCUINTPTR GCPtrFaultAddress) RT_NOEXCEPT
7529{
7530 Assert(VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo));
7531
7532 uint8_t const uType = VMX_ENTRY_INT_INFO_TYPE(uEntryIntInfo);
7533 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(uEntryIntInfo);
7534 TRPMEVENT const enmTrpmEvent = HMVmxEventTypeToTrpmEventType(uEntryIntInfo);
7535
7536 Assert(uType != VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT);
7537
7538 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrpmEvent);
7539 AssertRC(rc);
7540 Log(("%s: Injecting: vector=%#x type=%#x (%s)\n", pszInstr, uVector, uType, VMXGetEntryIntInfoTypeDesc(uType)));
7541
7542 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(uEntryIntInfo))
7543 {
7544 TRPMSetErrorCode(pVCpu, uErrCode);
7545 Log(("%s: Injecting: err_code=%#x\n", pszInstr, uErrCode));
7546 }
7547
7548 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(uEntryIntInfo))
7549 {
7550 TRPMSetFaultAddress(pVCpu, GCPtrFaultAddress);
7551 Log(("%s: Injecting: fault_addr=%RGp\n", pszInstr, GCPtrFaultAddress));
7552 }
7553 else if ( uType == VMX_ENTRY_INT_INFO_TYPE_SW_INT
7554 || uType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT
7555 || uType == VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT)
7556 {
7557 TRPMSetInstrLength(pVCpu, cbInstr);
7558 Log(("%s: Injecting: instr_len=%u\n", pszInstr, cbInstr));
7559 }
7560
7561 if (VMX_ENTRY_INT_INFO_TYPE(uEntryIntInfo) == VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT)
7562 {
7563 TRPMSetTrapDueToIcebp(pVCpu);
7564 Log(("%s: Injecting: icebp\n", pszInstr));
7565 }
7566
7567 NOREF(pszInstr);
7568}
7569
7570
7571/**
7572 * Performs event injection (if any) as part of VM-entry.
7573 *
7574 * @param pVCpu The cross context virtual CPU structure.
7575 * @param pszInstr The VMX instruction name (for logging purposes).
7576 */
7577static void iemVmxVmentryInjectEvent(PVMCPUCC pVCpu, const char *pszInstr) RT_NOEXCEPT
7578{
7579 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7580
7581 /*
7582 * Inject events.
7583 * The event that is going to be made pending for injection is not subject to VMX intercepts,
7584 * thus we flag ignoring of intercepts. However, recursive exceptions if any during delivery
7585 * of the current event -are- subject to intercepts, hence this flag will be flipped during
7586 * the actually delivery of this event.
7587 *
7588 * See Intel spec. 26.5 "Event Injection".
7589 */
7590 uint32_t const uEntryIntInfo = pVmcs->u32EntryIntInfo;
7591 bool const fEntryIntInfoValid = VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo);
7592
7593 CPUMSetGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx, !fEntryIntInfoValid);
7594 if (fEntryIntInfoValid)
7595 {
7596 if (VMX_ENTRY_INT_INFO_TYPE(uEntryIntInfo) == VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT)
7597 {
7598 Assert(VMX_ENTRY_INT_INFO_VECTOR(uEntryIntInfo) == VMX_ENTRY_INT_INFO_VECTOR_MTF);
7599 VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_MTF);
7600 }
7601 else
7602 iemVmxVmentryInjectTrpmEvent(pVCpu, pszInstr, uEntryIntInfo, pVmcs->u32EntryXcptErrCode, pVmcs->u32EntryInstrLen,
7603 pVCpu->cpum.GstCtx.cr2);
7604
7605 /*
7606 * We need to clear the VM-entry interruption information field's valid bit on VM-exit.
7607 *
7608 * However, we do it here on VM-entry as well because while it isn't visible to guest
7609 * software until VM-exit, when and if HM looks at the VMCS to continue nested-guest
7610 * execution using hardware-assisted VMX, it will not try to inject the event again.
7611 *
7612 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
7613 */
7614 pVmcs->u32EntryIntInfo &= ~VMX_ENTRY_INT_INFO_VALID;
7615 }
7616 else
7617 {
7618 /*
7619 * Inject any pending guest debug exception.
7620 * Unlike injecting events, this #DB injection on VM-entry is subject to #DB VMX intercept.
7621 * See Intel spec. 26.6.3 "Delivery of Pending Debug Exceptions after VM Entry".
7622 */
7623 bool const fPendingDbgXcpt = iemVmxVmentryIsPendingDebugXcpt(pVCpu, pszInstr);
7624 if (fPendingDbgXcpt)
7625 {
7626 uint32_t const uDbgXcptInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
7627 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
7628 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7629 iemVmxVmentryInjectTrpmEvent(pVCpu, pszInstr, uDbgXcptInfo, 0 /* uErrCode */, pVmcs->u32EntryInstrLen,
7630 0 /* GCPtrFaultAddress */);
7631 }
7632 }
7633
7634 NOREF(pszInstr);
7635}
7636
7637
7638/**
7639 * Initializes all read-only VMCS fields as part of VM-entry.
7640 *
7641 * @param pVCpu The cross context virtual CPU structure.
7642 */
7643static void iemVmxVmentryInitReadOnlyFields(PVMCPUCC pVCpu) RT_NOEXCEPT
7644{
7645 /*
7646 * Any VMCS field which we do not establish on every VM-exit but may potentially
7647 * be used on the VM-exit path of a nested hypervisor -and- is not explicitly
7648 * specified to be undefined, needs to be initialized here.
7649 *
7650 * Thus, it is especially important to clear the Exit qualification field
7651 * since it must be zero for VM-exits where it is not used. Similarly, the
7652 * VM-exit interruption information field's valid bit needs to be cleared for
7653 * the same reasons.
7654 */
7655 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7656 Assert(pVmcs);
7657
7658 /* 16-bit (none currently). */
7659 /* 32-bit. */
7660 pVmcs->u32RoVmInstrError = 0;
7661 pVmcs->u32RoExitReason = 0;
7662 pVmcs->u32RoExitIntInfo = 0;
7663 pVmcs->u32RoExitIntErrCode = 0;
7664 pVmcs->u32RoIdtVectoringInfo = 0;
7665 pVmcs->u32RoIdtVectoringErrCode = 0;
7666 pVmcs->u32RoExitInstrLen = 0;
7667 pVmcs->u32RoExitInstrInfo = 0;
7668
7669 /* 64-bit. */
7670 pVmcs->u64RoGuestPhysAddr.u = 0;
7671
7672 /* Natural-width. */
7673 pVmcs->u64RoExitQual.u = 0;
7674 pVmcs->u64RoIoRcx.u = 0;
7675 pVmcs->u64RoIoRsi.u = 0;
7676 pVmcs->u64RoIoRdi.u = 0;
7677 pVmcs->u64RoIoRip.u = 0;
7678 pVmcs->u64RoGuestLinearAddr.u = 0;
7679}
7680
7681
7682/**
7683 * VMLAUNCH/VMRESUME instruction execution worker.
7684 *
7685 * @returns Strict VBox status code.
7686 * @param pVCpu The cross context virtual CPU structure.
7687 * @param cbInstr The instruction length in bytes.
7688 * @param uInstrId The instruction identity (VMXINSTRID_VMLAUNCH or
7689 * VMXINSTRID_VMRESUME).
7690 *
7691 * @remarks Common VMX instruction checks are already expected to by the caller,
7692 * i.e. CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
7693 */
7694static VBOXSTRICTRC iemVmxVmlaunchVmresume(PVMCPUCC pVCpu, uint8_t cbInstr, VMXINSTRID uInstrId) RT_NOEXCEPT
7695{
7696# if defined(VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM) && !defined(IN_RING3)
7697 RT_NOREF3(pVCpu, cbInstr, uInstrId);
7698 return VINF_EM_RAW_EMULATE_INSTR;
7699# else
7700 Assert( uInstrId == VMXINSTRID_VMLAUNCH
7701 || uInstrId == VMXINSTRID_VMRESUME);
7702 const char * const pszInstr = uInstrId == VMXINSTRID_VMRESUME ? "vmresume" : "vmlaunch";
7703
7704 /* Nested-guest intercept. */
7705 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
7706 return iemVmxVmexitInstr(pVCpu, uInstrId == VMXINSTRID_VMRESUME ? VMX_EXIT_VMRESUME : VMX_EXIT_VMLAUNCH, cbInstr);
7707
7708 Assert(IEM_VMX_IS_ROOT_MODE(pVCpu));
7709
7710 /*
7711 * Basic VM-entry checks.
7712 * The order of the CPL, current and shadow VMCS and block-by-MovSS are important.
7713 * The checks following that do not have to follow a specific order.
7714 *
7715 * See Intel spec. 26.1 "Basic VM-entry Checks".
7716 */
7717
7718 /* CPL. */
7719 if (pVCpu->iem.s.uCpl == 0)
7720 { /* likely */ }
7721 else
7722 {
7723 Log(("%s: CPL %u -> #GP(0)\n", pszInstr, pVCpu->iem.s.uCpl));
7724 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmentry_Cpl;
7725 return iemRaiseGeneralProtectionFault0(pVCpu);
7726 }
7727
7728 /* Current VMCS valid. */
7729 if (IEM_VMX_HAS_CURRENT_VMCS(pVCpu))
7730 { /* likely */ }
7731 else
7732 {
7733 Log(("%s: VMCS pointer %#RGp invalid -> VMFailInvalid\n", pszInstr, IEM_VMX_GET_CURRENT_VMCS(pVCpu)));
7734 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmentry_PtrInvalid;
7735 iemVmxVmFailInvalid(pVCpu);
7736 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7737 }
7738
7739 /* Current VMCS is not a shadow VMCS. */
7740 if (!pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32VmcsRevId.n.fIsShadowVmcs)
7741 { /* likely */ }
7742 else
7743 {
7744 Log(("%s: VMCS pointer %#RGp is a shadow VMCS -> VMFailInvalid\n", pszInstr, IEM_VMX_GET_CURRENT_VMCS(pVCpu)));
7745 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmentry_PtrShadowVmcs;
7746 iemVmxVmFailInvalid(pVCpu);
7747 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7748 }
7749
7750 /** @todo Distinguish block-by-MovSS from block-by-STI. Currently we
7751 * use block-by-STI here which is not quite correct. */
7752 if (!CPUMIsInInterruptShadowWithUpdate(&pVCpu->cpum.GstCtx))
7753 { /* likely */ }
7754 else
7755 {
7756 Log(("%s: VM entry with events blocked by MOV SS -> VMFail\n", pszInstr));
7757 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmentry_BlocKMovSS;
7758 iemVmxVmFail(pVCpu, VMXINSTRERR_VMENTRY_BLOCK_MOVSS);
7759 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7760 }
7761
7762 if (uInstrId == VMXINSTRID_VMLAUNCH)
7763 {
7764 /* VMLAUNCH with non-clear VMCS. */
7765 if (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.fVmcsState == VMX_V_VMCS_LAUNCH_STATE_CLEAR)
7766 { /* likely */ }
7767 else
7768 {
7769 Log(("vmlaunch: VMLAUNCH with non-clear VMCS -> VMFail\n"));
7770 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmentry_VmcsClear;
7771 iemVmxVmFail(pVCpu, VMXINSTRERR_VMLAUNCH_NON_CLEAR_VMCS);
7772 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7773 }
7774 }
7775 else
7776 {
7777 /* VMRESUME with non-launched VMCS. */
7778 if (pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.fVmcsState == VMX_V_VMCS_LAUNCH_STATE_LAUNCHED)
7779 { /* likely */ }
7780 else
7781 {
7782 Log(("vmresume: VMRESUME with non-launched VMCS -> VMFail\n"));
7783 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmentry_VmcsLaunch;
7784 iemVmxVmFail(pVCpu, VMXINSTRERR_VMRESUME_NON_LAUNCHED_VMCS);
7785 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7786 }
7787 }
7788
7789 /*
7790 * We are allowed to cache VMCS related data structures (such as I/O bitmaps, MSR bitmaps)
7791 * while entering VMX non-root mode. We do some of this while checking VM-execution
7792 * controls. The nested hypervisor should not make assumptions and cannot expect
7793 * predictable behavior if changes to these structures are made in guest memory while
7794 * executing in VMX non-root mode. As far as VirtualBox is concerned, the guest cannot
7795 * modify them anyway as we cache them in host memory.
7796 *
7797 * See Intel spec. 24.11.4 "Software Access to Related Structures".
7798 */
7799 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7800 Assert(pVmcs);
7801 Assert(IEM_VMX_HAS_CURRENT_VMCS(pVCpu));
7802
7803 int rc = iemVmxVmentryCheckCtls(pVCpu, pszInstr);
7804 if (RT_SUCCESS(rc))
7805 {
7806 rc = iemVmxVmentryCheckHostState(pVCpu, pszInstr);
7807 if (RT_SUCCESS(rc))
7808 {
7809 /*
7810 * Initialize read-only VMCS fields before VM-entry since we don't update all of them
7811 * for every VM-exit. This needs to be done before invoking a VM-exit (even those
7812 * ones that may occur during VM-entry below).
7813 */
7814 iemVmxVmentryInitReadOnlyFields(pVCpu);
7815
7816 /*
7817 * Blocking of NMIs need to be restored if VM-entry fails due to invalid-guest state.
7818 * So we save the VMCPU_FF_BLOCK_NMI force-flag here so we can restore it on
7819 * VM-exit when required.
7820 * See Intel spec. 26.7 "VM-entry Failures During or After Loading Guest State"
7821 */
7822 iemVmxVmentrySaveNmiBlockingFF(pVCpu);
7823
7824 rc = iemVmxVmentryCheckGuestState(pVCpu, pszInstr);
7825 if (RT_SUCCESS(rc))
7826 {
7827 /*
7828 * We've now entered nested-guest execution.
7829 *
7830 * It is important do this prior to loading the guest state because
7831 * as part of loading the guest state, PGM (and perhaps other components
7832 * in the future) relies on detecting whether VMX non-root mode has been
7833 * entered.
7834 */
7835 pVCpu->cpum.GstCtx.hwvirt.vmx.fInVmxNonRootMode = true;
7836
7837 rc = iemVmxVmentryLoadGuestState(pVCpu, pszInstr);
7838 if (RT_SUCCESS(rc))
7839 {
7840 rc = iemVmxVmentryLoadGuestAutoMsrs(pVCpu, pszInstr);
7841 if (RT_SUCCESS(rc))
7842 {
7843 Assert(rc != VINF_CPUM_R3_MSR_WRITE);
7844
7845 /* VMLAUNCH instruction must update the VMCS launch state. */
7846 if (uInstrId == VMXINSTRID_VMLAUNCH)
7847 pVmcs->fVmcsState = VMX_V_VMCS_LAUNCH_STATE_LAUNCHED;
7848
7849 /* Perform the VMX transition (PGM updates). */
7850 VBOXSTRICTRC rcStrict = iemVmxTransition(pVCpu);
7851 if (rcStrict == VINF_SUCCESS)
7852 { /* likely */ }
7853 else if (RT_SUCCESS(rcStrict))
7854 {
7855 Log3(("%s: iemVmxTransition returns %Rrc -> Setting passup status\n", pszInstr,
7856 VBOXSTRICTRC_VAL(rcStrict)));
7857 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
7858 }
7859 else
7860 {
7861 Log3(("%s: iemVmxTransition failed! rc=%Rrc\n", pszInstr, VBOXSTRICTRC_VAL(rcStrict)));
7862 return rcStrict;
7863 }
7864
7865 /* Paranoia. */
7866 Assert(rcStrict == VINF_SUCCESS);
7867
7868 /*
7869 * The priority of potential VM-exits during VM-entry is important.
7870 * The priorities of VM-exits and events are listed from highest
7871 * to lowest as follows:
7872 *
7873 * 1. Event injection.
7874 * 2. Trap on task-switch (T flag set in TSS).
7875 * 3. TPR below threshold / APIC-write.
7876 * 4. SMI, INIT.
7877 * 5. MTF exit.
7878 * 6. Debug-trap exceptions (EFLAGS.TF), pending debug exceptions.
7879 * 7. VMX-preemption timer.
7880 * 9. NMI-window exit.
7881 * 10. NMI injection.
7882 * 11. Interrupt-window exit.
7883 * 12. Virtual-interrupt injection.
7884 * 13. Interrupt injection.
7885 * 14. Process next instruction (fetch, decode, execute).
7886 */
7887
7888 /* Setup VMX-preemption timer. */
7889 iemVmxVmentrySetupPreemptTimer(pVCpu, pszInstr);
7890
7891 /* Setup monitor-trap flag. */
7892 iemVmxVmentrySetupMtf(pVCpu, pszInstr);
7893
7894 /* Setup NMI-window exiting. */
7895 iemVmxVmentrySetupNmiWindow(pVCpu, pszInstr);
7896
7897 /* Setup interrupt-window exiting. */
7898 iemVmxVmentrySetupIntWindow(pVCpu, pszInstr);
7899
7900 /*
7901 * Inject any event that the nested hypervisor wants to inject.
7902 * Note! We cannot immediately perform the event injection here as we may have
7903 * pending PGM operations to perform due to switching page tables and/or
7904 * mode.
7905 */
7906 iemVmxVmentryInjectEvent(pVCpu, pszInstr);
7907
7908# if defined(VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM) && defined(IN_RING3)
7909 /* Reschedule to IEM-only execution of the nested-guest. */
7910 LogFlow(("%s: Enabling IEM-only EM execution policy!\n", pszInstr));
7911 int rcSched = EMR3SetExecutionPolicy(pVCpu->CTX_SUFF(pVM)->pUVM, EMEXECPOLICY_IEM_ALL, true);
7912 if (rcSched != VINF_SUCCESS)
7913 iemSetPassUpStatus(pVCpu, rcSched);
7914# endif
7915
7916 /* Finally, done. */
7917 Log2(("vmentry: %s: cs:rip=%04x:%08RX64 cr0=%#RX64 (%#RX64) cr4=%#RX64 (%#RX64) efer=%#RX64 (%#RX64)\n",
7918 pszInstr, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.cr0,
7919 pVmcs->u64Cr0ReadShadow.u, pVCpu->cpum.GstCtx.cr4, pVmcs->u64Cr4ReadShadow.u,
7920 pVCpu->cpum.GstCtx.msrEFER, pVmcs->u64GuestEferMsr.u));
7921 return VINF_SUCCESS;
7922 }
7923 return iemVmxVmexit(pVCpu, VMX_EXIT_ERR_MSR_LOAD | VMX_EXIT_REASON_ENTRY_FAILED, pVmcs->u64RoExitQual.u);
7924 }
7925 }
7926 return iemVmxVmexit(pVCpu, VMX_EXIT_ERR_INVALID_GUEST_STATE | VMX_EXIT_REASON_ENTRY_FAILED, pVmcs->u64RoExitQual.u);
7927 }
7928
7929 iemVmxVmFail(pVCpu, VMXINSTRERR_VMENTRY_INVALID_HOST_STATE);
7930 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7931 }
7932
7933 iemVmxVmFail(pVCpu, VMXINSTRERR_VMENTRY_INVALID_CTLS);
7934 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7935# endif
7936}
7937
7938
7939/**
7940 * Interface for HM and EM to emulate the VMLAUNCH/VMRESUME instruction.
7941 *
7942 * @returns Strict VBox status code.
7943 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
7944 * @param cbInstr The instruction length in bytes.
7945 * @param uInstrId The instruction ID (VMXINSTRID_VMLAUNCH or
7946 * VMXINSTRID_VMRESUME).
7947 * @thread EMT(pVCpu)
7948 */
7949VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmlaunchVmresume(PVMCPUCC pVCpu, uint8_t cbInstr, VMXINSTRID uInstrId)
7950{
7951 IEMEXEC_ASSERT_INSTR_LEN_RETURN(cbInstr, 3);
7952 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK);
7953
7954 iemInitExec(pVCpu, false /*fBypassHandlers*/);
7955 VBOXSTRICTRC rcStrict = iemVmxVmlaunchVmresume(pVCpu, cbInstr, uInstrId);
7956 Assert(!pVCpu->iem.s.cActiveMappings);
7957 return iemUninitExecAndFiddleStatusAndMaybeReenter(pVCpu, rcStrict);
7958}
7959
7960
7961/**
7962 * Checks whether an RDMSR or WRMSR instruction for the given MSR is intercepted
7963 * (causes a VM-exit) or not.
7964 *
7965 * @returns @c true if the instruction is intercepted, @c false otherwise.
7966 * @param pVCpu The cross context virtual CPU structure.
7967 * @param uExitReason The VM-exit reason (VMX_EXIT_RDMSR or
7968 * VMX_EXIT_WRMSR).
7969 * @param idMsr The MSR.
7970 */
7971bool iemVmxIsRdmsrWrmsrInterceptSet(PCVMCPU pVCpu, uint32_t uExitReason, uint32_t idMsr) RT_NOEXCEPT
7972{
7973 Assert(IEM_VMX_IS_NON_ROOT_MODE(pVCpu));
7974 Assert( uExitReason == VMX_EXIT_RDMSR
7975 || uExitReason == VMX_EXIT_WRMSR);
7976
7977 /* Consult the MSR bitmap if the feature is supported. */
7978 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7979 Assert(pVmcs);
7980 if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
7981 {
7982 uint32_t const fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap, idMsr);
7983 if (uExitReason == VMX_EXIT_RDMSR)
7984 return RT_BOOL(fMsrpm & VMXMSRPM_EXIT_RD);
7985 return RT_BOOL(fMsrpm & VMXMSRPM_EXIT_WR);
7986 }
7987
7988 /* Without MSR bitmaps, all MSR accesses are intercepted. */
7989 return true;
7990}
7991
7992
7993/**
7994 * VMREAD instruction execution worker that does not perform any validation checks.
7995 *
7996 * Callers are expected to have performed the necessary checks and to ensure the
7997 * VMREAD will succeed.
7998 *
7999 * @param pVmcs Pointer to the virtual VMCS.
8000 * @param pu64Dst Where to write the VMCS value.
8001 * @param u64VmcsField The VMCS field.
8002 *
8003 * @remarks May be called with interrupts disabled.
8004 */
8005static void iemVmxVmreadNoCheck(PCVMXVVMCS pVmcs, uint64_t *pu64Dst, uint64_t u64VmcsField) RT_NOEXCEPT
8006{
8007 VMXVMCSFIELD VmcsField;
8008 VmcsField.u = u64VmcsField;
8009 uint8_t const uWidth = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_WIDTH);
8010 uint8_t const uType = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_TYPE);
8011 uint8_t const uWidthType = (uWidth << 2) | uType;
8012 uint8_t const uIndex = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_INDEX);
8013 Assert(uIndex <= VMX_V_VMCS_MAX_INDEX);
8014 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
8015 AssertMsg(offField < VMX_V_VMCS_SIZE, ("off=%u field=%#RX64 width=%#x type=%#x index=%#x (%u)\n", offField, u64VmcsField,
8016 uWidth, uType, uIndex, uIndex));
8017 AssertCompile(VMX_V_SHADOW_VMCS_SIZE == VMX_V_VMCS_SIZE);
8018
8019 /*
8020 * Read the VMCS component based on the field's effective width.
8021 *
8022 * The effective width is 64-bit fields adjusted to 32-bits if the access-type
8023 * indicates high bits (little endian).
8024 *
8025 * Note! The caller is responsible to trim the result and update registers
8026 * or memory locations are required. Here we just zero-extend to the largest
8027 * type (i.e. 64-bits).
8028 */
8029 uint8_t const *pbVmcs = (uint8_t const *)pVmcs;
8030 uint8_t const *pbField = pbVmcs + offField;
8031 uint8_t const uEffWidth = VMXGetVmcsFieldWidthEff(VmcsField.u);
8032 switch (uEffWidth)
8033 {
8034 case VMX_VMCSFIELD_WIDTH_64BIT:
8035 case VMX_VMCSFIELD_WIDTH_NATURAL: *pu64Dst = *(uint64_t const *)pbField; break;
8036 case VMX_VMCSFIELD_WIDTH_32BIT: *pu64Dst = *(uint32_t const *)pbField; break;
8037 case VMX_VMCSFIELD_WIDTH_16BIT: *pu64Dst = *(uint16_t const *)pbField; break;
8038 }
8039}
8040
8041
8042/**
8043 * Interface for HM and EM to read a VMCS field from the nested-guest VMCS.
8044 *
8045 * It is ASSUMED the caller knows what they're doing. No VMREAD instruction checks
8046 * are performed. Bounds checks are strict builds only.
8047 *
8048 * @param pVmcs Pointer to the virtual VMCS.
8049 * @param u64VmcsField The VMCS field.
8050 * @param pu64Dst Where to store the VMCS value.
8051 *
8052 * @remarks May be called with interrupts disabled.
8053 * @todo This should probably be moved to CPUM someday.
8054 */
8055VMM_INT_DECL(void) IEMReadVmxVmcsField(PCVMXVVMCS pVmcs, uint64_t u64VmcsField, uint64_t *pu64Dst)
8056{
8057 AssertPtr(pVmcs);
8058 AssertPtr(pu64Dst);
8059 iemVmxVmreadNoCheck(pVmcs, pu64Dst, u64VmcsField);
8060}
8061
8062
8063/**
8064 * VMREAD common (memory/register) instruction execution worker.
8065 *
8066 * @returns Strict VBox status code.
8067 * @param pVCpu The cross context virtual CPU structure.
8068 * @param cbInstr The instruction length in bytes.
8069 * @param pu64Dst Where to write the VMCS value (only updated when
8070 * VINF_SUCCESS is returned).
8071 * @param u64VmcsField The VMCS field.
8072 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
8073 * NULL.
8074 */
8075static VBOXSTRICTRC iemVmxVmreadCommon(PVMCPUCC pVCpu, uint8_t cbInstr, uint64_t *pu64Dst,
8076 uint64_t u64VmcsField, PCVMXVEXITINFO pExitInfo) RT_NOEXCEPT
8077{
8078 /* Nested-guest intercept. */
8079 if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
8080 && CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, VMX_EXIT_VMREAD, u64VmcsField))
8081 {
8082 if (pExitInfo)
8083 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
8084 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_VMREAD, VMXINSTRID_VMREAD, cbInstr);
8085 }
8086
8087 /* CPL. */
8088 if (pVCpu->iem.s.uCpl == 0)
8089 { /* likely */ }
8090 else
8091 {
8092 Log(("vmread: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
8093 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmread_Cpl;
8094 return iemRaiseGeneralProtectionFault0(pVCpu);
8095 }
8096
8097 pVCpu->iem.s.cPotentialExits++;
8098
8099 /* VMCS pointer in root mode. */
8100 if ( !IEM_VMX_IS_ROOT_MODE(pVCpu)
8101 || IEM_VMX_HAS_CURRENT_VMCS(pVCpu))
8102 { /* likely */ }
8103 else
8104 {
8105 Log(("vmread: VMCS pointer %#RGp invalid -> VMFailInvalid\n", IEM_VMX_GET_CURRENT_VMCS(pVCpu)));
8106 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmread_PtrInvalid;
8107 iemVmxVmFailInvalid(pVCpu);
8108 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8109 }
8110
8111 /* VMCS-link pointer in non-root mode. */
8112 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
8113 || IEM_VMX_HAS_SHADOW_VMCS(pVCpu))
8114 { /* likely */ }
8115 else
8116 {
8117 Log(("vmread: VMCS-link pointer %#RGp invalid -> VMFailInvalid\n", IEM_VMX_GET_SHADOW_VMCS(pVCpu)));
8118 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmread_LinkPtrInvalid;
8119 iemVmxVmFailInvalid(pVCpu);
8120 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8121 }
8122
8123 /* Supported VMCS field. */
8124 if (CPUMIsGuestVmxVmcsFieldValid(pVCpu->CTX_SUFF(pVM), u64VmcsField))
8125 { /* likely */ }
8126 else
8127 {
8128 Log(("vmread: VMCS field %#RX64 invalid -> VMFail\n", u64VmcsField));
8129 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmread_FieldInvalid;
8130 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64VmcsField;
8131 iemVmxVmFail(pVCpu, VMXINSTRERR_VMREAD_INVALID_COMPONENT);
8132 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8133 }
8134
8135 /*
8136 * Reading from the current or shadow VMCS.
8137 */
8138 PCVMXVVMCS pVmcs = !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
8139 ? &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs
8140 : &pVCpu->cpum.GstCtx.hwvirt.vmx.ShadowVmcs;
8141 iemVmxVmreadNoCheck(pVmcs, pu64Dst, u64VmcsField);
8142 Log4(("vmread %#RX64 => %#RX64\n", u64VmcsField, *pu64Dst));
8143 return VINF_SUCCESS;
8144}
8145
8146
8147/**
8148 * VMREAD (64-bit register) instruction execution worker.
8149 *
8150 * @returns Strict VBox status code.
8151 * @param pVCpu The cross context virtual CPU structure.
8152 * @param cbInstr The instruction length in bytes.
8153 * @param pu64Dst Where to store the VMCS field's value.
8154 * @param u64VmcsField The VMCS field.
8155 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
8156 * NULL.
8157 */
8158static VBOXSTRICTRC iemVmxVmreadReg64(PVMCPUCC pVCpu, uint8_t cbInstr, uint64_t *pu64Dst,
8159 uint64_t u64VmcsField, PCVMXVEXITINFO pExitInfo) RT_NOEXCEPT
8160{
8161 VBOXSTRICTRC rcStrict = iemVmxVmreadCommon(pVCpu, cbInstr, pu64Dst, u64VmcsField, pExitInfo);
8162 if (rcStrict == VINF_SUCCESS)
8163 {
8164 iemVmxVmSucceed(pVCpu);
8165 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8166 }
8167
8168 Log(("vmread/reg: iemVmxVmreadCommon failed rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8169 return rcStrict;
8170}
8171
8172
8173/**
8174 * VMREAD (32-bit register) instruction execution worker.
8175 *
8176 * @returns Strict VBox status code.
8177 * @param pVCpu The cross context virtual CPU structure.
8178 * @param cbInstr The instruction length in bytes.
8179 * @param pu32Dst Where to store the VMCS field's value.
8180 * @param u32VmcsField The VMCS field.
8181 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
8182 * NULL.
8183 */
8184static VBOXSTRICTRC iemVmxVmreadReg32(PVMCPUCC pVCpu, uint8_t cbInstr, uint32_t *pu32Dst,
8185 uint64_t u32VmcsField, PCVMXVEXITINFO pExitInfo) RT_NOEXCEPT
8186{
8187 uint64_t u64Dst;
8188 VBOXSTRICTRC rcStrict = iemVmxVmreadCommon(pVCpu, cbInstr, &u64Dst, u32VmcsField, pExitInfo);
8189 if (rcStrict == VINF_SUCCESS)
8190 {
8191 *pu32Dst = u64Dst;
8192 iemVmxVmSucceed(pVCpu);
8193 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8194 }
8195
8196 Log(("vmread/reg: iemVmxVmreadCommon failed rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8197 return rcStrict;
8198}
8199
8200
8201/**
8202 * VMREAD (memory) instruction execution worker.
8203 *
8204 * @returns Strict VBox status code.
8205 * @param pVCpu The cross context virtual CPU structure.
8206 * @param cbInstr The instruction length in bytes.
8207 * @param iEffSeg The effective segment register to use with @a u64Val.
8208 * Pass UINT8_MAX if it is a register access.
8209 * @param GCPtrDst The guest linear address to store the VMCS field's
8210 * value.
8211 * @param u64VmcsField The VMCS field.
8212 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
8213 * NULL.
8214 */
8215static VBOXSTRICTRC iemVmxVmreadMem(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrDst,
8216 uint64_t u64VmcsField, PCVMXVEXITINFO pExitInfo) RT_NOEXCEPT
8217{
8218 uint64_t u64Dst;
8219 VBOXSTRICTRC rcStrict = iemVmxVmreadCommon(pVCpu, cbInstr, &u64Dst, u64VmcsField, pExitInfo);
8220 if (rcStrict == VINF_SUCCESS)
8221 {
8222 /*
8223 * Write the VMCS field's value to the location specified in guest-memory.
8224 */
8225 if (pVCpu->iem.s.enmCpuMode == IEMMODE_64BIT)
8226 rcStrict = iemMemStoreDataU64(pVCpu, iEffSeg, GCPtrDst, u64Dst);
8227 else
8228 rcStrict = iemMemStoreDataU32(pVCpu, iEffSeg, GCPtrDst, u64Dst);
8229 if (rcStrict == VINF_SUCCESS)
8230 {
8231 iemVmxVmSucceed(pVCpu);
8232 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8233 }
8234
8235 Log(("vmread/mem: Failed to write to memory operand at %#RGv, rc=%Rrc\n", GCPtrDst, VBOXSTRICTRC_VAL(rcStrict)));
8236 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmread_PtrMap;
8237 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrDst;
8238 return rcStrict;
8239 }
8240
8241 Log(("vmread/mem: iemVmxVmreadCommon failed rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8242 return rcStrict;
8243}
8244
8245
8246/**
8247 * Interface for HM and EM to emulate the VMREAD instruction.
8248 *
8249 * @returns Strict VBox status code.
8250 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
8251 * @param pExitInfo Pointer to the VM-exit information.
8252 * @thread EMT(pVCpu)
8253 */
8254VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmread(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo)
8255{
8256 IEMEXEC_ASSERT_INSTR_LEN_RETURN(pExitInfo->cbInstr, 3);
8257 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI);
8258 Assert(pExitInfo);
8259
8260 iemInitExec(pVCpu, false /*fBypassHandlers*/);
8261
8262 VBOXSTRICTRC rcStrict;
8263 uint8_t const cbInstr = pExitInfo->cbInstr;
8264 bool const fIs64BitMode = RT_BOOL(pVCpu->iem.s.enmCpuMode == IEMMODE_64BIT);
8265 uint64_t const u64FieldEnc = fIs64BitMode
8266 ? iemGRegFetchU64(pVCpu, pExitInfo->InstrInfo.VmreadVmwrite.iReg2)
8267 : iemGRegFetchU32(pVCpu, pExitInfo->InstrInfo.VmreadVmwrite.iReg2);
8268 if (pExitInfo->InstrInfo.VmreadVmwrite.fIsRegOperand)
8269 {
8270 if (fIs64BitMode)
8271 {
8272 uint64_t *pu64Dst = iemGRegRefU64(pVCpu, pExitInfo->InstrInfo.VmreadVmwrite.iReg1);
8273 rcStrict = iemVmxVmreadReg64(pVCpu, cbInstr, pu64Dst, u64FieldEnc, pExitInfo);
8274 }
8275 else
8276 {
8277 uint32_t *pu32Dst = iemGRegRefU32(pVCpu, pExitInfo->InstrInfo.VmreadVmwrite.iReg1);
8278 rcStrict = iemVmxVmreadReg32(pVCpu, cbInstr, pu32Dst, u64FieldEnc, pExitInfo);
8279 }
8280 }
8281 else
8282 {
8283 RTGCPTR const GCPtrDst = pExitInfo->GCPtrEffAddr;
8284 uint8_t const iEffSeg = pExitInfo->InstrInfo.VmreadVmwrite.iSegReg;
8285 rcStrict = iemVmxVmreadMem(pVCpu, cbInstr, iEffSeg, GCPtrDst, u64FieldEnc, pExitInfo);
8286 }
8287 Assert(!pVCpu->iem.s.cActiveMappings);
8288 return iemUninitExecAndFiddleStatusAndMaybeReenter(pVCpu, rcStrict);
8289}
8290
8291
8292/**
8293 * VMWRITE instruction execution worker that does not perform any validation
8294 * checks.
8295 *
8296 * Callers are expected to have performed the necessary checks and to ensure the
8297 * VMWRITE will succeed.
8298 *
8299 * @param pVmcs Pointer to the virtual VMCS.
8300 * @param u64Val The value to write.
8301 * @param u64VmcsField The VMCS field.
8302 *
8303 * @remarks May be called with interrupts disabled.
8304 */
8305static void iemVmxVmwriteNoCheck(PVMXVVMCS pVmcs, uint64_t u64Val, uint64_t u64VmcsField) RT_NOEXCEPT
8306{
8307 VMXVMCSFIELD VmcsField;
8308 VmcsField.u = u64VmcsField;
8309 uint8_t const uWidth = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_WIDTH);
8310 uint8_t const uType = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_TYPE);
8311 uint8_t const uWidthType = (uWidth << 2) | uType;
8312 uint8_t const uIndex = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_INDEX);
8313 Assert(uIndex <= VMX_V_VMCS_MAX_INDEX);
8314 uint16_t const offField = g_aoffVmcsMap[uWidthType][uIndex];
8315 Assert(offField < VMX_V_VMCS_SIZE);
8316 AssertCompile(VMX_V_SHADOW_VMCS_SIZE == VMX_V_VMCS_SIZE);
8317
8318 /*
8319 * Write the VMCS component based on the field's effective width.
8320 *
8321 * The effective width is 64-bit fields adjusted to 32-bits if the access-type
8322 * indicates high bits (little endian).
8323 */
8324 uint8_t *pbVmcs = (uint8_t *)pVmcs;
8325 uint8_t *pbField = pbVmcs + offField;
8326 uint8_t const uEffWidth = VMXGetVmcsFieldWidthEff(VmcsField.u);
8327 switch (uEffWidth)
8328 {
8329 case VMX_VMCSFIELD_WIDTH_64BIT:
8330 case VMX_VMCSFIELD_WIDTH_NATURAL: *(uint64_t *)pbField = u64Val; break;
8331 case VMX_VMCSFIELD_WIDTH_32BIT: *(uint32_t *)pbField = u64Val; break;
8332 case VMX_VMCSFIELD_WIDTH_16BIT: *(uint16_t *)pbField = u64Val; break;
8333 }
8334}
8335
8336
8337/**
8338 * Interface for HM and EM to write a VMCS field in the nested-guest VMCS.
8339 *
8340 * It is ASSUMED the caller knows what they're doing. No VMWRITE instruction checks
8341 * are performed. Bounds checks are strict builds only.
8342 *
8343 * @param pVmcs Pointer to the virtual VMCS.
8344 * @param u64VmcsField The VMCS field.
8345 * @param u64Val The value to write.
8346 *
8347 * @remarks May be called with interrupts disabled.
8348 * @todo This should probably be moved to CPUM someday.
8349 */
8350VMM_INT_DECL(void) IEMWriteVmxVmcsField(PVMXVVMCS pVmcs, uint64_t u64VmcsField, uint64_t u64Val)
8351{
8352 AssertPtr(pVmcs);
8353 iemVmxVmwriteNoCheck(pVmcs, u64Val, u64VmcsField);
8354}
8355
8356
8357/**
8358 * VMWRITE instruction execution worker.
8359 *
8360 * @returns Strict VBox status code.
8361 * @param pVCpu The cross context virtual CPU structure.
8362 * @param cbInstr The instruction length in bytes.
8363 * @param iEffSeg The effective segment register to use with @a u64Val.
8364 * Pass UINT8_MAX if it is a register access.
8365 * @param u64Val The value to write (or guest linear address to the
8366 * value), @a iEffSeg will indicate if it's a memory
8367 * operand.
8368 * @param u64VmcsField The VMCS field.
8369 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
8370 * NULL.
8371 */
8372static VBOXSTRICTRC iemVmxVmwrite(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, uint64_t u64Val,
8373 uint64_t u64VmcsField, PCVMXVEXITINFO pExitInfo) RT_NOEXCEPT
8374{
8375 /* Nested-guest intercept. */
8376 if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
8377 && CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, VMX_EXIT_VMWRITE, u64VmcsField))
8378 {
8379 if (pExitInfo)
8380 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
8381 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_VMWRITE, VMXINSTRID_VMWRITE, cbInstr);
8382 }
8383
8384 /* CPL. */
8385 if (pVCpu->iem.s.uCpl == 0)
8386 { /* likely */ }
8387 else
8388 {
8389 Log(("vmwrite: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
8390 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmwrite_Cpl;
8391 return iemRaiseGeneralProtectionFault0(pVCpu);
8392 }
8393
8394 pVCpu->iem.s.cPotentialExits++;
8395
8396 /* VMCS pointer in root mode. */
8397 if ( !IEM_VMX_IS_ROOT_MODE(pVCpu)
8398 || IEM_VMX_HAS_CURRENT_VMCS(pVCpu))
8399 { /* likely */ }
8400 else
8401 {
8402 Log(("vmwrite: VMCS pointer %#RGp invalid -> VMFailInvalid\n", IEM_VMX_GET_CURRENT_VMCS(pVCpu)));
8403 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmwrite_PtrInvalid;
8404 iemVmxVmFailInvalid(pVCpu);
8405 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8406 }
8407
8408 /* VMCS-link pointer in non-root mode. */
8409 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
8410 || IEM_VMX_HAS_SHADOW_VMCS(pVCpu))
8411 { /* likely */ }
8412 else
8413 {
8414 Log(("vmwrite: VMCS-link pointer %#RGp invalid -> VMFailInvalid\n", IEM_VMX_GET_SHADOW_VMCS(pVCpu)));
8415 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmwrite_LinkPtrInvalid;
8416 iemVmxVmFailInvalid(pVCpu);
8417 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8418 }
8419
8420 /* If the VMWRITE instruction references memory, access the specified memory operand. */
8421 bool const fIsRegOperand = iEffSeg == UINT8_MAX;
8422 if (!fIsRegOperand)
8423 {
8424 /* Read the value from the specified guest memory location. */
8425 VBOXSTRICTRC rcStrict;
8426 RTGCPTR const GCPtrVal = u64Val;
8427 if (pVCpu->iem.s.enmCpuMode == IEMMODE_64BIT)
8428 rcStrict = iemMemFetchDataU64(pVCpu, &u64Val, iEffSeg, GCPtrVal);
8429 else
8430 rcStrict = iemMemFetchDataU32_ZX_U64(pVCpu, &u64Val, iEffSeg, GCPtrVal);
8431 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
8432 {
8433 Log(("vmwrite: Failed to read value from memory operand at %#RGv, rc=%Rrc\n", GCPtrVal, VBOXSTRICTRC_VAL(rcStrict)));
8434 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmwrite_PtrMap;
8435 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrVal;
8436 return rcStrict;
8437 }
8438 }
8439 else
8440 Assert(!pExitInfo || pExitInfo->InstrInfo.VmreadVmwrite.fIsRegOperand);
8441
8442 /* Supported VMCS field. */
8443 if (CPUMIsGuestVmxVmcsFieldValid(pVCpu->CTX_SUFF(pVM), u64VmcsField))
8444 { /* likely */ }
8445 else
8446 {
8447 Log(("vmwrite: VMCS field %#RX64 invalid -> VMFail\n", u64VmcsField));
8448 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmwrite_FieldInvalid;
8449 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64VmcsField;
8450 iemVmxVmFail(pVCpu, VMXINSTRERR_VMWRITE_INVALID_COMPONENT);
8451 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8452 }
8453
8454 /* Read-only VMCS field. */
8455 bool const fIsFieldReadOnly = VMXIsVmcsFieldReadOnly(u64VmcsField);
8456 if ( !fIsFieldReadOnly
8457 || IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxVmwriteAll)
8458 { /* likely */ }
8459 else
8460 {
8461 Log(("vmwrite: Write to read-only VMCS component %#RX64 -> VMFail\n", u64VmcsField));
8462 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmwrite_FieldRo;
8463 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64VmcsField;
8464 iemVmxVmFail(pVCpu, VMXINSTRERR_VMWRITE_RO_COMPONENT);
8465 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8466 }
8467
8468 /*
8469 * Write to the current or shadow VMCS.
8470 */
8471 bool const fInVmxNonRootMode = IEM_VMX_IS_NON_ROOT_MODE(pVCpu);
8472 PVMXVVMCS pVmcs = !fInVmxNonRootMode
8473 ? &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs
8474 : &pVCpu->cpum.GstCtx.hwvirt.vmx.ShadowVmcs;
8475 iemVmxVmwriteNoCheck(pVmcs, u64Val, u64VmcsField);
8476 Log4(("vmwrite %#RX64 <= %#RX64\n", u64VmcsField, u64Val));
8477
8478 if ( !fInVmxNonRootMode
8479 && VM_IS_HM_ENABLED(pVCpu->CTX_SUFF(pVM)))
8480 {
8481 /* Notify HM that the VMCS content might have changed. */
8482 HMNotifyVmxNstGstCurrentVmcsChanged(pVCpu);
8483 }
8484
8485 iemVmxVmSucceed(pVCpu);
8486 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8487}
8488
8489
8490/**
8491 * Interface for HM and EM to emulate the VMWRITE instruction.
8492 *
8493 * @returns Strict VBox status code.
8494 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
8495 * @param pExitInfo Pointer to the VM-exit information.
8496 * @thread EMT(pVCpu)
8497 */
8498VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmwrite(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo)
8499{
8500 IEMEXEC_ASSERT_INSTR_LEN_RETURN(pExitInfo->cbInstr, 3);
8501 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI);
8502 Assert(pExitInfo);
8503
8504 iemInitExec(pVCpu, false /*fBypassHandlers*/);
8505
8506 uint64_t u64Val;
8507 uint8_t iEffSeg;
8508 if (pExitInfo->InstrInfo.VmreadVmwrite.fIsRegOperand)
8509 {
8510 u64Val = iemGRegFetchU64(pVCpu, pExitInfo->InstrInfo.VmreadVmwrite.iReg1);
8511 iEffSeg = UINT8_MAX;
8512 }
8513 else
8514 {
8515 u64Val = pExitInfo->GCPtrEffAddr;
8516 iEffSeg = pExitInfo->InstrInfo.VmreadVmwrite.iSegReg;
8517 }
8518 uint8_t const cbInstr = pExitInfo->cbInstr;
8519 uint64_t const u64FieldEnc = pVCpu->iem.s.enmCpuMode == IEMMODE_64BIT
8520 ? iemGRegFetchU64(pVCpu, pExitInfo->InstrInfo.VmreadVmwrite.iReg2)
8521 : iemGRegFetchU32(pVCpu, pExitInfo->InstrInfo.VmreadVmwrite.iReg2);
8522 VBOXSTRICTRC rcStrict = iemVmxVmwrite(pVCpu, cbInstr, iEffSeg, u64Val, u64FieldEnc, pExitInfo);
8523 Assert(!pVCpu->iem.s.cActiveMappings);
8524 return iemUninitExecAndFiddleStatusAndMaybeReenter(pVCpu, rcStrict);
8525}
8526
8527
8528/**
8529 * VMCLEAR instruction execution worker.
8530 *
8531 * @returns Strict VBox status code.
8532 * @param pVCpu The cross context virtual CPU structure.
8533 * @param cbInstr The instruction length in bytes.
8534 * @param iEffSeg The effective segment register to use with @a GCPtrVmcs.
8535 * @param GCPtrVmcs The linear address of the VMCS pointer.
8536 * @param pExitInfo Pointer to the VM-exit information. Optional, can be NULL.
8537 *
8538 * @remarks Common VMX instruction checks are already expected to by the caller,
8539 * i.e. VMX operation, CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
8540 */
8541static VBOXSTRICTRC iemVmxVmclear(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg,
8542 RTGCPHYS GCPtrVmcs, PCVMXVEXITINFO pExitInfo) RT_NOEXCEPT
8543{
8544 /* Nested-guest intercept. */
8545 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8546 {
8547 if (pExitInfo)
8548 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
8549 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_VMCLEAR, VMXINSTRID_NONE, cbInstr);
8550 }
8551
8552 Assert(IEM_VMX_IS_ROOT_MODE(pVCpu));
8553
8554 /* CPL. */
8555 if (pVCpu->iem.s.uCpl == 0)
8556 { /* likely */ }
8557 else
8558 {
8559 Log(("vmclear: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
8560 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmclear_Cpl;
8561 return iemRaiseGeneralProtectionFault0(pVCpu);
8562 }
8563
8564 /* Get the VMCS pointer from the location specified by the source memory operand. */
8565 RTGCPHYS GCPhysVmcs;
8566 VBOXSTRICTRC rcStrict = iemMemFetchDataU64(pVCpu, &GCPhysVmcs, iEffSeg, GCPtrVmcs);
8567 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8568 { /* likely */ }
8569 else
8570 {
8571 Log(("vmclear: Failed to read VMCS physaddr from %#RGv, rc=%Rrc\n", GCPtrVmcs, VBOXSTRICTRC_VAL(rcStrict)));
8572 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmclear_PtrMap;
8573 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrVmcs;
8574 return rcStrict;
8575 }
8576
8577 /* VMCS pointer alignment. */
8578 if (!(GCPhysVmcs & X86_PAGE_4K_OFFSET_MASK))
8579 { /* likely */ }
8580 else
8581 {
8582 Log(("vmclear: VMCS pointer not page-aligned -> VMFail()\n"));
8583 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmclear_PtrAlign;
8584 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8585 iemVmxVmFail(pVCpu, VMXINSTRERR_VMCLEAR_INVALID_PHYSADDR);
8586 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8587 }
8588
8589 /* VMCS physical-address width limits. */
8590 if (!(GCPhysVmcs >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth))
8591 { /* likely */ }
8592 else
8593 {
8594 Log(("vmclear: VMCS pointer extends beyond physical-address width -> VMFail()\n"));
8595 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmclear_PtrWidth;
8596 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8597 iemVmxVmFail(pVCpu, VMXINSTRERR_VMCLEAR_INVALID_PHYSADDR);
8598 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8599 }
8600
8601 /* VMCS is not the VMXON region. */
8602 if (GCPhysVmcs != pVCpu->cpum.GstCtx.hwvirt.vmx.GCPhysVmxon)
8603 { /* likely */ }
8604 else
8605 {
8606 Log(("vmclear: VMCS pointer cannot be identical to VMXON region pointer -> VMFail()\n"));
8607 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmclear_PtrVmxon;
8608 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8609 iemVmxVmFail(pVCpu, VMXINSTRERR_VMCLEAR_VMXON_PTR);
8610 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8611 }
8612
8613 /* Ensure VMCS is not MMIO, ROM etc. This is not an Intel requirement but a
8614 restriction imposed by our implementation. */
8615 if (PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysVmcs))
8616 { /* likely */ }
8617 else
8618 {
8619 Log(("vmclear: VMCS not normal memory -> VMFail()\n"));
8620 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmclear_PtrAbnormal;
8621 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8622 iemVmxVmFail(pVCpu, VMXINSTRERR_VMCLEAR_INVALID_PHYSADDR);
8623 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8624 }
8625
8626 /*
8627 * VMCLEAR allows committing and clearing any valid VMCS pointer.
8628 *
8629 * If the current VMCS is the one being cleared, set its state to 'clear' and commit
8630 * to guest memory. Otherwise, set the state of the VMCS referenced in guest memory
8631 * to 'clear'.
8632 */
8633 uint8_t const fVmcsLaunchStateClear = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
8634 if ( IEM_VMX_HAS_CURRENT_VMCS(pVCpu)
8635 && IEM_VMX_GET_CURRENT_VMCS(pVCpu) == GCPhysVmcs)
8636 {
8637 pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.fVmcsState = fVmcsLaunchStateClear;
8638 iemVmxWriteCurrentVmcsToGstMem(pVCpu);
8639 IEM_VMX_CLEAR_CURRENT_VMCS(pVCpu);
8640 }
8641 else
8642 {
8643 AssertCompileMemberSize(VMXVVMCS, fVmcsState, sizeof(fVmcsLaunchStateClear));
8644 rcStrict = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVmcs + RT_UOFFSETOF(VMXVVMCS, fVmcsState),
8645 (const void *)&fVmcsLaunchStateClear, sizeof(fVmcsLaunchStateClear));
8646 if (RT_FAILURE(rcStrict))
8647 return rcStrict;
8648 }
8649
8650 iemVmxVmSucceed(pVCpu);
8651 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8652}
8653
8654
8655/**
8656 * Interface for HM and EM to emulate the VMCLEAR instruction.
8657 *
8658 * @returns Strict VBox status code.
8659 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
8660 * @param pExitInfo Pointer to the VM-exit information.
8661 * @thread EMT(pVCpu)
8662 */
8663VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmclear(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo)
8664{
8665 Assert(pExitInfo);
8666 IEMEXEC_ASSERT_INSTR_LEN_RETURN(pExitInfo->cbInstr, 3);
8667 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI);
8668
8669 iemInitExec(pVCpu, false /*fBypassHandlers*/);
8670
8671 uint8_t const iEffSeg = pExitInfo->InstrInfo.VmxXsave.iSegReg;
8672 uint8_t const cbInstr = pExitInfo->cbInstr;
8673 RTGCPTR const GCPtrVmcs = pExitInfo->GCPtrEffAddr;
8674 VBOXSTRICTRC rcStrict = iemVmxVmclear(pVCpu, cbInstr, iEffSeg, GCPtrVmcs, pExitInfo);
8675 Assert(!pVCpu->iem.s.cActiveMappings);
8676 return iemUninitExecAndFiddleStatusAndMaybeReenter(pVCpu, rcStrict);
8677}
8678
8679
8680/**
8681 * VMPTRST instruction execution worker.
8682 *
8683 * @returns Strict VBox status code.
8684 * @param pVCpu The cross context virtual CPU structure.
8685 * @param cbInstr The instruction length in bytes.
8686 * @param iEffSeg The effective segment register to use with @a GCPtrVmcs.
8687 * @param GCPtrVmcs The linear address of where to store the current VMCS
8688 * pointer.
8689 * @param pExitInfo Pointer to the VM-exit information. Optional, can be NULL.
8690 *
8691 * @remarks Common VMX instruction checks are already expected to by the caller,
8692 * i.e. VMX operation, CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
8693 */
8694static VBOXSTRICTRC iemVmxVmptrst(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg,
8695 RTGCPHYS GCPtrVmcs, PCVMXVEXITINFO pExitInfo) RT_NOEXCEPT
8696{
8697 /* Nested-guest intercept. */
8698 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8699 {
8700 if (pExitInfo)
8701 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
8702 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_VMPTRST, VMXINSTRID_NONE, cbInstr);
8703 }
8704
8705 Assert(IEM_VMX_IS_ROOT_MODE(pVCpu));
8706
8707 /* CPL. */
8708 if (pVCpu->iem.s.uCpl == 0)
8709 { /* likely */ }
8710 else
8711 {
8712 Log(("vmptrst: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
8713 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrst_Cpl;
8714 return iemRaiseGeneralProtectionFault0(pVCpu);
8715 }
8716
8717 /* Set the VMCS pointer to the location specified by the destination memory operand. */
8718 AssertCompile(NIL_RTGCPHYS == ~(RTGCPHYS)0U);
8719 VBOXSTRICTRC rcStrict = iemMemStoreDataU64(pVCpu, iEffSeg, GCPtrVmcs, IEM_VMX_GET_CURRENT_VMCS(pVCpu));
8720 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8721 {
8722 iemVmxVmSucceed(pVCpu);
8723 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8724 }
8725
8726 Log(("vmptrst: Failed to store VMCS pointer to memory at destination operand %#Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8727 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrst_PtrMap;
8728 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrVmcs;
8729 return rcStrict;
8730}
8731
8732
8733/**
8734 * Interface for HM and EM to emulate the VMPTRST instruction.
8735 *
8736 * @returns Strict VBox status code.
8737 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
8738 * @param pExitInfo Pointer to the VM-exit information.
8739 * @thread EMT(pVCpu)
8740 */
8741VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmptrst(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo)
8742{
8743 Assert(pExitInfo);
8744 IEMEXEC_ASSERT_INSTR_LEN_RETURN(pExitInfo->cbInstr, 3);
8745 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI);
8746
8747 iemInitExec(pVCpu, false /*fBypassHandlers*/);
8748
8749 uint8_t const iEffSeg = pExitInfo->InstrInfo.VmxXsave.iSegReg;
8750 uint8_t const cbInstr = pExitInfo->cbInstr;
8751 RTGCPTR const GCPtrVmcs = pExitInfo->GCPtrEffAddr;
8752 VBOXSTRICTRC rcStrict = iemVmxVmptrst(pVCpu, cbInstr, iEffSeg, GCPtrVmcs, pExitInfo);
8753 Assert(!pVCpu->iem.s.cActiveMappings);
8754 return iemUninitExecAndFiddleStatusAndMaybeReenter(pVCpu, rcStrict);
8755}
8756
8757
8758/**
8759 * VMPTRLD instruction execution worker.
8760 *
8761 * @returns Strict VBox status code.
8762 * @param pVCpu The cross context virtual CPU structure.
8763 * @param cbInstr The instruction length in bytes.
8764 * @param GCPtrVmcs The linear address of the current VMCS pointer.
8765 * @param pExitInfo Pointer to the VM-exit information. Optional, can be NULL.
8766 *
8767 * @remarks Common VMX instruction checks are already expected to by the caller,
8768 * i.e. VMX operation, CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
8769 */
8770static VBOXSTRICTRC iemVmxVmptrld(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg,
8771 RTGCPHYS GCPtrVmcs, PCVMXVEXITINFO pExitInfo) RT_NOEXCEPT
8772{
8773 /* Nested-guest intercept. */
8774 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8775 {
8776 if (pExitInfo)
8777 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
8778 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_VMPTRLD, VMXINSTRID_NONE, cbInstr);
8779 }
8780
8781 Assert(IEM_VMX_IS_ROOT_MODE(pVCpu));
8782
8783 /* CPL. */
8784 if (pVCpu->iem.s.uCpl == 0)
8785 { /* likely */ }
8786 else
8787 {
8788 Log(("vmptrld: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
8789 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_Cpl;
8790 return iemRaiseGeneralProtectionFault0(pVCpu);
8791 }
8792
8793 /* Get the VMCS pointer from the location specified by the source memory operand. */
8794 RTGCPHYS GCPhysVmcs;
8795 VBOXSTRICTRC rcStrict = iemMemFetchDataU64(pVCpu, &GCPhysVmcs, iEffSeg, GCPtrVmcs);
8796 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8797 { /* likely */ }
8798 else
8799 {
8800 Log(("vmptrld: Failed to read VMCS physaddr from %#RGv, rc=%Rrc\n", GCPtrVmcs, VBOXSTRICTRC_VAL(rcStrict)));
8801 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_PtrMap;
8802 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrVmcs;
8803 return rcStrict;
8804 }
8805
8806 /* VMCS pointer alignment. */
8807 if (!(GCPhysVmcs & X86_PAGE_4K_OFFSET_MASK))
8808 { /* likely */ }
8809 else
8810 {
8811 Log(("vmptrld: VMCS pointer not page-aligned -> VMFail()\n"));
8812 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_PtrAlign;
8813 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8814 iemVmxVmFail(pVCpu, VMXINSTRERR_VMPTRLD_INVALID_PHYSADDR);
8815 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8816 }
8817
8818 /* VMCS physical-address width limits. */
8819 if (!(GCPhysVmcs >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth))
8820 { /* likely */ }
8821 else
8822 {
8823 Log(("vmptrld: VMCS pointer extends beyond physical-address width -> VMFail()\n"));
8824 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_PtrWidth;
8825 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8826 iemVmxVmFail(pVCpu, VMXINSTRERR_VMPTRLD_INVALID_PHYSADDR);
8827 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8828 }
8829
8830 /* VMCS is not the VMXON region. */
8831 if (GCPhysVmcs != pVCpu->cpum.GstCtx.hwvirt.vmx.GCPhysVmxon)
8832 { /* likely */ }
8833 else
8834 {
8835 Log(("vmptrld: VMCS pointer cannot be identical to VMXON region pointer -> VMFail()\n"));
8836 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_PtrVmxon;
8837 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8838 iemVmxVmFail(pVCpu, VMXINSTRERR_VMPTRLD_VMXON_PTR);
8839 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8840 }
8841
8842 /* Ensure VMCS is not MMIO, ROM etc. This is not an Intel requirement but a
8843 restriction imposed by our implementation. */
8844 if (PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysVmcs))
8845 { /* likely */ }
8846 else
8847 {
8848 Log(("vmptrld: VMCS not normal memory -> VMFail()\n"));
8849 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_PtrAbnormal;
8850 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8851 iemVmxVmFail(pVCpu, VMXINSTRERR_VMPTRLD_INVALID_PHYSADDR);
8852 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8853 }
8854
8855 /* Read just the VMCS revision from the VMCS. */
8856 VMXVMCSREVID VmcsRevId;
8857 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &VmcsRevId, GCPhysVmcs, sizeof(VmcsRevId));
8858 if (RT_SUCCESS(rc))
8859 { /* likely */ }
8860 else
8861 {
8862 Log(("vmptrld: Failed to read revision identifier from VMCS at %#RGp, rc=%Rrc\n", GCPhysVmcs, rc));
8863 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_RevPtrReadPhys;
8864 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8865 return rc;
8866 }
8867
8868 /*
8869 * Verify the VMCS revision specified by the guest matches what we reported to the guest.
8870 * Verify the VMCS is not a shadow VMCS, if the VMCS shadowing feature is supported.
8871 */
8872 if ( VmcsRevId.n.u31RevisionId == VMX_V_VMCS_REVISION_ID
8873 && ( !VmcsRevId.n.fIsShadowVmcs
8874 || IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxVmcsShadowing))
8875 { /* likely */ }
8876 else
8877 {
8878 if (VmcsRevId.n.u31RevisionId != VMX_V_VMCS_REVISION_ID)
8879 {
8880 Log(("vmptrld: VMCS revision mismatch, expected %#RX32 got %#RX32, GCPtrVmcs=%#RGv GCPhysVmcs=%#RGp -> VMFail()\n",
8881 VMX_V_VMCS_REVISION_ID, VmcsRevId.n.u31RevisionId, GCPtrVmcs, GCPhysVmcs));
8882 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_VmcsRevId;
8883 }
8884 else
8885 {
8886 Log(("vmptrld: Shadow VMCS -> VMFail()\n"));
8887 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_ShadowVmcs;
8888 }
8889 iemVmxVmFail(pVCpu, VMXINSTRERR_VMPTRLD_INCORRECT_VMCS_REV);
8890 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8891 }
8892
8893 /*
8894 * We cache only the current VMCS in CPUMCTX. Therefore, VMPTRLD should always flush
8895 * the cache of an existing, current VMCS back to guest memory before loading a new,
8896 * different current VMCS.
8897 */
8898 if (IEM_VMX_GET_CURRENT_VMCS(pVCpu) != GCPhysVmcs)
8899 {
8900 if (IEM_VMX_HAS_CURRENT_VMCS(pVCpu))
8901 {
8902 iemVmxWriteCurrentVmcsToGstMem(pVCpu);
8903 IEM_VMX_CLEAR_CURRENT_VMCS(pVCpu);
8904 }
8905
8906 /* Set the new VMCS as the current VMCS and read it from guest memory. */
8907 IEM_VMX_SET_CURRENT_VMCS(pVCpu, GCPhysVmcs);
8908 rc = iemVmxReadCurrentVmcsFromGstMem(pVCpu);
8909 if (RT_SUCCESS(rc))
8910 {
8911 /* Notify HM that a new, current VMCS is loaded. */
8912 if (VM_IS_HM_ENABLED(pVCpu->CTX_SUFF(pVM)))
8913 HMNotifyVmxNstGstCurrentVmcsChanged(pVCpu);
8914 }
8915 else
8916 {
8917 Log(("vmptrld: Failed to read VMCS at %#RGp, rc=%Rrc\n", GCPhysVmcs, rc));
8918 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmptrld_PtrReadPhys;
8919 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmcs;
8920 return rc;
8921 }
8922 }
8923
8924 Assert(IEM_VMX_HAS_CURRENT_VMCS(pVCpu));
8925 iemVmxVmSucceed(pVCpu);
8926 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8927}
8928
8929
8930/**
8931 * Interface for HM and EM to emulate the VMPTRLD instruction.
8932 *
8933 * @returns Strict VBox status code.
8934 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
8935 * @param pExitInfo Pointer to the VM-exit information.
8936 * @thread EMT(pVCpu)
8937 */
8938VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmptrld(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo)
8939{
8940 Assert(pExitInfo);
8941 IEMEXEC_ASSERT_INSTR_LEN_RETURN(pExitInfo->cbInstr, 3);
8942 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI);
8943
8944 iemInitExec(pVCpu, false /*fBypassHandlers*/);
8945
8946 uint8_t const iEffSeg = pExitInfo->InstrInfo.VmxXsave.iSegReg;
8947 uint8_t const cbInstr = pExitInfo->cbInstr;
8948 RTGCPTR const GCPtrVmcs = pExitInfo->GCPtrEffAddr;
8949 VBOXSTRICTRC rcStrict = iemVmxVmptrld(pVCpu, cbInstr, iEffSeg, GCPtrVmcs, pExitInfo);
8950 Assert(!pVCpu->iem.s.cActiveMappings);
8951 return iemUninitExecAndFiddleStatusAndMaybeReenter(pVCpu, rcStrict);
8952}
8953
8954
8955/**
8956 * INVVPID instruction execution worker.
8957 *
8958 * @returns Strict VBox status code.
8959 * @param pVCpu The cross context virtual CPU structure.
8960 * @param cbInstr The instruction length in bytes.
8961 * @param iEffSeg The segment of the invvpid descriptor.
8962 * @param GCPtrInvvpidDesc The address of invvpid descriptor.
8963 * @param u64InvvpidType The invalidation type.
8964 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
8965 * NULL.
8966 *
8967 * @remarks Common VMX instruction checks are already expected to by the caller,
8968 * i.e. VMX operation, CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
8969 */
8970VBOXSTRICTRC iemVmxInvvpid(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrInvvpidDesc,
8971 uint64_t u64InvvpidType, PCVMXVEXITINFO pExitInfo) RT_NOEXCEPT
8972{
8973 /* Check if INVVPID instruction is supported, otherwise raise #UD. */
8974 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxVpid)
8975 return iemRaiseUndefinedOpcode(pVCpu);
8976
8977 /* Nested-guest intercept. */
8978 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8979 {
8980 if (pExitInfo)
8981 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
8982 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_INVVPID, VMXINSTRID_NONE, cbInstr);
8983 }
8984
8985 /* CPL. */
8986 if (pVCpu->iem.s.uCpl != 0)
8987 {
8988 Log(("invvpid: CPL != 0 -> #GP(0)\n"));
8989 return iemRaiseGeneralProtectionFault0(pVCpu);
8990 }
8991
8992 /*
8993 * Validate INVVPID invalidation type.
8994 *
8995 * The instruction specifies exactly ONE of the supported invalidation types.
8996 *
8997 * Each of the types has a bit in IA32_VMX_EPT_VPID_CAP MSR specifying if it is
8998 * supported. In theory, it's possible for a CPU to not support flushing individual
8999 * addresses but all the other types or any other combination. We do not take any
9000 * shortcuts here by assuming the types we currently expose to the guest.
9001 */
9002 uint64_t const fCaps = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64EptVpidCaps;
9003 bool const fInvvpidSupported = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVVPID);
9004 bool const fTypeIndivAddr = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVVPID_INDIV_ADDR);
9005 bool const fTypeSingleCtx = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX);
9006 bool const fTypeAllCtx = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVVPID_ALL_CTX);
9007 bool const fTypeSingleCtxRetainGlobals = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_RETAIN_GLOBALS);
9008
9009 bool afSupportedTypes[4];
9010 afSupportedTypes[0] = fTypeIndivAddr;
9011 afSupportedTypes[1] = fTypeSingleCtx;
9012 afSupportedTypes[2] = fTypeAllCtx;
9013 afSupportedTypes[3] = fTypeSingleCtxRetainGlobals;
9014
9015 if ( fInvvpidSupported
9016 && !(u64InvvpidType & ~(uint64_t)VMX_INVVPID_VALID_MASK)
9017 && afSupportedTypes[u64InvvpidType & 3])
9018 { /* likely */ }
9019 else
9020 {
9021 Log(("invvpid: invalid/unsupported invvpid type %#x -> VMFail\n", u64InvvpidType));
9022 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invvpid_TypeInvalid;
9023 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64InvvpidType;
9024 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
9025 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9026 }
9027
9028 /*
9029 * Fetch the invvpid descriptor from guest memory.
9030 */
9031 RTUINT128U uDesc;
9032 VBOXSTRICTRC rcStrict = iemMemFetchDataU128(pVCpu, &uDesc, iEffSeg, GCPtrInvvpidDesc);
9033 if (rcStrict == VINF_SUCCESS)
9034 {
9035 /*
9036 * Validate the descriptor.
9037 */
9038 if (uDesc.s.Lo <= 0xffff)
9039 { /* likely */ }
9040 else
9041 {
9042 Log(("invvpid: reserved bits set in invvpid descriptor %#RX64 -> #GP(0)\n", uDesc.s.Lo));
9043 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invvpid_DescRsvd;
9044 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = uDesc.s.Lo;
9045 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
9046 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9047 }
9048
9049 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
9050 RTGCUINTPTR64 const GCPtrInvAddr = uDesc.s.Hi;
9051 uint8_t const uVpid = uDesc.s.Lo & UINT64_C(0xfff);
9052 uint64_t const uCr3 = pVCpu->cpum.GstCtx.cr3;
9053 switch (u64InvvpidType)
9054 {
9055 case VMXTLBFLUSHVPID_INDIV_ADDR:
9056 {
9057 if (uVpid != 0)
9058 {
9059 if (IEM_IS_CANONICAL(GCPtrInvAddr))
9060 {
9061 /* Invalidate mappings for the linear address tagged with VPID. */
9062 /** @todo PGM support for VPID? Currently just flush everything. */
9063 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
9064 iemVmxVmSucceed(pVCpu);
9065 }
9066 else
9067 {
9068 Log(("invvpid: invalidation address %#RGP is not canonical -> VMFail\n", GCPtrInvAddr));
9069 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invvpid_Type0InvalidAddr;
9070 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrInvAddr;
9071 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
9072 }
9073 }
9074 else
9075 {
9076 Log(("invvpid: invalid VPID %#x for invalidation type %u -> VMFail\n", uVpid, u64InvvpidType));
9077 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invvpid_Type0InvalidVpid;
9078 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64InvvpidType;
9079 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
9080 }
9081 break;
9082 }
9083
9084 case VMXTLBFLUSHVPID_SINGLE_CONTEXT:
9085 {
9086 if (uVpid != 0)
9087 {
9088 /* Invalidate all mappings with VPID. */
9089 /** @todo PGM support for VPID? Currently just flush everything. */
9090 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
9091 iemVmxVmSucceed(pVCpu);
9092 }
9093 else
9094 {
9095 Log(("invvpid: invalid VPID %#x for invalidation type %u -> VMFail\n", uVpid, u64InvvpidType));
9096 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invvpid_Type1InvalidVpid;
9097 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64InvvpidType;
9098 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
9099 }
9100 break;
9101 }
9102
9103 case VMXTLBFLUSHVPID_ALL_CONTEXTS:
9104 {
9105 /* Invalidate all mappings with non-zero VPIDs. */
9106 /** @todo PGM support for VPID? Currently just flush everything. */
9107 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
9108 iemVmxVmSucceed(pVCpu);
9109 break;
9110 }
9111
9112 case VMXTLBFLUSHVPID_SINGLE_CONTEXT_RETAIN_GLOBALS:
9113 {
9114 if (uVpid != 0)
9115 {
9116 /* Invalidate all mappings with VPID except global translations. */
9117 /** @todo PGM support for VPID? Currently just flush everything. */
9118 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
9119 iemVmxVmSucceed(pVCpu);
9120 }
9121 else
9122 {
9123 Log(("invvpid: invalid VPID %#x for invalidation type %u -> VMFail\n", uVpid, u64InvvpidType));
9124 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invvpid_Type3InvalidVpid;
9125 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = uVpid;
9126 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
9127 }
9128 break;
9129 }
9130 IEM_NOT_REACHED_DEFAULT_CASE_RET();
9131 }
9132 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9133 }
9134 return rcStrict;
9135}
9136
9137
9138/**
9139 * Interface for HM and EM to emulate the INVVPID instruction.
9140 *
9141 * @returns Strict VBox status code.
9142 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
9143 * @param pExitInfo Pointer to the VM-exit information.
9144 * @thread EMT(pVCpu)
9145 */
9146VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvvpid(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo)
9147{
9148 IEMEXEC_ASSERT_INSTR_LEN_RETURN(pExitInfo->cbInstr, 4);
9149 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI);
9150 Assert(pExitInfo);
9151
9152 iemInitExec(pVCpu, false /*fBypassHandlers*/);
9153
9154 uint8_t const iEffSeg = pExitInfo->InstrInfo.Inv.iSegReg;
9155 uint8_t const cbInstr = pExitInfo->cbInstr;
9156 RTGCPTR const GCPtrInvvpidDesc = pExitInfo->GCPtrEffAddr;
9157 uint64_t const u64InvvpidType = pVCpu->iem.s.enmCpuMode == IEMMODE_64BIT
9158 ? iemGRegFetchU64(pVCpu, pExitInfo->InstrInfo.Inv.iReg2)
9159 : iemGRegFetchU32(pVCpu, pExitInfo->InstrInfo.Inv.iReg2);
9160 VBOXSTRICTRC rcStrict = iemVmxInvvpid(pVCpu, cbInstr, iEffSeg, GCPtrInvvpidDesc, u64InvvpidType, pExitInfo);
9161 Assert(!pVCpu->iem.s.cActiveMappings);
9162 return iemUninitExecAndFiddleStatusAndMaybeReenter(pVCpu, rcStrict);
9163}
9164
9165#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
9166
9167/**
9168 * INVEPT instruction execution worker.
9169 *
9170 * @returns Strict VBox status code.
9171 * @param pVCpu The cross context virtual CPU structure.
9172 * @param cbInstr The instruction length in bytes.
9173 * @param iEffSeg The segment of the invept descriptor.
9174 * @param GCPtrInveptDesc The address of invept descriptor.
9175 * @param u64InveptType The invalidation type.
9176 * @param pExitInfo Pointer to the VM-exit information. Optional, can be
9177 * NULL.
9178 *
9179 * @remarks Common VMX instruction checks are already expected to by the caller,
9180 * i.e. VMX operation, CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
9181 */
9182static VBOXSTRICTRC iemVmxInvept(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrInveptDesc,
9183 uint64_t u64InveptType, PCVMXVEXITINFO pExitInfo) RT_NOEXCEPT
9184{
9185 /* Check if EPT is supported, otherwise raise #UD. */
9186 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxEpt)
9187 return iemRaiseUndefinedOpcode(pVCpu);
9188
9189 /* Nested-guest intercept. */
9190 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
9191 {
9192 if (pExitInfo)
9193 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
9194 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_INVEPT, VMXINSTRID_NONE, cbInstr);
9195 }
9196
9197 /* CPL. */
9198 if (pVCpu->iem.s.uCpl != 0)
9199 {
9200 Log(("invept: CPL != 0 -> #GP(0)\n"));
9201 return iemRaiseGeneralProtectionFault0(pVCpu);
9202 }
9203
9204 /*
9205 * Validate INVEPT invalidation type.
9206 *
9207 * The instruction specifies exactly ONE of the supported invalidation types.
9208 *
9209 * Each of the types has a bit in IA32_VMX_EPT_VPID_CAP MSR specifying if it is
9210 * supported. In theory, it's possible for a CPU to not support flushing individual
9211 * addresses but all the other types or any other combination. We do not take any
9212 * shortcuts here by assuming the types we currently expose to the guest.
9213 */
9214 uint64_t const fCaps = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64EptVpidCaps;
9215 bool const fInveptSupported = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVEPT);
9216 bool const fTypeSingleCtx = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVEPT_SINGLE_CTX);
9217 bool const fTypeAllCtx = RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_INVEPT_ALL_CTX);
9218
9219 bool afSupportedTypes[4];
9220 afSupportedTypes[0] = false;
9221 afSupportedTypes[1] = fTypeSingleCtx;
9222 afSupportedTypes[2] = fTypeAllCtx;
9223 afSupportedTypes[3] = false;
9224
9225 if ( fInveptSupported
9226 && !(u64InveptType & ~(uint64_t)VMX_INVEPT_VALID_MASK)
9227 && afSupportedTypes[u64InveptType & 3])
9228 { /* likely */ }
9229 else
9230 {
9231 Log(("invept: invalid/unsupported invvpid type %#x -> VMFail\n", u64InveptType));
9232 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invept_TypeInvalid;
9233 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = u64InveptType;
9234 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
9235 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9236 }
9237
9238 /*
9239 * Fetch the invept descriptor from guest memory.
9240 */
9241 RTUINT128U uDesc;
9242 VBOXSTRICTRC rcStrict = iemMemFetchDataU128(pVCpu, &uDesc, iEffSeg, GCPtrInveptDesc);
9243 if (rcStrict == VINF_SUCCESS)
9244 {
9245 /*
9246 * Validate the descriptor.
9247 *
9248 * The Intel spec. does not explicit say the INVEPT instruction fails when reserved
9249 * bits in the descriptor are set, but it -does- for INVVPID. Until we test on real
9250 * hardware, it's assumed INVEPT behaves the same as INVVPID in this regard. It's
9251 * better to be strict in our emulation until proven otherwise.
9252 */
9253 if (uDesc.s.Hi)
9254 {
9255 Log(("invept: reserved bits set in invept descriptor %#RX64 -> VMFail\n", uDesc.s.Hi));
9256 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invept_DescRsvd;
9257 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = uDesc.s.Hi;
9258 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
9259 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9260 }
9261
9262 /*
9263 * Flush TLB mappings based on the EPT type.
9264 */
9265 if (u64InveptType == VMXTLBFLUSHEPT_SINGLE_CONTEXT)
9266 {
9267 uint64_t const GCPhysEptPtr = uDesc.s.Lo;
9268 int const rc = iemVmxVmentryCheckEptPtr(pVCpu, GCPhysEptPtr, NULL /* enmDiag */);
9269 if (RT_SUCCESS(rc))
9270 { /* likely */ }
9271 else
9272 {
9273 Log(("invept: EPTP invalid %#RX64 -> VMFail\n", GCPhysEptPtr));
9274 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Invept_EptpInvalid;
9275 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysEptPtr;
9276 iemVmxVmFail(pVCpu, VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND);
9277 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9278 }
9279 }
9280
9281 /** @todo PGM support for EPT tags? Currently just flush everything. */
9282 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
9283 uint64_t const uCr3 = pVCpu->cpum.GstCtx.cr3;
9284 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
9285
9286 iemVmxVmSucceed(pVCpu);
9287 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9288 }
9289
9290 return rcStrict;
9291}
9292
9293
9294/**
9295 * Interface for HM and EM to emulate the INVEPT instruction.
9296 *
9297 * @returns Strict VBox status code.
9298 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
9299 * @param pExitInfo Pointer to the VM-exit information.
9300 * @thread EMT(pVCpu)
9301 */
9302VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvept(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo)
9303{
9304 IEMEXEC_ASSERT_INSTR_LEN_RETURN(pExitInfo->cbInstr, 4);
9305 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI);
9306 Assert(pExitInfo);
9307
9308 iemInitExec(pVCpu, false /*fBypassHandlers*/);
9309
9310 uint8_t const iEffSeg = pExitInfo->InstrInfo.Inv.iSegReg;
9311 uint8_t const cbInstr = pExitInfo->cbInstr;
9312 RTGCPTR const GCPtrInveptDesc = pExitInfo->GCPtrEffAddr;
9313 uint64_t const u64InveptType = pVCpu->iem.s.enmCpuMode == IEMMODE_64BIT
9314 ? iemGRegFetchU64(pVCpu, pExitInfo->InstrInfo.Inv.iReg2)
9315 : iemGRegFetchU32(pVCpu, pExitInfo->InstrInfo.Inv.iReg2);
9316 VBOXSTRICTRC rcStrict = iemVmxInvept(pVCpu, cbInstr, iEffSeg, GCPtrInveptDesc, u64InveptType, pExitInfo);
9317 Assert(!pVCpu->iem.s.cActiveMappings);
9318 return iemUninitExecAndFiddleStatusAndMaybeReenter(pVCpu, rcStrict);
9319}
9320
9321#endif /* VBOX_WITH_NESTED_HWVIRT_VMX_EPT */
9322
9323/**
9324 * VMXON instruction execution worker.
9325 *
9326 * @returns Strict VBox status code.
9327 * @param pVCpu The cross context virtual CPU structure.
9328 * @param cbInstr The instruction length in bytes.
9329 * @param iEffSeg The effective segment register to use with @a
9330 * GCPtrVmxon.
9331 * @param GCPtrVmxon The linear address of the VMXON pointer.
9332 * @param pExitInfo Pointer to the VM-exit information. Optional, can be NULL.
9333 *
9334 * @remarks Common VMX instruction checks are already expected to by the caller,
9335 * i.e. CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
9336 */
9337static VBOXSTRICTRC iemVmxVmxon(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg,
9338 RTGCPHYS GCPtrVmxon, PCVMXVEXITINFO pExitInfo) RT_NOEXCEPT
9339{
9340 if (!IEM_VMX_IS_ROOT_MODE(pVCpu))
9341 {
9342 /* CPL. */
9343 if (pVCpu->iem.s.uCpl == 0)
9344 { /* likely */ }
9345 else
9346 {
9347 Log(("vmxon: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
9348 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_Cpl;
9349 return iemRaiseGeneralProtectionFault0(pVCpu);
9350 }
9351
9352 /* A20M (A20 Masked) mode. */
9353 if (PGMPhysIsA20Enabled(pVCpu))
9354 { /* likely */ }
9355 else
9356 {
9357 Log(("vmxon: A20M mode -> #GP(0)\n"));
9358 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_A20M;
9359 return iemRaiseGeneralProtectionFault0(pVCpu);
9360 }
9361
9362 /* CR0. */
9363 {
9364 /*
9365 * CR0 MB1 bits.
9366 *
9367 * We use VMX_V_CR0_FIXED0 below to ensure CR0.PE and CR0.PG are always set
9368 * while executing VMXON. CR0.PE and CR0.PG are only allowed to be clear
9369 * when the guest running in VMX non-root mode with unrestricted-guest control
9370 * enabled in the VMCS.
9371 */
9372 uint64_t const uCr0Fixed0 = VMX_V_CR0_FIXED0;
9373 if ((pVCpu->cpum.GstCtx.cr0 & uCr0Fixed0) == uCr0Fixed0)
9374 { /* likely */ }
9375 else
9376 {
9377 Log(("vmxon: CR0 fixed0 bits cleared -> #GP(0)\n"));
9378 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_Cr0Fixed0;
9379 return iemRaiseGeneralProtectionFault0(pVCpu);
9380 }
9381
9382 /* CR0 MBZ bits. */
9383 uint64_t const uCr0Fixed1 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr0Fixed1;
9384 if (!(pVCpu->cpum.GstCtx.cr0 & ~uCr0Fixed1))
9385 { /* likely */ }
9386 else
9387 {
9388 Log(("vmxon: CR0 fixed1 bits set -> #GP(0)\n"));
9389 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_Cr0Fixed1;
9390 return iemRaiseGeneralProtectionFault0(pVCpu);
9391 }
9392 }
9393
9394 /* CR4. */
9395 {
9396 /* CR4 MB1 bits. */
9397 uint64_t const uCr4Fixed0 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed0;
9398 if ((pVCpu->cpum.GstCtx.cr4 & uCr4Fixed0) == uCr4Fixed0)
9399 { /* likely */ }
9400 else
9401 {
9402 Log(("vmxon: CR4 fixed0 bits cleared -> #GP(0)\n"));
9403 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_Cr4Fixed0;
9404 return iemRaiseGeneralProtectionFault0(pVCpu);
9405 }
9406
9407 /* CR4 MBZ bits. */
9408 uint64_t const uCr4Fixed1 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed1;
9409 if (!(pVCpu->cpum.GstCtx.cr4 & ~uCr4Fixed1))
9410 { /* likely */ }
9411 else
9412 {
9413 Log(("vmxon: CR4 fixed1 bits set -> #GP(0)\n"));
9414 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_Cr4Fixed1;
9415 return iemRaiseGeneralProtectionFault0(pVCpu);
9416 }
9417 }
9418
9419 /* Feature control MSR's LOCK and VMXON bits. */
9420 uint64_t const uMsrFeatCtl = CPUMGetGuestIa32FeatCtrl(pVCpu);
9421 if ((uMsrFeatCtl & (MSR_IA32_FEATURE_CONTROL_LOCK | MSR_IA32_FEATURE_CONTROL_VMXON))
9422 == (MSR_IA32_FEATURE_CONTROL_LOCK | MSR_IA32_FEATURE_CONTROL_VMXON))
9423 { /* likely */ }
9424 else
9425 {
9426 Log(("vmxon: Feature control lock bit or VMXON bit cleared -> #GP(0)\n"));
9427 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_MsrFeatCtl;
9428 return iemRaiseGeneralProtectionFault0(pVCpu);
9429 }
9430
9431 /* Get the VMXON pointer from the location specified by the source memory operand. */
9432 RTGCPHYS GCPhysVmxon;
9433 VBOXSTRICTRC rcStrict = iemMemFetchDataU64(pVCpu, &GCPhysVmxon, iEffSeg, GCPtrVmxon);
9434 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9435 { /* likely */ }
9436 else
9437 {
9438 Log(("vmxon: Failed to read VMXON region physaddr from %#RGv, rc=%Rrc\n", GCPtrVmxon, VBOXSTRICTRC_VAL(rcStrict)));
9439 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_PtrMap;
9440 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPtrVmxon;
9441 return rcStrict;
9442 }
9443
9444 /* VMXON region pointer alignment. */
9445 if (!(GCPhysVmxon & X86_PAGE_4K_OFFSET_MASK))
9446 { /* likely */ }
9447 else
9448 {
9449 Log(("vmxon: VMXON region pointer not page-aligned -> VMFailInvalid\n"));
9450 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_PtrAlign;
9451 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmxon;
9452 iemVmxVmFailInvalid(pVCpu);
9453 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9454 }
9455
9456 /* VMXON physical-address width limits. */
9457 if (!(GCPhysVmxon >> IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cVmxMaxPhysAddrWidth))
9458 { /* likely */ }
9459 else
9460 {
9461 Log(("vmxon: VMXON region pointer extends beyond physical-address width -> VMFailInvalid\n"));
9462 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_PtrWidth;
9463 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmxon;
9464 iemVmxVmFailInvalid(pVCpu);
9465 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9466 }
9467
9468 /* Ensure VMXON region is not MMIO, ROM etc. This is not an Intel requirement but a
9469 restriction imposed by our implementation. */
9470 if (PGMPhysIsGCPhysNormal(pVCpu->CTX_SUFF(pVM), GCPhysVmxon))
9471 { /* likely */ }
9472 else
9473 {
9474 Log(("vmxon: VMXON region not normal memory -> VMFailInvalid\n"));
9475 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_PtrAbnormal;
9476 pVCpu->cpum.GstCtx.hwvirt.vmx.uDiagAux = GCPhysVmxon;
9477 iemVmxVmFailInvalid(pVCpu);
9478 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9479 }
9480
9481 /* Read the VMCS revision ID from the VMXON region. */
9482 VMXVMCSREVID VmcsRevId;
9483 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &VmcsRevId, GCPhysVmxon, sizeof(VmcsRevId));
9484 if (RT_SUCCESS(rc))
9485 { /* likely */ }
9486 else
9487 {
9488 Log(("vmxon: Failed to read VMXON region at %#RGp, rc=%Rrc\n", GCPhysVmxon, rc));
9489 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_PtrReadPhys;
9490 return rc;
9491 }
9492
9493 /* Verify the VMCS revision specified by the guest matches what we reported to the guest. */
9494 if (RT_LIKELY(VmcsRevId.u == VMX_V_VMCS_REVISION_ID))
9495 { /* likely */ }
9496 else
9497 {
9498 /* Revision ID mismatch. */
9499 if (!VmcsRevId.n.fIsShadowVmcs)
9500 {
9501 Log(("vmxon: VMCS revision mismatch, expected %#RX32 got %#RX32 -> VMFailInvalid\n", VMX_V_VMCS_REVISION_ID,
9502 VmcsRevId.n.u31RevisionId));
9503 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_VmcsRevId;
9504 iemVmxVmFailInvalid(pVCpu);
9505 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9506 }
9507
9508 /* Shadow VMCS disallowed. */
9509 Log(("vmxon: Shadow VMCS -> VMFailInvalid\n"));
9510 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_ShadowVmcs;
9511 iemVmxVmFailInvalid(pVCpu);
9512 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9513 }
9514
9515 /*
9516 * Record that we're in VMX operation, block INIT, block and disable A20M.
9517 */
9518 pVCpu->cpum.GstCtx.hwvirt.vmx.GCPhysVmxon = GCPhysVmxon;
9519 IEM_VMX_CLEAR_CURRENT_VMCS(pVCpu);
9520 pVCpu->cpum.GstCtx.hwvirt.vmx.fInVmxRootMode = true;
9521
9522 /* Clear address-range monitoring. */
9523 EMMonitorWaitClear(pVCpu);
9524 /** @todo NSTVMX: Intel PT. */
9525
9526 iemVmxVmSucceed(pVCpu);
9527 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9528 }
9529 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
9530 {
9531 /* Nested-guest intercept. */
9532 if (pExitInfo)
9533 return iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
9534 return iemVmxVmexitInstrNeedsInfo(pVCpu, VMX_EXIT_VMXON, VMXINSTRID_NONE, cbInstr);
9535 }
9536
9537 Assert(IEM_VMX_IS_ROOT_MODE(pVCpu));
9538
9539 /* CPL. */
9540 if (pVCpu->iem.s.uCpl > 0)
9541 {
9542 Log(("vmxon: In VMX root mode: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
9543 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_VmxRootCpl;
9544 return iemRaiseGeneralProtectionFault0(pVCpu);
9545 }
9546
9547 /* VMXON when already in VMX root mode. */
9548 iemVmxVmFail(pVCpu, VMXINSTRERR_VMXON_IN_VMXROOTMODE);
9549 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxon_VmxAlreadyRoot;
9550 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9551}
9552
9553
9554/**
9555 * Interface for HM and EM to emulate the VMXON instruction.
9556 *
9557 * @returns Strict VBox status code.
9558 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
9559 * @param pExitInfo Pointer to the VM-exit information.
9560 * @thread EMT(pVCpu)
9561 */
9562VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmxon(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo)
9563{
9564 Assert(pExitInfo);
9565 IEMEXEC_ASSERT_INSTR_LEN_RETURN(pExitInfo->cbInstr, 3);
9566 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI);
9567
9568 iemInitExec(pVCpu, false /*fBypassHandlers*/);
9569
9570 uint8_t const iEffSeg = pExitInfo->InstrInfo.VmxXsave.iSegReg;
9571 uint8_t const cbInstr = pExitInfo->cbInstr;
9572 RTGCPTR const GCPtrVmxon = pExitInfo->GCPtrEffAddr;
9573 VBOXSTRICTRC rcStrict = iemVmxVmxon(pVCpu, cbInstr, iEffSeg, GCPtrVmxon, pExitInfo);
9574 Assert(!pVCpu->iem.s.cActiveMappings);
9575 return iemUninitExecAndFiddleStatusAndMaybeReenter(pVCpu, rcStrict);
9576}
9577
9578
9579/**
9580 * Implements 'VMXOFF'.
9581 *
9582 * @remarks Common VMX instruction checks are already expected to by the caller,
9583 * i.e. CR4.VMXE, Real/V86 mode, EFER/CS.L checks.
9584 */
9585IEM_CIMPL_DEF_0(iemCImpl_vmxoff)
9586{
9587 /* Nested-guest intercept. */
9588 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
9589 return iemVmxVmexitInstr(pVCpu, VMX_EXIT_VMXOFF, cbInstr);
9590
9591 /* CPL. */
9592 if (pVCpu->iem.s.uCpl == 0)
9593 { /* likely */ }
9594 else
9595 {
9596 Log(("vmxoff: CPL %u -> #GP(0)\n", pVCpu->iem.s.uCpl));
9597 pVCpu->cpum.GstCtx.hwvirt.vmx.enmDiag = kVmxVDiag_Vmxoff_Cpl;
9598 return iemRaiseGeneralProtectionFault0(pVCpu);
9599 }
9600
9601 /* Dual monitor treatment of SMIs and SMM. */
9602 uint64_t const fSmmMonitorCtl = CPUMGetGuestIa32SmmMonitorCtl(pVCpu);
9603 if (!(fSmmMonitorCtl & MSR_IA32_SMM_MONITOR_VALID))
9604 { /* likely */ }
9605 else
9606 {
9607 iemVmxVmFail(pVCpu, VMXINSTRERR_VMXOFF_DUAL_MON);
9608 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9609 }
9610
9611 /* Record that we're no longer in VMX root operation, block INIT, block and disable A20M. */
9612 pVCpu->cpum.GstCtx.hwvirt.vmx.fInVmxRootMode = false;
9613 Assert(!pVCpu->cpum.GstCtx.hwvirt.vmx.fInVmxNonRootMode);
9614
9615 if (fSmmMonitorCtl & MSR_IA32_SMM_MONITOR_VMXOFF_UNBLOCK_SMI)
9616 { /** @todo NSTVMX: Unblock SMI. */ }
9617
9618 EMMonitorWaitClear(pVCpu);
9619 /** @todo NSTVMX: Unblock and enable A20M. */
9620
9621 iemVmxVmSucceed(pVCpu);
9622 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9623}
9624
9625
9626/**
9627 * Interface for HM and EM to emulate the VMXOFF instruction.
9628 *
9629 * @returns Strict VBox status code.
9630 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
9631 * @param cbInstr The instruction length in bytes.
9632 * @thread EMT(pVCpu)
9633 */
9634VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmxoff(PVMCPUCC pVCpu, uint8_t cbInstr)
9635{
9636 IEMEXEC_ASSERT_INSTR_LEN_RETURN(cbInstr, 3);
9637 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI);
9638
9639 iemInitExec(pVCpu, false /*fBypassHandlers*/);
9640 VBOXSTRICTRC rcStrict = IEM_CIMPL_CALL_0(iemCImpl_vmxoff);
9641 Assert(!pVCpu->iem.s.cActiveMappings);
9642 return iemUninitExecAndFiddleStatusAndMaybeReenter(pVCpu, rcStrict);
9643}
9644
9645
9646/**
9647 * Implements 'VMXON'.
9648 */
9649IEM_CIMPL_DEF_2(iemCImpl_vmxon, uint8_t, iEffSeg, RTGCPTR, GCPtrVmxon)
9650{
9651 return iemVmxVmxon(pVCpu, cbInstr, iEffSeg, GCPtrVmxon, NULL /* pExitInfo */);
9652}
9653
9654
9655/**
9656 * Implements 'VMLAUNCH'.
9657 */
9658IEM_CIMPL_DEF_0(iemCImpl_vmlaunch)
9659{
9660 return iemVmxVmlaunchVmresume(pVCpu, cbInstr, VMXINSTRID_VMLAUNCH);
9661}
9662
9663
9664/**
9665 * Implements 'VMRESUME'.
9666 */
9667IEM_CIMPL_DEF_0(iemCImpl_vmresume)
9668{
9669 return iemVmxVmlaunchVmresume(pVCpu, cbInstr, VMXINSTRID_VMRESUME);
9670}
9671
9672
9673/**
9674 * Implements 'VMPTRLD'.
9675 */
9676IEM_CIMPL_DEF_2(iemCImpl_vmptrld, uint8_t, iEffSeg, RTGCPTR, GCPtrVmcs)
9677{
9678 return iemVmxVmptrld(pVCpu, cbInstr, iEffSeg, GCPtrVmcs, NULL /* pExitInfo */);
9679}
9680
9681
9682/**
9683 * Implements 'VMPTRST'.
9684 */
9685IEM_CIMPL_DEF_2(iemCImpl_vmptrst, uint8_t, iEffSeg, RTGCPTR, GCPtrVmcs)
9686{
9687 return iemVmxVmptrst(pVCpu, cbInstr, iEffSeg, GCPtrVmcs, NULL /* pExitInfo */);
9688}
9689
9690
9691/**
9692 * Implements 'VMCLEAR'.
9693 */
9694IEM_CIMPL_DEF_2(iemCImpl_vmclear, uint8_t, iEffSeg, RTGCPTR, GCPtrVmcs)
9695{
9696 return iemVmxVmclear(pVCpu, cbInstr, iEffSeg, GCPtrVmcs, NULL /* pExitInfo */);
9697}
9698
9699
9700/**
9701 * Implements 'VMWRITE' register.
9702 */
9703IEM_CIMPL_DEF_2(iemCImpl_vmwrite_reg, uint64_t, u64Val, uint64_t, u64VmcsField)
9704{
9705 return iemVmxVmwrite(pVCpu, cbInstr, UINT8_MAX /* iEffSeg */, u64Val, u64VmcsField, NULL /* pExitInfo */);
9706}
9707
9708
9709/**
9710 * Implements 'VMWRITE' memory.
9711 */
9712IEM_CIMPL_DEF_3(iemCImpl_vmwrite_mem, uint8_t, iEffSeg, RTGCPTR, GCPtrVal, uint32_t, u64VmcsField)
9713{
9714 return iemVmxVmwrite(pVCpu, cbInstr, iEffSeg, GCPtrVal, u64VmcsField, NULL /* pExitInfo */);
9715}
9716
9717
9718/**
9719 * Implements 'VMREAD' register (64-bit).
9720 */
9721IEM_CIMPL_DEF_2(iemCImpl_vmread_reg64, uint64_t *, pu64Dst, uint64_t, u64VmcsField)
9722{
9723 return iemVmxVmreadReg64(pVCpu, cbInstr, pu64Dst, u64VmcsField, NULL /* pExitInfo */);
9724}
9725
9726
9727/**
9728 * Implements 'VMREAD' register (32-bit).
9729 */
9730IEM_CIMPL_DEF_2(iemCImpl_vmread_reg32, uint32_t *, pu32Dst, uint32_t, u32VmcsField)
9731{
9732 return iemVmxVmreadReg32(pVCpu, cbInstr, pu32Dst, u32VmcsField, NULL /* pExitInfo */);
9733}
9734
9735
9736/**
9737 * Implements 'VMREAD' memory, 64-bit register.
9738 */
9739IEM_CIMPL_DEF_3(iemCImpl_vmread_mem_reg64, uint8_t, iEffSeg, RTGCPTR, GCPtrDst, uint32_t, u64VmcsField)
9740{
9741 return iemVmxVmreadMem(pVCpu, cbInstr, iEffSeg, GCPtrDst, u64VmcsField, NULL /* pExitInfo */);
9742}
9743
9744
9745/**
9746 * Implements 'VMREAD' memory, 32-bit register.
9747 */
9748IEM_CIMPL_DEF_3(iemCImpl_vmread_mem_reg32, uint8_t, iEffSeg, RTGCPTR, GCPtrDst, uint32_t, u32VmcsField)
9749{
9750 return iemVmxVmreadMem(pVCpu, cbInstr, iEffSeg, GCPtrDst, u32VmcsField, NULL /* pExitInfo */);
9751}
9752
9753
9754/**
9755 * Implements 'INVVPID'.
9756 */
9757IEM_CIMPL_DEF_3(iemCImpl_invvpid, uint8_t, iEffSeg, RTGCPTR, GCPtrInvvpidDesc, uint64_t, uInvvpidType)
9758{
9759 return iemVmxInvvpid(pVCpu, cbInstr, iEffSeg, GCPtrInvvpidDesc, uInvvpidType, NULL /* pExitInfo */);
9760}
9761
9762
9763#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
9764/**
9765 * Implements 'INVEPT'.
9766 */
9767IEM_CIMPL_DEF_3(iemCImpl_invept, uint8_t, iEffSeg, RTGCPTR, GCPtrInveptDesc, uint64_t, uInveptType)
9768{
9769 return iemVmxInvept(pVCpu, cbInstr, iEffSeg, GCPtrInveptDesc, uInveptType, NULL /* pExitInfo */);
9770}
9771#endif
9772
9773
9774/**
9775 * Implements VMX's implementation of PAUSE.
9776 */
9777IEM_CIMPL_DEF_0(iemCImpl_vmx_pause)
9778{
9779 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
9780 {
9781 VBOXSTRICTRC rcStrict = iemVmxVmexitInstrPause(pVCpu, cbInstr);
9782 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
9783 return rcStrict;
9784 }
9785
9786 /*
9787 * Outside VMX non-root operation or if the PAUSE instruction does not cause
9788 * a VM-exit, the instruction operates normally.
9789 */
9790 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9791}
9792
9793#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
9794
9795
9796/**
9797 * Implements 'VMCALL'.
9798 */
9799IEM_CIMPL_DEF_0(iemCImpl_vmcall)
9800{
9801 pVCpu->iem.s.cPotentialExits++;
9802
9803#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9804 /* Nested-guest intercept. */
9805 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
9806 return iemVmxVmexitInstr(pVCpu, VMX_EXIT_VMCALL, cbInstr);
9807#endif
9808
9809 /* Join forces with vmmcall. */
9810 return IEM_CIMPL_CALL_1(iemCImpl_Hypercall, OP_VMCALL);
9811}
9812
9813
9814#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9815
9816/**
9817 * @callback_method_impl{FNPGMPHYSHANDLER, VMX APIC-access page accesses}
9818 *
9819 * @remarks The @a uUser argument is currently unused.
9820 */
9821DECLCALLBACK(VBOXSTRICTRC) iemVmxApicAccessPageHandler(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhysFault, void *pvPhys,
9822 void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType,
9823 PGMACCESSORIGIN enmOrigin, uint64_t uUser)
9824{
9825 RT_NOREF3(pvPhys, enmOrigin, uUser);
9826
9827 RTGCPHYS const GCPhysAccessBase = GCPhysFault & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
9828 if (CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu)))
9829 {
9830 Assert(CPUMIsGuestVmxProcCtls2Set(IEM_GET_CTX(pVCpu), VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
9831 Assert(CPUMGetGuestVmxApicAccessPageAddrEx(IEM_GET_CTX(pVCpu)) == GCPhysAccessBase);
9832
9833 uint32_t const fAccess = enmAccessType == PGMACCESSTYPE_WRITE ? IEM_ACCESS_DATA_W : IEM_ACCESS_DATA_R;
9834 uint16_t const offAccess = GCPhysFault & GUEST_PAGE_OFFSET_MASK;
9835
9836 LogFlowFunc(("Fault at %#RGp (cbBuf=%u fAccess=%#x)\n", GCPhysFault, cbBuf, fAccess));
9837 VBOXSTRICTRC rcStrict = iemVmxVirtApicAccessMem(pVCpu, offAccess, cbBuf, pvBuf, fAccess);
9838 if (RT_FAILURE(rcStrict))
9839 return rcStrict;
9840
9841 /* Any access on this APIC-access page has been handled, caller should not carry out the access. */
9842 return VINF_SUCCESS;
9843 }
9844
9845 LogFunc(("Accessed outside VMX non-root mode, deregistering page handler for %#RGp\n", GCPhysAccessBase));
9846 int rc = PGMHandlerPhysicalDeregister(pVM, GCPhysAccessBase);
9847 if (RT_FAILURE(rc))
9848 return rc;
9849
9850 /* Instruct the caller of this handler to perform the read/write as normal memory. */
9851 return VINF_PGM_HANDLER_DO_DEFAULT;
9852}
9853
9854
9855# ifndef IN_RING3
9856/**
9857 * @callback_method_impl{FNPGMRZPHYSPFHANDLER,
9858 * \#PF access handler callback for guest VMX APIC-access page.}
9859 */
9860DECLCALLBACK(VBOXSTRICTRC) iemVmxApicAccessPagePfHandler(PVMCC pVM, PVMCPUCC pVCpu, RTGCUINT uErr, PCPUMCTX pCtx,
9861 RTGCPTR pvFault, RTGCPHYS GCPhysFault, uint64_t uUser)
9862
9863{
9864 RT_NOREF3(pVM, pCtx, uUser);
9865
9866 /*
9867 * Handle the VMX APIC-access page only when the guest is in VMX non-root mode.
9868 * Otherwise we must deregister the page and allow regular RAM access.
9869 * Failing to do so lands us with endless EPT VM-exits.
9870 */
9871 RTGCPHYS const GCPhysPage = GCPhysFault & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
9872 if (CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu)))
9873 {
9874 Assert(CPUMIsGuestVmxProcCtls2Set(IEM_GET_CTX(pVCpu), VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
9875 Assert(CPUMGetGuestVmxApicAccessPageAddrEx(IEM_GET_CTX(pVCpu)) == GCPhysPage);
9876
9877 /*
9878 * Check if the access causes an APIC-access VM-exit.
9879 */
9880 uint32_t fAccess;
9881 if (uErr & X86_TRAP_PF_ID)
9882 fAccess = IEM_ACCESS_INSTRUCTION;
9883 else if (uErr & X86_TRAP_PF_RW)
9884 fAccess = IEM_ACCESS_DATA_W;
9885 else
9886 fAccess = IEM_ACCESS_DATA_R;
9887
9888 RTGCPHYS const GCPhysNestedFault = (RTGCPHYS)pvFault;
9889 uint16_t const offAccess = GCPhysNestedFault & GUEST_PAGE_OFFSET_MASK;
9890 bool const fIntercept = iemVmxVirtApicIsMemAccessIntercepted(pVCpu, offAccess, 1 /* cbAccess */, fAccess);
9891 LogFlowFunc(("#PF at %#RGp (GCPhysNestedFault=%#RGp offAccess=%#x)\n", GCPhysFault, GCPhysNestedFault, offAccess));
9892 if (fIntercept)
9893 {
9894 /*
9895 * Query the source VM-exit (from the execution engine) that caused this access
9896 * within the APIC-access page. Currently only HM is supported.
9897 */
9898 AssertMsg(VM_IS_HM_ENABLED(pVM),
9899 ("VM-exit auxiliary info. fetching not supported for execution engine %d\n", pVM->bMainExecutionEngine));
9900
9901 HMEXITAUX HmExitAux;
9902 RT_ZERO(HmExitAux);
9903 int const rc = HMR0GetExitAuxInfo(pVCpu, &HmExitAux, HMVMX_READ_EXIT_INSTR_LEN
9904 | HMVMX_READ_EXIT_QUALIFICATION
9905 | HMVMX_READ_IDT_VECTORING_INFO
9906 | HMVMX_READ_IDT_VECTORING_ERROR_CODE);
9907 AssertRC(rc);
9908
9909 /*
9910 * Verify the VM-exit reason must be an EPT violation.
9911 * Other accesses should go through the other handler (iemVmxApicAccessPageHandler).
9912 * Refer to @bugref{10092#c33s} for a more detailed explanation.
9913 */
9914 AssertMsgReturn(HmExitAux.Vmx.uReason == VMX_EXIT_EPT_VIOLATION,
9915 ("Unexpected call to APIC-access page #PF handler for %#RGp offAcesss=%u uErr=%#RGx uReason=%u\n",
9916 GCPhysPage, offAccess, uErr, HmExitAux.Vmx.uReason), VERR_IEM_IPE_7);
9917
9918 /*
9919 * Construct the virtual APIC-access VM-exit.
9920 */
9921 VMXAPICACCESS enmAccess;
9922 if (HmExitAux.Vmx.u64Qual & VMX_EXIT_QUAL_EPT_LINEAR_ADDR_VALID)
9923 {
9924 if (VMX_IDT_VECTORING_INFO_IS_VALID(HmExitAux.Vmx.uIdtVectoringInfo))
9925 enmAccess = VMXAPICACCESS_LINEAR_EVENT_DELIVERY;
9926 else if (fAccess == IEM_ACCESS_INSTRUCTION)
9927 enmAccess = VMXAPICACCESS_LINEAR_INSTR_FETCH;
9928 else if (fAccess & IEM_ACCESS_TYPE_WRITE)
9929 enmAccess = VMXAPICACCESS_LINEAR_WRITE;
9930 else
9931 enmAccess = VMXAPICACCESS_LINEAR_READ;
9932
9933 /* For linear-address accesss the instruction length must be valid. */
9934 AssertMsg(HmExitAux.Vmx.cbInstr > 0,
9935 ("Invalid APIC-access VM-exit instruction length. cbInstr=%u\n", HmExitAux.Vmx.cbInstr));
9936 }
9937 else
9938 {
9939 if (VMX_IDT_VECTORING_INFO_IS_VALID(HmExitAux.Vmx.uIdtVectoringInfo))
9940 enmAccess = VMXAPICACCESS_PHYSICAL_EVENT_DELIVERY;
9941 else
9942 {
9943 /** @todo How to distinguish between monitoring/trace vs other instructions
9944 * here? */
9945 enmAccess = VMXAPICACCESS_PHYSICAL_INSTR;
9946 }
9947
9948 /* For physical accesses the instruction length is undefined, we zero it for safety and consistency. */
9949 HmExitAux.Vmx.cbInstr = 0;
9950 }
9951
9952 /*
9953 * Raise the APIC-access VM-exit.
9954 */
9955 LogFlowFunc(("Raising APIC-access VM-exit from #PF handler at offset %#x\n", offAccess));
9956 VMXVEXITINFO const ExitInfo
9957 = VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN(VMX_EXIT_APIC_ACCESS,
9958 RT_BF_MAKE(VMX_BF_EXIT_QUAL_APIC_ACCESS_OFFSET, offAccess)
9959 | RT_BF_MAKE(VMX_BF_EXIT_QUAL_APIC_ACCESS_TYPE, enmAccess),
9960 HmExitAux.Vmx.cbInstr);
9961 VMXVEXITEVENTINFO const ExitEventInfo = VMXVEXITEVENTINFO_INIT_ONLY_IDT(HmExitAux.Vmx.uIdtVectoringInfo,
9962 HmExitAux.Vmx.uIdtVectoringErrCode);
9963 VBOXSTRICTRC const rcStrict = iemVmxVmexitApicAccessWithInfo(pVCpu, &ExitInfo, &ExitEventInfo);
9964 return iemExecStatusCodeFiddling(pVCpu, rcStrict);
9965 }
9966
9967 /*
9968 * The access isn't intercepted, which means it needs to be virtualized.
9969 *
9970 * This requires emulating the instruction because we need the bytes being
9971 * read/written by the instruction not just the offset being accessed within
9972 * the APIC-access page (which we derive from the faulting address).
9973 */
9974 LogFlowFunc(("Access at offset %#x not intercepted -> VINF_EM_RAW_EMULATE_INSTR\n", offAccess));
9975 return VINF_EM_RAW_EMULATE_INSTR;
9976 }
9977
9978 /** @todo This isn't ideal but works for now as nested-hypervisors generally play
9979 * nice because the spec states that this page should be modified only when
9980 * no CPU refers to it VMX non-root mode. Nonetheless, we could use an atomic
9981 * reference counter to ensure the aforementioned condition before
9982 * de-registering the page. */
9983 LogFunc(("Accessed outside VMX non-root mode, deregistering page handler for %#RGp\n", GCPhysPage));
9984 int const rc = PGMHandlerPhysicalDeregister(pVM, GCPhysPage);
9985 if (RT_FAILURE(rc))
9986 return rc;
9987
9988 return VINF_SUCCESS;
9989}
9990# endif /* !IN_RING3 */
9991
9992#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
9993
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