VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp@ 105125

Last change on this file since 105125 was 105125, checked in by vboxsync, 7 months ago

VMM/IEM,ValKit/bs3-cpu-weird-1: Fixed popf mistreatment of the new TF bit generally and the calculation of the VIF flags in VME+v86 mode; extended bs3-cpu-weird-1 with popf testcase. bugref:10715

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 390.8 KB
Line 
1/* $Id: IEMAllCImpl.cpp 105125 2024-07-03 20:07:48Z vboxsync $ */
2/** @file
3 * IEM - Instruction Implementation in C/C++ (code include).
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
33#define VMCPU_INCL_CPUM_GST_CTX
34#define IEM_WITH_OPAQUE_DECODER_STATE
35#include <VBox/vmm/iem.h>
36#include <VBox/vmm/cpum.h>
37#include <VBox/vmm/apic.h>
38#include <VBox/vmm/pdm.h>
39#include <VBox/vmm/pgm.h>
40#include <VBox/vmm/iom.h>
41#include <VBox/vmm/em.h>
42#include <VBox/vmm/hm.h>
43#include <VBox/vmm/nem.h>
44#include <VBox/vmm/gim.h>
45#include <VBox/vmm/gcm.h>
46#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
47# include <VBox/vmm/em.h>
48# include <VBox/vmm/hm_svm.h>
49#endif
50#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
51# include <VBox/vmm/hmvmxinline.h>
52#endif
53#ifndef VBOX_WITHOUT_CPUID_HOST_CALL
54# include <VBox/vmm/cpuidcall.h>
55#endif
56#include <VBox/vmm/tm.h>
57#include <VBox/vmm/dbgf.h>
58#include <VBox/vmm/dbgftrace.h>
59#include "IEMInternal.h"
60#include <VBox/vmm/vmcc.h>
61#include <VBox/log.h>
62#include <VBox/err.h>
63#include <VBox/param.h>
64#include <VBox/dis.h>
65#include <iprt/asm-math.h>
66#include <iprt/assert.h>
67#include <iprt/string.h>
68#include <iprt/x86.h>
69
70#include "IEMInline.h"
71
72
73/*********************************************************************************************************************************
74* Defined Constants And Macros *
75*********************************************************************************************************************************/
76/**
77 * Flushes the prefetch buffer, light version.
78 * @todo The \#if conditions here must match the ones in iemOpcodeFlushLight().
79 */
80#ifndef IEM_WITH_CODE_TLB
81# define IEM_FLUSH_PREFETCH_LIGHT(a_pVCpu, a_cbInstr) iemOpcodeFlushLight(a_pVCpu, a_cbInstr)
82#else
83# define IEM_FLUSH_PREFETCH_LIGHT(a_pVCpu, a_cbInstr) do { } while (0)
84#endif
85
86/**
87 * Flushes the prefetch buffer, heavy version.
88 * @todo The \#if conditions here must match the ones in iemOpcodeFlushHeavy().
89 */
90#if !defined(IEM_WITH_CODE_TLB) || 1
91# define IEM_FLUSH_PREFETCH_HEAVY(a_pVCpu, a_cbInstr) iemOpcodeFlushHeavy(a_pVCpu, a_cbInstr)
92#else
93# define IEM_FLUSH_PREFETCH_HEAVY(a_pVCpu, a_cbInstr) do { } while (0)
94#endif
95
96
97
98/** @name Misc Helpers
99 * @{
100 */
101
102
103/**
104 * Worker function for iemHlpCheckPortIOPermission, don't call directly.
105 *
106 * @returns Strict VBox status code.
107 *
108 * @param pVCpu The cross context virtual CPU structure of the calling thread.
109 * @param u16Port The port number.
110 * @param cbOperand The operand size.
111 */
112static VBOXSTRICTRC iemHlpCheckPortIOPermissionBitmap(PVMCPUCC pVCpu, uint16_t u16Port, uint8_t cbOperand)
113{
114 /* The TSS bits we're interested in are the same on 386 and AMD64. */
115 AssertCompile(AMD64_SEL_TYPE_SYS_TSS_BUSY == X86_SEL_TYPE_SYS_386_TSS_BUSY);
116 AssertCompile(AMD64_SEL_TYPE_SYS_TSS_AVAIL == X86_SEL_TYPE_SYS_386_TSS_AVAIL);
117 AssertCompileMembersAtSameOffset(X86TSS32, offIoBitmap, X86TSS64, offIoBitmap);
118 AssertCompile(sizeof(X86TSS32) == sizeof(X86TSS64));
119
120 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_TR);
121
122 /*
123 * Check the TSS type, 16-bit TSSes doesn't have any I/O permission bitmap.
124 */
125 Assert(!pVCpu->cpum.GstCtx.tr.Attr.n.u1DescType);
126 if (RT_UNLIKELY( pVCpu->cpum.GstCtx.tr.Attr.n.u4Type != AMD64_SEL_TYPE_SYS_TSS_BUSY
127 && pVCpu->cpum.GstCtx.tr.Attr.n.u4Type != AMD64_SEL_TYPE_SYS_TSS_AVAIL))
128 {
129 Log(("iemHlpCheckPortIOPermissionBitmap: Port=%#x cb=%d - TSS type %#x (attr=%#x) has no I/O bitmap -> #GP(0)\n",
130 u16Port, cbOperand, pVCpu->cpum.GstCtx.tr.Attr.n.u4Type, pVCpu->cpum.GstCtx.tr.Attr.u));
131 return iemRaiseGeneralProtectionFault0(pVCpu);
132 }
133
134 /*
135 * Read the bitmap offset (may #PF).
136 */
137 uint16_t offBitmap;
138 VBOXSTRICTRC rcStrict = iemMemFetchSysU16(pVCpu, &offBitmap, UINT8_MAX,
139 pVCpu->cpum.GstCtx.tr.u64Base + RT_UOFFSETOF(X86TSS64, offIoBitmap));
140 if (rcStrict != VINF_SUCCESS)
141 {
142 Log(("iemHlpCheckPortIOPermissionBitmap: Error reading offIoBitmap (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
143 return rcStrict;
144 }
145
146 /*
147 * The bit range from u16Port to (u16Port + cbOperand - 1), however intel
148 * describes the CPU actually reading two bytes regardless of whether the
149 * bit range crosses a byte boundrary. Thus the + 1 in the test below.
150 */
151 uint32_t offFirstBit = (uint32_t)u16Port / 8 + offBitmap;
152 /** @todo check if real CPUs ensures that offBitmap has a minimum value of
153 * for instance sizeof(X86TSS32). */
154 if (offFirstBit + 1 > pVCpu->cpum.GstCtx.tr.u32Limit) /* the limit is inclusive */
155 {
156 Log(("iemHlpCheckPortIOPermissionBitmap: offFirstBit=%#x + 1 is beyond u32Limit=%#x -> #GP(0)\n",
157 offFirstBit, pVCpu->cpum.GstCtx.tr.u32Limit));
158 return iemRaiseGeneralProtectionFault0(pVCpu);
159 }
160
161 /*
162 * Read the necessary bits.
163 */
164 /** @todo Test the assertion in the intel manual that the CPU reads two
165 * bytes. The question is how this works wrt to \#PF and \#GP on the
166 * 2nd byte when it's not required. */
167 uint16_t bmBytes = UINT16_MAX;
168 rcStrict = iemMemFetchSysU16(pVCpu, &bmBytes, UINT8_MAX, pVCpu->cpum.GstCtx.tr.u64Base + offFirstBit);
169 if (rcStrict != VINF_SUCCESS)
170 {
171 Log(("iemHlpCheckPortIOPermissionBitmap: Error reading I/O bitmap @%#x (%Rrc)\n", offFirstBit, VBOXSTRICTRC_VAL(rcStrict)));
172 return rcStrict;
173 }
174
175 /*
176 * Perform the check.
177 */
178 uint16_t fPortMask = (1 << cbOperand) - 1;
179 bmBytes >>= (u16Port & 7);
180 if (bmBytes & fPortMask)
181 {
182 Log(("iemHlpCheckPortIOPermissionBitmap: u16Port=%#x LB %u - access denied (bm=%#x mask=%#x) -> #GP(0)\n",
183 u16Port, cbOperand, bmBytes, fPortMask));
184 return iemRaiseGeneralProtectionFault0(pVCpu);
185 }
186
187 return VINF_SUCCESS;
188}
189
190
191/**
192 * Checks if we are allowed to access the given I/O port, raising the
193 * appropriate exceptions if we aren't (or if the I/O bitmap is not
194 * accessible).
195 *
196 * @returns Strict VBox status code.
197 *
198 * @param pVCpu The cross context virtual CPU structure of the calling thread.
199 * @param u16Port The port number.
200 * @param cbOperand The operand size.
201 */
202DECLINLINE(VBOXSTRICTRC) iemHlpCheckPortIOPermission(PVMCPUCC pVCpu, uint16_t u16Port, uint8_t cbOperand)
203{
204 X86EFLAGS Efl;
205 Efl.u = IEMMISC_GET_EFL(pVCpu);
206 if ( (pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE)
207 && ( IEM_GET_CPL(pVCpu) > Efl.Bits.u2IOPL
208 || Efl.Bits.u1VM) )
209 return iemHlpCheckPortIOPermissionBitmap(pVCpu, u16Port, cbOperand);
210 return VINF_SUCCESS;
211}
212
213
214#if 0
215/**
216 * Calculates the parity bit.
217 *
218 * @returns true if the bit is set, false if not.
219 * @param u8Result The least significant byte of the result.
220 */
221static bool iemHlpCalcParityFlag(uint8_t u8Result)
222{
223 /*
224 * Parity is set if the number of bits in the least significant byte of
225 * the result is even.
226 */
227 uint8_t cBits;
228 cBits = u8Result & 1; /* 0 */
229 u8Result >>= 1;
230 cBits += u8Result & 1;
231 u8Result >>= 1;
232 cBits += u8Result & 1;
233 u8Result >>= 1;
234 cBits += u8Result & 1;
235 u8Result >>= 1;
236 cBits += u8Result & 1; /* 4 */
237 u8Result >>= 1;
238 cBits += u8Result & 1;
239 u8Result >>= 1;
240 cBits += u8Result & 1;
241 u8Result >>= 1;
242 cBits += u8Result & 1;
243 return !(cBits & 1);
244}
245#endif /* not used */
246
247
248/**
249 * Updates the specified flags according to a 8-bit result.
250 *
251 * @param pVCpu The cross context virtual CPU structure of the calling thread.
252 * @param u8Result The result to set the flags according to.
253 * @param fToUpdate The flags to update.
254 * @param fUndefined The flags that are specified as undefined.
255 */
256static void iemHlpUpdateArithEFlagsU8(PVMCPUCC pVCpu, uint8_t u8Result, uint32_t fToUpdate, uint32_t fUndefined)
257{
258 uint32_t fEFlags = iemAImpl_test_u8(pVCpu->cpum.GstCtx.eflags.u, &u8Result, u8Result);
259 pVCpu->cpum.GstCtx.eflags.u &= ~(fToUpdate | fUndefined);
260 pVCpu->cpum.GstCtx.eflags.u |= (fToUpdate | fUndefined) & fEFlags;
261}
262
263
264/**
265 * Updates the specified flags according to a 16-bit result.
266 *
267 * @param pVCpu The cross context virtual CPU structure of the calling thread.
268 * @param u16Result The result to set the flags according to.
269 * @param fToUpdate The flags to update.
270 * @param fUndefined The flags that are specified as undefined.
271 */
272static void iemHlpUpdateArithEFlagsU16(PVMCPUCC pVCpu, uint16_t u16Result, uint32_t fToUpdate, uint32_t fUndefined)
273{
274 uint32_t fEFlags = iemAImpl_test_u16(pVCpu->cpum.GstCtx.eflags.u, &u16Result, u16Result);
275 pVCpu->cpum.GstCtx.eflags.u &= ~(fToUpdate | fUndefined);
276 pVCpu->cpum.GstCtx.eflags.u |= (fToUpdate | fUndefined) & fEFlags;
277}
278
279
280/**
281 * Helper used by iret.
282 *
283 * @param pVCpu The cross context virtual CPU structure of the calling thread.
284 * @param uCpl The new CPL.
285 * @param pSReg Pointer to the segment register.
286 */
287static void iemHlpAdjustSelectorForNewCpl(PVMCPUCC pVCpu, uint8_t uCpl, PCPUMSELREG pSReg)
288{
289 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg));
290 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SREG_MASK);
291
292 if ( uCpl > pSReg->Attr.n.u2Dpl
293 && pSReg->Attr.n.u1DescType /* code or data, not system */
294 && (pSReg->Attr.n.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
295 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF)) /* not conforming code */
296 iemHlpLoadNullDataSelectorProt(pVCpu, pSReg, 0);
297}
298
299
300/**
301 * Indicates that we have modified the FPU state.
302 *
303 * @param pVCpu The cross context virtual CPU structure of the calling thread.
304 */
305DECLINLINE(void) iemHlpUsedFpu(PVMCPUCC pVCpu)
306{
307 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_FPU_REM);
308}
309
310/** @} */
311
312/** @name C Implementations
313 * @{
314 */
315
316
317/**
318 * Implements a pop [mem16].
319 */
320IEM_CIMPL_DEF_2(iemCImpl_pop_mem16, uint16_t, iEffSeg, RTGCPTR, GCPtrEffDst)
321{
322 uint16_t u16Value;
323 RTUINT64U TmpRsp;
324 TmpRsp.u = pVCpu->cpum.GstCtx.rsp;
325 VBOXSTRICTRC rcStrict = iemMemStackPopU16Ex(pVCpu, &u16Value, &TmpRsp);
326 if (rcStrict == VINF_SUCCESS)
327 {
328 rcStrict = iemMemStoreDataU16(pVCpu, iEffSeg, GCPtrEffDst, u16Value);
329 if (rcStrict == VINF_SUCCESS)
330 {
331 pVCpu->cpum.GstCtx.rsp = TmpRsp.u;
332 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
333 }
334 }
335 return rcStrict;
336
337}
338
339
340/**
341 * Implements a pop [mem32].
342 */
343IEM_CIMPL_DEF_2(iemCImpl_pop_mem32, uint16_t, iEffSeg, RTGCPTR, GCPtrEffDst)
344{
345 uint32_t u32Value;
346 RTUINT64U TmpRsp;
347 TmpRsp.u = pVCpu->cpum.GstCtx.rsp;
348 VBOXSTRICTRC rcStrict = iemMemStackPopU32Ex(pVCpu, &u32Value, &TmpRsp);
349 if (rcStrict == VINF_SUCCESS)
350 {
351 rcStrict = iemMemStoreDataU32(pVCpu, iEffSeg, GCPtrEffDst, u32Value);
352 if (rcStrict == VINF_SUCCESS)
353 {
354 pVCpu->cpum.GstCtx.rsp = TmpRsp.u;
355 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
356 }
357 }
358 return rcStrict;
359
360}
361
362
363/**
364 * Implements a pop [mem64].
365 */
366IEM_CIMPL_DEF_2(iemCImpl_pop_mem64, uint16_t, iEffSeg, RTGCPTR, GCPtrEffDst)
367{
368 uint64_t u64Value;
369 RTUINT64U TmpRsp;
370 TmpRsp.u = pVCpu->cpum.GstCtx.rsp;
371 VBOXSTRICTRC rcStrict = iemMemStackPopU64Ex(pVCpu, &u64Value, &TmpRsp);
372 if (rcStrict == VINF_SUCCESS)
373 {
374 rcStrict = iemMemStoreDataU64(pVCpu, iEffSeg, GCPtrEffDst, u64Value);
375 if (rcStrict == VINF_SUCCESS)
376 {
377 pVCpu->cpum.GstCtx.rsp = TmpRsp.u;
378 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
379 }
380 }
381 return rcStrict;
382
383}
384
385
386/**
387 * Implements a 16-bit popa.
388 */
389IEM_CIMPL_DEF_0(iemCImpl_popa_16)
390{
391 RTGCPTR GCPtrStart = iemRegGetEffRsp(pVCpu);
392 RTGCPTR GCPtrLast = GCPtrStart + 15;
393 VBOXSTRICTRC rcStrict;
394
395 /*
396 * The docs are a bit hard to comprehend here, but it looks like we wrap
397 * around in real mode as long as none of the individual "popa" crosses the
398 * end of the stack segment. In protected mode we check the whole access
399 * in one go. For efficiency, only do the word-by-word thing if we're in
400 * danger of wrapping around.
401 */
402 /** @todo do popa boundary / wrap-around checks. */
403 if (RT_UNLIKELY( IEM_IS_REAL_OR_V86_MODE(pVCpu)
404 && (pVCpu->cpum.GstCtx.cs.u32Limit < GCPtrLast)) ) /* ASSUMES 64-bit RTGCPTR */
405 {
406 /* word-by-word */
407 RTUINT64U TmpRsp;
408 TmpRsp.u = pVCpu->cpum.GstCtx.rsp;
409 rcStrict = iemMemStackPopU16Ex(pVCpu, &pVCpu->cpum.GstCtx.di, &TmpRsp);
410 if (rcStrict == VINF_SUCCESS)
411 rcStrict = iemMemStackPopU16Ex(pVCpu, &pVCpu->cpum.GstCtx.si, &TmpRsp);
412 if (rcStrict == VINF_SUCCESS)
413 rcStrict = iemMemStackPopU16Ex(pVCpu, &pVCpu->cpum.GstCtx.bp, &TmpRsp);
414 if (rcStrict == VINF_SUCCESS)
415 {
416 iemRegAddToRspEx(pVCpu, &TmpRsp, 2); /* sp */
417 rcStrict = iemMemStackPopU16Ex(pVCpu, &pVCpu->cpum.GstCtx.bx, &TmpRsp);
418 }
419 if (rcStrict == VINF_SUCCESS)
420 rcStrict = iemMemStackPopU16Ex(pVCpu, &pVCpu->cpum.GstCtx.dx, &TmpRsp);
421 if (rcStrict == VINF_SUCCESS)
422 rcStrict = iemMemStackPopU16Ex(pVCpu, &pVCpu->cpum.GstCtx.cx, &TmpRsp);
423 if (rcStrict == VINF_SUCCESS)
424 rcStrict = iemMemStackPopU16Ex(pVCpu, &pVCpu->cpum.GstCtx.ax, &TmpRsp);
425 if (rcStrict == VINF_SUCCESS)
426 {
427 pVCpu->cpum.GstCtx.rsp = TmpRsp.u;
428 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
429 }
430 }
431 else
432 {
433 uint8_t bUnmapInfo;
434 uint16_t const *pau16Mem = NULL;
435 rcStrict = iemMemMap(pVCpu, (void **)&pau16Mem, &bUnmapInfo, 16, X86_SREG_SS, GCPtrStart,
436 IEM_ACCESS_STACK_R, sizeof(*pau16Mem) - 1);
437 if (rcStrict == VINF_SUCCESS)
438 {
439 pVCpu->cpum.GstCtx.di = pau16Mem[7 - X86_GREG_xDI];
440 pVCpu->cpum.GstCtx.si = pau16Mem[7 - X86_GREG_xSI];
441 pVCpu->cpum.GstCtx.bp = pau16Mem[7 - X86_GREG_xBP];
442 /* skip sp */
443 pVCpu->cpum.GstCtx.bx = pau16Mem[7 - X86_GREG_xBX];
444 pVCpu->cpum.GstCtx.dx = pau16Mem[7 - X86_GREG_xDX];
445 pVCpu->cpum.GstCtx.cx = pau16Mem[7 - X86_GREG_xCX];
446 pVCpu->cpum.GstCtx.ax = pau16Mem[7 - X86_GREG_xAX];
447 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
448 if (rcStrict == VINF_SUCCESS)
449 {
450 iemRegAddToRsp(pVCpu, 16);
451 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
452 }
453 }
454 }
455 return rcStrict;
456}
457
458
459/**
460 * Implements a 32-bit popa.
461 */
462IEM_CIMPL_DEF_0(iemCImpl_popa_32)
463{
464 RTGCPTR GCPtrStart = iemRegGetEffRsp(pVCpu);
465 RTGCPTR GCPtrLast = GCPtrStart + 31;
466 VBOXSTRICTRC rcStrict;
467
468 /*
469 * The docs are a bit hard to comprehend here, but it looks like we wrap
470 * around in real mode as long as none of the individual "popa" crosses the
471 * end of the stack segment. In protected mode we check the whole access
472 * in one go. For efficiency, only do the word-by-word thing if we're in
473 * danger of wrapping around.
474 */
475 /** @todo do popa boundary / wrap-around checks. */
476 if (RT_UNLIKELY( IEM_IS_REAL_OR_V86_MODE(pVCpu)
477 && (pVCpu->cpum.GstCtx.cs.u32Limit < GCPtrLast)) ) /* ASSUMES 64-bit RTGCPTR */
478 {
479 /* word-by-word */
480 RTUINT64U TmpRsp;
481 TmpRsp.u = pVCpu->cpum.GstCtx.rsp;
482 rcStrict = iemMemStackPopU32Ex(pVCpu, &pVCpu->cpum.GstCtx.edi, &TmpRsp);
483 if (rcStrict == VINF_SUCCESS)
484 rcStrict = iemMemStackPopU32Ex(pVCpu, &pVCpu->cpum.GstCtx.esi, &TmpRsp);
485 if (rcStrict == VINF_SUCCESS)
486 rcStrict = iemMemStackPopU32Ex(pVCpu, &pVCpu->cpum.GstCtx.ebp, &TmpRsp);
487 if (rcStrict == VINF_SUCCESS)
488 {
489 iemRegAddToRspEx(pVCpu, &TmpRsp, 2); /* sp */
490 rcStrict = iemMemStackPopU32Ex(pVCpu, &pVCpu->cpum.GstCtx.ebx, &TmpRsp);
491 }
492 if (rcStrict == VINF_SUCCESS)
493 rcStrict = iemMemStackPopU32Ex(pVCpu, &pVCpu->cpum.GstCtx.edx, &TmpRsp);
494 if (rcStrict == VINF_SUCCESS)
495 rcStrict = iemMemStackPopU32Ex(pVCpu, &pVCpu->cpum.GstCtx.ecx, &TmpRsp);
496 if (rcStrict == VINF_SUCCESS)
497 rcStrict = iemMemStackPopU32Ex(pVCpu, &pVCpu->cpum.GstCtx.eax, &TmpRsp);
498 if (rcStrict == VINF_SUCCESS)
499 {
500#if 1 /** @todo what actually happens with the high bits when we're in 16-bit mode? */
501 pVCpu->cpum.GstCtx.rdi &= UINT32_MAX;
502 pVCpu->cpum.GstCtx.rsi &= UINT32_MAX;
503 pVCpu->cpum.GstCtx.rbp &= UINT32_MAX;
504 pVCpu->cpum.GstCtx.rbx &= UINT32_MAX;
505 pVCpu->cpum.GstCtx.rdx &= UINT32_MAX;
506 pVCpu->cpum.GstCtx.rcx &= UINT32_MAX;
507 pVCpu->cpum.GstCtx.rax &= UINT32_MAX;
508#endif
509 pVCpu->cpum.GstCtx.rsp = TmpRsp.u;
510 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
511 }
512 }
513 else
514 {
515 uint8_t bUnmapInfo;
516 uint32_t const *pau32Mem;
517 rcStrict = iemMemMap(pVCpu, (void **)&pau32Mem, &bUnmapInfo, 32, X86_SREG_SS, GCPtrStart,
518 IEM_ACCESS_STACK_R, sizeof(*pau32Mem) - 1);
519 if (rcStrict == VINF_SUCCESS)
520 {
521 pVCpu->cpum.GstCtx.rdi = pau32Mem[7 - X86_GREG_xDI];
522 pVCpu->cpum.GstCtx.rsi = pau32Mem[7 - X86_GREG_xSI];
523 pVCpu->cpum.GstCtx.rbp = pau32Mem[7 - X86_GREG_xBP];
524 /* skip esp */
525 pVCpu->cpum.GstCtx.rbx = pau32Mem[7 - X86_GREG_xBX];
526 pVCpu->cpum.GstCtx.rdx = pau32Mem[7 - X86_GREG_xDX];
527 pVCpu->cpum.GstCtx.rcx = pau32Mem[7 - X86_GREG_xCX];
528 pVCpu->cpum.GstCtx.rax = pau32Mem[7 - X86_GREG_xAX];
529 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
530 if (rcStrict == VINF_SUCCESS)
531 {
532 iemRegAddToRsp(pVCpu, 32);
533 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
534 }
535 }
536 }
537 return rcStrict;
538}
539
540
541/**
542 * Implements a 16-bit pusha.
543 */
544IEM_CIMPL_DEF_0(iemCImpl_pusha_16)
545{
546 RTGCPTR GCPtrTop = iemRegGetEffRsp(pVCpu);
547 RTGCPTR GCPtrBottom = GCPtrTop - 15;
548 VBOXSTRICTRC rcStrict;
549
550 /*
551 * The docs are a bit hard to comprehend here, but it looks like we wrap
552 * around in real mode as long as none of the individual "pushd" crosses the
553 * end of the stack segment. In protected mode we check the whole access
554 * in one go. For efficiency, only do the word-by-word thing if we're in
555 * danger of wrapping around.
556 */
557 /** @todo do pusha boundary / wrap-around checks. */
558 if (RT_UNLIKELY( GCPtrBottom > GCPtrTop
559 && IEM_IS_REAL_OR_V86_MODE(pVCpu) ) )
560 {
561 /* word-by-word */
562 RTUINT64U TmpRsp;
563 TmpRsp.u = pVCpu->cpum.GstCtx.rsp;
564 rcStrict = iemMemStackPushU16Ex(pVCpu, pVCpu->cpum.GstCtx.ax, &TmpRsp);
565 if (rcStrict == VINF_SUCCESS)
566 rcStrict = iemMemStackPushU16Ex(pVCpu, pVCpu->cpum.GstCtx.cx, &TmpRsp);
567 if (rcStrict == VINF_SUCCESS)
568 rcStrict = iemMemStackPushU16Ex(pVCpu, pVCpu->cpum.GstCtx.dx, &TmpRsp);
569 if (rcStrict == VINF_SUCCESS)
570 rcStrict = iemMemStackPushU16Ex(pVCpu, pVCpu->cpum.GstCtx.bx, &TmpRsp);
571 if (rcStrict == VINF_SUCCESS)
572 rcStrict = iemMemStackPushU16Ex(pVCpu, pVCpu->cpum.GstCtx.sp, &TmpRsp);
573 if (rcStrict == VINF_SUCCESS)
574 rcStrict = iemMemStackPushU16Ex(pVCpu, pVCpu->cpum.GstCtx.bp, &TmpRsp);
575 if (rcStrict == VINF_SUCCESS)
576 rcStrict = iemMemStackPushU16Ex(pVCpu, pVCpu->cpum.GstCtx.si, &TmpRsp);
577 if (rcStrict == VINF_SUCCESS)
578 rcStrict = iemMemStackPushU16Ex(pVCpu, pVCpu->cpum.GstCtx.di, &TmpRsp);
579 if (rcStrict == VINF_SUCCESS)
580 {
581 pVCpu->cpum.GstCtx.rsp = TmpRsp.u;
582 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
583 }
584 }
585 else
586 {
587 GCPtrBottom--;
588 uint8_t bUnmapInfo;
589 uint16_t *pau16Mem = NULL;
590 rcStrict = iemMemMap(pVCpu, (void **)&pau16Mem, &bUnmapInfo, 16, X86_SREG_SS, GCPtrBottom,
591 IEM_ACCESS_STACK_W, sizeof(*pau16Mem) - 1);
592 if (rcStrict == VINF_SUCCESS)
593 {
594 pau16Mem[7 - X86_GREG_xDI] = pVCpu->cpum.GstCtx.di;
595 pau16Mem[7 - X86_GREG_xSI] = pVCpu->cpum.GstCtx.si;
596 pau16Mem[7 - X86_GREG_xBP] = pVCpu->cpum.GstCtx.bp;
597 pau16Mem[7 - X86_GREG_xSP] = pVCpu->cpum.GstCtx.sp;
598 pau16Mem[7 - X86_GREG_xBX] = pVCpu->cpum.GstCtx.bx;
599 pau16Mem[7 - X86_GREG_xDX] = pVCpu->cpum.GstCtx.dx;
600 pau16Mem[7 - X86_GREG_xCX] = pVCpu->cpum.GstCtx.cx;
601 pau16Mem[7 - X86_GREG_xAX] = pVCpu->cpum.GstCtx.ax;
602 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
603 if (rcStrict == VINF_SUCCESS)
604 {
605 iemRegSubFromRsp(pVCpu, 16);
606 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
607 }
608 }
609 }
610 return rcStrict;
611}
612
613
614/**
615 * Implements a 32-bit pusha.
616 */
617IEM_CIMPL_DEF_0(iemCImpl_pusha_32)
618{
619 RTGCPTR GCPtrTop = iemRegGetEffRsp(pVCpu);
620 RTGCPTR GCPtrBottom = GCPtrTop - 31;
621 VBOXSTRICTRC rcStrict;
622
623 /*
624 * The docs are a bit hard to comprehend here, but it looks like we wrap
625 * around in real mode as long as none of the individual "pusha" crosses the
626 * end of the stack segment. In protected mode we check the whole access
627 * in one go. For efficiency, only do the word-by-word thing if we're in
628 * danger of wrapping around.
629 */
630 /** @todo do pusha boundary / wrap-around checks. */
631 if (RT_UNLIKELY( GCPtrBottom > GCPtrTop
632 && IEM_IS_REAL_OR_V86_MODE(pVCpu) ) )
633 {
634 /* word-by-word */
635 RTUINT64U TmpRsp;
636 TmpRsp.u = pVCpu->cpum.GstCtx.rsp;
637 rcStrict = iemMemStackPushU32Ex(pVCpu, pVCpu->cpum.GstCtx.eax, &TmpRsp);
638 if (rcStrict == VINF_SUCCESS)
639 rcStrict = iemMemStackPushU32Ex(pVCpu, pVCpu->cpum.GstCtx.ecx, &TmpRsp);
640 if (rcStrict == VINF_SUCCESS)
641 rcStrict = iemMemStackPushU32Ex(pVCpu, pVCpu->cpum.GstCtx.edx, &TmpRsp);
642 if (rcStrict == VINF_SUCCESS)
643 rcStrict = iemMemStackPushU32Ex(pVCpu, pVCpu->cpum.GstCtx.ebx, &TmpRsp);
644 if (rcStrict == VINF_SUCCESS)
645 rcStrict = iemMemStackPushU32Ex(pVCpu, pVCpu->cpum.GstCtx.esp, &TmpRsp);
646 if (rcStrict == VINF_SUCCESS)
647 rcStrict = iemMemStackPushU32Ex(pVCpu, pVCpu->cpum.GstCtx.ebp, &TmpRsp);
648 if (rcStrict == VINF_SUCCESS)
649 rcStrict = iemMemStackPushU32Ex(pVCpu, pVCpu->cpum.GstCtx.esi, &TmpRsp);
650 if (rcStrict == VINF_SUCCESS)
651 rcStrict = iemMemStackPushU32Ex(pVCpu, pVCpu->cpum.GstCtx.edi, &TmpRsp);
652 if (rcStrict == VINF_SUCCESS)
653 {
654 pVCpu->cpum.GstCtx.rsp = TmpRsp.u;
655 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
656 }
657 }
658 else
659 {
660 GCPtrBottom--;
661 uint8_t bUnmapInfo;
662 uint32_t *pau32Mem;
663 rcStrict = iemMemMap(pVCpu, (void **)&pau32Mem, &bUnmapInfo, 32, X86_SREG_SS, GCPtrBottom,
664 IEM_ACCESS_STACK_W, sizeof(*pau32Mem) - 1);
665 if (rcStrict == VINF_SUCCESS)
666 {
667 pau32Mem[7 - X86_GREG_xDI] = pVCpu->cpum.GstCtx.edi;
668 pau32Mem[7 - X86_GREG_xSI] = pVCpu->cpum.GstCtx.esi;
669 pau32Mem[7 - X86_GREG_xBP] = pVCpu->cpum.GstCtx.ebp;
670 pau32Mem[7 - X86_GREG_xSP] = pVCpu->cpum.GstCtx.esp;
671 pau32Mem[7 - X86_GREG_xBX] = pVCpu->cpum.GstCtx.ebx;
672 pau32Mem[7 - X86_GREG_xDX] = pVCpu->cpum.GstCtx.edx;
673 pau32Mem[7 - X86_GREG_xCX] = pVCpu->cpum.GstCtx.ecx;
674 pau32Mem[7 - X86_GREG_xAX] = pVCpu->cpum.GstCtx.eax;
675 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
676 if (rcStrict == VINF_SUCCESS)
677 {
678 iemRegSubFromRsp(pVCpu, 32);
679 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
680 }
681 }
682 }
683 return rcStrict;
684}
685
686
687/**
688 * Implements pushf.
689 *
690 *
691 * @param enmEffOpSize The effective operand size.
692 */
693IEM_CIMPL_DEF_1(iemCImpl_pushf, IEMMODE, enmEffOpSize)
694{
695 VBOXSTRICTRC rcStrict;
696
697 if (!IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_PUSHF))
698 { /* probable */ }
699 else
700 {
701 Log2(("pushf: Guest intercept -> #VMEXIT\n"));
702 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
703 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_PUSHF, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
704 }
705
706 /*
707 * If we're in V8086 mode some care is required (which is why we're in
708 * doing this in a C implementation).
709 */
710 uint32_t fEfl = IEMMISC_GET_EFL(pVCpu);
711 if ( (fEfl & X86_EFL_VM)
712 && X86_EFL_GET_IOPL(fEfl) != 3 )
713 {
714 Assert(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE);
715 if ( enmEffOpSize != IEMMODE_16BIT
716 || !(pVCpu->cpum.GstCtx.cr4 & X86_CR4_VME))
717 return iemRaiseGeneralProtectionFault0(pVCpu);
718 fEfl &= ~X86_EFL_IF; /* (RF and VM are out of range) */
719 fEfl |= (fEfl & X86_EFL_VIF) >> (19 - 9);
720 rcStrict = iemMemStackPushU16(pVCpu, (uint16_t)fEfl);
721 }
722 else
723 {
724
725 /*
726 * Ok, clear RF and VM, adjust for ancient CPUs, and push the flags.
727 */
728 fEfl &= ~(X86_EFL_RF | X86_EFL_VM);
729
730 switch (enmEffOpSize)
731 {
732 case IEMMODE_16BIT:
733 AssertCompile(IEMTARGETCPU_8086 <= IEMTARGETCPU_186 && IEMTARGETCPU_V20 <= IEMTARGETCPU_186 && IEMTARGETCPU_286 > IEMTARGETCPU_186);
734 if (IEM_GET_TARGET_CPU(pVCpu) <= IEMTARGETCPU_186)
735 fEfl |= UINT16_C(0xf000);
736 rcStrict = iemMemStackPushU16(pVCpu, (uint16_t)fEfl);
737 break;
738 case IEMMODE_32BIT:
739 rcStrict = iemMemStackPushU32(pVCpu, fEfl);
740 break;
741 case IEMMODE_64BIT:
742 rcStrict = iemMemStackPushU64(pVCpu, fEfl);
743 break;
744 IEM_NOT_REACHED_DEFAULT_CASE_RET();
745 }
746 }
747
748 if (rcStrict == VINF_SUCCESS)
749 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
750 return rcStrict;
751}
752
753
754/**
755 * Implements popf.
756 *
757 * @param enmEffOpSize The effective operand size.
758 */
759IEM_CIMPL_DEF_1(iemCImpl_popf, IEMMODE, enmEffOpSize)
760{
761 uint32_t const fEflOld = IEMMISC_GET_EFL(pVCpu);
762 VBOXSTRICTRC rcStrict;
763 uint32_t fEflNew;
764
765 if (!IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_POPF))
766 { /* probable */ }
767 else
768 {
769 Log2(("popf: Guest intercept -> #VMEXIT\n"));
770 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
771 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_POPF, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
772 }
773
774 /*
775 * V8086 is special as usual.
776 */
777 if (fEflOld & X86_EFL_VM)
778 {
779 /*
780 * Almost anything goes if IOPL is 3.
781 */
782 if (X86_EFL_GET_IOPL(fEflOld) == 3)
783 {
784 switch (enmEffOpSize)
785 {
786 case IEMMODE_16BIT:
787 {
788 uint16_t u16Value;
789 rcStrict = iemMemStackPopU16(pVCpu, &u16Value);
790 if (rcStrict != VINF_SUCCESS)
791 return rcStrict;
792 fEflNew = u16Value | (fEflOld & UINT32_C(0xffff0000));
793 break;
794 }
795 case IEMMODE_32BIT:
796 rcStrict = iemMemStackPopU32(pVCpu, &fEflNew);
797 if (rcStrict != VINF_SUCCESS)
798 return rcStrict;
799 break;
800 IEM_NOT_REACHED_DEFAULT_CASE_RET();
801 }
802
803 const uint32_t fPopfBits = pVCpu->CTX_SUFF(pVM)->cpum.ro.GuestFeatures.enmMicroarch != kCpumMicroarch_Intel_80386
804 ? X86_EFL_POPF_BITS : X86_EFL_POPF_BITS_386;
805 fEflNew &= fPopfBits & ~(X86_EFL_IOPL);
806 fEflNew |= ~(fPopfBits & ~(X86_EFL_IOPL)) & fEflOld;
807 }
808 /*
809 * Interrupt flag virtualization with CR4.VME=1.
810 */
811 else if ( enmEffOpSize == IEMMODE_16BIT
812 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_VME) )
813 {
814 uint16_t u16Value;
815 RTUINT64U TmpRsp;
816 TmpRsp.u = pVCpu->cpum.GstCtx.rsp;
817 rcStrict = iemMemStackPopU16Ex(pVCpu, &u16Value, &TmpRsp);
818 if (rcStrict != VINF_SUCCESS)
819 return rcStrict;
820
821 if ( ( (u16Value & X86_EFL_IF)
822 && (fEflOld & X86_EFL_VIP))
823 || (u16Value & X86_EFL_TF) )
824 return iemRaiseGeneralProtectionFault0(pVCpu);
825
826 fEflNew = X86_EFL_RA1_MASK
827 | (u16Value & ~(X86_EFL_IF | X86_EFL_IOPL | X86_EFL_RAZ_MASK))
828 | (fEflOld & (UINT32_C(0xffff0000) | X86_EFL_IF | X86_EFL_IOPL) & ~(X86_EFL_VIF | X86_EFL_RF))
829 | ((uint32_t)(u16Value & X86_EFL_IF) << (X86_EFL_VIF_BIT - X86_EFL_IF_BIT));
830
831 pVCpu->cpum.GstCtx.rsp = TmpRsp.u;
832 }
833 else
834 return iemRaiseGeneralProtectionFault0(pVCpu);
835
836 }
837 /*
838 * Not in V8086 mode.
839 */
840 else
841 {
842 /* Pop the flags. */
843 switch (enmEffOpSize)
844 {
845 case IEMMODE_16BIT:
846 {
847 uint16_t u16Value;
848 rcStrict = iemMemStackPopU16(pVCpu, &u16Value);
849 if (rcStrict != VINF_SUCCESS)
850 return rcStrict;
851 fEflNew = u16Value | (fEflOld & UINT32_C(0xffff0000));
852
853 /*
854 * Ancient CPU adjustments:
855 * - 8086, 80186, V20/30:
856 * Fixed bits 15:12 bits are not kept correctly internally, mostly for
857 * practical reasons (masking below). We add them when pushing flags.
858 * - 80286:
859 * The NT and IOPL flags cannot be popped from real mode and are
860 * therefore always zero (since a 286 can never exit from PM and
861 * their initial value is zero). This changed on a 386 and can
862 * therefore be used to detect 286 or 386 CPU in real mode.
863 */
864 if ( IEM_GET_TARGET_CPU(pVCpu) == IEMTARGETCPU_286
865 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE) )
866 fEflNew &= ~(X86_EFL_NT | X86_EFL_IOPL);
867 break;
868 }
869 case IEMMODE_32BIT:
870 rcStrict = iemMemStackPopU32(pVCpu, &fEflNew);
871 if (rcStrict != VINF_SUCCESS)
872 return rcStrict;
873 break;
874 case IEMMODE_64BIT:
875 {
876 uint64_t u64Value;
877 rcStrict = iemMemStackPopU64(pVCpu, &u64Value);
878 if (rcStrict != VINF_SUCCESS)
879 return rcStrict;
880 fEflNew = u64Value; /** @todo testcase: Check exactly what happens if high bits are set. */
881 break;
882 }
883 IEM_NOT_REACHED_DEFAULT_CASE_RET();
884 }
885
886 /* Merge them with the current flags. */
887 const uint32_t fPopfBits = pVCpu->CTX_SUFF(pVM)->cpum.ro.GuestFeatures.enmMicroarch != kCpumMicroarch_Intel_80386
888 ? X86_EFL_POPF_BITS : X86_EFL_POPF_BITS_386;
889 if ( (fEflNew & (X86_EFL_IOPL | X86_EFL_IF)) == (fEflOld & (X86_EFL_IOPL | X86_EFL_IF))
890 || IEM_GET_CPL(pVCpu) == 0)
891 {
892 fEflNew &= fPopfBits;
893 fEflNew |= ~fPopfBits & fEflOld;
894 }
895 else if (IEM_GET_CPL(pVCpu) <= X86_EFL_GET_IOPL(fEflOld))
896 {
897 fEflNew &= fPopfBits & ~(X86_EFL_IOPL);
898 fEflNew |= ~(fPopfBits & ~(X86_EFL_IOPL)) & fEflOld;
899 }
900 else
901 {
902 fEflNew &= fPopfBits & ~(X86_EFL_IOPL | X86_EFL_IF);
903 fEflNew |= ~(fPopfBits & ~(X86_EFL_IOPL | X86_EFL_IF)) & fEflOld;
904 }
905 }
906
907 /*
908 * Commit the flags.
909 */
910 Assert(fEflNew & RT_BIT_32(1));
911 IEMMISC_SET_EFL(pVCpu, fEflNew);
912 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~IEM_F_X86_AC) | iemCalcExecAcFlag(pVCpu);
913 return iemRegAddToRipAndFinishingClearingRfEx(pVCpu, cbInstr, fEflOld);
914}
915
916
917/**
918 * Implements far jumps and calls thru task segments (TSS).
919 *
920 * @returns VBox strict status code.
921 * @param pVCpu The cross context virtual CPU structure of the
922 * calling thread.
923 * @param cbInstr The current instruction length.
924 * @param uSel The selector.
925 * @param enmBranch The kind of branching we're performing.
926 * @param enmEffOpSize The effective operand size.
927 * @param pDesc The descriptor corresponding to @a uSel. The type is
928 * task gate.
929 */
930static VBOXSTRICTRC iemCImpl_BranchTaskSegment(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t uSel, IEMBRANCH enmBranch,
931 IEMMODE enmEffOpSize, PIEMSELDESC pDesc)
932{
933#ifndef IEM_IMPLEMENTS_TASKSWITCH
934 IEM_RETURN_ASPECT_NOT_IMPLEMENTED();
935#else
936 Assert(enmBranch == IEMBRANCH_JUMP || enmBranch == IEMBRANCH_CALL);
937 Assert( pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_286_TSS_AVAIL
938 || pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_386_TSS_AVAIL);
939 RT_NOREF_PV(enmEffOpSize);
940 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_XCPT_MASK);
941
942 if ( pDesc->Legacy.Gate.u2Dpl < IEM_GET_CPL(pVCpu)
943 || pDesc->Legacy.Gate.u2Dpl < (uSel & X86_SEL_RPL))
944 {
945 Log(("BranchTaskSegment invalid priv. uSel=%04x TSS DPL=%d CPL=%u Sel RPL=%u -> #GP\n", uSel, pDesc->Legacy.Gate.u2Dpl,
946 IEM_GET_CPL(pVCpu), (uSel & X86_SEL_RPL)));
947 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel & X86_SEL_MASK_OFF_RPL);
948 }
949
950 /** @todo This is checked earlier for far jumps (see iemCImpl_FarJmp) but not
951 * far calls (see iemCImpl_callf). Most likely in both cases it should be
952 * checked here, need testcases. */
953 if (!pDesc->Legacy.Gen.u1Present)
954 {
955 Log(("BranchTaskSegment TSS not present uSel=%04x -> #NP\n", uSel));
956 return iemRaiseSelectorNotPresentBySelector(pVCpu, uSel & X86_SEL_MASK_OFF_RPL);
957 }
958
959 uint32_t uNextEip = pVCpu->cpum.GstCtx.eip + cbInstr;
960 return iemTaskSwitch(pVCpu, enmBranch == IEMBRANCH_JUMP ? IEMTASKSWITCH_JUMP : IEMTASKSWITCH_CALL,
961 uNextEip, 0 /* fFlags */, 0 /* uErr */, 0 /* uCr2 */, uSel, pDesc);
962#endif
963}
964
965
966/**
967 * Implements far jumps and calls thru task gates.
968 *
969 * @returns VBox strict status code.
970 * @param pVCpu The cross context virtual CPU structure of the
971 * calling thread.
972 * @param cbInstr The current instruction length.
973 * @param uSel The selector.
974 * @param enmBranch The kind of branching we're performing.
975 * @param enmEffOpSize The effective operand size.
976 * @param pDesc The descriptor corresponding to @a uSel. The type is
977 * task gate.
978 */
979static VBOXSTRICTRC iemCImpl_BranchTaskGate(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t uSel, IEMBRANCH enmBranch,
980 IEMMODE enmEffOpSize, PIEMSELDESC pDesc)
981{
982#ifndef IEM_IMPLEMENTS_TASKSWITCH
983 IEM_RETURN_ASPECT_NOT_IMPLEMENTED();
984#else
985 Assert(enmBranch == IEMBRANCH_JUMP || enmBranch == IEMBRANCH_CALL);
986 RT_NOREF_PV(enmEffOpSize);
987 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_XCPT_MASK);
988
989 if ( pDesc->Legacy.Gate.u2Dpl < IEM_GET_CPL(pVCpu)
990 || pDesc->Legacy.Gate.u2Dpl < (uSel & X86_SEL_RPL))
991 {
992 Log(("BranchTaskGate invalid priv. uSel=%04x TSS DPL=%d CPL=%u Sel RPL=%u -> #GP\n", uSel, pDesc->Legacy.Gate.u2Dpl,
993 IEM_GET_CPL(pVCpu), (uSel & X86_SEL_RPL)));
994 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel & X86_SEL_MASK_OFF_RPL);
995 }
996
997 /** @todo This is checked earlier for far jumps (see iemCImpl_FarJmp) but not
998 * far calls (see iemCImpl_callf). Most likely in both cases it should be
999 * checked here, need testcases. */
1000 if (!pDesc->Legacy.Gen.u1Present)
1001 {
1002 Log(("BranchTaskSegment segment not present uSel=%04x -> #NP\n", uSel));
1003 return iemRaiseSelectorNotPresentBySelector(pVCpu, uSel & X86_SEL_MASK_OFF_RPL);
1004 }
1005
1006 /*
1007 * Fetch the new TSS descriptor from the GDT.
1008 */
1009 RTSEL uSelTss = pDesc->Legacy.Gate.u16Sel;
1010 if (uSelTss & X86_SEL_LDT)
1011 {
1012 Log(("BranchTaskGate TSS is in LDT. uSel=%04x uSelTss=%04x -> #GP\n", uSel, uSelTss));
1013 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel & X86_SEL_MASK_OFF_RPL);
1014 }
1015
1016 IEMSELDESC TssDesc;
1017 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pVCpu, &TssDesc, uSelTss, X86_XCPT_GP);
1018 if (rcStrict != VINF_SUCCESS)
1019 return rcStrict;
1020
1021 if (TssDesc.Legacy.Gate.u4Type & X86_SEL_TYPE_SYS_TSS_BUSY_MASK)
1022 {
1023 Log(("BranchTaskGate TSS is busy. uSel=%04x uSelTss=%04x DescType=%#x -> #GP\n", uSel, uSelTss,
1024 TssDesc.Legacy.Gate.u4Type));
1025 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel & X86_SEL_MASK_OFF_RPL);
1026 }
1027
1028 if (!TssDesc.Legacy.Gate.u1Present)
1029 {
1030 Log(("BranchTaskGate TSS is not present. uSel=%04x uSelTss=%04x -> #NP\n", uSel, uSelTss));
1031 return iemRaiseSelectorNotPresentBySelector(pVCpu, uSelTss & X86_SEL_MASK_OFF_RPL);
1032 }
1033
1034 uint32_t uNextEip = pVCpu->cpum.GstCtx.eip + cbInstr;
1035 return iemTaskSwitch(pVCpu, enmBranch == IEMBRANCH_JUMP ? IEMTASKSWITCH_JUMP : IEMTASKSWITCH_CALL,
1036 uNextEip, 0 /* fFlags */, 0 /* uErr */, 0 /* uCr2 */, uSelTss, &TssDesc);
1037#endif
1038}
1039
1040
1041/**
1042 * Implements far jumps and calls thru call gates.
1043 *
1044 * @returns VBox strict status code.
1045 * @param pVCpu The cross context virtual CPU structure of the
1046 * calling thread.
1047 * @param cbInstr The current instruction length.
1048 * @param uSel The selector.
1049 * @param enmBranch The kind of branching we're performing.
1050 * @param enmEffOpSize The effective operand size.
1051 * @param pDesc The descriptor corresponding to @a uSel. The type is
1052 * call gate.
1053 */
1054static VBOXSTRICTRC iemCImpl_BranchCallGate(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t uSel, IEMBRANCH enmBranch,
1055 IEMMODE enmEffOpSize, PIEMSELDESC pDesc)
1056{
1057#define IEM_IMPLEMENTS_CALLGATE
1058#ifndef IEM_IMPLEMENTS_CALLGATE
1059 IEM_RETURN_ASPECT_NOT_IMPLEMENTED();
1060#else
1061 RT_NOREF_PV(enmEffOpSize);
1062 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_XCPT_MASK);
1063
1064 /* NB: Far jumps can only do intra-privilege transfers. Far calls support
1065 * inter-privilege calls and are much more complex.
1066 *
1067 * NB: 64-bit call gate has the same type as a 32-bit call gate! If
1068 * EFER.LMA=1, the gate must be 64-bit. Conversely if EFER.LMA=0, the gate
1069 * must be 16-bit or 32-bit.
1070 */
1071 /** @todo effective operand size is probably irrelevant here, only the
1072 * call gate bitness matters??
1073 */
1074 VBOXSTRICTRC rcStrict;
1075 RTPTRUNION uPtrRet;
1076 uint64_t uNewRsp;
1077 uint64_t uNewRip;
1078 uint64_t u64Base;
1079 uint32_t cbLimit;
1080 RTSEL uNewCS;
1081 IEMSELDESC DescCS;
1082
1083 AssertCompile(X86_SEL_TYPE_SYS_386_CALL_GATE == AMD64_SEL_TYPE_SYS_CALL_GATE);
1084 Assert(enmBranch == IEMBRANCH_JUMP || enmBranch == IEMBRANCH_CALL);
1085 Assert( pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_286_CALL_GATE
1086 || pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_386_CALL_GATE);
1087
1088 /* Determine the new instruction pointer from the gate descriptor. */
1089 uNewRip = pDesc->Legacy.Gate.u16OffsetLow
1090 | ((uint32_t)pDesc->Legacy.Gate.u16OffsetHigh << 16)
1091 | ((uint64_t)pDesc->Long.Gate.u32OffsetTop << 32);
1092
1093 /* Perform DPL checks on the gate descriptor. */
1094 if ( pDesc->Legacy.Gate.u2Dpl < IEM_GET_CPL(pVCpu)
1095 || pDesc->Legacy.Gate.u2Dpl < (uSel & X86_SEL_RPL))
1096 {
1097 Log(("BranchCallGate invalid priv. uSel=%04x Gate DPL=%d CPL=%u Sel RPL=%u -> #GP\n", uSel, pDesc->Legacy.Gate.u2Dpl,
1098 IEM_GET_CPL(pVCpu), (uSel & X86_SEL_RPL)));
1099 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
1100 }
1101
1102 /** @todo does this catch NULL selectors, too? */
1103 if (!pDesc->Legacy.Gen.u1Present)
1104 {
1105 Log(("BranchCallGate Gate not present uSel=%04x -> #NP\n", uSel));
1106 return iemRaiseSelectorNotPresentBySelector(pVCpu, uSel);
1107 }
1108
1109 /*
1110 * Fetch the target CS descriptor from the GDT or LDT.
1111 */
1112 uNewCS = pDesc->Legacy.Gate.u16Sel;
1113 rcStrict = iemMemFetchSelDesc(pVCpu, &DescCS, uNewCS, X86_XCPT_GP);
1114 if (rcStrict != VINF_SUCCESS)
1115 return rcStrict;
1116
1117 /* Target CS must be a code selector. */
1118 if ( !DescCS.Legacy.Gen.u1DescType
1119 || !(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE) )
1120 {
1121 Log(("BranchCallGate %04x:%08RX64 -> not a code selector (u1DescType=%u u4Type=%#x).\n",
1122 uNewCS, uNewRip, DescCS.Legacy.Gen.u1DescType, DescCS.Legacy.Gen.u4Type));
1123 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCS);
1124 }
1125
1126 /* Privilege checks on target CS. */
1127 if (enmBranch == IEMBRANCH_JUMP)
1128 {
1129 if (DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF)
1130 {
1131 if (DescCS.Legacy.Gen.u2Dpl > IEM_GET_CPL(pVCpu))
1132 {
1133 Log(("BranchCallGate jump (conforming) bad DPL uNewCS=%04x Gate DPL=%d CPL=%u -> #GP\n",
1134 uNewCS, DescCS.Legacy.Gen.u2Dpl, IEM_GET_CPL(pVCpu)));
1135 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCS);
1136 }
1137 }
1138 else
1139 {
1140 if (DescCS.Legacy.Gen.u2Dpl != IEM_GET_CPL(pVCpu))
1141 {
1142 Log(("BranchCallGate jump (non-conforming) bad DPL uNewCS=%04x Gate DPL=%d CPL=%u -> #GP\n",
1143 uNewCS, DescCS.Legacy.Gen.u2Dpl, IEM_GET_CPL(pVCpu)));
1144 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCS);
1145 }
1146 }
1147 }
1148 else
1149 {
1150 Assert(enmBranch == IEMBRANCH_CALL);
1151 if (DescCS.Legacy.Gen.u2Dpl > IEM_GET_CPL(pVCpu))
1152 {
1153 Log(("BranchCallGate call invalid priv. uNewCS=%04x Gate DPL=%d CPL=%u -> #GP\n",
1154 uNewCS, DescCS.Legacy.Gen.u2Dpl, IEM_GET_CPL(pVCpu)));
1155 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCS & X86_SEL_MASK_OFF_RPL);
1156 }
1157 }
1158
1159 /* Additional long mode checks. */
1160 if (IEM_IS_LONG_MODE(pVCpu))
1161 {
1162 if (!DescCS.Legacy.Gen.u1Long)
1163 {
1164 Log(("BranchCallGate uNewCS %04x -> not a 64-bit code segment.\n", uNewCS));
1165 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCS);
1166 }
1167
1168 /* L vs D. */
1169 if ( DescCS.Legacy.Gen.u1Long
1170 && DescCS.Legacy.Gen.u1DefBig)
1171 {
1172 Log(("BranchCallGate uNewCS %04x -> both L and D are set.\n", uNewCS));
1173 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCS);
1174 }
1175 }
1176
1177 if (!DescCS.Legacy.Gate.u1Present)
1178 {
1179 Log(("BranchCallGate target CS is not present. uSel=%04x uNewCS=%04x -> #NP(CS)\n", uSel, uNewCS));
1180 return iemRaiseSelectorNotPresentBySelector(pVCpu, uNewCS);
1181 }
1182
1183 if (enmBranch == IEMBRANCH_JUMP)
1184 {
1185 /** @todo This is very similar to regular far jumps; merge! */
1186 /* Jumps are fairly simple... */
1187
1188 /* Chop the high bits off if 16-bit gate (Intel says so). */
1189 if (pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_286_CALL_GATE)
1190 uNewRip = (uint16_t)uNewRip;
1191
1192 /* Limit check for non-long segments. */
1193 cbLimit = X86DESC_LIMIT_G(&DescCS.Legacy);
1194 if (DescCS.Legacy.Gen.u1Long)
1195 u64Base = 0;
1196 else
1197 {
1198 if (uNewRip > cbLimit)
1199 {
1200 Log(("BranchCallGate jump %04x:%08RX64 -> out of bounds (%#x) -> #GP(0)\n", uNewCS, uNewRip, cbLimit));
1201 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, 0);
1202 }
1203 u64Base = X86DESC_BASE(&DescCS.Legacy);
1204 }
1205
1206 /* Canonical address check. */
1207 if (!IEM_IS_CANONICAL(uNewRip))
1208 {
1209 Log(("BranchCallGate jump %04x:%016RX64 - not canonical -> #GP\n", uNewCS, uNewRip));
1210 return iemRaiseNotCanonical(pVCpu);
1211 }
1212
1213 /*
1214 * Ok, everything checked out fine. Now set the accessed bit before
1215 * committing the result into CS, CSHID and RIP.
1216 */
1217 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1218 {
1219 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uNewCS);
1220 if (rcStrict != VINF_SUCCESS)
1221 return rcStrict;
1222 /** @todo check what VT-x and AMD-V does. */
1223 DescCS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1224 }
1225
1226 /* commit */
1227 pVCpu->cpum.GstCtx.rip = uNewRip;
1228 pVCpu->cpum.GstCtx.cs.Sel = uNewCS & X86_SEL_MASK_OFF_RPL;
1229 pVCpu->cpum.GstCtx.cs.Sel |= IEM_GET_CPL(pVCpu); /** @todo is this right for conforming segs? or in general? */
1230 pVCpu->cpum.GstCtx.cs.ValidSel = pVCpu->cpum.GstCtx.cs.Sel;
1231 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
1232 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCS.Legacy);
1233 pVCpu->cpum.GstCtx.cs.u32Limit = cbLimit;
1234 pVCpu->cpum.GstCtx.cs.u64Base = u64Base;
1235 }
1236 else
1237 {
1238 Assert(enmBranch == IEMBRANCH_CALL);
1239 /* Calls are much more complicated. */
1240
1241 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF) && (DescCS.Legacy.Gen.u2Dpl < IEM_GET_CPL(pVCpu)))
1242 {
1243 /* More privilege. This is the fun part. */
1244 Assert(!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF)); /* Filtered out above. */
1245
1246 /*
1247 * Determine new SS:rSP from the TSS.
1248 */
1249 Assert(!pVCpu->cpum.GstCtx.tr.Attr.n.u1DescType);
1250
1251 /* Figure out where the new stack pointer is stored in the TSS. */
1252 uint8_t const uNewCSDpl = DescCS.Legacy.Gen.u2Dpl;
1253 uint16_t offNewStack; /* Offset of new stack in TSS. */
1254 uint16_t cbNewStack; /* Number of bytes the stack information takes up in TSS. */
1255 if (!IEM_IS_LONG_MODE(pVCpu))
1256 {
1257 if (pVCpu->cpum.GstCtx.tr.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_BUSY)
1258 {
1259 offNewStack = RT_UOFFSETOF(X86TSS32, esp0) + uNewCSDpl * 8;
1260 cbNewStack = RT_SIZEOFMEMB(X86TSS32, esp0) + RT_SIZEOFMEMB(X86TSS32, ss0);
1261 }
1262 else
1263 {
1264 Assert(pVCpu->cpum.GstCtx.tr.Attr.n.u4Type == X86_SEL_TYPE_SYS_286_TSS_BUSY);
1265 offNewStack = RT_UOFFSETOF(X86TSS16, sp0) + uNewCSDpl * 4;
1266 cbNewStack = RT_SIZEOFMEMB(X86TSS16, sp0) + RT_SIZEOFMEMB(X86TSS16, ss0);
1267 }
1268 }
1269 else
1270 {
1271 Assert(pVCpu->cpum.GstCtx.tr.Attr.n.u4Type == AMD64_SEL_TYPE_SYS_TSS_BUSY);
1272 offNewStack = RT_UOFFSETOF(X86TSS64, rsp0) + uNewCSDpl * RT_SIZEOFMEMB(X86TSS64, rsp0);
1273 cbNewStack = RT_SIZEOFMEMB(X86TSS64, rsp0);
1274 }
1275
1276 /* Check against TSS limit. */
1277 if ((uint16_t)(offNewStack + cbNewStack - 1) > pVCpu->cpum.GstCtx.tr.u32Limit)
1278 {
1279 Log(("BranchCallGate inner stack past TSS limit - %u > %u -> #TS(TSS)\n", offNewStack + cbNewStack - 1, pVCpu->cpum.GstCtx.tr.u32Limit));
1280 return iemRaiseTaskSwitchFaultBySelector(pVCpu, pVCpu->cpum.GstCtx.tr.Sel);
1281 }
1282
1283 uint8_t bUnmapInfo;
1284 RTPTRUNION uPtrTss;
1285 RTGCPTR GCPtrTss = pVCpu->cpum.GstCtx.tr.u64Base + offNewStack;
1286 rcStrict = iemMemMap(pVCpu, &uPtrTss.pv, &bUnmapInfo, cbNewStack, UINT8_MAX, GCPtrTss, IEM_ACCESS_SYS_R, 0);
1287 if (rcStrict != VINF_SUCCESS)
1288 {
1289 Log(("BranchCallGate: TSS mapping failed (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
1290 return rcStrict;
1291 }
1292
1293 RTSEL uNewSS;
1294 if (!IEM_IS_LONG_MODE(pVCpu))
1295 {
1296 if (pVCpu->cpum.GstCtx.tr.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_BUSY)
1297 {
1298 uNewRsp = uPtrTss.pu32[0];
1299 uNewSS = uPtrTss.pu16[2];
1300 }
1301 else
1302 {
1303 Assert(pVCpu->cpum.GstCtx.tr.Attr.n.u4Type == X86_SEL_TYPE_SYS_286_TSS_BUSY);
1304 uNewRsp = uPtrTss.pu16[0];
1305 uNewSS = uPtrTss.pu16[1];
1306 }
1307 }
1308 else
1309 {
1310 Assert(pVCpu->cpum.GstCtx.tr.Attr.n.u4Type == AMD64_SEL_TYPE_SYS_TSS_BUSY);
1311 /* SS will be a NULL selector, but that's valid. */
1312 uNewRsp = uPtrTss.pu64[0];
1313 uNewSS = uNewCSDpl;
1314 }
1315
1316 /* Done with the TSS now. */
1317 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
1318 if (rcStrict != VINF_SUCCESS)
1319 {
1320 Log(("BranchCallGate: TSS unmapping failed (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
1321 return rcStrict;
1322 }
1323
1324 /* Only used outside of long mode. */
1325 uint8_t const cbWords = pDesc->Legacy.Gate.u5ParmCount;
1326
1327 /* If EFER.LMA is 0, there's extra work to do. */
1328 IEMSELDESC DescSS;
1329 if (!IEM_IS_LONG_MODE(pVCpu))
1330 {
1331 if ((uNewSS & X86_SEL_MASK_OFF_RPL) == 0)
1332 {
1333 Log(("BranchCallGate new SS NULL -> #TS(NewSS)\n"));
1334 return iemRaiseTaskSwitchFaultBySelector(pVCpu, uNewSS);
1335 }
1336
1337 /* Grab the new SS descriptor. */
1338 rcStrict = iemMemFetchSelDesc(pVCpu, &DescSS, uNewSS, X86_XCPT_SS);
1339 if (rcStrict != VINF_SUCCESS)
1340 return rcStrict;
1341
1342 /* Ensure that CS.DPL == SS.RPL == SS.DPL. */
1343 if ( (DescCS.Legacy.Gen.u2Dpl != (uNewSS & X86_SEL_RPL))
1344 || (DescCS.Legacy.Gen.u2Dpl != DescSS.Legacy.Gen.u2Dpl))
1345 {
1346 Log(("BranchCallGate call bad RPL/DPL uNewSS=%04x SS DPL=%d CS DPL=%u -> #TS(NewSS)\n",
1347 uNewSS, DescCS.Legacy.Gen.u2Dpl, DescCS.Legacy.Gen.u2Dpl));
1348 return iemRaiseTaskSwitchFaultBySelector(pVCpu, uNewSS);
1349 }
1350
1351 /* Ensure new SS is a writable data segment. */
1352 if ((DescSS.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE)) != X86_SEL_TYPE_WRITE)
1353 {
1354 Log(("BranchCallGate call new SS -> not a writable data selector (u4Type=%#x)\n", DescSS.Legacy.Gen.u4Type));
1355 return iemRaiseTaskSwitchFaultBySelector(pVCpu, uNewSS);
1356 }
1357
1358 if (!DescSS.Legacy.Gen.u1Present)
1359 {
1360 Log(("BranchCallGate New stack not present uSel=%04x -> #SS(NewSS)\n", uNewSS));
1361 return iemRaiseStackSelectorNotPresentBySelector(pVCpu, uNewSS);
1362 }
1363 if (pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_386_CALL_GATE)
1364 cbNewStack = (uint16_t)sizeof(uint32_t) * (4 + cbWords);
1365 else
1366 cbNewStack = (uint16_t)sizeof(uint16_t) * (4 + cbWords);
1367 }
1368 else
1369 {
1370 /* Just grab the new (NULL) SS descriptor. */
1371 /** @todo testcase: Check whether the zero GDT entry is actually loaded here
1372 * like we do... */
1373 rcStrict = iemMemFetchSelDesc(pVCpu, &DescSS, uNewSS, X86_XCPT_SS);
1374 if (rcStrict != VINF_SUCCESS)
1375 return rcStrict;
1376
1377 cbNewStack = sizeof(uint64_t) * 4;
1378 }
1379
1380 /** @todo According to Intel, new stack is checked for enough space first,
1381 * then switched. According to AMD, the stack is switched first and
1382 * then pushes might fault!
1383 * NB: OS/2 Warp 3/4 actively relies on the fact that possible
1384 * incoming stack \#PF happens before actual stack switch. AMD is
1385 * either lying or implicitly assumes that new state is committed
1386 * only if and when an instruction doesn't fault.
1387 */
1388
1389 /** @todo According to AMD, CS is loaded first, then SS.
1390 * According to Intel, it's the other way around!?
1391 */
1392
1393 /** @todo Intel and AMD disagree on when exactly the CPL changes! */
1394
1395 /* Set the accessed bit before committing new SS. */
1396 if (!(DescSS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1397 {
1398 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uNewSS);
1399 if (rcStrict != VINF_SUCCESS)
1400 return rcStrict;
1401 DescSS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1402 }
1403
1404 /* Remember the old SS:rSP and their linear address. */
1405 RTSEL const uOldSS = pVCpu->cpum.GstCtx.ss.Sel;
1406 uint64_t const uOldRsp = pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig ? pVCpu->cpum.GstCtx.rsp : pVCpu->cpum.GstCtx.sp;
1407
1408 RTGCPTR const GCPtrParmWds = pVCpu->cpum.GstCtx.ss.u64Base + uOldRsp;
1409
1410 /* HACK ALERT! Probe if the write to the new stack will succeed. May #SS(NewSS)
1411 or #PF, the former is not implemented in this workaround. */
1412 /** @todo Proper fix callgate target stack exceptions. */
1413 /** @todo testcase: Cover callgates with partially or fully inaccessible
1414 * target stacks. */
1415 void *pvNewFrame;
1416 RTGCPTR GCPtrNewStack = X86DESC_BASE(&DescSS.Legacy) + uNewRsp - cbNewStack;
1417 rcStrict = iemMemMap(pVCpu, &pvNewFrame, &bUnmapInfo, cbNewStack, UINT8_MAX, GCPtrNewStack, IEM_ACCESS_SYS_RW, 0);
1418 if (rcStrict != VINF_SUCCESS)
1419 {
1420 Log(("BranchCallGate: Incoming stack (%04x:%08RX64) not accessible, rc=%Rrc\n", uNewSS, uNewRsp, VBOXSTRICTRC_VAL(rcStrict)));
1421 return rcStrict;
1422 }
1423 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
1424 if (rcStrict != VINF_SUCCESS)
1425 {
1426 Log(("BranchCallGate: New stack probe unmapping failed (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
1427 return rcStrict;
1428 }
1429
1430 /* Commit new SS:rSP. */
1431 pVCpu->cpum.GstCtx.ss.Sel = uNewSS;
1432 pVCpu->cpum.GstCtx.ss.ValidSel = uNewSS;
1433 pVCpu->cpum.GstCtx.ss.Attr.u = X86DESC_GET_HID_ATTR(&DescSS.Legacy);
1434 pVCpu->cpum.GstCtx.ss.u32Limit = X86DESC_LIMIT_G(&DescSS.Legacy);
1435 pVCpu->cpum.GstCtx.ss.u64Base = X86DESC_BASE(&DescSS.Legacy);
1436 pVCpu->cpum.GstCtx.ss.fFlags = CPUMSELREG_FLAGS_VALID;
1437 pVCpu->cpum.GstCtx.rsp = uNewRsp;
1438 IEM_SET_CPL(pVCpu, uNewCSDpl); /** @todo Are the parameter words accessed using the new CPL or the old CPL? */
1439 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
1440 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_HIDDEN_SEL_REGS);
1441
1442 /* At this point the stack access must not fail because new state was already committed. */
1443 /** @todo this can still fail due to SS.LIMIT not check. */
1444 uint8_t bUnmapInfoRet;
1445 rcStrict = iemMemStackPushBeginSpecial(pVCpu, cbNewStack,
1446 IEM_IS_LONG_MODE(pVCpu) ? 7
1447 : pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_386_CALL_GATE ? 3 : 1,
1448 &uPtrRet.pv, &bUnmapInfoRet, &uNewRsp);
1449 AssertMsgReturn(rcStrict == VINF_SUCCESS, ("BranchCallGate: New stack mapping failed (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)),
1450 VERR_INTERNAL_ERROR_5);
1451
1452 if (!IEM_IS_LONG_MODE(pVCpu))
1453 {
1454 if (pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_386_CALL_GATE)
1455 {
1456 if (cbWords)
1457 {
1458 /* Map the relevant chunk of the old stack. */
1459 RTPTRUNION uPtrParmWds;
1460 rcStrict = iemMemMap(pVCpu, &uPtrParmWds.pv, &bUnmapInfo, cbWords * 4, UINT8_MAX, GCPtrParmWds,
1461 IEM_ACCESS_DATA_R, 0 /** @todo Can uNewCSDpl == 3? Then we need alignment mask here! */);
1462 if (rcStrict != VINF_SUCCESS)
1463 {
1464 Log(("BranchCallGate: Old stack mapping (32-bit) failed (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
1465 return rcStrict;
1466 }
1467
1468 /* Copy the parameter (d)words. */
1469 for (int i = 0; i < cbWords; ++i)
1470 uPtrRet.pu32[2 + i] = uPtrParmWds.pu32[i];
1471
1472 /* Unmap the old stack. */
1473 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
1474 if (rcStrict != VINF_SUCCESS)
1475 {
1476 Log(("BranchCallGate: Old stack unmapping (32-bit) failed (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
1477 return rcStrict;
1478 }
1479 }
1480
1481 /* Push the old CS:rIP. */
1482 uPtrRet.pu32[0] = pVCpu->cpum.GstCtx.eip + cbInstr;
1483 uPtrRet.pu32[1] = pVCpu->cpum.GstCtx.cs.Sel; /** @todo Testcase: What is written to the high word when pushing CS? */
1484
1485 /* Push the old SS:rSP. */
1486 uPtrRet.pu32[2 + cbWords + 0] = uOldRsp;
1487 uPtrRet.pu32[2 + cbWords + 1] = uOldSS;
1488 }
1489 else
1490 {
1491 Assert(pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_286_CALL_GATE);
1492
1493 if (cbWords)
1494 {
1495 /* Map the relevant chunk of the old stack. */
1496 RTPTRUNION uPtrParmWds;
1497 rcStrict = iemMemMap(pVCpu, &uPtrParmWds.pv, &bUnmapInfo, cbWords * 2, UINT8_MAX, GCPtrParmWds,
1498 IEM_ACCESS_DATA_R, 0 /** @todo Can uNewCSDpl == 3? Then we need alignment mask here! */);
1499 if (rcStrict != VINF_SUCCESS)
1500 {
1501 Log(("BranchCallGate: Old stack mapping (16-bit) failed (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
1502 return rcStrict;
1503 }
1504
1505 /* Copy the parameter words. */
1506 for (int i = 0; i < cbWords; ++i)
1507 uPtrRet.pu16[2 + i] = uPtrParmWds.pu16[i];
1508
1509 /* Unmap the old stack. */
1510 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
1511 if (rcStrict != VINF_SUCCESS)
1512 {
1513 Log(("BranchCallGate: Old stack unmapping (32-bit) failed (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
1514 return rcStrict;
1515 }
1516 }
1517
1518 /* Push the old CS:rIP. */
1519 uPtrRet.pu16[0] = pVCpu->cpum.GstCtx.ip + cbInstr;
1520 uPtrRet.pu16[1] = pVCpu->cpum.GstCtx.cs.Sel;
1521
1522 /* Push the old SS:rSP. */
1523 uPtrRet.pu16[2 + cbWords + 0] = uOldRsp;
1524 uPtrRet.pu16[2 + cbWords + 1] = uOldSS;
1525 }
1526 }
1527 else
1528 {
1529 Assert(pDesc->Legacy.Gate.u4Type == AMD64_SEL_TYPE_SYS_CALL_GATE);
1530
1531 /* For 64-bit gates, no parameters are copied. Just push old SS:rSP and CS:rIP. */
1532 uPtrRet.pu64[0] = pVCpu->cpum.GstCtx.rip + cbInstr;
1533 uPtrRet.pu64[1] = pVCpu->cpum.GstCtx.cs.Sel; /** @todo Testcase: What is written to the high words when pushing CS? */
1534 uPtrRet.pu64[2] = uOldRsp;
1535 uPtrRet.pu64[3] = uOldSS; /** @todo Testcase: What is written to the high words when pushing SS? */
1536 }
1537
1538 rcStrict = iemMemStackPushCommitSpecial(pVCpu, bUnmapInfoRet, uNewRsp);
1539 if (rcStrict != VINF_SUCCESS)
1540 {
1541 Log(("BranchCallGate: New stack unmapping failed (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
1542 return rcStrict;
1543 }
1544
1545 /* Chop the high bits off if 16-bit gate (Intel says so). */
1546 if (pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_286_CALL_GATE)
1547 uNewRip = (uint16_t)uNewRip;
1548
1549 /* Limit / canonical check. */
1550 cbLimit = X86DESC_LIMIT_G(&DescCS.Legacy);
1551 if (!IEM_IS_LONG_MODE(pVCpu))
1552 {
1553 if (uNewRip > cbLimit)
1554 {
1555 Log(("BranchCallGate %04x:%08RX64 -> out of bounds (%#x)\n", uNewCS, uNewRip, cbLimit));
1556 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, 0);
1557 }
1558 u64Base = X86DESC_BASE(&DescCS.Legacy);
1559 }
1560 else
1561 {
1562 Assert(pDesc->Legacy.Gate.u4Type == AMD64_SEL_TYPE_SYS_CALL_GATE);
1563 if (!IEM_IS_CANONICAL(uNewRip))
1564 {
1565 Log(("BranchCallGate call %04x:%016RX64 - not canonical -> #GP\n", uNewCS, uNewRip));
1566 return iemRaiseNotCanonical(pVCpu);
1567 }
1568 u64Base = 0;
1569 }
1570
1571 /*
1572 * Now set the accessed bit before
1573 * writing the return address to the stack and committing the result into
1574 * CS, CSHID and RIP.
1575 */
1576 /** @todo Testcase: Need to check WHEN exactly the accessed bit is set. */
1577 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1578 {
1579 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uNewCS);
1580 if (rcStrict != VINF_SUCCESS)
1581 return rcStrict;
1582 /** @todo check what VT-x and AMD-V does. */
1583 DescCS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1584 }
1585
1586 /* Commit new CS:rIP. */
1587 pVCpu->cpum.GstCtx.rip = uNewRip;
1588 pVCpu->cpum.GstCtx.cs.Sel = uNewCS & X86_SEL_MASK_OFF_RPL;
1589 pVCpu->cpum.GstCtx.cs.Sel |= IEM_GET_CPL(pVCpu);
1590 pVCpu->cpum.GstCtx.cs.ValidSel = pVCpu->cpum.GstCtx.cs.Sel;
1591 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
1592 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCS.Legacy);
1593 pVCpu->cpum.GstCtx.cs.u32Limit = cbLimit;
1594 pVCpu->cpum.GstCtx.cs.u64Base = u64Base;
1595 }
1596 else
1597 {
1598 /* Same privilege. */
1599 /** @todo This is very similar to regular far calls; merge! */
1600
1601 /* Check stack first - may #SS(0). */
1602 /** @todo check how gate size affects pushing of CS! Does callf 16:32 in
1603 * 16-bit code cause a two or four byte CS to be pushed? */
1604 uint8_t bUnmapInfoRet;
1605 rcStrict = iemMemStackPushBeginSpecial(pVCpu,
1606 IEM_IS_LONG_MODE(pVCpu) ? 8+8
1607 : pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_386_CALL_GATE ? 4+4 : 2+2,
1608 IEM_IS_LONG_MODE(pVCpu) ? 7
1609 : pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_386_CALL_GATE ? 3 : 2,
1610 &uPtrRet.pv, &bUnmapInfoRet, &uNewRsp);
1611 if (rcStrict != VINF_SUCCESS)
1612 return rcStrict;
1613
1614 /* Chop the high bits off if 16-bit gate (Intel says so). */
1615 if (pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_286_CALL_GATE)
1616 uNewRip = (uint16_t)uNewRip;
1617
1618 /* Limit / canonical check. */
1619 cbLimit = X86DESC_LIMIT_G(&DescCS.Legacy);
1620 if (!IEM_IS_LONG_MODE(pVCpu))
1621 {
1622 if (uNewRip > cbLimit)
1623 {
1624 Log(("BranchCallGate %04x:%08RX64 -> out of bounds (%#x)\n", uNewCS, uNewRip, cbLimit));
1625 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, 0);
1626 }
1627 u64Base = X86DESC_BASE(&DescCS.Legacy);
1628 }
1629 else
1630 {
1631 if (!IEM_IS_CANONICAL(uNewRip))
1632 {
1633 Log(("BranchCallGate call %04x:%016RX64 - not canonical -> #GP\n", uNewCS, uNewRip));
1634 return iemRaiseNotCanonical(pVCpu);
1635 }
1636 u64Base = 0;
1637 }
1638
1639 /*
1640 * Now set the accessed bit before
1641 * writing the return address to the stack and committing the result into
1642 * CS, CSHID and RIP.
1643 */
1644 /** @todo Testcase: Need to check WHEN exactly the accessed bit is set. */
1645 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1646 {
1647 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uNewCS);
1648 if (rcStrict != VINF_SUCCESS)
1649 return rcStrict;
1650 /** @todo check what VT-x and AMD-V does. */
1651 DescCS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1652 }
1653
1654 /* stack */
1655 if (!IEM_IS_LONG_MODE(pVCpu))
1656 {
1657 if (pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_386_CALL_GATE)
1658 {
1659 uPtrRet.pu32[0] = pVCpu->cpum.GstCtx.eip + cbInstr;
1660 uPtrRet.pu32[1] = pVCpu->cpum.GstCtx.cs.Sel; /** @todo Testcase: What is written to the high word when pushing CS? */
1661 }
1662 else
1663 {
1664 Assert(pDesc->Legacy.Gate.u4Type == X86_SEL_TYPE_SYS_286_CALL_GATE);
1665 uPtrRet.pu16[0] = pVCpu->cpum.GstCtx.ip + cbInstr;
1666 uPtrRet.pu16[1] = pVCpu->cpum.GstCtx.cs.Sel;
1667 }
1668 }
1669 else
1670 {
1671 Assert(pDesc->Legacy.Gate.u4Type == AMD64_SEL_TYPE_SYS_CALL_GATE);
1672 uPtrRet.pu64[0] = pVCpu->cpum.GstCtx.rip + cbInstr;
1673 uPtrRet.pu64[1] = pVCpu->cpum.GstCtx.cs.Sel; /** @todo Testcase: What is written to the high words when pushing CS? */
1674 }
1675
1676 rcStrict = iemMemStackPushCommitSpecial(pVCpu, bUnmapInfoRet, uNewRsp);
1677 if (rcStrict != VINF_SUCCESS)
1678 return rcStrict;
1679
1680 /* commit */
1681 pVCpu->cpum.GstCtx.rip = uNewRip;
1682 pVCpu->cpum.GstCtx.cs.Sel = uNewCS & X86_SEL_MASK_OFF_RPL;
1683 pVCpu->cpum.GstCtx.cs.Sel |= IEM_GET_CPL(pVCpu);
1684 pVCpu->cpum.GstCtx.cs.ValidSel = pVCpu->cpum.GstCtx.cs.Sel;
1685 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
1686 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCS.Legacy);
1687 pVCpu->cpum.GstCtx.cs.u32Limit = cbLimit;
1688 pVCpu->cpum.GstCtx.cs.u64Base = u64Base;
1689 }
1690 }
1691 pVCpu->cpum.GstCtx.eflags.Bits.u1RF = 0;
1692
1693 iemRecalcExecModeAndCplAndAcFlags(pVCpu);
1694
1695/** @todo single stepping */
1696
1697 /* Flush the prefetch buffer. */
1698 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr);
1699 return VINF_SUCCESS;
1700#endif /* IEM_IMPLEMENTS_CALLGATE */
1701}
1702
1703
1704/**
1705 * Implements far jumps and calls thru system selectors.
1706 *
1707 * @returns VBox strict status code.
1708 * @param pVCpu The cross context virtual CPU structure of the
1709 * calling thread.
1710 * @param cbInstr The current instruction length.
1711 * @param uSel The selector.
1712 * @param enmBranch The kind of branching we're performing.
1713 * @param enmEffOpSize The effective operand size.
1714 * @param pDesc The descriptor corresponding to @a uSel.
1715 */
1716static VBOXSTRICTRC iemCImpl_BranchSysSel(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t uSel, IEMBRANCH enmBranch,
1717 IEMMODE enmEffOpSize, PIEMSELDESC pDesc)
1718{
1719 Assert(enmBranch == IEMBRANCH_JUMP || enmBranch == IEMBRANCH_CALL);
1720 Assert((uSel & X86_SEL_MASK_OFF_RPL));
1721 IEM_CTX_IMPORT_RET(pVCpu, IEM_CPUMCTX_EXTRN_XCPT_MASK);
1722
1723 if (IEM_IS_LONG_MODE(pVCpu))
1724 switch (pDesc->Legacy.Gen.u4Type)
1725 {
1726 case AMD64_SEL_TYPE_SYS_CALL_GATE:
1727 return iemCImpl_BranchCallGate(pVCpu, cbInstr, uSel, enmBranch, enmEffOpSize, pDesc);
1728
1729 default:
1730 case AMD64_SEL_TYPE_SYS_LDT:
1731 case AMD64_SEL_TYPE_SYS_TSS_BUSY:
1732 case AMD64_SEL_TYPE_SYS_TSS_AVAIL:
1733 case AMD64_SEL_TYPE_SYS_TRAP_GATE:
1734 case AMD64_SEL_TYPE_SYS_INT_GATE:
1735 Log(("branch %04x -> wrong sys selector (64-bit): %d\n", uSel, pDesc->Legacy.Gen.u4Type));
1736 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
1737 }
1738
1739 switch (pDesc->Legacy.Gen.u4Type)
1740 {
1741 case X86_SEL_TYPE_SYS_286_CALL_GATE:
1742 case X86_SEL_TYPE_SYS_386_CALL_GATE:
1743 return iemCImpl_BranchCallGate(pVCpu, cbInstr, uSel, enmBranch, enmEffOpSize, pDesc);
1744
1745 case X86_SEL_TYPE_SYS_TASK_GATE:
1746 return iemCImpl_BranchTaskGate(pVCpu, cbInstr, uSel, enmBranch, enmEffOpSize, pDesc);
1747
1748 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
1749 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
1750 return iemCImpl_BranchTaskSegment(pVCpu, cbInstr, uSel, enmBranch, enmEffOpSize, pDesc);
1751
1752 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
1753 Log(("branch %04x -> busy 286 TSS\n", uSel));
1754 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
1755
1756 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
1757 Log(("branch %04x -> busy 386 TSS\n", uSel));
1758 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
1759
1760 default:
1761 case X86_SEL_TYPE_SYS_LDT:
1762 case X86_SEL_TYPE_SYS_286_INT_GATE:
1763 case X86_SEL_TYPE_SYS_286_TRAP_GATE:
1764 case X86_SEL_TYPE_SYS_386_INT_GATE:
1765 case X86_SEL_TYPE_SYS_386_TRAP_GATE:
1766 Log(("branch %04x -> wrong sys selector: %d\n", uSel, pDesc->Legacy.Gen.u4Type));
1767 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
1768 }
1769}
1770
1771
1772/**
1773 * Implements far jumps.
1774 *
1775 * @param uSel The selector.
1776 * @param offSeg The segment offset.
1777 * @param enmEffOpSize The effective operand size.
1778 */
1779IEM_CIMPL_DEF_3(iemCImpl_FarJmp, uint16_t, uSel, uint64_t, offSeg, IEMMODE, enmEffOpSize)
1780{
1781 NOREF(cbInstr);
1782 Assert(offSeg <= UINT32_MAX || (!IEM_IS_GUEST_CPU_AMD(pVCpu) && IEM_IS_64BIT_CODE(pVCpu)));
1783
1784 /*
1785 * Real mode and V8086 mode are easy. The only snag seems to be that
1786 * CS.limit doesn't change and the limit check is done against the current
1787 * limit.
1788 */
1789 /** @todo Robert Collins claims (The Segment Descriptor Cache, DDJ August
1790 * 1998) that up to and including the Intel 486, far control
1791 * transfers in real mode set default CS attributes (0x93) and also
1792 * set a 64K segment limit. Starting with the Pentium, the
1793 * attributes and limit are left alone but the access rights are
1794 * ignored. We only implement the Pentium+ behavior.
1795 * */
1796 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
1797 {
1798 Assert(enmEffOpSize == IEMMODE_16BIT || enmEffOpSize == IEMMODE_32BIT);
1799 if (offSeg > pVCpu->cpum.GstCtx.cs.u32Limit)
1800 {
1801 Log(("iemCImpl_FarJmp: 16-bit limit\n"));
1802 return iemRaiseGeneralProtectionFault0(pVCpu);
1803 }
1804
1805 if (enmEffOpSize == IEMMODE_16BIT) /** @todo WRONG, must pass this. */
1806 pVCpu->cpum.GstCtx.rip = offSeg;
1807 else
1808 pVCpu->cpum.GstCtx.rip = offSeg & UINT16_MAX;
1809 pVCpu->cpum.GstCtx.cs.Sel = uSel;
1810 pVCpu->cpum.GstCtx.cs.ValidSel = uSel;
1811 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
1812 pVCpu->cpum.GstCtx.cs.u64Base = (uint32_t)uSel << 4;
1813
1814 /* Update the FLAT 32-bit mode flag, if we're in 32-bit unreal mode (unlikely): */
1815 if (RT_LIKELY(!IEM_IS_32BIT_CODE(pVCpu)))
1816 { /* likely */ }
1817 else if (uSel != 0)
1818 pVCpu->iem.s.fExec &= ~IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK;
1819 else
1820 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK)
1821 | iemCalc32BitFlatIndicator(pVCpu);
1822
1823 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
1824 }
1825
1826 /*
1827 * Protected mode. Need to parse the specified descriptor...
1828 */
1829 if (!(uSel & X86_SEL_MASK_OFF_RPL))
1830 {
1831 Log(("jmpf %04x:%08RX64 -> invalid selector, #GP(0)\n", uSel, offSeg));
1832 return iemRaiseGeneralProtectionFault0(pVCpu);
1833 }
1834
1835 /* Fetch the descriptor. */
1836 IEMSELDESC Desc;
1837 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pVCpu, &Desc, uSel, X86_XCPT_GP);
1838 if (rcStrict != VINF_SUCCESS)
1839 return rcStrict;
1840
1841 /* Is it there? */
1842 if (!Desc.Legacy.Gen.u1Present) /** @todo this is probably checked too early. Testcase! */
1843 {
1844 Log(("jmpf %04x:%08RX64 -> segment not present\n", uSel, offSeg));
1845 return iemRaiseSelectorNotPresentBySelector(pVCpu, uSel);
1846 }
1847
1848 /*
1849 * Deal with it according to its type. We do the standard code selectors
1850 * here and dispatch the system selectors to worker functions.
1851 */
1852 if (!Desc.Legacy.Gen.u1DescType)
1853 return iemCImpl_BranchSysSel(pVCpu, cbInstr, uSel, IEMBRANCH_JUMP, enmEffOpSize, &Desc);
1854
1855 /* Only code segments. */
1856 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE))
1857 {
1858 Log(("jmpf %04x:%08RX64 -> not a code selector (u4Type=%#x).\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
1859 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
1860 }
1861
1862 /* L vs D. */
1863 if ( Desc.Legacy.Gen.u1Long
1864 && Desc.Legacy.Gen.u1DefBig
1865 && IEM_IS_LONG_MODE(pVCpu))
1866 {
1867 Log(("jmpf %04x:%08RX64 -> both L and D are set.\n", uSel, offSeg));
1868 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
1869 }
1870
1871 /* DPL/RPL/CPL check, where conforming segments makes a difference. */
1872 if (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF)
1873 {
1874 if (IEM_GET_CPL(pVCpu) < Desc.Legacy.Gen.u2Dpl)
1875 {
1876 Log(("jmpf %04x:%08RX64 -> DPL violation (conforming); DPL=%d CPL=%u\n",
1877 uSel, offSeg, Desc.Legacy.Gen.u2Dpl, IEM_GET_CPL(pVCpu)));
1878 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
1879 }
1880 }
1881 else
1882 {
1883 if (IEM_GET_CPL(pVCpu) != Desc.Legacy.Gen.u2Dpl)
1884 {
1885 Log(("jmpf %04x:%08RX64 -> CPL != DPL; DPL=%d CPL=%u\n", uSel, offSeg, Desc.Legacy.Gen.u2Dpl, IEM_GET_CPL(pVCpu)));
1886 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
1887 }
1888 if ((uSel & X86_SEL_RPL) > IEM_GET_CPL(pVCpu))
1889 {
1890 Log(("jmpf %04x:%08RX64 -> RPL > DPL; RPL=%d CPL=%u\n", uSel, offSeg, (uSel & X86_SEL_RPL), IEM_GET_CPL(pVCpu)));
1891 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
1892 }
1893 }
1894
1895 /* Chop the high bits if 16-bit (Intel says so). */
1896 if (enmEffOpSize == IEMMODE_16BIT)
1897 offSeg &= UINT16_MAX;
1898
1899 /* Limit check and get the base. */
1900 uint64_t u64Base;
1901 uint32_t cbLimit = X86DESC_LIMIT_G(&Desc.Legacy);
1902 if ( !Desc.Legacy.Gen.u1Long
1903 || !IEM_IS_LONG_MODE(pVCpu))
1904 {
1905 if (RT_LIKELY(offSeg <= cbLimit))
1906 u64Base = X86DESC_BASE(&Desc.Legacy);
1907 else
1908 {
1909 Log(("jmpf %04x:%08RX64 -> out of bounds (%#x)\n", uSel, offSeg, cbLimit));
1910 /** @todo Intel says this is \#GP(0)! */
1911 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
1912 }
1913 }
1914 else
1915 u64Base = 0;
1916
1917 /*
1918 * Ok, everything checked out fine. Now set the accessed bit before
1919 * committing the result into CS, CSHID and RIP.
1920 */
1921 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1922 {
1923 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uSel);
1924 if (rcStrict != VINF_SUCCESS)
1925 return rcStrict;
1926 /** @todo check what VT-x and AMD-V does. */
1927 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1928 }
1929
1930 /* commit */
1931 pVCpu->cpum.GstCtx.rip = offSeg;
1932 pVCpu->cpum.GstCtx.cs.Sel = uSel & X86_SEL_MASK_OFF_RPL;
1933 pVCpu->cpum.GstCtx.cs.Sel |= IEM_GET_CPL(pVCpu); /** @todo is this right for conforming segs? or in general? */
1934 pVCpu->cpum.GstCtx.cs.ValidSel = pVCpu->cpum.GstCtx.cs.Sel;
1935 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
1936 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
1937 pVCpu->cpum.GstCtx.cs.u32Limit = cbLimit;
1938 pVCpu->cpum.GstCtx.cs.u64Base = u64Base;
1939
1940 /** @todo check if the hidden bits are loaded correctly for 64-bit
1941 * mode. */
1942
1943 iemRecalcExecModeAndCplAndAcFlags(pVCpu);
1944
1945 /* Flush the prefetch buffer. */
1946 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr);
1947
1948 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
1949}
1950
1951
1952/**
1953 * Implements far calls.
1954 *
1955 * This very similar to iemCImpl_FarJmp.
1956 *
1957 * @param uSel The selector.
1958 * @param offSeg The segment offset.
1959 * @param enmEffOpSize The operand size (in case we need it).
1960 */
1961IEM_CIMPL_DEF_3(iemCImpl_callf, uint16_t, uSel, uint64_t, offSeg, IEMMODE, enmEffOpSize)
1962{
1963 VBOXSTRICTRC rcStrict;
1964 uint64_t uNewRsp;
1965 RTPTRUNION uPtrRet;
1966 uint8_t bUnmapInfo;
1967
1968 /*
1969 * Real mode and V8086 mode are easy. The only snag seems to be that
1970 * CS.limit doesn't change and the limit check is done against the current
1971 * limit.
1972 */
1973 /** @todo See comment for similar code in iemCImpl_FarJmp */
1974 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
1975 {
1976 Assert(enmEffOpSize == IEMMODE_16BIT || enmEffOpSize == IEMMODE_32BIT);
1977
1978 /* Check stack first - may #SS(0). */
1979 rcStrict = iemMemStackPushBeginSpecial(pVCpu, enmEffOpSize == IEMMODE_32BIT ? 4+4 : 2+2,
1980 enmEffOpSize == IEMMODE_32BIT ? 3 : 1,
1981 &uPtrRet.pv, &bUnmapInfo, &uNewRsp);
1982 if (rcStrict != VINF_SUCCESS)
1983 return rcStrict;
1984
1985 /* Check the target address range. */
1986/** @todo this must be wrong! Write unreal mode tests! */
1987 if (offSeg > UINT32_MAX)
1988 return iemRaiseGeneralProtectionFault0(pVCpu);
1989
1990 /* Everything is fine, push the return address. */
1991 if (enmEffOpSize == IEMMODE_16BIT)
1992 {
1993 uPtrRet.pu16[0] = pVCpu->cpum.GstCtx.ip + cbInstr;
1994 uPtrRet.pu16[1] = pVCpu->cpum.GstCtx.cs.Sel;
1995 }
1996 else
1997 {
1998 uPtrRet.pu32[0] = pVCpu->cpum.GstCtx.eip + cbInstr;
1999 uPtrRet.pu16[2] = pVCpu->cpum.GstCtx.cs.Sel;
2000 }
2001 rcStrict = iemMemStackPushCommitSpecial(pVCpu, bUnmapInfo, uNewRsp);
2002 if (rcStrict != VINF_SUCCESS)
2003 return rcStrict;
2004
2005 /* Branch. */
2006 pVCpu->cpum.GstCtx.rip = offSeg;
2007 pVCpu->cpum.GstCtx.cs.Sel = uSel;
2008 pVCpu->cpum.GstCtx.cs.ValidSel = uSel;
2009 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
2010 pVCpu->cpum.GstCtx.cs.u64Base = (uint32_t)uSel << 4;
2011
2012 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
2013 }
2014
2015 /*
2016 * Protected mode. Need to parse the specified descriptor...
2017 */
2018 if (!(uSel & X86_SEL_MASK_OFF_RPL))
2019 {
2020 Log(("callf %04x:%08RX64 -> invalid selector, #GP(0)\n", uSel, offSeg));
2021 return iemRaiseGeneralProtectionFault0(pVCpu);
2022 }
2023
2024 /* Fetch the descriptor. */
2025 IEMSELDESC Desc;
2026 rcStrict = iemMemFetchSelDesc(pVCpu, &Desc, uSel, X86_XCPT_GP);
2027 if (rcStrict != VINF_SUCCESS)
2028 return rcStrict;
2029
2030 /*
2031 * Deal with it according to its type. We do the standard code selectors
2032 * here and dispatch the system selectors to worker functions.
2033 */
2034 if (!Desc.Legacy.Gen.u1DescType)
2035 return iemCImpl_BranchSysSel(pVCpu, cbInstr, uSel, IEMBRANCH_CALL, enmEffOpSize, &Desc);
2036
2037 /* Only code segments. */
2038 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE))
2039 {
2040 Log(("callf %04x:%08RX64 -> not a code selector (u4Type=%#x).\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
2041 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
2042 }
2043
2044 /* L vs D. */
2045 if ( Desc.Legacy.Gen.u1Long
2046 && Desc.Legacy.Gen.u1DefBig
2047 && IEM_IS_LONG_MODE(pVCpu))
2048 {
2049 Log(("callf %04x:%08RX64 -> both L and D are set.\n", uSel, offSeg));
2050 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
2051 }
2052
2053 /* DPL/RPL/CPL check, where conforming segments makes a difference. */
2054 if (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF)
2055 {
2056 if (IEM_GET_CPL(pVCpu) < Desc.Legacy.Gen.u2Dpl)
2057 {
2058 Log(("callf %04x:%08RX64 -> DPL violation (conforming); DPL=%d CPL=%u\n",
2059 uSel, offSeg, Desc.Legacy.Gen.u2Dpl, IEM_GET_CPL(pVCpu)));
2060 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
2061 }
2062 }
2063 else
2064 {
2065 if (IEM_GET_CPL(pVCpu) != Desc.Legacy.Gen.u2Dpl)
2066 {
2067 Log(("callf %04x:%08RX64 -> CPL != DPL; DPL=%d CPL=%u\n", uSel, offSeg, Desc.Legacy.Gen.u2Dpl, IEM_GET_CPL(pVCpu)));
2068 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
2069 }
2070 if ((uSel & X86_SEL_RPL) > IEM_GET_CPL(pVCpu))
2071 {
2072 Log(("callf %04x:%08RX64 -> RPL > DPL; RPL=%d CPL=%u\n", uSel, offSeg, (uSel & X86_SEL_RPL), IEM_GET_CPL(pVCpu)));
2073 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
2074 }
2075 }
2076
2077 /* Is it there? */
2078 if (!Desc.Legacy.Gen.u1Present)
2079 {
2080 Log(("callf %04x:%08RX64 -> segment not present\n", uSel, offSeg));
2081 return iemRaiseSelectorNotPresentBySelector(pVCpu, uSel);
2082 }
2083
2084 /* Check stack first - may #SS(0). */
2085 /** @todo check how operand prefix affects pushing of CS! Does callf 16:32 in
2086 * 16-bit code cause a two or four byte CS to be pushed? */
2087 rcStrict = iemMemStackPushBeginSpecial(pVCpu,
2088 enmEffOpSize == IEMMODE_64BIT ? 8+8 : enmEffOpSize == IEMMODE_32BIT ? 4+4 : 2+2,
2089 enmEffOpSize == IEMMODE_64BIT ? 7 : enmEffOpSize == IEMMODE_32BIT ? 3 : 1,
2090 &uPtrRet.pv, &bUnmapInfo, &uNewRsp);
2091 if (rcStrict != VINF_SUCCESS)
2092 return rcStrict;
2093
2094 /* Chop the high bits if 16-bit (Intel says so). */
2095 if (enmEffOpSize == IEMMODE_16BIT)
2096 offSeg &= UINT16_MAX;
2097
2098 /* Limit / canonical check. */
2099 uint64_t u64Base;
2100 uint32_t cbLimit = X86DESC_LIMIT_G(&Desc.Legacy);
2101 if ( !Desc.Legacy.Gen.u1Long
2102 || !IEM_IS_LONG_MODE(pVCpu))
2103 {
2104 if (RT_LIKELY(offSeg <= cbLimit))
2105 u64Base = X86DESC_BASE(&Desc.Legacy);
2106 else
2107 {
2108 Log(("callf %04x:%08RX64 -> out of bounds (%#x)\n", uSel, offSeg, cbLimit));
2109 /** @todo Intel says this is \#GP(0)! */
2110 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
2111 }
2112 }
2113 else if (IEM_IS_CANONICAL(offSeg))
2114 u64Base = 0;
2115 else
2116 {
2117 Log(("callf %04x:%016RX64 - not canonical -> #GP\n", uSel, offSeg));
2118 return iemRaiseNotCanonical(pVCpu);
2119 }
2120
2121 /*
2122 * Now set the accessed bit before
2123 * writing the return address to the stack and committing the result into
2124 * CS, CSHID and RIP.
2125 */
2126 /** @todo Testcase: Need to check WHEN exactly the accessed bit is set. */
2127 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
2128 {
2129 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uSel);
2130 if (rcStrict != VINF_SUCCESS)
2131 return rcStrict;
2132 /** @todo check what VT-x and AMD-V does. */
2133 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
2134 }
2135
2136 /* stack */
2137 if (enmEffOpSize == IEMMODE_16BIT)
2138 {
2139 uPtrRet.pu16[0] = pVCpu->cpum.GstCtx.ip + cbInstr;
2140 uPtrRet.pu16[1] = pVCpu->cpum.GstCtx.cs.Sel;
2141 }
2142 else if (enmEffOpSize == IEMMODE_32BIT)
2143 {
2144 uPtrRet.pu32[0] = pVCpu->cpum.GstCtx.eip + cbInstr;
2145 uPtrRet.pu32[1] = pVCpu->cpum.GstCtx.cs.Sel; /** @todo Testcase: What is written to the high word when callf is pushing CS? */
2146 }
2147 else
2148 {
2149 uPtrRet.pu64[0] = pVCpu->cpum.GstCtx.rip + cbInstr;
2150 uPtrRet.pu64[1] = pVCpu->cpum.GstCtx.cs.Sel; /** @todo Testcase: What is written to the high words when callf is pushing CS? */
2151 }
2152 rcStrict = iemMemStackPushCommitSpecial(pVCpu, bUnmapInfo, uNewRsp);
2153 if (rcStrict != VINF_SUCCESS)
2154 return rcStrict;
2155
2156 /* commit */
2157 pVCpu->cpum.GstCtx.rip = offSeg;
2158 pVCpu->cpum.GstCtx.cs.Sel = uSel & X86_SEL_MASK_OFF_RPL;
2159 pVCpu->cpum.GstCtx.cs.Sel |= IEM_GET_CPL(pVCpu);
2160 pVCpu->cpum.GstCtx.cs.ValidSel = pVCpu->cpum.GstCtx.cs.Sel;
2161 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
2162 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
2163 pVCpu->cpum.GstCtx.cs.u32Limit = cbLimit;
2164 pVCpu->cpum.GstCtx.cs.u64Base = u64Base;
2165
2166 /** @todo check if the hidden bits are loaded correctly for 64-bit
2167 * mode. */
2168
2169 iemRecalcExecModeAndCplAndAcFlags(pVCpu);
2170
2171 /* Flush the prefetch buffer. */
2172 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr);
2173
2174 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
2175}
2176
2177
2178/**
2179 * Implements retf.
2180 *
2181 * @param enmEffOpSize The effective operand size.
2182 * @param cbPop The amount of arguments to pop from the stack
2183 * (bytes).
2184 */
2185IEM_CIMPL_DEF_2(iemCImpl_retf, IEMMODE, enmEffOpSize, uint16_t, cbPop)
2186{
2187 NOREF(cbInstr);
2188
2189 /*
2190 * Read the stack values first.
2191 */
2192 RTUINT64U NewRsp;
2193 uint8_t bUnmapInfo;
2194 RTCPTRUNION uPtrFrame;
2195 uint32_t cbRetPtr = enmEffOpSize == IEMMODE_16BIT ? 2+2
2196 : enmEffOpSize == IEMMODE_32BIT ? 4+4 : 8+8;
2197 VBOXSTRICTRC rcStrict = iemMemStackPopBeginSpecial(pVCpu, cbRetPtr,
2198 enmEffOpSize == IEMMODE_16BIT ? 1 : enmEffOpSize == IEMMODE_32BIT ? 3 : 7,
2199 &uPtrFrame.pv, &bUnmapInfo, &NewRsp.u);
2200 if (rcStrict != VINF_SUCCESS)
2201 return rcStrict;
2202
2203 uint64_t uNewRip;
2204 uint16_t uNewCs;
2205 if (enmEffOpSize == IEMMODE_16BIT)
2206 {
2207 uNewRip = uPtrFrame.pu16[0];
2208 uNewCs = uPtrFrame.pu16[1];
2209 }
2210 else if (enmEffOpSize == IEMMODE_32BIT)
2211 {
2212 uNewRip = uPtrFrame.pu32[0];
2213 uNewCs = uPtrFrame.pu16[2];
2214 }
2215 else
2216 {
2217 uNewRip = uPtrFrame.pu64[0];
2218 uNewCs = uPtrFrame.pu16[4];
2219 }
2220
2221 rcStrict = iemMemStackPopDoneSpecial(pVCpu, bUnmapInfo);
2222 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
2223 { /* extremely likely */ }
2224 else
2225 return rcStrict;
2226
2227 /*
2228 * Real mode and V8086 mode are easy.
2229 */
2230 /** @todo See comment for similar code in iemCImpl_FarJmp */
2231 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
2232 {
2233 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
2234 /** @todo check how this is supposed to work if sp=0xfffe. */
2235
2236 /* Check the limit of the new EIP. */
2237 /** @todo Intel pseudo code only does the limit check for 16-bit
2238 * operands, AMD does not make any distinction. What is right? */
2239 if (uNewRip > pVCpu->cpum.GstCtx.cs.u32Limit)
2240 return iemRaiseSelectorBounds(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
2241
2242 /* commit the operation. */
2243 if (cbPop)
2244 iemRegAddToRspEx(pVCpu, &NewRsp, cbPop);
2245 pVCpu->cpum.GstCtx.rsp = NewRsp.u;
2246 pVCpu->cpum.GstCtx.rip = uNewRip;
2247 pVCpu->cpum.GstCtx.cs.Sel = uNewCs;
2248 pVCpu->cpum.GstCtx.cs.ValidSel = uNewCs;
2249 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
2250 pVCpu->cpum.GstCtx.cs.u64Base = (uint32_t)uNewCs << 4;
2251 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
2252 }
2253
2254 /*
2255 * Protected mode is complicated, of course.
2256 */
2257 if (!(uNewCs & X86_SEL_MASK_OFF_RPL))
2258 {
2259 Log(("retf %04x:%08RX64 -> invalid selector, #GP(0)\n", uNewCs, uNewRip));
2260 return iemRaiseGeneralProtectionFault0(pVCpu);
2261 }
2262
2263 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_GDTR | CPUMCTX_EXTRN_LDTR);
2264
2265 /* Fetch the descriptor. */
2266 IEMSELDESC DescCs;
2267 rcStrict = iemMemFetchSelDesc(pVCpu, &DescCs, uNewCs, X86_XCPT_GP);
2268 if (rcStrict != VINF_SUCCESS)
2269 return rcStrict;
2270
2271 /* Can only return to a code selector. */
2272 if ( !DescCs.Legacy.Gen.u1DescType
2273 || !(DescCs.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE) )
2274 {
2275 Log(("retf %04x:%08RX64 -> not a code selector (u1DescType=%u u4Type=%#x).\n",
2276 uNewCs, uNewRip, DescCs.Legacy.Gen.u1DescType, DescCs.Legacy.Gen.u4Type));
2277 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
2278 }
2279
2280 /* L vs D. */
2281 if ( DescCs.Legacy.Gen.u1Long /** @todo Testcase: far return to a selector with both L and D set. */
2282 && DescCs.Legacy.Gen.u1DefBig
2283 && IEM_IS_LONG_MODE(pVCpu))
2284 {
2285 Log(("retf %04x:%08RX64 -> both L & D set.\n", uNewCs, uNewRip));
2286 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
2287 }
2288
2289 /* DPL/RPL/CPL checks. */
2290 if ((uNewCs & X86_SEL_RPL) < IEM_GET_CPL(pVCpu))
2291 {
2292 Log(("retf %04x:%08RX64 -> RPL < CPL(%d).\n", uNewCs, uNewRip, IEM_GET_CPL(pVCpu)));
2293 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
2294 }
2295
2296 if (DescCs.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF)
2297 {
2298 if ((uNewCs & X86_SEL_RPL) < DescCs.Legacy.Gen.u2Dpl)
2299 {
2300 Log(("retf %04x:%08RX64 -> DPL violation (conforming); DPL=%u RPL=%u\n",
2301 uNewCs, uNewRip, DescCs.Legacy.Gen.u2Dpl, (uNewCs & X86_SEL_RPL)));
2302 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
2303 }
2304 }
2305 else
2306 {
2307 if ((uNewCs & X86_SEL_RPL) != DescCs.Legacy.Gen.u2Dpl)
2308 {
2309 Log(("retf %04x:%08RX64 -> RPL != DPL; DPL=%u RPL=%u\n",
2310 uNewCs, uNewRip, DescCs.Legacy.Gen.u2Dpl, (uNewCs & X86_SEL_RPL)));
2311 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
2312 }
2313 }
2314
2315 /* Is it there? */
2316 if (!DescCs.Legacy.Gen.u1Present)
2317 {
2318 Log(("retf %04x:%08RX64 -> segment not present\n", uNewCs, uNewRip));
2319 return iemRaiseSelectorNotPresentBySelector(pVCpu, uNewCs);
2320 }
2321
2322 /*
2323 * Return to outer privilege? (We'll typically have entered via a call gate.)
2324 */
2325 if ((uNewCs & X86_SEL_RPL) != IEM_GET_CPL(pVCpu))
2326 {
2327 /* Read the outer stack pointer stored *after* the parameters. */
2328 rcStrict = iemMemStackPopContinueSpecial(pVCpu, cbPop /*off*/, cbRetPtr, &uPtrFrame.pv, &bUnmapInfo, NewRsp.u);
2329 if (rcStrict != VINF_SUCCESS)
2330 return rcStrict;
2331
2332 uint16_t uNewOuterSs;
2333 RTUINT64U NewOuterRsp;
2334 if (enmEffOpSize == IEMMODE_16BIT)
2335 {
2336 NewOuterRsp.u = uPtrFrame.pu16[0];
2337 uNewOuterSs = uPtrFrame.pu16[1];
2338 }
2339 else if (enmEffOpSize == IEMMODE_32BIT)
2340 {
2341 NewOuterRsp.u = uPtrFrame.pu32[0];
2342 uNewOuterSs = uPtrFrame.pu16[2];
2343 }
2344 else
2345 {
2346 NewOuterRsp.u = uPtrFrame.pu64[0];
2347 uNewOuterSs = uPtrFrame.pu16[4];
2348 }
2349 rcStrict = iemMemStackPopDoneSpecial(pVCpu, bUnmapInfo);
2350 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
2351 { /* extremely likely */ }
2352 else
2353 return rcStrict;
2354
2355 /* Check for NULL stack selector (invalid in ring-3 and non-long mode)
2356 and read the selector. */
2357 IEMSELDESC DescSs;
2358 if (!(uNewOuterSs & X86_SEL_MASK_OFF_RPL))
2359 {
2360 if ( !DescCs.Legacy.Gen.u1Long
2361 || (uNewOuterSs & X86_SEL_RPL) == 3)
2362 {
2363 Log(("retf %04x:%08RX64 %04x:%08RX64 -> invalid stack selector, #GP\n",
2364 uNewCs, uNewRip, uNewOuterSs, NewOuterRsp.u));
2365 return iemRaiseGeneralProtectionFault0(pVCpu);
2366 }
2367 /** @todo Testcase: Return far to ring-1 or ring-2 with SS=0. */
2368 iemMemFakeStackSelDesc(&DescSs, (uNewOuterSs & X86_SEL_RPL));
2369 }
2370 else
2371 {
2372 /* Fetch the descriptor for the new stack segment. */
2373 rcStrict = iemMemFetchSelDesc(pVCpu, &DescSs, uNewOuterSs, X86_XCPT_GP);
2374 if (rcStrict != VINF_SUCCESS)
2375 return rcStrict;
2376 }
2377
2378 /* Check that RPL of stack and code selectors match. */
2379 if ((uNewCs & X86_SEL_RPL) != (uNewOuterSs & X86_SEL_RPL))
2380 {
2381 Log(("retf %04x:%08RX64 %04x:%08RX64 - SS.RPL != CS.RPL -> #GP(SS)\n", uNewCs, uNewRip, uNewOuterSs, NewOuterRsp.u));
2382 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewOuterSs);
2383 }
2384
2385 /* Must be a writable data segment. */
2386 if ( !DescSs.Legacy.Gen.u1DescType
2387 || (DescSs.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
2388 || !(DescSs.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
2389 {
2390 Log(("retf %04x:%08RX64 %04x:%08RX64 - SS not a writable data segment (u1DescType=%u u4Type=%#x) -> #GP(SS).\n",
2391 uNewCs, uNewRip, uNewOuterSs, NewOuterRsp.u, DescSs.Legacy.Gen.u1DescType, DescSs.Legacy.Gen.u4Type));
2392 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewOuterSs);
2393 }
2394
2395 /* L vs D. (Not mentioned by intel.) */
2396 if ( DescSs.Legacy.Gen.u1Long /** @todo Testcase: far return to a stack selector with both L and D set. */
2397 && DescSs.Legacy.Gen.u1DefBig
2398 && IEM_IS_LONG_MODE(pVCpu))
2399 {
2400 Log(("retf %04x:%08RX64 %04x:%08RX64 - SS has both L & D set -> #GP(SS).\n",
2401 uNewCs, uNewRip, uNewOuterSs, NewOuterRsp.u));
2402 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewOuterSs);
2403 }
2404
2405 /* DPL/RPL/CPL checks. */
2406 if (DescSs.Legacy.Gen.u2Dpl != (uNewCs & X86_SEL_RPL))
2407 {
2408 Log(("retf %04x:%08RX64 %04x:%08RX64 - SS.DPL(%u) != CS.RPL (%u) -> #GP(SS).\n",
2409 uNewCs, uNewRip, uNewOuterSs, NewOuterRsp.u, DescSs.Legacy.Gen.u2Dpl, uNewCs & X86_SEL_RPL));
2410 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewOuterSs);
2411 }
2412
2413 /* Is it there? */
2414 if (!DescSs.Legacy.Gen.u1Present)
2415 {
2416 Log(("retf %04x:%08RX64 %04x:%08RX64 - SS not present -> #NP(SS).\n", uNewCs, uNewRip, uNewOuterSs, NewOuterRsp.u));
2417 return iemRaiseSelectorNotPresentBySelector(pVCpu, uNewCs);
2418 }
2419
2420 /* Calc SS limit.*/
2421 uint64_t u64BaseSs;
2422 uint32_t cbLimitSs = X86DESC_LIMIT_G(&DescSs.Legacy);
2423
2424 /* Is RIP canonical or within CS.limit? */
2425 uint64_t u64BaseCs;
2426 uint32_t cbLimitCs = X86DESC_LIMIT_G(&DescCs.Legacy);
2427
2428 /** @todo Testcase: Is this correct? */
2429 if ( DescCs.Legacy.Gen.u1Long
2430 && IEM_IS_LONG_MODE(pVCpu) )
2431 {
2432 if (!IEM_IS_CANONICAL(uNewRip))
2433 {
2434 Log(("retf %04x:%08RX64 %04x:%08RX64 - not canonical -> #GP.\n", uNewCs, uNewRip, uNewOuterSs, NewOuterRsp.u));
2435 return iemRaiseNotCanonical(pVCpu);
2436 }
2437 u64BaseCs = 0;
2438 u64BaseSs = 0;
2439 }
2440 else
2441 {
2442 if (uNewRip > cbLimitCs)
2443 {
2444 Log(("retf %04x:%08RX64 %04x:%08RX64 - out of bounds (%#x)-> #GP(CS).\n",
2445 uNewCs, uNewRip, uNewOuterSs, NewOuterRsp.u, cbLimitCs));
2446 /** @todo Intel says this is \#GP(0)! */
2447 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
2448 }
2449 u64BaseCs = X86DESC_BASE(&DescCs.Legacy);
2450 u64BaseSs = X86DESC_BASE(&DescSs.Legacy);
2451 }
2452
2453 /*
2454 * Now set the accessed bit before
2455 * writing the return address to the stack and committing the result into
2456 * CS, CSHID and RIP.
2457 */
2458 /** @todo Testcase: Need to check WHEN exactly the CS accessed bit is set. */
2459 if (!(DescCs.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
2460 {
2461 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uNewCs);
2462 if (rcStrict != VINF_SUCCESS)
2463 return rcStrict;
2464 /** @todo check what VT-x and AMD-V does. */
2465 DescCs.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
2466 }
2467 /** @todo Testcase: Need to check WHEN exactly the SS accessed bit is set. */
2468 if (!(DescSs.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
2469 {
2470 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uNewOuterSs);
2471 if (rcStrict != VINF_SUCCESS)
2472 return rcStrict;
2473 /** @todo check what VT-x and AMD-V does. */
2474 DescSs.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
2475 }
2476
2477 /* commit */
2478 if (enmEffOpSize == IEMMODE_16BIT)
2479 pVCpu->cpum.GstCtx.rip = uNewRip & UINT16_MAX; /** @todo Testcase: When exactly does this occur? With call it happens prior to the limit check according to Intel... */
2480 else
2481 pVCpu->cpum.GstCtx.rip = uNewRip;
2482 pVCpu->cpum.GstCtx.cs.Sel = uNewCs;
2483 pVCpu->cpum.GstCtx.cs.ValidSel = uNewCs;
2484 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
2485 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCs.Legacy);
2486 pVCpu->cpum.GstCtx.cs.u32Limit = cbLimitCs;
2487 pVCpu->cpum.GstCtx.cs.u64Base = u64BaseCs;
2488 pVCpu->cpum.GstCtx.ss.Sel = uNewOuterSs;
2489 pVCpu->cpum.GstCtx.ss.ValidSel = uNewOuterSs;
2490 pVCpu->cpum.GstCtx.ss.fFlags = CPUMSELREG_FLAGS_VALID;
2491 pVCpu->cpum.GstCtx.ss.Attr.u = X86DESC_GET_HID_ATTR(&DescSs.Legacy);
2492 pVCpu->cpum.GstCtx.ss.u32Limit = cbLimitSs;
2493 pVCpu->cpum.GstCtx.ss.u64Base = u64BaseSs;
2494
2495 iemHlpAdjustSelectorForNewCpl(pVCpu, uNewCs & X86_SEL_RPL, &pVCpu->cpum.GstCtx.ds);
2496 iemHlpAdjustSelectorForNewCpl(pVCpu, uNewCs & X86_SEL_RPL, &pVCpu->cpum.GstCtx.es);
2497 iemHlpAdjustSelectorForNewCpl(pVCpu, uNewCs & X86_SEL_RPL, &pVCpu->cpum.GstCtx.fs);
2498 iemHlpAdjustSelectorForNewCpl(pVCpu, uNewCs & X86_SEL_RPL, &pVCpu->cpum.GstCtx.gs);
2499
2500 iemRecalcExecModeAndCplAndAcFlags(pVCpu); /* Affects iemRegAddToRspEx and the setting of RSP/SP below. */
2501
2502 if (cbPop)
2503 iemRegAddToRspEx(pVCpu, &NewOuterRsp, cbPop);
2504 if (IEM_IS_64BIT_CODE(pVCpu))
2505 pVCpu->cpum.GstCtx.rsp = NewOuterRsp.u;
2506 else if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
2507 pVCpu->cpum.GstCtx.rsp = (uint32_t)NewOuterRsp.u;
2508 else
2509 pVCpu->cpum.GstCtx.sp = (uint16_t)NewOuterRsp.u;
2510
2511 iemRecalcExecModeAndCplAndAcFlags(pVCpu); /* Affects iemRegAddToRspEx and the setting of RSP/SP below. */
2512
2513 /** @todo check if the hidden bits are loaded correctly for 64-bit
2514 * mode. */
2515 }
2516 /*
2517 * Return to the same privilege level
2518 */
2519 else
2520 {
2521 /* Limit / canonical check. */
2522 uint64_t u64Base;
2523 uint32_t cbLimitCs = X86DESC_LIMIT_G(&DescCs.Legacy);
2524
2525 /** @todo Testcase: Is this correct? */
2526 bool f64BitCs = false;
2527 if ( DescCs.Legacy.Gen.u1Long
2528 && IEM_IS_LONG_MODE(pVCpu) )
2529 {
2530 if (!IEM_IS_CANONICAL(uNewRip))
2531 {
2532 Log(("retf %04x:%08RX64 - not canonical -> #GP\n", uNewCs, uNewRip));
2533 return iemRaiseNotCanonical(pVCpu);
2534 }
2535 u64Base = 0;
2536 f64BitCs = true;
2537 f64BitCs = true;
2538 }
2539 else
2540 {
2541 if (uNewRip > cbLimitCs)
2542 {
2543 Log(("retf %04x:%08RX64 -> out of bounds (%#x)\n", uNewCs, uNewRip, cbLimitCs));
2544 /** @todo Intel says this is \#GP(0)! */
2545 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
2546 }
2547 u64Base = X86DESC_BASE(&DescCs.Legacy);
2548 }
2549
2550 /*
2551 * Now set the accessed bit before
2552 * writing the return address to the stack and committing the result into
2553 * CS, CSHID and RIP.
2554 */
2555 /** @todo Testcase: Need to check WHEN exactly the accessed bit is set. */
2556 if (!(DescCs.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
2557 {
2558 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uNewCs);
2559 if (rcStrict != VINF_SUCCESS)
2560 return rcStrict;
2561 /** @todo check what VT-x and AMD-V does. */
2562 DescCs.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
2563 }
2564
2565 /* commit */
2566 if (cbPop)
2567/** @todo This cannot be right. We're using the old CS mode here, and iemRegAddToRspEx checks fExec. */
2568 iemRegAddToRspEx(pVCpu, &NewRsp, cbPop);
2569 if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig || f64BitCs)
2570 pVCpu->cpum.GstCtx.rsp = NewRsp.u;
2571 else
2572 pVCpu->cpum.GstCtx.sp = (uint16_t)NewRsp.u;
2573 if (enmEffOpSize == IEMMODE_16BIT)
2574 pVCpu->cpum.GstCtx.rip = uNewRip & UINT16_MAX; /** @todo Testcase: When exactly does this occur? With call it happens prior to the limit check according to Intel... */
2575 else
2576 pVCpu->cpum.GstCtx.rip = uNewRip;
2577 pVCpu->cpum.GstCtx.cs.Sel = uNewCs;
2578 pVCpu->cpum.GstCtx.cs.ValidSel = uNewCs;
2579 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
2580 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCs.Legacy);
2581 pVCpu->cpum.GstCtx.cs.u32Limit = cbLimitCs;
2582 pVCpu->cpum.GstCtx.cs.u64Base = u64Base;
2583 /** @todo check if the hidden bits are loaded correctly for 64-bit
2584 * mode. */
2585
2586 iemRecalcExecModeAndCplAndAcFlags(pVCpu);
2587 }
2588
2589 /* Flush the prefetch buffer. */
2590 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr); /** @todo use light flush for same privilege? */
2591
2592 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
2593}
2594
2595
2596/**
2597 * Implements enter.
2598 *
2599 * We're doing this in C because the instruction is insane, even for the
2600 * u8NestingLevel=0 case dealing with the stack is tedious.
2601 *
2602 * @param enmEffOpSize The effective operand size.
2603 * @param cbFrame Frame size.
2604 * @param cParameters Frame parameter count.
2605 */
2606IEM_CIMPL_DEF_3(iemCImpl_enter, IEMMODE, enmEffOpSize, uint16_t, cbFrame, uint8_t, cParameters)
2607{
2608 /* Push RBP, saving the old value in TmpRbp. */
2609 RTUINT64U NewRsp; NewRsp.u = pVCpu->cpum.GstCtx.rsp;
2610 RTUINT64U TmpRbp; TmpRbp.u = pVCpu->cpum.GstCtx.rbp;
2611 RTUINT64U NewRbp;
2612 VBOXSTRICTRC rcStrict;
2613 if (enmEffOpSize == IEMMODE_64BIT)
2614 {
2615 rcStrict = iemMemStackPushU64Ex(pVCpu, TmpRbp.u, &NewRsp);
2616 NewRbp = NewRsp;
2617 }
2618 else if (enmEffOpSize == IEMMODE_32BIT)
2619 {
2620 rcStrict = iemMemStackPushU32Ex(pVCpu, TmpRbp.DWords.dw0, &NewRsp);
2621 NewRbp = NewRsp;
2622 }
2623 else
2624 {
2625 rcStrict = iemMemStackPushU16Ex(pVCpu, TmpRbp.Words.w0, &NewRsp);
2626 NewRbp = TmpRbp;
2627 NewRbp.Words.w0 = NewRsp.Words.w0;
2628 }
2629 if (rcStrict != VINF_SUCCESS)
2630 return rcStrict;
2631
2632 /* Copy the parameters (aka nesting levels by Intel). */
2633 cParameters &= 0x1f;
2634 if (cParameters > 0)
2635 {
2636 switch (enmEffOpSize)
2637 {
2638 case IEMMODE_16BIT:
2639 if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
2640 TmpRbp.DWords.dw0 -= 2;
2641 else
2642 TmpRbp.Words.w0 -= 2;
2643 do
2644 {
2645 uint16_t u16Tmp;
2646 rcStrict = iemMemStackPopU16Ex(pVCpu, &u16Tmp, &TmpRbp);
2647 if (rcStrict != VINF_SUCCESS)
2648 break;
2649 rcStrict = iemMemStackPushU16Ex(pVCpu, u16Tmp, &NewRsp);
2650 } while (--cParameters > 0 && rcStrict == VINF_SUCCESS);
2651 break;
2652
2653 case IEMMODE_32BIT:
2654 if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
2655 TmpRbp.DWords.dw0 -= 4;
2656 else
2657 TmpRbp.Words.w0 -= 4;
2658 do
2659 {
2660 uint32_t u32Tmp;
2661 rcStrict = iemMemStackPopU32Ex(pVCpu, &u32Tmp, &TmpRbp);
2662 if (rcStrict != VINF_SUCCESS)
2663 break;
2664 rcStrict = iemMemStackPushU32Ex(pVCpu, u32Tmp, &NewRsp);
2665 } while (--cParameters > 0 && rcStrict == VINF_SUCCESS);
2666 break;
2667
2668 case IEMMODE_64BIT:
2669 TmpRbp.u -= 8;
2670 do
2671 {
2672 uint64_t u64Tmp;
2673 rcStrict = iemMemStackPopU64Ex(pVCpu, &u64Tmp, &TmpRbp);
2674 if (rcStrict != VINF_SUCCESS)
2675 break;
2676 rcStrict = iemMemStackPushU64Ex(pVCpu, u64Tmp, &NewRsp);
2677 } while (--cParameters > 0 && rcStrict == VINF_SUCCESS);
2678 break;
2679
2680 IEM_NOT_REACHED_DEFAULT_CASE_RET();
2681 }
2682 if (rcStrict != VINF_SUCCESS)
2683 return VINF_SUCCESS;
2684
2685 /* Push the new RBP */
2686 if (enmEffOpSize == IEMMODE_64BIT)
2687 rcStrict = iemMemStackPushU64Ex(pVCpu, NewRbp.u, &NewRsp);
2688 else if (enmEffOpSize == IEMMODE_32BIT)
2689 rcStrict = iemMemStackPushU32Ex(pVCpu, NewRbp.DWords.dw0, &NewRsp);
2690 else
2691 rcStrict = iemMemStackPushU16Ex(pVCpu, NewRbp.Words.w0, &NewRsp);
2692 if (rcStrict != VINF_SUCCESS)
2693 return rcStrict;
2694
2695 }
2696
2697 /* Recalc RSP. */
2698 iemRegSubFromRspEx(pVCpu, &NewRsp, cbFrame);
2699
2700 /** @todo Should probe write access at the new RSP according to AMD. */
2701 /** @todo Should handle accesses to the VMX APIC-access page. */
2702
2703 /* Commit it. */
2704 pVCpu->cpum.GstCtx.rbp = NewRbp.u;
2705 pVCpu->cpum.GstCtx.rsp = NewRsp.u;
2706 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
2707}
2708
2709
2710
2711/**
2712 * Implements leave.
2713 *
2714 * We're doing this in C because messing with the stack registers is annoying
2715 * since they depends on SS attributes.
2716 *
2717 * @param enmEffOpSize The effective operand size.
2718 */
2719IEM_CIMPL_DEF_1(iemCImpl_leave, IEMMODE, enmEffOpSize)
2720{
2721 /* Calculate the intermediate RSP from RBP and the stack attributes. */
2722 RTUINT64U NewRsp;
2723 if (IEM_IS_64BIT_CODE(pVCpu))
2724 NewRsp.u = pVCpu->cpum.GstCtx.rbp;
2725 else if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
2726 NewRsp.u = pVCpu->cpum.GstCtx.ebp;
2727 else
2728 {
2729 /** @todo Check that LEAVE actually preserve the high EBP bits. */
2730 NewRsp.u = pVCpu->cpum.GstCtx.rsp;
2731 NewRsp.Words.w0 = pVCpu->cpum.GstCtx.bp;
2732 }
2733
2734 /* Pop RBP according to the operand size. */
2735 VBOXSTRICTRC rcStrict;
2736 RTUINT64U NewRbp;
2737 switch (enmEffOpSize)
2738 {
2739 case IEMMODE_16BIT:
2740 NewRbp.u = pVCpu->cpum.GstCtx.rbp;
2741 rcStrict = iemMemStackPopU16Ex(pVCpu, &NewRbp.Words.w0, &NewRsp);
2742 break;
2743 case IEMMODE_32BIT:
2744 NewRbp.u = 0;
2745 rcStrict = iemMemStackPopU32Ex(pVCpu, &NewRbp.DWords.dw0, &NewRsp);
2746 break;
2747 case IEMMODE_64BIT:
2748 rcStrict = iemMemStackPopU64Ex(pVCpu, &NewRbp.u, &NewRsp);
2749 break;
2750 IEM_NOT_REACHED_DEFAULT_CASE_RET();
2751 }
2752 if (rcStrict != VINF_SUCCESS)
2753 return rcStrict;
2754
2755
2756 /* Commit it. */
2757 pVCpu->cpum.GstCtx.rbp = NewRbp.u;
2758 pVCpu->cpum.GstCtx.rsp = NewRsp.u;
2759 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
2760}
2761
2762
2763/**
2764 * Implements int3 and int XX.
2765 *
2766 * @param u8Int The interrupt vector number.
2767 * @param enmInt The int instruction type.
2768 */
2769IEM_CIMPL_DEF_2(iemCImpl_int, uint8_t, u8Int, IEMINT, enmInt)
2770{
2771 Assert(pVCpu->iem.s.cXcptRecursions == 0);
2772
2773 /*
2774 * We must check if this INT3 might belong to DBGF before raising a #BP.
2775 */
2776 if (u8Int == 3)
2777 {
2778 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2779 if (pVM->dbgf.ro.cEnabledInt3Breakpoints == 0)
2780 { /* likely: No vbox debugger breakpoints */ }
2781 else
2782 {
2783 VBOXSTRICTRC rcStrict = DBGFTrap03Handler(pVM, pVCpu, &pVCpu->cpum.GstCtx);
2784 Log(("iemCImpl_int: DBGFTrap03Handler -> %Rrc\n", VBOXSTRICTRC_VAL(rcStrict) ));
2785 if (rcStrict != VINF_EM_RAW_GUEST_TRAP)
2786 return iemSetPassUpStatus(pVCpu, rcStrict);
2787 }
2788 }
2789/** @todo single stepping */
2790 return iemRaiseXcptOrInt(pVCpu,
2791 cbInstr,
2792 u8Int,
2793 IEM_XCPT_FLAGS_T_SOFT_INT | enmInt,
2794 0,
2795 0);
2796}
2797
2798
2799/**
2800 * Implements iret for real mode and V8086 mode.
2801 *
2802 * @param enmEffOpSize The effective operand size.
2803 */
2804IEM_CIMPL_DEF_1(iemCImpl_iret_real_v8086, IEMMODE, enmEffOpSize)
2805{
2806 X86EFLAGS Efl;
2807 Efl.u = IEMMISC_GET_EFL(pVCpu);
2808 NOREF(cbInstr);
2809
2810 /*
2811 * iret throws an exception if VME isn't enabled.
2812 */
2813 if ( Efl.Bits.u1VM
2814 && Efl.Bits.u2IOPL != 3
2815 && !(pVCpu->cpum.GstCtx.cr4 & X86_CR4_VME))
2816 return iemRaiseGeneralProtectionFault0(pVCpu);
2817
2818 /*
2819 * Do the stack bits, but don't commit RSP before everything checks
2820 * out right.
2821 */
2822 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
2823 VBOXSTRICTRC rcStrict;
2824 uint8_t bUnmapInfo;
2825 RTCPTRUNION uFrame;
2826 uint16_t uNewCs;
2827 uint32_t uNewEip;
2828 uint32_t uNewFlags;
2829 uint64_t uNewRsp;
2830 if (enmEffOpSize == IEMMODE_32BIT)
2831 {
2832 rcStrict = iemMemStackPopBeginSpecial(pVCpu, 12, 1, &uFrame.pv, &bUnmapInfo, &uNewRsp);
2833 if (rcStrict != VINF_SUCCESS)
2834 return rcStrict;
2835 uNewEip = uFrame.pu32[0];
2836 if (uNewEip > UINT16_MAX)
2837 return iemRaiseGeneralProtectionFault0(pVCpu);
2838
2839 uNewCs = (uint16_t)uFrame.pu32[1];
2840 uNewFlags = uFrame.pu32[2];
2841 uNewFlags &= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
2842 | X86_EFL_TF | X86_EFL_IF | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT
2843 | X86_EFL_RF /*| X86_EFL_VM*/ | X86_EFL_AC /*|X86_EFL_VIF*/ /*|X86_EFL_VIP*/
2844 | X86_EFL_ID;
2845 if (IEM_GET_TARGET_CPU(pVCpu) <= IEMTARGETCPU_386)
2846 uNewFlags &= ~(X86_EFL_AC | X86_EFL_ID | X86_EFL_VIF | X86_EFL_VIP);
2847 uNewFlags |= Efl.u & (X86_EFL_VM | X86_EFL_VIF | X86_EFL_VIP | X86_EFL_1);
2848 }
2849 else
2850 {
2851 rcStrict = iemMemStackPopBeginSpecial(pVCpu, 6, 1, &uFrame.pv, &bUnmapInfo, &uNewRsp);
2852 if (rcStrict != VINF_SUCCESS)
2853 return rcStrict;
2854 uNewEip = uFrame.pu16[0];
2855 uNewCs = uFrame.pu16[1];
2856 uNewFlags = uFrame.pu16[2];
2857 uNewFlags &= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
2858 | X86_EFL_TF | X86_EFL_IF | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT;
2859 uNewFlags |= Efl.u & ((UINT32_C(0xffff0000) | X86_EFL_1) & ~X86_EFL_RF);
2860 /** @todo The intel pseudo code does not indicate what happens to
2861 * reserved flags. We just ignore them. */
2862 /* Ancient CPU adjustments: See iemCImpl_popf. */
2863 if (IEM_GET_TARGET_CPU(pVCpu) == IEMTARGETCPU_286)
2864 uNewFlags &= ~(X86_EFL_NT | X86_EFL_IOPL);
2865 }
2866 rcStrict = iemMemStackPopDoneSpecial(pVCpu, bUnmapInfo);
2867 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
2868 { /* extremely likely */ }
2869 else
2870 return rcStrict;
2871
2872 /** @todo Check how this is supposed to work if sp=0xfffe. */
2873 Log7(("iemCImpl_iret_real_v8086: uNewCs=%#06x uNewRip=%#010x uNewFlags=%#x uNewRsp=%#18llx\n",
2874 uNewCs, uNewEip, uNewFlags, uNewRsp));
2875
2876 /*
2877 * Check the limit of the new EIP.
2878 */
2879 /** @todo Only the AMD pseudo code check the limit here, what's
2880 * right? */
2881 if (uNewEip > pVCpu->cpum.GstCtx.cs.u32Limit)
2882 return iemRaiseSelectorBounds(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
2883
2884 /*
2885 * V8086 checks and flag adjustments
2886 */
2887 if (Efl.Bits.u1VM)
2888 {
2889 if (Efl.Bits.u2IOPL == 3)
2890 {
2891 /* Preserve IOPL and clear RF. */
2892 uNewFlags &= ~(X86_EFL_IOPL | X86_EFL_RF);
2893 uNewFlags |= Efl.u & (X86_EFL_IOPL);
2894 }
2895 else if ( enmEffOpSize == IEMMODE_16BIT
2896 && ( !(uNewFlags & X86_EFL_IF)
2897 || !Efl.Bits.u1VIP )
2898 && !(uNewFlags & X86_EFL_TF) )
2899 {
2900 /* Move IF to VIF, clear RF and preserve IF and IOPL.*/
2901 uNewFlags &= ~X86_EFL_VIF;
2902 uNewFlags |= (uNewFlags & X86_EFL_IF) << (19 - 9);
2903 uNewFlags &= ~(X86_EFL_IF | X86_EFL_IOPL | X86_EFL_RF);
2904 uNewFlags |= Efl.u & (X86_EFL_IF | X86_EFL_IOPL);
2905 }
2906 else
2907 return iemRaiseGeneralProtectionFault0(pVCpu);
2908 Log7(("iemCImpl_iret_real_v8086: u1VM=1: adjusted uNewFlags=%#x\n", uNewFlags));
2909 }
2910
2911 /*
2912 * Commit the operation.
2913 */
2914#ifdef DBGFTRACE_ENABLED
2915 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "iret/rm %04x:%04x -> %04x:%04x %x %04llx",
2916 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip, uNewCs, uNewEip, uNewFlags, uNewRsp);
2917#endif
2918 pVCpu->cpum.GstCtx.rsp = uNewRsp;
2919 pVCpu->cpum.GstCtx.rip = uNewEip;
2920 pVCpu->cpum.GstCtx.cs.Sel = uNewCs;
2921 pVCpu->cpum.GstCtx.cs.ValidSel = uNewCs;
2922 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
2923 pVCpu->cpum.GstCtx.cs.u64Base = (uint32_t)uNewCs << 4;
2924 /** @todo do we load attribs and limit as well? */
2925 Assert(uNewFlags & X86_EFL_1);
2926 IEMMISC_SET_EFL(pVCpu, uNewFlags);
2927 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~IEM_F_X86_AC) | iemCalcExecAcFlag(pVCpu);
2928
2929 /* Flush the prefetch buffer. */
2930 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr); /** @todo can do light flush in real mode at least */
2931
2932/** @todo single stepping */
2933 return VINF_SUCCESS;
2934}
2935
2936
2937/**
2938 * Loads a segment register when entering V8086 mode.
2939 *
2940 * @param pSReg The segment register.
2941 * @param uSeg The segment to load.
2942 */
2943static void iemCImplCommonV8086LoadSeg(PCPUMSELREG pSReg, uint16_t uSeg)
2944{
2945 pSReg->Sel = uSeg;
2946 pSReg->ValidSel = uSeg;
2947 pSReg->fFlags = CPUMSELREG_FLAGS_VALID;
2948 pSReg->u64Base = (uint32_t)uSeg << 4;
2949 pSReg->u32Limit = 0xffff;
2950 pSReg->Attr.u = X86_SEL_TYPE_RW_ACC | RT_BIT(4) /*!sys*/ | RT_BIT(7) /*P*/ | (3 /*DPL*/ << 5); /* VT-x wants 0xf3 */
2951 /** @todo Testcase: Check if VT-x really needs this and what it does itself when
2952 * IRET'ing to V8086. */
2953}
2954
2955
2956/**
2957 * Implements iret for protected mode returning to V8086 mode.
2958 *
2959 * @param uNewEip The new EIP.
2960 * @param uNewCs The new CS.
2961 * @param uNewFlags The new EFLAGS.
2962 * @param uNewRsp The RSP after the initial IRET frame.
2963 *
2964 * @note This can only be a 32-bit iret du to the X86_EFL_VM position.
2965 */
2966IEM_CIMPL_DEF_4(iemCImpl_iret_prot_v8086, uint32_t, uNewEip, uint16_t, uNewCs, uint32_t, uNewFlags, uint64_t, uNewRsp)
2967{
2968 RT_NOREF_PV(cbInstr);
2969 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_SREG_MASK);
2970
2971 /*
2972 * Pop the V8086 specific frame bits off the stack.
2973 */
2974 uint8_t bUnmapInfo;
2975 RTCPTRUNION uFrame;
2976 VBOXSTRICTRC rcStrict = iemMemStackPopContinueSpecial(pVCpu, 0 /*off*/, 24 /*cbMem*/, &uFrame.pv, &bUnmapInfo, uNewRsp);
2977 if (rcStrict != VINF_SUCCESS)
2978 return rcStrict;
2979 uint32_t uNewEsp = uFrame.pu32[0];
2980 uint16_t uNewSs = uFrame.pu32[1];
2981 uint16_t uNewEs = uFrame.pu32[2];
2982 uint16_t uNewDs = uFrame.pu32[3];
2983 uint16_t uNewFs = uFrame.pu32[4];
2984 uint16_t uNewGs = uFrame.pu32[5];
2985 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo); /* don't use iemMemStackPopCommitSpecial here. */
2986 if (rcStrict != VINF_SUCCESS)
2987 return rcStrict;
2988
2989 /*
2990 * Commit the operation.
2991 */
2992 uNewFlags &= X86_EFL_LIVE_MASK;
2993 uNewFlags |= X86_EFL_RA1_MASK;
2994#ifdef DBGFTRACE_ENABLED
2995 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "iret/p/v %04x:%08x -> %04x:%04x %x %04x:%04x",
2996 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip, uNewCs, uNewEip, uNewFlags, uNewSs, uNewEsp);
2997#endif
2998 Log7(("iemCImpl_iret_prot_v8086: %04x:%08x -> %04x:%04x %x %04x:%04x\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip, uNewCs, uNewEip, uNewFlags, uNewSs, uNewEsp));
2999
3000 IEMMISC_SET_EFL(pVCpu, uNewFlags);
3001 iemCImplCommonV8086LoadSeg(&pVCpu->cpum.GstCtx.cs, uNewCs);
3002 iemCImplCommonV8086LoadSeg(&pVCpu->cpum.GstCtx.ss, uNewSs);
3003 iemCImplCommonV8086LoadSeg(&pVCpu->cpum.GstCtx.es, uNewEs);
3004 iemCImplCommonV8086LoadSeg(&pVCpu->cpum.GstCtx.ds, uNewDs);
3005 iemCImplCommonV8086LoadSeg(&pVCpu->cpum.GstCtx.fs, uNewFs);
3006 iemCImplCommonV8086LoadSeg(&pVCpu->cpum.GstCtx.gs, uNewGs);
3007 pVCpu->cpum.GstCtx.rip = (uint16_t)uNewEip;
3008 pVCpu->cpum.GstCtx.rsp = uNewEsp; /** @todo check this out! */
3009 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~(IEM_F_MODE_MASK | IEM_F_X86_CPL_MASK | IEM_F_X86_AC))
3010 | (3 << IEM_F_X86_CPL_SHIFT)
3011 | IEM_F_MODE_X86_16BIT_PROT_V86
3012 | iemCalcExecAcFlag(pVCpu);
3013
3014 /* Flush the prefetch buffer. */
3015 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr);
3016
3017/** @todo single stepping */
3018 return VINF_SUCCESS;
3019}
3020
3021
3022/**
3023 * Implements iret for protected mode returning via a nested task.
3024 *
3025 * @param enmEffOpSize The effective operand size.
3026 */
3027IEM_CIMPL_DEF_1(iemCImpl_iret_prot_NestedTask, IEMMODE, enmEffOpSize)
3028{
3029 Log7(("iemCImpl_iret_prot_NestedTask:\n"));
3030#ifndef IEM_IMPLEMENTS_TASKSWITCH
3031 IEM_RETURN_ASPECT_NOT_IMPLEMENTED();
3032#else
3033 RT_NOREF_PV(enmEffOpSize);
3034
3035 /*
3036 * Read the segment selector in the link-field of the current TSS.
3037 */
3038 RTSEL uSelRet;
3039 VBOXSTRICTRC rcStrict = iemMemFetchSysU16(pVCpu, &uSelRet, UINT8_MAX, pVCpu->cpum.GstCtx.tr.u64Base);
3040 if (rcStrict != VINF_SUCCESS)
3041 return rcStrict;
3042
3043 /*
3044 * Fetch the returning task's TSS descriptor from the GDT.
3045 */
3046 if (uSelRet & X86_SEL_LDT)
3047 {
3048 Log(("iret_prot_NestedTask TSS not in LDT. uSelRet=%04x -> #TS\n", uSelRet));
3049 return iemRaiseTaskSwitchFaultBySelector(pVCpu, uSelRet);
3050 }
3051
3052 IEMSELDESC TssDesc;
3053 rcStrict = iemMemFetchSelDesc(pVCpu, &TssDesc, uSelRet, X86_XCPT_GP);
3054 if (rcStrict != VINF_SUCCESS)
3055 return rcStrict;
3056
3057 if (TssDesc.Legacy.Gate.u1DescType)
3058 {
3059 Log(("iret_prot_NestedTask Invalid TSS type. uSelRet=%04x -> #TS\n", uSelRet));
3060 return iemRaiseTaskSwitchFaultBySelector(pVCpu, uSelRet & X86_SEL_MASK_OFF_RPL);
3061 }
3062
3063 if ( TssDesc.Legacy.Gate.u4Type != X86_SEL_TYPE_SYS_286_TSS_BUSY
3064 && TssDesc.Legacy.Gate.u4Type != X86_SEL_TYPE_SYS_386_TSS_BUSY)
3065 {
3066 Log(("iret_prot_NestedTask TSS is not busy. uSelRet=%04x DescType=%#x -> #TS\n", uSelRet, TssDesc.Legacy.Gate.u4Type));
3067 return iemRaiseTaskSwitchFaultBySelector(pVCpu, uSelRet & X86_SEL_MASK_OFF_RPL);
3068 }
3069
3070 if (!TssDesc.Legacy.Gate.u1Present)
3071 {
3072 Log(("iret_prot_NestedTask TSS is not present. uSelRet=%04x -> #NP\n", uSelRet));
3073 return iemRaiseSelectorNotPresentBySelector(pVCpu, uSelRet & X86_SEL_MASK_OFF_RPL);
3074 }
3075
3076 uint32_t uNextEip = pVCpu->cpum.GstCtx.eip + cbInstr;
3077 return iemTaskSwitch(pVCpu, IEMTASKSWITCH_IRET, uNextEip, 0 /* fFlags */, 0 /* uErr */,
3078 0 /* uCr2 */, uSelRet, &TssDesc);
3079#endif
3080}
3081
3082
3083/**
3084 * Implements iret for protected mode
3085 *
3086 * @param enmEffOpSize The effective operand size.
3087 */
3088IEM_CIMPL_DEF_1(iemCImpl_iret_prot, IEMMODE, enmEffOpSize)
3089{
3090 NOREF(cbInstr);
3091 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
3092
3093 /*
3094 * Nested task return.
3095 */
3096 if (pVCpu->cpum.GstCtx.eflags.Bits.u1NT)
3097 return IEM_CIMPL_CALL_1(iemCImpl_iret_prot_NestedTask, enmEffOpSize);
3098
3099 /*
3100 * Normal return.
3101 *
3102 * Do the stack bits, but don't commit RSP before everything checks
3103 * out right.
3104 */
3105 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
3106 uint8_t bUnmapInfo;
3107 VBOXSTRICTRC rcStrict;
3108 RTCPTRUNION uFrame;
3109 uint16_t uNewCs;
3110 uint32_t uNewEip;
3111 uint32_t uNewFlags;
3112 uint64_t uNewRsp;
3113 if (enmEffOpSize == IEMMODE_32BIT)
3114 {
3115 rcStrict = iemMemStackPopBeginSpecial(pVCpu, 12, 3, &uFrame.pv, &bUnmapInfo, &uNewRsp);
3116 if (rcStrict != VINF_SUCCESS)
3117 return rcStrict;
3118 uNewEip = uFrame.pu32[0];
3119 uNewCs = (uint16_t)uFrame.pu32[1];
3120 uNewFlags = uFrame.pu32[2];
3121 }
3122 else
3123 {
3124 rcStrict = iemMemStackPopBeginSpecial(pVCpu, 6, 1, &uFrame.pv, &bUnmapInfo, &uNewRsp);
3125 if (rcStrict != VINF_SUCCESS)
3126 return rcStrict;
3127 uNewEip = uFrame.pu16[0];
3128 uNewCs = uFrame.pu16[1];
3129 uNewFlags = uFrame.pu16[2];
3130 }
3131 rcStrict = iemMemStackPopDoneSpecial(pVCpu, bUnmapInfo); /* don't use iemMemStackPopCommitSpecial here. */
3132 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
3133 { /* extremely likely */ }
3134 else
3135 return rcStrict;
3136 Log7(("iemCImpl_iret_prot: uNewCs=%#06x uNewEip=%#010x uNewFlags=%#x uNewRsp=%#18llx uCpl=%u\n", uNewCs, uNewEip, uNewFlags, uNewRsp, IEM_GET_CPL(pVCpu)));
3137
3138 /*
3139 * We're hopefully not returning to V8086 mode...
3140 */
3141 if ( (uNewFlags & X86_EFL_VM)
3142 && IEM_GET_CPL(pVCpu) == 0)
3143 {
3144 Assert(enmEffOpSize == IEMMODE_32BIT);
3145 return IEM_CIMPL_CALL_4(iemCImpl_iret_prot_v8086, uNewEip, uNewCs, uNewFlags, uNewRsp);
3146 }
3147
3148 /*
3149 * Protected mode.
3150 */
3151 /* Read the CS descriptor. */
3152 if (!(uNewCs & X86_SEL_MASK_OFF_RPL))
3153 {
3154 Log(("iret %04x:%08x -> invalid CS selector, #GP(0)\n", uNewCs, uNewEip));
3155 return iemRaiseGeneralProtectionFault0(pVCpu);
3156 }
3157
3158 IEMSELDESC DescCS;
3159 rcStrict = iemMemFetchSelDesc(pVCpu, &DescCS, uNewCs, X86_XCPT_GP);
3160 if (rcStrict != VINF_SUCCESS)
3161 {
3162 Log(("iret %04x:%08x - rcStrict=%Rrc when fetching CS\n", uNewCs, uNewEip, VBOXSTRICTRC_VAL(rcStrict)));
3163 return rcStrict;
3164 }
3165
3166 /* Must be a code descriptor. */
3167 if (!DescCS.Legacy.Gen.u1DescType)
3168 {
3169 Log(("iret %04x:%08x - CS is system segment (%#x) -> #GP\n", uNewCs, uNewEip, DescCS.Legacy.Gen.u4Type));
3170 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
3171 }
3172 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE))
3173 {
3174 Log(("iret %04x:%08x - not code segment (%#x) -> #GP\n", uNewCs, uNewEip, DescCS.Legacy.Gen.u4Type));
3175 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
3176 }
3177
3178 /* Privilege checks. */
3179 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF))
3180 {
3181 if ((uNewCs & X86_SEL_RPL) != DescCS.Legacy.Gen.u2Dpl)
3182 {
3183 Log(("iret %04x:%08x - RPL != DPL (%d) -> #GP\n", uNewCs, uNewEip, DescCS.Legacy.Gen.u2Dpl));
3184 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
3185 }
3186 }
3187 else if ((uNewCs & X86_SEL_RPL) < DescCS.Legacy.Gen.u2Dpl)
3188 {
3189 Log(("iret %04x:%08x - RPL < DPL (%d) -> #GP\n", uNewCs, uNewEip, DescCS.Legacy.Gen.u2Dpl));
3190 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
3191 }
3192 if ((uNewCs & X86_SEL_RPL) < IEM_GET_CPL(pVCpu))
3193 {
3194 Log(("iret %04x:%08x - RPL < CPL (%d) -> #GP\n", uNewCs, uNewEip, IEM_GET_CPL(pVCpu)));
3195 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
3196 }
3197
3198 /* Present? */
3199 if (!DescCS.Legacy.Gen.u1Present)
3200 {
3201 Log(("iret %04x:%08x - CS not present -> #NP\n", uNewCs, uNewEip));
3202 return iemRaiseSelectorNotPresentBySelector(pVCpu, uNewCs);
3203 }
3204
3205 uint32_t cbLimitCS = X86DESC_LIMIT_G(&DescCS.Legacy);
3206
3207 /*
3208 * Return to outer level?
3209 */
3210 if ((uNewCs & X86_SEL_RPL) != IEM_GET_CPL(pVCpu))
3211 {
3212 uint16_t uNewSS;
3213 uint32_t uNewESP;
3214 if (enmEffOpSize == IEMMODE_32BIT)
3215 {
3216 rcStrict = iemMemStackPopContinueSpecial(pVCpu, 0/*off*/, 8 /*cbMem*/, &uFrame.pv, &bUnmapInfo, uNewRsp);
3217 if (rcStrict != VINF_SUCCESS)
3218 return rcStrict;
3219/** @todo We might be popping a 32-bit ESP from the IRET frame, but whether
3220 * 16-bit or 32-bit are being loaded into SP depends on the D/B
3221 * bit of the popped SS selector it turns out. */
3222 uNewESP = uFrame.pu32[0];
3223 uNewSS = (uint16_t)uFrame.pu32[1];
3224 }
3225 else
3226 {
3227 rcStrict = iemMemStackPopContinueSpecial(pVCpu, 0 /*off*/, 4 /*cbMem*/, &uFrame.pv, &bUnmapInfo, uNewRsp);
3228 if (rcStrict != VINF_SUCCESS)
3229 return rcStrict;
3230 uNewESP = uFrame.pu16[0];
3231 uNewSS = uFrame.pu16[1];
3232 }
3233 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
3234 if (rcStrict != VINF_SUCCESS)
3235 return rcStrict;
3236 Log7(("iemCImpl_iret_prot: uNewSS=%#06x uNewESP=%#010x\n", uNewSS, uNewESP));
3237
3238 /* Read the SS descriptor. */
3239 if (!(uNewSS & X86_SEL_MASK_OFF_RPL))
3240 {
3241 Log(("iret %04x:%08x/%04x:%08x -> invalid SS selector, #GP(0)\n", uNewCs, uNewEip, uNewSS, uNewESP));
3242 return iemRaiseGeneralProtectionFault0(pVCpu);
3243 }
3244
3245 IEMSELDESC DescSS;
3246 rcStrict = iemMemFetchSelDesc(pVCpu, &DescSS, uNewSS, X86_XCPT_GP); /** @todo Correct exception? */
3247 if (rcStrict != VINF_SUCCESS)
3248 {
3249 Log(("iret %04x:%08x/%04x:%08x - %Rrc when fetching SS\n",
3250 uNewCs, uNewEip, uNewSS, uNewESP, VBOXSTRICTRC_VAL(rcStrict)));
3251 return rcStrict;
3252 }
3253
3254 /* Privilege checks. */
3255 if ((uNewSS & X86_SEL_RPL) != (uNewCs & X86_SEL_RPL))
3256 {
3257 Log(("iret %04x:%08x/%04x:%08x -> SS.RPL != CS.RPL -> #GP\n", uNewCs, uNewEip, uNewSS, uNewESP));
3258 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewSS);
3259 }
3260 if (DescSS.Legacy.Gen.u2Dpl != (uNewCs & X86_SEL_RPL))
3261 {
3262 Log(("iret %04x:%08x/%04x:%08x -> SS.DPL (%d) != CS.RPL -> #GP\n",
3263 uNewCs, uNewEip, uNewSS, uNewESP, DescSS.Legacy.Gen.u2Dpl));
3264 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewSS);
3265 }
3266
3267 /* Must be a writeable data segment descriptor. */
3268 if (!DescSS.Legacy.Gen.u1DescType)
3269 {
3270 Log(("iret %04x:%08x/%04x:%08x -> SS is system segment (%#x) -> #GP\n",
3271 uNewCs, uNewEip, uNewSS, uNewESP, DescSS.Legacy.Gen.u4Type));
3272 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewSS);
3273 }
3274 if ((DescSS.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE)) != X86_SEL_TYPE_WRITE)
3275 {
3276 Log(("iret %04x:%08x/%04x:%08x - not writable data segment (%#x) -> #GP\n",
3277 uNewCs, uNewEip, uNewSS, uNewESP, DescSS.Legacy.Gen.u4Type));
3278 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewSS);
3279 }
3280
3281 /* Present? */
3282 if (!DescSS.Legacy.Gen.u1Present)
3283 {
3284 Log(("iret %04x:%08x/%04x:%08x -> SS not present -> #SS\n", uNewCs, uNewEip, uNewSS, uNewESP));
3285 return iemRaiseStackSelectorNotPresentBySelector(pVCpu, uNewSS);
3286 }
3287
3288 uint32_t cbLimitSs = X86DESC_LIMIT_G(&DescSS.Legacy);
3289
3290 /* Check EIP. */
3291 if (uNewEip > cbLimitCS)
3292 {
3293 Log(("iret %04x:%08x/%04x:%08x -> EIP is out of bounds (%#x) -> #GP(0)\n",
3294 uNewCs, uNewEip, uNewSS, uNewESP, cbLimitCS));
3295 /** @todo Which is it, \#GP(0) or \#GP(sel)? */
3296 return iemRaiseSelectorBoundsBySelector(pVCpu, uNewCs);
3297 }
3298
3299 /*
3300 * Commit the changes, marking CS and SS accessed first since
3301 * that may fail.
3302 */
3303 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
3304 {
3305 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uNewCs);
3306 if (rcStrict != VINF_SUCCESS)
3307 return rcStrict;
3308 DescCS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
3309 }
3310 if (!(DescSS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
3311 {
3312 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uNewSS);
3313 if (rcStrict != VINF_SUCCESS)
3314 return rcStrict;
3315 DescSS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
3316 }
3317
3318 uint32_t fEFlagsMask = X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
3319 | X86_EFL_TF | X86_EFL_DF | X86_EFL_OF | X86_EFL_NT;
3320 if (enmEffOpSize != IEMMODE_16BIT)
3321 fEFlagsMask |= X86_EFL_RF | X86_EFL_AC | X86_EFL_ID;
3322 if (IEM_GET_CPL(pVCpu) == 0)
3323 fEFlagsMask |= X86_EFL_IF | X86_EFL_IOPL | X86_EFL_VIF | X86_EFL_VIP; /* VM is 0 */
3324 else if (IEM_GET_CPL(pVCpu) <= pVCpu->cpum.GstCtx.eflags.Bits.u2IOPL)
3325 fEFlagsMask |= X86_EFL_IF;
3326 if (IEM_GET_TARGET_CPU(pVCpu) <= IEMTARGETCPU_386)
3327 fEFlagsMask &= ~(X86_EFL_AC | X86_EFL_ID | X86_EFL_VIF | X86_EFL_VIP);
3328 uint32_t fEFlagsNew = IEMMISC_GET_EFL(pVCpu);
3329 fEFlagsNew &= ~fEFlagsMask;
3330 fEFlagsNew |= uNewFlags & fEFlagsMask;
3331#ifdef DBGFTRACE_ENABLED
3332 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "iret/%up%u %04x:%08x -> %04x:%04x %x %04x:%04x",
3333 IEM_GET_CPL(pVCpu), uNewCs & X86_SEL_RPL, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip,
3334 uNewCs, uNewEip, uNewFlags, uNewSS, uNewESP);
3335#endif
3336
3337 IEMMISC_SET_EFL(pVCpu, fEFlagsNew);
3338 pVCpu->cpum.GstCtx.rip = uNewEip;
3339 pVCpu->cpum.GstCtx.cs.Sel = uNewCs;
3340 pVCpu->cpum.GstCtx.cs.ValidSel = uNewCs;
3341 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
3342 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCS.Legacy);
3343 pVCpu->cpum.GstCtx.cs.u32Limit = cbLimitCS;
3344 pVCpu->cpum.GstCtx.cs.u64Base = X86DESC_BASE(&DescCS.Legacy);
3345
3346 pVCpu->cpum.GstCtx.ss.Sel = uNewSS;
3347 pVCpu->cpum.GstCtx.ss.ValidSel = uNewSS;
3348 pVCpu->cpum.GstCtx.ss.fFlags = CPUMSELREG_FLAGS_VALID;
3349 pVCpu->cpum.GstCtx.ss.Attr.u = X86DESC_GET_HID_ATTR(&DescSS.Legacy);
3350 pVCpu->cpum.GstCtx.ss.u32Limit = cbLimitSs;
3351 pVCpu->cpum.GstCtx.ss.u64Base = X86DESC_BASE(&DescSS.Legacy);
3352 if (!pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
3353 pVCpu->cpum.GstCtx.sp = (uint16_t)uNewESP;
3354 else
3355 pVCpu->cpum.GstCtx.rsp = uNewESP;
3356
3357 iemHlpAdjustSelectorForNewCpl(pVCpu, uNewCs & X86_SEL_RPL, &pVCpu->cpum.GstCtx.ds);
3358 iemHlpAdjustSelectorForNewCpl(pVCpu, uNewCs & X86_SEL_RPL, &pVCpu->cpum.GstCtx.es);
3359 iemHlpAdjustSelectorForNewCpl(pVCpu, uNewCs & X86_SEL_RPL, &pVCpu->cpum.GstCtx.fs);
3360 iemHlpAdjustSelectorForNewCpl(pVCpu, uNewCs & X86_SEL_RPL, &pVCpu->cpum.GstCtx.gs);
3361
3362 iemRecalcExecModeAndCplAndAcFlags(pVCpu);
3363
3364 /* Done! */
3365
3366 }
3367 /*
3368 * Return to the same level.
3369 */
3370 else
3371 {
3372 /* Check EIP. */
3373 if (uNewEip > cbLimitCS)
3374 {
3375 Log(("iret %04x:%08x - EIP is out of bounds (%#x) -> #GP(0)\n", uNewCs, uNewEip, cbLimitCS));
3376 /** @todo Which is it, \#GP(0) or \#GP(sel)? */
3377 return iemRaiseSelectorBoundsBySelector(pVCpu, uNewCs);
3378 }
3379
3380 /*
3381 * Commit the changes, marking CS first since it may fail.
3382 */
3383 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
3384 {
3385 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uNewCs);
3386 if (rcStrict != VINF_SUCCESS)
3387 return rcStrict;
3388 DescCS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
3389 }
3390
3391 X86EFLAGS NewEfl;
3392 NewEfl.u = IEMMISC_GET_EFL(pVCpu);
3393 uint32_t fEFlagsMask = X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
3394 | X86_EFL_TF | X86_EFL_DF | X86_EFL_OF | X86_EFL_NT;
3395 if (enmEffOpSize != IEMMODE_16BIT)
3396 fEFlagsMask |= X86_EFL_RF | X86_EFL_AC | X86_EFL_ID;
3397 if (IEM_GET_CPL(pVCpu) == 0)
3398 fEFlagsMask |= X86_EFL_IF | X86_EFL_IOPL | X86_EFL_VIF | X86_EFL_VIP; /* VM is 0 */
3399 else if (IEM_GET_CPL(pVCpu) <= NewEfl.Bits.u2IOPL)
3400 fEFlagsMask |= X86_EFL_IF;
3401 if (IEM_GET_TARGET_CPU(pVCpu) <= IEMTARGETCPU_386)
3402 fEFlagsMask &= ~(X86_EFL_AC | X86_EFL_ID | X86_EFL_VIF | X86_EFL_VIP);
3403 NewEfl.u &= ~fEFlagsMask;
3404 NewEfl.u |= fEFlagsMask & uNewFlags;
3405#ifdef DBGFTRACE_ENABLED
3406 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "iret/%up %04x:%08x -> %04x:%04x %x %04x:%04llx",
3407 IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip,
3408 uNewCs, uNewEip, uNewFlags, pVCpu->cpum.GstCtx.ss.Sel, uNewRsp);
3409#endif
3410
3411 IEMMISC_SET_EFL(pVCpu, NewEfl.u);
3412 pVCpu->cpum.GstCtx.rip = uNewEip;
3413 pVCpu->cpum.GstCtx.cs.Sel = uNewCs;
3414 pVCpu->cpum.GstCtx.cs.ValidSel = uNewCs;
3415 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
3416 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCS.Legacy);
3417 pVCpu->cpum.GstCtx.cs.u32Limit = cbLimitCS;
3418 pVCpu->cpum.GstCtx.cs.u64Base = X86DESC_BASE(&DescCS.Legacy);
3419 if (!pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
3420 pVCpu->cpum.GstCtx.sp = (uint16_t)uNewRsp;
3421 else
3422 pVCpu->cpum.GstCtx.rsp = uNewRsp;
3423
3424 iemRecalcExecModeAndCplAndAcFlags(pVCpu);
3425
3426 /* Done! */
3427 }
3428
3429 /* Flush the prefetch buffer. */
3430 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr); /** @todo may light flush if same ring? */
3431
3432/** @todo single stepping */
3433 return VINF_SUCCESS;
3434}
3435
3436
3437/**
3438 * Implements iret for long mode
3439 *
3440 * @param enmEffOpSize The effective operand size.
3441 */
3442IEM_CIMPL_DEF_1(iemCImpl_iret_64bit, IEMMODE, enmEffOpSize)
3443{
3444 NOREF(cbInstr);
3445
3446 /*
3447 * Nested task return is not supported in long mode.
3448 */
3449 if (pVCpu->cpum.GstCtx.eflags.Bits.u1NT)
3450 {
3451 Log(("iret/64 with NT=1 (eflags=%#x) -> #GP(0)\n", pVCpu->cpum.GstCtx.eflags.u));
3452 return iemRaiseGeneralProtectionFault0(pVCpu);
3453 }
3454
3455 /*
3456 * Normal return.
3457 *
3458 * Do the stack bits, but don't commit RSP before everything checks
3459 * out right.
3460 */
3461 VBOXSTRICTRC rcStrict;
3462 uint8_t bUnmapInfo;
3463 RTCPTRUNION uFrame;
3464 uint64_t uNewRip;
3465 uint16_t uNewCs;
3466 uint16_t uNewSs;
3467 uint32_t uNewFlags;
3468 uint64_t uNewRsp;
3469 if (enmEffOpSize == IEMMODE_64BIT)
3470 {
3471 rcStrict = iemMemStackPopBeginSpecial(pVCpu, 5*8, 7, &uFrame.pv, &bUnmapInfo, &uNewRsp);
3472 if (rcStrict != VINF_SUCCESS)
3473 return rcStrict;
3474 uNewRip = uFrame.pu64[0];
3475 uNewCs = (uint16_t)uFrame.pu64[1];
3476 uNewFlags = (uint32_t)uFrame.pu64[2];
3477 uNewRsp = uFrame.pu64[3];
3478 uNewSs = (uint16_t)uFrame.pu64[4];
3479 }
3480 else if (enmEffOpSize == IEMMODE_32BIT)
3481 {
3482 rcStrict = iemMemStackPopBeginSpecial(pVCpu, 5*4, 3, &uFrame.pv, &bUnmapInfo, &uNewRsp);
3483 if (rcStrict != VINF_SUCCESS)
3484 return rcStrict;
3485 uNewRip = uFrame.pu32[0];
3486 uNewCs = (uint16_t)uFrame.pu32[1];
3487 uNewFlags = uFrame.pu32[2];
3488 uNewRsp = uFrame.pu32[3];
3489 uNewSs = (uint16_t)uFrame.pu32[4];
3490 }
3491 else
3492 {
3493 Assert(enmEffOpSize == IEMMODE_16BIT);
3494 rcStrict = iemMemStackPopBeginSpecial(pVCpu, 5*2, 1, &uFrame.pv, &bUnmapInfo, &uNewRsp);
3495 if (rcStrict != VINF_SUCCESS)
3496 return rcStrict;
3497 uNewRip = uFrame.pu16[0];
3498 uNewCs = uFrame.pu16[1];
3499 uNewFlags = uFrame.pu16[2];
3500 uNewRsp = uFrame.pu16[3];
3501 uNewSs = uFrame.pu16[4];
3502 }
3503 rcStrict = iemMemStackPopDoneSpecial(pVCpu, bUnmapInfo); /* don't use iemMemStackPopCommitSpecial here. */
3504 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
3505 { /* extremely like */ }
3506 else
3507 return rcStrict;
3508 Log7(("iret/64 stack: cs:rip=%04x:%016RX64 rflags=%016RX64 ss:rsp=%04x:%016RX64\n", uNewCs, uNewRip, uNewFlags, uNewSs, uNewRsp));
3509
3510 /*
3511 * Check stuff.
3512 */
3513 /* Read the CS descriptor. */
3514 if (!(uNewCs & X86_SEL_MASK_OFF_RPL))
3515 {
3516 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 -> invalid CS selector, #GP(0)\n", uNewCs, uNewRip, uNewSs, uNewRsp));
3517 return iemRaiseGeneralProtectionFault0(pVCpu);
3518 }
3519
3520 IEMSELDESC DescCS;
3521 rcStrict = iemMemFetchSelDesc(pVCpu, &DescCS, uNewCs, X86_XCPT_GP);
3522 if (rcStrict != VINF_SUCCESS)
3523 {
3524 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 - rcStrict=%Rrc when fetching CS\n",
3525 uNewCs, uNewRip, uNewSs, uNewRsp, VBOXSTRICTRC_VAL(rcStrict)));
3526 return rcStrict;
3527 }
3528
3529 /* Must be a code descriptor. */
3530 if ( !DescCS.Legacy.Gen.u1DescType
3531 || !(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE))
3532 {
3533 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 - CS is not a code segment T=%u T=%#xu -> #GP\n",
3534 uNewCs, uNewRip, uNewSs, uNewRsp, DescCS.Legacy.Gen.u1DescType, DescCS.Legacy.Gen.u4Type));
3535 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
3536 }
3537
3538 /* Privilege checks. */
3539 uint8_t const uNewCpl = uNewCs & X86_SEL_RPL;
3540 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF))
3541 {
3542 if ((uNewCs & X86_SEL_RPL) != DescCS.Legacy.Gen.u2Dpl)
3543 {
3544 Log(("iret/64 %04x:%016RX64 - RPL != DPL (%d) -> #GP\n", uNewCs, uNewRip, DescCS.Legacy.Gen.u2Dpl));
3545 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
3546 }
3547 }
3548 else if ((uNewCs & X86_SEL_RPL) < DescCS.Legacy.Gen.u2Dpl)
3549 {
3550 Log(("iret/64 %04x:%016RX64 - RPL < DPL (%d) -> #GP\n", uNewCs, uNewRip, DescCS.Legacy.Gen.u2Dpl));
3551 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
3552 }
3553 if ((uNewCs & X86_SEL_RPL) < IEM_GET_CPL(pVCpu))
3554 {
3555 Log(("iret/64 %04x:%016RX64 - RPL < CPL (%d) -> #GP\n", uNewCs, uNewRip, IEM_GET_CPL(pVCpu)));
3556 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewCs);
3557 }
3558
3559 /* Present? */
3560 if (!DescCS.Legacy.Gen.u1Present)
3561 {
3562 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 - CS not present -> #NP\n", uNewCs, uNewRip, uNewSs, uNewRsp));
3563 return iemRaiseSelectorNotPresentBySelector(pVCpu, uNewCs);
3564 }
3565
3566 uint32_t cbLimitCS = X86DESC_LIMIT_G(&DescCS.Legacy);
3567
3568 /* Read the SS descriptor. */
3569 IEMSELDESC DescSS;
3570 if (!(uNewSs & X86_SEL_MASK_OFF_RPL))
3571 {
3572 if ( !DescCS.Legacy.Gen.u1Long
3573 || DescCS.Legacy.Gen.u1DefBig /** @todo exactly how does iret (and others) behave with u1Long=1 and u1DefBig=1? \#GP(sel)? */
3574 || uNewCpl > 2) /** @todo verify SS=0 impossible for ring-3. */
3575 {
3576 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 -> invalid SS selector, #GP(0)\n", uNewCs, uNewRip, uNewSs, uNewRsp));
3577 return iemRaiseGeneralProtectionFault0(pVCpu);
3578 }
3579 /* Make sure SS is sensible, marked as accessed etc. */
3580 iemMemFakeStackSelDesc(&DescSS, (uNewSs & X86_SEL_RPL));
3581 }
3582 else
3583 {
3584 rcStrict = iemMemFetchSelDesc(pVCpu, &DescSS, uNewSs, X86_XCPT_GP); /** @todo Correct exception? */
3585 if (rcStrict != VINF_SUCCESS)
3586 {
3587 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 - %Rrc when fetching SS\n",
3588 uNewCs, uNewRip, uNewSs, uNewRsp, VBOXSTRICTRC_VAL(rcStrict)));
3589 return rcStrict;
3590 }
3591 }
3592
3593 /* Privilege checks. */
3594 if ((uNewSs & X86_SEL_RPL) != (uNewCs & X86_SEL_RPL))
3595 {
3596 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 -> SS.RPL != CS.RPL -> #GP\n", uNewCs, uNewRip, uNewSs, uNewRsp));
3597 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewSs);
3598 }
3599
3600 uint32_t cbLimitSs;
3601 if (!(uNewSs & X86_SEL_MASK_OFF_RPL))
3602 cbLimitSs = UINT32_MAX;
3603 else
3604 {
3605 if (DescSS.Legacy.Gen.u2Dpl != (uNewCs & X86_SEL_RPL))
3606 {
3607 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 -> SS.DPL (%d) != CS.RPL -> #GP\n",
3608 uNewCs, uNewRip, uNewSs, uNewRsp, DescSS.Legacy.Gen.u2Dpl));
3609 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewSs);
3610 }
3611
3612 /* Must be a writeable data segment descriptor. */
3613 if (!DescSS.Legacy.Gen.u1DescType)
3614 {
3615 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 -> SS is system segment (%#x) -> #GP\n",
3616 uNewCs, uNewRip, uNewSs, uNewRsp, DescSS.Legacy.Gen.u4Type));
3617 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewSs);
3618 }
3619 if ((DescSS.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE)) != X86_SEL_TYPE_WRITE)
3620 {
3621 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 - not writable data segment (%#x) -> #GP\n",
3622 uNewCs, uNewRip, uNewSs, uNewRsp, DescSS.Legacy.Gen.u4Type));
3623 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewSs);
3624 }
3625
3626 /* Present? */
3627 if (!DescSS.Legacy.Gen.u1Present)
3628 {
3629 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 -> SS not present -> #SS\n", uNewCs, uNewRip, uNewSs, uNewRsp));
3630 return iemRaiseStackSelectorNotPresentBySelector(pVCpu, uNewSs);
3631 }
3632 cbLimitSs = X86DESC_LIMIT_G(&DescSS.Legacy);
3633 }
3634
3635 /* Check EIP. */
3636 if (DescCS.Legacy.Gen.u1Long)
3637 {
3638 if (!IEM_IS_CANONICAL(uNewRip))
3639 {
3640 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 -> RIP is not canonical -> #GP(0)\n", uNewCs, uNewRip, uNewSs, uNewRsp));
3641 return iemRaiseNotCanonical(pVCpu);
3642 }
3643/** @todo check the location of this... Testcase. */
3644 if (RT_LIKELY(!DescCS.Legacy.Gen.u1DefBig))
3645 { /* likely */ }
3646 else
3647 {
3648 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 -> both L and D are set -> #GP(0)\n", uNewCs, uNewRip, uNewSs, uNewRsp));
3649 return iemRaiseGeneralProtectionFault0(pVCpu);
3650 }
3651 }
3652 else
3653 {
3654 if (uNewRip > cbLimitCS)
3655 {
3656 Log(("iret/64 %04x:%016RX64/%04x:%016RX64 -> EIP is out of bounds (%#x) -> #GP(0)\n",
3657 uNewCs, uNewRip, uNewSs, uNewRsp, cbLimitCS));
3658 /** @todo Which is it, \#GP(0) or \#GP(sel)? */
3659 return iemRaiseSelectorBoundsBySelector(pVCpu, uNewCs);
3660 }
3661 }
3662
3663 /*
3664 * Commit the changes, marking CS and SS accessed first since
3665 * that may fail.
3666 */
3667 /** @todo where exactly are these actually marked accessed by a real CPU? */
3668 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
3669 {
3670 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uNewCs);
3671 if (rcStrict != VINF_SUCCESS)
3672 return rcStrict;
3673 DescCS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
3674 }
3675 if (!(DescSS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
3676 {
3677 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uNewSs);
3678 if (rcStrict != VINF_SUCCESS)
3679 return rcStrict;
3680 DescSS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
3681 }
3682
3683 uint32_t fEFlagsMask = X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
3684 | X86_EFL_TF | X86_EFL_DF | X86_EFL_OF | X86_EFL_NT;
3685 if (enmEffOpSize != IEMMODE_16BIT)
3686 fEFlagsMask |= X86_EFL_RF | X86_EFL_AC | X86_EFL_ID;
3687 if (IEM_GET_CPL(pVCpu) == 0)
3688 fEFlagsMask |= X86_EFL_IF | X86_EFL_IOPL | X86_EFL_VIF | X86_EFL_VIP; /* VM is ignored */
3689 else if (IEM_GET_CPL(pVCpu) <= pVCpu->cpum.GstCtx.eflags.Bits.u2IOPL)
3690 fEFlagsMask |= X86_EFL_IF;
3691 uint32_t fEFlagsNew = IEMMISC_GET_EFL(pVCpu);
3692 fEFlagsNew &= ~fEFlagsMask;
3693 fEFlagsNew |= uNewFlags & fEFlagsMask;
3694#ifdef DBGFTRACE_ENABLED
3695 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "iret/64/%ul%u %08llx -> %04x:%04llx %llx %04x:%04llx",
3696 IEM_GET_CPL(pVCpu), uNewCpl, pVCpu->cpum.GstCtx.rip, uNewCs, uNewRip, uNewFlags, uNewSs, uNewRsp);
3697#endif
3698
3699 IEMMISC_SET_EFL(pVCpu, fEFlagsNew);
3700 pVCpu->cpum.GstCtx.rip = uNewRip;
3701 pVCpu->cpum.GstCtx.cs.Sel = uNewCs;
3702 pVCpu->cpum.GstCtx.cs.ValidSel = uNewCs;
3703 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
3704 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCS.Legacy);
3705 pVCpu->cpum.GstCtx.cs.u32Limit = cbLimitCS;
3706 pVCpu->cpum.GstCtx.cs.u64Base = X86DESC_BASE(&DescCS.Legacy);
3707 if (pVCpu->cpum.GstCtx.cs.Attr.n.u1Long || pVCpu->cpum.GstCtx.cs.Attr.n.u1DefBig)
3708 pVCpu->cpum.GstCtx.rsp = uNewRsp;
3709 else
3710 pVCpu->cpum.GstCtx.sp = (uint16_t)uNewRsp;
3711 pVCpu->cpum.GstCtx.ss.Sel = uNewSs;
3712 pVCpu->cpum.GstCtx.ss.ValidSel = uNewSs;
3713 if (!(uNewSs & X86_SEL_MASK_OFF_RPL))
3714 {
3715 pVCpu->cpum.GstCtx.ss.fFlags = CPUMSELREG_FLAGS_VALID;
3716 pVCpu->cpum.GstCtx.ss.Attr.u = X86DESCATTR_UNUSABLE | (uNewCpl << X86DESCATTR_DPL_SHIFT);
3717 pVCpu->cpum.GstCtx.ss.u32Limit = UINT32_MAX;
3718 pVCpu->cpum.GstCtx.ss.u64Base = 0;
3719 Log2(("iret/64 new SS: NULL\n"));
3720 }
3721 else
3722 {
3723 pVCpu->cpum.GstCtx.ss.fFlags = CPUMSELREG_FLAGS_VALID;
3724 pVCpu->cpum.GstCtx.ss.Attr.u = X86DESC_GET_HID_ATTR(&DescSS.Legacy);
3725 pVCpu->cpum.GstCtx.ss.u32Limit = cbLimitSs;
3726 pVCpu->cpum.GstCtx.ss.u64Base = X86DESC_BASE(&DescSS.Legacy);
3727 Log2(("iret/64 new SS: base=%#RX64 lim=%#x attr=%#x\n", pVCpu->cpum.GstCtx.ss.u64Base, pVCpu->cpum.GstCtx.ss.u32Limit, pVCpu->cpum.GstCtx.ss.Attr.u));
3728 }
3729
3730 if (IEM_GET_CPL(pVCpu) != uNewCpl)
3731 {
3732 iemHlpAdjustSelectorForNewCpl(pVCpu, uNewCpl, &pVCpu->cpum.GstCtx.ds);
3733 iemHlpAdjustSelectorForNewCpl(pVCpu, uNewCpl, &pVCpu->cpum.GstCtx.es);
3734 iemHlpAdjustSelectorForNewCpl(pVCpu, uNewCpl, &pVCpu->cpum.GstCtx.fs);
3735 iemHlpAdjustSelectorForNewCpl(pVCpu, uNewCpl, &pVCpu->cpum.GstCtx.gs);
3736 }
3737
3738 iemRecalcExecModeAndCplAndAcFlags(pVCpu);
3739
3740 /* Flush the prefetch buffer. */
3741 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr); /** @todo may light flush if the ring + mode doesn't change */
3742
3743/** @todo single stepping */
3744 return VINF_SUCCESS;
3745}
3746
3747
3748/**
3749 * Implements iret.
3750 *
3751 * @param enmEffOpSize The effective operand size.
3752 */
3753IEM_CIMPL_DEF_1(iemCImpl_iret, IEMMODE, enmEffOpSize)
3754{
3755 bool fBlockingNmi = CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx);
3756
3757 if (!IEM_IS_IN_GUEST(pVCpu))
3758 { /* probable */ }
3759#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3760 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
3761 {
3762 /*
3763 * Record whether NMI (or virtual-NMI) blocking is in effect during the execution
3764 * of this IRET instruction. We need to provide this information as part of some
3765 * VM-exits.
3766 *
3767 * See Intel spec. 27.2.2 "Information for VM Exits Due to Vectored Events".
3768 */
3769 if (IEM_VMX_IS_PINCTLS_SET(pVCpu, VMX_PIN_CTLS_VIRT_NMI))
3770 pVCpu->cpum.GstCtx.hwvirt.vmx.fNmiUnblockingIret = pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtNmiBlocking;
3771 else
3772 pVCpu->cpum.GstCtx.hwvirt.vmx.fNmiUnblockingIret = fBlockingNmi;
3773
3774 /*
3775 * If "NMI exiting" is set, IRET does not affect blocking of NMIs.
3776 * See Intel Spec. 25.3 "Changes To Instruction Behavior In VMX Non-root Operation".
3777 */
3778 if (IEM_VMX_IS_PINCTLS_SET(pVCpu, VMX_PIN_CTLS_NMI_EXIT))
3779 fBlockingNmi = false;
3780
3781 /* Clear virtual-NMI blocking, if any, before causing any further exceptions. */
3782 pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtNmiBlocking = false;
3783 }
3784#endif
3785 /*
3786 * The SVM nested-guest intercept for IRET takes priority over all exceptions,
3787 * The NMI is still held pending (which I assume means blocking of further NMIs
3788 * is in effect).
3789 *
3790 * See AMD spec. 15.9 "Instruction Intercepts".
3791 * See AMD spec. 15.21.9 "NMI Support".
3792 */
3793 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_IRET))
3794 {
3795 Log(("iret: Guest intercept -> #VMEXIT\n"));
3796 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
3797 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_IRET, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
3798 }
3799
3800 /*
3801 * Clear NMI blocking, if any, before causing any further exceptions.
3802 * See Intel spec. 6.7.1 "Handling Multiple NMIs".
3803 */
3804 if (fBlockingNmi)
3805 CPUMClearInterruptInhibitingByNmi(&pVCpu->cpum.GstCtx);
3806
3807 /*
3808 * Call a mode specific worker.
3809 */
3810 VBOXSTRICTRC rcStrict;
3811 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
3812 rcStrict = IEM_CIMPL_CALL_1(iemCImpl_iret_real_v8086, enmEffOpSize);
3813 else
3814 {
3815 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_GDTR | CPUMCTX_EXTRN_LDTR);
3816 if (IEM_IS_64BIT_CODE(pVCpu))
3817 rcStrict = IEM_CIMPL_CALL_1(iemCImpl_iret_64bit, enmEffOpSize);
3818 else
3819 rcStrict = IEM_CIMPL_CALL_1(iemCImpl_iret_prot, enmEffOpSize);
3820 }
3821
3822#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3823 /*
3824 * Clear NMI unblocking IRET state with the completion of IRET.
3825 */
3826 if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
3827 pVCpu->cpum.GstCtx.hwvirt.vmx.fNmiUnblockingIret = false;
3828#endif
3829 return rcStrict;
3830}
3831
3832
3833static void iemLoadallSetSelector(PVMCPUCC pVCpu, uint8_t iSegReg, uint16_t uSel)
3834{
3835 PCPUMSELREGHID pHid = iemSRegGetHid(pVCpu, iSegReg);
3836
3837 pHid->Sel = uSel;
3838 pHid->ValidSel = uSel;
3839 pHid->fFlags = CPUMSELREG_FLAGS_VALID;
3840}
3841
3842
3843static void iemLoadall286SetDescCache(PVMCPUCC pVCpu, uint8_t iSegReg, uint8_t const *pbMem)
3844{
3845 PCPUMSELREGHID pHid = iemSRegGetHid(pVCpu, iSegReg);
3846
3847 /* The base is in the first three bytes. */
3848 pHid->u64Base = pbMem[0] + (pbMem[1] << 8) + (pbMem[2] << 16);
3849 /* The attributes are in the fourth byte. */
3850 pHid->Attr.u = pbMem[3];
3851 pHid->Attr.u &= ~(X86DESCATTR_L | X86DESCATTR_D); /* (just to be on the safe side) */
3852 /* The limit is in the last two bytes. */
3853 pHid->u32Limit = pbMem[4] + (pbMem[5] << 8);
3854}
3855
3856
3857/**
3858 * Implements 286 LOADALL (286 CPUs only).
3859 */
3860IEM_CIMPL_DEF_0(iemCImpl_loadall286)
3861{
3862 NOREF(cbInstr);
3863
3864 /* Data is loaded from a buffer at 800h. No checks are done on the
3865 * validity of loaded state.
3866 *
3867 * LOADALL only loads the internal CPU state, it does not access any
3868 * GDT, LDT, or similar tables.
3869 */
3870
3871 if (IEM_GET_CPL(pVCpu) != 0)
3872 {
3873 Log(("loadall286: CPL must be 0 not %u -> #GP(0)\n", IEM_GET_CPL(pVCpu)));
3874 return iemRaiseGeneralProtectionFault0(pVCpu);
3875 }
3876
3877 uint8_t bUnmapInfo;
3878 uint8_t const *pbMem = NULL;
3879 RTGCPHYS GCPtrStart = 0x800; /* Fixed table location. */
3880 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, (void **)&pbMem, &bUnmapInfo, 0x66, UINT8_MAX, GCPtrStart, IEM_ACCESS_SYS_R, 0);
3881 if (rcStrict != VINF_SUCCESS)
3882 return rcStrict;
3883
3884 /* The MSW is at offset 0x06. */
3885 uint16_t const *pau16Mem = (uint16_t const *)(pbMem + 0x06);
3886 /* Even LOADALL can't clear the MSW.PE bit, though it can set it. */
3887 uint64_t uNewCr0 = pVCpu->cpum.GstCtx.cr0 & ~(X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
3888 uNewCr0 |= *pau16Mem & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
3889 uint64_t const uOldCr0 = pVCpu->cpum.GstCtx.cr0;
3890
3891 CPUMSetGuestCR0(pVCpu, uNewCr0);
3892 Assert(pVCpu->cpum.GstCtx.cr0 == uNewCr0);
3893
3894 /* Inform PGM if mode changed. */
3895 if ((uNewCr0 & X86_CR0_PE) != (uOldCr0 & X86_CR0_PE))
3896 {
3897 int rc = PGMFlushTLB(pVCpu, pVCpu->cpum.GstCtx.cr3, true /* global */);
3898 AssertRCReturn(rc, rc);
3899 /* ignore informational status codes */
3900 }
3901 rcStrict = PGMChangeMode(pVCpu, pVCpu->cpum.GstCtx.cr0, pVCpu->cpum.GstCtx.cr4, pVCpu->cpum.GstCtx.msrEFER,
3902 false /* fForce */);
3903
3904 /* TR selector is at offset 0x16. */
3905 pau16Mem = (uint16_t const *)(pbMem + 0x16);
3906 pVCpu->cpum.GstCtx.tr.Sel = pau16Mem[0];
3907 pVCpu->cpum.GstCtx.tr.ValidSel = pau16Mem[0];
3908 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
3909
3910 /* Followed by FLAGS... */
3911 pVCpu->cpum.GstCtx.eflags.u = pau16Mem[1] | X86_EFL_1;
3912 pVCpu->cpum.GstCtx.ip = pau16Mem[2]; /* ...and IP. */
3913
3914 /* LDT is at offset 0x1C. */
3915 pau16Mem = (uint16_t const *)(pbMem + 0x1C);
3916 pVCpu->cpum.GstCtx.ldtr.Sel = pau16Mem[0];
3917 pVCpu->cpum.GstCtx.ldtr.ValidSel = pau16Mem[0];
3918 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
3919
3920 /* Segment registers are at offset 0x1E. */
3921 pau16Mem = (uint16_t const *)(pbMem + 0x1E);
3922 iemLoadallSetSelector(pVCpu, X86_SREG_DS, pau16Mem[0]);
3923 iemLoadallSetSelector(pVCpu, X86_SREG_SS, pau16Mem[1]);
3924 iemLoadallSetSelector(pVCpu, X86_SREG_CS, pau16Mem[2]);
3925 iemLoadallSetSelector(pVCpu, X86_SREG_ES, pau16Mem[3]);
3926
3927 /* GPRs are at offset 0x26. */
3928 pau16Mem = (uint16_t const *)(pbMem + 0x26);
3929 pVCpu->cpum.GstCtx.di = pau16Mem[0];
3930 pVCpu->cpum.GstCtx.si = pau16Mem[1];
3931 pVCpu->cpum.GstCtx.bp = pau16Mem[2];
3932 pVCpu->cpum.GstCtx.sp = pau16Mem[3];
3933 pVCpu->cpum.GstCtx.bx = pau16Mem[4];
3934 pVCpu->cpum.GstCtx.dx = pau16Mem[5];
3935 pVCpu->cpum.GstCtx.cx = pau16Mem[6];
3936 pVCpu->cpum.GstCtx.ax = pau16Mem[7];
3937
3938 /* Descriptor caches are at offset 0x36, 6 bytes per entry. */
3939 iemLoadall286SetDescCache(pVCpu, X86_SREG_ES, pbMem + 0x36);
3940 iemLoadall286SetDescCache(pVCpu, X86_SREG_CS, pbMem + 0x3C);
3941 iemLoadall286SetDescCache(pVCpu, X86_SREG_SS, pbMem + 0x42);
3942 iemLoadall286SetDescCache(pVCpu, X86_SREG_DS, pbMem + 0x48);
3943
3944 /* GDTR contents are at offset 0x4E, 6 bytes. */
3945 uint8_t const *pau8Mem = pbMem + 0x4E;
3946 /* NB: Fourth byte "should be zero"; we are ignoring it. */
3947 RTGCPHYS GCPtrBase = pau8Mem[0] + ((uint32_t)pau8Mem[1] << 8) + ((uint32_t)pau8Mem[2] << 16);
3948 uint16_t cbLimit = pau8Mem[4] + ((uint32_t)pau8Mem[5] << 8);
3949 CPUMSetGuestGDTR(pVCpu, GCPtrBase, cbLimit);
3950
3951 /* IDTR contents are at offset 0x5A, 6 bytes. */
3952 pau8Mem = pbMem + 0x5A;
3953 GCPtrBase = pau8Mem[0] + ((uint32_t)pau8Mem[1] << 8) + ((uint32_t)pau8Mem[2] << 16);
3954 cbLimit = pau8Mem[4] + ((uint32_t)pau8Mem[5] << 8);
3955 CPUMSetGuestIDTR(pVCpu, GCPtrBase, cbLimit);
3956
3957 Log(("LOADALL: GDTR:%08RX64/%04X, IDTR:%08RX64/%04X\n", pVCpu->cpum.GstCtx.gdtr.pGdt, pVCpu->cpum.GstCtx.gdtr.cbGdt, pVCpu->cpum.GstCtx.idtr.pIdt, pVCpu->cpum.GstCtx.idtr.cbIdt));
3958 Log(("LOADALL: CS:%04X, CS base:%08X, limit:%04X, attrs:%02X\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.cs.u64Base, pVCpu->cpum.GstCtx.cs.u32Limit, pVCpu->cpum.GstCtx.cs.Attr.u));
3959 Log(("LOADALL: DS:%04X, DS base:%08X, limit:%04X, attrs:%02X\n", pVCpu->cpum.GstCtx.ds.Sel, pVCpu->cpum.GstCtx.ds.u64Base, pVCpu->cpum.GstCtx.ds.u32Limit, pVCpu->cpum.GstCtx.ds.Attr.u));
3960 Log(("LOADALL: ES:%04X, ES base:%08X, limit:%04X, attrs:%02X\n", pVCpu->cpum.GstCtx.es.Sel, pVCpu->cpum.GstCtx.es.u64Base, pVCpu->cpum.GstCtx.es.u32Limit, pVCpu->cpum.GstCtx.es.Attr.u));
3961 Log(("LOADALL: SS:%04X, SS base:%08X, limit:%04X, attrs:%02X\n", pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.ss.u64Base, pVCpu->cpum.GstCtx.ss.u32Limit, pVCpu->cpum.GstCtx.ss.Attr.u));
3962 Log(("LOADALL: SI:%04X, DI:%04X, AX:%04X, BX:%04X, CX:%04X, DX:%04X\n", pVCpu->cpum.GstCtx.si, pVCpu->cpum.GstCtx.di, pVCpu->cpum.GstCtx.bx, pVCpu->cpum.GstCtx.bx, pVCpu->cpum.GstCtx.cx, pVCpu->cpum.GstCtx.dx));
3963
3964 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
3965 if (rcStrict != VINF_SUCCESS)
3966 return rcStrict;
3967
3968 /*
3969 * The CPL may change and protected mode may change enabled. It is taken
3970 * from the "DPL fields of the SS and CS descriptor caches" but there is no
3971 * word as to what happens if those are not identical (probably bad things).
3972 */
3973 iemRecalcExecModeAndCplAndAcFlags(pVCpu);
3974 Assert(IEM_IS_16BIT_CODE(pVCpu));
3975
3976 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_HIDDEN_SEL_REGS | CPUM_CHANGED_IDTR | CPUM_CHANGED_GDTR | CPUM_CHANGED_TR | CPUM_CHANGED_LDTR);
3977
3978 /* Flush the prefetch buffer. */
3979 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr);
3980
3981/** @todo single stepping */
3982 return rcStrict;
3983}
3984
3985
3986/**
3987 * Implements SYSCALL (AMD and Intel64).
3988 */
3989IEM_CIMPL_DEF_0(iemCImpl_syscall)
3990{
3991
3992
3993 /*
3994 * Check preconditions.
3995 *
3996 * Note that CPUs described in the documentation may load a few odd values
3997 * into CS and SS than we allow here. This has yet to be checked on real
3998 * hardware.
3999 */
4000 if (!(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_SCE))
4001 {
4002 Log(("syscall: Not enabled in EFER -> #UD\n"));
4003 return iemRaiseUndefinedOpcode(pVCpu);
4004 }
4005 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
4006 {
4007 Log(("syscall: Protected mode is required -> #GP(0)\n"));
4008 return iemRaiseGeneralProtectionFault0(pVCpu);
4009 }
4010 if ( IEM_IS_GUEST_CPU_INTEL(pVCpu)
4011 && !IEM_IS_64BIT_CODE(pVCpu)) //&& !CPUMIsGuestInLongModeEx(IEM_GET_CTX(pVCpu)))
4012 {
4013 Log(("syscall: Only available in 64-bit mode on intel -> #UD\n"));
4014 return iemRaiseUndefinedOpcode(pVCpu);
4015 }
4016
4017 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_SYSCALL_MSRS);
4018
4019 /** @todo verify RPL ignoring and CS=0xfff8 (i.e. SS == 0). */
4020 /** @todo what about LDT selectors? Shouldn't matter, really. */
4021 uint16_t uNewCs = (pVCpu->cpum.GstCtx.msrSTAR >> MSR_K6_STAR_SYSCALL_CS_SS_SHIFT) & X86_SEL_MASK_OFF_RPL;
4022 uint16_t uNewSs = uNewCs + 8;
4023 if (uNewCs == 0 || uNewSs == 0)
4024 {
4025 /** @todo Neither Intel nor AMD document this check. */
4026 Log(("syscall: msrSTAR.CS = 0 or SS = 0 -> #GP(0)\n"));
4027 return iemRaiseGeneralProtectionFault0(pVCpu);
4028 }
4029
4030 /*
4031 * Hack alert! Convert incoming debug events to slient on Intel.
4032 * See the dbg+inhibit+ringxfer test in bs3-cpu-weird-1.
4033 */
4034 if ( !(pVCpu->cpum.GstCtx.eflags.uBoth & CPUMCTX_DBG_HIT_DRX_MASK_NONSILENT)
4035 || !IEM_IS_GUEST_CPU_INTEL(pVCpu))
4036 { /* ignore */ }
4037 else
4038 {
4039 Log(("iemCImpl_syscall: Converting pending debug events to a silent one (intel hack)\n",
4040 pVCpu->cpum.GstCtx.eflags.uBoth & CPUMCTX_DBG_HIT_DRX_MASK));
4041 pVCpu->cpum.GstCtx.eflags.uBoth = (pVCpu->cpum.GstCtx.eflags.uBoth & ~CPUMCTX_DBG_HIT_DRX_MASK)
4042 | CPUMCTX_DBG_HIT_DRX_SILENT;
4043 }
4044
4045 /*
4046 * Long mode and legacy mode differs.
4047 */
4048 if (CPUMIsGuestInLongModeEx(IEM_GET_CTX(pVCpu)))
4049 {
4050 uint64_t uNewRip = IEM_IS_64BIT_CODE(pVCpu) ? pVCpu->cpum.GstCtx.msrLSTAR : pVCpu->cpum.GstCtx. msrCSTAR;
4051
4052 /* This test isn't in the docs, but I'm not trusting the guys writing
4053 the MSRs to have validated the values as canonical like they should. */
4054 if (!IEM_IS_CANONICAL(uNewRip))
4055 {
4056 /** @todo Intel claims this can't happen because IA32_LSTAR MSR can't be written with non-canonical address. */
4057 Log(("syscall: New RIP not canonical -> #UD\n"));
4058 return iemRaiseUndefinedOpcode(pVCpu);
4059 }
4060
4061 /*
4062 * Commit it.
4063 */
4064 Log(("syscall: %04x:%016RX64 [efl=%#llx] -> %04x:%016RX64\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags.u, uNewCs, uNewRip));
4065 pVCpu->cpum.GstCtx.rcx = pVCpu->cpum.GstCtx.rip + cbInstr;
4066 pVCpu->cpum.GstCtx.rip = uNewRip;
4067
4068 pVCpu->cpum.GstCtx.rflags.u &= ~X86_EFL_RF;
4069 pVCpu->cpum.GstCtx.r11 = pVCpu->cpum.GstCtx.rflags.u;
4070 pVCpu->cpum.GstCtx.rflags.u &= ~pVCpu->cpum.GstCtx.msrSFMASK;
4071 pVCpu->cpum.GstCtx.rflags.u |= X86_EFL_RA1_MASK;
4072
4073 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_L | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC;
4074 pVCpu->cpum.GstCtx.ss.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_RW_ACC;
4075
4076 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~(IEM_F_MODE_MASK | IEM_F_X86_CPL_MASK | IEM_F_X86_AC))
4077 | IEM_F_MODE_X86_64BIT;
4078 }
4079 else
4080 {
4081 /*
4082 * Commit it.
4083 */
4084 Log(("syscall: %04x:%08RX32 [efl=%#x] -> %04x:%08RX32\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip, pVCpu->cpum.GstCtx.eflags.u, uNewCs, (uint32_t)(pVCpu->cpum.GstCtx.msrSTAR & MSR_K6_STAR_SYSCALL_EIP_MASK)));
4085 pVCpu->cpum.GstCtx.rcx = pVCpu->cpum.GstCtx.eip + cbInstr;
4086 pVCpu->cpum.GstCtx.rip = pVCpu->cpum.GstCtx.msrSTAR & MSR_K6_STAR_SYSCALL_EIP_MASK;
4087 pVCpu->cpum.GstCtx.rflags.u &= ~(X86_EFL_VM | X86_EFL_IF | X86_EFL_RF);
4088
4089 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC;
4090 pVCpu->cpum.GstCtx.ss.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_RW_ACC;
4091
4092 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~(IEM_F_MODE_MASK | IEM_F_X86_CPL_MASK | IEM_F_X86_AC))
4093 | IEM_F_MODE_X86_32BIT_PROT
4094 | iemCalc32BitFlatIndicatorEsDs(pVCpu);
4095 }
4096 pVCpu->cpum.GstCtx.cs.Sel = uNewCs;
4097 pVCpu->cpum.GstCtx.cs.ValidSel = uNewCs;
4098 pVCpu->cpum.GstCtx.cs.u64Base = 0;
4099 pVCpu->cpum.GstCtx.cs.u32Limit = UINT32_MAX;
4100 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
4101
4102 pVCpu->cpum.GstCtx.ss.Sel = uNewSs;
4103 pVCpu->cpum.GstCtx.ss.ValidSel = uNewSs;
4104 pVCpu->cpum.GstCtx.ss.u64Base = 0;
4105 pVCpu->cpum.GstCtx.ss.u32Limit = UINT32_MAX;
4106 pVCpu->cpum.GstCtx.ss.fFlags = CPUMSELREG_FLAGS_VALID;
4107
4108 /* Flush the prefetch buffer. */
4109 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr);
4110
4111 /*
4112 * Handle debug events.
4113 * If TF isn't masked, we're supposed to raise a single step #DB.
4114 */
4115 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
4116}
4117
4118
4119/**
4120 * Implements SYSRET (AMD and Intel64).
4121 *
4122 * @param enmEffOpSize The effective operand size.
4123 */
4124IEM_CIMPL_DEF_1(iemCImpl_sysret, IEMMODE, enmEffOpSize)
4125
4126{
4127 RT_NOREF_PV(cbInstr);
4128
4129 /*
4130 * Check preconditions.
4131 *
4132 * Note that CPUs described in the documentation may load a few odd values
4133 * into CS and SS than we allow here. This has yet to be checked on real
4134 * hardware.
4135 */
4136 if (!(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_SCE))
4137 {
4138 Log(("sysret: Not enabled in EFER -> #UD\n"));
4139 return iemRaiseUndefinedOpcode(pVCpu);
4140 }
4141 if (IEM_IS_GUEST_CPU_INTEL(pVCpu) && !CPUMIsGuestInLongModeEx(IEM_GET_CTX(pVCpu)))
4142 {
4143 Log(("sysret: Only available in long mode on intel -> #UD\n"));
4144 return iemRaiseUndefinedOpcode(pVCpu);
4145 }
4146 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
4147 {
4148 Log(("sysret: Protected mode is required -> #GP(0)\n"));
4149 return iemRaiseGeneralProtectionFault0(pVCpu);
4150 }
4151 if (IEM_GET_CPL(pVCpu) != 0)
4152 {
4153 Log(("sysret: CPL must be 0 not %u -> #GP(0)\n", IEM_GET_CPL(pVCpu)));
4154 return iemRaiseGeneralProtectionFault0(pVCpu);
4155 }
4156
4157 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_SYSCALL_MSRS);
4158
4159 /** @todo Does SYSRET verify CS != 0 and SS != 0? Neither is valid in ring-3. */
4160 uint16_t uNewCs = (pVCpu->cpum.GstCtx.msrSTAR >> MSR_K6_STAR_SYSRET_CS_SS_SHIFT) & X86_SEL_MASK_OFF_RPL;
4161 uint16_t uNewSs = uNewCs + 8;
4162 if (enmEffOpSize == IEMMODE_64BIT)
4163 uNewCs += 16;
4164 if (uNewCs == 0 || uNewSs == 0)
4165 {
4166 Log(("sysret: msrSTAR.CS = 0 or SS = 0 -> #GP(0)\n"));
4167 return iemRaiseGeneralProtectionFault0(pVCpu);
4168 }
4169
4170 /*
4171 * Commit it.
4172 */
4173 bool f32Bit = true;
4174 if (CPUMIsGuestInLongModeEx(IEM_GET_CTX(pVCpu)))
4175 {
4176 if (enmEffOpSize == IEMMODE_64BIT)
4177 {
4178 Log(("sysret: %04x:%016RX64 [efl=%#llx] -> %04x:%016RX64 [r11=%#llx]\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags.u, uNewCs, pVCpu->cpum.GstCtx.rcx, pVCpu->cpum.GstCtx.r11));
4179 /* Note! We disregard intel manual regarding the RCX canonical
4180 check, ask intel+xen why AMD doesn't do it. */
4181 pVCpu->cpum.GstCtx.rip = pVCpu->cpum.GstCtx.rcx;
4182 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_L | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC
4183 | (3 << X86DESCATTR_DPL_SHIFT);
4184 f32Bit = false;
4185 }
4186 else
4187 {
4188 Log(("sysret: %04x:%016RX64 [efl=%#llx] -> %04x:%08RX32 [r11=%#llx]\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags.u, uNewCs, pVCpu->cpum.GstCtx.ecx, pVCpu->cpum.GstCtx.r11));
4189 pVCpu->cpum.GstCtx.rip = pVCpu->cpum.GstCtx.ecx;
4190 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC
4191 | (3 << X86DESCATTR_DPL_SHIFT);
4192 }
4193 /** @todo testcase: See what kind of flags we can make SYSRET restore and
4194 * what it really ignores. RF and VM are hinted at being zero, by AMD.
4195 * Intel says: RFLAGS := (R11 & 3C7FD7H) | 2; */
4196 pVCpu->cpum.GstCtx.rflags.u = pVCpu->cpum.GstCtx.r11 & (X86_EFL_POPF_BITS | X86_EFL_VIF | X86_EFL_VIP);
4197 pVCpu->cpum.GstCtx.rflags.u |= X86_EFL_RA1_MASK;
4198 }
4199 else
4200 {
4201 Log(("sysret: %04x:%08RX32 [efl=%#x] -> %04x:%08RX32\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip, pVCpu->cpum.GstCtx.eflags.u, uNewCs, pVCpu->cpum.GstCtx.ecx));
4202 pVCpu->cpum.GstCtx.rip = pVCpu->cpum.GstCtx.rcx;
4203 pVCpu->cpum.GstCtx.rflags.u |= X86_EFL_IF;
4204 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC
4205 | (3 << X86DESCATTR_DPL_SHIFT);
4206 }
4207 pVCpu->cpum.GstCtx.cs.Sel = uNewCs | 3;
4208 pVCpu->cpum.GstCtx.cs.ValidSel = uNewCs | 3;
4209 pVCpu->cpum.GstCtx.cs.u64Base = 0;
4210 pVCpu->cpum.GstCtx.cs.u32Limit = UINT32_MAX;
4211 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
4212
4213 /* The SS hidden bits remains unchanged says AMD, we presume they set DPL to 3.
4214 Intel (and presuably VIA) OTOH sets loads valid ring-3 values it seems, see
4215 X86_BUG_SYSRET_SS_ATTRS in linux 5.3. */
4216 if (IEM_IS_GUEST_CPU_AMD(pVCpu))
4217 {
4218 Log(("sysret: ss:rsp=%04x:%08RX64 attr=%x -> %04x:%08RX64 attr=%#x\n", pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.ss.Attr.u, uNewSs | 3, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.ss.Attr.u | (3 << X86DESCATTR_DPL_SHIFT) ));
4219 pVCpu->cpum.GstCtx.ss.Attr.u |= (3 << X86DESCATTR_DPL_SHIFT);
4220 }
4221 else
4222 {
4223 Log(("sysret: ss:rsp=%04x:%08RX64 attr=%x -> %04x:%08RX64 attr=%#x\n", pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.ss.Attr.u, uNewSs | 3, pVCpu->cpum.GstCtx.rsp, X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_RW_ACC | (3 << X86DESCATTR_DPL_SHIFT) ));
4224 pVCpu->cpum.GstCtx.ss.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_RW_ACC
4225 | (3 << X86DESCATTR_DPL_SHIFT);
4226 pVCpu->cpum.GstCtx.ss.u64Base = 0;
4227 pVCpu->cpum.GstCtx.ss.u32Limit = UINT32_MAX;
4228 }
4229 pVCpu->cpum.GstCtx.ss.Sel = uNewSs | 3;
4230 pVCpu->cpum.GstCtx.ss.ValidSel = uNewSs | 3;
4231 pVCpu->cpum.GstCtx.ss.fFlags = CPUMSELREG_FLAGS_VALID;
4232 /** @todo Testcase: verify that SS.u1Long and SS.u1DefBig are left unchanged
4233 * on sysret on AMD and not on intel. */
4234
4235 if (!f32Bit)
4236 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~(IEM_F_MODE_MASK | IEM_F_X86_CPL_MASK | IEM_F_X86_AC))
4237 | (3 << IEM_F_X86_CPL_SHIFT)
4238 | IEM_F_MODE_X86_64BIT
4239 | iemCalcExecAcFlag(pVCpu);
4240 else
4241 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~(IEM_F_MODE_MASK | IEM_F_X86_CPL_MASK | IEM_F_X86_AC))
4242 | (3 << IEM_F_X86_CPL_SHIFT)
4243 | IEM_F_MODE_X86_32BIT_PROT
4244 /** @todo sort out the SS.BASE/LIM/ATTR claim by AMD and maybe we can switch to
4245 * iemCalc32BitFlatIndicatorDsEs and move this up into the above branch. */
4246 | iemCalc32BitFlatIndicator(pVCpu)
4247 | iemCalcExecAcFlag(pVCpu);
4248
4249 /* Flush the prefetch buffer. */
4250 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr);
4251
4252/** @todo single step */
4253 return VINF_SUCCESS;
4254}
4255
4256
4257/**
4258 * Implements SYSENTER (Intel, 32-bit AMD).
4259 */
4260IEM_CIMPL_DEF_0(iemCImpl_sysenter)
4261{
4262 RT_NOREF(cbInstr);
4263
4264 /*
4265 * Check preconditions.
4266 *
4267 * Note that CPUs described in the documentation may load a few odd values
4268 * into CS and SS than we allow here. This has yet to be checked on real
4269 * hardware.
4270 */
4271 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fSysEnter)
4272 {
4273 Log(("sysenter: not supported -=> #UD\n"));
4274 return iemRaiseUndefinedOpcode(pVCpu);
4275 }
4276 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
4277 {
4278 Log(("sysenter: Protected or long mode is required -> #GP(0)\n"));
4279 return iemRaiseGeneralProtectionFault0(pVCpu);
4280 }
4281 bool fIsLongMode = CPUMIsGuestInLongModeEx(IEM_GET_CTX(pVCpu));
4282 if (IEM_IS_GUEST_CPU_AMD(pVCpu) && fIsLongMode)
4283 {
4284 Log(("sysenter: Only available in protected mode on AMD -> #UD\n"));
4285 return iemRaiseUndefinedOpcode(pVCpu);
4286 }
4287 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_SYSENTER_MSRS);
4288 uint16_t uNewCs = pVCpu->cpum.GstCtx.SysEnter.cs;
4289 if ((uNewCs & X86_SEL_MASK_OFF_RPL) == 0)
4290 {
4291 Log(("sysenter: SYSENTER_CS = %#x -> #GP(0)\n", uNewCs));
4292 return iemRaiseGeneralProtectionFault0(pVCpu);
4293 }
4294
4295 /* This test isn't in the docs, it's just a safeguard against missing
4296 canonical checks when writing the registers. */
4297 if (RT_LIKELY( !fIsLongMode
4298 || ( IEM_IS_CANONICAL(pVCpu->cpum.GstCtx.SysEnter.eip)
4299 && IEM_IS_CANONICAL(pVCpu->cpum.GstCtx.SysEnter.esp))))
4300 { /* likely */ }
4301 else
4302 {
4303 Log(("sysenter: SYSENTER_EIP = %#RX64 or/and SYSENTER_ESP = %#RX64 not canonical -> #GP(0)\n",
4304 pVCpu->cpum.GstCtx.SysEnter.eip, pVCpu->cpum.GstCtx.SysEnter.esp));
4305 return iemRaiseUndefinedOpcode(pVCpu);
4306 }
4307
4308/** @todo Test: Sysenter from ring-0, ring-1 and ring-2. */
4309
4310 /*
4311 * Update registers and commit.
4312 */
4313 if (fIsLongMode)
4314 {
4315 Log(("sysenter: %04x:%016RX64 [efl=%#llx] -> %04x:%016RX64\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
4316 pVCpu->cpum.GstCtx.rflags.u, uNewCs & X86_SEL_MASK_OFF_RPL, pVCpu->cpum.GstCtx.SysEnter.eip));
4317 pVCpu->cpum.GstCtx.rip = pVCpu->cpum.GstCtx.SysEnter.eip;
4318 pVCpu->cpum.GstCtx.rsp = pVCpu->cpum.GstCtx.SysEnter.esp;
4319 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESCATTR_L | X86DESCATTR_G | X86DESCATTR_P | X86DESCATTR_DT
4320 | X86DESCATTR_LIMIT_HIGH | X86_SEL_TYPE_ER_ACC;
4321 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~(IEM_F_MODE_MASK | IEM_F_X86_CPL_MASK | IEM_F_X86_AC))
4322 | IEM_F_MODE_X86_64BIT;
4323 }
4324 else
4325 {
4326 Log(("sysenter: %04x:%08RX32 [efl=%#llx] -> %04x:%08RX32\n", pVCpu->cpum.GstCtx.cs.Sel, (uint32_t)pVCpu->cpum.GstCtx.rip,
4327 pVCpu->cpum.GstCtx.rflags.u, uNewCs & X86_SEL_MASK_OFF_RPL, (uint32_t)pVCpu->cpum.GstCtx.SysEnter.eip));
4328 pVCpu->cpum.GstCtx.rip = (uint32_t)pVCpu->cpum.GstCtx.SysEnter.eip;
4329 pVCpu->cpum.GstCtx.rsp = (uint32_t)pVCpu->cpum.GstCtx.SysEnter.esp;
4330 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESCATTR_D | X86DESCATTR_G | X86DESCATTR_P | X86DESCATTR_DT
4331 | X86DESCATTR_LIMIT_HIGH | X86_SEL_TYPE_ER_ACC;
4332 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~(IEM_F_MODE_MASK | IEM_F_X86_CPL_MASK | IEM_F_X86_AC))
4333 | IEM_F_MODE_X86_32BIT_PROT
4334 | iemCalc32BitFlatIndicatorEsDs(pVCpu);
4335 }
4336 pVCpu->cpum.GstCtx.cs.Sel = uNewCs & X86_SEL_MASK_OFF_RPL;
4337 pVCpu->cpum.GstCtx.cs.ValidSel = uNewCs & X86_SEL_MASK_OFF_RPL;
4338 pVCpu->cpum.GstCtx.cs.u64Base = 0;
4339 pVCpu->cpum.GstCtx.cs.u32Limit = UINT32_MAX;
4340 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
4341
4342 pVCpu->cpum.GstCtx.ss.Sel = (uNewCs & X86_SEL_MASK_OFF_RPL) + 8;
4343 pVCpu->cpum.GstCtx.ss.ValidSel = (uNewCs & X86_SEL_MASK_OFF_RPL) + 8;
4344 pVCpu->cpum.GstCtx.ss.u64Base = 0;
4345 pVCpu->cpum.GstCtx.ss.u32Limit = UINT32_MAX;
4346 pVCpu->cpum.GstCtx.ss.Attr.u = X86DESCATTR_D | X86DESCATTR_G | X86DESCATTR_P | X86DESCATTR_DT
4347 | X86DESCATTR_LIMIT_HIGH | X86_SEL_TYPE_RW_ACC;
4348 pVCpu->cpum.GstCtx.ss.fFlags = CPUMSELREG_FLAGS_VALID;
4349
4350 pVCpu->cpum.GstCtx.rflags.Bits.u1IF = 0;
4351 pVCpu->cpum.GstCtx.rflags.Bits.u1VM = 0;
4352 pVCpu->cpum.GstCtx.rflags.Bits.u1RF = 0;
4353
4354 /* Flush the prefetch buffer. */
4355 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr);
4356
4357/** @todo single stepping */
4358 return VINF_SUCCESS;
4359}
4360
4361
4362/**
4363 * Implements SYSEXIT (Intel, 32-bit AMD).
4364 *
4365 * @param enmEffOpSize The effective operand size.
4366 */
4367IEM_CIMPL_DEF_1(iemCImpl_sysexit, IEMMODE, enmEffOpSize)
4368{
4369 RT_NOREF(cbInstr);
4370
4371 /*
4372 * Check preconditions.
4373 *
4374 * Note that CPUs described in the documentation may load a few odd values
4375 * into CS and SS than we allow here. This has yet to be checked on real
4376 * hardware.
4377 */
4378 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fSysEnter)
4379 {
4380 Log(("sysexit: not supported -=> #UD\n"));
4381 return iemRaiseUndefinedOpcode(pVCpu);
4382 }
4383 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
4384 {
4385 Log(("sysexit: Protected or long mode is required -> #GP(0)\n"));
4386 return iemRaiseGeneralProtectionFault0(pVCpu);
4387 }
4388 bool fIsLongMode = CPUMIsGuestInLongModeEx(IEM_GET_CTX(pVCpu));
4389 if (IEM_IS_GUEST_CPU_AMD(pVCpu) && fIsLongMode)
4390 {
4391 Log(("sysexit: Only available in protected mode on AMD -> #UD\n"));
4392 return iemRaiseUndefinedOpcode(pVCpu);
4393 }
4394 if (IEM_GET_CPL(pVCpu) != 0)
4395 {
4396 Log(("sysexit: CPL(=%u) != 0 -> #GP(0)\n", IEM_GET_CPL(pVCpu)));
4397 return iemRaiseGeneralProtectionFault0(pVCpu);
4398 }
4399 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_SYSENTER_MSRS);
4400 uint16_t uNewCs = pVCpu->cpum.GstCtx.SysEnter.cs;
4401 if ((uNewCs & X86_SEL_MASK_OFF_RPL) == 0)
4402 {
4403 Log(("sysexit: SYSENTER_CS = %#x -> #GP(0)\n", uNewCs));
4404 return iemRaiseGeneralProtectionFault0(pVCpu);
4405 }
4406
4407 /*
4408 * Update registers and commit.
4409 */
4410 if (enmEffOpSize == IEMMODE_64BIT)
4411 {
4412 Log(("sysexit: %04x:%016RX64 [efl=%#llx] -> %04x:%016RX64\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
4413 pVCpu->cpum.GstCtx.rflags.u, (uNewCs | 3) + 32, pVCpu->cpum.GstCtx.rcx));
4414 pVCpu->cpum.GstCtx.rip = pVCpu->cpum.GstCtx.rdx;
4415 pVCpu->cpum.GstCtx.rsp = pVCpu->cpum.GstCtx.rcx;
4416 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESCATTR_L | X86DESCATTR_G | X86DESCATTR_P | X86DESCATTR_DT
4417 | X86DESCATTR_LIMIT_HIGH | X86_SEL_TYPE_ER_ACC | (3 << X86DESCATTR_DPL_SHIFT);
4418 pVCpu->cpum.GstCtx.cs.Sel = (uNewCs | 3) + 32;
4419 pVCpu->cpum.GstCtx.cs.ValidSel = (uNewCs | 3) + 32;
4420 pVCpu->cpum.GstCtx.ss.Sel = (uNewCs | 3) + 40;
4421 pVCpu->cpum.GstCtx.ss.ValidSel = (uNewCs | 3) + 40;
4422
4423 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~(IEM_F_MODE_MASK | IEM_F_X86_CPL_MASK))
4424 | (3 << IEM_F_X86_CPL_SHIFT)
4425 | IEM_F_MODE_X86_64BIT
4426 | iemCalcExecAcFlag(pVCpu);
4427 }
4428 else
4429 {
4430 Log(("sysexit: %04x:%08RX64 [efl=%#llx] -> %04x:%08RX32\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
4431 pVCpu->cpum.GstCtx.rflags.u, (uNewCs | 3) + 16, (uint32_t)pVCpu->cpum.GstCtx.edx));
4432 pVCpu->cpum.GstCtx.rip = pVCpu->cpum.GstCtx.edx;
4433 pVCpu->cpum.GstCtx.rsp = pVCpu->cpum.GstCtx.ecx;
4434 pVCpu->cpum.GstCtx.cs.Attr.u = X86DESCATTR_D | X86DESCATTR_G | X86DESCATTR_P | X86DESCATTR_DT
4435 | X86DESCATTR_LIMIT_HIGH | X86_SEL_TYPE_ER_ACC | (3 << X86DESCATTR_DPL_SHIFT);
4436 pVCpu->cpum.GstCtx.cs.Sel = (uNewCs | 3) + 16;
4437 pVCpu->cpum.GstCtx.cs.ValidSel = (uNewCs | 3) + 16;
4438 pVCpu->cpum.GstCtx.ss.Sel = (uNewCs | 3) + 24;
4439 pVCpu->cpum.GstCtx.ss.ValidSel = (uNewCs | 3) + 24;
4440
4441 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~(IEM_F_MODE_MASK | IEM_F_X86_CPL_MASK))
4442 | (3 << IEM_F_X86_CPL_SHIFT)
4443 | IEM_F_MODE_X86_32BIT_PROT
4444 | iemCalc32BitFlatIndicatorEsDs(pVCpu)
4445 | iemCalcExecAcFlag(pVCpu);
4446 }
4447 pVCpu->cpum.GstCtx.cs.u64Base = 0;
4448 pVCpu->cpum.GstCtx.cs.u32Limit = UINT32_MAX;
4449 pVCpu->cpum.GstCtx.cs.fFlags = CPUMSELREG_FLAGS_VALID;
4450
4451 pVCpu->cpum.GstCtx.ss.u64Base = 0;
4452 pVCpu->cpum.GstCtx.ss.u32Limit = UINT32_MAX;
4453 pVCpu->cpum.GstCtx.ss.Attr.u = X86DESCATTR_D | X86DESCATTR_G | X86DESCATTR_P | X86DESCATTR_DT
4454 | X86DESCATTR_LIMIT_HIGH | X86_SEL_TYPE_RW_ACC | (3 << X86DESCATTR_DPL_SHIFT);
4455 pVCpu->cpum.GstCtx.ss.fFlags = CPUMSELREG_FLAGS_VALID;
4456 pVCpu->cpum.GstCtx.rflags.Bits.u1RF = 0;
4457
4458/** @todo single stepping */
4459
4460 /* Flush the prefetch buffer. */
4461 IEM_FLUSH_PREFETCH_HEAVY(pVCpu, cbInstr);
4462
4463 return VINF_SUCCESS;
4464}
4465
4466
4467/**
4468 * Completes a MOV SReg,XXX or POP SReg instruction.
4469 *
4470 * When not modifying SS or when we're already in an interrupt shadow we
4471 * can update RIP and finish the instruction the normal way.
4472 *
4473 * Otherwise, the MOV/POP SS interrupt shadow that we now enable will block
4474 * both TF and DBx events. The TF will be ignored while the DBx ones will
4475 * be delayed till the next instruction boundrary. For more details see
4476 * @sdmv3{077,200,6.8.3,Masking Exceptions and Interrupts When Switching Stacks}.
4477 */
4478DECLINLINE(VBOXSTRICTRC) iemCImpl_LoadSRegFinish(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iSegReg)
4479{
4480 if (iSegReg != X86_SREG_SS || CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx))
4481 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
4482
4483 iemRegAddToRip(pVCpu, cbInstr);
4484 pVCpu->cpum.GstCtx.eflags.uBoth &= ~X86_EFL_RF; /* Shadow int isn't set and DRx is delayed, so only clear RF. */
4485 CPUMSetInInterruptShadowSs(&pVCpu->cpum.GstCtx);
4486
4487 return VINF_SUCCESS;
4488}
4489
4490
4491/**
4492 * Common worker for 'pop SReg', 'mov SReg, GReg' and 'lXs GReg, reg/mem'.
4493 *
4494 * @param pVCpu The cross context virtual CPU structure of the calling
4495 * thread.
4496 * @param iSegReg The segment register number (valid).
4497 * @param uSel The new selector value.
4498 */
4499static VBOXSTRICTRC iemCImpl_LoadSRegWorker(PVMCPUCC pVCpu, uint8_t iSegReg, uint16_t uSel)
4500{
4501 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
4502 uint16_t *pSel = iemSRegRef(pVCpu, iSegReg);
4503 PCPUMSELREGHID pHid = iemSRegGetHid(pVCpu, iSegReg);
4504
4505 Assert(iSegReg <= X86_SREG_GS && iSegReg != X86_SREG_CS);
4506
4507 /*
4508 * Real mode and V8086 mode are easy.
4509 */
4510 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
4511 {
4512 *pSel = uSel;
4513 pHid->u64Base = (uint32_t)uSel << 4;
4514 pHid->ValidSel = uSel;
4515 pHid->fFlags = CPUMSELREG_FLAGS_VALID;
4516#if 0 /* AMD Volume 2, chapter 4.1 - "real mode segmentation" - states that limit and attributes are untouched. */
4517 /** @todo Does the CPU actually load limits and attributes in the
4518 * real/V8086 mode segment load case? It doesn't for CS in far
4519 * jumps... Affects unreal mode. */
4520 pHid->u32Limit = 0xffff;
4521 pHid->Attr.u = 0;
4522 pHid->Attr.n.u1Present = 1;
4523 pHid->Attr.n.u1DescType = 1;
4524 pHid->Attr.n.u4Type = iSegReg != X86_SREG_CS
4525 ? X86_SEL_TYPE_RW
4526 : X86_SEL_TYPE_READ | X86_SEL_TYPE_CODE;
4527#endif
4528
4529 /* Update the FLAT 32-bit mode flag, if we're in 32-bit unreal mode (unlikely): */
4530 if (RT_LIKELY(!IEM_IS_32BIT_CODE(pVCpu)))
4531 { /* likely */ }
4532 else if (uSel != 0)
4533 pVCpu->iem.s.fExec &= ~IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK;
4534 else
4535 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK)
4536 | iemCalc32BitFlatIndicator(pVCpu);
4537 }
4538 /*
4539 * Protected / long mode - null segment.
4540 *
4541 * Check if it's a null segment selector value first, that's OK for DS, ES,
4542 * FS and GS. If not null, then we have to load and parse the descriptor.
4543 */
4544 else if (!(uSel & X86_SEL_MASK_OFF_RPL))
4545 {
4546 Assert(iSegReg != X86_SREG_CS); /** @todo testcase for \#UD on MOV CS, ax! */
4547 if (iSegReg == X86_SREG_SS)
4548 {
4549 /* In 64-bit kernel mode, the stack can be 0 because of the way
4550 interrupts are dispatched. AMD seems to have a slighly more
4551 relaxed relationship to SS.RPL than intel does. */
4552 /** @todo We cannot 'mov ss, 3' in 64-bit kernel mode, can we? There is a testcase (bs-cpu-xcpt-1), but double check this! */
4553 if ( !IEM_IS_64BIT_CODE(pVCpu)
4554 || IEM_GET_CPL(pVCpu) > 2
4555 || ( uSel != IEM_GET_CPL(pVCpu)
4556 && !IEM_IS_GUEST_CPU_AMD(pVCpu)) )
4557 {
4558 Log(("load sreg %#x -> invalid stack selector, #GP(0)\n", uSel));
4559 return iemRaiseGeneralProtectionFault0(pVCpu);
4560 }
4561 }
4562
4563 *pSel = uSel; /* Not RPL, remember :-) */
4564 iemHlpLoadNullDataSelectorProt(pVCpu, pHid, uSel);
4565 if (iSegReg == X86_SREG_SS)
4566 pHid->Attr.u |= IEM_GET_CPL(pVCpu) << X86DESCATTR_DPL_SHIFT;
4567
4568 /* This will affect the FLAT 32-bit mode flag: */
4569 if ( iSegReg < X86_SREG_FS
4570 && IEM_IS_32BIT_CODE(pVCpu))
4571 pVCpu->iem.s.fExec &= ~IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK;
4572 }
4573 /*
4574 * Protected / long mode.
4575 */
4576 else
4577 {
4578 /* Fetch the descriptor. */
4579 IEMSELDESC Desc;
4580 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pVCpu, &Desc, uSel, X86_XCPT_GP); /** @todo Correct exception? */
4581 if (rcStrict != VINF_SUCCESS)
4582 return rcStrict;
4583
4584 /* Check GPs first. */
4585 if (!Desc.Legacy.Gen.u1DescType)
4586 {
4587 Log(("load sreg %d (=%#x) - system selector (%#x) -> #GP\n", iSegReg, uSel, Desc.Legacy.Gen.u4Type));
4588 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
4589 }
4590 if (iSegReg == X86_SREG_SS) /* SS gets different treatment */
4591 {
4592 if ( (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
4593 || !(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
4594 {
4595 Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
4596 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
4597 }
4598 if ((uSel & X86_SEL_RPL) != IEM_GET_CPL(pVCpu))
4599 {
4600 Log(("load sreg SS, %#x - RPL and CPL (%d) differs -> #GP\n", uSel, IEM_GET_CPL(pVCpu)));
4601 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
4602 }
4603 if (Desc.Legacy.Gen.u2Dpl != IEM_GET_CPL(pVCpu))
4604 {
4605 Log(("load sreg SS, %#x - DPL (%d) and CPL (%d) differs -> #GP\n", uSel, Desc.Legacy.Gen.u2Dpl, IEM_GET_CPL(pVCpu)));
4606 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
4607 }
4608 }
4609 else
4610 {
4611 if ((Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
4612 {
4613 Log(("load sreg%u, %#x - execute only segment -> #GP\n", iSegReg, uSel));
4614 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
4615 }
4616 if ( (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
4617 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
4618 {
4619#if 0 /* this is what intel says. */
4620 if ( (uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl
4621 && IEM_GET_CPL(pVCpu) > Desc.Legacy.Gen.u2Dpl)
4622 {
4623 Log(("load sreg%u, %#x - both RPL (%d) and CPL (%d) are greater than DPL (%d) -> #GP\n",
4624 iSegReg, uSel, (uSel & X86_SEL_RPL), IEM_GET_CPL(pVCpu), Desc.Legacy.Gen.u2Dpl));
4625 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
4626 }
4627#else /* this is what makes more sense. */
4628 if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
4629 {
4630 Log(("load sreg%u, %#x - RPL (%d) is greater than DPL (%d) -> #GP\n",
4631 iSegReg, uSel, (uSel & X86_SEL_RPL), Desc.Legacy.Gen.u2Dpl));
4632 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
4633 }
4634 if (IEM_GET_CPL(pVCpu) > Desc.Legacy.Gen.u2Dpl)
4635 {
4636 Log(("load sreg%u, %#x - CPL (%d) is greater than DPL (%d) -> #GP\n",
4637 iSegReg, uSel, IEM_GET_CPL(pVCpu), Desc.Legacy.Gen.u2Dpl));
4638 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
4639 }
4640#endif
4641 }
4642 }
4643
4644 /* Is it there? */
4645 if (!Desc.Legacy.Gen.u1Present)
4646 {
4647 Log(("load sreg%d,%#x - segment not present -> #NP\n", iSegReg, uSel));
4648 return iemRaiseSelectorNotPresentBySelector(pVCpu, uSel);
4649 }
4650
4651 /* The base and limit. */
4652 uint32_t cbLimit = X86DESC_LIMIT_G(&Desc.Legacy);
4653 uint64_t u64Base = X86DESC_BASE(&Desc.Legacy);
4654
4655 /*
4656 * Ok, everything checked out fine. Now set the accessed bit before
4657 * committing the result into the registers.
4658 */
4659 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
4660 {
4661 rcStrict = iemMemMarkSelDescAccessed(pVCpu, uSel);
4662 if (rcStrict != VINF_SUCCESS)
4663 return rcStrict;
4664 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
4665 }
4666
4667 /* commit */
4668 *pSel = uSel;
4669 pHid->Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
4670 pHid->u32Limit = cbLimit;
4671 pHid->u64Base = u64Base;
4672 pHid->ValidSel = uSel;
4673 pHid->fFlags = CPUMSELREG_FLAGS_VALID;
4674
4675 /** @todo check if the hidden bits are loaded correctly for 64-bit
4676 * mode. */
4677
4678 /* This will affect the FLAT 32-bit mode flag: */
4679 if ( iSegReg < X86_SREG_FS
4680 && IEM_IS_32BIT_CODE(pVCpu))
4681 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK)
4682 | iemCalc32BitFlatIndicator(pVCpu);
4683 }
4684
4685 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pHid));
4686 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_HIDDEN_SEL_REGS);
4687 return VINF_SUCCESS;
4688}
4689
4690
4691/**
4692 * Implements 'mov SReg, r/m'.
4693 *
4694 * @param iSegReg The segment register number (valid).
4695 * @param uSel The new selector value.
4696 */
4697IEM_CIMPL_DEF_2(iemCImpl_load_SReg, uint8_t, iSegReg, uint16_t, uSel)
4698{
4699 VBOXSTRICTRC rcStrict = iemCImpl_LoadSRegWorker(pVCpu, iSegReg, uSel);
4700 if (rcStrict == VINF_SUCCESS)
4701 rcStrict = iemCImpl_LoadSRegFinish(pVCpu, cbInstr, iSegReg);
4702 return rcStrict;
4703}
4704
4705
4706/**
4707 * Implements 'pop SReg'.
4708 *
4709 * @param iSegReg The segment register number (valid).
4710 * @param enmEffOpSize The efficient operand size (valid).
4711 */
4712IEM_CIMPL_DEF_2(iemCImpl_pop_Sreg, uint8_t, iSegReg, IEMMODE, enmEffOpSize)
4713{
4714 VBOXSTRICTRC rcStrict;
4715
4716 /*
4717 * Read the selector off the stack and join paths with mov ss, reg.
4718 */
4719 RTUINT64U TmpRsp;
4720 TmpRsp.u = pVCpu->cpum.GstCtx.rsp;
4721 switch (enmEffOpSize)
4722 {
4723 case IEMMODE_16BIT:
4724 {
4725 uint16_t uSel;
4726 rcStrict = iemMemStackPopU16Ex(pVCpu, &uSel, &TmpRsp);
4727 if (rcStrict == VINF_SUCCESS)
4728 rcStrict = iemCImpl_LoadSRegWorker(pVCpu, iSegReg, uSel);
4729 break;
4730 }
4731
4732 case IEMMODE_32BIT:
4733 {
4734 /* Modern Intel CPU only does a WORD sized access here, both as
4735 segmentation and paging is concerned. So, we have to emulate
4736 this to make bs3-cpu-weird-1 happy. */
4737 if (IEM_IS_GUEST_CPU_INTEL(pVCpu))
4738 {
4739 /* We don't have flexible enough stack primitives here, so just
4740 do a word pop and add two bytes to SP/RSP on success. */
4741 uint16_t uSel;
4742 rcStrict = iemMemStackPopU16Ex(pVCpu, &uSel, &TmpRsp);
4743 if (rcStrict == VINF_SUCCESS)
4744 {
4745 iemRegAddToRspEx(pVCpu, &TmpRsp, sizeof(uint32_t) - sizeof(uint16_t));
4746 rcStrict = iemCImpl_LoadSRegWorker(pVCpu, iSegReg, uSel);
4747 }
4748 }
4749 else
4750 {
4751 uint32_t u32Value;
4752 rcStrict = iemMemStackPopU32Ex(pVCpu, &u32Value, &TmpRsp);
4753 if (rcStrict == VINF_SUCCESS)
4754 rcStrict = iemCImpl_LoadSRegWorker(pVCpu, iSegReg, (uint16_t)u32Value);
4755 }
4756 break;
4757 }
4758
4759 case IEMMODE_64BIT:
4760 {
4761 /* Like for the 32-bit case above, intel only does a WORD access. */
4762 if (IEM_IS_GUEST_CPU_INTEL(pVCpu))
4763 {
4764 uint16_t uSel;
4765 rcStrict = iemMemStackPopU16Ex(pVCpu, &uSel, &TmpRsp);
4766 if (rcStrict == VINF_SUCCESS)
4767 {
4768 iemRegAddToRspEx(pVCpu, &TmpRsp, sizeof(uint64_t) - sizeof(uint16_t));
4769 rcStrict = iemCImpl_LoadSRegWorker(pVCpu, iSegReg, uSel);
4770 }
4771 }
4772 else
4773 {
4774 uint64_t u64Value;
4775 rcStrict = iemMemStackPopU64Ex(pVCpu, &u64Value, &TmpRsp);
4776 if (rcStrict == VINF_SUCCESS)
4777 rcStrict = iemCImpl_LoadSRegWorker(pVCpu, iSegReg, (uint16_t)u64Value);
4778 }
4779 break;
4780 }
4781 IEM_NOT_REACHED_DEFAULT_CASE_RET();
4782 }
4783
4784 /*
4785 * If the load succeeded, commit the stack change and finish the instruction.
4786 */
4787 if (rcStrict == VINF_SUCCESS)
4788 {
4789 pVCpu->cpum.GstCtx.rsp = TmpRsp.u;
4790 rcStrict = iemCImpl_LoadSRegFinish(pVCpu, cbInstr, iSegReg);
4791 }
4792
4793 return rcStrict;
4794}
4795
4796
4797/**
4798 * Implements lgs, lfs, les, lds & lss.
4799 */
4800IEM_CIMPL_DEF_5(iemCImpl_load_SReg_Greg, uint16_t, uSel, uint64_t, offSeg, uint8_t, iSegReg, uint8_t, iGReg, IEMMODE, enmEffOpSize)
4801{
4802 /*
4803 * Use iemCImpl_LoadSRegWorker to do the tricky segment register loading.
4804 */
4805 /** @todo verify and test that mov, pop and lXs works the segment
4806 * register loading in the exact same way. */
4807 VBOXSTRICTRC rcStrict = iemCImpl_LoadSRegWorker(pVCpu, iSegReg, uSel);
4808 if (rcStrict == VINF_SUCCESS)
4809 {
4810 switch (enmEffOpSize)
4811 {
4812 case IEMMODE_16BIT:
4813 iemGRegStoreU16(pVCpu, iGReg, offSeg);
4814 break;
4815 case IEMMODE_32BIT:
4816 case IEMMODE_64BIT:
4817 iemGRegStoreU64(pVCpu, iGReg, offSeg);
4818 break;
4819 IEM_NOT_REACHED_DEFAULT_CASE_RET();
4820 }
4821 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
4822 }
4823 return rcStrict;
4824}
4825
4826
4827/**
4828 * Helper for VERR, VERW, LAR, and LSL and loads the descriptor into memory.
4829 *
4830 * @retval VINF_SUCCESS on success.
4831 * @retval VINF_IEM_SELECTOR_NOT_OK if the selector isn't ok.
4832 * @retval iemMemFetchSysU64 return value.
4833 *
4834 * @param pVCpu The cross context virtual CPU structure of the calling thread.
4835 * @param uSel The selector value.
4836 * @param fAllowSysDesc Whether system descriptors are OK or not.
4837 * @param pDesc Where to return the descriptor on success.
4838 */
4839static VBOXSTRICTRC iemCImpl_LoadDescHelper(PVMCPUCC pVCpu, uint16_t uSel, bool fAllowSysDesc, PIEMSELDESC pDesc)
4840{
4841 pDesc->Long.au64[0] = 0;
4842 pDesc->Long.au64[1] = 0;
4843
4844 if (!(uSel & X86_SEL_MASK_OFF_RPL)) /** @todo test this on 64-bit. */
4845 return VINF_IEM_SELECTOR_NOT_OK;
4846
4847 /* Within the table limits? */
4848 RTGCPTR GCPtrBase;
4849 if (uSel & X86_SEL_LDT)
4850 {
4851 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_LDTR);
4852 if ( !pVCpu->cpum.GstCtx.ldtr.Attr.n.u1Present
4853 || (uSel | X86_SEL_RPL_LDT) > pVCpu->cpum.GstCtx.ldtr.u32Limit )
4854 return VINF_IEM_SELECTOR_NOT_OK;
4855 GCPtrBase = pVCpu->cpum.GstCtx.ldtr.u64Base;
4856 }
4857 else
4858 {
4859 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_GDTR);
4860 if ((uSel | X86_SEL_RPL_LDT) > pVCpu->cpum.GstCtx.gdtr.cbGdt)
4861 return VINF_IEM_SELECTOR_NOT_OK;
4862 GCPtrBase = pVCpu->cpum.GstCtx.gdtr.pGdt;
4863 }
4864
4865 /* Fetch the descriptor. */
4866 VBOXSTRICTRC rcStrict = iemMemFetchSysU64(pVCpu, &pDesc->Legacy.u, UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK));
4867 if (rcStrict != VINF_SUCCESS)
4868 return rcStrict;
4869 if (!pDesc->Legacy.Gen.u1DescType)
4870 {
4871 if (!fAllowSysDesc)
4872 return VINF_IEM_SELECTOR_NOT_OK;
4873 if (CPUMIsGuestInLongModeEx(IEM_GET_CTX(pVCpu)))
4874 {
4875 rcStrict = iemMemFetchSysU64(pVCpu, &pDesc->Long.au64[1], UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK) + 8);
4876 if (rcStrict != VINF_SUCCESS)
4877 return rcStrict;
4878 }
4879
4880 }
4881
4882 return VINF_SUCCESS;
4883}
4884
4885
4886/**
4887 * Implements verr (fWrite = false) and verw (fWrite = true).
4888 */
4889IEM_CIMPL_DEF_2(iemCImpl_VerX, uint16_t, uSel, bool, fWrite)
4890{
4891 Assert(!IEM_IS_REAL_OR_V86_MODE(pVCpu));
4892
4893 /** @todo figure whether the accessed bit is set or not. */
4894
4895 bool fAccessible = true;
4896 IEMSELDESC Desc;
4897 VBOXSTRICTRC rcStrict = iemCImpl_LoadDescHelper(pVCpu, uSel, false /*fAllowSysDesc*/, &Desc);
4898 if (rcStrict == VINF_SUCCESS)
4899 {
4900 /* Check the descriptor, order doesn't matter much here. */
4901 if ( !Desc.Legacy.Gen.u1DescType
4902 || !Desc.Legacy.Gen.u1Present)
4903 fAccessible = false;
4904 else
4905 {
4906 if ( fWrite
4907 ? (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE)) != X86_SEL_TYPE_WRITE
4908 : (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
4909 fAccessible = false;
4910
4911 /** @todo testcase for the conforming behavior. */
4912 if ( (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
4913 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
4914 {
4915 if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
4916 fAccessible = false;
4917 else if (IEM_GET_CPL(pVCpu) > Desc.Legacy.Gen.u2Dpl)
4918 fAccessible = false;
4919 }
4920 }
4921
4922 }
4923 else if (rcStrict == VINF_IEM_SELECTOR_NOT_OK)
4924 fAccessible = false;
4925 else
4926 return rcStrict;
4927
4928 /* commit */
4929 pVCpu->cpum.GstCtx.eflags.Bits.u1ZF = fAccessible;
4930
4931 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
4932}
4933
4934
4935/**
4936 * Implements LAR and LSL with 64-bit operand size.
4937 *
4938 * @returns VINF_SUCCESS.
4939 * @param pu64Dst Pointer to the destination register.
4940 * @param uSel The selector to load details for.
4941 * @param fIsLar true = LAR, false = LSL.
4942 */
4943IEM_CIMPL_DEF_3(iemCImpl_LarLsl_u64, uint64_t *, pu64Dst, uint16_t, uSel, bool, fIsLar)
4944{
4945 Assert(!IEM_IS_REAL_OR_V86_MODE(pVCpu));
4946
4947 /** @todo figure whether the accessed bit is set or not. */
4948
4949 bool fDescOk = true;
4950 IEMSELDESC Desc;
4951 VBOXSTRICTRC rcStrict = iemCImpl_LoadDescHelper(pVCpu, uSel, true /*fAllowSysDesc*/, &Desc);
4952 if (rcStrict == VINF_SUCCESS)
4953 {
4954 /*
4955 * Check the descriptor type.
4956 */
4957 if (!Desc.Legacy.Gen.u1DescType)
4958 {
4959 if (CPUMIsGuestInLongModeEx(IEM_GET_CTX(pVCpu)))
4960 {
4961 if (Desc.Long.Gen.u5Zeros)
4962 fDescOk = false;
4963 else
4964 switch (Desc.Long.Gen.u4Type)
4965 {
4966 /** @todo Intel lists 0 as valid for LSL, verify whether that's correct */
4967 case AMD64_SEL_TYPE_SYS_TSS_AVAIL:
4968 case AMD64_SEL_TYPE_SYS_TSS_BUSY:
4969 case AMD64_SEL_TYPE_SYS_LDT: /** @todo Intel lists this as invalid for LAR, AMD and 32-bit does otherwise. */
4970 break;
4971 case AMD64_SEL_TYPE_SYS_CALL_GATE:
4972 fDescOk = fIsLar;
4973 break;
4974 default:
4975 fDescOk = false;
4976 break;
4977 }
4978 }
4979 else
4980 {
4981 switch (Desc.Long.Gen.u4Type)
4982 {
4983 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
4984 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
4985 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
4986 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
4987 case X86_SEL_TYPE_SYS_LDT:
4988 break;
4989 case X86_SEL_TYPE_SYS_286_CALL_GATE:
4990 case X86_SEL_TYPE_SYS_TASK_GATE:
4991 case X86_SEL_TYPE_SYS_386_CALL_GATE:
4992 fDescOk = fIsLar;
4993 break;
4994 default:
4995 fDescOk = false;
4996 break;
4997 }
4998 }
4999 }
5000 if (fDescOk)
5001 {
5002 /*
5003 * Check the RPL/DPL/CPL interaction..
5004 */
5005 /** @todo testcase for the conforming behavior. */
5006 if ( (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF)) != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF)
5007 || !Desc.Legacy.Gen.u1DescType)
5008 {
5009 if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
5010 fDescOk = false;
5011 else if (IEM_GET_CPL(pVCpu) > Desc.Legacy.Gen.u2Dpl)
5012 fDescOk = false;
5013 }
5014 }
5015
5016 if (fDescOk)
5017 {
5018 /*
5019 * All fine, start committing the result.
5020 */
5021 if (fIsLar)
5022 *pu64Dst = Desc.Legacy.au32[1] & UINT32_C(0x00ffff00);
5023 else
5024 *pu64Dst = X86DESC_LIMIT_G(&Desc.Legacy);
5025 }
5026
5027 }
5028 else if (rcStrict == VINF_IEM_SELECTOR_NOT_OK)
5029 fDescOk = false;
5030 else
5031 return rcStrict;
5032
5033 /* commit flags value and advance rip. */
5034 pVCpu->cpum.GstCtx.eflags.Bits.u1ZF = fDescOk;
5035 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5036}
5037
5038
5039/**
5040 * Implements LAR and LSL with 16-bit operand size.
5041 *
5042 * @returns VINF_SUCCESS.
5043 * @param pu16Dst Pointer to the destination register.
5044 * @param uSel The selector to load details for.
5045 * @param fIsLar true = LAR, false = LSL.
5046 */
5047IEM_CIMPL_DEF_3(iemCImpl_LarLsl_u16, uint16_t *, pu16Dst, uint16_t, uSel, bool, fIsLar)
5048{
5049 uint64_t u64TmpDst = *pu16Dst;
5050 IEM_CIMPL_CALL_3(iemCImpl_LarLsl_u64, &u64TmpDst, uSel, fIsLar);
5051 *pu16Dst = u64TmpDst;
5052 return VINF_SUCCESS;
5053}
5054
5055
5056/**
5057 * Implements lgdt.
5058 *
5059 * @param iEffSeg The segment of the new gdtr contents
5060 * @param GCPtrEffSrc The address of the new gdtr contents.
5061 * @param enmEffOpSize The effective operand size.
5062 */
5063IEM_CIMPL_DEF_3(iemCImpl_lgdt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc, IEMMODE, enmEffOpSize)
5064{
5065 if (IEM_GET_CPL(pVCpu) != 0)
5066 return iemRaiseGeneralProtectionFault0(pVCpu);
5067 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
5068
5069 if (!IEM_IS_IN_GUEST(pVCpu))
5070 { /* probable */ }
5071 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
5072 && IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_DESC_TABLE_EXIT))
5073 {
5074 Log(("lgdt: Guest intercept -> VM-exit\n"));
5075 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_GDTR_IDTR_ACCESS, VMXINSTRID_LGDT, cbInstr);
5076 }
5077 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_GDTR_WRITES))
5078 {
5079 Log(("lgdt: Guest intercept -> #VMEXIT\n"));
5080 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
5081 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_GDTR_WRITE, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
5082 }
5083
5084 /*
5085 * Fetch the limit and base address.
5086 */
5087 uint16_t cbLimit;
5088 RTGCPTR GCPtrBase;
5089 VBOXSTRICTRC rcStrict = iemMemFetchDataXdtr(pVCpu, &cbLimit, &GCPtrBase, iEffSeg, GCPtrEffSrc, enmEffOpSize);
5090 if (rcStrict == VINF_SUCCESS)
5091 {
5092 if ( !IEM_IS_64BIT_CODE(pVCpu)
5093 || X86_IS_CANONICAL(GCPtrBase))
5094 {
5095 rcStrict = CPUMSetGuestGDTR(pVCpu, GCPtrBase, cbLimit);
5096 if (rcStrict == VINF_SUCCESS)
5097 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5098 }
5099 else
5100 {
5101 Log(("iemCImpl_lgdt: Non-canonical base %04x:%RGv\n", cbLimit, GCPtrBase));
5102 return iemRaiseGeneralProtectionFault0(pVCpu);
5103 }
5104 }
5105 return rcStrict;
5106}
5107
5108
5109/**
5110 * Implements sgdt.
5111 *
5112 * @param iEffSeg The segment where to store the gdtr content.
5113 * @param GCPtrEffDst The address where to store the gdtr content.
5114 */
5115IEM_CIMPL_DEF_2(iemCImpl_sgdt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
5116{
5117 /*
5118 * Join paths with sidt.
5119 * Note! No CPL or V8086 checks here, it's a really sad story, ask Intel if
5120 * you really must know.
5121 */
5122 if (!IEM_IS_IN_GUEST(pVCpu))
5123 { /* probable */ }
5124 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
5125 && IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_DESC_TABLE_EXIT))
5126 {
5127 Log(("sgdt: Guest intercept -> VM-exit\n"));
5128 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_GDTR_IDTR_ACCESS, VMXINSTRID_SGDT, cbInstr);
5129 }
5130 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_GDTR_READS))
5131 {
5132 Log(("sgdt: Guest intercept -> #VMEXIT\n"));
5133 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
5134 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_GDTR_READ, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
5135 }
5136
5137 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_GDTR);
5138 VBOXSTRICTRC rcStrict = iemMemStoreDataXdtr(pVCpu, pVCpu->cpum.GstCtx.gdtr.cbGdt, pVCpu->cpum.GstCtx.gdtr.pGdt, iEffSeg, GCPtrEffDst);
5139 if (rcStrict == VINF_SUCCESS)
5140 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5141 return rcStrict;
5142}
5143
5144
5145/**
5146 * Implements lidt.
5147 *
5148 * @param iEffSeg The segment of the new idtr contents
5149 * @param GCPtrEffSrc The address of the new idtr contents.
5150 * @param enmEffOpSize The effective operand size.
5151 */
5152IEM_CIMPL_DEF_3(iemCImpl_lidt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc, IEMMODE, enmEffOpSize)
5153{
5154 if (IEM_GET_CPL(pVCpu) != 0)
5155 return iemRaiseGeneralProtectionFault0(pVCpu);
5156 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
5157
5158 if (!IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_IDTR_WRITES))
5159 { /* probable */ }
5160 else
5161 {
5162 Log(("lidt: Guest intercept -> #VMEXIT\n"));
5163 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
5164 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_IDTR_WRITE, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
5165 }
5166
5167 /*
5168 * Fetch the limit and base address.
5169 */
5170 uint16_t cbLimit;
5171 RTGCPTR GCPtrBase;
5172 VBOXSTRICTRC rcStrict = iemMemFetchDataXdtr(pVCpu, &cbLimit, &GCPtrBase, iEffSeg, GCPtrEffSrc, enmEffOpSize);
5173 if (rcStrict == VINF_SUCCESS)
5174 {
5175 if ( !IEM_IS_64BIT_CODE(pVCpu)
5176 || X86_IS_CANONICAL(GCPtrBase))
5177 {
5178 CPUMSetGuestIDTR(pVCpu, GCPtrBase, cbLimit);
5179 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5180 }
5181 else
5182 {
5183 Log(("iemCImpl_lidt: Non-canonical base %04x:%RGv\n", cbLimit, GCPtrBase));
5184 return iemRaiseGeneralProtectionFault0(pVCpu);
5185 }
5186 }
5187 return rcStrict;
5188}
5189
5190
5191/**
5192 * Implements sidt.
5193 *
5194 * @param iEffSeg The segment where to store the idtr content.
5195 * @param GCPtrEffDst The address where to store the idtr content.
5196 */
5197IEM_CIMPL_DEF_2(iemCImpl_sidt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
5198{
5199 /*
5200 * Join paths with sgdt.
5201 * Note! No CPL or V8086 checks here, it's a really sad story, ask Intel if
5202 * you really must know.
5203 */
5204 if (!IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_IDTR_READS))
5205 { /* probable */ }
5206 else
5207 {
5208 Log(("sidt: Guest intercept -> #VMEXIT\n"));
5209 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
5210 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_IDTR_READ, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
5211 }
5212
5213 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_IDTR);
5214 VBOXSTRICTRC rcStrict = iemMemStoreDataXdtr(pVCpu, pVCpu->cpum.GstCtx.idtr.cbIdt, pVCpu->cpum.GstCtx.idtr.pIdt, iEffSeg, GCPtrEffDst);
5215 if (rcStrict == VINF_SUCCESS)
5216 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5217 return rcStrict;
5218}
5219
5220
5221/**
5222 * Implements lldt.
5223 *
5224 * @param uNewLdt The new LDT selector value.
5225 */
5226IEM_CIMPL_DEF_1(iemCImpl_lldt, uint16_t, uNewLdt)
5227{
5228 /*
5229 * Check preconditions.
5230 */
5231 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
5232 {
5233 Log(("lldt %04x - real or v8086 mode -> #GP(0)\n", uNewLdt));
5234 return iemRaiseUndefinedOpcode(pVCpu);
5235 }
5236 if (IEM_GET_CPL(pVCpu) != 0)
5237 {
5238 Log(("lldt %04x - CPL is %d -> #GP(0)\n", uNewLdt, IEM_GET_CPL(pVCpu)));
5239 return iemRaiseGeneralProtectionFault0(pVCpu);
5240 }
5241
5242 /* Nested-guest VMX intercept (SVM is after all checks). */
5243 /** @todo testcase: exit vs check order. */
5244 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
5245 || !IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_DESC_TABLE_EXIT))
5246 { /* probable */ }
5247 else
5248 {
5249 Log(("lldt: Guest intercept -> VM-exit\n"));
5250 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_LDTR_TR_ACCESS, VMXINSTRID_LLDT, cbInstr);
5251 }
5252
5253 if (uNewLdt & X86_SEL_LDT)
5254 {
5255 Log(("lldt %04x - LDT selector -> #GP\n", uNewLdt));
5256 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewLdt);
5257 }
5258
5259 /*
5260 * Now, loading a NULL selector is easy.
5261 */
5262 if (!(uNewLdt & X86_SEL_MASK_OFF_RPL))
5263 {
5264 /* Nested-guest SVM intercept. */
5265 if (!IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_LDTR_WRITES))
5266 { /* probable */ }
5267 else
5268 {
5269 Log(("lldt: Guest intercept -> #VMEXIT\n"));
5270 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
5271 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_LDTR_WRITE, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
5272 }
5273
5274 Log(("lldt %04x: Loading NULL selector.\n", uNewLdt));
5275 pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_LDTR;
5276 CPUMSetGuestLDTR(pVCpu, uNewLdt);
5277 pVCpu->cpum.GstCtx.ldtr.ValidSel = uNewLdt;
5278 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
5279 if (IEM_IS_GUEST_CPU_AMD(pVCpu))
5280 {
5281 /* AMD-V seems to leave the base and limit alone. */
5282 pVCpu->cpum.GstCtx.ldtr.Attr.u = X86DESCATTR_UNUSABLE;
5283 }
5284 else
5285 {
5286 /* VT-x (Intel 3960x) seems to be doing the following. */
5287 pVCpu->cpum.GstCtx.ldtr.Attr.u = X86DESCATTR_UNUSABLE | X86DESCATTR_G | X86DESCATTR_D;
5288 pVCpu->cpum.GstCtx.ldtr.u64Base = 0;
5289 pVCpu->cpum.GstCtx.ldtr.u32Limit = UINT32_MAX;
5290 }
5291
5292 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5293 }
5294
5295 /*
5296 * Read the descriptor.
5297 */
5298 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_LDTR | CPUMCTX_EXTRN_GDTR);
5299 IEMSELDESC Desc;
5300 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pVCpu, &Desc, uNewLdt, X86_XCPT_GP); /** @todo Correct exception? */
5301 if (rcStrict != VINF_SUCCESS)
5302 return rcStrict;
5303
5304 /* Check GPs first. */
5305 if (Desc.Legacy.Gen.u1DescType)
5306 {
5307 Log(("lldt %#x - not system selector (type %x) -> #GP\n", uNewLdt, Desc.Legacy.Gen.u4Type));
5308 return iemRaiseGeneralProtectionFault(pVCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
5309 }
5310 if (Desc.Legacy.Gen.u4Type != X86_SEL_TYPE_SYS_LDT)
5311 {
5312 Log(("lldt %#x - not LDT selector (type %x) -> #GP\n", uNewLdt, Desc.Legacy.Gen.u4Type));
5313 return iemRaiseGeneralProtectionFault(pVCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
5314 }
5315 uint64_t u64Base;
5316 if (!IEM_IS_LONG_MODE(pVCpu))
5317 u64Base = X86DESC_BASE(&Desc.Legacy);
5318 else
5319 {
5320 if (Desc.Long.Gen.u5Zeros)
5321 {
5322 Log(("lldt %#x - u5Zeros=%#x -> #GP\n", uNewLdt, Desc.Long.Gen.u5Zeros));
5323 return iemRaiseGeneralProtectionFault(pVCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
5324 }
5325
5326 u64Base = X86DESC64_BASE(&Desc.Long);
5327 if (!IEM_IS_CANONICAL(u64Base))
5328 {
5329 Log(("lldt %#x - non-canonical base address %#llx -> #GP\n", uNewLdt, u64Base));
5330 return iemRaiseGeneralProtectionFault(pVCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
5331 }
5332 }
5333
5334 /* NP */
5335 if (!Desc.Legacy.Gen.u1Present)
5336 {
5337 Log(("lldt %#x - segment not present -> #NP\n", uNewLdt));
5338 return iemRaiseSelectorNotPresentBySelector(pVCpu, uNewLdt);
5339 }
5340
5341 /* Nested-guest SVM intercept. */
5342 if (!IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_LDTR_WRITES))
5343 { /* probable */ }
5344 else
5345 {
5346 Log(("lldt: Guest intercept -> #VMEXIT\n"));
5347 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
5348 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_LDTR_WRITE, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
5349 }
5350
5351 /*
5352 * It checks out alright, update the registers.
5353 */
5354/** @todo check if the actual value is loaded or if the RPL is dropped */
5355 CPUMSetGuestLDTR(pVCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
5356 pVCpu->cpum.GstCtx.ldtr.ValidSel = uNewLdt & X86_SEL_MASK_OFF_RPL;
5357 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
5358 pVCpu->cpum.GstCtx.ldtr.Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
5359 pVCpu->cpum.GstCtx.ldtr.u32Limit = X86DESC_LIMIT_G(&Desc.Legacy);
5360 pVCpu->cpum.GstCtx.ldtr.u64Base = u64Base;
5361
5362 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5363}
5364
5365
5366/**
5367 * Implements sldt GReg
5368 *
5369 * @param iGReg The general register to store the CRx value in.
5370 * @param enmEffOpSize The operand size.
5371 */
5372IEM_CIMPL_DEF_2(iemCImpl_sldt_reg, uint8_t, iGReg, uint8_t, enmEffOpSize)
5373{
5374 if (!IEM_IS_IN_GUEST(pVCpu))
5375 { /* probable */ }
5376 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
5377 && IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_DESC_TABLE_EXIT))
5378 {
5379 Log(("sldt: Guest intercept -> VM-exit\n"));
5380 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_LDTR_TR_ACCESS, VMXINSTRID_SLDT, cbInstr);
5381 }
5382 else
5383 IEM_SVM_CHECK_INSTR_INTERCEPT(pVCpu, SVM_CTRL_INTERCEPT_LDTR_READS, SVM_EXIT_LDTR_READ, 0, 0, cbInstr);
5384
5385 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_LDTR);
5386 switch (enmEffOpSize)
5387 {
5388 case IEMMODE_16BIT:
5389 iemGRegStoreU16(pVCpu, iGReg, pVCpu->cpum.GstCtx.ldtr.Sel);
5390 break;
5391 case IEMMODE_32BIT:
5392 case IEMMODE_64BIT:
5393 iemGRegStoreU64(pVCpu, iGReg, pVCpu->cpum.GstCtx.ldtr.Sel);
5394 break;
5395 IEM_NOT_REACHED_DEFAULT_CASE_RET();
5396 }
5397 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5398}
5399
5400
5401/**
5402 * Implements sldt mem.
5403 *
5404 * @param iEffSeg The effective segment register to use with @a GCPtrMem.
5405 * @param GCPtrEffDst Where to store the 16-bit CR0 value.
5406 */
5407IEM_CIMPL_DEF_2(iemCImpl_sldt_mem, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
5408{
5409 IEM_SVM_CHECK_INSTR_INTERCEPT(pVCpu, SVM_CTRL_INTERCEPT_LDTR_READS, SVM_EXIT_LDTR_READ, 0, 0, cbInstr);
5410
5411 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_LDTR);
5412 VBOXSTRICTRC rcStrict = iemMemStoreDataU16(pVCpu, iEffSeg, GCPtrEffDst, pVCpu->cpum.GstCtx.ldtr.Sel);
5413 if (rcStrict == VINF_SUCCESS)
5414 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5415 return rcStrict;
5416}
5417
5418
5419/**
5420 * Implements ltr.
5421 *
5422 * @param uNewTr The new TSS selector value.
5423 */
5424IEM_CIMPL_DEF_1(iemCImpl_ltr, uint16_t, uNewTr)
5425{
5426 /*
5427 * Check preconditions.
5428 */
5429 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
5430 {
5431 Log(("ltr %04x - real or v8086 mode -> #GP(0)\n", uNewTr));
5432 return iemRaiseUndefinedOpcode(pVCpu);
5433 }
5434 if (IEM_GET_CPL(pVCpu) != 0)
5435 {
5436 Log(("ltr %04x - CPL is %d -> #GP(0)\n", uNewTr, IEM_GET_CPL(pVCpu)));
5437 return iemRaiseGeneralProtectionFault0(pVCpu);
5438 }
5439 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
5440 || !IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_DESC_TABLE_EXIT))
5441 { /* probable */ }
5442 else
5443 {
5444 Log(("ltr: Guest intercept -> VM-exit\n"));
5445 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_LDTR_TR_ACCESS, VMXINSTRID_LTR, cbInstr);
5446 }
5447 if (uNewTr & X86_SEL_LDT)
5448 {
5449 Log(("ltr %04x - LDT selector -> #GP\n", uNewTr));
5450 return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uNewTr);
5451 }
5452 if (!(uNewTr & X86_SEL_MASK_OFF_RPL))
5453 {
5454 Log(("ltr %04x - NULL selector -> #GP(0)\n", uNewTr));
5455 return iemRaiseGeneralProtectionFault0(pVCpu);
5456 }
5457 if (!IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_TR_WRITES))
5458 { /* probable */ }
5459 else
5460 {
5461 Log(("ltr: Guest intercept -> #VMEXIT\n"));
5462 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
5463 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_TR_WRITE, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
5464 }
5465
5466 /*
5467 * Read the descriptor.
5468 */
5469 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_LDTR | CPUMCTX_EXTRN_GDTR | CPUMCTX_EXTRN_TR);
5470 IEMSELDESC Desc;
5471 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pVCpu, &Desc, uNewTr, X86_XCPT_GP); /** @todo Correct exception? */
5472 if (rcStrict != VINF_SUCCESS)
5473 return rcStrict;
5474
5475 /* Check GPs first. */
5476 if (Desc.Legacy.Gen.u1DescType)
5477 {
5478 Log(("ltr %#x - not system selector (type %x) -> #GP\n", uNewTr, Desc.Legacy.Gen.u4Type));
5479 return iemRaiseGeneralProtectionFault(pVCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
5480 }
5481 if ( Desc.Legacy.Gen.u4Type != X86_SEL_TYPE_SYS_386_TSS_AVAIL /* same as AMD64_SEL_TYPE_SYS_TSS_AVAIL */
5482 && ( Desc.Legacy.Gen.u4Type != X86_SEL_TYPE_SYS_286_TSS_AVAIL
5483 || IEM_IS_LONG_MODE(pVCpu)) )
5484 {
5485 Log(("ltr %#x - not an available TSS selector (type %x) -> #GP\n", uNewTr, Desc.Legacy.Gen.u4Type));
5486 return iemRaiseGeneralProtectionFault(pVCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
5487 }
5488 uint64_t u64Base;
5489 if (!IEM_IS_LONG_MODE(pVCpu))
5490 u64Base = X86DESC_BASE(&Desc.Legacy);
5491 else
5492 {
5493 if (Desc.Long.Gen.u5Zeros)
5494 {
5495 Log(("ltr %#x - u5Zeros=%#x -> #GP\n", uNewTr, Desc.Long.Gen.u5Zeros));
5496 return iemRaiseGeneralProtectionFault(pVCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
5497 }
5498
5499 u64Base = X86DESC64_BASE(&Desc.Long);
5500 if (!IEM_IS_CANONICAL(u64Base))
5501 {
5502 Log(("ltr %#x - non-canonical base address %#llx -> #GP\n", uNewTr, u64Base));
5503 return iemRaiseGeneralProtectionFault(pVCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
5504 }
5505 }
5506
5507 /* NP */
5508 if (!Desc.Legacy.Gen.u1Present)
5509 {
5510 Log(("ltr %#x - segment not present -> #NP\n", uNewTr));
5511 return iemRaiseSelectorNotPresentBySelector(pVCpu, uNewTr);
5512 }
5513
5514 /*
5515 * Set it busy.
5516 * Note! Intel says this should lock down the whole descriptor, but we'll
5517 * restrict our selves to 32-bit for now due to lack of inline
5518 * assembly and such.
5519 */
5520 uint8_t bUnmapInfo;
5521 void *pvDesc;
5522 rcStrict = iemMemMap(pVCpu, &pvDesc, &bUnmapInfo, 8, UINT8_MAX,
5523 pVCpu->cpum.GstCtx.gdtr.pGdt + (uNewTr & X86_SEL_MASK_OFF_RPL), IEM_ACCESS_DATA_RW, 0);
5524 if (rcStrict != VINF_SUCCESS)
5525 return rcStrict;
5526 switch ((uintptr_t)pvDesc & 3)
5527 {
5528 case 0: ASMAtomicBitSet(pvDesc, 40 + 1); break;
5529 case 1: ASMAtomicBitSet((uint8_t *)pvDesc + 3, 40 + 1 - 24); break;
5530 case 2: ASMAtomicBitSet((uint8_t *)pvDesc + 2, 40 + 1 - 16); break;
5531 case 3: ASMAtomicBitSet((uint8_t *)pvDesc + 1, 40 + 1 - 8); break;
5532 }
5533 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
5534 if (rcStrict != VINF_SUCCESS)
5535 return rcStrict;
5536 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_SYS_TSS_BUSY_MASK;
5537
5538 /*
5539 * It checks out alright, update the registers.
5540 */
5541/** @todo check if the actual value is loaded or if the RPL is dropped */
5542 CPUMSetGuestTR(pVCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
5543 pVCpu->cpum.GstCtx.tr.ValidSel = uNewTr & X86_SEL_MASK_OFF_RPL;
5544 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
5545 pVCpu->cpum.GstCtx.tr.Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
5546 pVCpu->cpum.GstCtx.tr.u32Limit = X86DESC_LIMIT_G(&Desc.Legacy);
5547 pVCpu->cpum.GstCtx.tr.u64Base = u64Base;
5548
5549 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5550}
5551
5552
5553/**
5554 * Implements str GReg
5555 *
5556 * @param iGReg The general register to store the CRx value in.
5557 * @param enmEffOpSize The operand size.
5558 */
5559IEM_CIMPL_DEF_2(iemCImpl_str_reg, uint8_t, iGReg, uint8_t, enmEffOpSize)
5560{
5561 if (!IEM_IS_IN_GUEST(pVCpu))
5562 { /* probable */ }
5563 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
5564 && IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_DESC_TABLE_EXIT))
5565 {
5566 Log(("str_reg: Guest intercept -> VM-exit\n"));
5567 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_LDTR_TR_ACCESS, VMXINSTRID_STR, cbInstr);
5568 }
5569 else
5570 IEM_SVM_CHECK_INSTR_INTERCEPT(pVCpu, SVM_CTRL_INTERCEPT_TR_READS, SVM_EXIT_TR_READ, 0, 0, cbInstr);
5571
5572 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_TR);
5573 switch (enmEffOpSize)
5574 {
5575 case IEMMODE_16BIT:
5576 iemGRegStoreU16(pVCpu, iGReg, pVCpu->cpum.GstCtx.tr.Sel);
5577 break;
5578 case IEMMODE_32BIT:
5579 case IEMMODE_64BIT:
5580 iemGRegStoreU64(pVCpu, iGReg, pVCpu->cpum.GstCtx.tr.Sel);
5581 break;
5582 IEM_NOT_REACHED_DEFAULT_CASE_RET();
5583 }
5584 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5585}
5586
5587
5588/**
5589 * Implements str mem.
5590 *
5591 * @param iEffSeg The effective segment register to use with @a GCPtrMem.
5592 * @param GCPtrEffDst Where to store the 16-bit CR0 value.
5593 */
5594IEM_CIMPL_DEF_2(iemCImpl_str_mem, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
5595{
5596 if (!IEM_IS_IN_GUEST(pVCpu))
5597 { /* probable */ }
5598 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
5599 && IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_DESC_TABLE_EXIT))
5600 {
5601 Log(("str_mem: Guest intercept -> VM-exit\n"));
5602 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_LDTR_TR_ACCESS, VMXINSTRID_STR, cbInstr);
5603 }
5604 else
5605 IEM_SVM_CHECK_INSTR_INTERCEPT(pVCpu, SVM_CTRL_INTERCEPT_TR_READS, SVM_EXIT_TR_READ, 0, 0, cbInstr);
5606
5607 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_TR);
5608 VBOXSTRICTRC rcStrict = iemMemStoreDataU16(pVCpu, iEffSeg, GCPtrEffDst, pVCpu->cpum.GstCtx.tr.Sel);
5609 if (rcStrict == VINF_SUCCESS)
5610 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5611 return rcStrict;
5612}
5613
5614
5615/**
5616 * Implements mov GReg,CRx.
5617 *
5618 * @param iGReg The general register to store the CRx value in.
5619 * @param iCrReg The CRx register to read (valid).
5620 */
5621IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Cd, uint8_t, iGReg, uint8_t, iCrReg)
5622{
5623 if (IEM_GET_CPL(pVCpu) != 0)
5624 return iemRaiseGeneralProtectionFault0(pVCpu);
5625 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
5626
5627 if (!IEM_SVM_IS_READ_CR_INTERCEPT_SET(pVCpu, iCrReg))
5628 { /* probable */ }
5629 else
5630 {
5631 Log(("iemCImpl_mov_Rd_Cd: Guest intercept CR%u -> #VMEXIT\n", iCrReg));
5632 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
5633 IEM_SVM_CRX_VMEXIT_RET(pVCpu, SVM_EXIT_READ_CR0 + iCrReg, IEMACCESSCRX_MOV_CRX, iGReg);
5634 }
5635
5636 /* Read it. */
5637 uint64_t crX;
5638 switch (iCrReg)
5639 {
5640 case 0:
5641 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5642 crX = pVCpu->cpum.GstCtx.cr0;
5643 if (IEM_GET_TARGET_CPU(pVCpu) <= IEMTARGETCPU_386)
5644 crX |= UINT32_C(0x7fffffe0); /* All reserved CR0 flags are set on a 386, just like MSW on 286. */
5645 break;
5646 case 2:
5647 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_CR2);
5648 crX = pVCpu->cpum.GstCtx.cr2;
5649 break;
5650 case 3:
5651 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
5652 crX = pVCpu->cpum.GstCtx.cr3;
5653 break;
5654 case 4:
5655 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
5656 crX = pVCpu->cpum.GstCtx.cr4;
5657 break;
5658 case 8:
5659 {
5660 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
5661 if (!IEM_IS_IN_GUEST(pVCpu))
5662 { /* probable */ }
5663#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5664 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
5665 {
5666 VBOXSTRICTRC rcStrict = iemVmxVmexitInstrMovFromCr8(pVCpu, iGReg, cbInstr);
5667 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
5668 return rcStrict;
5669
5670 /*
5671 * If the Mov-from-CR8 doesn't cause a VM-exit, bits 7:4 of the VTPR is copied
5672 * to bits 0:3 of the destination operand. Bits 63:4 of the destination operand
5673 * are cleared.
5674 *
5675 * See Intel Spec. 29.3 "Virtualizing CR8-based TPR Accesses"
5676 */
5677 if (IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_USE_TPR_SHADOW))
5678 {
5679 uint32_t const uTpr = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
5680 crX = (uTpr >> 4) & 0xf;
5681 break;
5682 }
5683 }
5684#endif
5685#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
5686 else if (pVCpu->iem.s.fExec & IEM_F_X86_CTX_SVM)
5687 {
5688 PCSVMVMCBCTRL pVmcbCtrl = &pVCpu->cpum.GstCtx.hwvirt.svm.Vmcb.ctrl;
5689 if (CPUMIsGuestSvmVirtIntrMasking(pVCpu, IEM_GET_CTX(pVCpu)))
5690 {
5691 crX = pVmcbCtrl->IntCtrl.n.u8VTPR & 0xf;
5692 break;
5693 }
5694 }
5695#endif
5696 uint8_t uTpr;
5697 int rc = APICGetTpr(pVCpu, &uTpr, NULL, NULL);
5698 if (RT_SUCCESS(rc))
5699 crX = uTpr >> 4;
5700 else
5701 crX = 0;
5702 break;
5703 }
5704 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
5705 }
5706
5707#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5708 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
5709 { /* probable */ }
5710 else
5711 switch (iCrReg)
5712 {
5713 /* CR0/CR4 reads are subject to masking when in VMX non-root mode. */
5714 case 0: crX = CPUMGetGuestVmxMaskedCr0(&pVCpu->cpum.GstCtx, pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64Cr0Mask.u); break;
5715 case 4: crX = CPUMGetGuestVmxMaskedCr4(&pVCpu->cpum.GstCtx, pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64Cr4Mask.u); break;
5716 case 3:
5717 {
5718 VBOXSTRICTRC rcStrict = iemVmxVmexitInstrMovFromCr3(pVCpu, iGReg, cbInstr);
5719 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
5720 return rcStrict;
5721 break;
5722 }
5723 }
5724#endif
5725
5726 /* Store it. */
5727 if (IEM_IS_64BIT_CODE(pVCpu))
5728 iemGRegStoreU64(pVCpu, iGReg, crX);
5729 else
5730 iemGRegStoreU64(pVCpu, iGReg, (uint32_t)crX);
5731
5732 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5733}
5734
5735
5736/**
5737 * Implements smsw GReg.
5738 *
5739 * @param iGReg The general register to store the CRx value in.
5740 * @param enmEffOpSize The operand size.
5741 */
5742IEM_CIMPL_DEF_2(iemCImpl_smsw_reg, uint8_t, iGReg, uint8_t, enmEffOpSize)
5743{
5744 IEM_SVM_CHECK_READ_CR0_INTERCEPT(pVCpu, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */, cbInstr);
5745
5746#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5747 uint64_t u64MaskedCr0;
5748 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
5749 u64MaskedCr0 = pVCpu->cpum.GstCtx.cr0;
5750 else
5751 u64MaskedCr0 = CPUMGetGuestVmxMaskedCr0(&pVCpu->cpum.GstCtx, pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64Cr0Mask.u);
5752 uint64_t const u64GuestCr0 = u64MaskedCr0;
5753#else
5754 uint64_t const u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5755#endif
5756
5757 switch (enmEffOpSize)
5758 {
5759 case IEMMODE_16BIT:
5760 if (IEM_GET_TARGET_CPU(pVCpu) > IEMTARGETCPU_386)
5761 iemGRegStoreU16(pVCpu, iGReg, (uint16_t)u64GuestCr0);
5762 /* Unused bits are set on 386 and older CPU: */
5763 else if (IEM_GET_TARGET_CPU(pVCpu) >= IEMTARGETCPU_386)
5764 iemGRegStoreU16(pVCpu, iGReg, (uint16_t)u64GuestCr0 | 0xffe0);
5765 else
5766 iemGRegStoreU16(pVCpu, iGReg, (uint16_t)u64GuestCr0 | 0xfff0);
5767 break;
5768
5769/** @todo testcase for bits 31:16. We're not doing that correctly. */
5770
5771 case IEMMODE_32BIT:
5772 if (IEM_GET_TARGET_CPU(pVCpu) >= IEMTARGETCPU_386)
5773 iemGRegStoreU32(pVCpu, iGReg, (uint32_t)u64GuestCr0);
5774 else /** @todo test this! */
5775 iemGRegStoreU32(pVCpu, iGReg, (uint32_t)u64GuestCr0 | UINT32_C(0x7fffffe0)); /* Unused bits are set on 386. */
5776 break;
5777
5778 case IEMMODE_64BIT:
5779 iemGRegStoreU64(pVCpu, iGReg, u64GuestCr0);
5780 break;
5781
5782 IEM_NOT_REACHED_DEFAULT_CASE_RET();
5783 }
5784
5785 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5786}
5787
5788
5789/**
5790 * Implements smsw mem.
5791 *
5792 * @param iEffSeg The effective segment register to use with @a GCPtrMem.
5793 * @param GCPtrEffDst Where to store the 16-bit CR0 value.
5794 */
5795IEM_CIMPL_DEF_2(iemCImpl_smsw_mem, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
5796{
5797 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5798 if (!IEM_IS_IN_GUEST(pVCpu))
5799 { /* probable */ }
5800 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
5801 u64GuestCr0 = CPUMGetGuestVmxMaskedCr0(&pVCpu->cpum.GstCtx, pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u64Cr0Mask.u);
5802 else
5803 IEM_SVM_CHECK_READ_CR0_INTERCEPT(pVCpu, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */, cbInstr);
5804
5805 uint16_t u16Value;
5806 if (IEM_GET_TARGET_CPU(pVCpu) > IEMTARGETCPU_386)
5807 u16Value = (uint16_t)u64GuestCr0;
5808 else if (IEM_GET_TARGET_CPU(pVCpu) >= IEMTARGETCPU_386)
5809 u16Value = (uint16_t)u64GuestCr0 | 0xffe0;
5810 else
5811 u16Value = (uint16_t)u64GuestCr0 | 0xfff0;
5812
5813 VBOXSTRICTRC rcStrict = iemMemStoreDataU16(pVCpu, iEffSeg, GCPtrEffDst, u16Value);
5814 if (rcStrict == VINF_SUCCESS)
5815 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
5816 return rcStrict;
5817}
5818
5819
5820/**
5821 * Helper for mapping CR3 and PAE PDPEs for 'mov CRx,GReg'.
5822 */
5823#define IEM_MAP_PAE_PDPES_AT_CR3_RET(a_pVCpu, a_iCrReg, a_uCr3) \
5824 do \
5825 { \
5826 int const rcX = PGMGstMapPaePdpesAtCr3(a_pVCpu, a_uCr3); \
5827 if (RT_SUCCESS(rcX)) \
5828 { /* likely */ } \
5829 else \
5830 { \
5831 /* Either invalid PDPTEs or CR3 second-level translation failed. Raise #GP(0) either way. */ \
5832 Log(("iemCImpl_load_Cr%#x: Trying to load invalid PAE PDPEs\n", a_iCrReg)); \
5833 return iemRaiseGeneralProtectionFault0(a_pVCpu); \
5834 } \
5835 } while (0)
5836
5837
5838/**
5839 * Used to implemented 'mov CRx,GReg' and 'lmsw r/m16'.
5840 *
5841 * @param iCrReg The CRx register to write (valid).
5842 * @param uNewCrX The new value.
5843 * @param enmAccessCrX The instruction that caused the CrX load.
5844 * @param iGReg The general register in case of a 'mov CRx,GReg'
5845 * instruction.
5846 */
5847IEM_CIMPL_DEF_4(iemCImpl_load_CrX, uint8_t, iCrReg, uint64_t, uNewCrX, IEMACCESSCRX, enmAccessCrX, uint8_t, iGReg)
5848{
5849 VBOXSTRICTRC rcStrict;
5850 int rc;
5851#ifndef VBOX_WITH_NESTED_HWVIRT_SVM
5852 RT_NOREF2(iGReg, enmAccessCrX);
5853#endif
5854
5855 /*
5856 * Try store it.
5857 * Unfortunately, CPUM only does a tiny bit of the work.
5858 */
5859 switch (iCrReg)
5860 {
5861 case 0:
5862 {
5863 /*
5864 * Perform checks.
5865 */
5866 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5867
5868 uint64_t const uOldCrX = pVCpu->cpum.GstCtx.cr0;
5869 uint32_t const fValid = CPUMGetGuestCR0ValidMask();
5870
5871 /* ET is hardcoded on 486 and later. */
5872 if (IEM_GET_TARGET_CPU(pVCpu) > IEMTARGETCPU_486)
5873 uNewCrX |= X86_CR0_ET;
5874 /* The 386 and 486 didn't #GP(0) on attempting to set reserved CR0 bits. ET was settable on 386. */
5875 else if (IEM_GET_TARGET_CPU(pVCpu) == IEMTARGETCPU_486)
5876 {
5877 uNewCrX &= fValid;
5878 uNewCrX |= X86_CR0_ET;
5879 }
5880 else
5881 uNewCrX &= X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS | X86_CR0_PG | X86_CR0_ET;
5882
5883 /* Check for reserved bits. */
5884 if (uNewCrX & ~(uint64_t)fValid)
5885 {
5886 Log(("Trying to set reserved CR0 bits: NewCR0=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
5887 return iemRaiseGeneralProtectionFault0(pVCpu);
5888 }
5889
5890 /* Check for invalid combinations. */
5891 if ( (uNewCrX & X86_CR0_PG)
5892 && !(uNewCrX & X86_CR0_PE) )
5893 {
5894 Log(("Trying to set CR0.PG without CR0.PE\n"));
5895 return iemRaiseGeneralProtectionFault0(pVCpu);
5896 }
5897
5898 if ( !(uNewCrX & X86_CR0_CD)
5899 && (uNewCrX & X86_CR0_NW) )
5900 {
5901 Log(("Trying to clear CR0.CD while leaving CR0.NW set\n"));
5902 return iemRaiseGeneralProtectionFault0(pVCpu);
5903 }
5904
5905 if ( !(uNewCrX & X86_CR0_PG)
5906 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PCIDE))
5907 {
5908 Log(("Trying to clear CR0.PG while leaving CR4.PCID set\n"));
5909 return iemRaiseGeneralProtectionFault0(pVCpu);
5910 }
5911
5912 /* Long mode consistency checks. */
5913 if ( (uNewCrX & X86_CR0_PG)
5914 && !(uOldCrX & X86_CR0_PG)
5915 && (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LME) )
5916 {
5917 if (!(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE))
5918 {
5919 Log(("Trying to enabled long mode paging without CR4.PAE set\n"));
5920 return iemRaiseGeneralProtectionFault0(pVCpu);
5921 }
5922 if (pVCpu->cpum.GstCtx.cs.Attr.n.u1Long)
5923 {
5924 Log(("Trying to enabled long mode paging with a long CS descriptor loaded.\n"));
5925 return iemRaiseGeneralProtectionFault0(pVCpu);
5926 }
5927 }
5928
5929 /** @todo testcase: what happens if we disable paging while in 64-bit code? */
5930
5931 if (!IEM_IS_IN_GUEST(pVCpu))
5932 { /* probable */ }
5933#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5934 /* Check for bits that must remain set or cleared in VMX operation,
5935 see Intel spec. 23.8 "Restrictions on VMX operation". */
5936 else if (IEM_VMX_IS_ROOT_MODE(pVCpu))
5937 {
5938 uint64_t const uCr0Fixed0 = iemVmxGetCr0Fixed0(pVCpu, IEM_VMX_IS_NON_ROOT_MODE(pVCpu));
5939 if ((uNewCrX & uCr0Fixed0) != uCr0Fixed0)
5940 {
5941 Log(("Trying to clear reserved CR0 bits in VMX operation: NewCr0=%#llx MB1=%#llx\n", uNewCrX, uCr0Fixed0));
5942 return iemRaiseGeneralProtectionFault0(pVCpu);
5943 }
5944
5945 uint64_t const uCr0Fixed1 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr0Fixed1;
5946 if (uNewCrX & ~uCr0Fixed1)
5947 {
5948 Log(("Trying to set reserved CR0 bits in VMX operation: NewCr0=%#llx MB0=%#llx\n", uNewCrX, uCr0Fixed1));
5949 return iemRaiseGeneralProtectionFault0(pVCpu);
5950 }
5951 }
5952#endif
5953 /*
5954 * SVM nested-guest CR0 write intercepts.
5955 */
5956 else if (IEM_SVM_IS_WRITE_CR_INTERCEPT_SET(pVCpu, iCrReg))
5957 {
5958 Log(("iemCImpl_load_Cr%#x: Guest intercept -> #VMEXIT\n", iCrReg));
5959 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
5960 IEM_SVM_CRX_VMEXIT_RET(pVCpu, SVM_EXIT_WRITE_CR0, enmAccessCrX, iGReg);
5961 }
5962 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_CR0_SEL_WRITE))
5963 {
5964 /* 'lmsw' intercepts regardless of whether the TS/MP bits are actually toggled. */
5965 if ( enmAccessCrX == IEMACCESSCRX_LMSW
5966 || (uNewCrX & ~(X86_CR0_TS | X86_CR0_MP)) != (uOldCrX & ~(X86_CR0_TS | X86_CR0_MP)))
5967 {
5968 Assert(enmAccessCrX != IEMACCESSCRX_CLTS);
5969 Log(("iemCImpl_load_Cr%#x: lmsw or bits other than TS/MP changed: Guest intercept -> #VMEXIT\n", iCrReg));
5970 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
5971 IEM_SVM_CRX_VMEXIT_RET(pVCpu, SVM_EXIT_CR0_SEL_WRITE, enmAccessCrX, iGReg);
5972 }
5973 }
5974
5975 /*
5976 * Change EFER.LMA if entering or leaving long mode.
5977 */
5978 uint64_t NewEFER = pVCpu->cpum.GstCtx.msrEFER;
5979 if ( (uNewCrX & X86_CR0_PG) != (uOldCrX & X86_CR0_PG)
5980 && (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LME) )
5981 {
5982 if (uNewCrX & X86_CR0_PG)
5983 NewEFER |= MSR_K6_EFER_LMA;
5984 else
5985 NewEFER &= ~MSR_K6_EFER_LMA;
5986
5987 CPUMSetGuestEFER(pVCpu, NewEFER);
5988 Assert(pVCpu->cpum.GstCtx.msrEFER == NewEFER);
5989 }
5990
5991 /*
5992 * Inform PGM.
5993 */
5994 if ( (uNewCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE | X86_CR0_CD | X86_CR0_NW))
5995 != (uOldCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE | X86_CR0_CD | X86_CR0_NW)) )
5996 {
5997 if ( enmAccessCrX != IEMACCESSCRX_MOV_CRX
5998 || !CPUMIsPaePagingEnabled(uNewCrX, pVCpu->cpum.GstCtx.cr4, NewEFER)
5999 || CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)))
6000 { /* likely */ }
6001 else
6002 IEM_MAP_PAE_PDPES_AT_CR3_RET(pVCpu, iCrReg, pVCpu->cpum.GstCtx.cr3);
6003 rc = PGMFlushTLB(pVCpu, pVCpu->cpum.GstCtx.cr3, true /* global */);
6004 AssertRCReturn(rc, rc);
6005 /* ignore informational status codes */
6006 }
6007
6008 /*
6009 * Change CR0.
6010 */
6011 CPUMSetGuestCR0(pVCpu, uNewCrX);
6012 Assert(pVCpu->cpum.GstCtx.cr0 == uNewCrX);
6013
6014 /* Update the fExec flags if PE changed. */
6015 if ((uNewCrX ^ uOldCrX) & X86_CR0_PE)
6016 iemRecalcExecModeAndCplAndAcFlags(pVCpu);
6017
6018 /*
6019 * Inform PGM some more...
6020 */
6021 rcStrict = PGMChangeMode(pVCpu, pVCpu->cpum.GstCtx.cr0, pVCpu->cpum.GstCtx.cr4, pVCpu->cpum.GstCtx.msrEFER,
6022 false /* fForce */);
6023 break;
6024 }
6025
6026 /*
6027 * CR2 can be changed without any restrictions.
6028 */
6029 case 2:
6030 {
6031 if (!IEM_SVM_IS_WRITE_CR_INTERCEPT_SET(pVCpu, /*cr*/ 2))
6032 { /* probable */ }
6033 else
6034 {
6035 Log(("iemCImpl_load_Cr%#x: Guest intercept -> #VMEXIT\n", iCrReg));
6036 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6037 IEM_SVM_CRX_VMEXIT_RET(pVCpu, SVM_EXIT_WRITE_CR2, enmAccessCrX, iGReg);
6038 }
6039 pVCpu->cpum.GstCtx.cr2 = uNewCrX;
6040 pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_CR2;
6041 rcStrict = VINF_SUCCESS;
6042 break;
6043 }
6044
6045 /*
6046 * CR3 is relatively simple, although AMD and Intel have different
6047 * accounts of how setting reserved bits are handled. We take intel's
6048 * word for the lower bits and AMD's for the high bits (63:52). The
6049 * lower reserved bits are ignored and left alone; OpenBSD 5.8 relies
6050 * on this.
6051 */
6052 /** @todo Testcase: Setting reserved bits in CR3, especially before
6053 * enabling paging. */
6054 case 3:
6055 {
6056 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
6057
6058 /* Bit 63 being clear in the source operand with PCIDE indicates no invalidations are required. */
6059 if ( (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PCIDE)
6060 && (uNewCrX & RT_BIT_64(63)))
6061 {
6062 /** @todo r=ramshankar: avoiding a TLB flush altogether here causes Windows 10
6063 * SMP(w/o nested-paging) to hang during bootup on Skylake systems, see
6064 * Intel spec. 4.10.4.1 "Operations that Invalidate TLBs and
6065 * Paging-Structure Caches". */
6066 uNewCrX &= ~RT_BIT_64(63);
6067 }
6068
6069 /* Check / mask the value. */
6070#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
6071 /* See Intel spec. 27.2.2 "EPT Translation Mechanism" footnote. */
6072 uint64_t const fInvPhysMask = !CPUMIsGuestVmxEptPagingEnabledEx(IEM_GET_CTX(pVCpu))
6073 ? (UINT64_MAX << IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cMaxPhysAddrWidth)
6074 : (~X86_CR3_EPT_PAGE_MASK & X86_PAGE_4K_BASE_MASK);
6075#else
6076 uint64_t const fInvPhysMask = UINT64_C(0xfff0000000000000);
6077#endif
6078 if (uNewCrX & fInvPhysMask)
6079 {
6080 /** @todo Should we raise this only for 64-bit mode like Intel claims? AMD is
6081 * very vague in this area. As mentioned above, need testcase on real
6082 * hardware... Sigh. */
6083 Log(("Trying to load CR3 with invalid high bits set: %#llx\n", uNewCrX));
6084 return iemRaiseGeneralProtectionFault0(pVCpu);
6085 }
6086
6087 uint64_t fValid;
6088 if ( (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE)
6089 && (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LME))
6090 {
6091 /** @todo Redundant? This value has already been validated above. */
6092 fValid = UINT64_C(0x000fffffffffffff);
6093 }
6094 else
6095 fValid = UINT64_C(0xffffffff);
6096 if (uNewCrX & ~fValid)
6097 {
6098 Log(("Automatically clearing reserved MBZ bits in CR3 load: NewCR3=%#llx ClearedBits=%#llx\n",
6099 uNewCrX, uNewCrX & ~fValid));
6100 uNewCrX &= fValid;
6101 }
6102
6103 if (!IEM_SVM_IS_WRITE_CR_INTERCEPT_SET(pVCpu, /*cr*/ 3))
6104 { /* probable */ }
6105 else
6106 {
6107 Log(("iemCImpl_load_Cr%#x: Guest intercept -> #VMEXIT\n", iCrReg));
6108 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6109 IEM_SVM_CRX_VMEXIT_RET(pVCpu, SVM_EXIT_WRITE_CR3, enmAccessCrX, iGReg);
6110 }
6111
6112 /* Inform PGM. */
6113 if (pVCpu->cpum.GstCtx.cr0 & X86_CR0_PG)
6114 {
6115 if ( !CPUMIsGuestInPAEModeEx(IEM_GET_CTX(pVCpu))
6116 || CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)))
6117 { /* likely */ }
6118 else
6119 {
6120 Assert(enmAccessCrX == IEMACCESSCRX_MOV_CRX);
6121 IEM_MAP_PAE_PDPES_AT_CR3_RET(pVCpu, iCrReg, uNewCrX);
6122 }
6123 rc = PGMFlushTLB(pVCpu, uNewCrX, !(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PGE));
6124 AssertRCReturn(rc, rc);
6125 /* ignore informational status codes */
6126 }
6127
6128 /* Make the change. */
6129 rc = CPUMSetGuestCR3(pVCpu, uNewCrX);
6130 AssertRCSuccessReturn(rc, rc);
6131
6132 rcStrict = VINF_SUCCESS;
6133 break;
6134 }
6135
6136 /*
6137 * CR4 is a bit more tedious as there are bits which cannot be cleared
6138 * under some circumstances and such.
6139 */
6140 case 4:
6141 {
6142 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
6143 uint64_t const uOldCrX = pVCpu->cpum.GstCtx.cr4;
6144
6145 /* Reserved bits. */
6146 uint32_t const fValid = CPUMGetGuestCR4ValidMask(pVCpu->CTX_SUFF(pVM));
6147 if (uNewCrX & ~(uint64_t)fValid)
6148 {
6149 Log(("Trying to set reserved CR4 bits: NewCR4=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
6150 return iemRaiseGeneralProtectionFault0(pVCpu);
6151 }
6152
6153 bool const fPcide = !(uOldCrX & X86_CR4_PCIDE) && (uNewCrX & X86_CR4_PCIDE);
6154 bool const fLongMode = CPUMIsGuestInLongModeEx(IEM_GET_CTX(pVCpu));
6155
6156 /* PCIDE check. */
6157 if ( fPcide
6158 && ( !fLongMode
6159 || (pVCpu->cpum.GstCtx.cr3 & UINT64_C(0xfff))))
6160 {
6161 Log(("Trying to set PCIDE with invalid PCID or outside long mode. Pcid=%#x\n", (pVCpu->cpum.GstCtx.cr3 & UINT64_C(0xfff))));
6162 return iemRaiseGeneralProtectionFault0(pVCpu);
6163 }
6164
6165 /* PAE check. */
6166 if ( fLongMode
6167 && (uOldCrX & X86_CR4_PAE)
6168 && !(uNewCrX & X86_CR4_PAE))
6169 {
6170 Log(("Trying to set clear CR4.PAE while long mode is active\n"));
6171 return iemRaiseGeneralProtectionFault0(pVCpu);
6172 }
6173
6174 if (!IEM_SVM_IS_WRITE_CR_INTERCEPT_SET(pVCpu, /*cr*/ 4))
6175 { /* probable */ }
6176 else
6177 {
6178 Log(("iemCImpl_load_Cr%#x: Guest intercept -> #VMEXIT\n", iCrReg));
6179 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6180 IEM_SVM_CRX_VMEXIT_RET(pVCpu, SVM_EXIT_WRITE_CR4, enmAccessCrX, iGReg);
6181 }
6182
6183 /* Check for bits that must remain set or cleared in VMX operation,
6184 see Intel spec. 23.8 "Restrictions on VMX operation". */
6185 if (!IEM_VMX_IS_ROOT_MODE(pVCpu))
6186 { /* probable */ }
6187 else
6188 {
6189 uint64_t const uCr4Fixed0 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed0;
6190 if ((uNewCrX & uCr4Fixed0) != uCr4Fixed0)
6191 {
6192 Log(("Trying to clear reserved CR4 bits in VMX operation: NewCr4=%#llx MB1=%#llx\n", uNewCrX, uCr4Fixed0));
6193 return iemRaiseGeneralProtectionFault0(pVCpu);
6194 }
6195
6196 uint64_t const uCr4Fixed1 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed1;
6197 if (uNewCrX & ~uCr4Fixed1)
6198 {
6199 Log(("Trying to set reserved CR4 bits in VMX operation: NewCr4=%#llx MB0=%#llx\n", uNewCrX, uCr4Fixed1));
6200 return iemRaiseGeneralProtectionFault0(pVCpu);
6201 }
6202 }
6203
6204 /*
6205 * Notify PGM.
6206 */
6207 if ((uNewCrX ^ uOldCrX) & (X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_PCIDE /* | X86_CR4_SMEP */))
6208 {
6209 if ( !CPUMIsPaePagingEnabled(pVCpu->cpum.GstCtx.cr0, uNewCrX, pVCpu->cpum.GstCtx.msrEFER)
6210 || CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)))
6211 { /* likely */ }
6212 else
6213 {
6214 Assert(enmAccessCrX == IEMACCESSCRX_MOV_CRX);
6215 IEM_MAP_PAE_PDPES_AT_CR3_RET(pVCpu, iCrReg, pVCpu->cpum.GstCtx.cr3);
6216 }
6217 rc = PGMFlushTLB(pVCpu, pVCpu->cpum.GstCtx.cr3, true /* global */);
6218 AssertRCReturn(rc, rc);
6219 /* ignore informational status codes */
6220 }
6221
6222 /*
6223 * Change it.
6224 */
6225 rc = CPUMSetGuestCR4(pVCpu, uNewCrX);
6226 AssertRCSuccessReturn(rc, rc);
6227 Assert(pVCpu->cpum.GstCtx.cr4 == uNewCrX);
6228
6229 rcStrict = PGMChangeMode(pVCpu, pVCpu->cpum.GstCtx.cr0, pVCpu->cpum.GstCtx.cr4, pVCpu->cpum.GstCtx.msrEFER,
6230 false /* fForce */);
6231 break;
6232 }
6233
6234 /*
6235 * CR8 maps to the APIC TPR.
6236 */
6237 case 8:
6238 {
6239 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
6240 if (uNewCrX & ~(uint64_t)0xf)
6241 {
6242 Log(("Trying to set reserved CR8 bits (%#RX64)\n", uNewCrX));
6243 return iemRaiseGeneralProtectionFault0(pVCpu);
6244 }
6245
6246 if (!IEM_IS_IN_GUEST(pVCpu))
6247 { /* probable */ }
6248#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6249 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
6250 && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_USE_TPR_SHADOW))
6251 {
6252 /*
6253 * If the Mov-to-CR8 doesn't cause a VM-exit, bits 0:3 of the source operand
6254 * is copied to bits 7:4 of the VTPR. Bits 0:3 and bits 31:8 of the VTPR are
6255 * cleared. Following this the processor performs TPR virtualization.
6256 *
6257 * However, we should not perform TPR virtualization immediately here but
6258 * after this instruction has completed.
6259 *
6260 * See Intel spec. 29.3 "Virtualizing CR8-based TPR Accesses"
6261 * See Intel spec. 27.1 "Architectural State Before A VM-exit"
6262 */
6263 uint32_t const uTpr = (uNewCrX & 0xf) << 4;
6264 Log(("iemCImpl_load_Cr%#x: Virtualizing TPR (%#x) write\n", iCrReg, uTpr));
6265 iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_TPR, uTpr);
6266 iemVmxVirtApicSetPendingWrite(pVCpu, XAPIC_OFF_TPR);
6267 rcStrict = VINF_SUCCESS;
6268 break;
6269 }
6270#endif
6271#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
6272 else if (pVCpu->iem.s.fExec & IEM_F_X86_CTX_SVM)
6273 {
6274 if (IEM_SVM_IS_WRITE_CR_INTERCEPT_SET(pVCpu, /*cr*/ 8))
6275 {
6276 Log(("iemCImpl_load_Cr%#x: Guest intercept -> #VMEXIT\n", iCrReg));
6277 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6278 IEM_SVM_CRX_VMEXIT_RET(pVCpu, SVM_EXIT_WRITE_CR8, enmAccessCrX, iGReg);
6279 }
6280
6281 pVCpu->cpum.GstCtx.hwvirt.svm.Vmcb.ctrl.IntCtrl.n.u8VTPR = uNewCrX;
6282 if (CPUMIsGuestSvmVirtIntrMasking(pVCpu, IEM_GET_CTX(pVCpu)))
6283 {
6284 rcStrict = VINF_SUCCESS;
6285 break;
6286 }
6287 }
6288#endif
6289 uint8_t const u8Tpr = (uint8_t)uNewCrX << 4;
6290 APICSetTpr(pVCpu, u8Tpr);
6291 rcStrict = VINF_SUCCESS;
6292 break;
6293 }
6294
6295 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
6296 }
6297
6298 /*
6299 * Advance the RIP on success.
6300 */
6301 if (RT_SUCCESS(rcStrict))
6302 {
6303 if (rcStrict != VINF_SUCCESS)
6304 iemSetPassUpStatus(pVCpu, rcStrict);
6305 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6306 }
6307
6308 return rcStrict;
6309}
6310
6311
6312/**
6313 * Implements mov CRx,GReg.
6314 *
6315 * @param iCrReg The CRx register to write (valid).
6316 * @param iGReg The general register to load the CRx value from.
6317 */
6318IEM_CIMPL_DEF_2(iemCImpl_mov_Cd_Rd, uint8_t, iCrReg, uint8_t, iGReg)
6319{
6320 if (IEM_GET_CPL(pVCpu) != 0)
6321 return iemRaiseGeneralProtectionFault0(pVCpu);
6322 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6323
6324 /*
6325 * Read the new value from the source register and call common worker.
6326 */
6327 uint64_t uNewCrX;
6328 if (IEM_IS_64BIT_CODE(pVCpu))
6329 uNewCrX = iemGRegFetchU64(pVCpu, iGReg);
6330 else
6331 uNewCrX = iemGRegFetchU32(pVCpu, iGReg);
6332
6333#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6334 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6335 { /* probable */ }
6336 else
6337 {
6338 VBOXSTRICTRC rcStrict = VINF_VMX_INTERCEPT_NOT_ACTIVE;
6339 switch (iCrReg)
6340 {
6341 case 0:
6342 case 4: rcStrict = iemVmxVmexitInstrMovToCr0Cr4(pVCpu, iCrReg, &uNewCrX, iGReg, cbInstr); break;
6343 case 3: rcStrict = iemVmxVmexitInstrMovToCr3(pVCpu, uNewCrX, iGReg, cbInstr); break;
6344 case 8: rcStrict = iemVmxVmexitInstrMovToCr8(pVCpu, iGReg, cbInstr); break;
6345 }
6346 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
6347 return rcStrict;
6348 }
6349#endif
6350
6351 return IEM_CIMPL_CALL_4(iemCImpl_load_CrX, iCrReg, uNewCrX, IEMACCESSCRX_MOV_CRX, iGReg);
6352}
6353
6354
6355/**
6356 * Implements 'LMSW r/m16'
6357 *
6358 * @param u16NewMsw The new value.
6359 * @param GCPtrEffDst The guest-linear address of the source operand in case
6360 * of a memory operand. For register operand, pass
6361 * NIL_RTGCPTR.
6362 */
6363IEM_CIMPL_DEF_2(iemCImpl_lmsw, uint16_t, u16NewMsw, RTGCPTR, GCPtrEffDst)
6364{
6365 if (IEM_GET_CPL(pVCpu) != 0)
6366 return iemRaiseGeneralProtectionFault0(pVCpu);
6367 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6368 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
6369
6370#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6371 /* Check nested-guest VMX intercept and get updated MSW if there's no VM-exit. */
6372 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6373 { /* probable */ }
6374 else
6375 {
6376 VBOXSTRICTRC rcStrict = iemVmxVmexitInstrLmsw(pVCpu, pVCpu->cpum.GstCtx.cr0, &u16NewMsw, GCPtrEffDst, cbInstr);
6377 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
6378 return rcStrict;
6379 }
6380#else
6381 RT_NOREF_PV(GCPtrEffDst);
6382#endif
6383
6384 /*
6385 * Compose the new CR0 value and call common worker.
6386 */
6387 uint64_t uNewCr0 = pVCpu->cpum.GstCtx.cr0 & ~(X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
6388 uNewCr0 |= u16NewMsw & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
6389 return IEM_CIMPL_CALL_4(iemCImpl_load_CrX, /*cr*/ 0, uNewCr0, IEMACCESSCRX_LMSW, UINT8_MAX /* iGReg */);
6390}
6391
6392
6393/**
6394 * Implements 'CLTS'.
6395 */
6396IEM_CIMPL_DEF_0(iemCImpl_clts)
6397{
6398 if (IEM_GET_CPL(pVCpu) != 0)
6399 return iemRaiseGeneralProtectionFault0(pVCpu);
6400
6401 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
6402 uint64_t uNewCr0 = pVCpu->cpum.GstCtx.cr0;
6403 uNewCr0 &= ~X86_CR0_TS;
6404
6405#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6406 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6407 { /* probable */ }
6408 else
6409 {
6410 VBOXSTRICTRC rcStrict = iemVmxVmexitInstrClts(pVCpu, cbInstr);
6411 if (rcStrict == VINF_VMX_MODIFIES_BEHAVIOR)
6412 uNewCr0 |= (pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS);
6413 else if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
6414 return rcStrict;
6415 }
6416#endif
6417
6418 return IEM_CIMPL_CALL_4(iemCImpl_load_CrX, /*cr*/ 0, uNewCr0, IEMACCESSCRX_CLTS, UINT8_MAX /* iGReg */);
6419}
6420
6421
6422/**
6423 * Implements mov GReg,DRx.
6424 *
6425 * @param iGReg The general register to store the DRx value in.
6426 * @param iDrReg The DRx register to read (0-7).
6427 */
6428IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Dd, uint8_t, iGReg, uint8_t, iDrReg)
6429{
6430#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6431 /*
6432 * Check nested-guest VMX intercept.
6433 * Unlike most other intercepts, the Mov DRx intercept takes preceedence
6434 * over CPL and CR4.DE and even DR4/DR5 checks.
6435 *
6436 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
6437 */
6438 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6439 { /* probable */ }
6440 else
6441 {
6442 VBOXSTRICTRC rcStrict = iemVmxVmexitInstrMovDrX(pVCpu, VMXINSTRID_MOV_FROM_DRX, iDrReg, iGReg, cbInstr);
6443 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
6444 return rcStrict;
6445 }
6446#endif
6447
6448 /*
6449 * Check preconditions.
6450 */
6451 /* Raise GPs. */
6452 if (IEM_GET_CPL(pVCpu) != 0)
6453 return iemRaiseGeneralProtectionFault0(pVCpu);
6454 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6455 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
6456
6457 /** @todo \#UD in outside ring-0 too? */
6458 if (iDrReg == 4 || iDrReg == 5)
6459 {
6460 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_CR4);
6461 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_DE)
6462 {
6463 Log(("mov r%u,dr%u: CR4.DE=1 -> #GP(0)\n", iGReg, iDrReg));
6464 return iemRaiseGeneralProtectionFault0(pVCpu);
6465 }
6466 iDrReg += 2;
6467 }
6468
6469 /* Raise #DB if general access detect is enabled. */
6470 if (pVCpu->cpum.GstCtx.dr[7] & X86_DR7_GD)
6471 {
6472 Log(("mov r%u,dr%u: DR7.GD=1 -> #DB\n", iGReg, iDrReg));
6473 return iemRaiseDebugException(pVCpu);
6474 }
6475
6476 /*
6477 * Read the debug register and store it in the specified general register.
6478 */
6479 uint64_t drX;
6480 switch (iDrReg)
6481 {
6482 case 0:
6483 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
6484 drX = pVCpu->cpum.GstCtx.dr[0];
6485 break;
6486 case 1:
6487 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
6488 drX = pVCpu->cpum.GstCtx.dr[1];
6489 break;
6490 case 2:
6491 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
6492 drX = pVCpu->cpum.GstCtx.dr[2];
6493 break;
6494 case 3:
6495 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
6496 drX = pVCpu->cpum.GstCtx.dr[3];
6497 break;
6498 case 6:
6499 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR6);
6500 drX = pVCpu->cpum.GstCtx.dr[6];
6501 drX |= X86_DR6_RA1_MASK;
6502 drX &= ~X86_DR6_RAZ_MASK;
6503 break;
6504 case 7:
6505 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
6506 drX = pVCpu->cpum.GstCtx.dr[7];
6507 drX |=X86_DR7_RA1_MASK;
6508 drX &= ~X86_DR7_RAZ_MASK;
6509 break;
6510 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* caller checks */
6511 }
6512
6513 /** @todo SVM nested-guest intercept for DR8-DR15? */
6514 /*
6515 * Check for any SVM nested-guest intercepts for the DRx read.
6516 */
6517 if (!IEM_SVM_IS_READ_DR_INTERCEPT_SET(pVCpu, iDrReg))
6518 { /* probable */ }
6519 else
6520 {
6521 Log(("mov r%u,dr%u: Guest intercept -> #VMEXIT\n", iGReg, iDrReg));
6522 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6523 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_READ_DR0 + (iDrReg & 0xf),
6524 IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fSvmDecodeAssists ? (iGReg & 7) : 0, 0 /* uExitInfo2 */);
6525 }
6526
6527 if (IEM_IS_64BIT_CODE(pVCpu))
6528 iemGRegStoreU64(pVCpu, iGReg, drX);
6529 else
6530 iemGRegStoreU32(pVCpu, iGReg, (uint32_t)drX);
6531
6532 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6533}
6534
6535
6536/**
6537 * Implements mov DRx,GReg.
6538 *
6539 * @param iDrReg The DRx register to write (valid).
6540 * @param iGReg The general register to load the DRx value from.
6541 */
6542IEM_CIMPL_DEF_2(iemCImpl_mov_Dd_Rd, uint8_t, iDrReg, uint8_t, iGReg)
6543{
6544#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6545 /*
6546 * Check nested-guest VMX intercept.
6547 * Unlike most other intercepts, the Mov DRx intercept takes preceedence
6548 * over CPL and CR4.DE and even DR4/DR5 checks.
6549 *
6550 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
6551 */
6552 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6553 { /* probable */ }
6554 else
6555 {
6556 VBOXSTRICTRC rcStrict = iemVmxVmexitInstrMovDrX(pVCpu, VMXINSTRID_MOV_TO_DRX, iDrReg, iGReg, cbInstr);
6557 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
6558 return rcStrict;
6559 }
6560#endif
6561
6562 /*
6563 * Check preconditions.
6564 */
6565 if (IEM_GET_CPL(pVCpu) != 0)
6566 return iemRaiseGeneralProtectionFault0(pVCpu);
6567 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6568 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
6569
6570 if (iDrReg == 4 || iDrReg == 5)
6571 {
6572 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_CR4);
6573 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_DE)
6574 {
6575 Log(("mov dr%u,r%u: CR4.DE=1 -> #GP(0)\n", iDrReg, iGReg));
6576 return iemRaiseGeneralProtectionFault0(pVCpu);
6577 }
6578 iDrReg += 2;
6579 }
6580
6581 /* Raise #DB if general access detect is enabled. */
6582 /** @todo is \#DB/DR7.GD raised before any reserved high bits in DR7/DR6
6583 * \#GP? */
6584 if (pVCpu->cpum.GstCtx.dr[7] & X86_DR7_GD)
6585 {
6586 Log(("mov dr%u,r%u: DR7.GD=1 -> #DB\n", iDrReg, iGReg));
6587 return iemRaiseDebugException(pVCpu);
6588 }
6589
6590 /*
6591 * Read the new value from the source register.
6592 */
6593 uint64_t uNewDrX;
6594 if (IEM_IS_64BIT_CODE(pVCpu))
6595 uNewDrX = iemGRegFetchU64(pVCpu, iGReg);
6596 else
6597 uNewDrX = iemGRegFetchU32(pVCpu, iGReg);
6598
6599 /*
6600 * Adjust it.
6601 */
6602 switch (iDrReg)
6603 {
6604 case 0:
6605 case 1:
6606 case 2:
6607 case 3:
6608 /* nothing to adjust */
6609 break;
6610
6611 case 6:
6612 if (uNewDrX & X86_DR6_MBZ_MASK)
6613 {
6614 Log(("mov dr%u,%#llx: DR6 high bits are not zero -> #GP(0)\n", iDrReg, uNewDrX));
6615 return iemRaiseGeneralProtectionFault0(pVCpu);
6616 }
6617 uNewDrX |= X86_DR6_RA1_MASK;
6618 uNewDrX &= ~X86_DR6_RAZ_MASK;
6619 break;
6620
6621 case 7:
6622 if (uNewDrX & X86_DR7_MBZ_MASK)
6623 {
6624 Log(("mov dr%u,%#llx: DR7 high bits are not zero -> #GP(0)\n", iDrReg, uNewDrX));
6625 return iemRaiseGeneralProtectionFault0(pVCpu);
6626 }
6627 uNewDrX |= X86_DR7_RA1_MASK;
6628 uNewDrX &= ~X86_DR7_RAZ_MASK;
6629 break;
6630
6631 IEM_NOT_REACHED_DEFAULT_CASE_RET();
6632 }
6633
6634 /** @todo SVM nested-guest intercept for DR8-DR15? */
6635 /*
6636 * Check for any SVM nested-guest intercepts for the DRx write.
6637 */
6638 if (!IEM_SVM_IS_WRITE_DR_INTERCEPT_SET(pVCpu, iDrReg))
6639 { /* probable */ }
6640 else
6641 {
6642 Log2(("mov dr%u,r%u: Guest intercept -> #VMEXIT\n", iDrReg, iGReg));
6643 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6644 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_WRITE_DR0 + (iDrReg & 0xf),
6645 IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fSvmDecodeAssists ? (iGReg & 7) : 0, 0 /* uExitInfo2 */);
6646 }
6647
6648 /*
6649 * Do the actual setting.
6650 */
6651 if (iDrReg < 4)
6652 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
6653 else if (iDrReg == 6)
6654 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR6);
6655
6656 int rc = CPUMSetGuestDRx(pVCpu, iDrReg, uNewDrX);
6657 AssertRCSuccessReturn(rc, RT_SUCCESS_NP(rc) ? VERR_IEM_IPE_1 : rc);
6658
6659 /*
6660 * Re-init hardware breakpoint summary if it was DR7 that got changed.
6661 *
6662 * We also do this when an active data breakpoint is updated so that the
6663 * TLB entry can be correctly invalidated.
6664 */
6665 if ( iDrReg == 7
6666#ifdef IEM_WITH_DATA_TLB
6667 || ( iDrReg <= 3
6668 && (X86_DR7_L_G(iDrReg) & pVCpu->cpum.GstCtx.dr[7])
6669 && X86_DR7_IS_W_CFG(pVCpu->cpum.GstCtx.dr[7], iDrReg) )
6670#endif
6671 )
6672 iemRecalcExecDbgFlags(pVCpu);
6673
6674 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6675}
6676
6677
6678/**
6679 * Implements mov GReg,TRx.
6680 *
6681 * @param iGReg The general register to store the
6682 * TRx value in.
6683 * @param iTrReg The TRx register to read (6/7).
6684 */
6685IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Td, uint8_t, iGReg, uint8_t, iTrReg)
6686{
6687 /*
6688 * Check preconditions. NB: This instruction is 386/486 only.
6689 */
6690
6691 /* Raise GPs. */
6692 if (IEM_GET_CPL(pVCpu) != 0)
6693 return iemRaiseGeneralProtectionFault0(pVCpu);
6694 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6695
6696 if (iTrReg < 6 || iTrReg > 7)
6697 {
6698 /** @todo Do Intel CPUs reject this or are the TRs aliased? */
6699 Log(("mov r%u,tr%u: invalid register -> #GP(0)\n", iGReg, iTrReg));
6700 return iemRaiseGeneralProtectionFault0(pVCpu);
6701 }
6702
6703 /*
6704 * Read the test register and store it in the specified general register.
6705 * This is currently a dummy implementation that only exists to satisfy
6706 * old debuggers like WDEB386 or OS/2 KDB which unconditionally read the
6707 * TR6/TR7 registers. Software which actually depends on the TR values
6708 * (different on 386/486) is exceedingly rare.
6709 */
6710 uint32_t trX;
6711 switch (iTrReg)
6712 {
6713 case 6:
6714 trX = 0; /* Currently a dummy. */
6715 break;
6716 case 7:
6717 trX = 0; /* Currently a dummy. */
6718 break;
6719 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
6720 }
6721
6722 iemGRegStoreU32(pVCpu, iGReg, trX);
6723
6724 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6725}
6726
6727
6728/**
6729 * Implements mov TRx,GReg.
6730 *
6731 * @param iTrReg The TRx register to write (valid).
6732 * @param iGReg The general register to load the TRx
6733 * value from.
6734 */
6735IEM_CIMPL_DEF_2(iemCImpl_mov_Td_Rd, uint8_t, iTrReg, uint8_t, iGReg)
6736{
6737 /*
6738 * Check preconditions. NB: This instruction is 386/486 only.
6739 */
6740
6741 /* Raise GPs. */
6742 if (IEM_GET_CPL(pVCpu) != 0)
6743 return iemRaiseGeneralProtectionFault0(pVCpu);
6744 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6745
6746 if (iTrReg < 6 || iTrReg > 7)
6747 {
6748 /** @todo Do Intel CPUs reject this or are the TRs aliased? */
6749 Log(("mov r%u,tr%u: invalid register -> #GP(0)\n", iGReg, iTrReg));
6750 return iemRaiseGeneralProtectionFault0(pVCpu);
6751 }
6752
6753 /*
6754 * Read the new value from the source register.
6755 */
6756 uint32_t uNewTrX = iemGRegFetchU32(pVCpu, iGReg);
6757
6758 /*
6759 * Here we would do the actual setting if this weren't a dummy implementation.
6760 * This is currently a dummy implementation that only exists to prevent
6761 * old debuggers like WDEB386 or OS/2 KDB from crashing.
6762 */
6763 RT_NOREF(uNewTrX);
6764
6765 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6766}
6767
6768
6769/**
6770 * Implements 'INVLPG m'.
6771 *
6772 * @param GCPtrPage The effective address of the page to invalidate.
6773 * @remarks Updates the RIP.
6774 */
6775IEM_CIMPL_DEF_1(iemCImpl_invlpg, RTGCPTR, GCPtrPage)
6776{
6777 /* ring-0 only. */
6778 if (IEM_GET_CPL(pVCpu) != 0)
6779 return iemRaiseGeneralProtectionFault0(pVCpu);
6780 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6781 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_EFER);
6782
6783 if (!IEM_IS_IN_GUEST(pVCpu))
6784 { /* probable */ }
6785#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6786 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
6787 && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_INVLPG_EXIT))
6788 {
6789 Log(("invlpg: Guest intercept (%RGp) -> VM-exit\n", GCPtrPage));
6790 return iemVmxVmexitInstrInvlpg(pVCpu, GCPtrPage, cbInstr);
6791 }
6792#endif
6793 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_INVLPG))
6794 {
6795 Log(("invlpg: Guest intercept (%RGp) -> #VMEXIT\n", GCPtrPage));
6796 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6797 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_INVLPG,
6798 IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fSvmDecodeAssists ? GCPtrPage : 0, 0 /* uExitInfo2 */);
6799 }
6800
6801 int rc = PGMInvalidatePage(pVCpu, GCPtrPage);
6802 if (rc == VINF_SUCCESS)
6803 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6804 if (rc == VINF_PGM_SYNC_CR3)
6805 {
6806 iemSetPassUpStatus(pVCpu, rc);
6807 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6808 }
6809
6810 AssertMsg(RT_FAILURE_NP(rc), ("%Rrc\n", rc));
6811 Log(("PGMInvalidatePage(%RGv) -> %Rrc\n", GCPtrPage, rc));
6812 return rc;
6813}
6814
6815
6816/**
6817 * Implements INVPCID.
6818 *
6819 * @param iEffSeg The segment of the invpcid descriptor.
6820 * @param GCPtrInvpcidDesc The address of invpcid descriptor.
6821 * @param uInvpcidType The invalidation type.
6822 * @remarks Updates the RIP.
6823 */
6824IEM_CIMPL_DEF_3(iemCImpl_invpcid, uint8_t, iEffSeg, RTGCPTR, GCPtrInvpcidDesc, uint64_t, uInvpcidType)
6825{
6826 /*
6827 * Check preconditions.
6828 */
6829 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fInvpcid)
6830 return iemRaiseUndefinedOpcode(pVCpu);
6831
6832 /* When in VMX non-root mode and INVPCID is not enabled, it results in #UD. */
6833 if (RT_LIKELY( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
6834 || IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_INVPCID)))
6835 { /* likely */ }
6836 else
6837 {
6838 Log(("invpcid: Not enabled for nested-guest execution -> #UD\n"));
6839 return iemRaiseUndefinedOpcode(pVCpu);
6840 }
6841
6842 if (IEM_GET_CPL(pVCpu) != 0)
6843 {
6844 Log(("invpcid: CPL != 0 -> #GP(0)\n"));
6845 return iemRaiseGeneralProtectionFault0(pVCpu);
6846 }
6847
6848 if (IEM_IS_V86_MODE(pVCpu))
6849 {
6850 Log(("invpcid: v8086 mode -> #GP(0)\n"));
6851 return iemRaiseGeneralProtectionFault0(pVCpu);
6852 }
6853
6854 /*
6855 * Check nested-guest intercept.
6856 *
6857 * INVPCID causes a VM-exit if "enable INVPCID" and "INVLPG exiting" are
6858 * both set. We have already checked the former earlier in this function.
6859 *
6860 * CPL and virtual-8086 mode checks take priority over this VM-exit.
6861 * See Intel spec. "25.1.1 Relative Priority of Faults and VM Exits".
6862 */
6863 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
6864 || !IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_INVLPG_EXIT))
6865 { /* probable */ }
6866 else
6867 {
6868 Log(("invpcid: Guest intercept -> #VM-exit\n"));
6869 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_INVPCID, VMXINSTRID_NONE, cbInstr);
6870 }
6871
6872 if (uInvpcidType > X86_INVPCID_TYPE_MAX_VALID)
6873 {
6874 Log(("invpcid: invalid/unrecognized invpcid type %#RX64 -> #GP(0)\n", uInvpcidType));
6875 return iemRaiseGeneralProtectionFault0(pVCpu);
6876 }
6877 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_EFER);
6878
6879 /*
6880 * Fetch the invpcid descriptor from guest memory.
6881 */
6882 RTUINT128U uDesc;
6883 VBOXSTRICTRC rcStrict = iemMemFetchDataU128(pVCpu, &uDesc, iEffSeg, GCPtrInvpcidDesc);
6884 if (rcStrict == VINF_SUCCESS)
6885 {
6886 /*
6887 * Validate the descriptor.
6888 */
6889 if (uDesc.s.Lo > 0xfff)
6890 {
6891 Log(("invpcid: reserved bits set in invpcid descriptor %#RX64 -> #GP(0)\n", uDesc.s.Lo));
6892 return iemRaiseGeneralProtectionFault0(pVCpu);
6893 }
6894
6895 RTGCUINTPTR64 const GCPtrInvAddr = uDesc.s.Hi;
6896 uint8_t const uPcid = uDesc.s.Lo & UINT64_C(0xfff);
6897 uint32_t const uCr4 = pVCpu->cpum.GstCtx.cr4;
6898 uint64_t const uCr3 = pVCpu->cpum.GstCtx.cr3;
6899 switch (uInvpcidType)
6900 {
6901 case X86_INVPCID_TYPE_INDV_ADDR:
6902 {
6903 if (!IEM_IS_CANONICAL(GCPtrInvAddr))
6904 {
6905 Log(("invpcid: invalidation address %#RGP is not canonical -> #GP(0)\n", GCPtrInvAddr));
6906 return iemRaiseGeneralProtectionFault0(pVCpu);
6907 }
6908 if ( !(uCr4 & X86_CR4_PCIDE)
6909 && uPcid != 0)
6910 {
6911 Log(("invpcid: invalid pcid %#x\n", uPcid));
6912 return iemRaiseGeneralProtectionFault0(pVCpu);
6913 }
6914
6915 /* Invalidate mappings for the linear address tagged with PCID except global translations. */
6916 PGMFlushTLB(pVCpu, uCr3, false /* fGlobal */);
6917 break;
6918 }
6919
6920 case X86_INVPCID_TYPE_SINGLE_CONTEXT:
6921 {
6922 if ( !(uCr4 & X86_CR4_PCIDE)
6923 && uPcid != 0)
6924 {
6925 Log(("invpcid: invalid pcid %#x\n", uPcid));
6926 return iemRaiseGeneralProtectionFault0(pVCpu);
6927 }
6928 /* Invalidate all mappings associated with PCID except global translations. */
6929 PGMFlushTLB(pVCpu, uCr3, false /* fGlobal */);
6930 break;
6931 }
6932
6933 case X86_INVPCID_TYPE_ALL_CONTEXT_INCL_GLOBAL:
6934 {
6935 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
6936 break;
6937 }
6938
6939 case X86_INVPCID_TYPE_ALL_CONTEXT_EXCL_GLOBAL:
6940 {
6941 PGMFlushTLB(pVCpu, uCr3, false /* fGlobal */);
6942 break;
6943 }
6944 IEM_NOT_REACHED_DEFAULT_CASE_RET();
6945 }
6946 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6947 }
6948 return rcStrict;
6949}
6950
6951
6952/**
6953 * Implements INVD.
6954 */
6955IEM_CIMPL_DEF_0(iemCImpl_invd)
6956{
6957 if (IEM_GET_CPL(pVCpu) != 0)
6958 {
6959 Log(("invd: CPL != 0 -> #GP(0)\n"));
6960 return iemRaiseGeneralProtectionFault0(pVCpu);
6961 }
6962
6963 if (!IEM_IS_IN_GUEST(pVCpu))
6964 { /* probable */ }
6965 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6966 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_INVD, cbInstr);
6967 else
6968 IEM_SVM_CHECK_INSTR_INTERCEPT(pVCpu, SVM_CTRL_INTERCEPT_INVD, SVM_EXIT_INVD, 0, 0, cbInstr);
6969
6970 /* We currently take no action here. */
6971 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6972}
6973
6974
6975/**
6976 * Implements WBINVD.
6977 */
6978IEM_CIMPL_DEF_0(iemCImpl_wbinvd)
6979{
6980 if (IEM_GET_CPL(pVCpu) != 0)
6981 {
6982 Log(("wbinvd: CPL != 0 -> #GP(0)\n"));
6983 return iemRaiseGeneralProtectionFault0(pVCpu);
6984 }
6985
6986 if (!IEM_IS_IN_GUEST(pVCpu))
6987 { /* probable */ }
6988 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6989 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_WBINVD, cbInstr);
6990 else
6991 IEM_SVM_CHECK_INSTR_INTERCEPT(pVCpu, SVM_CTRL_INTERCEPT_WBINVD, SVM_EXIT_WBINVD, 0, 0, cbInstr);
6992
6993 /* We currently take no action here. */
6994 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6995}
6996
6997
6998/** Opcode 0x0f 0xaa. */
6999IEM_CIMPL_DEF_0(iemCImpl_rsm)
7000{
7001 IEM_SVM_CHECK_INSTR_INTERCEPT(pVCpu, SVM_CTRL_INTERCEPT_RSM, SVM_EXIT_RSM, 0, 0, cbInstr);
7002 NOREF(cbInstr);
7003 return iemRaiseUndefinedOpcode(pVCpu);
7004}
7005
7006
7007/**
7008 * Implements RDTSC.
7009 */
7010IEM_CIMPL_DEF_0(iemCImpl_rdtsc)
7011{
7012 /*
7013 * Check preconditions.
7014 */
7015 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fTsc)
7016 return iemRaiseUndefinedOpcode(pVCpu);
7017
7018 if (IEM_GET_CPL(pVCpu) != 0)
7019 {
7020 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
7021 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_TSD)
7022 {
7023 Log(("rdtsc: CR4.TSD and CPL=%u -> #GP(0)\n", IEM_GET_CPL(pVCpu)));
7024 return iemRaiseGeneralProtectionFault0(pVCpu);
7025 }
7026 }
7027
7028 if (!IEM_IS_IN_GUEST(pVCpu))
7029 { /* probable */ }
7030 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7031 && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_RDTSC_EXIT))
7032 {
7033 Log(("rdtsc: Guest intercept -> VM-exit\n"));
7034 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_RDTSC, cbInstr);
7035 }
7036 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_RDTSC))
7037 {
7038 Log(("rdtsc: Guest intercept -> #VMEXIT\n"));
7039 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7040 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_RDTSC, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7041 }
7042
7043 /*
7044 * Do the job.
7045 */
7046 uint64_t uTicks = TMCpuTickGet(pVCpu);
7047#if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
7048 uTicks = CPUMApplyNestedGuestTscOffset(pVCpu, uTicks);
7049#endif
7050 pVCpu->cpum.GstCtx.rax = RT_LO_U32(uTicks);
7051 pVCpu->cpum.GstCtx.rdx = RT_HI_U32(uTicks);
7052 pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX); /* For IEMExecDecodedRdtsc. */
7053 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7054}
7055
7056
7057/**
7058 * Implements RDTSC.
7059 */
7060IEM_CIMPL_DEF_0(iemCImpl_rdtscp)
7061{
7062 /*
7063 * Check preconditions.
7064 */
7065 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fRdTscP)
7066 return iemRaiseUndefinedOpcode(pVCpu);
7067
7068 if (RT_LIKELY( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7069 || IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_RDTSCP)))
7070 { /* likely */ }
7071 else
7072 {
7073 Log(("rdtscp: Not enabled for VMX non-root mode -> #UD\n"));
7074 return iemRaiseUndefinedOpcode(pVCpu);
7075 }
7076
7077 if (IEM_GET_CPL(pVCpu) != 0)
7078 {
7079 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
7080 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_TSD)
7081 {
7082 Log(("rdtscp: CR4.TSD and CPL=%u -> #GP(0)\n", IEM_GET_CPL(pVCpu)));
7083 return iemRaiseGeneralProtectionFault0(pVCpu);
7084 }
7085 }
7086
7087 if (!IEM_IS_IN_GUEST(pVCpu))
7088 { /* probable */ }
7089 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7090 && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_RDTSC_EXIT))
7091 {
7092 Log(("rdtscp: Guest intercept -> VM-exit\n"));
7093 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_RDTSCP, cbInstr);
7094 }
7095 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_RDTSCP))
7096 {
7097 Log(("rdtscp: Guest intercept -> #VMEXIT\n"));
7098 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7099 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_RDTSCP, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7100 }
7101
7102 /*
7103 * Do the job.
7104 * Query the MSR first in case of trips to ring-3.
7105 */
7106 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_TSC_AUX);
7107 VBOXSTRICTRC rcStrict = CPUMQueryGuestMsr(pVCpu, MSR_K8_TSC_AUX, &pVCpu->cpum.GstCtx.rcx);
7108 if (rcStrict == VINF_SUCCESS)
7109 {
7110 /* Low dword of the TSC_AUX msr only. */
7111 pVCpu->cpum.GstCtx.rcx &= UINT32_C(0xffffffff);
7112
7113 uint64_t uTicks = TMCpuTickGet(pVCpu);
7114#if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
7115 uTicks = CPUMApplyNestedGuestTscOffset(pVCpu, uTicks);
7116#endif
7117 pVCpu->cpum.GstCtx.rax = RT_LO_U32(uTicks);
7118 pVCpu->cpum.GstCtx.rdx = RT_HI_U32(uTicks);
7119 pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX); /* For IEMExecDecodedRdtscp. */
7120 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7121 }
7122 return rcStrict;
7123}
7124
7125
7126/**
7127 * Implements RDPMC.
7128 */
7129IEM_CIMPL_DEF_0(iemCImpl_rdpmc)
7130{
7131 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
7132
7133 if ( IEM_GET_CPL(pVCpu) != 0
7134 && !(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PCE))
7135 return iemRaiseGeneralProtectionFault0(pVCpu);
7136
7137 if (!IEM_IS_IN_GUEST(pVCpu))
7138 { /* probable */ }
7139 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7140 && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_RDPMC_EXIT))
7141 {
7142 Log(("rdpmc: Guest intercept -> VM-exit\n"));
7143 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_RDPMC, cbInstr);
7144 }
7145 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_RDPMC))
7146 {
7147 Log(("rdpmc: Guest intercept -> #VMEXIT\n"));
7148 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7149 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_RDPMC, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7150 }
7151
7152 /** @todo Emulate performance counters, for now just return 0. */
7153 pVCpu->cpum.GstCtx.rax = 0;
7154 pVCpu->cpum.GstCtx.rdx = 0;
7155 pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX);
7156 /** @todo We should trigger a \#GP here if the CPU doesn't support the index in
7157 * ecx but see @bugref{3472}! */
7158
7159 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7160}
7161
7162
7163/**
7164 * Implements RDMSR.
7165 */
7166IEM_CIMPL_DEF_0(iemCImpl_rdmsr)
7167{
7168 /*
7169 * Check preconditions.
7170 */
7171 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fMsr)
7172 return iemRaiseUndefinedOpcode(pVCpu);
7173 if (IEM_GET_CPL(pVCpu) != 0)
7174 return iemRaiseGeneralProtectionFault0(pVCpu);
7175
7176 /*
7177 * Check nested-guest intercepts.
7178 */
7179 if (!IEM_IS_IN_GUEST(pVCpu))
7180 { /* probable */ }
7181#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7182 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
7183 {
7184 if (iemVmxIsRdmsrWrmsrInterceptSet(pVCpu, VMX_EXIT_RDMSR, pVCpu->cpum.GstCtx.ecx))
7185 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_RDMSR, cbInstr);
7186 }
7187#endif
7188#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
7189 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_MSR_PROT))
7190 {
7191 VBOXSTRICTRC rcStrict = iemSvmHandleMsrIntercept(pVCpu, pVCpu->cpum.GstCtx.ecx, false /* fWrite */, cbInstr);
7192 if (rcStrict == VINF_SVM_VMEXIT)
7193 return VINF_SUCCESS;
7194 if (rcStrict != VINF_SVM_INTERCEPT_NOT_ACTIVE)
7195 {
7196 Log(("IEM: SVM intercepted rdmsr(%#x) failed. rc=%Rrc\n", pVCpu->cpum.GstCtx.ecx, VBOXSTRICTRC_VAL(rcStrict)));
7197 return rcStrict;
7198 }
7199 }
7200#endif
7201
7202 /*
7203 * Do the job.
7204 */
7205 RTUINT64U uValue;
7206 /** @todo make CPUMAllMsrs.cpp import the necessary MSR state. */
7207 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_ALL_MSRS);
7208
7209 VBOXSTRICTRC rcStrict = CPUMQueryGuestMsr(pVCpu, pVCpu->cpum.GstCtx.ecx, &uValue.u);
7210 if (rcStrict == VINF_SUCCESS)
7211 {
7212 pVCpu->cpum.GstCtx.rax = uValue.s.Lo;
7213 pVCpu->cpum.GstCtx.rdx = uValue.s.Hi;
7214 pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX);
7215
7216 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7217 }
7218
7219#ifndef IN_RING3
7220 /* Deferred to ring-3. */
7221 if (rcStrict == VINF_CPUM_R3_MSR_READ)
7222 {
7223 Log(("IEM: rdmsr(%#x) -> ring-3\n", pVCpu->cpum.GstCtx.ecx));
7224 return rcStrict;
7225 }
7226#endif
7227
7228 /* Often a unimplemented MSR or MSR bit, so worth logging. */
7229 if (pVCpu->iem.s.cLogRelRdMsr < 32)
7230 {
7231 pVCpu->iem.s.cLogRelRdMsr++;
7232 LogRel(("IEM: rdmsr(%#x) -> #GP(0)\n", pVCpu->cpum.GstCtx.ecx));
7233 }
7234 else
7235 Log(( "IEM: rdmsr(%#x) -> #GP(0)\n", pVCpu->cpum.GstCtx.ecx));
7236 AssertMsgReturn(rcStrict == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)), VERR_IPE_UNEXPECTED_STATUS);
7237 return iemRaiseGeneralProtectionFault0(pVCpu);
7238}
7239
7240
7241/**
7242 * Implements WRMSR.
7243 */
7244IEM_CIMPL_DEF_0(iemCImpl_wrmsr)
7245{
7246 /*
7247 * Check preconditions.
7248 */
7249 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fMsr)
7250 return iemRaiseUndefinedOpcode(pVCpu);
7251 if (IEM_GET_CPL(pVCpu) != 0)
7252 return iemRaiseGeneralProtectionFault0(pVCpu);
7253
7254 RTUINT64U uValue;
7255 uValue.s.Lo = pVCpu->cpum.GstCtx.eax;
7256 uValue.s.Hi = pVCpu->cpum.GstCtx.edx;
7257
7258 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
7259
7260 /** @todo make CPUMAllMsrs.cpp import the necessary MSR state. */
7261 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_ALL_MSRS);
7262
7263 /*
7264 * Check nested-guest intercepts.
7265 */
7266 if (!IEM_IS_IN_GUEST(pVCpu))
7267 { /* probable */ }
7268#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7269 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
7270 {
7271 if (iemVmxIsRdmsrWrmsrInterceptSet(pVCpu, VMX_EXIT_WRMSR, idMsr))
7272 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_WRMSR, cbInstr);
7273 }
7274#endif
7275#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
7276 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_MSR_PROT))
7277 {
7278 VBOXSTRICTRC rcStrict = iemSvmHandleMsrIntercept(pVCpu, idMsr, true /* fWrite */, cbInstr);
7279 if (rcStrict == VINF_SVM_VMEXIT)
7280 return VINF_SUCCESS;
7281 if (rcStrict != VINF_SVM_INTERCEPT_NOT_ACTIVE)
7282 {
7283 Log(("IEM: SVM intercepted rdmsr(%#x) failed. rc=%Rrc\n", idMsr, VBOXSTRICTRC_VAL(rcStrict)));
7284 return rcStrict;
7285 }
7286 }
7287#endif
7288
7289 /*
7290 * Do the job.
7291 */
7292 VBOXSTRICTRC rcStrict = CPUMSetGuestMsr(pVCpu, idMsr, uValue.u);
7293 if (rcStrict == VINF_SUCCESS)
7294 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7295
7296#ifndef IN_RING3
7297 /* Deferred to ring-3. */
7298 if (rcStrict == VINF_CPUM_R3_MSR_WRITE)
7299 {
7300 Log(("IEM: wrmsr(%#x) -> ring-3\n", idMsr));
7301 return rcStrict;
7302 }
7303#endif
7304
7305 /* Often a unimplemented MSR or MSR bit, so worth logging. */
7306 if (pVCpu->iem.s.cLogRelWrMsr < 32)
7307 {
7308 pVCpu->iem.s.cLogRelWrMsr++;
7309 LogRel(("IEM: wrmsr(%#x,%#x`%08x) -> #GP(0)\n", idMsr, uValue.s.Hi, uValue.s.Lo));
7310 }
7311 else
7312 Log(( "IEM: wrmsr(%#x,%#x`%08x) -> #GP(0)\n", idMsr, uValue.s.Hi, uValue.s.Lo));
7313 AssertMsgReturn(rcStrict == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)), VERR_IPE_UNEXPECTED_STATUS);
7314 return iemRaiseGeneralProtectionFault0(pVCpu);
7315}
7316
7317
7318/**
7319 * Implements 'IN eAX, port'.
7320 *
7321 * @param u16Port The source port.
7322 * @param cbReg The register size.
7323 * @param bImmAndEffAddrMode Bit 7: Whether the port was specified through an
7324 * immediate operand or the implicit DX register.
7325 * Bits 3-0: Effective address mode.
7326 */
7327IEM_CIMPL_DEF_3(iemCImpl_in, uint16_t, u16Port, uint8_t, cbReg, uint8_t, bImmAndEffAddrMode)
7328{
7329 /*
7330 * GCM intercept.
7331 *
7332 * This must be placed before the IOPL check as the mesa driver intercept
7333 * would otherwise trigger a #GP(0).
7334 */
7335 if (!IEM_IS_IN_GUEST(pVCpu) && GCMIsInterceptingIOPortRead(pVCpu, u16Port, cbReg))
7336 {
7337 VBOXSTRICTRC rcStrict = GCMInterceptedIOPortRead(pVCpu, &pVCpu->cpum.GstCtx, u16Port, cbReg);
7338 if (rcStrict == VINF_GCM_HANDLED_ADVANCE_RIP || rcStrict == VINF_GCM_HANDLED)
7339 {
7340 Log(("iemCImpl_in: u16Port=%#x cbReg=%d was handled by GCMIOPortRead (%d)\n", u16Port, cbReg, VBOXSTRICTRC_VAL(rcStrict)));
7341 if (rcStrict == VINF_GCM_HANDLED_ADVANCE_RIP)
7342 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7343 else
7344 rcStrict = VINF_SUCCESS;
7345 return rcStrict;
7346 }
7347 Assert(rcStrict == VERR_GCM_NOT_HANDLED);
7348 }
7349
7350 /*
7351 * CPL check
7352 */
7353 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pVCpu, u16Port, cbReg);
7354 if (rcStrict != VINF_SUCCESS)
7355 return rcStrict;
7356
7357 if (!IEM_IS_IN_GUEST(pVCpu))
7358 { /* probable */ }
7359
7360 /*
7361 * Check VMX nested-guest IO intercept.
7362 */
7363#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7364 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
7365 {
7366 rcStrict = iemVmxVmexitInstrIo(pVCpu, VMXINSTRID_IO_IN, u16Port, RT_BOOL(bImmAndEffAddrMode & 0x80), cbReg, cbInstr);
7367 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
7368 return rcStrict;
7369 }
7370#endif
7371
7372 /*
7373 * Check SVM nested-guest IO intercept.
7374 */
7375#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
7376 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_IOIO_PROT))
7377 {
7378 uint8_t cAddrSizeBits;
7379 switch (bImmAndEffAddrMode & 0xf)
7380 {
7381 case IEMMODE_16BIT: cAddrSizeBits = 16; break;
7382 case IEMMODE_32BIT: cAddrSizeBits = 32; break;
7383 case IEMMODE_64BIT: cAddrSizeBits = 64; break;
7384 IEM_NOT_REACHED_DEFAULT_CASE_RET();
7385 }
7386 rcStrict = iemSvmHandleIOIntercept(pVCpu, u16Port, SVMIOIOTYPE_IN, cbReg, cAddrSizeBits, 0 /* N/A - iEffSeg */,
7387 false /* fRep */, false /* fStrIo */, cbInstr);
7388 if (rcStrict == VINF_SVM_VMEXIT)
7389 return VINF_SUCCESS;
7390 if (rcStrict != VINF_SVM_INTERCEPT_NOT_ACTIVE)
7391 {
7392 Log(("iemCImpl_in: iemSvmHandleIOIntercept failed (u16Port=%#x, cbReg=%u) rc=%Rrc\n", u16Port, cbReg,
7393 VBOXSTRICTRC_VAL(rcStrict)));
7394 return rcStrict;
7395 }
7396 }
7397#endif
7398#if !defined(VBOX_WITH_NESTED_HWVIRT_VMX) && !defined(VBOX_WITH_NESTED_HWVIRT_SVM)
7399 RT_NOREF(bImmAndEffAddrMode);
7400#endif
7401
7402 /*
7403 * Perform the I/O.
7404 */
7405 PVMCC const pVM = pVCpu->CTX_SUFF(pVM);
7406 uint32_t u32Value = 0;
7407 rcStrict = IOMIOPortRead(pVM, pVCpu, u16Port, &u32Value, cbReg);
7408 if (IOM_SUCCESS(rcStrict))
7409 {
7410 switch (cbReg)
7411 {
7412 case 1: pVCpu->cpum.GstCtx.al = (uint8_t)u32Value; break;
7413 case 2: pVCpu->cpum.GstCtx.ax = (uint16_t)u32Value; break;
7414 case 4: pVCpu->cpum.GstCtx.rax = u32Value; break;
7415 default: AssertFailedReturn(VERR_IEM_IPE_3);
7416 }
7417
7418 pVCpu->iem.s.cPotentialExits++;
7419 if (rcStrict != VINF_SUCCESS)
7420 iemSetPassUpStatus(pVCpu, rcStrict);
7421
7422 /*
7423 * Check for I/O breakpoints before we complete the instruction.
7424 */
7425 uint32_t const fDr7 = pVCpu->cpum.GstCtx.dr[7];
7426 if (RT_UNLIKELY( ( ( (fDr7 & X86_DR7_ENABLED_MASK)
7427 && X86_DR7_ANY_RW_IO(fDr7)
7428 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_DE))
7429 || pVM->dbgf.ro.cEnabledHwIoBreakpoints > 0)
7430 && rcStrict == VINF_SUCCESS))
7431 {
7432 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3 | CPUMCTX_EXTRN_DR6);
7433 pVCpu->cpum.GstCtx.eflags.uBoth |= DBGFBpCheckIo2(pVM, pVCpu, u16Port, cbReg);
7434 }
7435
7436 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7437 }
7438
7439 return rcStrict;
7440}
7441
7442
7443/**
7444 * Implements 'IN eAX, DX'.
7445 *
7446 * @param cbReg The register size.
7447 * @param enmEffAddrMode Effective address mode.
7448 */
7449IEM_CIMPL_DEF_2(iemCImpl_in_eAX_DX, uint8_t, cbReg, IEMMODE, enmEffAddrMode)
7450{
7451 return IEM_CIMPL_CALL_3(iemCImpl_in, pVCpu->cpum.GstCtx.dx, cbReg, 0 /* fImm */ | enmEffAddrMode);
7452}
7453
7454
7455/**
7456 * Implements 'OUT port, eAX'.
7457 *
7458 * @param u16Port The destination port.
7459 * @param cbReg The register size.
7460 * @param bImmAndEffAddrMode Bit 7: Whether the port was specified through an
7461 * immediate operand or the implicit DX register.
7462 * Bits 3-0: Effective address mode.
7463 */
7464IEM_CIMPL_DEF_3(iemCImpl_out, uint16_t, u16Port, uint8_t, cbReg, uint8_t, bImmAndEffAddrMode)
7465{
7466 /*
7467 * CPL check
7468 */
7469 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pVCpu, u16Port, cbReg);
7470 if (rcStrict != VINF_SUCCESS)
7471 return rcStrict;
7472
7473 if (!IEM_IS_IN_GUEST(pVCpu))
7474 { /* probable */ }
7475
7476 /*
7477 * Check VMX nested-guest I/O intercept.
7478 */
7479#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7480 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
7481 {
7482 rcStrict = iemVmxVmexitInstrIo(pVCpu, VMXINSTRID_IO_OUT, u16Port, RT_BOOL(bImmAndEffAddrMode & 0x80), cbReg, cbInstr);
7483 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
7484 return rcStrict;
7485 }
7486#endif
7487
7488 /*
7489 * Check SVM nested-guest I/O intercept.
7490 */
7491#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
7492 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_IOIO_PROT))
7493 {
7494 uint8_t cAddrSizeBits;
7495 switch (bImmAndEffAddrMode & 0xf)
7496 {
7497 case IEMMODE_16BIT: cAddrSizeBits = 16; break;
7498 case IEMMODE_32BIT: cAddrSizeBits = 32; break;
7499 case IEMMODE_64BIT: cAddrSizeBits = 64; break;
7500 IEM_NOT_REACHED_DEFAULT_CASE_RET();
7501 }
7502 rcStrict = iemSvmHandleIOIntercept(pVCpu, u16Port, SVMIOIOTYPE_OUT, cbReg, cAddrSizeBits, 0 /* N/A - iEffSeg */,
7503 false /* fRep */, false /* fStrIo */, cbInstr);
7504 if (rcStrict == VINF_SVM_VMEXIT)
7505 return VINF_SUCCESS;
7506 if (rcStrict != VINF_SVM_INTERCEPT_NOT_ACTIVE)
7507 {
7508 Log(("iemCImpl_out: iemSvmHandleIOIntercept failed (u16Port=%#x, cbReg=%u) rc=%Rrc\n", u16Port, cbReg,
7509 VBOXSTRICTRC_VAL(rcStrict)));
7510 return rcStrict;
7511 }
7512 }
7513#endif
7514#if !defined(VBOX_WITH_NESTED_HWVIRT_VMX) && !defined(VBOX_WITH_NESTED_HWVIRT_SVM)
7515 RT_NOREF(bImmAndEffAddrMode);
7516#endif
7517
7518 /*
7519 * Perform the I/O.
7520 */
7521 PVMCC const pVM = pVCpu->CTX_SUFF(pVM);
7522 uint32_t u32Value;
7523 switch (cbReg)
7524 {
7525 case 1: u32Value = pVCpu->cpum.GstCtx.al; break;
7526 case 2: u32Value = pVCpu->cpum.GstCtx.ax; break;
7527 case 4: u32Value = pVCpu->cpum.GstCtx.eax; break;
7528 default: AssertFailedReturn(VERR_IEM_IPE_4);
7529 }
7530 rcStrict = IOMIOPortWrite(pVM, pVCpu, u16Port, u32Value, cbReg);
7531 if (IOM_SUCCESS(rcStrict))
7532 {
7533 pVCpu->iem.s.cPotentialExits++;
7534 if (rcStrict != VINF_SUCCESS)
7535 iemSetPassUpStatus(pVCpu, rcStrict);
7536
7537 /*
7538 * Check for I/O breakpoints before we complete the instruction.
7539 */
7540 uint32_t const fDr7 = pVCpu->cpum.GstCtx.dr[7];
7541 if (RT_UNLIKELY( ( ( (fDr7 & X86_DR7_ENABLED_MASK)
7542 && X86_DR7_ANY_RW_IO(fDr7)
7543 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_DE))
7544 || pVM->dbgf.ro.cEnabledHwIoBreakpoints > 0)
7545 && rcStrict == VINF_SUCCESS))
7546 {
7547 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3 | CPUMCTX_EXTRN_DR6);
7548 pVCpu->cpum.GstCtx.eflags.uBoth |= DBGFBpCheckIo2(pVM, pVCpu, u16Port, cbReg);
7549 }
7550
7551 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7552 }
7553 return rcStrict;
7554}
7555
7556
7557/**
7558 * Implements 'OUT DX, eAX'.
7559 *
7560 * @param cbReg The register size.
7561 * @param enmEffAddrMode Effective address mode.
7562 */
7563IEM_CIMPL_DEF_2(iemCImpl_out_DX_eAX, uint8_t, cbReg, IEMMODE, enmEffAddrMode)
7564{
7565 return IEM_CIMPL_CALL_3(iemCImpl_out, pVCpu->cpum.GstCtx.dx, cbReg, 0 /* fImm */ | enmEffAddrMode);
7566}
7567
7568
7569/**
7570 * Implements 'CLI'.
7571 */
7572IEM_CIMPL_DEF_0(iemCImpl_cli)
7573{
7574 uint32_t fEfl = IEMMISC_GET_EFL(pVCpu);
7575#ifdef LOG_ENABLED
7576 uint32_t const fEflOld = fEfl;
7577#endif
7578
7579 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4);
7580 if (pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE)
7581 {
7582 uint8_t const uIopl = X86_EFL_GET_IOPL(fEfl);
7583 if (!(fEfl & X86_EFL_VM))
7584 {
7585 if (IEM_GET_CPL(pVCpu) <= uIopl)
7586 fEfl &= ~X86_EFL_IF;
7587 else if ( IEM_GET_CPL(pVCpu) == 3
7588 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PVI) )
7589 fEfl &= ~X86_EFL_VIF;
7590 else
7591 return iemRaiseGeneralProtectionFault0(pVCpu);
7592 }
7593 /* V8086 */
7594 else if (uIopl == 3)
7595 fEfl &= ~X86_EFL_IF;
7596 else if ( uIopl < 3
7597 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_VME) )
7598 fEfl &= ~X86_EFL_VIF;
7599 else
7600 return iemRaiseGeneralProtectionFault0(pVCpu);
7601 }
7602 /* real mode */
7603 else
7604 fEfl &= ~X86_EFL_IF;
7605
7606 /* Commit. */
7607 IEMMISC_SET_EFL(pVCpu, fEfl);
7608 VBOXSTRICTRC const rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7609 Log2(("CLI: %#x -> %#x\n", fEflOld, fEfl));
7610 return rcStrict;
7611}
7612
7613
7614/**
7615 * Implements 'STI'.
7616 */
7617IEM_CIMPL_DEF_0(iemCImpl_sti)
7618{
7619 uint32_t fEfl = IEMMISC_GET_EFL(pVCpu);
7620 uint32_t const fEflOld = fEfl;
7621
7622 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4);
7623 if (pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE)
7624 {
7625 uint8_t const uIopl = X86_EFL_GET_IOPL(fEfl);
7626 if (!(fEfl & X86_EFL_VM))
7627 {
7628 if (IEM_GET_CPL(pVCpu) <= uIopl)
7629 fEfl |= X86_EFL_IF;
7630 else if ( IEM_GET_CPL(pVCpu) == 3
7631 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PVI)
7632 && !(fEfl & X86_EFL_VIP) )
7633 fEfl |= X86_EFL_VIF;
7634 else
7635 return iemRaiseGeneralProtectionFault0(pVCpu);
7636 }
7637 /* V8086 */
7638 else if (uIopl == 3)
7639 fEfl |= X86_EFL_IF;
7640 else if ( uIopl < 3
7641 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_VME)
7642 && !(fEfl & X86_EFL_VIP) )
7643 fEfl |= X86_EFL_VIF;
7644 else
7645 return iemRaiseGeneralProtectionFault0(pVCpu);
7646 }
7647 /* real mode */
7648 else
7649 fEfl |= X86_EFL_IF;
7650
7651 /*
7652 * Commit.
7653 *
7654 * Note! Setting the shadow interrupt flag must be done after RIP updating.
7655 */
7656 IEMMISC_SET_EFL(pVCpu, fEfl);
7657 VBOXSTRICTRC const rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7658 if (!(fEflOld & X86_EFL_IF) && (fEfl & X86_EFL_IF))
7659 {
7660 /** @todo only set it the shadow flag if it was clear before? */
7661 CPUMSetInInterruptShadowSti(&pVCpu->cpum.GstCtx);
7662 }
7663 pVCpu->iem.s.fTbCurInstrIsSti = true;
7664 Log2(("STI: %#x -> %#x\n", fEflOld, fEfl));
7665 return rcStrict;
7666}
7667
7668
7669/**
7670 * Implements 'HLT'.
7671 */
7672IEM_CIMPL_DEF_0(iemCImpl_hlt)
7673{
7674 if (IEM_GET_CPL(pVCpu) != 0)
7675 return iemRaiseGeneralProtectionFault0(pVCpu);
7676
7677 if (!IEM_IS_IN_GUEST(pVCpu))
7678 { /* probable */ }
7679 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7680 && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_HLT_EXIT))
7681 {
7682 Log2(("hlt: Guest intercept -> VM-exit\n"));
7683 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_HLT, cbInstr);
7684 }
7685 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_HLT))
7686 {
7687 Log2(("hlt: Guest intercept -> #VMEXIT\n"));
7688 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7689 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_HLT, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7690 }
7691
7692 /** @todo finish: This ASSUMES that iemRegAddToRipAndFinishingClearingRF won't
7693 * be returning any status codes relating to non-guest events being raised, as
7694 * we'll mess up the guest HALT otherwise. */
7695 VBOXSTRICTRC rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7696 if (rcStrict == VINF_SUCCESS)
7697 rcStrict = VINF_EM_HALT;
7698 return rcStrict;
7699}
7700
7701
7702/**
7703 * Implements 'MONITOR'.
7704 */
7705IEM_CIMPL_DEF_1(iemCImpl_monitor, uint8_t, iEffSeg)
7706{
7707 /*
7708 * Permission checks.
7709 */
7710 if (IEM_GET_CPL(pVCpu) != 0)
7711 {
7712 Log2(("monitor: CPL != 0\n"));
7713 return iemRaiseUndefinedOpcode(pVCpu); /** @todo MSR[0xC0010015].MonMwaitUserEn if we care. */
7714 }
7715 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fMonitorMWait)
7716 {
7717 Log2(("monitor: Not in CPUID\n"));
7718 return iemRaiseUndefinedOpcode(pVCpu);
7719 }
7720
7721 /*
7722 * Check VMX guest-intercept.
7723 * This should be considered a fault-like VM-exit.
7724 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
7725 */
7726 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7727 || !IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_MONITOR_EXIT))
7728 { /* probable */ }
7729 else
7730 {
7731 Log2(("monitor: Guest intercept -> #VMEXIT\n"));
7732 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_MONITOR, cbInstr);
7733 }
7734
7735 /*
7736 * Gather the operands and validate them.
7737 */
7738 RTGCPTR GCPtrMem = IEM_IS_64BIT_CODE(pVCpu) ? pVCpu->cpum.GstCtx.rax : pVCpu->cpum.GstCtx.eax;
7739 uint32_t uEcx = pVCpu->cpum.GstCtx.ecx;
7740 uint32_t uEdx = pVCpu->cpum.GstCtx.edx;
7741/** @todo Test whether EAX or ECX is processed first, i.e. do we get \#PF or
7742 * \#GP first. */
7743 if (uEcx != 0)
7744 {
7745 Log2(("monitor rax=%RX64, ecx=%RX32, edx=%RX32; ECX != 0 -> #GP(0)\n", GCPtrMem, uEcx, uEdx)); NOREF(uEdx);
7746 return iemRaiseGeneralProtectionFault0(pVCpu);
7747 }
7748
7749 VBOXSTRICTRC rcStrict = iemMemApplySegment(pVCpu, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, iEffSeg, 1, &GCPtrMem);
7750 if (rcStrict != VINF_SUCCESS)
7751 return rcStrict;
7752
7753 RTGCPHYS GCPhysMem;
7754 /** @todo access size */
7755 rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, GCPtrMem, 1, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, &GCPhysMem);
7756 if (rcStrict != VINF_SUCCESS)
7757 return rcStrict;
7758
7759 if (!IEM_IS_IN_GUEST(pVCpu))
7760 { /* probable */ }
7761#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7762 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7763 && IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_VIRT_APIC_ACCESS))
7764 {
7765 /*
7766 * MONITOR does not access the memory, just monitors the address. However,
7767 * if the address falls in the APIC-access page, the address monitored must
7768 * instead be the corresponding address in the virtual-APIC page.
7769 *
7770 * See Intel spec. 29.4.4 "Instruction-Specific Considerations".
7771 */
7772 rcStrict = iemVmxVirtApicAccessUnused(pVCpu, &GCPhysMem, 1, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA);
7773 if ( rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE
7774 && rcStrict != VINF_VMX_MODIFIES_BEHAVIOR)
7775 return rcStrict;
7776 }
7777#endif
7778 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_MONITOR))
7779 {
7780 Log2(("monitor: Guest intercept -> #VMEXIT\n"));
7781 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7782 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_MONITOR, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7783 }
7784
7785 /*
7786 * Call EM to prepare the monitor/wait.
7787 */
7788 rcStrict = EMMonitorWaitPrepare(pVCpu, pVCpu->cpum.GstCtx.rax, pVCpu->cpum.GstCtx.rcx, pVCpu->cpum.GstCtx.rdx, GCPhysMem);
7789 Assert(rcStrict == VINF_SUCCESS);
7790 if (rcStrict == VINF_SUCCESS)
7791 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7792 return rcStrict;
7793}
7794
7795
7796/**
7797 * Implements 'MWAIT'.
7798 */
7799IEM_CIMPL_DEF_0(iemCImpl_mwait)
7800{
7801 /*
7802 * Permission checks.
7803 */
7804 if (IEM_GET_CPL(pVCpu) != 0)
7805 {
7806 Log2(("mwait: CPL != 0\n"));
7807 /** @todo MSR[0xC0010015].MonMwaitUserEn if we care. (Remember to check
7808 * EFLAGS.VM then.) */
7809 return iemRaiseUndefinedOpcode(pVCpu);
7810 }
7811 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fMonitorMWait)
7812 {
7813 Log2(("mwait: Not in CPUID\n"));
7814 return iemRaiseUndefinedOpcode(pVCpu);
7815 }
7816
7817 /* Check VMX nested-guest intercept. */
7818 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7819 || !IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_MWAIT_EXIT))
7820 { /* probable */ }
7821 else
7822 IEM_VMX_VMEXIT_MWAIT_RET(pVCpu, EMMonitorIsArmed(pVCpu), cbInstr);
7823
7824 /*
7825 * Gather the operands and validate them.
7826 */
7827 uint32_t const uEax = pVCpu->cpum.GstCtx.eax;
7828 uint32_t const uEcx = pVCpu->cpum.GstCtx.ecx;
7829 if (uEcx != 0)
7830 {
7831 /* Only supported extension is break on IRQ when IF=0. */
7832 if (uEcx > 1)
7833 {
7834 Log2(("mwait eax=%RX32, ecx=%RX32; ECX > 1 -> #GP(0)\n", uEax, uEcx));
7835 return iemRaiseGeneralProtectionFault0(pVCpu);
7836 }
7837 uint32_t fMWaitFeatures = 0;
7838 uint32_t uIgnore = 0;
7839 CPUMGetGuestCpuId(pVCpu, 5, 0, -1 /*f64BitMode*/, &uIgnore, &uIgnore, &fMWaitFeatures, &uIgnore);
7840 if ( (fMWaitFeatures & (X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
7841 != (X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
7842 {
7843 Log2(("mwait eax=%RX32, ecx=%RX32; break-on-IRQ-IF=0 extension not enabled -> #GP(0)\n", uEax, uEcx));
7844 return iemRaiseGeneralProtectionFault0(pVCpu);
7845 }
7846
7847#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7848 /*
7849 * If the interrupt-window exiting control is set or a virtual-interrupt is pending
7850 * for delivery; and interrupts are disabled the processor does not enter its
7851 * mwait state but rather passes control to the next instruction.
7852 *
7853 * See Intel spec. 25.3 "Changes to Instruction Behavior In VMX Non-root Operation".
7854 */
7855 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7856 || pVCpu->cpum.GstCtx.eflags.Bits.u1IF)
7857 { /* probable */ }
7858 else if ( IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_INT_WINDOW_EXIT)
7859 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST))
7860 /** @todo finish: check up this out after we move int window stuff out of the
7861 * run loop and into the instruction finishing logic here. */
7862 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7863#endif
7864 }
7865
7866 /*
7867 * Check SVM nested-guest mwait intercepts.
7868 */
7869 if (!IEM_IS_IN_GUEST(pVCpu))
7870 { /* probable */ }
7871 else if ( IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_MWAIT_ARMED)
7872 && EMMonitorIsArmed(pVCpu))
7873 {
7874 Log2(("mwait: Guest intercept (monitor hardware armed) -> #VMEXIT\n"));
7875 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7876 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_MWAIT_ARMED, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7877 }
7878 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_MWAIT))
7879 {
7880 Log2(("mwait: Guest intercept -> #VMEXIT\n"));
7881 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7882 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_MWAIT, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7883 }
7884
7885 /*
7886 * Call EM to prepare the monitor/wait.
7887 *
7888 * This will return VINF_EM_HALT. If there the trap flag is set, we may
7889 * override it when executing iemRegAddToRipAndFinishingClearingRF ASSUMING
7890 * that will only return guest related events.
7891 */
7892 VBOXSTRICTRC rcStrict = EMMonitorWaitPerform(pVCpu, uEax, uEcx);
7893
7894 /** @todo finish: This needs more thinking as we should suppress internal
7895 * debugger events here, or we'll bugger up the guest state even more than we
7896 * alread do around VINF_EM_HALT. */
7897 VBOXSTRICTRC rcStrict2 = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7898 if (rcStrict2 != VINF_SUCCESS)
7899 {
7900 Log2(("mwait: %Rrc (perform) -> %Rrc (finish)!\n", VBOXSTRICTRC_VAL(rcStrict), VBOXSTRICTRC_VAL(rcStrict2) ));
7901 rcStrict = rcStrict2;
7902 }
7903
7904 return rcStrict;
7905}
7906
7907
7908/**
7909 * Implements 'SWAPGS'.
7910 */
7911IEM_CIMPL_DEF_0(iemCImpl_swapgs)
7912{
7913 Assert(IEM_IS_64BIT_CODE(pVCpu)); /* Caller checks this. */
7914
7915 /*
7916 * Permission checks.
7917 */
7918 if (IEM_GET_CPL(pVCpu) != 0)
7919 {
7920 Log2(("swapgs: CPL != 0\n"));
7921 return iemRaiseUndefinedOpcode(pVCpu);
7922 }
7923
7924 /*
7925 * Do the job.
7926 */
7927 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_GS);
7928 uint64_t uOtherGsBase = pVCpu->cpum.GstCtx.msrKERNELGSBASE;
7929 pVCpu->cpum.GstCtx.msrKERNELGSBASE = pVCpu->cpum.GstCtx.gs.u64Base;
7930 pVCpu->cpum.GstCtx.gs.u64Base = uOtherGsBase;
7931
7932 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7933}
7934
7935
7936#ifndef VBOX_WITHOUT_CPUID_HOST_CALL
7937/**
7938 * Handles a CPUID call.
7939 */
7940static VBOXSTRICTRC iemCpuIdVBoxCall(PVMCPUCC pVCpu, uint32_t iFunction,
7941 uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)
7942{
7943 switch (iFunction)
7944 {
7945 case VBOX_CPUID_FN_ID:
7946 LogFlow(("iemCpuIdVBoxCall: VBOX_CPUID_FN_ID\n"));
7947 *pEax = VBOX_CPUID_RESP_ID_EAX;
7948 *pEbx = VBOX_CPUID_RESP_ID_EBX;
7949 *pEcx = VBOX_CPUID_RESP_ID_ECX;
7950 *pEdx = VBOX_CPUID_RESP_ID_EDX;
7951 break;
7952
7953 case VBOX_CPUID_FN_LOG:
7954 {
7955 CPUM_IMPORT_EXTRN_RET(pVCpu, CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX | CPUMCTX_EXTRN_RSI
7956 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
7957
7958 /* Validate input. */
7959 uint32_t cchToLog = *pEdx;
7960 if (cchToLog <= _2M)
7961 {
7962 uint32_t const uLogPicker = *pEbx;
7963 if (uLogPicker <= 1)
7964 {
7965 /* Resolve the logger. */
7966 PRTLOGGER const pLogger = !uLogPicker
7967 ? RTLogDefaultInstanceEx(UINT32_MAX) : RTLogRelGetDefaultInstanceEx(UINT32_MAX);
7968 if (pLogger)
7969 {
7970 /* Copy over the data: */
7971 RTGCPTR GCPtrSrc = pVCpu->cpum.GstCtx.rsi;
7972 while (cchToLog > 0)
7973 {
7974 uint32_t cbToMap = GUEST_PAGE_SIZE - (GCPtrSrc & GUEST_PAGE_OFFSET_MASK);
7975 if (cbToMap > cchToLog)
7976 cbToMap = cchToLog;
7977 /** @todo Extend iemMemMap to allowing page size accessing and avoid 7
7978 * unnecessary calls & iterations per pages. */
7979 if (cbToMap > 512)
7980 cbToMap = 512;
7981 uint8_t bUnmapInfo;
7982 void *pvSrc = NULL;
7983 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvSrc, &bUnmapInfo, cbToMap,
7984 UINT8_MAX, GCPtrSrc, IEM_ACCESS_DATA_R, 0);
7985 if (rcStrict == VINF_SUCCESS)
7986 {
7987 RTLogBulkNestedWrite(pLogger, (const char *)pvSrc, cbToMap, "Gst:");
7988 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
7989 AssertRCSuccessReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
7990 }
7991 else
7992 {
7993 Log(("iemCpuIdVBoxCall: %Rrc at %RGp LB %#x\n", VBOXSTRICTRC_VAL(rcStrict), GCPtrSrc, cbToMap));
7994 return rcStrict;
7995 }
7996
7997 /* Advance. */
7998 pVCpu->cpum.GstCtx.rsi = GCPtrSrc += cbToMap;
7999 *pEdx = cchToLog -= cbToMap;
8000 }
8001 *pEax = VINF_SUCCESS;
8002 }
8003 else
8004 *pEax = (uint32_t)VERR_NOT_FOUND;
8005 }
8006 else
8007 *pEax = (uint32_t)VERR_NOT_FOUND;
8008 }
8009 else
8010 *pEax = (uint32_t)VERR_TOO_MUCH_DATA;
8011 *pEdx = VBOX_CPUID_RESP_GEN_EDX;
8012 *pEcx = VBOX_CPUID_RESP_GEN_ECX;
8013 *pEbx = VBOX_CPUID_RESP_GEN_EBX;
8014 break;
8015 }
8016
8017 default:
8018 LogFlow(("iemCpuIdVBoxCall: Invalid function %#x (%#x, %#x)\n", iFunction, *pEbx, *pEdx));
8019 *pEax = (uint32_t)VERR_INVALID_FUNCTION;
8020 *pEbx = (uint32_t)VERR_INVALID_FUNCTION;
8021 *pEcx = (uint32_t)VERR_INVALID_FUNCTION;
8022 *pEdx = (uint32_t)VERR_INVALID_FUNCTION;
8023 break;
8024 }
8025 return VINF_SUCCESS;
8026}
8027#endif /* VBOX_WITHOUT_CPUID_HOST_CALL */
8028
8029/**
8030 * Implements 'CPUID'.
8031 */
8032IEM_CIMPL_DEF_0(iemCImpl_cpuid)
8033{
8034 if (!IEM_IS_IN_GUEST(pVCpu))
8035 { /* probable */ }
8036 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8037 {
8038 Log2(("cpuid: Guest intercept -> VM-exit\n"));
8039 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_CPUID, cbInstr);
8040 }
8041 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_CPUID))
8042 {
8043 Log2(("cpuid: Guest intercept -> #VMEXIT\n"));
8044 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
8045 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_CPUID, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
8046 }
8047
8048
8049 uint32_t const uEax = pVCpu->cpum.GstCtx.eax;
8050 uint32_t const uEcx = pVCpu->cpum.GstCtx.ecx;
8051
8052#ifndef VBOX_WITHOUT_CPUID_HOST_CALL
8053 /*
8054 * CPUID host call backdoor.
8055 */
8056 if ( uEax == VBOX_CPUID_REQ_EAX_FIXED
8057 && (uEcx & VBOX_CPUID_REQ_ECX_FIXED_MASK) == VBOX_CPUID_REQ_ECX_FIXED
8058 && pVCpu->CTX_SUFF(pVM)->iem.s.fCpuIdHostCall)
8059 {
8060 VBOXSTRICTRC rcStrict = iemCpuIdVBoxCall(pVCpu, uEcx & VBOX_CPUID_REQ_ECX_FN_MASK,
8061 &pVCpu->cpum.GstCtx.eax, &pVCpu->cpum.GstCtx.ebx,
8062 &pVCpu->cpum.GstCtx.ecx, &pVCpu->cpum.GstCtx.edx);
8063 if (rcStrict != VINF_SUCCESS)
8064 return rcStrict;
8065 }
8066 /*
8067 * Regular CPUID.
8068 */
8069 else
8070#endif
8071 CPUMGetGuestCpuId(pVCpu, uEax, uEcx, pVCpu->cpum.GstCtx.cs.Attr.n.u1Long,
8072 &pVCpu->cpum.GstCtx.eax, &pVCpu->cpum.GstCtx.ebx, &pVCpu->cpum.GstCtx.ecx, &pVCpu->cpum.GstCtx.edx);
8073
8074 pVCpu->cpum.GstCtx.rax &= UINT32_C(0xffffffff);
8075 pVCpu->cpum.GstCtx.rbx &= UINT32_C(0xffffffff);
8076 pVCpu->cpum.GstCtx.rcx &= UINT32_C(0xffffffff);
8077 pVCpu->cpum.GstCtx.rdx &= UINT32_C(0xffffffff);
8078 pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
8079
8080 pVCpu->iem.s.cPotentialExits++;
8081 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8082}
8083
8084
8085/**
8086 * Implements 'AAD'.
8087 *
8088 * @param bImm The immediate operand.
8089 */
8090IEM_CIMPL_DEF_1(iemCImpl_aad, uint8_t, bImm)
8091{
8092 uint16_t const ax = pVCpu->cpum.GstCtx.ax;
8093 uint8_t const al = (uint8_t)ax + (uint8_t)(ax >> 8) * bImm;
8094 pVCpu->cpum.GstCtx.ax = al;
8095 iemHlpUpdateArithEFlagsU8(pVCpu, al,
8096 X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF,
8097 X86_EFL_OF | X86_EFL_AF | X86_EFL_CF);
8098
8099 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8100}
8101
8102
8103/**
8104 * Implements 'AAM'.
8105 *
8106 * @param bImm The immediate operand. Cannot be 0.
8107 */
8108IEM_CIMPL_DEF_1(iemCImpl_aam, uint8_t, bImm)
8109{
8110 Assert(bImm != 0); /* #DE on 0 is handled in the decoder. */
8111
8112 uint16_t const ax = pVCpu->cpum.GstCtx.ax;
8113 uint8_t const al = (uint8_t)ax % bImm;
8114 uint8_t const ah = (uint8_t)ax / bImm;
8115 pVCpu->cpum.GstCtx.ax = (ah << 8) + al;
8116 iemHlpUpdateArithEFlagsU8(pVCpu, al,
8117 X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF,
8118 X86_EFL_OF | X86_EFL_AF | X86_EFL_CF);
8119
8120 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8121}
8122
8123
8124/**
8125 * Implements 'DAA'.
8126 */
8127IEM_CIMPL_DEF_0(iemCImpl_daa)
8128{
8129 uint8_t const al = pVCpu->cpum.GstCtx.al;
8130 bool const fCarry = pVCpu->cpum.GstCtx.eflags.Bits.u1CF;
8131
8132 if ( pVCpu->cpum.GstCtx.eflags.Bits.u1AF
8133 || (al & 0xf) >= 10)
8134 {
8135 pVCpu->cpum.GstCtx.al = al + 6;
8136 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 1;
8137 }
8138 else
8139 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 0;
8140
8141 if (al >= 0x9a || fCarry)
8142 {
8143 pVCpu->cpum.GstCtx.al += 0x60;
8144 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8145 }
8146 else
8147 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 0;
8148
8149 iemHlpUpdateArithEFlagsU8(pVCpu, pVCpu->cpum.GstCtx.al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
8150 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8151}
8152
8153
8154/**
8155 * Implements 'DAS'.
8156 */
8157IEM_CIMPL_DEF_0(iemCImpl_das)
8158{
8159 uint8_t const uInputAL = pVCpu->cpum.GstCtx.al;
8160 bool const fCarry = pVCpu->cpum.GstCtx.eflags.Bits.u1CF;
8161
8162 if ( pVCpu->cpum.GstCtx.eflags.Bits.u1AF
8163 || (uInputAL & 0xf) >= 10)
8164 {
8165 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 1;
8166 if (uInputAL < 6)
8167 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8168 pVCpu->cpum.GstCtx.al = uInputAL - 6;
8169 }
8170 else
8171 {
8172 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 0;
8173 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 0;
8174 }
8175
8176 if (uInputAL >= 0x9a || fCarry)
8177 {
8178 pVCpu->cpum.GstCtx.al -= 0x60;
8179 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8180 }
8181
8182 iemHlpUpdateArithEFlagsU8(pVCpu, pVCpu->cpum.GstCtx.al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
8183 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8184}
8185
8186
8187/**
8188 * Implements 'AAA'.
8189 */
8190IEM_CIMPL_DEF_0(iemCImpl_aaa)
8191{
8192 if (IEM_IS_GUEST_CPU_AMD(pVCpu))
8193 {
8194 if ( pVCpu->cpum.GstCtx.eflags.Bits.u1AF
8195 || (pVCpu->cpum.GstCtx.ax & 0xf) >= 10)
8196 {
8197 pVCpu->cpum.GstCtx.eflags.uBoth = iemAImpl_add_u16(pVCpu->cpum.GstCtx.eflags.uBoth, &pVCpu->cpum.GstCtx.ax, 0x106);
8198 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 1;
8199 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8200 }
8201 else
8202 {
8203 iemHlpUpdateArithEFlagsU16(pVCpu, pVCpu->cpum.GstCtx.ax, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
8204 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 0;
8205 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 0;
8206 }
8207 pVCpu->cpum.GstCtx.ax &= UINT16_C(0xff0f);
8208 }
8209 else
8210 {
8211 if ( pVCpu->cpum.GstCtx.eflags.Bits.u1AF
8212 || (pVCpu->cpum.GstCtx.ax & 0xf) >= 10)
8213 {
8214 pVCpu->cpum.GstCtx.ax += UINT16_C(0x106);
8215 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 1;
8216 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8217 }
8218 else
8219 {
8220 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 0;
8221 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 0;
8222 }
8223 pVCpu->cpum.GstCtx.ax &= UINT16_C(0xff0f);
8224 iemHlpUpdateArithEFlagsU8(pVCpu, pVCpu->cpum.GstCtx.al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
8225 }
8226
8227 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8228}
8229
8230
8231/**
8232 * Implements 'AAS'.
8233 */
8234IEM_CIMPL_DEF_0(iemCImpl_aas)
8235{
8236 if (IEM_IS_GUEST_CPU_AMD(pVCpu))
8237 {
8238 if ( pVCpu->cpum.GstCtx.eflags.Bits.u1AF
8239 || (pVCpu->cpum.GstCtx.ax & 0xf) >= 10)
8240 {
8241 pVCpu->cpum.GstCtx.eflags.uBoth = iemAImpl_sub_u16(pVCpu->cpum.GstCtx.eflags.uBoth, &pVCpu->cpum.GstCtx.ax, 0x106);
8242 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 1;
8243 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8244 }
8245 else
8246 {
8247 iemHlpUpdateArithEFlagsU16(pVCpu, pVCpu->cpum.GstCtx.ax, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
8248 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 0;
8249 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 0;
8250 }
8251 pVCpu->cpum.GstCtx.ax &= UINT16_C(0xff0f);
8252 }
8253 else
8254 {
8255 if ( pVCpu->cpum.GstCtx.eflags.Bits.u1AF
8256 || (pVCpu->cpum.GstCtx.ax & 0xf) >= 10)
8257 {
8258 pVCpu->cpum.GstCtx.ax -= UINT16_C(0x106);
8259 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 1;
8260 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8261 }
8262 else
8263 {
8264 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 0;
8265 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 0;
8266 }
8267 pVCpu->cpum.GstCtx.ax &= UINT16_C(0xff0f);
8268 iemHlpUpdateArithEFlagsU8(pVCpu, pVCpu->cpum.GstCtx.al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
8269 }
8270
8271 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8272}
8273
8274
8275/**
8276 * Implements the 16-bit version of 'BOUND'.
8277 *
8278 * @note We have separate 16-bit and 32-bit variants of this function due to
8279 * the decoder using unsigned parameters, whereas we want signed one to
8280 * do the job. This is significant for a recompiler.
8281 */
8282IEM_CIMPL_DEF_3(iemCImpl_bound_16, int16_t, idxArray, int16_t, idxLowerBound, int16_t, idxUpperBound)
8283{
8284 /*
8285 * Check if the index is inside the bounds, otherwise raise #BR.
8286 */
8287 if ( idxArray >= idxLowerBound
8288 && idxArray <= idxUpperBound)
8289 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8290 return iemRaiseBoundRangeExceeded(pVCpu);
8291}
8292
8293
8294/**
8295 * Implements the 32-bit version of 'BOUND'.
8296 */
8297IEM_CIMPL_DEF_3(iemCImpl_bound_32, int32_t, idxArray, int32_t, idxLowerBound, int32_t, idxUpperBound)
8298{
8299 /*
8300 * Check if the index is inside the bounds, otherwise raise #BR.
8301 */
8302 if ( idxArray >= idxLowerBound
8303 && idxArray <= idxUpperBound)
8304 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8305 return iemRaiseBoundRangeExceeded(pVCpu);
8306}
8307
8308
8309
8310/*
8311 * Instantiate the various string operation combinations.
8312 */
8313#define OP_SIZE 8
8314#define ADDR_SIZE 16
8315#include "IEMAllCImplStrInstr.cpp.h"
8316#define OP_SIZE 8
8317#define ADDR_SIZE 32
8318#include "IEMAllCImplStrInstr.cpp.h"
8319#define OP_SIZE 8
8320#define ADDR_SIZE 64
8321#include "IEMAllCImplStrInstr.cpp.h"
8322
8323#define OP_SIZE 16
8324#define ADDR_SIZE 16
8325#include "IEMAllCImplStrInstr.cpp.h"
8326#define OP_SIZE 16
8327#define ADDR_SIZE 32
8328#include "IEMAllCImplStrInstr.cpp.h"
8329#define OP_SIZE 16
8330#define ADDR_SIZE 64
8331#include "IEMAllCImplStrInstr.cpp.h"
8332
8333#define OP_SIZE 32
8334#define ADDR_SIZE 16
8335#include "IEMAllCImplStrInstr.cpp.h"
8336#define OP_SIZE 32
8337#define ADDR_SIZE 32
8338#include "IEMAllCImplStrInstr.cpp.h"
8339#define OP_SIZE 32
8340#define ADDR_SIZE 64
8341#include "IEMAllCImplStrInstr.cpp.h"
8342
8343#define OP_SIZE 64
8344#define ADDR_SIZE 32
8345#include "IEMAllCImplStrInstr.cpp.h"
8346#define OP_SIZE 64
8347#define ADDR_SIZE 64
8348#include "IEMAllCImplStrInstr.cpp.h"
8349
8350
8351/**
8352 * Implements 'XGETBV'.
8353 */
8354IEM_CIMPL_DEF_0(iemCImpl_xgetbv)
8355{
8356 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
8357 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSXSAVE)
8358 {
8359 uint32_t uEcx = pVCpu->cpum.GstCtx.ecx;
8360 switch (uEcx)
8361 {
8362 case 0:
8363 break;
8364
8365 case 1: /** @todo Implement XCR1 support. */
8366 default:
8367 Log(("xgetbv ecx=%RX32 -> #GP(0)\n", uEcx));
8368 return iemRaiseGeneralProtectionFault0(pVCpu);
8369
8370 }
8371 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_XCRx);
8372 pVCpu->cpum.GstCtx.rax = RT_LO_U32(pVCpu->cpum.GstCtx.aXcr[uEcx]);
8373 pVCpu->cpum.GstCtx.rdx = RT_HI_U32(pVCpu->cpum.GstCtx.aXcr[uEcx]);
8374
8375 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8376 }
8377 Log(("xgetbv CR4.OSXSAVE=0 -> UD\n"));
8378 return iemRaiseUndefinedOpcode(pVCpu);
8379}
8380
8381
8382/**
8383 * Implements 'XSETBV'.
8384 */
8385IEM_CIMPL_DEF_0(iemCImpl_xsetbv)
8386{
8387 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSXSAVE)
8388 {
8389 /** @todo explain why this happens before the CPL check. */
8390 if (!IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_XSETBV))
8391 { /* probable */ }
8392 else
8393 {
8394 Log2(("xsetbv: Guest intercept -> #VMEXIT\n"));
8395 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
8396 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_XSETBV, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
8397 }
8398
8399 if (IEM_GET_CPL(pVCpu) == 0)
8400 {
8401 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_XCRx);
8402
8403 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8404 { /* probable */ }
8405 else
8406 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_XSETBV, cbInstr);
8407
8408 uint32_t uEcx = pVCpu->cpum.GstCtx.ecx;
8409 uint64_t uNewValue = RT_MAKE_U64(pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.edx);
8410 switch (uEcx)
8411 {
8412 case 0:
8413 {
8414 int rc = CPUMSetGuestXcr0(pVCpu, uNewValue);
8415 if (rc == VINF_SUCCESS)
8416 break;
8417 Assert(rc == VERR_CPUM_RAISE_GP_0);
8418 Log(("xsetbv ecx=%RX32 (newvalue=%RX64) -> #GP(0)\n", uEcx, uNewValue));
8419 return iemRaiseGeneralProtectionFault0(pVCpu);
8420 }
8421
8422 case 1: /** @todo Implement XCR1 support. */
8423 default:
8424 Log(("xsetbv ecx=%RX32 (newvalue=%RX64) -> #GP(0)\n", uEcx, uNewValue));
8425 return iemRaiseGeneralProtectionFault0(pVCpu);
8426
8427 }
8428
8429 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8430 }
8431
8432 Log(("xsetbv cpl=%u -> GP(0)\n", IEM_GET_CPL(pVCpu)));
8433 return iemRaiseGeneralProtectionFault0(pVCpu);
8434 }
8435 Log(("xsetbv CR4.OSXSAVE=0 -> UD\n"));
8436 return iemRaiseUndefinedOpcode(pVCpu);
8437}
8438
8439#ifndef RT_ARCH_ARM64
8440# ifdef IN_RING3
8441
8442/** Argument package for iemCImpl_cmpxchg16b_fallback_rendezvous_callback. */
8443struct IEMCIMPLCX16ARGS
8444{
8445 PRTUINT128U pu128Dst;
8446 PRTUINT128U pu128RaxRdx;
8447 PRTUINT128U pu128RbxRcx;
8448 uint32_t *pEFlags;
8449# ifdef VBOX_STRICT
8450 uint32_t cCalls;
8451# endif
8452};
8453
8454/**
8455 * @callback_method_impl{FNVMMEMTRENDEZVOUS,
8456 * Worker for iemCImpl_cmpxchg16b_fallback_rendezvous}
8457 */
8458static DECLCALLBACK(VBOXSTRICTRC) iemCImpl_cmpxchg16b_fallback_rendezvous_callback(PVM pVM, PVMCPUCC pVCpu, void *pvUser)
8459{
8460 RT_NOREF(pVM, pVCpu);
8461 struct IEMCIMPLCX16ARGS *pArgs = (struct IEMCIMPLCX16ARGS *)pvUser;
8462# ifdef VBOX_STRICT
8463 Assert(pArgs->cCalls == 0);
8464 pArgs->cCalls++;
8465# endif
8466
8467 iemAImpl_cmpxchg16b_fallback(pArgs->pu128Dst, pArgs->pu128RaxRdx, pArgs->pu128RbxRcx, pArgs->pEFlags);
8468 return VINF_SUCCESS;
8469}
8470
8471# endif /* IN_RING3 */
8472
8473/**
8474 * Implements 'CMPXCHG16B' fallback using rendezvous.
8475 */
8476IEM_CIMPL_DEF_5(iemCImpl_cmpxchg16b_fallback_rendezvous, PRTUINT128U, pu128Dst, PRTUINT128U, pu128RaxRdx,
8477 PRTUINT128U, pu128RbxRcx, uint32_t *, pEFlags, uint8_t, bUnmapInfo)
8478{
8479# ifdef IN_RING3
8480 struct IEMCIMPLCX16ARGS Args;
8481 Args.pu128Dst = pu128Dst;
8482 Args.pu128RaxRdx = pu128RaxRdx;
8483 Args.pu128RbxRcx = pu128RbxRcx;
8484 Args.pEFlags = pEFlags;
8485# ifdef VBOX_STRICT
8486 Args.cCalls = 0;
8487# endif
8488 VBOXSTRICTRC rcStrict = VMMR3EmtRendezvous(pVCpu->CTX_SUFF(pVM), VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE,
8489 iemCImpl_cmpxchg16b_fallback_rendezvous_callback, &Args);
8490 Assert(Args.cCalls == 1);
8491 if (rcStrict == VINF_SUCCESS)
8492 {
8493 /* Duplicated tail code. */
8494 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
8495 if (rcStrict == VINF_SUCCESS)
8496 {
8497 pVCpu->cpum.GstCtx.eflags.u = *pEFlags; /* IEM_MC_COMMIT_EFLAGS */
8498 if (!(*pEFlags & X86_EFL_ZF))
8499 {
8500 pVCpu->cpum.GstCtx.rax = pu128RaxRdx->s.Lo;
8501 pVCpu->cpum.GstCtx.rdx = pu128RaxRdx->s.Hi;
8502 }
8503 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8504 }
8505 }
8506 return rcStrict;
8507# else
8508 RT_NOREF(pVCpu, cbInstr, pu128Dst, pu128RaxRdx, pu128RbxRcx, pEFlags, bUnmapInfo);
8509 return VERR_IEM_ASPECT_NOT_IMPLEMENTED; /* This should get us to ring-3 for now. Should perhaps be replaced later. */
8510# endif
8511}
8512
8513#endif /* RT_ARCH_ARM64 */
8514
8515/**
8516 * Implements 'CLFLUSH' and 'CLFLUSHOPT'.
8517 *
8518 * This is implemented in C because it triggers a load like behaviour without
8519 * actually reading anything. Since that's not so common, it's implemented
8520 * here.
8521 *
8522 * @param iEffSeg The effective segment.
8523 * @param GCPtrEff The address of the image.
8524 */
8525IEM_CIMPL_DEF_2(iemCImpl_clflush_clflushopt, uint8_t, iEffSeg, RTGCPTR, GCPtrEff)
8526{
8527 /*
8528 * Pretend to do a load w/o reading (see also iemCImpl_monitor and iemMemMap).
8529 */
8530 VBOXSTRICTRC rcStrict = iemMemApplySegment(pVCpu, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, iEffSeg, 1, &GCPtrEff);
8531 if (rcStrict == VINF_SUCCESS)
8532 {
8533 RTGCPHYS GCPhysMem;
8534 /** @todo access size. */
8535 rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, GCPtrEff, 1, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, &GCPhysMem);
8536 if (rcStrict == VINF_SUCCESS)
8537 {
8538#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8539 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
8540 || !IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_VIRT_APIC_ACCESS))
8541 { /* probable */ }
8542 else
8543 {
8544 /*
8545 * CLFLUSH/CLFLUSHOPT does not access the memory, but flushes the cache-line
8546 * that contains the address. However, if the address falls in the APIC-access
8547 * page, the address flushed must instead be the corresponding address in the
8548 * virtual-APIC page.
8549 *
8550 * See Intel spec. 29.4.4 "Instruction-Specific Considerations".
8551 */
8552 rcStrict = iemVmxVirtApicAccessUnused(pVCpu, &GCPhysMem, 1, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA);
8553 if ( rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE
8554 && rcStrict != VINF_VMX_MODIFIES_BEHAVIOR)
8555 return rcStrict;
8556 }
8557#endif
8558 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8559 }
8560 }
8561
8562 return rcStrict;
8563}
8564
8565
8566/**
8567 * Implements 'FINIT' and 'FNINIT'.
8568 *
8569 * @param fCheckXcpts Whether to check for umasked pending exceptions or
8570 * not.
8571 */
8572IEM_CIMPL_DEF_1(iemCImpl_finit, bool, fCheckXcpts)
8573{
8574 /*
8575 * Exceptions.
8576 */
8577 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
8578 if (pVCpu->cpum.GstCtx.cr0 & (X86_CR0_EM | X86_CR0_TS))
8579 return iemRaiseDeviceNotAvailable(pVCpu);
8580
8581 iemFpuActualizeStateForChange(pVCpu);
8582 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_X87);
8583
8584 /* FINIT: Raise #MF on pending exception(s): */
8585 if (fCheckXcpts && (pVCpu->cpum.GstCtx.XState.x87.FSW & X86_FSW_ES))
8586 return iemRaiseMathFault(pVCpu);
8587
8588 /*
8589 * Reset the state.
8590 */
8591 PX86XSAVEAREA pXState = &pVCpu->cpum.GstCtx.XState;
8592
8593 /* Rotate the stack to account for changed TOS. */
8594 iemFpuRotateStackSetTop(&pXState->x87, 0);
8595
8596 pXState->x87.FCW = 0x37f;
8597 pXState->x87.FSW = 0;
8598 pXState->x87.FTW = 0x00; /* 0 - empty. */
8599 /** @todo Intel says the instruction and data pointers are not cleared on
8600 * 387, presume that 8087 and 287 doesn't do so either. */
8601 /** @todo test this stuff. */
8602 if (IEM_GET_TARGET_CPU(pVCpu) > IEMTARGETCPU_386)
8603 {
8604 pXState->x87.FPUDP = 0;
8605 pXState->x87.DS = 0; //??
8606 pXState->x87.Rsrvd2 = 0;
8607 pXState->x87.FPUIP = 0;
8608 pXState->x87.CS = 0; //??
8609 pXState->x87.Rsrvd1 = 0;
8610 }
8611 pXState->x87.FOP = 0;
8612
8613 iemHlpUsedFpu(pVCpu);
8614 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8615}
8616
8617
8618/**
8619 * Implements 'FXSAVE'.
8620 *
8621 * @param iEffSeg The effective segment.
8622 * @param GCPtrEff The address of the image.
8623 * @param enmEffOpSize The operand size (only REX.W really matters).
8624 */
8625IEM_CIMPL_DEF_3(iemCImpl_fxsave, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
8626{
8627 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX);
8628
8629 /** @todo check out bugref{1529} and AMD behaviour */
8630
8631 /*
8632 * Raise exceptions.
8633 */
8634 if (pVCpu->cpum.GstCtx.cr0 & (X86_CR0_TS | X86_CR0_EM))
8635 return iemRaiseDeviceNotAvailable(pVCpu);
8636
8637 /*
8638 * Access the memory.
8639 */
8640 uint8_t bUnmapInfo;
8641 void *pvMem512;
8642 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMem512, &bUnmapInfo, 512,
8643 iEffSeg, GCPtrEff, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE,
8644 15 | IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_GP_OR_AC);
8645 if (rcStrict != VINF_SUCCESS)
8646 return rcStrict;
8647 PX86FXSTATE pDst = (PX86FXSTATE)pvMem512;
8648 PCX86FXSTATE pSrc = &pVCpu->cpum.GstCtx.XState.x87;
8649
8650 /*
8651 * Store the registers.
8652 */
8653 /** @todo CPU/VM detection possible! If CR4.OSFXSR=0 MXCSR it's
8654 * implementation specific whether MXCSR and XMM0-XMM7 are saved. */
8655
8656 /* common for all formats */
8657 pDst->FCW = pSrc->FCW;
8658 pDst->FSW = pSrc->FSW;
8659 pDst->FTW = pSrc->FTW & UINT16_C(0xff);
8660 pDst->FOP = pSrc->FOP;
8661 pDst->MXCSR = pSrc->MXCSR;
8662 pDst->MXCSR_MASK = CPUMGetGuestMxCsrMask(pVCpu->CTX_SUFF(pVM));
8663 for (uint32_t i = 0; i < RT_ELEMENTS(pDst->aRegs); i++)
8664 {
8665 /** @todo Testcase: What actually happens to the 6 reserved bytes? I'm clearing
8666 * them for now... */
8667 pDst->aRegs[i].au32[0] = pSrc->aRegs[i].au32[0];
8668 pDst->aRegs[i].au32[1] = pSrc->aRegs[i].au32[1];
8669 pDst->aRegs[i].au32[2] = pSrc->aRegs[i].au32[2] & UINT32_C(0xffff);
8670 pDst->aRegs[i].au32[3] = 0;
8671 }
8672
8673 /* FPU IP, CS, DP and DS. */
8674 pDst->FPUIP = pSrc->FPUIP;
8675 pDst->CS = pSrc->CS;
8676 pDst->FPUDP = pSrc->FPUDP;
8677 pDst->DS = pSrc->DS;
8678 if (enmEffOpSize == IEMMODE_64BIT)
8679 {
8680 /* Save upper 16-bits of FPUIP (IP:CS:Rsvd1) and FPUDP (DP:DS:Rsvd2). */
8681 pDst->Rsrvd1 = pSrc->Rsrvd1;
8682 pDst->Rsrvd2 = pSrc->Rsrvd2;
8683 }
8684 else
8685 {
8686 pDst->Rsrvd1 = 0;
8687 pDst->Rsrvd2 = 0;
8688 }
8689
8690 /* XMM registers. Skipped in 64-bit CPL0 if EFER.FFXSR (AMD only) is set. */
8691 if ( !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_FFXSR)
8692 || !IEM_IS_64BIT_CODE(pVCpu)
8693 || IEM_GET_CPL(pVCpu) != 0)
8694 {
8695 uint32_t cXmmRegs = IEM_IS_64BIT_CODE(pVCpu) ? 16 : 8;
8696 for (uint32_t i = 0; i < cXmmRegs; i++)
8697 pDst->aXMM[i] = pSrc->aXMM[i];
8698 /** @todo Testcase: What happens to the reserved XMM registers? Untouched,
8699 * right? */
8700 }
8701
8702 /*
8703 * Commit the memory.
8704 */
8705 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
8706 if (rcStrict != VINF_SUCCESS)
8707 return rcStrict;
8708
8709 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8710}
8711
8712
8713/**
8714 * Implements 'FXRSTOR'.
8715 *
8716 * @param iEffSeg The effective segment register for @a GCPtrEff.
8717 * @param GCPtrEff The address of the image.
8718 * @param enmEffOpSize The operand size (only REX.W really matters).
8719 */
8720IEM_CIMPL_DEF_3(iemCImpl_fxrstor, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
8721{
8722 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX);
8723
8724 /** @todo check out bugref{1529} and AMD behaviour */
8725
8726 /*
8727 * Raise exceptions.
8728 */
8729 if (pVCpu->cpum.GstCtx.cr0 & (X86_CR0_TS | X86_CR0_EM))
8730 return iemRaiseDeviceNotAvailable(pVCpu);
8731
8732 /*
8733 * Access the memory.
8734 */
8735 uint8_t bUnmapInfo;
8736 void *pvMem512;
8737 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMem512, &bUnmapInfo, 512, iEffSeg, GCPtrEff, IEM_ACCESS_DATA_R,
8738 15 | IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_GP_OR_AC);
8739 if (rcStrict != VINF_SUCCESS)
8740 return rcStrict;
8741 PCX86FXSTATE pSrc = (PCX86FXSTATE)pvMem512;
8742 PX86FXSTATE pDst = &pVCpu->cpum.GstCtx.XState.x87;
8743
8744 /*
8745 * Check the state for stuff which will #GP(0).
8746 */
8747 uint32_t const fMXCSR = pSrc->MXCSR;
8748 uint32_t const fMXCSR_MASK = CPUMGetGuestMxCsrMask(pVCpu->CTX_SUFF(pVM));
8749 if (fMXCSR & ~fMXCSR_MASK)
8750 {
8751 Log(("fxrstor: MXCSR=%#x (MXCSR_MASK=%#x) -> #GP(0)\n", fMXCSR, fMXCSR_MASK));
8752 return iemRaiseGeneralProtectionFault0(pVCpu);
8753 }
8754
8755 /*
8756 * Load the registers.
8757 */
8758 /** @todo CPU/VM detection possible! If CR4.OSFXSR=0 MXCSR it's
8759 * implementation specific whether MXCSR and XMM0-XMM7 are
8760 * restored according to Intel.
8761 * AMD says MXCSR and XMM registers are never loaded if
8762 * CR4.OSFXSR=0.
8763 */
8764
8765 /* common for all formats */
8766 pDst->FCW = pSrc->FCW;
8767 pDst->FSW = pSrc->FSW;
8768 pDst->FTW = pSrc->FTW & UINT16_C(0xff);
8769 pDst->FOP = pSrc->FOP;
8770 pDst->MXCSR = fMXCSR;
8771 /* (MXCSR_MASK is read-only) */
8772 for (uint32_t i = 0; i < RT_ELEMENTS(pSrc->aRegs); i++)
8773 {
8774 pDst->aRegs[i].au32[0] = pSrc->aRegs[i].au32[0];
8775 pDst->aRegs[i].au32[1] = pSrc->aRegs[i].au32[1];
8776 pDst->aRegs[i].au32[2] = pSrc->aRegs[i].au32[2] & UINT32_C(0xffff);
8777 pDst->aRegs[i].au32[3] = 0;
8778 }
8779
8780 /* FPU IP, CS, DP and DS. */
8781 /** @todo AMD says this is only done if FSW.ES is set after loading. */
8782 if (enmEffOpSize == IEMMODE_64BIT)
8783 {
8784 pDst->FPUIP = pSrc->FPUIP;
8785 pDst->CS = pSrc->CS;
8786 pDst->Rsrvd1 = pSrc->Rsrvd1;
8787 pDst->FPUDP = pSrc->FPUDP;
8788 pDst->DS = pSrc->DS;
8789 pDst->Rsrvd2 = pSrc->Rsrvd2;
8790 }
8791 else
8792 {
8793 pDst->FPUIP = pSrc->FPUIP;
8794 pDst->CS = pSrc->CS;
8795 pDst->Rsrvd1 = 0;
8796 pDst->FPUDP = pSrc->FPUDP;
8797 pDst->DS = pSrc->DS;
8798 pDst->Rsrvd2 = 0;
8799 }
8800
8801 /* XMM registers. Skipped in 64-bit CPL0 if EFER.FFXSR (AMD only) is set.
8802 * Does not affect MXCSR, only registers.
8803 */
8804 if ( !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_FFXSR)
8805 || !IEM_IS_64BIT_CODE(pVCpu)
8806 || IEM_GET_CPL(pVCpu) != 0)
8807 {
8808 uint32_t cXmmRegs = IEM_IS_64BIT_CODE(pVCpu) ? 16 : 8;
8809 for (uint32_t i = 0; i < cXmmRegs; i++)
8810 pDst->aXMM[i] = pSrc->aXMM[i];
8811 }
8812
8813 pDst->FCW &= ~X86_FCW_ZERO_MASK | X86_FCW_IC_MASK; /* Intel 10980xe allows setting the IC bit. Win 3.11 CALC.EXE sets it. */
8814 iemFpuRecalcExceptionStatus(pDst);
8815
8816 if (pDst->FSW & X86_FSW_ES)
8817 Log11(("fxrstor: %04x:%08RX64: loading state with pending FPU exception (FSW=%#x)\n",
8818 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pSrc->FSW));
8819
8820 /*
8821 * Unmap the memory.
8822 */
8823 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
8824 if (rcStrict != VINF_SUCCESS)
8825 return rcStrict;
8826
8827 iemHlpUsedFpu(pVCpu);
8828 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8829}
8830
8831
8832/**
8833 * Implements 'XSAVE'.
8834 *
8835 * @param iEffSeg The effective segment.
8836 * @param GCPtrEff The address of the image.
8837 * @param enmEffOpSize The operand size (only REX.W really matters).
8838 */
8839IEM_CIMPL_DEF_3(iemCImpl_xsave, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
8840{
8841 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx);
8842
8843 /*
8844 * Raise exceptions.
8845 */
8846 if (!(pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSXSAVE))
8847 return iemRaiseUndefinedOpcode(pVCpu);
8848 /* When in VMX non-root mode and XSAVE/XRSTOR is not enabled, it results in #UD. */
8849 if (RT_LIKELY( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
8850 || IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_XSAVES_XRSTORS)))
8851 { /* likely */ }
8852 else
8853 {
8854 Log(("xrstor: Not enabled for nested-guest execution -> #UD\n"));
8855 return iemRaiseUndefinedOpcode(pVCpu);
8856 }
8857 if (pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS)
8858 return iemRaiseDeviceNotAvailable(pVCpu);
8859
8860 /*
8861 * Calc the requested mask.
8862 */
8863 uint64_t const fReqComponents = RT_MAKE_U64(pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.edx) & pVCpu->cpum.GstCtx.aXcr[0];
8864 AssertLogRelReturn(!(fReqComponents & ~(XSAVE_C_X87 | XSAVE_C_SSE | XSAVE_C_YMM)), VERR_IEM_ASPECT_NOT_IMPLEMENTED);
8865 uint64_t const fXInUse = pVCpu->cpum.GstCtx.aXcr[0];
8866
8867/** @todo figure out the exact protocol for the memory access. Currently we
8868 * just need this crap to work halfways to make it possible to test
8869 * AVX instructions. */
8870/** @todo figure out the XINUSE and XMODIFIED */
8871
8872 /*
8873 * Access the x87 memory state.
8874 */
8875 /* The x87+SSE state. */
8876 uint8_t bUnmapInfoMem512;
8877 void *pvMem512;
8878 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMem512, &bUnmapInfoMem512, 512,
8879 iEffSeg, GCPtrEff, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE,
8880 63 | IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_GP_OR_AC);
8881 if (rcStrict != VINF_SUCCESS)
8882 return rcStrict;
8883 PX86FXSTATE pDst = (PX86FXSTATE)pvMem512;
8884 PCX86FXSTATE pSrc = &pVCpu->cpum.GstCtx.XState.x87;
8885
8886 /* The header. */
8887 uint8_t bUnmapInfoHdr;
8888 PX86XSAVEHDR pHdr;
8889 rcStrict = iemMemMap(pVCpu, (void **)&pHdr, &bUnmapInfoHdr, sizeof(pHdr),
8890 iEffSeg, GCPtrEff + 512, IEM_ACCESS_DATA_RW, 0 /* checked above */);
8891 if (rcStrict != VINF_SUCCESS)
8892 return rcStrict;
8893
8894 /*
8895 * Store the X87 state.
8896 */
8897 if (fReqComponents & XSAVE_C_X87)
8898 {
8899 /* common for all formats */
8900 pDst->FCW = pSrc->FCW;
8901 pDst->FSW = pSrc->FSW;
8902 pDst->FTW = pSrc->FTW & UINT16_C(0xff);
8903 pDst->FOP = pSrc->FOP;
8904 pDst->FPUIP = pSrc->FPUIP;
8905 pDst->CS = pSrc->CS;
8906 pDst->FPUDP = pSrc->FPUDP;
8907 pDst->DS = pSrc->DS;
8908 if (enmEffOpSize == IEMMODE_64BIT)
8909 {
8910 /* Save upper 16-bits of FPUIP (IP:CS:Rsvd1) and FPUDP (DP:DS:Rsvd2). */
8911 pDst->Rsrvd1 = pSrc->Rsrvd1;
8912 pDst->Rsrvd2 = pSrc->Rsrvd2;
8913 }
8914 else
8915 {
8916 pDst->Rsrvd1 = 0;
8917 pDst->Rsrvd2 = 0;
8918 }
8919 for (uint32_t i = 0; i < RT_ELEMENTS(pDst->aRegs); i++)
8920 {
8921 /** @todo Testcase: What actually happens to the 6 reserved bytes? I'm clearing
8922 * them for now... */
8923 pDst->aRegs[i].au32[0] = pSrc->aRegs[i].au32[0];
8924 pDst->aRegs[i].au32[1] = pSrc->aRegs[i].au32[1];
8925 pDst->aRegs[i].au32[2] = pSrc->aRegs[i].au32[2] & UINT32_C(0xffff);
8926 pDst->aRegs[i].au32[3] = 0;
8927 }
8928
8929 }
8930
8931 if (fReqComponents & (XSAVE_C_SSE | XSAVE_C_YMM))
8932 {
8933 pDst->MXCSR = pSrc->MXCSR;
8934 pDst->MXCSR_MASK = CPUMGetGuestMxCsrMask(pVCpu->CTX_SUFF(pVM));
8935 }
8936
8937 if (fReqComponents & XSAVE_C_SSE)
8938 {
8939 /* XMM registers. */
8940 uint32_t cXmmRegs = enmEffOpSize == IEMMODE_64BIT ? 16 : 8;
8941 for (uint32_t i = 0; i < cXmmRegs; i++)
8942 pDst->aXMM[i] = pSrc->aXMM[i];
8943 /** @todo Testcase: What happens to the reserved XMM registers? Untouched,
8944 * right? */
8945 }
8946
8947 /* Commit the x87 state bits. (probably wrong) */
8948 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfoMem512);
8949 if (rcStrict != VINF_SUCCESS)
8950 return rcStrict;
8951
8952 /*
8953 * Store AVX state.
8954 */
8955 if (fReqComponents & XSAVE_C_YMM)
8956 {
8957 /** @todo testcase: xsave64 vs xsave32 wrt XSAVE_C_YMM. */
8958 AssertLogRelReturn(pVCpu->cpum.GstCtx.aoffXState[XSAVE_C_YMM_BIT] != UINT16_MAX, VERR_IEM_IPE_9);
8959 uint8_t bUnmapInfoComp;
8960 PCX86XSAVEYMMHI pCompSrc = CPUMCTX_XSAVE_C_PTR(IEM_GET_CTX(pVCpu), XSAVE_C_YMM_BIT, PCX86XSAVEYMMHI);
8961 PX86XSAVEYMMHI pCompDst;
8962 rcStrict = iemMemMap(pVCpu, (void **)&pCompDst, &bUnmapInfoComp, sizeof(*pCompDst), iEffSeg,
8963 GCPtrEff + pVCpu->cpum.GstCtx.aoffXState[XSAVE_C_YMM_BIT],
8964 IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE, 0 /* checked above */);
8965 if (rcStrict != VINF_SUCCESS)
8966 return rcStrict;
8967
8968 uint32_t cXmmRegs = enmEffOpSize == IEMMODE_64BIT ? 16 : 8;
8969 for (uint32_t i = 0; i < cXmmRegs; i++)
8970 pCompDst->aYmmHi[i] = pCompSrc->aYmmHi[i];
8971
8972 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfoComp);
8973 if (rcStrict != VINF_SUCCESS)
8974 return rcStrict;
8975 }
8976
8977 /*
8978 * Update the header.
8979 */
8980 pHdr->bmXState = (pHdr->bmXState & ~fReqComponents)
8981 | (fReqComponents & fXInUse);
8982
8983 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfoHdr);
8984 if (rcStrict != VINF_SUCCESS)
8985 return rcStrict;
8986
8987 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8988}
8989
8990
8991/**
8992 * Implements 'XRSTOR'.
8993 *
8994 * @param iEffSeg The effective segment.
8995 * @param GCPtrEff The address of the image.
8996 * @param enmEffOpSize The operand size (only REX.W really matters).
8997 */
8998IEM_CIMPL_DEF_3(iemCImpl_xrstor, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
8999{
9000 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx);
9001
9002 /*
9003 * Raise exceptions.
9004 */
9005 if (!(pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSXSAVE))
9006 return iemRaiseUndefinedOpcode(pVCpu);
9007 /* When in VMX non-root mode and XSAVE/XRSTOR is not enabled, it results in #UD. */
9008 if (RT_LIKELY( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
9009 || IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_XSAVES_XRSTORS)))
9010 { /* likely */ }
9011 else
9012 {
9013 Log(("xrstor: Not enabled for nested-guest execution -> #UD\n"));
9014 return iemRaiseUndefinedOpcode(pVCpu);
9015 }
9016 if (pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS)
9017 return iemRaiseDeviceNotAvailable(pVCpu);
9018 if (GCPtrEff & 63)
9019 {
9020 /** @todo CPU/VM detection possible! \#AC might not be signal for
9021 * all/any misalignment sizes, intel says its an implementation detail. */
9022 if ( (pVCpu->cpum.GstCtx.cr0 & X86_CR0_AM)
9023 && pVCpu->cpum.GstCtx.eflags.Bits.u1AC
9024 && IEM_GET_CPL(pVCpu) == 3)
9025 return iemRaiseAlignmentCheckException(pVCpu);
9026 return iemRaiseGeneralProtectionFault0(pVCpu);
9027 }
9028
9029/** @todo figure out the exact protocol for the memory access. Currently we
9030 * just need this crap to work halfways to make it possible to test
9031 * AVX instructions. */
9032/** @todo figure out the XINUSE and XMODIFIED */
9033
9034 /*
9035 * Access the x87 memory state.
9036 */
9037 /* The x87+SSE state. */
9038 uint8_t bUnmapInfoMem512;
9039 void *pvMem512;
9040 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMem512, &bUnmapInfoMem512, 512, iEffSeg, GCPtrEff, IEM_ACCESS_DATA_R,
9041 63 | IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_GP_OR_AC);
9042 if (rcStrict != VINF_SUCCESS)
9043 return rcStrict;
9044 PCX86FXSTATE pSrc = (PCX86FXSTATE)pvMem512;
9045 PX86FXSTATE pDst = &pVCpu->cpum.GstCtx.XState.x87;
9046
9047 /*
9048 * Calc the requested mask
9049 */
9050 uint8_t bUnmapInfoHdr;
9051 PX86XSAVEHDR pHdrDst = &pVCpu->cpum.GstCtx.XState.Hdr;
9052 PCX86XSAVEHDR pHdrSrc;
9053 rcStrict = iemMemMap(pVCpu, (void **)&pHdrSrc, &bUnmapInfoHdr, sizeof(*pHdrSrc), iEffSeg, GCPtrEff + 512,
9054 IEM_ACCESS_DATA_R, 0 /* checked above */);
9055 if (rcStrict != VINF_SUCCESS)
9056 return rcStrict;
9057
9058 uint64_t const fReqComponents = RT_MAKE_U64(pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.edx) & pVCpu->cpum.GstCtx.aXcr[0];
9059 AssertLogRelReturn(!(fReqComponents & ~(XSAVE_C_X87 | XSAVE_C_SSE | XSAVE_C_YMM)), VERR_IEM_ASPECT_NOT_IMPLEMENTED);
9060 //uint64_t const fXInUse = pVCpu->cpum.GstCtx.aXcr[0];
9061 uint64_t const fRstorMask = pHdrSrc->bmXState;
9062 uint64_t const fCompMask = pHdrSrc->bmXComp;
9063
9064 AssertLogRelReturn(!(fCompMask & XSAVE_C_X), VERR_IEM_ASPECT_NOT_IMPLEMENTED);
9065
9066 uint32_t const cXmmRegs = enmEffOpSize == IEMMODE_64BIT ? 16 : 8;
9067
9068 /* We won't need this any longer. */
9069 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfoHdr);
9070 if (rcStrict != VINF_SUCCESS)
9071 return rcStrict;
9072
9073 /*
9074 * Load the X87 state.
9075 */
9076 if (fReqComponents & XSAVE_C_X87)
9077 {
9078 if (fRstorMask & XSAVE_C_X87)
9079 {
9080 pDst->FCW = pSrc->FCW;
9081 pDst->FSW = pSrc->FSW;
9082 pDst->FTW = pSrc->FTW & UINT16_C(0xff);
9083 pDst->FOP = pSrc->FOP;
9084 pDst->FPUIP = pSrc->FPUIP;
9085 pDst->CS = pSrc->CS;
9086 pDst->FPUDP = pSrc->FPUDP;
9087 pDst->DS = pSrc->DS;
9088 if (enmEffOpSize == IEMMODE_64BIT)
9089 {
9090 /* Load upper 16-bits of FPUIP (IP:CS:Rsvd1) and FPUDP (DP:DS:Rsvd2). */
9091 pDst->Rsrvd1 = pSrc->Rsrvd1;
9092 pDst->Rsrvd2 = pSrc->Rsrvd2;
9093 }
9094 else
9095 {
9096 pDst->Rsrvd1 = 0;
9097 pDst->Rsrvd2 = 0;
9098 }
9099 for (uint32_t i = 0; i < RT_ELEMENTS(pDst->aRegs); i++)
9100 {
9101 pDst->aRegs[i].au32[0] = pSrc->aRegs[i].au32[0];
9102 pDst->aRegs[i].au32[1] = pSrc->aRegs[i].au32[1];
9103 pDst->aRegs[i].au32[2] = pSrc->aRegs[i].au32[2] & UINT32_C(0xffff);
9104 pDst->aRegs[i].au32[3] = 0;
9105 }
9106
9107 pDst->FCW &= ~X86_FCW_ZERO_MASK | X86_FCW_IC_MASK; /* Intel 10980xe allows setting the IC bit. Win 3.11 CALC.EXE sets it. */
9108 iemFpuRecalcExceptionStatus(pDst);
9109
9110 if (pDst->FSW & X86_FSW_ES)
9111 Log11(("xrstor: %04x:%08RX64: loading state with pending FPU exception (FSW=%#x)\n",
9112 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pSrc->FSW));
9113 }
9114 else
9115 {
9116 pDst->FCW = 0x37f;
9117 pDst->FSW = 0;
9118 pDst->FTW = 0x00; /* 0 - empty. */
9119 pDst->FPUDP = 0;
9120 pDst->DS = 0; //??
9121 pDst->Rsrvd2= 0;
9122 pDst->FPUIP = 0;
9123 pDst->CS = 0; //??
9124 pDst->Rsrvd1= 0;
9125 pDst->FOP = 0;
9126 for (uint32_t i = 0; i < RT_ELEMENTS(pSrc->aRegs); i++)
9127 {
9128 pDst->aRegs[i].au32[0] = 0;
9129 pDst->aRegs[i].au32[1] = 0;
9130 pDst->aRegs[i].au32[2] = 0;
9131 pDst->aRegs[i].au32[3] = 0;
9132 }
9133 }
9134 pHdrDst->bmXState |= XSAVE_C_X87; /* playing safe for now */
9135 }
9136
9137 /* MXCSR */
9138 if (fReqComponents & (XSAVE_C_SSE | XSAVE_C_YMM))
9139 {
9140 if (fRstorMask & (XSAVE_C_SSE | XSAVE_C_YMM))
9141 pDst->MXCSR = pSrc->MXCSR;
9142 else
9143 pDst->MXCSR = 0x1f80;
9144 }
9145
9146 /* XMM registers. */
9147 if (fReqComponents & XSAVE_C_SSE)
9148 {
9149 if (fRstorMask & XSAVE_C_SSE)
9150 {
9151 for (uint32_t i = 0; i < cXmmRegs; i++)
9152 pDst->aXMM[i] = pSrc->aXMM[i];
9153 /** @todo Testcase: What happens to the reserved XMM registers? Untouched,
9154 * right? */
9155 }
9156 else
9157 {
9158 for (uint32_t i = 0; i < cXmmRegs; i++)
9159 {
9160 pDst->aXMM[i].au64[0] = 0;
9161 pDst->aXMM[i].au64[1] = 0;
9162 }
9163 }
9164 pHdrDst->bmXState |= XSAVE_C_SSE; /* playing safe for now */
9165 }
9166
9167 /* Unmap the x87 state bits (so we've don't run out of mapping). */
9168 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfoMem512);
9169 if (rcStrict != VINF_SUCCESS)
9170 return rcStrict;
9171
9172 /*
9173 * Restore AVX state.
9174 */
9175 if (fReqComponents & XSAVE_C_YMM)
9176 {
9177 AssertLogRelReturn(pVCpu->cpum.GstCtx.aoffXState[XSAVE_C_YMM_BIT] != UINT16_MAX, VERR_IEM_IPE_9);
9178 PX86XSAVEYMMHI pCompDst = CPUMCTX_XSAVE_C_PTR(IEM_GET_CTX(pVCpu), XSAVE_C_YMM_BIT, PX86XSAVEYMMHI);
9179
9180 if (fRstorMask & XSAVE_C_YMM)
9181 {
9182 /** @todo testcase: xsave64 vs xsave32 wrt XSAVE_C_YMM. */
9183 uint8_t bUnmapInfoComp;
9184 PCX86XSAVEYMMHI pCompSrc;
9185 rcStrict = iemMemMap(pVCpu, (void **)&pCompSrc, &bUnmapInfoComp, sizeof(*pCompDst),
9186 iEffSeg, GCPtrEff + pVCpu->cpum.GstCtx.aoffXState[XSAVE_C_YMM_BIT],
9187 IEM_ACCESS_DATA_R, 0 /* checked above */);
9188 if (rcStrict != VINF_SUCCESS)
9189 return rcStrict;
9190
9191 for (uint32_t i = 0; i < cXmmRegs; i++)
9192 {
9193 pCompDst->aYmmHi[i].au64[0] = pCompSrc->aYmmHi[i].au64[0];
9194 pCompDst->aYmmHi[i].au64[1] = pCompSrc->aYmmHi[i].au64[1];
9195 }
9196
9197 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfoComp);
9198 if (rcStrict != VINF_SUCCESS)
9199 return rcStrict;
9200 }
9201 else
9202 {
9203 for (uint32_t i = 0; i < cXmmRegs; i++)
9204 {
9205 pCompDst->aYmmHi[i].au64[0] = 0;
9206 pCompDst->aYmmHi[i].au64[1] = 0;
9207 }
9208 }
9209 pHdrDst->bmXState |= XSAVE_C_YMM; /* playing safe for now */
9210 }
9211
9212 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9213}
9214
9215
9216
9217
9218/**
9219 * Implements 'STMXCSR'.
9220 *
9221 * @param iEffSeg The effective segment register for @a GCPtrEff.
9222 * @param GCPtrEff The address of the image.
9223 */
9224IEM_CIMPL_DEF_2(iemCImpl_stmxcsr, uint8_t, iEffSeg, RTGCPTR, GCPtrEff)
9225{
9226 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX);
9227
9228 /*
9229 * Raise exceptions.
9230 */
9231 if ( !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_EM)
9232 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSFXSR))
9233 {
9234 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS))
9235 {
9236 /*
9237 * Do the job.
9238 */
9239 VBOXSTRICTRC rcStrict = iemMemStoreDataU32(pVCpu, iEffSeg, GCPtrEff, pVCpu->cpum.GstCtx.XState.x87.MXCSR);
9240 if (rcStrict == VINF_SUCCESS)
9241 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9242 return rcStrict;
9243 }
9244 return iemRaiseDeviceNotAvailable(pVCpu);
9245 }
9246 return iemRaiseUndefinedOpcode(pVCpu);
9247}
9248
9249
9250/**
9251 * Implements 'VSTMXCSR'.
9252 *
9253 * @param iEffSeg The effective segment register for @a GCPtrEff.
9254 * @param GCPtrEff The address of the image.
9255 */
9256IEM_CIMPL_DEF_2(iemCImpl_vstmxcsr, uint8_t, iEffSeg, RTGCPTR, GCPtrEff)
9257{
9258 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_XCRx);
9259
9260 /*
9261 * Raise exceptions.
9262 */
9263 if ( ( !IEM_IS_GUEST_CPU_AMD(pVCpu)
9264 ? (pVCpu->cpum.GstCtx.aXcr[0] & (XSAVE_C_SSE | XSAVE_C_YMM)) == (XSAVE_C_SSE | XSAVE_C_YMM)
9265 : !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_EM)) /* AMD Jaguar CPU (f0x16,m0,s1) behaviour */
9266 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSXSAVE))
9267 {
9268 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS))
9269 {
9270 /*
9271 * Do the job.
9272 */
9273 VBOXSTRICTRC rcStrict = iemMemStoreDataU32(pVCpu, iEffSeg, GCPtrEff, pVCpu->cpum.GstCtx.XState.x87.MXCSR);
9274 if (rcStrict == VINF_SUCCESS)
9275 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9276 return rcStrict;
9277 }
9278 return iemRaiseDeviceNotAvailable(pVCpu);
9279 }
9280 return iemRaiseUndefinedOpcode(pVCpu);
9281}
9282
9283
9284/**
9285 * Implements 'LDMXCSR'.
9286 *
9287 * @param iEffSeg The effective segment register for @a GCPtrEff.
9288 * @param GCPtrEff The address of the image.
9289 */
9290IEM_CIMPL_DEF_2(iemCImpl_ldmxcsr, uint8_t, iEffSeg, RTGCPTR, GCPtrEff)
9291{
9292 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX);
9293
9294 /*
9295 * Raise exceptions.
9296 */
9297 /** @todo testcase - order of LDMXCSR faults. Does \#PF, \#GP and \#SS
9298 * happen after or before \#UD and \#EM? */
9299 if ( !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_EM)
9300 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSFXSR))
9301 {
9302 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS))
9303 {
9304 /*
9305 * Do the job.
9306 */
9307 uint32_t fNewMxCsr;
9308 VBOXSTRICTRC rcStrict = iemMemFetchDataU32(pVCpu, &fNewMxCsr, iEffSeg, GCPtrEff);
9309 if (rcStrict == VINF_SUCCESS)
9310 {
9311 uint32_t const fMxCsrMask = CPUMGetGuestMxCsrMask(pVCpu->CTX_SUFF(pVM));
9312 if (!(fNewMxCsr & ~fMxCsrMask))
9313 {
9314 pVCpu->cpum.GstCtx.XState.x87.MXCSR = fNewMxCsr;
9315 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9316 }
9317 Log(("ldmxcsr: New MXCSR=%#RX32 & ~MASK=%#RX32 = %#RX32 -> #GP(0)\n",
9318 fNewMxCsr, fMxCsrMask, fNewMxCsr & ~fMxCsrMask));
9319 return iemRaiseGeneralProtectionFault0(pVCpu);
9320 }
9321 return rcStrict;
9322 }
9323 return iemRaiseDeviceNotAvailable(pVCpu);
9324 }
9325 return iemRaiseUndefinedOpcode(pVCpu);
9326}
9327
9328
9329/**
9330 * Commmon routine for fnstenv and fnsave.
9331 *
9332 * @param pVCpu The cross context virtual CPU structure of the calling thread.
9333 * @param enmEffOpSize The effective operand size.
9334 * @param uPtr Where to store the state.
9335 */
9336static void iemCImplCommonFpuStoreEnv(PVMCPUCC pVCpu, IEMMODE enmEffOpSize, RTPTRUNION uPtr)
9337{
9338 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87);
9339 PCX86FXSTATE pSrcX87 = &pVCpu->cpum.GstCtx.XState.x87;
9340 if (enmEffOpSize == IEMMODE_16BIT)
9341 {
9342 uPtr.pu16[0] = pSrcX87->FCW;
9343 uPtr.pu16[1] = pSrcX87->FSW;
9344 uPtr.pu16[2] = iemFpuCalcFullFtw(pSrcX87);
9345 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
9346 {
9347 /** @todo Testcase: How does this work when the FPUIP/CS was saved in
9348 * protected mode or long mode and we save it in real mode? And vice
9349 * versa? And with 32-bit operand size? I think CPU is storing the
9350 * effective address ((CS << 4) + IP) in the offset register and not
9351 * doing any address calculations here. */
9352 uPtr.pu16[3] = (uint16_t)pSrcX87->FPUIP;
9353 uPtr.pu16[4] = ((pSrcX87->FPUIP >> 4) & UINT16_C(0xf000)) | pSrcX87->FOP;
9354 uPtr.pu16[5] = (uint16_t)pSrcX87->FPUDP;
9355 uPtr.pu16[6] = (pSrcX87->FPUDP >> 4) & UINT16_C(0xf000);
9356 }
9357 else
9358 {
9359 uPtr.pu16[3] = pSrcX87->FPUIP;
9360 uPtr.pu16[4] = pSrcX87->CS;
9361 uPtr.pu16[5] = pSrcX87->FPUDP;
9362 uPtr.pu16[6] = pSrcX87->DS;
9363 }
9364 }
9365 else
9366 {
9367 /** @todo Testcase: what is stored in the "gray" areas? (figure 8-9 and 8-10) */
9368 uPtr.pu16[0*2] = pSrcX87->FCW;
9369 uPtr.pu16[0*2+1] = 0xffff; /* (0xffff observed on intel skylake.) */
9370 uPtr.pu16[1*2] = pSrcX87->FSW;
9371 uPtr.pu16[1*2+1] = 0xffff;
9372 uPtr.pu16[2*2] = iemFpuCalcFullFtw(pSrcX87);
9373 uPtr.pu16[2*2+1] = 0xffff;
9374 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
9375 {
9376 uPtr.pu16[3*2] = (uint16_t)pSrcX87->FPUIP;
9377 uPtr.pu32[4] = ((pSrcX87->FPUIP & UINT32_C(0xffff0000)) >> 4) | pSrcX87->FOP;
9378 uPtr.pu16[5*2] = (uint16_t)pSrcX87->FPUDP;
9379 uPtr.pu32[6] = (pSrcX87->FPUDP & UINT32_C(0xffff0000)) >> 4;
9380 }
9381 else
9382 {
9383 uPtr.pu32[3] = pSrcX87->FPUIP;
9384 uPtr.pu16[4*2] = pSrcX87->CS;
9385 uPtr.pu16[4*2+1] = pSrcX87->FOP;
9386 uPtr.pu32[5] = pSrcX87->FPUDP;
9387 uPtr.pu16[6*2] = pSrcX87->DS;
9388 uPtr.pu16[6*2+1] = 0xffff;
9389 }
9390 }
9391}
9392
9393
9394/**
9395 * Commmon routine for fldenv and frstor
9396 *
9397 * @param pVCpu The cross context virtual CPU structure of the calling thread.
9398 * @param enmEffOpSize The effective operand size.
9399 * @param uPtr Where to store the state.
9400 */
9401static void iemCImplCommonFpuRestoreEnv(PVMCPUCC pVCpu, IEMMODE enmEffOpSize, RTCPTRUNION uPtr)
9402{
9403 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87);
9404 PX86FXSTATE pDstX87 = &pVCpu->cpum.GstCtx.XState.x87;
9405 if (enmEffOpSize == IEMMODE_16BIT)
9406 {
9407 pDstX87->FCW = uPtr.pu16[0];
9408 pDstX87->FSW = uPtr.pu16[1];
9409 pDstX87->FTW = uPtr.pu16[2];
9410 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
9411 {
9412 pDstX87->FPUIP = uPtr.pu16[3] | ((uint32_t)(uPtr.pu16[4] & UINT16_C(0xf000)) << 4);
9413 pDstX87->FPUDP = uPtr.pu16[5] | ((uint32_t)(uPtr.pu16[6] & UINT16_C(0xf000)) << 4);
9414 pDstX87->FOP = uPtr.pu16[4] & UINT16_C(0x07ff);
9415 pDstX87->CS = 0;
9416 pDstX87->Rsrvd1= 0;
9417 pDstX87->DS = 0;
9418 pDstX87->Rsrvd2= 0;
9419 }
9420 else
9421 {
9422 pDstX87->FPUIP = uPtr.pu16[3];
9423 pDstX87->CS = uPtr.pu16[4];
9424 pDstX87->Rsrvd1= 0;
9425 pDstX87->FPUDP = uPtr.pu16[5];
9426 pDstX87->DS = uPtr.pu16[6];
9427 pDstX87->Rsrvd2= 0;
9428 /** @todo Testcase: Is FOP cleared when doing 16-bit protected mode fldenv? */
9429 }
9430 }
9431 else
9432 {
9433 pDstX87->FCW = uPtr.pu16[0*2];
9434 pDstX87->FSW = uPtr.pu16[1*2];
9435 pDstX87->FTW = uPtr.pu16[2*2];
9436 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
9437 {
9438 pDstX87->FPUIP = uPtr.pu16[3*2] | ((uPtr.pu32[4] & UINT32_C(0x0ffff000)) << 4);
9439 pDstX87->FOP = uPtr.pu32[4] & UINT16_C(0x07ff);
9440 pDstX87->FPUDP = uPtr.pu16[5*2] | ((uPtr.pu32[6] & UINT32_C(0x0ffff000)) << 4);
9441 pDstX87->CS = 0;
9442 pDstX87->Rsrvd1= 0;
9443 pDstX87->DS = 0;
9444 pDstX87->Rsrvd2= 0;
9445 }
9446 else
9447 {
9448 pDstX87->FPUIP = uPtr.pu32[3];
9449 pDstX87->CS = uPtr.pu16[4*2];
9450 pDstX87->Rsrvd1= 0;
9451 pDstX87->FOP = uPtr.pu16[4*2+1];
9452 pDstX87->FPUDP = uPtr.pu32[5];
9453 pDstX87->DS = uPtr.pu16[6*2];
9454 pDstX87->Rsrvd2= 0;
9455 }
9456 }
9457
9458 /* Make adjustments. */
9459 pDstX87->FTW = iemFpuCompressFtw(pDstX87->FTW);
9460#ifdef LOG_ENABLED
9461 uint16_t const fOldFsw = pDstX87->FSW;
9462#endif
9463 pDstX87->FCW &= ~X86_FCW_ZERO_MASK | X86_FCW_IC_MASK; /* Intel 10980xe allows setting the IC bit. Win 3.11 CALC.EXE sets it. */
9464 iemFpuRecalcExceptionStatus(pDstX87);
9465#ifdef LOG_ENABLED
9466 if ((pDstX87->FSW & X86_FSW_ES) ^ (fOldFsw & X86_FSW_ES))
9467 Log11(("iemCImplCommonFpuRestoreEnv: %04x:%08RX64: %s FPU exception (FCW=%#x FSW=%#x -> %#x)\n",
9468 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, fOldFsw & X86_FSW_ES ? "Supressed" : "Raised",
9469 pDstX87->FCW, fOldFsw, pDstX87->FSW));
9470#endif
9471
9472 /** @todo Testcase: Check if ES and/or B are automatically cleared if no
9473 * exceptions are pending after loading the saved state? */
9474}
9475
9476
9477/**
9478 * Implements 'FNSTENV'.
9479 *
9480 * @param enmEffOpSize The operand size (only REX.W really matters).
9481 * @param iEffSeg The effective segment register for @a GCPtrEffDst.
9482 * @param GCPtrEffDst The address of the image.
9483 */
9484IEM_CIMPL_DEF_3(iemCImpl_fnstenv, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
9485{
9486 uint8_t bUnmapInfo;
9487 RTPTRUNION uPtr;
9488 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &uPtr.pv, &bUnmapInfo, enmEffOpSize == IEMMODE_16BIT ? 14 : 28,
9489 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE,
9490 enmEffOpSize == IEMMODE_16BIT ? 1 : 3 /** @todo ? */);
9491 if (rcStrict != VINF_SUCCESS)
9492 return rcStrict;
9493
9494 iemCImplCommonFpuStoreEnv(pVCpu, enmEffOpSize, uPtr);
9495
9496 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
9497 if (rcStrict != VINF_SUCCESS)
9498 return rcStrict;
9499
9500 /* Mask all math exceptions. Any possibly pending exceptions will be cleared. */
9501 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
9502 pFpuCtx->FCW |= X86_FCW_XCPT_MASK;
9503#ifdef LOG_ENABLED
9504 uint16_t fOldFsw = pFpuCtx->FSW;
9505#endif
9506 iemFpuRecalcExceptionStatus(pFpuCtx);
9507#ifdef LOG_ENABLED
9508 if ((pFpuCtx->FSW & X86_FSW_ES) ^ (fOldFsw & X86_FSW_ES))
9509 Log11(("fnstenv: %04x:%08RX64: %s FPU exception (FCW=%#x, FSW %#x -> %#x)\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
9510 fOldFsw & X86_FSW_ES ? "Supressed" : "Raised", pFpuCtx->FCW, fOldFsw, pFpuCtx->FSW));
9511#endif
9512
9513 iemHlpUsedFpu(pVCpu);
9514
9515 /* Note: C0, C1, C2 and C3 are documented as undefined, we leave them untouched! */
9516 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9517}
9518
9519
9520/**
9521 * Implements 'FNSAVE'.
9522 *
9523 * @param enmEffOpSize The operand size.
9524 * @param iEffSeg The effective segment register for @a GCPtrEffDst.
9525 * @param GCPtrEffDst The address of the image.
9526 */
9527IEM_CIMPL_DEF_3(iemCImpl_fnsave, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
9528{
9529 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87);
9530
9531 uint8_t bUnmapInfo;
9532 RTPTRUNION uPtr;
9533 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &uPtr.pv, &bUnmapInfo, enmEffOpSize == IEMMODE_16BIT ? 94 : 108,
9534 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE, 3 /** @todo ? */);
9535 if (rcStrict != VINF_SUCCESS)
9536 return rcStrict;
9537
9538 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
9539 iemCImplCommonFpuStoreEnv(pVCpu, enmEffOpSize, uPtr);
9540 PRTFLOAT80U paRegs = (PRTFLOAT80U)(uPtr.pu8 + (enmEffOpSize == IEMMODE_16BIT ? 14 : 28));
9541 for (uint32_t i = 0; i < RT_ELEMENTS(pFpuCtx->aRegs); i++)
9542 {
9543 paRegs[i].au32[0] = pFpuCtx->aRegs[i].au32[0];
9544 paRegs[i].au32[1] = pFpuCtx->aRegs[i].au32[1];
9545 paRegs[i].au16[4] = pFpuCtx->aRegs[i].au16[4];
9546 }
9547
9548 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
9549 if (rcStrict != VINF_SUCCESS)
9550 return rcStrict;
9551
9552 /* Rotate the stack to account for changed TOS. */
9553 iemFpuRotateStackSetTop(pFpuCtx, 0);
9554
9555 /*
9556 * Re-initialize the FPU context.
9557 */
9558 pFpuCtx->FCW = 0x37f;
9559 pFpuCtx->FSW = 0;
9560 pFpuCtx->FTW = 0x00; /* 0 - empty */
9561 pFpuCtx->FPUDP = 0;
9562 pFpuCtx->DS = 0;
9563 pFpuCtx->Rsrvd2= 0;
9564 pFpuCtx->FPUIP = 0;
9565 pFpuCtx->CS = 0;
9566 pFpuCtx->Rsrvd1= 0;
9567 pFpuCtx->FOP = 0;
9568
9569 iemHlpUsedFpu(pVCpu);
9570 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9571}
9572
9573
9574
9575/**
9576 * Implements 'FLDENV'.
9577 *
9578 * @param enmEffOpSize The operand size (only REX.W really matters).
9579 * @param iEffSeg The effective segment register for @a GCPtrEffSrc.
9580 * @param GCPtrEffSrc The address of the image.
9581 */
9582IEM_CIMPL_DEF_3(iemCImpl_fldenv, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
9583{
9584 uint8_t bUnmapInfo;
9585 RTCPTRUNION uPtr;
9586 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, (void **)&uPtr.pv, &bUnmapInfo, enmEffOpSize == IEMMODE_16BIT ? 14 : 28,
9587 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R,
9588 enmEffOpSize == IEMMODE_16BIT ? 1 : 3 /** @todo ?*/);
9589 if (rcStrict != VINF_SUCCESS)
9590 return rcStrict;
9591
9592 iemCImplCommonFpuRestoreEnv(pVCpu, enmEffOpSize, uPtr);
9593
9594 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
9595 if (rcStrict != VINF_SUCCESS)
9596 return rcStrict;
9597
9598 iemHlpUsedFpu(pVCpu);
9599 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9600}
9601
9602
9603/**
9604 * Implements 'FRSTOR'.
9605 *
9606 * @param enmEffOpSize The operand size.
9607 * @param iEffSeg The effective segment register for @a GCPtrEffSrc.
9608 * @param GCPtrEffSrc The address of the image.
9609 */
9610IEM_CIMPL_DEF_3(iemCImpl_frstor, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
9611{
9612 uint8_t bUnmapInfo;
9613 RTCPTRUNION uPtr;
9614 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, (void **)&uPtr.pv, &bUnmapInfo, enmEffOpSize == IEMMODE_16BIT ? 94 : 108,
9615 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R, 3 /** @todo ?*/ );
9616 if (rcStrict != VINF_SUCCESS)
9617 return rcStrict;
9618
9619 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
9620 iemCImplCommonFpuRestoreEnv(pVCpu, enmEffOpSize, uPtr);
9621 PCRTFLOAT80U paRegs = (PCRTFLOAT80U)(uPtr.pu8 + (enmEffOpSize == IEMMODE_16BIT ? 14 : 28));
9622 for (uint32_t i = 0; i < RT_ELEMENTS(pFpuCtx->aRegs); i++)
9623 {
9624 pFpuCtx->aRegs[i].au32[0] = paRegs[i].au32[0];
9625 pFpuCtx->aRegs[i].au32[1] = paRegs[i].au32[1];
9626 pFpuCtx->aRegs[i].au32[2] = paRegs[i].au16[4];
9627 pFpuCtx->aRegs[i].au32[3] = 0;
9628 }
9629
9630 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
9631 if (rcStrict != VINF_SUCCESS)
9632 return rcStrict;
9633
9634 iemHlpUsedFpu(pVCpu);
9635 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9636}
9637
9638
9639/**
9640 * Implements 'FLDCW'.
9641 *
9642 * @param u16Fcw The new FCW.
9643 */
9644IEM_CIMPL_DEF_1(iemCImpl_fldcw, uint16_t, u16Fcw)
9645{
9646 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87);
9647
9648 /** @todo Testcase: Check what happens when trying to load X86_FCW_PC_RSVD. */
9649 /** @todo Testcase: Try see what happens when trying to set undefined bits
9650 * (other than 6 and 7). Currently ignoring them. */
9651 /** @todo Testcase: Test that it raises and loweres the FPU exception bits
9652 * according to FSW. (This is what is currently implemented.) */
9653 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
9654 pFpuCtx->FCW = u16Fcw & (~X86_FCW_ZERO_MASK | X86_FCW_IC_MASK); /* Intel 10980xe allows setting the IC bit. Win 3.11 CALC.EXE sets it. */
9655#ifdef LOG_ENABLED
9656 uint16_t fOldFsw = pFpuCtx->FSW;
9657#endif
9658 iemFpuRecalcExceptionStatus(pFpuCtx);
9659#ifdef LOG_ENABLED
9660 if ((pFpuCtx->FSW & X86_FSW_ES) ^ (fOldFsw & X86_FSW_ES))
9661 Log11(("fldcw: %04x:%08RX64: %s FPU exception (FCW=%#x, FSW %#x -> %#x)\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
9662 fOldFsw & X86_FSW_ES ? "Supressed" : "Raised", pFpuCtx->FCW, fOldFsw, pFpuCtx->FSW));
9663#endif
9664
9665 /* Note: C0, C1, C2 and C3 are documented as undefined, we leave them untouched! */
9666 iemHlpUsedFpu(pVCpu);
9667 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9668}
9669
9670
9671
9672/**
9673 * Implements the underflow case of fxch.
9674 *
9675 * @param iStReg The other stack register.
9676 * @param uFpuOpcode The FPU opcode (for simplicity).
9677 */
9678IEM_CIMPL_DEF_2(iemCImpl_fxch_underflow, uint8_t, iStReg, uint16_t, uFpuOpcode)
9679{
9680 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87);
9681
9682 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
9683 unsigned const iReg1 = X86_FSW_TOP_GET(pFpuCtx->FSW);
9684 unsigned const iReg2 = (iReg1 + iStReg) & X86_FSW_TOP_SMASK;
9685 Assert(!(RT_BIT(iReg1) & pFpuCtx->FTW) || !(RT_BIT(iReg2) & pFpuCtx->FTW));
9686
9687 /** @todo Testcase: fxch underflow. Making assumptions that underflowed
9688 * registers are read as QNaN and then exchanged. This could be
9689 * wrong... */
9690 if (pFpuCtx->FCW & X86_FCW_IM)
9691 {
9692 if (RT_BIT(iReg1) & pFpuCtx->FTW)
9693 {
9694 if (RT_BIT(iReg2) & pFpuCtx->FTW)
9695 iemFpuStoreQNan(&pFpuCtx->aRegs[0].r80);
9696 else
9697 pFpuCtx->aRegs[0].r80 = pFpuCtx->aRegs[iStReg].r80;
9698 iemFpuStoreQNan(&pFpuCtx->aRegs[iStReg].r80);
9699 }
9700 else
9701 {
9702 pFpuCtx->aRegs[iStReg].r80 = pFpuCtx->aRegs[0].r80;
9703 iemFpuStoreQNan(&pFpuCtx->aRegs[0].r80);
9704 }
9705 pFpuCtx->FSW &= ~X86_FSW_C_MASK;
9706 pFpuCtx->FSW |= X86_FSW_C1 | X86_FSW_IE | X86_FSW_SF;
9707 }
9708 else
9709 {
9710 /* raise underflow exception, don't change anything. */
9711 pFpuCtx->FSW &= ~(X86_FSW_TOP_MASK | X86_FSW_XCPT_MASK);
9712 pFpuCtx->FSW |= X86_FSW_C1 | X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B;
9713 Log11(("fxch: %04x:%08RX64: Underflow exception (FSW=%#x)\n",
9714 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pFpuCtx->FSW));
9715 }
9716
9717 iemFpuUpdateOpcodeAndIpWorkerEx(pVCpu, pFpuCtx, uFpuOpcode);
9718 iemHlpUsedFpu(pVCpu);
9719 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9720}
9721
9722
9723/**
9724 * Implements 'FCOMI', 'FCOMIP', 'FUCOMI', and 'FUCOMIP'.
9725 *
9726 * @param iStReg The other stack register.
9727 * @param fUCmp true for FUCOMI[P], false for FCOMI[P].
9728 * @param uPopAndFpuOpcode Bits 15-0: The FPU opcode.
9729 * Bit 31: Whether we should pop the stack when
9730 * done or not.
9731 */
9732IEM_CIMPL_DEF_3(iemCImpl_fcomi_fucomi, uint8_t, iStReg, bool, fUCmp, uint32_t, uPopAndFpuOpcode)
9733{
9734 Assert(iStReg < 8);
9735 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87);
9736
9737 /*
9738 * Raise exceptions.
9739 */
9740 if (pVCpu->cpum.GstCtx.cr0 & (X86_CR0_EM | X86_CR0_TS))
9741 return iemRaiseDeviceNotAvailable(pVCpu);
9742
9743 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
9744 uint16_t u16Fsw = pFpuCtx->FSW;
9745 if (u16Fsw & X86_FSW_ES)
9746 return iemRaiseMathFault(pVCpu);
9747
9748 /*
9749 * Check if any of the register accesses causes #SF + #IA.
9750 */
9751 bool fPop = RT_BOOL(uPopAndFpuOpcode & RT_BIT_32(31));
9752 unsigned const iReg1 = X86_FSW_TOP_GET(u16Fsw);
9753 unsigned const iReg2 = (iReg1 + iStReg) & X86_FSW_TOP_SMASK;
9754 if ((pFpuCtx->FTW & (RT_BIT(iReg1) | RT_BIT(iReg2))) == (RT_BIT(iReg1) | RT_BIT(iReg2)))
9755 {
9756 uint32_t u32Eflags;
9757 if (!fUCmp)
9758 u32Eflags = iemAImpl_fcomi_r80_by_r80(pFpuCtx, &u16Fsw, &pFpuCtx->aRegs[0].r80, &pFpuCtx->aRegs[iStReg].r80);
9759 else
9760 u32Eflags = iemAImpl_fucomi_r80_by_r80(pFpuCtx, &u16Fsw, &pFpuCtx->aRegs[0].r80, &pFpuCtx->aRegs[iStReg].r80);
9761
9762 pFpuCtx->FSW &= ~X86_FSW_C1;
9763 pFpuCtx->FSW |= u16Fsw & ~X86_FSW_TOP_MASK;
9764 if ( !(u16Fsw & X86_FSW_IE)
9765 || (pFpuCtx->FCW & X86_FCW_IM) )
9766 {
9767 pVCpu->cpum.GstCtx.eflags.u &= ~(X86_EFL_OF | X86_EFL_SF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
9768 pVCpu->cpum.GstCtx.eflags.u |= u32Eflags & (X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
9769 }
9770 }
9771 else if (pFpuCtx->FCW & X86_FCW_IM)
9772 {
9773 /* Masked underflow. */
9774 pFpuCtx->FSW &= ~X86_FSW_C1;
9775 pFpuCtx->FSW |= X86_FSW_IE | X86_FSW_SF;
9776 pVCpu->cpum.GstCtx.eflags.u &= ~(X86_EFL_OF | X86_EFL_SF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
9777 pVCpu->cpum.GstCtx.eflags.u |= X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF;
9778 }
9779 else
9780 {
9781 /* Raise underflow - don't touch EFLAGS or TOP. */
9782 pFpuCtx->FSW &= ~X86_FSW_C1;
9783 pFpuCtx->FSW |= X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B;
9784 Log11(("fxch: %04x:%08RX64: Raising IE+SF exception (FSW=%#x)\n",
9785 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pFpuCtx->FSW));
9786 fPop = false;
9787 }
9788
9789 /*
9790 * Pop if necessary.
9791 */
9792 if (fPop)
9793 {
9794 pFpuCtx->FTW &= ~RT_BIT(iReg1);
9795 iemFpuStackIncTop(pVCpu);
9796 }
9797
9798 iemFpuUpdateOpcodeAndIpWorkerEx(pVCpu, pFpuCtx, (uint16_t)uPopAndFpuOpcode);
9799 iemHlpUsedFpu(pVCpu);
9800 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9801}
9802
9803
9804/**
9805 * Implements 'RDSEED'.
9806 *
9807 * @returns VINF_SUCCESS.
9808 * @param iReg The register.
9809 * @param enmEffOpSize The operand size.
9810 */
9811IEM_CIMPL_DEF_2(iemCImpl_rdseed, uint8_t, iReg, IEMMODE, enmEffOpSize)
9812{
9813#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9814 /* Nested-guest VMX intercept. */
9815 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
9816 || !IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_RDSEED_EXIT))
9817 { /* probable */ }
9818 else
9819 {
9820 Log(("rdseed: Guest intercept -> VM-exit\n"));
9821 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_RDSEED, VMXINSTRID_RDSEED, cbInstr);
9822 }
9823#endif
9824
9825 uint32_t *pEFlags = &pVCpu->cpum.GstCtx.eflags.uBoth;
9826 switch (enmEffOpSize)
9827 {
9828 case IEMMODE_16BIT:
9829 {
9830 PFNIEMAIMPLRDRANDSEEDU16 pfnImpl = IEM_SELECT_HOST_OR_FALLBACK(fRdSeed,
9831 &iemAImpl_rdseed_u16,
9832 &iemAImpl_rdseed_u16_fallback);
9833 uint16_t *pu16Dst = iemGRegRefU16(pVCpu, iReg);
9834 (pfnImpl)(pu16Dst, pEFlags);
9835 break;
9836 }
9837 case IEMMODE_32BIT:
9838 {
9839 PFNIEMAIMPLRDRANDSEEDU32 pfnImpl = IEM_SELECT_HOST_OR_FALLBACK(fRdSeed,
9840 &iemAImpl_rdseed_u32,
9841 &iemAImpl_rdseed_u32_fallback);
9842 uint32_t *pu32Dst = iemGRegRefU32(pVCpu, iReg);
9843 (pfnImpl)(pu32Dst, pEFlags);
9844 iemGRegStoreU32(pVCpu, iReg, *pu32Dst);
9845 break;
9846 }
9847 case IEMMODE_64BIT:
9848 {
9849 PFNIEMAIMPLRDRANDSEEDU64 pfnImpl = IEM_SELECT_HOST_OR_FALLBACK(fRdSeed,
9850 &iemAImpl_rdseed_u64,
9851 &iemAImpl_rdseed_u64_fallback);
9852 uint64_t *pu64Dst = iemGRegRefU64(pVCpu, iReg);
9853 (pfnImpl)(pu64Dst, pEFlags);
9854 break;
9855 }
9856 IEM_NOT_REACHED_DEFAULT_CASE_RET();
9857 }
9858 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9859}
9860
9861
9862/**
9863 * Implements 'RDRAND'.
9864 *
9865 * @returns VINF_SUCCESS.
9866 * @param iReg The register.
9867 * @param enmEffOpSize The operand size.
9868 */
9869IEM_CIMPL_DEF_2(iemCImpl_rdrand, uint8_t, iReg, IEMMODE, enmEffOpSize)
9870{
9871#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9872 /* Nested-guest VMX intercept. */
9873 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
9874 || !IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_RDRAND_EXIT))
9875 { /* probable */ }
9876 else
9877 {
9878 Log(("rdrand: Guest intercept -> VM-exit\n"));
9879 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_RDRAND, VMXINSTRID_RDRAND, cbInstr);
9880 }
9881#endif
9882
9883 uint32_t *pEFlags = &pVCpu->cpum.GstCtx.eflags.uBoth;
9884 switch (enmEffOpSize)
9885 {
9886 case IEMMODE_16BIT:
9887 {
9888 PFNIEMAIMPLRDRANDSEEDU16 pfnImpl = IEM_SELECT_HOST_OR_FALLBACK(fRdRand, &iemAImpl_rdrand_u16,
9889 &iemAImpl_rdrand_u16_fallback);
9890 uint16_t *pu16Dst = iemGRegRefU16(pVCpu, iReg);
9891 (pfnImpl)(pu16Dst, pEFlags);
9892 break;
9893 }
9894 case IEMMODE_32BIT:
9895 {
9896 PFNIEMAIMPLRDRANDSEEDU32 pfnImpl = IEM_SELECT_HOST_OR_FALLBACK(fRdRand, &iemAImpl_rdrand_u32,
9897 &iemAImpl_rdrand_u32_fallback);
9898 uint32_t *pu32Dst = iemGRegRefU32(pVCpu, iReg);
9899 (pfnImpl)(pu32Dst, pEFlags);
9900 iemGRegStoreU32(pVCpu, iReg, *pu32Dst);
9901 break;
9902 }
9903 case IEMMODE_64BIT:
9904 {
9905 PFNIEMAIMPLRDRANDSEEDU64 pfnImpl = IEM_SELECT_HOST_OR_FALLBACK(fRdRand, &iemAImpl_rdrand_u64,
9906 &iemAImpl_rdrand_u64_fallback);
9907 uint64_t *pu64Dst = iemGRegRefU64(pVCpu, iReg);
9908 (pfnImpl)(pu64Dst, pEFlags);
9909 break;
9910 }
9911 IEM_NOT_REACHED_DEFAULT_CASE_RET();
9912 }
9913 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9914}
9915
9916
9917/**
9918 * Worker for 'VMASKMOVPS / VPMASKMOVD' 128-bit 32-bit-masked load.
9919 *
9920 * @param pVCpu The cross context virtual CPU structure of the calling thread.
9921 * @param cbInstr The current instruction length.
9922 * @param iXRegDst The destination XMM register index.
9923 * @param iXRegMsk The mask XMM register index.
9924 * @param iEffSeg The effective segment.
9925 * @param GCPtrEffSrc The source memory address.
9926 */
9927static VBOXSTRICTRC iemCImpl_maskmov_load_u128_32_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iXRegDst, uint8_t iXRegMsk, uint8_t iEffSeg, RTGCPTR GCPtrEffSrc)
9928{
9929 uint32_t fAccessed = 0;
9930
9931 PRTUINT128U puDst = (PRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegDst];
9932 PCRTUINT128U puMsk = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegMsk];
9933 PCRTUINT128U puSrc;
9934
9935 for (uint32_t i = 0; i < RT_ELEMENTS(puMsk->au32); i++)
9936 {
9937 fAccessed |= puMsk->au32[i];
9938 }
9939
9940 if (fAccessed & RT_BIT(31)) {
9941 /*
9942 * Access the source memory.
9943 */
9944 uint8_t bUnmapInfo;
9945 void *pvMemSrc;
9946 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemSrc, &bUnmapInfo, sizeof(*puSrc),
9947 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R, 0);
9948 if (rcStrict != VINF_SUCCESS)
9949 return rcStrict;
9950
9951 puSrc = (PCRTUINT128U)pvMemSrc;
9952
9953 for (uint32_t i = 0; i < RT_ELEMENTS(puSrc->au32); i++)
9954 {
9955 puDst->au32[i] = (puMsk->au32[i] & RT_BIT(31)) ? puSrc->au32[i] : 0;
9956 }
9957 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[0] = 0;
9958 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[1] = 0;
9959
9960 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
9961 if (rcStrict != VINF_SUCCESS)
9962 return rcStrict;
9963 }
9964 else
9965 {
9966 puDst->au64[0] = 0;
9967 puDst->au64[1] = 0;
9968 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[0] = 0;
9969 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[1] = 0;
9970 }
9971
9972 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9973}
9974
9975
9976
9977/**
9978 * Worker for 'VMASKMOVPS / VPMASKMOVD' 256-bit 32-bit-masked load.
9979 *
9980 * @param pVCpu The cross context virtual CPU structure of the calling thread.
9981 * @param cbInstr The current instruction length.
9982 * @param iYRegDst The destination YMM register index.
9983 * @param iYRegMsk The mask YMM register index.
9984 * @param iEffSeg The effective segment.
9985 * @param GCPtrEffSrc The source memory address.
9986 */
9987static VBOXSTRICTRC iemCImpl_maskmov_load_u256_32_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iYRegDst, uint8_t iYRegMsk, uint8_t iEffSeg, RTGCPTR GCPtrEffSrc)
9988{
9989 uint32_t fAccessed = 0;
9990
9991 PRTUINT128U puDstLo = (PRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegDst];
9992 PRTUINT128U puDstHi = (PRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegDst];
9993 PCRTUINT128U puMskLo = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegMsk];
9994 PCRTUINT128U puMskHi = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegMsk];
9995 PCRTUINT256U puSrc;
9996
9997 for (uint32_t i = 0; i < RT_ELEMENTS(puMskLo->au32); i++)
9998 {
9999 fAccessed |= puMskLo->au32[i] | puMskHi->au32[i];
10000 }
10001
10002 if (fAccessed & RT_BIT(31)) {
10003 /*
10004 * Access the source memory.
10005 */
10006 uint8_t bUnmapInfo;
10007 void *pvMemSrc;
10008 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemSrc, &bUnmapInfo, sizeof(*puSrc),
10009 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R, 0);
10010 if (rcStrict != VINF_SUCCESS)
10011 return rcStrict;
10012
10013 puSrc = (PCRTUINT256U)pvMemSrc;
10014
10015 uint8_t const iHalf = RT_ELEMENTS(puSrc->au32) / 2;
10016
10017 for (uint32_t i = 0; i < iHalf; i++)
10018 {
10019 puDstLo->au32[i] = (puMskLo->au32[i] & RT_BIT(31)) ? puSrc->au32[i] : 0;
10020 }
10021 for (uint32_t i = iHalf; i < RT_ELEMENTS(puSrc->au32); i++)
10022 {
10023 puDstHi->au32[i - iHalf] = (puMskHi->au32[i - iHalf] & RT_BIT(31)) ? puSrc->au32[i] : 0;
10024 }
10025
10026 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10027 if (rcStrict != VINF_SUCCESS)
10028 return rcStrict;
10029 }
10030 else
10031 {
10032 puDstLo->au64[0] = 0;
10033 puDstLo->au64[1] = 0;
10034 puDstHi->au64[0] = 0;
10035 puDstHi->au64[1] = 0;
10036 }
10037
10038 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10039}
10040
10041
10042/**
10043 * Worker for 'VMASKMOVPS / VPMASKMOVD' 128-bit 32-bit-masked store.
10044 *
10045 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10046 * @param cbInstr The current instruction length.
10047 * @param iEffSeg The effective segment.
10048 * @param GCPtrEffDst The destination memory address.
10049 * @param iXRegMsk The mask XMM register index.
10050 * @param iXRegSrc The source XMM register index.
10051 */
10052static VBOXSTRICTRC iemCImpl_maskmov_store_u128_32_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrEffDst, uint8_t iXRegMsk, uint8_t iXRegSrc)
10053{
10054 uint32_t fAccessed = 0;
10055
10056 PRTUINT128U puDst;
10057 PCRTUINT128U puMsk = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegMsk];
10058 PCRTUINT128U puSrc = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegSrc];
10059
10060 for (uint32_t i = 0; i < RT_ELEMENTS(puMsk->au32); i++)
10061 {
10062 fAccessed |= puMsk->au32[i];
10063 }
10064
10065 if (fAccessed & RT_BIT(31)) {
10066 /*
10067 * Access the destination memory.
10068 */
10069 uint8_t bUnmapInfo;
10070 void *pvMemDst;
10071 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemDst, &bUnmapInfo, sizeof(*puDst),
10072 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_RW, 0);
10073 if (rcStrict != VINF_SUCCESS)
10074 return rcStrict;
10075
10076 puDst = (PRTUINT128U)pvMemDst;
10077
10078 for (uint32_t i = 0; i < RT_ELEMENTS(puDst->au32); i++)
10079 {
10080 if (puMsk->au32[i] & RT_BIT(31))
10081 puDst->au32[i] = puSrc->au32[i];
10082 }
10083
10084 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10085 if (rcStrict != VINF_SUCCESS)
10086 return rcStrict;
10087 }
10088
10089 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10090}
10091
10092
10093
10094/**
10095 * Worker for 'VMASKMOVPS / VPMASKMOVD' 256-bit 32-bit-masked store.
10096 *
10097 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10098 * @param cbInstr The current instruction length.
10099 * @param iEffSeg The effective segment.
10100 * @param GCPtrEffDst The destination memory address.
10101 * @param iYRegMsk The mask YMM register index.
10102 * @param iYRegSrc The source YMM register index.
10103 */
10104static VBOXSTRICTRC iemCImpl_maskmov_store_u256_32_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrEffDst, uint8_t iYRegMsk, uint8_t iYRegSrc)
10105{
10106 uint32_t fAccessed = 0;
10107
10108 PRTUINT256U puDst;
10109 PCRTUINT128U puMskLo = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegMsk];
10110 PCRTUINT128U puMskHi = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegMsk];
10111 PCRTUINT128U puSrcLo = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegSrc];
10112 PCRTUINT128U puSrcHi = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegSrc];
10113
10114 for (uint32_t i = 0; i < RT_ELEMENTS(puMskLo->au32); i++)
10115 {
10116 fAccessed |= puMskLo->au32[i] | puMskHi->au32[i];
10117 }
10118
10119 if (fAccessed & RT_BIT(31)) {
10120 /*
10121 * Access the destination memory.
10122 */
10123 uint8_t bUnmapInfo;
10124 void *pvMemDst;
10125 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemDst, &bUnmapInfo, sizeof(*puDst),
10126 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_RW, 0);
10127 if (rcStrict != VINF_SUCCESS)
10128 return rcStrict;
10129
10130 puDst = (PRTUINT256U)pvMemDst;
10131
10132 uint8_t const iHalf = RT_ELEMENTS(puDst->au32) / 2;
10133
10134 for (uint32_t i = 0; i < iHalf; i++)
10135 {
10136 if (puMskLo->au32[i] & RT_BIT(31))
10137 puDst->au32[i] = puSrcLo->au32[i];
10138 }
10139 for (uint32_t i = iHalf; i < RT_ELEMENTS(puDst->au32); i++)
10140 {
10141 if (puMskHi->au32[i - iHalf] & RT_BIT(31))
10142 puDst->au32[i] = puSrcHi->au32[i - iHalf];
10143 }
10144
10145 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10146 if (rcStrict != VINF_SUCCESS)
10147 return rcStrict;
10148 }
10149
10150 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10151}
10152
10153
10154/**
10155 * Worker for 'VMASKMOVPD / VPMASKMOVQ' 128-bit 64-bit-masked load.
10156 *
10157 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10158 * @param cbInstr The current instruction length.
10159 * @param iXRegDst The destination XMM register index.
10160 * @param iXRegMsk The mask XMM register index.
10161 * @param iEffSeg The effective segment.
10162 * @param GCPtrEffSrc The source memory address.
10163 */
10164static VBOXSTRICTRC iemCImpl_maskmov_load_u128_64_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iXRegDst, uint8_t iXRegMsk, uint8_t iEffSeg, RTGCPTR GCPtrEffSrc)
10165{
10166 uint64_t fAccessed = 0;
10167
10168 PRTUINT128U puDst = (PRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegDst];
10169 PCRTUINT128U puMsk = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegMsk];
10170 PCRTUINT128U puSrc;
10171
10172 for (uint32_t i = 0; i < RT_ELEMENTS(puMsk->au64); i++)
10173 {
10174 fAccessed |= puMsk->au64[i];
10175 }
10176
10177 if (fAccessed & RT_BIT_64(63)) {
10178 /*
10179 * Access the source memory.
10180 */
10181 uint8_t bUnmapInfo;
10182 void *pvMemSrc;
10183 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemSrc, &bUnmapInfo, sizeof(*puSrc),
10184 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R, 0);
10185 if (rcStrict != VINF_SUCCESS)
10186 return rcStrict;
10187
10188 puSrc = (PCRTUINT128U)pvMemSrc;
10189
10190 for (uint32_t i = 0; i < RT_ELEMENTS(puSrc->au64); i++)
10191 {
10192 puDst->au64[i] = (puMsk->au64[i] & RT_BIT_64(63)) ? puSrc->au64[i] : 0;
10193 }
10194 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[0] = 0;
10195 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[1] = 0;
10196
10197 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10198 if (rcStrict != VINF_SUCCESS)
10199 return rcStrict;
10200 }
10201 else
10202 {
10203 puDst->au64[0] = 0;
10204 puDst->au64[1] = 0;
10205 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[0] = 0;
10206 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[1] = 0;
10207 }
10208
10209 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10210}
10211
10212
10213
10214/**
10215 * Worker for 'VMASKMOVPD / VPMASKMOVQ' 256-bit 64-bit-masked load.
10216 *
10217 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10218 * @param cbInstr The current instruction length.
10219 * @param iYRegDst The destination YMM register index.
10220 * @param iYRegMsk The mask YMM register index.
10221 * @param iEffSeg The effective segment.
10222 * @param GCPtrEffSrc The source memory address.
10223 */
10224static VBOXSTRICTRC iemCImpl_maskmov_load_u256_64_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iYRegDst, uint8_t iYRegMsk, uint8_t iEffSeg, RTGCPTR GCPtrEffSrc)
10225{
10226 uint64_t fAccessed = 0;
10227
10228 PRTUINT128U puDstLo = (PRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegDst];
10229 PRTUINT128U puDstHi = (PRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegDst];
10230 PCRTUINT128U puMskLo = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegMsk];
10231 PCRTUINT128U puMskHi = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegMsk];
10232 PCRTUINT256U puSrc;
10233
10234 for (uint32_t i = 0; i < RT_ELEMENTS(puMskLo->au64); i++)
10235 {
10236 fAccessed |= puMskLo->au64[i] | puMskHi->au64[i];
10237 }
10238
10239 if (fAccessed & RT_BIT_64(63)) {
10240 /*
10241 * Access the source memory.
10242 */
10243 uint8_t bUnmapInfo;
10244 void *pvMemSrc;
10245 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemSrc, &bUnmapInfo, sizeof(*puSrc),
10246 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R, 0);
10247 if (rcStrict != VINF_SUCCESS)
10248 return rcStrict;
10249
10250 puSrc = (PCRTUINT256U)pvMemSrc;
10251
10252 uint8_t const iHalf = RT_ELEMENTS(puSrc->au64) / 2;
10253
10254 for (uint32_t i = 0; i < iHalf; i++)
10255 {
10256 puDstLo->au64[i] = (puMskLo->au64[i] & RT_BIT_64(63)) ? puSrc->au64[i] : 0;
10257 }
10258 for (uint32_t i = iHalf; i < RT_ELEMENTS(puSrc->au64); i++)
10259 {
10260 puDstHi->au64[i - iHalf] = (puMskHi->au64[i - iHalf] & RT_BIT_64(63)) ? puSrc->au64[i] : 0;
10261 }
10262
10263 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10264 if (rcStrict != VINF_SUCCESS)
10265 return rcStrict;
10266 }
10267 else
10268 {
10269 puDstLo->au64[0] = 0;
10270 puDstLo->au64[1] = 0;
10271 puDstHi->au64[0] = 0;
10272 puDstHi->au64[1] = 0;
10273 }
10274
10275 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10276}
10277
10278
10279/**
10280 * Worker for 'VMASKMOVPD / VPMASKMOVQ' 128-bit 64-bit-masked store.
10281 *
10282 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10283 * @param cbInstr The current instruction length.
10284 * @param iEffSeg The effective segment.
10285 * @param GCPtrEffDst The destination memory address.
10286 * @param iXRegMsk The mask XMM register index.
10287 * @param iXRegSrc The source XMM register index.
10288 */
10289static VBOXSTRICTRC iemCImpl_maskmov_store_u128_64_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrEffDst, uint8_t iXRegMsk, uint8_t iXRegSrc)
10290{
10291 uint64_t fAccessed = 0;
10292
10293 PRTUINT128U puDst;
10294 PCRTUINT128U puMsk = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegMsk];
10295 PCRTUINT128U puSrc = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegSrc];
10296
10297 for (uint32_t i = 0; i < RT_ELEMENTS(puMsk->au64); i++)
10298 {
10299 fAccessed |= puMsk->au64[i];
10300 }
10301
10302 if (fAccessed & RT_BIT_64(63)) {
10303 /*
10304 * Access the destination memory.
10305 */
10306 uint8_t bUnmapInfo;
10307 void *pvMemDst;
10308 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemDst, &bUnmapInfo, sizeof(*puDst),
10309 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_RW, 0);
10310 if (rcStrict != VINF_SUCCESS)
10311 return rcStrict;
10312
10313 puDst = (PRTUINT128U)pvMemDst;
10314
10315 for (uint32_t i = 0; i < RT_ELEMENTS(puDst->au64); i++)
10316 {
10317 if (puMsk->au64[i] & RT_BIT_64(63))
10318 puDst->au64[i] = puSrc->au64[i];
10319 }
10320
10321 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10322 if (rcStrict != VINF_SUCCESS)
10323 return rcStrict;
10324 }
10325
10326 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10327}
10328
10329
10330
10331/**
10332 * Worker for 'VMASKMOVPD / VPMASKMOVQ' 256-bit 64-bit-masked store.
10333 *
10334 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10335 * @param cbInstr The current instruction length.
10336 * @param iEffSeg The effective segment.
10337 * @param GCPtrEffDst The destination memory address.
10338 * @param iYRegMsk The mask YMM register index.
10339 * @param iYRegSrc The source YMM register index.
10340 */
10341static VBOXSTRICTRC iemCImpl_maskmov_store_u256_64_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrEffDst, uint8_t iYRegMsk, uint8_t iYRegSrc)
10342{
10343 uint64_t fAccessed = 0;
10344
10345 PRTUINT256U puDst;
10346 PCRTUINT128U puMskLo = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegMsk];
10347 PCRTUINT128U puMskHi = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegMsk];
10348 PCRTUINT128U puSrcLo = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegSrc];
10349 PCRTUINT128U puSrcHi = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegSrc];
10350
10351 for (uint32_t i = 0; i < RT_ELEMENTS(puMskLo->au64); i++)
10352 {
10353 fAccessed |= puMskLo->au64[i] | puMskHi->au64[i];
10354 }
10355
10356 if (fAccessed & RT_BIT_64(63)) {
10357 /*
10358 * Access the destination memory.
10359 */
10360 uint8_t bUnmapInfo;
10361 void *pvMemDst;
10362 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemDst, &bUnmapInfo, sizeof(*puDst),
10363 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_RW, 0);
10364 if (rcStrict != VINF_SUCCESS)
10365 return rcStrict;
10366
10367 puDst = (PRTUINT256U)pvMemDst;
10368
10369 uint8_t const iHalf = RT_ELEMENTS(puDst->au64) / 2;
10370
10371 for (uint32_t i = 0; i < iHalf; i++)
10372 {
10373 if (puMskLo->au64[i] & RT_BIT_64(63))
10374 puDst->au64[i] = puSrcLo->au64[i];
10375 }
10376 for (uint32_t i = iHalf; i < RT_ELEMENTS(puDst->au64); i++)
10377 {
10378 if (puMskHi->au64[i - iHalf] & RT_BIT_64(63))
10379 puDst->au64[i] = puSrcHi->au64[i - iHalf];
10380 }
10381
10382 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10383 if (rcStrict != VINF_SUCCESS)
10384 return rcStrict;
10385 }
10386
10387 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10388}
10389
10390
10391/**
10392 * Implements 'VMASKMOVPS' 128-bit 32-bit-masked load.
10393 *
10394 * @param iXRegDst The destination XMM register index.
10395 * @param iXRegMsk The mask XMM register index.
10396 * @param iEffSeg The effective segment.
10397 * @param GCPtrEffSrc The source memory address.
10398 */
10399IEM_CIMPL_DEF_4(iemCImpl_vmaskmovps_load_u128, uint8_t, iXRegDst, uint8_t, iXRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10400{
10401 return iemCImpl_maskmov_load_u128_32_worker(pVCpu, cbInstr, iXRegDst, iXRegMsk, iEffSeg, GCPtrEffSrc);
10402}
10403
10404
10405/**
10406 * Implements 'VMASKMOVPS' 256-bit 32-bit-masked load.
10407 *
10408 * @param iYRegDst The destination YMM register index.
10409 * @param iYRegMsk The mask YMM register index.
10410 * @param iEffSeg The effective segment.
10411 * @param GCPtrEffSrc The source memory address.
10412 */
10413IEM_CIMPL_DEF_4(iemCImpl_vmaskmovps_load_u256, uint8_t, iYRegDst, uint8_t, iYRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10414{
10415 return iemCImpl_maskmov_load_u256_32_worker(pVCpu, cbInstr, iYRegDst, iYRegMsk, iEffSeg, GCPtrEffSrc);
10416}
10417
10418
10419/**
10420 * Implements 'VMASKMOVPS' 128-bit 32-bit-masked store.
10421 *
10422 * @param iEffSeg The effective segment.
10423 * @param GCPtrEffDst The destination memory address.
10424 * @param iXRegMsk The mask XMM register index.
10425 * @param iXRegSrc The source XMM register index.
10426 */
10427IEM_CIMPL_DEF_4(iemCImpl_vmaskmovps_store_u128, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iXRegMsk, uint8_t, iXRegSrc)
10428{
10429 return iemCImpl_maskmov_store_u128_32_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iXRegMsk, iXRegSrc);
10430}
10431
10432
10433/**
10434 * Implements 'VMASKMOVPS' 256-bit 32-bit-masked store.
10435 *
10436 * @param iEffSeg The effective segment.
10437 * @param GCPtrEffDst The destination memory address.
10438 * @param iYRegMsk The mask YMM register index.
10439 * @param iYRegSrc The source YMM register index.
10440 */
10441IEM_CIMPL_DEF_4(iemCImpl_vmaskmovps_store_u256, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iYRegMsk, uint8_t, iYRegSrc)
10442{
10443 return iemCImpl_maskmov_store_u256_32_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iYRegMsk, iYRegSrc);
10444}
10445
10446
10447/**
10448 * Implements 'VPMASKMOVD' 128-bit 32-bit-masked load.
10449 *
10450 * @param iXRegDst The destination XMM register index.
10451 * @param iXRegMsk The mask XMM register index.
10452 * @param iEffSeg The effective segment.
10453 * @param GCPtrEffSrc The source memory address.
10454 */
10455IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovd_load_u128, uint8_t, iXRegDst, uint8_t, iXRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10456{
10457 return iemCImpl_maskmov_load_u128_32_worker(pVCpu, cbInstr, iXRegDst, iXRegMsk, iEffSeg, GCPtrEffSrc);
10458}
10459
10460
10461/**
10462 * Implements 'VPMASKMOVD' 256-bit 32-bit-masked load.
10463 *
10464 * @param iYRegDst The destination YMM register index.
10465 * @param iYRegMsk The mask YMM register index.
10466 * @param iEffSeg The effective segment.
10467 * @param GCPtrEffSrc The source memory address.
10468 */
10469IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovd_load_u256, uint8_t, iYRegDst, uint8_t, iYRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10470{
10471 return iemCImpl_maskmov_load_u256_32_worker(pVCpu, cbInstr, iYRegDst, iYRegMsk, iEffSeg, GCPtrEffSrc);
10472}
10473
10474
10475/**
10476 * Implements 'VPMASKMOVD' 128-bit 32-bit-masked store.
10477 *
10478 * @param iEffSeg The effective segment.
10479 * @param GCPtrEffDst The destination memory address.
10480 * @param iXRegMsk The mask XMM register index.
10481 * @param iXRegSrc The source XMM register index.
10482 */
10483IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovd_store_u128, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iXRegMsk, uint8_t, iXRegSrc)
10484{
10485 return iemCImpl_maskmov_store_u128_32_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iXRegMsk, iXRegSrc);
10486}
10487
10488
10489/**
10490 * Implements 'VPMASKMOVD' 256-bit 32-bit-masked store.
10491 *
10492 * @param iEffSeg The effective segment.
10493 * @param GCPtrEffDst The destination memory address.
10494 * @param iYRegMsk The mask YMM register index.
10495 * @param iYRegSrc The source YMM register index.
10496 */
10497IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovd_store_u256, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iYRegMsk, uint8_t, iYRegSrc)
10498{
10499 return iemCImpl_maskmov_store_u256_32_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iYRegMsk, iYRegSrc);
10500}
10501
10502
10503/**
10504 * Implements 'VMASKMOVPD' 128-bit 64-bit-masked load.
10505 *
10506 * @param iXRegDst The destination XMM register index.
10507 * @param iXRegMsk The mask XMM register index.
10508 * @param iEffSeg The effective segment.
10509 * @param GCPtrEffSrc The source memory address.
10510 */
10511IEM_CIMPL_DEF_4(iemCImpl_vmaskmovpd_load_u128, uint8_t, iXRegDst, uint8_t, iXRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10512{
10513 return iemCImpl_maskmov_load_u128_64_worker(pVCpu, cbInstr, iXRegDst, iXRegMsk, iEffSeg, GCPtrEffSrc);
10514}
10515
10516
10517/**
10518 * Implements 'VMASKMOVPD' 256-bit 64-bit-masked load.
10519 *
10520 * @param iYRegDst The destination YMM register index.
10521 * @param iYRegMsk The mask YMM register index.
10522 * @param iEffSeg The effective segment.
10523 * @param GCPtrEffSrc The source memory address.
10524 */
10525IEM_CIMPL_DEF_4(iemCImpl_vmaskmovpd_load_u256, uint8_t, iYRegDst, uint8_t, iYRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10526{
10527 return iemCImpl_maskmov_load_u256_64_worker(pVCpu, cbInstr, iYRegDst, iYRegMsk, iEffSeg, GCPtrEffSrc);
10528}
10529
10530
10531/**
10532 * Implements 'VMASKMOVPD' 128-bit 64-bit-masked store.
10533 *
10534 * @param iEffSeg The effective segment.
10535 * @param GCPtrEffDst The destination memory address.
10536 * @param iXRegMsk The mask XMM register index.
10537 * @param iXRegSrc The source XMM register index.
10538 */
10539IEM_CIMPL_DEF_4(iemCImpl_vmaskmovpd_store_u128, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iXRegMsk, uint8_t, iXRegSrc)
10540{
10541 return iemCImpl_maskmov_store_u128_64_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iXRegMsk, iXRegSrc);
10542}
10543
10544
10545/**
10546 * Implements 'VMASKMOVPD' 256-bit 64-bit-masked store.
10547 *
10548 * @param iEffSeg The effective segment.
10549 * @param GCPtrEffDst The destination memory address.
10550 * @param iYRegMsk The mask YMM register index.
10551 * @param iYRegSrc The source YMM register index.
10552 */
10553IEM_CIMPL_DEF_4(iemCImpl_vmaskmovpd_store_u256, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iYRegMsk, uint8_t, iYRegSrc)
10554{
10555 return iemCImpl_maskmov_store_u256_64_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iYRegMsk, iYRegSrc);
10556}
10557
10558
10559/**
10560 * Implements 'VPMASKMOVQ' 128-bit 64-bit-masked load.
10561 *
10562 * @param iXRegDst The destination XMM register index.
10563 * @param iXRegMsk The mask XMM register index.
10564 * @param iEffSeg The effective segment.
10565 * @param GCPtrEffSrc The source memory address.
10566 */
10567IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovq_load_u128, uint8_t, iXRegDst, uint8_t, iXRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10568{
10569 return iemCImpl_maskmov_load_u128_64_worker(pVCpu, cbInstr, iXRegDst, iXRegMsk, iEffSeg, GCPtrEffSrc);
10570}
10571
10572
10573/**
10574 * Implements 'VPMASKMOVQ' 256-bit 64-bit-masked load.
10575 *
10576 * @param iYRegDst The destination YMM register index.
10577 * @param iYRegMsk The mask YMM register index.
10578 * @param iEffSeg The effective segment.
10579 * @param GCPtrEffSrc The source memory address.
10580 */
10581IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovq_load_u256, uint8_t, iYRegDst, uint8_t, iYRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10582{
10583 return iemCImpl_maskmov_load_u256_64_worker(pVCpu, cbInstr, iYRegDst, iYRegMsk, iEffSeg, GCPtrEffSrc);
10584}
10585
10586
10587/**
10588 * Implements 'VPMASKMOVQ' 128-bit 64-bit-masked store.
10589 *
10590 * @param iEffSeg The effective segment.
10591 * @param GCPtrEffDst The destination memory address.
10592 * @param iXRegMsk The mask XMM register index.
10593 * @param iXRegSrc The source XMM register index.
10594 */
10595IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovq_store_u128, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iXRegMsk, uint8_t, iXRegSrc)
10596{
10597 return iemCImpl_maskmov_store_u128_64_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iXRegMsk, iXRegSrc);
10598}
10599
10600
10601/**
10602 * Implements 'VPMASKMOVQ' 256-bit 64-bit-masked store.
10603 *
10604 * @param iEffSeg The effective segment.
10605 * @param GCPtrEffDst The destination memory address.
10606 * @param iYRegMsk The mask YMM register index.
10607 * @param iYRegSrc The source YMM register index.
10608 */
10609IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovq_store_u256, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iYRegMsk, uint8_t, iYRegSrc)
10610{
10611 return iemCImpl_maskmov_store_u256_64_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iYRegMsk, iYRegSrc);
10612}
10613
10614
10615/** @} */
10616
Note: See TracBrowser for help on using the repository browser.

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