VirtualBox

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

Last change on this file since 100096 was 100052, checked in by vboxsync, 23 months ago

VMM/IEM: Refactored the enmCpuMode, uCpl, fBypassHandlers, fDisregardLock and fPendingInstruction* IEMCPU members into a single fExec member and associated IEM_F_XXX flag defines. Added more flags needed for recompiled execution. The fExec value is maintained as code is executed, so it does not need to be recalculated in the instruction loops. bugref:10369

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette