VirtualBox

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

Last change on this file since 105462 was 105440, checked in by vboxsync, 4 months ago

VMM/IEM: Added some simple TLB tracing (disabled by default). bugref:10727

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 393.0 KB
Line 
1/* $Id: IEMAllCImpl.cpp 105440 2024-07-23 10:50:17Z 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 %#x 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 IEMTLBTRACE_LOAD_CR0(pVCpu, uNewCrX, uOldCrX);
5992
5993 /*
5994 * Inform PGM.
5995 */
5996 if ( (uNewCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE | X86_CR0_CD | X86_CR0_NW))
5997 != (uOldCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE | X86_CR0_CD | X86_CR0_NW)) )
5998 {
5999 if ( enmAccessCrX != IEMACCESSCRX_MOV_CRX
6000 || !CPUMIsPaePagingEnabled(uNewCrX, pVCpu->cpum.GstCtx.cr4, NewEFER)
6001 || CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)))
6002 { /* likely */ }
6003 else
6004 IEM_MAP_PAE_PDPES_AT_CR3_RET(pVCpu, iCrReg, pVCpu->cpum.GstCtx.cr3);
6005 rc = PGMFlushTLB(pVCpu, pVCpu->cpum.GstCtx.cr3, true /* global */);
6006 AssertRCReturn(rc, rc);
6007 /* ignore informational status codes */
6008 }
6009
6010 /*
6011 * Change CR0.
6012 */
6013 CPUMSetGuestCR0(pVCpu, uNewCrX);
6014 Assert(pVCpu->cpum.GstCtx.cr0 == uNewCrX);
6015
6016 /* Update the fExec flags if PE changed. */
6017 if ((uNewCrX ^ uOldCrX) & X86_CR0_PE)
6018 iemRecalcExecModeAndCplAndAcFlags(pVCpu);
6019
6020 /*
6021 * Inform PGM some more...
6022 */
6023 rcStrict = PGMChangeMode(pVCpu, pVCpu->cpum.GstCtx.cr0, pVCpu->cpum.GstCtx.cr4, pVCpu->cpum.GstCtx.msrEFER,
6024 false /* fForce */);
6025 break;
6026 }
6027
6028 /*
6029 * CR2 can be changed without any restrictions.
6030 */
6031 case 2:
6032 {
6033 if (!IEM_SVM_IS_WRITE_CR_INTERCEPT_SET(pVCpu, /*cr*/ 2))
6034 { /* probable */ }
6035 else
6036 {
6037 Log(("iemCImpl_load_Cr%#x: Guest intercept -> #VMEXIT\n", iCrReg));
6038 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6039 IEM_SVM_CRX_VMEXIT_RET(pVCpu, SVM_EXIT_WRITE_CR2, enmAccessCrX, iGReg);
6040 }
6041 pVCpu->cpum.GstCtx.cr2 = uNewCrX;
6042 pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_CR2;
6043 rcStrict = VINF_SUCCESS;
6044 break;
6045 }
6046
6047 /*
6048 * CR3 is relatively simple, although AMD and Intel have different
6049 * accounts of how setting reserved bits are handled. We take intel's
6050 * word for the lower bits and AMD's for the high bits (63:52). The
6051 * lower reserved bits are ignored and left alone; OpenBSD 5.8 relies
6052 * on this.
6053 */
6054 /** @todo Testcase: Setting reserved bits in CR3, especially before
6055 * enabling paging. */
6056 case 3:
6057 {
6058 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
6059
6060 /* Bit 63 being clear in the source operand with PCIDE indicates no invalidations are required. */
6061 if ( (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PCIDE)
6062 && (uNewCrX & RT_BIT_64(63)))
6063 {
6064 /** @todo r=ramshankar: avoiding a TLB flush altogether here causes Windows 10
6065 * SMP(w/o nested-paging) to hang during bootup on Skylake systems, see
6066 * Intel spec. 4.10.4.1 "Operations that Invalidate TLBs and
6067 * Paging-Structure Caches". */
6068 uNewCrX &= ~RT_BIT_64(63);
6069 }
6070
6071 /* Check / mask the value. */
6072#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
6073 /* See Intel spec. 27.2.2 "EPT Translation Mechanism" footnote. */
6074 uint64_t const fInvPhysMask = !CPUMIsGuestVmxEptPagingEnabledEx(IEM_GET_CTX(pVCpu))
6075 ? (UINT64_MAX << IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cMaxPhysAddrWidth)
6076 : (~X86_CR3_EPT_PAGE_MASK & X86_PAGE_4K_BASE_MASK);
6077#else
6078 uint64_t const fInvPhysMask = UINT64_C(0xfff0000000000000);
6079#endif
6080 if (uNewCrX & fInvPhysMask)
6081 {
6082 /** @todo Should we raise this only for 64-bit mode like Intel claims? AMD is
6083 * very vague in this area. As mentioned above, need testcase on real
6084 * hardware... Sigh. */
6085 Log(("Trying to load CR3 with invalid high bits set: %#llx\n", uNewCrX));
6086 return iemRaiseGeneralProtectionFault0(pVCpu);
6087 }
6088
6089 uint64_t fValid;
6090 if ( (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE)
6091 && (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LME))
6092 {
6093 /** @todo Redundant? This value has already been validated above. */
6094 fValid = UINT64_C(0x000fffffffffffff);
6095 }
6096 else
6097 fValid = UINT64_C(0xffffffff);
6098 if (uNewCrX & ~fValid)
6099 {
6100 Log(("Automatically clearing reserved MBZ bits in CR3 load: NewCR3=%#llx ClearedBits=%#llx\n",
6101 uNewCrX, uNewCrX & ~fValid));
6102 uNewCrX &= fValid;
6103 }
6104
6105 if (!IEM_SVM_IS_WRITE_CR_INTERCEPT_SET(pVCpu, /*cr*/ 3))
6106 { /* probable */ }
6107 else
6108 {
6109 Log(("iemCImpl_load_Cr%#x: Guest intercept -> #VMEXIT\n", iCrReg));
6110 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6111 IEM_SVM_CRX_VMEXIT_RET(pVCpu, SVM_EXIT_WRITE_CR3, enmAccessCrX, iGReg);
6112 }
6113
6114 IEMTLBTRACE_LOAD_CR3(pVCpu, uNewCrX, pVCpu->cpum.GstCtx.cr3);
6115
6116 /* Inform PGM. */
6117 if (pVCpu->cpum.GstCtx.cr0 & X86_CR0_PG)
6118 {
6119 if ( !CPUMIsGuestInPAEModeEx(IEM_GET_CTX(pVCpu))
6120 || CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)))
6121 { /* likely */ }
6122 else
6123 {
6124 Assert(enmAccessCrX == IEMACCESSCRX_MOV_CRX);
6125 IEM_MAP_PAE_PDPES_AT_CR3_RET(pVCpu, iCrReg, uNewCrX);
6126 }
6127 rc = PGMFlushTLB(pVCpu, uNewCrX, !(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PGE));
6128 AssertRCReturn(rc, rc);
6129 /* ignore informational status codes */
6130 }
6131
6132 /* Make the change. */
6133 rc = CPUMSetGuestCR3(pVCpu, uNewCrX);
6134 AssertRCSuccessReturn(rc, rc);
6135
6136 rcStrict = VINF_SUCCESS;
6137 break;
6138 }
6139
6140 /*
6141 * CR4 is a bit more tedious as there are bits which cannot be cleared
6142 * under some circumstances and such.
6143 */
6144 case 4:
6145 {
6146 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
6147 uint64_t const uOldCrX = pVCpu->cpum.GstCtx.cr4;
6148
6149 /* Reserved bits. */
6150 uint32_t const fValid = CPUMGetGuestCR4ValidMask(pVCpu->CTX_SUFF(pVM));
6151 if (uNewCrX & ~(uint64_t)fValid)
6152 {
6153 Log(("Trying to set reserved CR4 bits: NewCR4=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
6154 return iemRaiseGeneralProtectionFault0(pVCpu);
6155 }
6156
6157 bool const fPcide = !(uOldCrX & X86_CR4_PCIDE) && (uNewCrX & X86_CR4_PCIDE);
6158 bool const fLongMode = CPUMIsGuestInLongModeEx(IEM_GET_CTX(pVCpu));
6159
6160 /* PCIDE check. */
6161 if ( fPcide
6162 && ( !fLongMode
6163 || (pVCpu->cpum.GstCtx.cr3 & UINT64_C(0xfff))))
6164 {
6165 Log(("Trying to set PCIDE with invalid PCID or outside long mode. Pcid=%#x\n", (pVCpu->cpum.GstCtx.cr3 & UINT64_C(0xfff))));
6166 return iemRaiseGeneralProtectionFault0(pVCpu);
6167 }
6168
6169 /* PAE check. */
6170 if ( fLongMode
6171 && (uOldCrX & X86_CR4_PAE)
6172 && !(uNewCrX & X86_CR4_PAE))
6173 {
6174 Log(("Trying to set clear CR4.PAE while long mode is active\n"));
6175 return iemRaiseGeneralProtectionFault0(pVCpu);
6176 }
6177
6178 if (!IEM_SVM_IS_WRITE_CR_INTERCEPT_SET(pVCpu, /*cr*/ 4))
6179 { /* probable */ }
6180 else
6181 {
6182 Log(("iemCImpl_load_Cr%#x: Guest intercept -> #VMEXIT\n", iCrReg));
6183 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6184 IEM_SVM_CRX_VMEXIT_RET(pVCpu, SVM_EXIT_WRITE_CR4, enmAccessCrX, iGReg);
6185 }
6186
6187 /* Check for bits that must remain set or cleared in VMX operation,
6188 see Intel spec. 23.8 "Restrictions on VMX operation". */
6189 if (!IEM_VMX_IS_ROOT_MODE(pVCpu))
6190 { /* probable */ }
6191 else
6192 {
6193 uint64_t const uCr4Fixed0 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed0;
6194 if ((uNewCrX & uCr4Fixed0) != uCr4Fixed0)
6195 {
6196 Log(("Trying to clear reserved CR4 bits in VMX operation: NewCr4=%#llx MB1=%#llx\n", uNewCrX, uCr4Fixed0));
6197 return iemRaiseGeneralProtectionFault0(pVCpu);
6198 }
6199
6200 uint64_t const uCr4Fixed1 = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64Cr4Fixed1;
6201 if (uNewCrX & ~uCr4Fixed1)
6202 {
6203 Log(("Trying to set reserved CR4 bits in VMX operation: NewCr4=%#llx MB0=%#llx\n", uNewCrX, uCr4Fixed1));
6204 return iemRaiseGeneralProtectionFault0(pVCpu);
6205 }
6206 }
6207
6208 IEMTLBTRACE_LOAD_CR4(pVCpu, uNewCrX, uOldCrX);
6209
6210 /*
6211 * Notify PGM.
6212 */
6213 if ((uNewCrX ^ uOldCrX) & (X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_PCIDE /* | X86_CR4_SMEP */))
6214 {
6215 if ( !CPUMIsPaePagingEnabled(pVCpu->cpum.GstCtx.cr0, uNewCrX, pVCpu->cpum.GstCtx.msrEFER)
6216 || CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)))
6217 { /* likely */ }
6218 else
6219 {
6220 Assert(enmAccessCrX == IEMACCESSCRX_MOV_CRX);
6221 IEM_MAP_PAE_PDPES_AT_CR3_RET(pVCpu, iCrReg, pVCpu->cpum.GstCtx.cr3);
6222 }
6223 rc = PGMFlushTLB(pVCpu, pVCpu->cpum.GstCtx.cr3, true /* global */);
6224 AssertRCReturn(rc, rc);
6225 /* ignore informational status codes */
6226 }
6227
6228 /*
6229 * Change it.
6230 */
6231 rc = CPUMSetGuestCR4(pVCpu, uNewCrX);
6232 AssertRCSuccessReturn(rc, rc);
6233 Assert(pVCpu->cpum.GstCtx.cr4 == uNewCrX);
6234
6235 rcStrict = PGMChangeMode(pVCpu, pVCpu->cpum.GstCtx.cr0, pVCpu->cpum.GstCtx.cr4, pVCpu->cpum.GstCtx.msrEFER,
6236 false /* fForce */);
6237 break;
6238 }
6239
6240 /*
6241 * CR8 maps to the APIC TPR.
6242 */
6243 case 8:
6244 {
6245 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
6246 if (uNewCrX & ~(uint64_t)0xf)
6247 {
6248 Log(("Trying to set reserved CR8 bits (%#RX64)\n", uNewCrX));
6249 return iemRaiseGeneralProtectionFault0(pVCpu);
6250 }
6251
6252 if (!IEM_IS_IN_GUEST(pVCpu))
6253 { /* probable */ }
6254#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6255 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
6256 && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_USE_TPR_SHADOW))
6257 {
6258 /*
6259 * If the Mov-to-CR8 doesn't cause a VM-exit, bits 0:3 of the source operand
6260 * is copied to bits 7:4 of the VTPR. Bits 0:3 and bits 31:8 of the VTPR are
6261 * cleared. Following this the processor performs TPR virtualization.
6262 *
6263 * However, we should not perform TPR virtualization immediately here but
6264 * after this instruction has completed.
6265 *
6266 * See Intel spec. 29.3 "Virtualizing CR8-based TPR Accesses"
6267 * See Intel spec. 27.1 "Architectural State Before A VM-exit"
6268 */
6269 uint32_t const uTpr = (uNewCrX & 0xf) << 4;
6270 Log(("iemCImpl_load_Cr%#x: Virtualizing TPR (%#x) write\n", iCrReg, uTpr));
6271 iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_TPR, uTpr);
6272 iemVmxVirtApicSetPendingWrite(pVCpu, XAPIC_OFF_TPR);
6273 rcStrict = VINF_SUCCESS;
6274 break;
6275 }
6276#endif
6277#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
6278 else if (pVCpu->iem.s.fExec & IEM_F_X86_CTX_SVM)
6279 {
6280 if (IEM_SVM_IS_WRITE_CR_INTERCEPT_SET(pVCpu, /*cr*/ 8))
6281 {
6282 Log(("iemCImpl_load_Cr%#x: Guest intercept -> #VMEXIT\n", iCrReg));
6283 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6284 IEM_SVM_CRX_VMEXIT_RET(pVCpu, SVM_EXIT_WRITE_CR8, enmAccessCrX, iGReg);
6285 }
6286
6287 pVCpu->cpum.GstCtx.hwvirt.svm.Vmcb.ctrl.IntCtrl.n.u8VTPR = uNewCrX;
6288 if (CPUMIsGuestSvmVirtIntrMasking(pVCpu, IEM_GET_CTX(pVCpu)))
6289 {
6290 rcStrict = VINF_SUCCESS;
6291 break;
6292 }
6293 }
6294#endif
6295 uint8_t const u8Tpr = (uint8_t)uNewCrX << 4;
6296 APICSetTpr(pVCpu, u8Tpr);
6297 rcStrict = VINF_SUCCESS;
6298 break;
6299 }
6300
6301 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
6302 }
6303
6304 /*
6305 * Advance the RIP on success.
6306 */
6307 if (RT_SUCCESS(rcStrict))
6308 {
6309 if (rcStrict != VINF_SUCCESS)
6310 iemSetPassUpStatus(pVCpu, rcStrict);
6311 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6312 }
6313
6314 return rcStrict;
6315}
6316
6317
6318/**
6319 * Implements mov CRx,GReg.
6320 *
6321 * @param iCrReg The CRx register to write (valid).
6322 * @param iGReg The general register to load the CRx value from.
6323 */
6324IEM_CIMPL_DEF_2(iemCImpl_mov_Cd_Rd, uint8_t, iCrReg, uint8_t, iGReg)
6325{
6326 if (IEM_GET_CPL(pVCpu) != 0)
6327 return iemRaiseGeneralProtectionFault0(pVCpu);
6328 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6329
6330 /*
6331 * Read the new value from the source register and call common worker.
6332 */
6333 uint64_t uNewCrX;
6334 if (IEM_IS_64BIT_CODE(pVCpu))
6335 uNewCrX = iemGRegFetchU64(pVCpu, iGReg);
6336 else
6337 uNewCrX = iemGRegFetchU32(pVCpu, iGReg);
6338
6339#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6340 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6341 { /* probable */ }
6342 else
6343 {
6344 VBOXSTRICTRC rcStrict = VINF_VMX_INTERCEPT_NOT_ACTIVE;
6345 switch (iCrReg)
6346 {
6347 case 0:
6348 case 4: rcStrict = iemVmxVmexitInstrMovToCr0Cr4(pVCpu, iCrReg, &uNewCrX, iGReg, cbInstr); break;
6349 case 3: rcStrict = iemVmxVmexitInstrMovToCr3(pVCpu, uNewCrX, iGReg, cbInstr); break;
6350 case 8: rcStrict = iemVmxVmexitInstrMovToCr8(pVCpu, iGReg, cbInstr); break;
6351 }
6352 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
6353 return rcStrict;
6354 }
6355#endif
6356
6357 return IEM_CIMPL_CALL_4(iemCImpl_load_CrX, iCrReg, uNewCrX, IEMACCESSCRX_MOV_CRX, iGReg);
6358}
6359
6360
6361/**
6362 * Implements 'LMSW r/m16'
6363 *
6364 * @param u16NewMsw The new value.
6365 * @param GCPtrEffDst The guest-linear address of the source operand in case
6366 * of a memory operand. For register operand, pass
6367 * NIL_RTGCPTR.
6368 */
6369IEM_CIMPL_DEF_2(iemCImpl_lmsw, uint16_t, u16NewMsw, RTGCPTR, GCPtrEffDst)
6370{
6371 if (IEM_GET_CPL(pVCpu) != 0)
6372 return iemRaiseGeneralProtectionFault0(pVCpu);
6373 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6374 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
6375
6376#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6377 /* Check nested-guest VMX intercept and get updated MSW if there's no VM-exit. */
6378 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6379 { /* probable */ }
6380 else
6381 {
6382 VBOXSTRICTRC rcStrict = iemVmxVmexitInstrLmsw(pVCpu, pVCpu->cpum.GstCtx.cr0, &u16NewMsw, GCPtrEffDst, cbInstr);
6383 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
6384 return rcStrict;
6385 }
6386#else
6387 RT_NOREF_PV(GCPtrEffDst);
6388#endif
6389
6390 /*
6391 * Compose the new CR0 value and call common worker.
6392 */
6393 uint64_t uNewCr0 = pVCpu->cpum.GstCtx.cr0 & ~(X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
6394 uNewCr0 |= u16NewMsw & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
6395 return IEM_CIMPL_CALL_4(iemCImpl_load_CrX, /*cr*/ 0, uNewCr0, IEMACCESSCRX_LMSW, UINT8_MAX /* iGReg */);
6396}
6397
6398
6399/**
6400 * Implements 'CLTS'.
6401 */
6402IEM_CIMPL_DEF_0(iemCImpl_clts)
6403{
6404 if (IEM_GET_CPL(pVCpu) != 0)
6405 return iemRaiseGeneralProtectionFault0(pVCpu);
6406
6407 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
6408 uint64_t uNewCr0 = pVCpu->cpum.GstCtx.cr0;
6409 uNewCr0 &= ~X86_CR0_TS;
6410
6411#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6412 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6413 { /* probable */ }
6414 else
6415 {
6416 VBOXSTRICTRC rcStrict = iemVmxVmexitInstrClts(pVCpu, cbInstr);
6417 if (rcStrict == VINF_VMX_MODIFIES_BEHAVIOR)
6418 uNewCr0 |= (pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS);
6419 else if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
6420 return rcStrict;
6421 }
6422#endif
6423
6424 return IEM_CIMPL_CALL_4(iemCImpl_load_CrX, /*cr*/ 0, uNewCr0, IEMACCESSCRX_CLTS, UINT8_MAX /* iGReg */);
6425}
6426
6427
6428/**
6429 * Implements mov GReg,DRx.
6430 *
6431 * @param iGReg The general register to store the DRx value in.
6432 * @param iDrReg The DRx register to read (0-7).
6433 */
6434IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Dd, uint8_t, iGReg, uint8_t, iDrReg)
6435{
6436#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6437 /*
6438 * Check nested-guest VMX intercept.
6439 * Unlike most other intercepts, the Mov DRx intercept takes preceedence
6440 * over CPL and CR4.DE and even DR4/DR5 checks.
6441 *
6442 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
6443 */
6444 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6445 { /* probable */ }
6446 else
6447 {
6448 VBOXSTRICTRC rcStrict = iemVmxVmexitInstrMovDrX(pVCpu, VMXINSTRID_MOV_FROM_DRX, iDrReg, iGReg, cbInstr);
6449 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
6450 return rcStrict;
6451 }
6452#endif
6453
6454 /*
6455 * Check preconditions.
6456 */
6457 /* Raise GPs. */
6458 if (IEM_GET_CPL(pVCpu) != 0)
6459 return iemRaiseGeneralProtectionFault0(pVCpu);
6460 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6461 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
6462
6463 /** @todo \#UD in outside ring-0 too? */
6464 if (iDrReg == 4 || iDrReg == 5)
6465 {
6466 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_CR4);
6467 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_DE)
6468 {
6469 Log(("mov r%u,dr%u: CR4.DE=1 -> #GP(0)\n", iGReg, iDrReg));
6470 return iemRaiseGeneralProtectionFault0(pVCpu);
6471 }
6472 iDrReg += 2;
6473 }
6474
6475 /* Raise #DB if general access detect is enabled. */
6476 if (pVCpu->cpum.GstCtx.dr[7] & X86_DR7_GD)
6477 {
6478 Log(("mov r%u,dr%u: DR7.GD=1 -> #DB\n", iGReg, iDrReg));
6479 return iemRaiseDebugException(pVCpu);
6480 }
6481
6482 /*
6483 * Read the debug register and store it in the specified general register.
6484 */
6485 uint64_t drX;
6486 switch (iDrReg)
6487 {
6488 case 0:
6489 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
6490 drX = pVCpu->cpum.GstCtx.dr[0];
6491 break;
6492 case 1:
6493 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
6494 drX = pVCpu->cpum.GstCtx.dr[1];
6495 break;
6496 case 2:
6497 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
6498 drX = pVCpu->cpum.GstCtx.dr[2];
6499 break;
6500 case 3:
6501 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
6502 drX = pVCpu->cpum.GstCtx.dr[3];
6503 break;
6504 case 6:
6505 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR6);
6506 drX = pVCpu->cpum.GstCtx.dr[6];
6507 drX |= X86_DR6_RA1_MASK;
6508 drX &= ~X86_DR6_RAZ_MASK;
6509 break;
6510 case 7:
6511 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
6512 drX = pVCpu->cpum.GstCtx.dr[7];
6513 drX |=X86_DR7_RA1_MASK;
6514 drX &= ~X86_DR7_RAZ_MASK;
6515 break;
6516 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* caller checks */
6517 }
6518
6519 /** @todo SVM nested-guest intercept for DR8-DR15? */
6520 /*
6521 * Check for any SVM nested-guest intercepts for the DRx read.
6522 */
6523 if (!IEM_SVM_IS_READ_DR_INTERCEPT_SET(pVCpu, iDrReg))
6524 { /* probable */ }
6525 else
6526 {
6527 Log(("mov r%u,dr%u: Guest intercept -> #VMEXIT\n", iGReg, iDrReg));
6528 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6529 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_READ_DR0 + (iDrReg & 0xf),
6530 IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fSvmDecodeAssists ? (iGReg & 7) : 0, 0 /* uExitInfo2 */);
6531 }
6532
6533 if (IEM_IS_64BIT_CODE(pVCpu))
6534 iemGRegStoreU64(pVCpu, iGReg, drX);
6535 else
6536 iemGRegStoreU32(pVCpu, iGReg, (uint32_t)drX);
6537
6538 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6539}
6540
6541
6542/**
6543 * Implements mov DRx,GReg.
6544 *
6545 * @param iDrReg The DRx register to write (valid).
6546 * @param iGReg The general register to load the DRx value from.
6547 */
6548IEM_CIMPL_DEF_2(iemCImpl_mov_Dd_Rd, uint8_t, iDrReg, uint8_t, iGReg)
6549{
6550#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6551 /*
6552 * Check nested-guest VMX intercept.
6553 * Unlike most other intercepts, the Mov DRx intercept takes preceedence
6554 * over CPL and CR4.DE and even DR4/DR5 checks.
6555 *
6556 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
6557 */
6558 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6559 { /* probable */ }
6560 else
6561 {
6562 VBOXSTRICTRC rcStrict = iemVmxVmexitInstrMovDrX(pVCpu, VMXINSTRID_MOV_TO_DRX, iDrReg, iGReg, cbInstr);
6563 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
6564 return rcStrict;
6565 }
6566#endif
6567
6568 /*
6569 * Check preconditions.
6570 */
6571 if (IEM_GET_CPL(pVCpu) != 0)
6572 return iemRaiseGeneralProtectionFault0(pVCpu);
6573 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6574 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
6575
6576 if (iDrReg == 4 || iDrReg == 5)
6577 {
6578 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_CR4);
6579 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_DE)
6580 {
6581 Log(("mov dr%u,r%u: CR4.DE=1 -> #GP(0)\n", iDrReg, iGReg));
6582 return iemRaiseGeneralProtectionFault0(pVCpu);
6583 }
6584 iDrReg += 2;
6585 }
6586
6587 /* Raise #DB if general access detect is enabled. */
6588 /** @todo is \#DB/DR7.GD raised before any reserved high bits in DR7/DR6
6589 * \#GP? */
6590 if (pVCpu->cpum.GstCtx.dr[7] & X86_DR7_GD)
6591 {
6592 Log(("mov dr%u,r%u: DR7.GD=1 -> #DB\n", iDrReg, iGReg));
6593 return iemRaiseDebugException(pVCpu);
6594 }
6595
6596 /*
6597 * Read the new value from the source register.
6598 */
6599 uint64_t uNewDrX;
6600 if (IEM_IS_64BIT_CODE(pVCpu))
6601 uNewDrX = iemGRegFetchU64(pVCpu, iGReg);
6602 else
6603 uNewDrX = iemGRegFetchU32(pVCpu, iGReg);
6604
6605 /*
6606 * Adjust it.
6607 */
6608 switch (iDrReg)
6609 {
6610 case 0:
6611 case 1:
6612 case 2:
6613 case 3:
6614 /* nothing to adjust */
6615 break;
6616
6617 case 6:
6618 if (uNewDrX & X86_DR6_MBZ_MASK)
6619 {
6620 Log(("mov dr%u,%#llx: DR6 high bits are not zero -> #GP(0)\n", iDrReg, uNewDrX));
6621 return iemRaiseGeneralProtectionFault0(pVCpu);
6622 }
6623 uNewDrX |= X86_DR6_RA1_MASK;
6624 uNewDrX &= ~X86_DR6_RAZ_MASK;
6625 break;
6626
6627 case 7:
6628 if (uNewDrX & X86_DR7_MBZ_MASK)
6629 {
6630 Log(("mov dr%u,%#llx: DR7 high bits are not zero -> #GP(0)\n", iDrReg, uNewDrX));
6631 return iemRaiseGeneralProtectionFault0(pVCpu);
6632 }
6633 uNewDrX |= X86_DR7_RA1_MASK;
6634 uNewDrX &= ~X86_DR7_RAZ_MASK;
6635 break;
6636
6637 IEM_NOT_REACHED_DEFAULT_CASE_RET();
6638 }
6639
6640 /** @todo SVM nested-guest intercept for DR8-DR15? */
6641 /*
6642 * Check for any SVM nested-guest intercepts for the DRx write.
6643 */
6644 if (!IEM_SVM_IS_WRITE_DR_INTERCEPT_SET(pVCpu, iDrReg))
6645 { /* probable */ }
6646 else
6647 {
6648 Log2(("mov dr%u,r%u: Guest intercept -> #VMEXIT\n", iDrReg, iGReg));
6649 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6650 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_WRITE_DR0 + (iDrReg & 0xf),
6651 IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fSvmDecodeAssists ? (iGReg & 7) : 0, 0 /* uExitInfo2 */);
6652 }
6653
6654 /*
6655 * Do the actual setting.
6656 */
6657 if (iDrReg < 4)
6658 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
6659 else if (iDrReg == 6)
6660 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR6);
6661
6662 int rc = CPUMSetGuestDRx(pVCpu, iDrReg, uNewDrX);
6663 AssertRCSuccessReturn(rc, RT_SUCCESS_NP(rc) ? VERR_IEM_IPE_1 : rc);
6664
6665 /*
6666 * Re-init hardware breakpoint summary if it was DR7 that got changed.
6667 *
6668 * We also do this when an active data breakpoint is updated so that the
6669 * TLB entry can be correctly invalidated.
6670 */
6671 if ( iDrReg == 7
6672#ifdef IEM_WITH_DATA_TLB
6673 || ( iDrReg <= 3
6674 && (X86_DR7_L_G(iDrReg) & pVCpu->cpum.GstCtx.dr[7])
6675 && X86_DR7_IS_W_CFG(pVCpu->cpum.GstCtx.dr[7], iDrReg) )
6676#endif
6677 )
6678 iemRecalcExecDbgFlags(pVCpu);
6679
6680 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6681}
6682
6683
6684/**
6685 * Implements mov GReg,TRx.
6686 *
6687 * @param iGReg The general register to store the
6688 * TRx value in.
6689 * @param iTrReg The TRx register to read (6/7).
6690 */
6691IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Td, uint8_t, iGReg, uint8_t, iTrReg)
6692{
6693 /*
6694 * Check preconditions. NB: This instruction is 386/486 only.
6695 */
6696
6697 /* Raise GPs. */
6698 if (IEM_GET_CPL(pVCpu) != 0)
6699 return iemRaiseGeneralProtectionFault0(pVCpu);
6700 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6701
6702 if (iTrReg < 6 || iTrReg > 7)
6703 {
6704 /** @todo Do Intel CPUs reject this or are the TRs aliased? */
6705 Log(("mov r%u,tr%u: invalid register -> #GP(0)\n", iGReg, iTrReg));
6706 return iemRaiseGeneralProtectionFault0(pVCpu);
6707 }
6708
6709 /*
6710 * Read the test register and store it in the specified general register.
6711 * This is currently a dummy implementation that only exists to satisfy
6712 * old debuggers like WDEB386 or OS/2 KDB which unconditionally read the
6713 * TR6/TR7 registers. Software which actually depends on the TR values
6714 * (different on 386/486) is exceedingly rare.
6715 */
6716 uint32_t trX;
6717 switch (iTrReg)
6718 {
6719 case 6:
6720 trX = 0; /* Currently a dummy. */
6721 break;
6722 case 7:
6723 trX = 0; /* Currently a dummy. */
6724 break;
6725 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
6726 }
6727
6728 iemGRegStoreU32(pVCpu, iGReg, trX);
6729
6730 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6731}
6732
6733
6734/**
6735 * Implements mov TRx,GReg.
6736 *
6737 * @param iTrReg The TRx register to write (valid).
6738 * @param iGReg The general register to load the TRx
6739 * value from.
6740 */
6741IEM_CIMPL_DEF_2(iemCImpl_mov_Td_Rd, uint8_t, iTrReg, uint8_t, iGReg)
6742{
6743 /*
6744 * Check preconditions. NB: This instruction is 386/486 only.
6745 */
6746
6747 /* Raise GPs. */
6748 if (IEM_GET_CPL(pVCpu) != 0)
6749 return iemRaiseGeneralProtectionFault0(pVCpu);
6750 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6751
6752 if (iTrReg < 6 || iTrReg > 7)
6753 {
6754 /** @todo Do Intel CPUs reject this or are the TRs aliased? */
6755 Log(("mov r%u,tr%u: invalid register -> #GP(0)\n", iGReg, iTrReg));
6756 return iemRaiseGeneralProtectionFault0(pVCpu);
6757 }
6758
6759 /*
6760 * Read the new value from the source register.
6761 */
6762 uint32_t uNewTrX = iemGRegFetchU32(pVCpu, iGReg);
6763
6764 /*
6765 * Here we would do the actual setting if this weren't a dummy implementation.
6766 * This is currently a dummy implementation that only exists to prevent
6767 * old debuggers like WDEB386 or OS/2 KDB from crashing.
6768 */
6769 RT_NOREF(uNewTrX);
6770
6771 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6772}
6773
6774
6775/**
6776 * Implements 'INVLPG m'.
6777 *
6778 * @param GCPtrPage The effective address of the page to invalidate.
6779 * @remarks Updates the RIP.
6780 */
6781IEM_CIMPL_DEF_1(iemCImpl_invlpg, RTGCPTR, GCPtrPage)
6782{
6783 /* ring-0 only. */
6784 if (IEM_GET_CPL(pVCpu) != 0)
6785 return iemRaiseGeneralProtectionFault0(pVCpu);
6786 Assert(!pVCpu->cpum.GstCtx.eflags.Bits.u1VM);
6787 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_EFER);
6788
6789 if (!IEM_IS_IN_GUEST(pVCpu))
6790 { /* probable */ }
6791#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6792 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
6793 && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_INVLPG_EXIT))
6794 {
6795 Log(("invlpg: Guest intercept (%RGp) -> VM-exit\n", GCPtrPage));
6796 return iemVmxVmexitInstrInvlpg(pVCpu, GCPtrPage, cbInstr);
6797 }
6798#endif
6799 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_INVLPG))
6800 {
6801 Log(("invlpg: Guest intercept (%RGp) -> #VMEXIT\n", GCPtrPage));
6802 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
6803 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_INVLPG,
6804 IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fSvmDecodeAssists ? GCPtrPage : 0, 0 /* uExitInfo2 */);
6805 }
6806
6807 int rc = PGMInvalidatePage(pVCpu, GCPtrPage);
6808 if (rc == VINF_SUCCESS)
6809 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6810 if (rc == VINF_PGM_SYNC_CR3)
6811 {
6812 iemSetPassUpStatus(pVCpu, rc);
6813 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6814 }
6815
6816 AssertMsg(RT_FAILURE_NP(rc), ("%Rrc\n", rc));
6817 Log(("PGMInvalidatePage(%RGv) -> %Rrc\n", GCPtrPage, rc));
6818 return rc;
6819}
6820
6821
6822/**
6823 * Implements INVPCID.
6824 *
6825 * @param iEffSeg The segment of the invpcid descriptor.
6826 * @param GCPtrInvpcidDesc The address of invpcid descriptor.
6827 * @param uInvpcidType The invalidation type.
6828 * @remarks Updates the RIP.
6829 */
6830IEM_CIMPL_DEF_3(iemCImpl_invpcid, uint8_t, iEffSeg, RTGCPTR, GCPtrInvpcidDesc, uint64_t, uInvpcidType)
6831{
6832 /*
6833 * Check preconditions.
6834 */
6835 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fInvpcid)
6836 return iemRaiseUndefinedOpcode(pVCpu);
6837
6838 /* When in VMX non-root mode and INVPCID is not enabled, it results in #UD. */
6839 if (RT_LIKELY( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
6840 || IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_INVPCID)))
6841 { /* likely */ }
6842 else
6843 {
6844 Log(("invpcid: Not enabled for nested-guest execution -> #UD\n"));
6845 return iemRaiseUndefinedOpcode(pVCpu);
6846 }
6847
6848 if (IEM_GET_CPL(pVCpu) != 0)
6849 {
6850 Log(("invpcid: CPL != 0 -> #GP(0)\n"));
6851 return iemRaiseGeneralProtectionFault0(pVCpu);
6852 }
6853
6854 if (IEM_IS_V86_MODE(pVCpu))
6855 {
6856 Log(("invpcid: v8086 mode -> #GP(0)\n"));
6857 return iemRaiseGeneralProtectionFault0(pVCpu);
6858 }
6859
6860 /*
6861 * Check nested-guest intercept.
6862 *
6863 * INVPCID causes a VM-exit if "enable INVPCID" and "INVLPG exiting" are
6864 * both set. We have already checked the former earlier in this function.
6865 *
6866 * CPL and virtual-8086 mode checks take priority over this VM-exit.
6867 * See Intel spec. "25.1.1 Relative Priority of Faults and VM Exits".
6868 */
6869 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
6870 || !IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_INVLPG_EXIT))
6871 { /* probable */ }
6872 else
6873 {
6874 Log(("invpcid: Guest intercept -> #VM-exit\n"));
6875 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_INVPCID, VMXINSTRID_NONE, cbInstr);
6876 }
6877
6878 if (uInvpcidType > X86_INVPCID_TYPE_MAX_VALID)
6879 {
6880 Log(("invpcid: invalid/unrecognized invpcid type %#RX64 -> #GP(0)\n", uInvpcidType));
6881 return iemRaiseGeneralProtectionFault0(pVCpu);
6882 }
6883 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_EFER);
6884
6885 /*
6886 * Fetch the invpcid descriptor from guest memory.
6887 */
6888/** @todo Check if the entire 128 bits are always read for all types. Check for invalid types as well. */
6889 RTUINT128U uDesc;
6890 VBOXSTRICTRC rcStrict = iemMemFetchDataU128(pVCpu, &uDesc, iEffSeg, GCPtrInvpcidDesc);
6891 if (rcStrict == VINF_SUCCESS)
6892 {
6893 /*
6894 * Validate the descriptor.
6895 */
6896 if (uDesc.s.Lo > 0xfff)
6897 {
6898 Log(("invpcid: reserved bits set in invpcid descriptor %#RX64 -> #GP(0)\n", uDesc.s.Lo));
6899 return iemRaiseGeneralProtectionFault0(pVCpu);
6900 }
6901
6902 RTGCUINTPTR64 const GCPtrInvAddr = uDesc.s.Hi;
6903 uint8_t const uPcid = uDesc.s.Lo & UINT64_C(0xfff);
6904 uint32_t const uCr4 = pVCpu->cpum.GstCtx.cr4;
6905 uint64_t const uCr3 = pVCpu->cpum.GstCtx.cr3;
6906 switch (uInvpcidType)
6907 {
6908 case X86_INVPCID_TYPE_INDV_ADDR:
6909 {
6910 if (!IEM_IS_CANONICAL(GCPtrInvAddr))
6911 {
6912 Log(("invpcid: invalidation address %#RGP is not canonical -> #GP(0)\n", GCPtrInvAddr));
6913 return iemRaiseGeneralProtectionFault0(pVCpu);
6914 }
6915 if ( !(uCr4 & X86_CR4_PCIDE)
6916 && uPcid != 0)
6917 {
6918 Log(("invpcid: invalid pcid %#x\n", uPcid));
6919 return iemRaiseGeneralProtectionFault0(pVCpu);
6920 }
6921
6922 /* Invalidate mappings for the linear address tagged with PCID except global translations. */
6923/** @todo PGMFlushTLB is overkill for X86_INVPCID_TYPE_INDV_ADDR. Add a fGlobal parameter
6924 * to PGMInvalidatePage or add a new function to support this variation of invlpg. */
6925 PGMFlushTLB(pVCpu, uCr3, false /* fGlobal */);
6926 break;
6927 }
6928
6929 case X86_INVPCID_TYPE_SINGLE_CONTEXT:
6930 {
6931 if ( !(uCr4 & X86_CR4_PCIDE)
6932 && uPcid != 0)
6933 {
6934 Log(("invpcid: invalid pcid %#x\n", uPcid));
6935 return iemRaiseGeneralProtectionFault0(pVCpu);
6936 }
6937 /* Invalidate all mappings associated with PCID except global translations. */
6938 PGMFlushTLB(pVCpu, uCr3, false /* fGlobal */);
6939 break;
6940 }
6941
6942 case X86_INVPCID_TYPE_ALL_CONTEXT_INCL_GLOBAL:
6943 {
6944 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
6945 break;
6946 }
6947
6948 case X86_INVPCID_TYPE_ALL_CONTEXT_EXCL_GLOBAL:
6949 {
6950 PGMFlushTLB(pVCpu, uCr3, false /* fGlobal */);
6951 break;
6952 }
6953 IEM_NOT_REACHED_DEFAULT_CASE_RET();
6954 }
6955 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6956 }
6957 return rcStrict;
6958}
6959
6960
6961/**
6962 * Implements INVD.
6963 */
6964IEM_CIMPL_DEF_0(iemCImpl_invd)
6965{
6966 if (IEM_GET_CPL(pVCpu) != 0)
6967 {
6968 Log(("invd: CPL != 0 -> #GP(0)\n"));
6969 return iemRaiseGeneralProtectionFault0(pVCpu);
6970 }
6971
6972 if (!IEM_IS_IN_GUEST(pVCpu))
6973 { /* probable */ }
6974 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6975 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_INVD, cbInstr);
6976 else
6977 IEM_SVM_CHECK_INSTR_INTERCEPT(pVCpu, SVM_CTRL_INTERCEPT_INVD, SVM_EXIT_INVD, 0, 0, cbInstr);
6978
6979 /* We currently take no action here. */
6980 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
6981}
6982
6983
6984/**
6985 * Implements WBINVD.
6986 */
6987IEM_CIMPL_DEF_0(iemCImpl_wbinvd)
6988{
6989 if (IEM_GET_CPL(pVCpu) != 0)
6990 {
6991 Log(("wbinvd: CPL != 0 -> #GP(0)\n"));
6992 return iemRaiseGeneralProtectionFault0(pVCpu);
6993 }
6994
6995 if (!IEM_IS_IN_GUEST(pVCpu))
6996 { /* probable */ }
6997 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
6998 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_WBINVD, cbInstr);
6999 else
7000 IEM_SVM_CHECK_INSTR_INTERCEPT(pVCpu, SVM_CTRL_INTERCEPT_WBINVD, SVM_EXIT_WBINVD, 0, 0, cbInstr);
7001
7002 /* We currently take no action here. */
7003 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7004}
7005
7006
7007/** Opcode 0x0f 0xaa. */
7008IEM_CIMPL_DEF_0(iemCImpl_rsm)
7009{
7010 IEM_SVM_CHECK_INSTR_INTERCEPT(pVCpu, SVM_CTRL_INTERCEPT_RSM, SVM_EXIT_RSM, 0, 0, cbInstr);
7011 NOREF(cbInstr);
7012 return iemRaiseUndefinedOpcode(pVCpu);
7013}
7014
7015
7016/**
7017 * Implements RDTSC.
7018 */
7019IEM_CIMPL_DEF_0(iemCImpl_rdtsc)
7020{
7021 /*
7022 * Check preconditions.
7023 */
7024 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fTsc)
7025 return iemRaiseUndefinedOpcode(pVCpu);
7026
7027 if (IEM_GET_CPL(pVCpu) != 0)
7028 {
7029 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
7030 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_TSD)
7031 {
7032 Log(("rdtsc: CR4.TSD and CPL=%u -> #GP(0)\n", IEM_GET_CPL(pVCpu)));
7033 return iemRaiseGeneralProtectionFault0(pVCpu);
7034 }
7035 }
7036
7037 if (!IEM_IS_IN_GUEST(pVCpu))
7038 { /* probable */ }
7039 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7040 && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_RDTSC_EXIT))
7041 {
7042 Log(("rdtsc: Guest intercept -> VM-exit\n"));
7043 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_RDTSC, cbInstr);
7044 }
7045 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_RDTSC))
7046 {
7047 Log(("rdtsc: Guest intercept -> #VMEXIT\n"));
7048 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7049 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_RDTSC, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7050 }
7051
7052 /*
7053 * Do the job.
7054 */
7055 uint64_t uTicks = TMCpuTickGet(pVCpu);
7056#if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
7057 uTicks = CPUMApplyNestedGuestTscOffset(pVCpu, uTicks);
7058#endif
7059 pVCpu->cpum.GstCtx.rax = RT_LO_U32(uTicks);
7060 pVCpu->cpum.GstCtx.rdx = RT_HI_U32(uTicks);
7061 pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX); /* For IEMExecDecodedRdtsc. */
7062 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7063}
7064
7065
7066/**
7067 * Implements RDTSC.
7068 */
7069IEM_CIMPL_DEF_0(iemCImpl_rdtscp)
7070{
7071 /*
7072 * Check preconditions.
7073 */
7074 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fRdTscP)
7075 return iemRaiseUndefinedOpcode(pVCpu);
7076
7077 if (RT_LIKELY( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7078 || IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_RDTSCP)))
7079 { /* likely */ }
7080 else
7081 {
7082 Log(("rdtscp: Not enabled for VMX non-root mode -> #UD\n"));
7083 return iemRaiseUndefinedOpcode(pVCpu);
7084 }
7085
7086 if (IEM_GET_CPL(pVCpu) != 0)
7087 {
7088 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
7089 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_TSD)
7090 {
7091 Log(("rdtscp: CR4.TSD and CPL=%u -> #GP(0)\n", IEM_GET_CPL(pVCpu)));
7092 return iemRaiseGeneralProtectionFault0(pVCpu);
7093 }
7094 }
7095
7096 if (!IEM_IS_IN_GUEST(pVCpu))
7097 { /* probable */ }
7098 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7099 && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_RDTSC_EXIT))
7100 {
7101 Log(("rdtscp: Guest intercept -> VM-exit\n"));
7102 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_RDTSCP, cbInstr);
7103 }
7104 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_RDTSCP))
7105 {
7106 Log(("rdtscp: Guest intercept -> #VMEXIT\n"));
7107 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7108 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_RDTSCP, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7109 }
7110
7111 /*
7112 * Do the job.
7113 * Query the MSR first in case of trips to ring-3.
7114 */
7115 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_TSC_AUX);
7116 VBOXSTRICTRC rcStrict = CPUMQueryGuestMsr(pVCpu, MSR_K8_TSC_AUX, &pVCpu->cpum.GstCtx.rcx);
7117 if (rcStrict == VINF_SUCCESS)
7118 {
7119 /* Low dword of the TSC_AUX msr only. */
7120 pVCpu->cpum.GstCtx.rcx &= UINT32_C(0xffffffff);
7121
7122 uint64_t uTicks = TMCpuTickGet(pVCpu);
7123#if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
7124 uTicks = CPUMApplyNestedGuestTscOffset(pVCpu, uTicks);
7125#endif
7126 pVCpu->cpum.GstCtx.rax = RT_LO_U32(uTicks);
7127 pVCpu->cpum.GstCtx.rdx = RT_HI_U32(uTicks);
7128 pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX); /* For IEMExecDecodedRdtscp. */
7129 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7130 }
7131 return rcStrict;
7132}
7133
7134
7135/**
7136 * Implements RDPMC.
7137 */
7138IEM_CIMPL_DEF_0(iemCImpl_rdpmc)
7139{
7140 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
7141
7142 if ( IEM_GET_CPL(pVCpu) != 0
7143 && !(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PCE))
7144 return iemRaiseGeneralProtectionFault0(pVCpu);
7145
7146 if (!IEM_IS_IN_GUEST(pVCpu))
7147 { /* probable */ }
7148 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7149 && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_RDPMC_EXIT))
7150 {
7151 Log(("rdpmc: Guest intercept -> VM-exit\n"));
7152 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_RDPMC, cbInstr);
7153 }
7154 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_RDPMC))
7155 {
7156 Log(("rdpmc: Guest intercept -> #VMEXIT\n"));
7157 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7158 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_RDPMC, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7159 }
7160
7161 /** @todo Emulate performance counters, for now just return 0. */
7162 pVCpu->cpum.GstCtx.rax = 0;
7163 pVCpu->cpum.GstCtx.rdx = 0;
7164 pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX);
7165 /** @todo We should trigger a \#GP here if the CPU doesn't support the index in
7166 * ecx but see @bugref{3472}! */
7167
7168 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7169}
7170
7171
7172/**
7173 * Implements RDMSR.
7174 */
7175IEM_CIMPL_DEF_0(iemCImpl_rdmsr)
7176{
7177 /*
7178 * Check preconditions.
7179 */
7180 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fMsr)
7181 return iemRaiseUndefinedOpcode(pVCpu);
7182 if (IEM_GET_CPL(pVCpu) != 0)
7183 return iemRaiseGeneralProtectionFault0(pVCpu);
7184
7185 /*
7186 * Check nested-guest intercepts.
7187 */
7188 if (!IEM_IS_IN_GUEST(pVCpu))
7189 { /* probable */ }
7190#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7191 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
7192 {
7193 if (iemVmxIsRdmsrWrmsrInterceptSet(pVCpu, VMX_EXIT_RDMSR, pVCpu->cpum.GstCtx.ecx))
7194 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_RDMSR, cbInstr);
7195 }
7196#endif
7197#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
7198 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_MSR_PROT))
7199 {
7200 VBOXSTRICTRC rcStrict = iemSvmHandleMsrIntercept(pVCpu, pVCpu->cpum.GstCtx.ecx, false /* fWrite */, cbInstr);
7201 if (rcStrict == VINF_SVM_VMEXIT)
7202 return VINF_SUCCESS;
7203 if (rcStrict != VINF_SVM_INTERCEPT_NOT_ACTIVE)
7204 {
7205 Log(("IEM: SVM intercepted rdmsr(%#x) failed. rc=%Rrc\n", pVCpu->cpum.GstCtx.ecx, VBOXSTRICTRC_VAL(rcStrict)));
7206 return rcStrict;
7207 }
7208 }
7209#endif
7210
7211 /*
7212 * Do the job.
7213 */
7214 RTUINT64U uValue;
7215 /** @todo make CPUMAllMsrs.cpp import the necessary MSR state. */
7216 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_ALL_MSRS);
7217
7218 VBOXSTRICTRC rcStrict = CPUMQueryGuestMsr(pVCpu, pVCpu->cpum.GstCtx.ecx, &uValue.u);
7219 if (rcStrict == VINF_SUCCESS)
7220 {
7221 pVCpu->cpum.GstCtx.rax = uValue.s.Lo;
7222 pVCpu->cpum.GstCtx.rdx = uValue.s.Hi;
7223 pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX);
7224
7225 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7226 }
7227
7228#ifndef IN_RING3
7229 /* Deferred to ring-3. */
7230 if (rcStrict == VINF_CPUM_R3_MSR_READ)
7231 {
7232 Log(("IEM: rdmsr(%#x) -> ring-3\n", pVCpu->cpum.GstCtx.ecx));
7233 return rcStrict;
7234 }
7235#endif
7236
7237 /* Often a unimplemented MSR or MSR bit, so worth logging. */
7238 if (pVCpu->iem.s.cLogRelRdMsr < 32)
7239 {
7240 pVCpu->iem.s.cLogRelRdMsr++;
7241 LogRel(("IEM: rdmsr(%#x) -> #GP(0)\n", pVCpu->cpum.GstCtx.ecx));
7242 }
7243 else
7244 Log(( "IEM: rdmsr(%#x) -> #GP(0)\n", pVCpu->cpum.GstCtx.ecx));
7245 AssertMsgReturn(rcStrict == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)), VERR_IPE_UNEXPECTED_STATUS);
7246 return iemRaiseGeneralProtectionFault0(pVCpu);
7247}
7248
7249
7250/**
7251 * Implements WRMSR.
7252 */
7253IEM_CIMPL_DEF_0(iemCImpl_wrmsr)
7254{
7255 /*
7256 * Check preconditions.
7257 */
7258 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fMsr)
7259 return iemRaiseUndefinedOpcode(pVCpu);
7260 if (IEM_GET_CPL(pVCpu) != 0)
7261 return iemRaiseGeneralProtectionFault0(pVCpu);
7262
7263 RTUINT64U uValue;
7264 uValue.s.Lo = pVCpu->cpum.GstCtx.eax;
7265 uValue.s.Hi = pVCpu->cpum.GstCtx.edx;
7266
7267 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
7268
7269 /** @todo make CPUMAllMsrs.cpp import the necessary MSR state. */
7270 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_ALL_MSRS);
7271
7272 /*
7273 * Check nested-guest intercepts.
7274 */
7275 if (!IEM_IS_IN_GUEST(pVCpu))
7276 { /* probable */ }
7277#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7278 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
7279 {
7280 if (iemVmxIsRdmsrWrmsrInterceptSet(pVCpu, VMX_EXIT_WRMSR, idMsr))
7281 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_WRMSR, cbInstr);
7282 }
7283#endif
7284#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
7285 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_MSR_PROT))
7286 {
7287 VBOXSTRICTRC rcStrict = iemSvmHandleMsrIntercept(pVCpu, idMsr, true /* fWrite */, cbInstr);
7288 if (rcStrict == VINF_SVM_VMEXIT)
7289 return VINF_SUCCESS;
7290 if (rcStrict != VINF_SVM_INTERCEPT_NOT_ACTIVE)
7291 {
7292 Log(("IEM: SVM intercepted rdmsr(%#x) failed. rc=%Rrc\n", idMsr, VBOXSTRICTRC_VAL(rcStrict)));
7293 return rcStrict;
7294 }
7295 }
7296#endif
7297
7298 if (idMsr == MSR_K6_EFER)
7299 IEMTLBTRACE_LOAD_EFER(pVCpu, uValue.u, pVCpu->cpum.GstCtx.msrEFER);
7300
7301 /*
7302 * Do the job.
7303 */
7304 VBOXSTRICTRC rcStrict = CPUMSetGuestMsr(pVCpu, idMsr, uValue.u);
7305 if (rcStrict == VINF_SUCCESS)
7306 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7307
7308#ifndef IN_RING3
7309 /* Deferred to ring-3. */
7310 if (rcStrict == VINF_CPUM_R3_MSR_WRITE)
7311 {
7312 Log(("IEM: wrmsr(%#x) -> ring-3\n", idMsr));
7313 return rcStrict;
7314 }
7315#endif
7316
7317 /* Often a unimplemented MSR or MSR bit, so worth logging. */
7318 if (pVCpu->iem.s.cLogRelWrMsr < 32)
7319 {
7320 pVCpu->iem.s.cLogRelWrMsr++;
7321 LogRel(("IEM: wrmsr(%#x,%#x`%08x) -> #GP(0)\n", idMsr, uValue.s.Hi, uValue.s.Lo));
7322 }
7323 else
7324 Log(( "IEM: wrmsr(%#x,%#x`%08x) -> #GP(0)\n", idMsr, uValue.s.Hi, uValue.s.Lo));
7325 AssertMsgReturn(rcStrict == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)), VERR_IPE_UNEXPECTED_STATUS);
7326 return iemRaiseGeneralProtectionFault0(pVCpu);
7327}
7328
7329
7330/**
7331 * Implements 'IN eAX, port'.
7332 *
7333 * @param u16Port The source port.
7334 * @param cbReg The register size.
7335 * @param bImmAndEffAddrMode Bit 7: Whether the port was specified through an
7336 * immediate operand or the implicit DX register.
7337 * Bits 3-0: Effective address mode.
7338 */
7339IEM_CIMPL_DEF_3(iemCImpl_in, uint16_t, u16Port, uint8_t, cbReg, uint8_t, bImmAndEffAddrMode)
7340{
7341 /*
7342 * GCM intercept.
7343 *
7344 * This must be placed before the IOPL check as the mesa driver intercept
7345 * would otherwise trigger a #GP(0).
7346 */
7347 if (!IEM_IS_IN_GUEST(pVCpu) && GCMIsInterceptingIOPortRead(pVCpu, u16Port, cbReg))
7348 {
7349 VBOXSTRICTRC rcStrict = GCMInterceptedIOPortRead(pVCpu, &pVCpu->cpum.GstCtx, u16Port, cbReg);
7350 if (rcStrict == VINF_GCM_HANDLED_ADVANCE_RIP || rcStrict == VINF_GCM_HANDLED)
7351 {
7352 Log(("iemCImpl_in: u16Port=%#x cbReg=%d was handled by GCMIOPortRead (%d)\n", u16Port, cbReg, VBOXSTRICTRC_VAL(rcStrict)));
7353 if (rcStrict == VINF_GCM_HANDLED_ADVANCE_RIP)
7354 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7355 else
7356 rcStrict = VINF_SUCCESS;
7357 return rcStrict;
7358 }
7359 Assert(rcStrict == VERR_GCM_NOT_HANDLED);
7360 }
7361
7362 /*
7363 * CPL check
7364 */
7365 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pVCpu, u16Port, cbReg);
7366 if (rcStrict != VINF_SUCCESS)
7367 return rcStrict;
7368
7369 if (!IEM_IS_IN_GUEST(pVCpu))
7370 { /* probable */ }
7371
7372 /*
7373 * Check VMX nested-guest IO intercept.
7374 */
7375#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7376 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
7377 {
7378 rcStrict = iemVmxVmexitInstrIo(pVCpu, VMXINSTRID_IO_IN, u16Port, RT_BOOL(bImmAndEffAddrMode & 0x80), cbReg, cbInstr);
7379 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
7380 return rcStrict;
7381 }
7382#endif
7383
7384 /*
7385 * Check SVM nested-guest IO intercept.
7386 */
7387#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
7388 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_IOIO_PROT))
7389 {
7390 uint8_t cAddrSizeBits;
7391 switch (bImmAndEffAddrMode & 0xf)
7392 {
7393 case IEMMODE_16BIT: cAddrSizeBits = 16; break;
7394 case IEMMODE_32BIT: cAddrSizeBits = 32; break;
7395 case IEMMODE_64BIT: cAddrSizeBits = 64; break;
7396 IEM_NOT_REACHED_DEFAULT_CASE_RET();
7397 }
7398 rcStrict = iemSvmHandleIOIntercept(pVCpu, u16Port, SVMIOIOTYPE_IN, cbReg, cAddrSizeBits, 0 /* N/A - iEffSeg */,
7399 false /* fRep */, false /* fStrIo */, cbInstr);
7400 if (rcStrict == VINF_SVM_VMEXIT)
7401 return VINF_SUCCESS;
7402 if (rcStrict != VINF_SVM_INTERCEPT_NOT_ACTIVE)
7403 {
7404 Log(("iemCImpl_in: iemSvmHandleIOIntercept failed (u16Port=%#x, cbReg=%u) rc=%Rrc\n", u16Port, cbReg,
7405 VBOXSTRICTRC_VAL(rcStrict)));
7406 return rcStrict;
7407 }
7408 }
7409#endif
7410#if !defined(VBOX_WITH_NESTED_HWVIRT_VMX) && !defined(VBOX_WITH_NESTED_HWVIRT_SVM)
7411 RT_NOREF(bImmAndEffAddrMode);
7412#endif
7413
7414 /*
7415 * Perform the I/O.
7416 */
7417 PVMCC const pVM = pVCpu->CTX_SUFF(pVM);
7418 uint32_t u32Value = 0;
7419 rcStrict = IOMIOPortRead(pVM, pVCpu, u16Port, &u32Value, cbReg);
7420 if (IOM_SUCCESS(rcStrict))
7421 {
7422 switch (cbReg)
7423 {
7424 case 1: pVCpu->cpum.GstCtx.al = (uint8_t)u32Value; break;
7425 case 2: pVCpu->cpum.GstCtx.ax = (uint16_t)u32Value; break;
7426 case 4: pVCpu->cpum.GstCtx.rax = u32Value; break;
7427 default: AssertFailedReturn(VERR_IEM_IPE_3);
7428 }
7429
7430 pVCpu->iem.s.cPotentialExits++;
7431 if (rcStrict != VINF_SUCCESS)
7432 iemSetPassUpStatus(pVCpu, rcStrict);
7433
7434 /*
7435 * Check for I/O breakpoints before we complete the instruction.
7436 */
7437 uint32_t const fDr7 = pVCpu->cpum.GstCtx.dr[7];
7438 if (RT_UNLIKELY( ( ( (fDr7 & X86_DR7_ENABLED_MASK)
7439 && X86_DR7_ANY_RW_IO(fDr7)
7440 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_DE))
7441 || pVM->dbgf.ro.cEnabledHwIoBreakpoints > 0)
7442 && rcStrict == VINF_SUCCESS))
7443 {
7444 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3 | CPUMCTX_EXTRN_DR6);
7445 pVCpu->cpum.GstCtx.eflags.uBoth |= DBGFBpCheckIo2(pVM, pVCpu, u16Port, cbReg);
7446 }
7447
7448 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7449 }
7450
7451 return rcStrict;
7452}
7453
7454
7455/**
7456 * Implements 'IN eAX, DX'.
7457 *
7458 * @param cbReg The register size.
7459 * @param enmEffAddrMode Effective address mode.
7460 */
7461IEM_CIMPL_DEF_2(iemCImpl_in_eAX_DX, uint8_t, cbReg, IEMMODE, enmEffAddrMode)
7462{
7463 return IEM_CIMPL_CALL_3(iemCImpl_in, pVCpu->cpum.GstCtx.dx, cbReg, 0 /* fImm */ | enmEffAddrMode);
7464}
7465
7466
7467/**
7468 * Implements 'OUT port, eAX'.
7469 *
7470 * @param u16Port The destination port.
7471 * @param cbReg The register size.
7472 * @param bImmAndEffAddrMode Bit 7: Whether the port was specified through an
7473 * immediate operand or the implicit DX register.
7474 * Bits 3-0: Effective address mode.
7475 */
7476IEM_CIMPL_DEF_3(iemCImpl_out, uint16_t, u16Port, uint8_t, cbReg, uint8_t, bImmAndEffAddrMode)
7477{
7478 /*
7479 * CPL check
7480 */
7481 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pVCpu, u16Port, cbReg);
7482 if (rcStrict != VINF_SUCCESS)
7483 return rcStrict;
7484
7485 if (!IEM_IS_IN_GUEST(pVCpu))
7486 { /* probable */ }
7487
7488 /*
7489 * Check VMX nested-guest I/O intercept.
7490 */
7491#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7492 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
7493 {
7494 rcStrict = iemVmxVmexitInstrIo(pVCpu, VMXINSTRID_IO_OUT, u16Port, RT_BOOL(bImmAndEffAddrMode & 0x80), cbReg, cbInstr);
7495 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
7496 return rcStrict;
7497 }
7498#endif
7499
7500 /*
7501 * Check SVM nested-guest I/O intercept.
7502 */
7503#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
7504 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_IOIO_PROT))
7505 {
7506 uint8_t cAddrSizeBits;
7507 switch (bImmAndEffAddrMode & 0xf)
7508 {
7509 case IEMMODE_16BIT: cAddrSizeBits = 16; break;
7510 case IEMMODE_32BIT: cAddrSizeBits = 32; break;
7511 case IEMMODE_64BIT: cAddrSizeBits = 64; break;
7512 IEM_NOT_REACHED_DEFAULT_CASE_RET();
7513 }
7514 rcStrict = iemSvmHandleIOIntercept(pVCpu, u16Port, SVMIOIOTYPE_OUT, cbReg, cAddrSizeBits, 0 /* N/A - iEffSeg */,
7515 false /* fRep */, false /* fStrIo */, cbInstr);
7516 if (rcStrict == VINF_SVM_VMEXIT)
7517 return VINF_SUCCESS;
7518 if (rcStrict != VINF_SVM_INTERCEPT_NOT_ACTIVE)
7519 {
7520 Log(("iemCImpl_out: iemSvmHandleIOIntercept failed (u16Port=%#x, cbReg=%u) rc=%Rrc\n", u16Port, cbReg,
7521 VBOXSTRICTRC_VAL(rcStrict)));
7522 return rcStrict;
7523 }
7524 }
7525#endif
7526#if !defined(VBOX_WITH_NESTED_HWVIRT_VMX) && !defined(VBOX_WITH_NESTED_HWVIRT_SVM)
7527 RT_NOREF(bImmAndEffAddrMode);
7528#endif
7529
7530 /*
7531 * Perform the I/O.
7532 */
7533 PVMCC const pVM = pVCpu->CTX_SUFF(pVM);
7534 uint32_t u32Value;
7535 switch (cbReg)
7536 {
7537 case 1: u32Value = pVCpu->cpum.GstCtx.al; break;
7538 case 2: u32Value = pVCpu->cpum.GstCtx.ax; break;
7539 case 4: u32Value = pVCpu->cpum.GstCtx.eax; break;
7540 default: AssertFailedReturn(VERR_IEM_IPE_4);
7541 }
7542 rcStrict = IOMIOPortWrite(pVM, pVCpu, u16Port, u32Value, cbReg);
7543 if (IOM_SUCCESS(rcStrict))
7544 {
7545 pVCpu->iem.s.cPotentialExits++;
7546 if (rcStrict != VINF_SUCCESS)
7547 iemSetPassUpStatus(pVCpu, rcStrict);
7548
7549 /*
7550 * Check for I/O breakpoints before we complete the instruction.
7551 */
7552 uint32_t const fDr7 = pVCpu->cpum.GstCtx.dr[7];
7553 if (RT_UNLIKELY( ( ( (fDr7 & X86_DR7_ENABLED_MASK)
7554 && X86_DR7_ANY_RW_IO(fDr7)
7555 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_DE))
7556 || pVM->dbgf.ro.cEnabledHwIoBreakpoints > 0)
7557 && rcStrict == VINF_SUCCESS))
7558 {
7559 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3 | CPUMCTX_EXTRN_DR6);
7560 pVCpu->cpum.GstCtx.eflags.uBoth |= DBGFBpCheckIo2(pVM, pVCpu, u16Port, cbReg);
7561 }
7562
7563 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7564 }
7565 return rcStrict;
7566}
7567
7568
7569/**
7570 * Implements 'OUT DX, eAX'.
7571 *
7572 * @param cbReg The register size.
7573 * @param enmEffAddrMode Effective address mode.
7574 */
7575IEM_CIMPL_DEF_2(iemCImpl_out_DX_eAX, uint8_t, cbReg, IEMMODE, enmEffAddrMode)
7576{
7577 return IEM_CIMPL_CALL_3(iemCImpl_out, pVCpu->cpum.GstCtx.dx, cbReg, 0 /* fImm */ | enmEffAddrMode);
7578}
7579
7580
7581/**
7582 * Implements 'CLI'.
7583 */
7584IEM_CIMPL_DEF_0(iemCImpl_cli)
7585{
7586 uint32_t fEfl = IEMMISC_GET_EFL(pVCpu);
7587#ifdef LOG_ENABLED
7588 uint32_t const fEflOld = fEfl;
7589#endif
7590
7591 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4);
7592 if (pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE)
7593 {
7594 uint8_t const uIopl = X86_EFL_GET_IOPL(fEfl);
7595 if (!(fEfl & X86_EFL_VM))
7596 {
7597 if (IEM_GET_CPL(pVCpu) <= uIopl)
7598 fEfl &= ~X86_EFL_IF;
7599 else if ( IEM_GET_CPL(pVCpu) == 3
7600 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PVI) )
7601 fEfl &= ~X86_EFL_VIF;
7602 else
7603 return iemRaiseGeneralProtectionFault0(pVCpu);
7604 }
7605 /* V8086 */
7606 else if (uIopl == 3)
7607 fEfl &= ~X86_EFL_IF;
7608 else if ( uIopl < 3
7609 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_VME) )
7610 fEfl &= ~X86_EFL_VIF;
7611 else
7612 return iemRaiseGeneralProtectionFault0(pVCpu);
7613 }
7614 /* real mode */
7615 else
7616 fEfl &= ~X86_EFL_IF;
7617
7618 /* Commit. */
7619 IEMMISC_SET_EFL(pVCpu, fEfl);
7620 VBOXSTRICTRC const rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7621 Log2(("CLI: %#x -> %#x\n", fEflOld, fEfl));
7622 return rcStrict;
7623}
7624
7625
7626/**
7627 * Implements 'STI'.
7628 */
7629IEM_CIMPL_DEF_0(iemCImpl_sti)
7630{
7631 uint32_t fEfl = IEMMISC_GET_EFL(pVCpu);
7632 uint32_t const fEflOld = fEfl;
7633
7634 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4);
7635 if (pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE)
7636 {
7637 uint8_t const uIopl = X86_EFL_GET_IOPL(fEfl);
7638 if (!(fEfl & X86_EFL_VM))
7639 {
7640 if (IEM_GET_CPL(pVCpu) <= uIopl)
7641 fEfl |= X86_EFL_IF;
7642 else if ( IEM_GET_CPL(pVCpu) == 3
7643 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PVI)
7644 && !(fEfl & X86_EFL_VIP) )
7645 fEfl |= X86_EFL_VIF;
7646 else
7647 return iemRaiseGeneralProtectionFault0(pVCpu);
7648 }
7649 /* V8086 */
7650 else if (uIopl == 3)
7651 fEfl |= X86_EFL_IF;
7652 else if ( uIopl < 3
7653 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_VME)
7654 && !(fEfl & X86_EFL_VIP) )
7655 fEfl |= X86_EFL_VIF;
7656 else
7657 return iemRaiseGeneralProtectionFault0(pVCpu);
7658 }
7659 /* real mode */
7660 else
7661 fEfl |= X86_EFL_IF;
7662
7663 /*
7664 * Commit.
7665 *
7666 * Note! Setting the shadow interrupt flag must be done after RIP updating.
7667 */
7668 IEMMISC_SET_EFL(pVCpu, fEfl);
7669 VBOXSTRICTRC const rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7670 if (!(fEflOld & X86_EFL_IF) && (fEfl & X86_EFL_IF))
7671 {
7672 /** @todo only set it the shadow flag if it was clear before? */
7673 CPUMSetInInterruptShadowSti(&pVCpu->cpum.GstCtx);
7674 }
7675 pVCpu->iem.s.fTbCurInstrIsSti = true;
7676 Log2(("STI: %#x -> %#x\n", fEflOld, fEfl));
7677 return rcStrict;
7678}
7679
7680
7681/**
7682 * Implements 'HLT'.
7683 */
7684IEM_CIMPL_DEF_0(iemCImpl_hlt)
7685{
7686 if (IEM_GET_CPL(pVCpu) != 0)
7687 return iemRaiseGeneralProtectionFault0(pVCpu);
7688
7689 if (!IEM_IS_IN_GUEST(pVCpu))
7690 { /* probable */ }
7691 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7692 && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_HLT_EXIT))
7693 {
7694 Log2(("hlt: Guest intercept -> VM-exit\n"));
7695 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_HLT, cbInstr);
7696 }
7697 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_HLT))
7698 {
7699 Log2(("hlt: Guest intercept -> #VMEXIT\n"));
7700 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7701 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_HLT, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7702 }
7703
7704 /** @todo finish: This ASSUMES that iemRegAddToRipAndFinishingClearingRF won't
7705 * be returning any status codes relating to non-guest events being raised, as
7706 * we'll mess up the guest HALT otherwise. */
7707 VBOXSTRICTRC rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7708 if (rcStrict == VINF_SUCCESS)
7709 rcStrict = VINF_EM_HALT;
7710 return rcStrict;
7711}
7712
7713
7714/**
7715 * Implements 'MONITOR'.
7716 */
7717IEM_CIMPL_DEF_1(iemCImpl_monitor, uint8_t, iEffSeg)
7718{
7719 /*
7720 * Permission checks.
7721 */
7722 if (IEM_GET_CPL(pVCpu) != 0)
7723 {
7724 Log2(("monitor: CPL != 0\n"));
7725 return iemRaiseUndefinedOpcode(pVCpu); /** @todo MSR[0xC0010015].MonMwaitUserEn if we care. */
7726 }
7727 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fMonitorMWait)
7728 {
7729 Log2(("monitor: Not in CPUID\n"));
7730 return iemRaiseUndefinedOpcode(pVCpu);
7731 }
7732
7733 /*
7734 * Check VMX guest-intercept.
7735 * This should be considered a fault-like VM-exit.
7736 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
7737 */
7738 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7739 || !IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_MONITOR_EXIT))
7740 { /* probable */ }
7741 else
7742 {
7743 Log2(("monitor: Guest intercept -> #VMEXIT\n"));
7744 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_MONITOR, cbInstr);
7745 }
7746
7747 /*
7748 * Gather the operands and validate them.
7749 */
7750 RTGCPTR GCPtrMem = IEM_IS_64BIT_CODE(pVCpu) ? pVCpu->cpum.GstCtx.rax : pVCpu->cpum.GstCtx.eax;
7751 uint32_t uEcx = pVCpu->cpum.GstCtx.ecx;
7752 uint32_t uEdx = pVCpu->cpum.GstCtx.edx;
7753/** @todo Test whether EAX or ECX is processed first, i.e. do we get \#PF or
7754 * \#GP first. */
7755 if (uEcx != 0)
7756 {
7757 Log2(("monitor rax=%RX64, ecx=%RX32, edx=%RX32; ECX != 0 -> #GP(0)\n", GCPtrMem, uEcx, uEdx)); NOREF(uEdx);
7758 return iemRaiseGeneralProtectionFault0(pVCpu);
7759 }
7760
7761 VBOXSTRICTRC rcStrict = iemMemApplySegment(pVCpu, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, iEffSeg, 1, &GCPtrMem);
7762 if (rcStrict != VINF_SUCCESS)
7763 return rcStrict;
7764
7765 RTGCPHYS GCPhysMem;
7766 /** @todo access size */
7767 rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, GCPtrMem, 1, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, &GCPhysMem);
7768 if (rcStrict != VINF_SUCCESS)
7769 return rcStrict;
7770
7771 if (!IEM_IS_IN_GUEST(pVCpu))
7772 { /* probable */ }
7773#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7774 else if ( IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7775 && IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_VIRT_APIC_ACCESS))
7776 {
7777 /*
7778 * MONITOR does not access the memory, just monitors the address. However,
7779 * if the address falls in the APIC-access page, the address monitored must
7780 * instead be the corresponding address in the virtual-APIC page.
7781 *
7782 * See Intel spec. 29.4.4 "Instruction-Specific Considerations".
7783 */
7784 rcStrict = iemVmxVirtApicAccessUnused(pVCpu, &GCPhysMem, 1, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA);
7785 if ( rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE
7786 && rcStrict != VINF_VMX_MODIFIES_BEHAVIOR)
7787 return rcStrict;
7788 }
7789#endif
7790 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_MONITOR))
7791 {
7792 Log2(("monitor: Guest intercept -> #VMEXIT\n"));
7793 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7794 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_MONITOR, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7795 }
7796
7797 /*
7798 * Call EM to prepare the monitor/wait.
7799 */
7800 rcStrict = EMMonitorWaitPrepare(pVCpu, pVCpu->cpum.GstCtx.rax, pVCpu->cpum.GstCtx.rcx, pVCpu->cpum.GstCtx.rdx, GCPhysMem);
7801 Assert(rcStrict == VINF_SUCCESS);
7802 if (rcStrict == VINF_SUCCESS)
7803 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7804 return rcStrict;
7805}
7806
7807
7808/**
7809 * Implements 'MWAIT'.
7810 */
7811IEM_CIMPL_DEF_0(iemCImpl_mwait)
7812{
7813 /*
7814 * Permission checks.
7815 */
7816 if (IEM_GET_CPL(pVCpu) != 0)
7817 {
7818 Log2(("mwait: CPL != 0\n"));
7819 /** @todo MSR[0xC0010015].MonMwaitUserEn if we care. (Remember to check
7820 * EFLAGS.VM then.) */
7821 return iemRaiseUndefinedOpcode(pVCpu);
7822 }
7823 if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fMonitorMWait)
7824 {
7825 Log2(("mwait: Not in CPUID\n"));
7826 return iemRaiseUndefinedOpcode(pVCpu);
7827 }
7828
7829 /* Check VMX nested-guest intercept. */
7830 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7831 || !IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_MWAIT_EXIT))
7832 { /* probable */ }
7833 else
7834 IEM_VMX_VMEXIT_MWAIT_RET(pVCpu, EMMonitorIsArmed(pVCpu), cbInstr);
7835
7836 /*
7837 * Gather the operands and validate them.
7838 */
7839 uint32_t const uEax = pVCpu->cpum.GstCtx.eax;
7840 uint32_t const uEcx = pVCpu->cpum.GstCtx.ecx;
7841 if (uEcx != 0)
7842 {
7843 /* Only supported extension is break on IRQ when IF=0. */
7844 if (uEcx > 1)
7845 {
7846 Log2(("mwait eax=%RX32, ecx=%RX32; ECX > 1 -> #GP(0)\n", uEax, uEcx));
7847 return iemRaiseGeneralProtectionFault0(pVCpu);
7848 }
7849 uint32_t fMWaitFeatures = 0;
7850 uint32_t uIgnore = 0;
7851 CPUMGetGuestCpuId(pVCpu, 5, 0, -1 /*f64BitMode*/, &uIgnore, &uIgnore, &fMWaitFeatures, &uIgnore);
7852 if ( (fMWaitFeatures & (X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
7853 != (X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
7854 {
7855 Log2(("mwait eax=%RX32, ecx=%RX32; break-on-IRQ-IF=0 extension not enabled -> #GP(0)\n", uEax, uEcx));
7856 return iemRaiseGeneralProtectionFault0(pVCpu);
7857 }
7858
7859#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7860 /*
7861 * If the interrupt-window exiting control is set or a virtual-interrupt is pending
7862 * for delivery; and interrupts are disabled the processor does not enter its
7863 * mwait state but rather passes control to the next instruction.
7864 *
7865 * See Intel spec. 25.3 "Changes to Instruction Behavior In VMX Non-root Operation".
7866 */
7867 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
7868 || pVCpu->cpum.GstCtx.eflags.Bits.u1IF)
7869 { /* probable */ }
7870 else if ( IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_INT_WINDOW_EXIT)
7871 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST))
7872 /** @todo finish: check up this out after we move int window stuff out of the
7873 * run loop and into the instruction finishing logic here. */
7874 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7875#endif
7876 }
7877
7878 /*
7879 * Check SVM nested-guest mwait intercepts.
7880 */
7881 if (!IEM_IS_IN_GUEST(pVCpu))
7882 { /* probable */ }
7883 else if ( IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_MWAIT_ARMED)
7884 && EMMonitorIsArmed(pVCpu))
7885 {
7886 Log2(("mwait: Guest intercept (monitor hardware armed) -> #VMEXIT\n"));
7887 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7888 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_MWAIT_ARMED, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7889 }
7890 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_MWAIT))
7891 {
7892 Log2(("mwait: Guest intercept -> #VMEXIT\n"));
7893 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
7894 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_MWAIT, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
7895 }
7896
7897 /*
7898 * Call EM to prepare the monitor/wait.
7899 *
7900 * This will return VINF_EM_HALT. If there the trap flag is set, we may
7901 * override it when executing iemRegAddToRipAndFinishingClearingRF ASSUMING
7902 * that will only return guest related events.
7903 */
7904 VBOXSTRICTRC rcStrict = EMMonitorWaitPerform(pVCpu, uEax, uEcx);
7905
7906 /** @todo finish: This needs more thinking as we should suppress internal
7907 * debugger events here, or we'll bugger up the guest state even more than we
7908 * alread do around VINF_EM_HALT. */
7909 VBOXSTRICTRC rcStrict2 = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7910 if (rcStrict2 != VINF_SUCCESS)
7911 {
7912 Log2(("mwait: %Rrc (perform) -> %Rrc (finish)!\n", VBOXSTRICTRC_VAL(rcStrict), VBOXSTRICTRC_VAL(rcStrict2) ));
7913 rcStrict = rcStrict2;
7914 }
7915
7916 return rcStrict;
7917}
7918
7919
7920/**
7921 * Implements 'SWAPGS'.
7922 */
7923IEM_CIMPL_DEF_0(iemCImpl_swapgs)
7924{
7925 Assert(IEM_IS_64BIT_CODE(pVCpu)); /* Caller checks this. */
7926
7927 /*
7928 * Permission checks.
7929 */
7930 if (IEM_GET_CPL(pVCpu) != 0)
7931 {
7932 Log2(("swapgs: CPL != 0\n"));
7933 return iemRaiseUndefinedOpcode(pVCpu);
7934 }
7935
7936 /*
7937 * Do the job.
7938 */
7939 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_GS);
7940 uint64_t uOtherGsBase = pVCpu->cpum.GstCtx.msrKERNELGSBASE;
7941 pVCpu->cpum.GstCtx.msrKERNELGSBASE = pVCpu->cpum.GstCtx.gs.u64Base;
7942 pVCpu->cpum.GstCtx.gs.u64Base = uOtherGsBase;
7943
7944 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
7945}
7946
7947
7948#ifndef VBOX_WITHOUT_CPUID_HOST_CALL
7949/**
7950 * Handles a CPUID call.
7951 */
7952static VBOXSTRICTRC iemCpuIdVBoxCall(PVMCPUCC pVCpu, uint32_t iFunction,
7953 uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)
7954{
7955 switch (iFunction)
7956 {
7957 case VBOX_CPUID_FN_ID:
7958 LogFlow(("iemCpuIdVBoxCall: VBOX_CPUID_FN_ID\n"));
7959 *pEax = VBOX_CPUID_RESP_ID_EAX;
7960 *pEbx = VBOX_CPUID_RESP_ID_EBX;
7961 *pEcx = VBOX_CPUID_RESP_ID_ECX;
7962 *pEdx = VBOX_CPUID_RESP_ID_EDX;
7963 break;
7964
7965 case VBOX_CPUID_FN_LOG:
7966 {
7967 CPUM_IMPORT_EXTRN_RET(pVCpu, CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX | CPUMCTX_EXTRN_RSI
7968 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
7969
7970 /* Validate input. */
7971 uint32_t cchToLog = *pEdx;
7972 if (cchToLog <= _2M)
7973 {
7974 uint32_t const uLogPicker = *pEbx;
7975 if (uLogPicker <= 1)
7976 {
7977 /* Resolve the logger. */
7978 PRTLOGGER const pLogger = !uLogPicker
7979 ? RTLogDefaultInstanceEx(UINT32_MAX) : RTLogRelGetDefaultInstanceEx(UINT32_MAX);
7980 if (pLogger)
7981 {
7982 /* Copy over the data: */
7983 RTGCPTR GCPtrSrc = pVCpu->cpum.GstCtx.rsi;
7984 while (cchToLog > 0)
7985 {
7986 uint32_t cbToMap = GUEST_PAGE_SIZE - (GCPtrSrc & GUEST_PAGE_OFFSET_MASK);
7987 if (cbToMap > cchToLog)
7988 cbToMap = cchToLog;
7989 /** @todo Extend iemMemMap to allowing page size accessing and avoid 7
7990 * unnecessary calls & iterations per pages. */
7991 if (cbToMap > 512)
7992 cbToMap = 512;
7993 uint8_t bUnmapInfo;
7994 void *pvSrc = NULL;
7995 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvSrc, &bUnmapInfo, cbToMap,
7996 UINT8_MAX, GCPtrSrc, IEM_ACCESS_DATA_R, 0);
7997 if (rcStrict == VINF_SUCCESS)
7998 {
7999 RTLogBulkNestedWrite(pLogger, (const char *)pvSrc, cbToMap, "Gst:");
8000 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
8001 AssertRCSuccessReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
8002 }
8003 else
8004 {
8005 Log(("iemCpuIdVBoxCall: %Rrc at %RGp LB %#x\n", VBOXSTRICTRC_VAL(rcStrict), GCPtrSrc, cbToMap));
8006 return rcStrict;
8007 }
8008
8009 /* Advance. */
8010 pVCpu->cpum.GstCtx.rsi = GCPtrSrc += cbToMap;
8011 *pEdx = cchToLog -= cbToMap;
8012 }
8013 *pEax = VINF_SUCCESS;
8014 }
8015 else
8016 *pEax = (uint32_t)VERR_NOT_FOUND;
8017 }
8018 else
8019 *pEax = (uint32_t)VERR_NOT_FOUND;
8020 }
8021 else
8022 *pEax = (uint32_t)VERR_TOO_MUCH_DATA;
8023 *pEdx = VBOX_CPUID_RESP_GEN_EDX;
8024 *pEcx = VBOX_CPUID_RESP_GEN_ECX;
8025 *pEbx = VBOX_CPUID_RESP_GEN_EBX;
8026 break;
8027 }
8028
8029 default:
8030 LogFlow(("iemCpuIdVBoxCall: Invalid function %#x (%#x, %#x)\n", iFunction, *pEbx, *pEdx));
8031 *pEax = (uint32_t)VERR_INVALID_FUNCTION;
8032 *pEbx = (uint32_t)VERR_INVALID_FUNCTION;
8033 *pEcx = (uint32_t)VERR_INVALID_FUNCTION;
8034 *pEdx = (uint32_t)VERR_INVALID_FUNCTION;
8035 break;
8036 }
8037 return VINF_SUCCESS;
8038}
8039#endif /* VBOX_WITHOUT_CPUID_HOST_CALL */
8040
8041/**
8042 * Implements 'CPUID'.
8043 */
8044IEM_CIMPL_DEF_0(iemCImpl_cpuid)
8045{
8046 if (!IEM_IS_IN_GUEST(pVCpu))
8047 { /* probable */ }
8048 else if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8049 {
8050 Log2(("cpuid: Guest intercept -> VM-exit\n"));
8051 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_CPUID, cbInstr);
8052 }
8053 else if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_CPUID))
8054 {
8055 Log2(("cpuid: Guest intercept -> #VMEXIT\n"));
8056 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
8057 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_CPUID, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
8058 }
8059
8060
8061 uint32_t const uEax = pVCpu->cpum.GstCtx.eax;
8062 uint32_t const uEcx = pVCpu->cpum.GstCtx.ecx;
8063
8064#ifndef VBOX_WITHOUT_CPUID_HOST_CALL
8065 /*
8066 * CPUID host call backdoor.
8067 */
8068 if ( uEax == VBOX_CPUID_REQ_EAX_FIXED
8069 && (uEcx & VBOX_CPUID_REQ_ECX_FIXED_MASK) == VBOX_CPUID_REQ_ECX_FIXED
8070 && pVCpu->CTX_SUFF(pVM)->iem.s.fCpuIdHostCall)
8071 {
8072 VBOXSTRICTRC rcStrict = iemCpuIdVBoxCall(pVCpu, uEcx & VBOX_CPUID_REQ_ECX_FN_MASK,
8073 &pVCpu->cpum.GstCtx.eax, &pVCpu->cpum.GstCtx.ebx,
8074 &pVCpu->cpum.GstCtx.ecx, &pVCpu->cpum.GstCtx.edx);
8075 if (rcStrict != VINF_SUCCESS)
8076 return rcStrict;
8077 }
8078 /*
8079 * Regular CPUID.
8080 */
8081 else
8082#endif
8083 CPUMGetGuestCpuId(pVCpu, uEax, uEcx, pVCpu->cpum.GstCtx.cs.Attr.n.u1Long,
8084 &pVCpu->cpum.GstCtx.eax, &pVCpu->cpum.GstCtx.ebx, &pVCpu->cpum.GstCtx.ecx, &pVCpu->cpum.GstCtx.edx);
8085
8086 pVCpu->cpum.GstCtx.rax &= UINT32_C(0xffffffff);
8087 pVCpu->cpum.GstCtx.rbx &= UINT32_C(0xffffffff);
8088 pVCpu->cpum.GstCtx.rcx &= UINT32_C(0xffffffff);
8089 pVCpu->cpum.GstCtx.rdx &= UINT32_C(0xffffffff);
8090 pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
8091
8092 pVCpu->iem.s.cPotentialExits++;
8093 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8094}
8095
8096
8097/**
8098 * Implements 'AAD'.
8099 *
8100 * @param bImm The immediate operand.
8101 */
8102IEM_CIMPL_DEF_1(iemCImpl_aad, uint8_t, bImm)
8103{
8104 uint16_t const ax = pVCpu->cpum.GstCtx.ax;
8105 uint8_t const al = (uint8_t)ax + (uint8_t)(ax >> 8) * bImm;
8106 pVCpu->cpum.GstCtx.ax = al;
8107 iemHlpUpdateArithEFlagsU8(pVCpu, al,
8108 X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF,
8109 X86_EFL_OF | X86_EFL_AF | X86_EFL_CF);
8110
8111 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8112}
8113
8114
8115/**
8116 * Implements 'AAM'.
8117 *
8118 * @param bImm The immediate operand. Cannot be 0.
8119 */
8120IEM_CIMPL_DEF_1(iemCImpl_aam, uint8_t, bImm)
8121{
8122 Assert(bImm != 0); /* #DE on 0 is handled in the decoder. */
8123
8124 uint16_t const ax = pVCpu->cpum.GstCtx.ax;
8125 uint8_t const al = (uint8_t)ax % bImm;
8126 uint8_t const ah = (uint8_t)ax / bImm;
8127 pVCpu->cpum.GstCtx.ax = (ah << 8) + al;
8128 iemHlpUpdateArithEFlagsU8(pVCpu, al,
8129 X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF,
8130 X86_EFL_OF | X86_EFL_AF | X86_EFL_CF);
8131
8132 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8133}
8134
8135
8136/**
8137 * Implements 'DAA'.
8138 */
8139IEM_CIMPL_DEF_0(iemCImpl_daa)
8140{
8141 uint8_t const al = pVCpu->cpum.GstCtx.al;
8142 bool const fCarry = pVCpu->cpum.GstCtx.eflags.Bits.u1CF;
8143
8144 if ( pVCpu->cpum.GstCtx.eflags.Bits.u1AF
8145 || (al & 0xf) >= 10)
8146 {
8147 pVCpu->cpum.GstCtx.al = al + 6;
8148 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 1;
8149 }
8150 else
8151 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 0;
8152
8153 if (al >= 0x9a || fCarry)
8154 {
8155 pVCpu->cpum.GstCtx.al += 0x60;
8156 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8157 }
8158 else
8159 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 0;
8160
8161 iemHlpUpdateArithEFlagsU8(pVCpu, pVCpu->cpum.GstCtx.al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
8162 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8163}
8164
8165
8166/**
8167 * Implements 'DAS'.
8168 */
8169IEM_CIMPL_DEF_0(iemCImpl_das)
8170{
8171 uint8_t const uInputAL = pVCpu->cpum.GstCtx.al;
8172 bool const fCarry = pVCpu->cpum.GstCtx.eflags.Bits.u1CF;
8173
8174 if ( pVCpu->cpum.GstCtx.eflags.Bits.u1AF
8175 || (uInputAL & 0xf) >= 10)
8176 {
8177 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 1;
8178 if (uInputAL < 6)
8179 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8180 pVCpu->cpum.GstCtx.al = uInputAL - 6;
8181 }
8182 else
8183 {
8184 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 0;
8185 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 0;
8186 }
8187
8188 if (uInputAL >= 0x9a || fCarry)
8189 {
8190 pVCpu->cpum.GstCtx.al -= 0x60;
8191 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8192 }
8193
8194 iemHlpUpdateArithEFlagsU8(pVCpu, pVCpu->cpum.GstCtx.al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
8195 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8196}
8197
8198
8199/**
8200 * Implements 'AAA'.
8201 */
8202IEM_CIMPL_DEF_0(iemCImpl_aaa)
8203{
8204 if (IEM_IS_GUEST_CPU_AMD(pVCpu))
8205 {
8206 if ( pVCpu->cpum.GstCtx.eflags.Bits.u1AF
8207 || (pVCpu->cpum.GstCtx.ax & 0xf) >= 10)
8208 {
8209 pVCpu->cpum.GstCtx.eflags.uBoth = iemAImpl_add_u16(pVCpu->cpum.GstCtx.eflags.uBoth, &pVCpu->cpum.GstCtx.ax, 0x106);
8210 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 1;
8211 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8212 }
8213 else
8214 {
8215 iemHlpUpdateArithEFlagsU16(pVCpu, pVCpu->cpum.GstCtx.ax, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
8216 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 0;
8217 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 0;
8218 }
8219 pVCpu->cpum.GstCtx.ax &= UINT16_C(0xff0f);
8220 }
8221 else
8222 {
8223 if ( pVCpu->cpum.GstCtx.eflags.Bits.u1AF
8224 || (pVCpu->cpum.GstCtx.ax & 0xf) >= 10)
8225 {
8226 pVCpu->cpum.GstCtx.ax += UINT16_C(0x106);
8227 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 1;
8228 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8229 }
8230 else
8231 {
8232 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 0;
8233 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 0;
8234 }
8235 pVCpu->cpum.GstCtx.ax &= UINT16_C(0xff0f);
8236 iemHlpUpdateArithEFlagsU8(pVCpu, pVCpu->cpum.GstCtx.al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
8237 }
8238
8239 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8240}
8241
8242
8243/**
8244 * Implements 'AAS'.
8245 */
8246IEM_CIMPL_DEF_0(iemCImpl_aas)
8247{
8248 if (IEM_IS_GUEST_CPU_AMD(pVCpu))
8249 {
8250 if ( pVCpu->cpum.GstCtx.eflags.Bits.u1AF
8251 || (pVCpu->cpum.GstCtx.ax & 0xf) >= 10)
8252 {
8253 pVCpu->cpum.GstCtx.eflags.uBoth = iemAImpl_sub_u16(pVCpu->cpum.GstCtx.eflags.uBoth, &pVCpu->cpum.GstCtx.ax, 0x106);
8254 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 1;
8255 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8256 }
8257 else
8258 {
8259 iemHlpUpdateArithEFlagsU16(pVCpu, pVCpu->cpum.GstCtx.ax, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
8260 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 0;
8261 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 0;
8262 }
8263 pVCpu->cpum.GstCtx.ax &= UINT16_C(0xff0f);
8264 }
8265 else
8266 {
8267 if ( pVCpu->cpum.GstCtx.eflags.Bits.u1AF
8268 || (pVCpu->cpum.GstCtx.ax & 0xf) >= 10)
8269 {
8270 pVCpu->cpum.GstCtx.ax -= UINT16_C(0x106);
8271 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 1;
8272 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 1;
8273 }
8274 else
8275 {
8276 pVCpu->cpum.GstCtx.eflags.Bits.u1AF = 0;
8277 pVCpu->cpum.GstCtx.eflags.Bits.u1CF = 0;
8278 }
8279 pVCpu->cpum.GstCtx.ax &= UINT16_C(0xff0f);
8280 iemHlpUpdateArithEFlagsU8(pVCpu, pVCpu->cpum.GstCtx.al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
8281 }
8282
8283 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8284}
8285
8286
8287/**
8288 * Implements the 16-bit version of 'BOUND'.
8289 *
8290 * @note We have separate 16-bit and 32-bit variants of this function due to
8291 * the decoder using unsigned parameters, whereas we want signed one to
8292 * do the job. This is significant for a recompiler.
8293 */
8294IEM_CIMPL_DEF_3(iemCImpl_bound_16, int16_t, idxArray, int16_t, idxLowerBound, int16_t, idxUpperBound)
8295{
8296 /*
8297 * Check if the index is inside the bounds, otherwise raise #BR.
8298 */
8299 if ( idxArray >= idxLowerBound
8300 && idxArray <= idxUpperBound)
8301 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8302 return iemRaiseBoundRangeExceeded(pVCpu);
8303}
8304
8305
8306/**
8307 * Implements the 32-bit version of 'BOUND'.
8308 */
8309IEM_CIMPL_DEF_3(iemCImpl_bound_32, int32_t, idxArray, int32_t, idxLowerBound, int32_t, idxUpperBound)
8310{
8311 /*
8312 * Check if the index is inside the bounds, otherwise raise #BR.
8313 */
8314 if ( idxArray >= idxLowerBound
8315 && idxArray <= idxUpperBound)
8316 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8317 return iemRaiseBoundRangeExceeded(pVCpu);
8318}
8319
8320
8321
8322/*
8323 * Instantiate the various string operation combinations.
8324 */
8325#define OP_SIZE 8
8326#define ADDR_SIZE 16
8327#include "IEMAllCImplStrInstr.cpp.h"
8328#define OP_SIZE 8
8329#define ADDR_SIZE 32
8330#include "IEMAllCImplStrInstr.cpp.h"
8331#define OP_SIZE 8
8332#define ADDR_SIZE 64
8333#include "IEMAllCImplStrInstr.cpp.h"
8334
8335#define OP_SIZE 16
8336#define ADDR_SIZE 16
8337#include "IEMAllCImplStrInstr.cpp.h"
8338#define OP_SIZE 16
8339#define ADDR_SIZE 32
8340#include "IEMAllCImplStrInstr.cpp.h"
8341#define OP_SIZE 16
8342#define ADDR_SIZE 64
8343#include "IEMAllCImplStrInstr.cpp.h"
8344
8345#define OP_SIZE 32
8346#define ADDR_SIZE 16
8347#include "IEMAllCImplStrInstr.cpp.h"
8348#define OP_SIZE 32
8349#define ADDR_SIZE 32
8350#include "IEMAllCImplStrInstr.cpp.h"
8351#define OP_SIZE 32
8352#define ADDR_SIZE 64
8353#include "IEMAllCImplStrInstr.cpp.h"
8354
8355#define OP_SIZE 64
8356#define ADDR_SIZE 32
8357#include "IEMAllCImplStrInstr.cpp.h"
8358#define OP_SIZE 64
8359#define ADDR_SIZE 64
8360#include "IEMAllCImplStrInstr.cpp.h"
8361
8362
8363/**
8364 * Implements 'XGETBV'.
8365 */
8366IEM_CIMPL_DEF_0(iemCImpl_xgetbv)
8367{
8368 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
8369 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSXSAVE)
8370 {
8371 uint32_t uEcx = pVCpu->cpum.GstCtx.ecx;
8372 switch (uEcx)
8373 {
8374 case 0:
8375 break;
8376
8377 case 1: /** @todo Implement XCR1 support. */
8378 default:
8379 Log(("xgetbv ecx=%RX32 -> #GP(0)\n", uEcx));
8380 return iemRaiseGeneralProtectionFault0(pVCpu);
8381
8382 }
8383 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_XCRx);
8384 pVCpu->cpum.GstCtx.rax = RT_LO_U32(pVCpu->cpum.GstCtx.aXcr[uEcx]);
8385 pVCpu->cpum.GstCtx.rdx = RT_HI_U32(pVCpu->cpum.GstCtx.aXcr[uEcx]);
8386
8387 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8388 }
8389 Log(("xgetbv CR4.OSXSAVE=0 -> UD\n"));
8390 return iemRaiseUndefinedOpcode(pVCpu);
8391}
8392
8393
8394/**
8395 * Implements 'XSETBV'.
8396 */
8397IEM_CIMPL_DEF_0(iemCImpl_xsetbv)
8398{
8399 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSXSAVE)
8400 {
8401 /** @todo explain why this happens before the CPL check. */
8402 if (!IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_XSETBV))
8403 { /* probable */ }
8404 else
8405 {
8406 Log2(("xsetbv: Guest intercept -> #VMEXIT\n"));
8407 IEM_SVM_UPDATE_NRIP(pVCpu, cbInstr);
8408 IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_XSETBV, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
8409 }
8410
8411 if (IEM_GET_CPL(pVCpu) == 0)
8412 {
8413 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_XCRx);
8414
8415 if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
8416 { /* probable */ }
8417 else
8418 IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_XSETBV, cbInstr);
8419
8420 uint32_t uEcx = pVCpu->cpum.GstCtx.ecx;
8421 uint64_t uNewValue = RT_MAKE_U64(pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.edx);
8422 switch (uEcx)
8423 {
8424 case 0:
8425 {
8426 int rc = CPUMSetGuestXcr0(pVCpu, uNewValue);
8427 if (rc == VINF_SUCCESS)
8428 break;
8429 Assert(rc == VERR_CPUM_RAISE_GP_0);
8430 Log(("xsetbv ecx=%RX32 (newvalue=%RX64) -> #GP(0)\n", uEcx, uNewValue));
8431 return iemRaiseGeneralProtectionFault0(pVCpu);
8432 }
8433
8434 case 1: /** @todo Implement XCR1 support. */
8435 default:
8436 Log(("xsetbv ecx=%RX32 (newvalue=%RX64) -> #GP(0)\n", uEcx, uNewValue));
8437 return iemRaiseGeneralProtectionFault0(pVCpu);
8438
8439 }
8440
8441 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8442 }
8443
8444 Log(("xsetbv cpl=%u -> GP(0)\n", IEM_GET_CPL(pVCpu)));
8445 return iemRaiseGeneralProtectionFault0(pVCpu);
8446 }
8447 Log(("xsetbv CR4.OSXSAVE=0 -> UD\n"));
8448 return iemRaiseUndefinedOpcode(pVCpu);
8449}
8450
8451#ifndef RT_ARCH_ARM64
8452# ifdef IN_RING3
8453
8454/** Argument package for iemCImpl_cmpxchg16b_fallback_rendezvous_callback. */
8455struct IEMCIMPLCX16ARGS
8456{
8457 PRTUINT128U pu128Dst;
8458 PRTUINT128U pu128RaxRdx;
8459 PRTUINT128U pu128RbxRcx;
8460 uint32_t *pEFlags;
8461# ifdef VBOX_STRICT
8462 uint32_t cCalls;
8463# endif
8464};
8465
8466/**
8467 * @callback_method_impl{FNVMMEMTRENDEZVOUS,
8468 * Worker for iemCImpl_cmpxchg16b_fallback_rendezvous}
8469 */
8470static DECLCALLBACK(VBOXSTRICTRC) iemCImpl_cmpxchg16b_fallback_rendezvous_callback(PVM pVM, PVMCPUCC pVCpu, void *pvUser)
8471{
8472 RT_NOREF(pVM, pVCpu);
8473 struct IEMCIMPLCX16ARGS *pArgs = (struct IEMCIMPLCX16ARGS *)pvUser;
8474# ifdef VBOX_STRICT
8475 Assert(pArgs->cCalls == 0);
8476 pArgs->cCalls++;
8477# endif
8478
8479 iemAImpl_cmpxchg16b_fallback(pArgs->pu128Dst, pArgs->pu128RaxRdx, pArgs->pu128RbxRcx, pArgs->pEFlags);
8480 return VINF_SUCCESS;
8481}
8482
8483# endif /* IN_RING3 */
8484
8485/**
8486 * Implements 'CMPXCHG16B' fallback using rendezvous.
8487 */
8488IEM_CIMPL_DEF_5(iemCImpl_cmpxchg16b_fallback_rendezvous, PRTUINT128U, pu128Dst, PRTUINT128U, pu128RaxRdx,
8489 PRTUINT128U, pu128RbxRcx, uint32_t *, pEFlags, uint8_t, bUnmapInfo)
8490{
8491# ifdef IN_RING3
8492 struct IEMCIMPLCX16ARGS Args;
8493 Args.pu128Dst = pu128Dst;
8494 Args.pu128RaxRdx = pu128RaxRdx;
8495 Args.pu128RbxRcx = pu128RbxRcx;
8496 Args.pEFlags = pEFlags;
8497# ifdef VBOX_STRICT
8498 Args.cCalls = 0;
8499# endif
8500 VBOXSTRICTRC rcStrict = VMMR3EmtRendezvous(pVCpu->CTX_SUFF(pVM), VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE,
8501 iemCImpl_cmpxchg16b_fallback_rendezvous_callback, &Args);
8502 Assert(Args.cCalls == 1);
8503 if (rcStrict == VINF_SUCCESS)
8504 {
8505 /* Duplicated tail code. */
8506 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
8507 if (rcStrict == VINF_SUCCESS)
8508 {
8509 pVCpu->cpum.GstCtx.eflags.u = *pEFlags; /* IEM_MC_COMMIT_EFLAGS */
8510 if (!(*pEFlags & X86_EFL_ZF))
8511 {
8512 pVCpu->cpum.GstCtx.rax = pu128RaxRdx->s.Lo;
8513 pVCpu->cpum.GstCtx.rdx = pu128RaxRdx->s.Hi;
8514 }
8515 rcStrict = iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8516 }
8517 }
8518 return rcStrict;
8519# else
8520 RT_NOREF(pVCpu, cbInstr, pu128Dst, pu128RaxRdx, pu128RbxRcx, pEFlags, bUnmapInfo);
8521 return VERR_IEM_ASPECT_NOT_IMPLEMENTED; /* This should get us to ring-3 for now. Should perhaps be replaced later. */
8522# endif
8523}
8524
8525#endif /* RT_ARCH_ARM64 */
8526
8527/**
8528 * Implements 'CLFLUSH' and 'CLFLUSHOPT'.
8529 *
8530 * This is implemented in C because it triggers a load like behaviour without
8531 * actually reading anything. Since that's not so common, it's implemented
8532 * here.
8533 *
8534 * @param iEffSeg The effective segment.
8535 * @param GCPtrEff The address of the image.
8536 */
8537IEM_CIMPL_DEF_2(iemCImpl_clflush_clflushopt, uint8_t, iEffSeg, RTGCPTR, GCPtrEff)
8538{
8539 /*
8540 * Pretend to do a load w/o reading (see also iemCImpl_monitor and iemMemMap).
8541 */
8542 VBOXSTRICTRC rcStrict = iemMemApplySegment(pVCpu, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, iEffSeg, 1, &GCPtrEff);
8543 if (rcStrict == VINF_SUCCESS)
8544 {
8545 RTGCPHYS GCPhysMem;
8546 /** @todo access size. */
8547 rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, GCPtrEff, 1, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, &GCPhysMem);
8548 if (rcStrict == VINF_SUCCESS)
8549 {
8550#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8551 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
8552 || !IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_VIRT_APIC_ACCESS))
8553 { /* probable */ }
8554 else
8555 {
8556 /*
8557 * CLFLUSH/CLFLUSHOPT does not access the memory, but flushes the cache-line
8558 * that contains the address. However, if the address falls in the APIC-access
8559 * page, the address flushed must instead be the corresponding address in the
8560 * virtual-APIC page.
8561 *
8562 * See Intel spec. 29.4.4 "Instruction-Specific Considerations".
8563 */
8564 rcStrict = iemVmxVirtApicAccessUnused(pVCpu, &GCPhysMem, 1, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA);
8565 if ( rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE
8566 && rcStrict != VINF_VMX_MODIFIES_BEHAVIOR)
8567 return rcStrict;
8568 }
8569#endif
8570 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8571 }
8572 }
8573
8574 return rcStrict;
8575}
8576
8577
8578/**
8579 * Implements 'FINIT' and 'FNINIT'.
8580 *
8581 * @param fCheckXcpts Whether to check for umasked pending exceptions or
8582 * not.
8583 */
8584IEM_CIMPL_DEF_1(iemCImpl_finit, bool, fCheckXcpts)
8585{
8586 /*
8587 * Exceptions.
8588 */
8589 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
8590 if (pVCpu->cpum.GstCtx.cr0 & (X86_CR0_EM | X86_CR0_TS))
8591 return iemRaiseDeviceNotAvailable(pVCpu);
8592
8593 iemFpuActualizeStateForChange(pVCpu);
8594 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_X87);
8595
8596 /* FINIT: Raise #MF on pending exception(s): */
8597 if (fCheckXcpts && (pVCpu->cpum.GstCtx.XState.x87.FSW & X86_FSW_ES))
8598 return iemRaiseMathFault(pVCpu);
8599
8600 /*
8601 * Reset the state.
8602 */
8603 PX86XSAVEAREA pXState = &pVCpu->cpum.GstCtx.XState;
8604
8605 /* Rotate the stack to account for changed TOS. */
8606 iemFpuRotateStackSetTop(&pXState->x87, 0);
8607
8608 pXState->x87.FCW = 0x37f;
8609 pXState->x87.FSW = 0;
8610 pXState->x87.FTW = 0x00; /* 0 - empty. */
8611 /** @todo Intel says the instruction and data pointers are not cleared on
8612 * 387, presume that 8087 and 287 doesn't do so either. */
8613 /** @todo test this stuff. */
8614 if (IEM_GET_TARGET_CPU(pVCpu) > IEMTARGETCPU_386)
8615 {
8616 pXState->x87.FPUDP = 0;
8617 pXState->x87.DS = 0; //??
8618 pXState->x87.Rsrvd2 = 0;
8619 pXState->x87.FPUIP = 0;
8620 pXState->x87.CS = 0; //??
8621 pXState->x87.Rsrvd1 = 0;
8622 }
8623 pXState->x87.FOP = 0;
8624
8625 iemHlpUsedFpu(pVCpu);
8626 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8627}
8628
8629
8630/**
8631 * Implements 'FXSAVE'.
8632 *
8633 * @param iEffSeg The effective segment.
8634 * @param GCPtrEff The address of the image.
8635 * @param enmEffOpSize The operand size (only REX.W really matters).
8636 */
8637IEM_CIMPL_DEF_3(iemCImpl_fxsave, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
8638{
8639 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX);
8640
8641 /** @todo check out bugref{1529} and AMD behaviour */
8642
8643 /*
8644 * Raise exceptions.
8645 */
8646 if (pVCpu->cpum.GstCtx.cr0 & (X86_CR0_TS | X86_CR0_EM))
8647 return iemRaiseDeviceNotAvailable(pVCpu);
8648
8649 /*
8650 * Access the memory.
8651 */
8652 uint8_t bUnmapInfo;
8653 void *pvMem512;
8654 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMem512, &bUnmapInfo, 512,
8655 iEffSeg, GCPtrEff, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE,
8656 15 | IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_GP_OR_AC);
8657 if (rcStrict != VINF_SUCCESS)
8658 return rcStrict;
8659 PX86FXSTATE pDst = (PX86FXSTATE)pvMem512;
8660 PCX86FXSTATE pSrc = &pVCpu->cpum.GstCtx.XState.x87;
8661
8662 /*
8663 * Store the registers.
8664 */
8665 /** @todo CPU/VM detection possible! If CR4.OSFXSR=0 MXCSR it's
8666 * implementation specific whether MXCSR and XMM0-XMM7 are saved. */
8667
8668 /* common for all formats */
8669 pDst->FCW = pSrc->FCW;
8670 pDst->FSW = pSrc->FSW;
8671 pDst->FTW = pSrc->FTW & UINT16_C(0xff);
8672 pDst->FOP = pSrc->FOP;
8673 pDst->MXCSR = pSrc->MXCSR;
8674 pDst->MXCSR_MASK = CPUMGetGuestMxCsrMask(pVCpu->CTX_SUFF(pVM));
8675 for (uint32_t i = 0; i < RT_ELEMENTS(pDst->aRegs); i++)
8676 {
8677 /** @todo Testcase: What actually happens to the 6 reserved bytes? I'm clearing
8678 * them for now... */
8679 pDst->aRegs[i].au32[0] = pSrc->aRegs[i].au32[0];
8680 pDst->aRegs[i].au32[1] = pSrc->aRegs[i].au32[1];
8681 pDst->aRegs[i].au32[2] = pSrc->aRegs[i].au32[2] & UINT32_C(0xffff);
8682 pDst->aRegs[i].au32[3] = 0;
8683 }
8684
8685 /* FPU IP, CS, DP and DS. */
8686 pDst->FPUIP = pSrc->FPUIP;
8687 pDst->CS = pSrc->CS;
8688 pDst->FPUDP = pSrc->FPUDP;
8689 pDst->DS = pSrc->DS;
8690 if (enmEffOpSize == IEMMODE_64BIT)
8691 {
8692 /* Save upper 16-bits of FPUIP (IP:CS:Rsvd1) and FPUDP (DP:DS:Rsvd2). */
8693 pDst->Rsrvd1 = pSrc->Rsrvd1;
8694 pDst->Rsrvd2 = pSrc->Rsrvd2;
8695 }
8696 else
8697 {
8698 pDst->Rsrvd1 = 0;
8699 pDst->Rsrvd2 = 0;
8700 }
8701
8702 /* XMM registers. Skipped in 64-bit CPL0 if EFER.FFXSR (AMD only) is set. */
8703 if ( !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_FFXSR)
8704 || !IEM_IS_64BIT_CODE(pVCpu)
8705 || IEM_GET_CPL(pVCpu) != 0)
8706 {
8707 uint32_t cXmmRegs = IEM_IS_64BIT_CODE(pVCpu) ? 16 : 8;
8708 for (uint32_t i = 0; i < cXmmRegs; i++)
8709 pDst->aXMM[i] = pSrc->aXMM[i];
8710 /** @todo Testcase: What happens to the reserved XMM registers? Untouched,
8711 * right? */
8712 }
8713
8714 /*
8715 * Commit the memory.
8716 */
8717 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
8718 if (rcStrict != VINF_SUCCESS)
8719 return rcStrict;
8720
8721 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8722}
8723
8724
8725/**
8726 * Implements 'FXRSTOR'.
8727 *
8728 * @param iEffSeg The effective segment register for @a GCPtrEff.
8729 * @param GCPtrEff The address of the image.
8730 * @param enmEffOpSize The operand size (only REX.W really matters).
8731 */
8732IEM_CIMPL_DEF_3(iemCImpl_fxrstor, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
8733{
8734 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX);
8735
8736 /** @todo check out bugref{1529} and AMD behaviour */
8737
8738 /*
8739 * Raise exceptions.
8740 */
8741 if (pVCpu->cpum.GstCtx.cr0 & (X86_CR0_TS | X86_CR0_EM))
8742 return iemRaiseDeviceNotAvailable(pVCpu);
8743
8744 /*
8745 * Access the memory.
8746 */
8747 uint8_t bUnmapInfo;
8748 void *pvMem512;
8749 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMem512, &bUnmapInfo, 512, iEffSeg, GCPtrEff, IEM_ACCESS_DATA_R,
8750 15 | IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_GP_OR_AC);
8751 if (rcStrict != VINF_SUCCESS)
8752 return rcStrict;
8753 PCX86FXSTATE pSrc = (PCX86FXSTATE)pvMem512;
8754 PX86FXSTATE pDst = &pVCpu->cpum.GstCtx.XState.x87;
8755
8756 /*
8757 * Check the state for stuff which will #GP(0).
8758 */
8759 uint32_t const fMXCSR = pSrc->MXCSR;
8760 uint32_t const fMXCSR_MASK = CPUMGetGuestMxCsrMask(pVCpu->CTX_SUFF(pVM));
8761 if (fMXCSR & ~fMXCSR_MASK)
8762 {
8763 Log(("fxrstor: MXCSR=%#x (MXCSR_MASK=%#x) -> #GP(0)\n", fMXCSR, fMXCSR_MASK));
8764 return iemRaiseGeneralProtectionFault0(pVCpu);
8765 }
8766
8767 /*
8768 * Load the registers.
8769 */
8770 /** @todo CPU/VM detection possible! If CR4.OSFXSR=0 MXCSR it's
8771 * implementation specific whether MXCSR and XMM0-XMM7 are
8772 * restored according to Intel.
8773 * AMD says MXCSR and XMM registers are never loaded if
8774 * CR4.OSFXSR=0.
8775 */
8776
8777 /* common for all formats */
8778 pDst->FCW = pSrc->FCW;
8779 pDst->FSW = pSrc->FSW;
8780 pDst->FTW = pSrc->FTW & UINT16_C(0xff);
8781 pDst->FOP = pSrc->FOP;
8782 pDst->MXCSR = fMXCSR;
8783 /* (MXCSR_MASK is read-only) */
8784 for (uint32_t i = 0; i < RT_ELEMENTS(pSrc->aRegs); i++)
8785 {
8786 pDst->aRegs[i].au32[0] = pSrc->aRegs[i].au32[0];
8787 pDst->aRegs[i].au32[1] = pSrc->aRegs[i].au32[1];
8788 pDst->aRegs[i].au32[2] = pSrc->aRegs[i].au32[2] & UINT32_C(0xffff);
8789 pDst->aRegs[i].au32[3] = 0;
8790 }
8791
8792 /* FPU IP, CS, DP and DS. */
8793 /** @todo AMD says this is only done if FSW.ES is set after loading. */
8794 if (enmEffOpSize == IEMMODE_64BIT)
8795 {
8796 pDst->FPUIP = pSrc->FPUIP;
8797 pDst->CS = pSrc->CS;
8798 pDst->Rsrvd1 = pSrc->Rsrvd1;
8799 pDst->FPUDP = pSrc->FPUDP;
8800 pDst->DS = pSrc->DS;
8801 pDst->Rsrvd2 = pSrc->Rsrvd2;
8802 }
8803 else
8804 {
8805 pDst->FPUIP = pSrc->FPUIP;
8806 pDst->CS = pSrc->CS;
8807 pDst->Rsrvd1 = 0;
8808 pDst->FPUDP = pSrc->FPUDP;
8809 pDst->DS = pSrc->DS;
8810 pDst->Rsrvd2 = 0;
8811 }
8812
8813 /* XMM registers. Skipped in 64-bit CPL0 if EFER.FFXSR (AMD only) is set.
8814 * Does not affect MXCSR, only registers.
8815 */
8816 if ( !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_FFXSR)
8817 || !IEM_IS_64BIT_CODE(pVCpu)
8818 || IEM_GET_CPL(pVCpu) != 0)
8819 {
8820 uint32_t cXmmRegs = IEM_IS_64BIT_CODE(pVCpu) ? 16 : 8;
8821 for (uint32_t i = 0; i < cXmmRegs; i++)
8822 pDst->aXMM[i] = pSrc->aXMM[i];
8823 }
8824
8825 pDst->FCW &= ~X86_FCW_ZERO_MASK | X86_FCW_IC_MASK; /* Intel 10980xe allows setting the IC bit. Win 3.11 CALC.EXE sets it. */
8826 iemFpuRecalcExceptionStatus(pDst);
8827
8828 if (pDst->FSW & X86_FSW_ES)
8829 Log11(("fxrstor: %04x:%08RX64: loading state with pending FPU exception (FSW=%#x)\n",
8830 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pSrc->FSW));
8831
8832 /*
8833 * Unmap the memory.
8834 */
8835 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
8836 if (rcStrict != VINF_SUCCESS)
8837 return rcStrict;
8838
8839 iemHlpUsedFpu(pVCpu);
8840 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
8841}
8842
8843
8844/**
8845 * Implements 'XSAVE'.
8846 *
8847 * @param iEffSeg The effective segment.
8848 * @param GCPtrEff The address of the image.
8849 * @param enmEffOpSize The operand size (only REX.W really matters).
8850 */
8851IEM_CIMPL_DEF_3(iemCImpl_xsave, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
8852{
8853 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx);
8854
8855 /*
8856 * Raise exceptions.
8857 */
8858 if (!(pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSXSAVE))
8859 return iemRaiseUndefinedOpcode(pVCpu);
8860 /* When in VMX non-root mode and XSAVE/XRSTOR is not enabled, it results in #UD. */
8861 if (RT_LIKELY( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
8862 || IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_XSAVES_XRSTORS)))
8863 { /* likely */ }
8864 else
8865 {
8866 Log(("xrstor: Not enabled for nested-guest execution -> #UD\n"));
8867 return iemRaiseUndefinedOpcode(pVCpu);
8868 }
8869 if (pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS)
8870 return iemRaiseDeviceNotAvailable(pVCpu);
8871
8872 /*
8873 * Calc the requested mask.
8874 */
8875 uint64_t const fReqComponents = RT_MAKE_U64(pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.edx) & pVCpu->cpum.GstCtx.aXcr[0];
8876 AssertLogRelReturn(!(fReqComponents & ~(XSAVE_C_X87 | XSAVE_C_SSE | XSAVE_C_YMM)), VERR_IEM_ASPECT_NOT_IMPLEMENTED);
8877 uint64_t const fXInUse = pVCpu->cpum.GstCtx.aXcr[0];
8878
8879/** @todo figure out the exact protocol for the memory access. Currently we
8880 * just need this crap to work halfways to make it possible to test
8881 * AVX instructions. */
8882/** @todo figure out the XINUSE and XMODIFIED */
8883
8884 /*
8885 * Access the x87 memory state.
8886 */
8887 /* The x87+SSE state. */
8888 uint8_t bUnmapInfoMem512;
8889 void *pvMem512;
8890 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMem512, &bUnmapInfoMem512, 512,
8891 iEffSeg, GCPtrEff, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE,
8892 63 | IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_GP_OR_AC);
8893 if (rcStrict != VINF_SUCCESS)
8894 return rcStrict;
8895 PX86FXSTATE pDst = (PX86FXSTATE)pvMem512;
8896 PCX86FXSTATE pSrc = &pVCpu->cpum.GstCtx.XState.x87;
8897
8898 /* The header. */
8899 uint8_t bUnmapInfoHdr;
8900 PX86XSAVEHDR pHdr;
8901 rcStrict = iemMemMap(pVCpu, (void **)&pHdr, &bUnmapInfoHdr, sizeof(pHdr),
8902 iEffSeg, GCPtrEff + 512, IEM_ACCESS_DATA_RW, 0 /* checked above */);
8903 if (rcStrict != VINF_SUCCESS)
8904 return rcStrict;
8905
8906 /*
8907 * Store the X87 state.
8908 */
8909 if (fReqComponents & XSAVE_C_X87)
8910 {
8911 /* common for all formats */
8912 pDst->FCW = pSrc->FCW;
8913 pDst->FSW = pSrc->FSW;
8914 pDst->FTW = pSrc->FTW & UINT16_C(0xff);
8915 pDst->FOP = pSrc->FOP;
8916 pDst->FPUIP = pSrc->FPUIP;
8917 pDst->CS = pSrc->CS;
8918 pDst->FPUDP = pSrc->FPUDP;
8919 pDst->DS = pSrc->DS;
8920 if (enmEffOpSize == IEMMODE_64BIT)
8921 {
8922 /* Save upper 16-bits of FPUIP (IP:CS:Rsvd1) and FPUDP (DP:DS:Rsvd2). */
8923 pDst->Rsrvd1 = pSrc->Rsrvd1;
8924 pDst->Rsrvd2 = pSrc->Rsrvd2;
8925 }
8926 else
8927 {
8928 pDst->Rsrvd1 = 0;
8929 pDst->Rsrvd2 = 0;
8930 }
8931 for (uint32_t i = 0; i < RT_ELEMENTS(pDst->aRegs); i++)
8932 {
8933 /** @todo Testcase: What actually happens to the 6 reserved bytes? I'm clearing
8934 * them for now... */
8935 pDst->aRegs[i].au32[0] = pSrc->aRegs[i].au32[0];
8936 pDst->aRegs[i].au32[1] = pSrc->aRegs[i].au32[1];
8937 pDst->aRegs[i].au32[2] = pSrc->aRegs[i].au32[2] & UINT32_C(0xffff);
8938 pDst->aRegs[i].au32[3] = 0;
8939 }
8940
8941 }
8942
8943 if (fReqComponents & (XSAVE_C_SSE | XSAVE_C_YMM))
8944 {
8945 pDst->MXCSR = pSrc->MXCSR;
8946 pDst->MXCSR_MASK = CPUMGetGuestMxCsrMask(pVCpu->CTX_SUFF(pVM));
8947 }
8948
8949 if (fReqComponents & XSAVE_C_SSE)
8950 {
8951 /* XMM registers. */
8952 uint32_t cXmmRegs = enmEffOpSize == IEMMODE_64BIT ? 16 : 8;
8953 for (uint32_t i = 0; i < cXmmRegs; i++)
8954 pDst->aXMM[i] = pSrc->aXMM[i];
8955 /** @todo Testcase: What happens to the reserved XMM registers? Untouched,
8956 * right? */
8957 }
8958
8959 /* Commit the x87 state bits. (probably wrong) */
8960 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfoMem512);
8961 if (rcStrict != VINF_SUCCESS)
8962 return rcStrict;
8963
8964 /*
8965 * Store AVX state.
8966 */
8967 if (fReqComponents & XSAVE_C_YMM)
8968 {
8969 /** @todo testcase: xsave64 vs xsave32 wrt XSAVE_C_YMM. */
8970 AssertLogRelReturn(pVCpu->cpum.GstCtx.aoffXState[XSAVE_C_YMM_BIT] != UINT16_MAX, VERR_IEM_IPE_9);
8971 uint8_t bUnmapInfoComp;
8972 PCX86XSAVEYMMHI pCompSrc = CPUMCTX_XSAVE_C_PTR(IEM_GET_CTX(pVCpu), XSAVE_C_YMM_BIT, PCX86XSAVEYMMHI);
8973 PX86XSAVEYMMHI pCompDst;
8974 rcStrict = iemMemMap(pVCpu, (void **)&pCompDst, &bUnmapInfoComp, sizeof(*pCompDst), iEffSeg,
8975 GCPtrEff + pVCpu->cpum.GstCtx.aoffXState[XSAVE_C_YMM_BIT],
8976 IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE, 0 /* checked above */);
8977 if (rcStrict != VINF_SUCCESS)
8978 return rcStrict;
8979
8980 uint32_t cXmmRegs = enmEffOpSize == IEMMODE_64BIT ? 16 : 8;
8981 for (uint32_t i = 0; i < cXmmRegs; i++)
8982 pCompDst->aYmmHi[i] = pCompSrc->aYmmHi[i];
8983
8984 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfoComp);
8985 if (rcStrict != VINF_SUCCESS)
8986 return rcStrict;
8987 }
8988
8989 /*
8990 * Update the header.
8991 */
8992 pHdr->bmXState = (pHdr->bmXState & ~fReqComponents)
8993 | (fReqComponents & fXInUse);
8994
8995 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfoHdr);
8996 if (rcStrict != VINF_SUCCESS)
8997 return rcStrict;
8998
8999 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9000}
9001
9002
9003/**
9004 * Implements 'XRSTOR'.
9005 *
9006 * @param iEffSeg The effective segment.
9007 * @param GCPtrEff The address of the image.
9008 * @param enmEffOpSize The operand size (only REX.W really matters).
9009 */
9010IEM_CIMPL_DEF_3(iemCImpl_xrstor, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
9011{
9012 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx);
9013
9014 /*
9015 * Raise exceptions.
9016 */
9017 if (!(pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSXSAVE))
9018 return iemRaiseUndefinedOpcode(pVCpu);
9019 /* When in VMX non-root mode and XSAVE/XRSTOR is not enabled, it results in #UD. */
9020 if (RT_LIKELY( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
9021 || IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_XSAVES_XRSTORS)))
9022 { /* likely */ }
9023 else
9024 {
9025 Log(("xrstor: Not enabled for nested-guest execution -> #UD\n"));
9026 return iemRaiseUndefinedOpcode(pVCpu);
9027 }
9028 if (pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS)
9029 return iemRaiseDeviceNotAvailable(pVCpu);
9030 if (GCPtrEff & 63)
9031 {
9032 /** @todo CPU/VM detection possible! \#AC might not be signal for
9033 * all/any misalignment sizes, intel says its an implementation detail. */
9034 if ( (pVCpu->cpum.GstCtx.cr0 & X86_CR0_AM)
9035 && pVCpu->cpum.GstCtx.eflags.Bits.u1AC
9036 && IEM_GET_CPL(pVCpu) == 3)
9037 return iemRaiseAlignmentCheckException(pVCpu);
9038 return iemRaiseGeneralProtectionFault0(pVCpu);
9039 }
9040
9041/** @todo figure out the exact protocol for the memory access. Currently we
9042 * just need this crap to work halfways to make it possible to test
9043 * AVX instructions. */
9044/** @todo figure out the XINUSE and XMODIFIED */
9045
9046 /*
9047 * Access the x87 memory state.
9048 */
9049 /* The x87+SSE state. */
9050 uint8_t bUnmapInfoMem512;
9051 void *pvMem512;
9052 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMem512, &bUnmapInfoMem512, 512, iEffSeg, GCPtrEff, IEM_ACCESS_DATA_R,
9053 63 | IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_GP_OR_AC);
9054 if (rcStrict != VINF_SUCCESS)
9055 return rcStrict;
9056 PCX86FXSTATE pSrc = (PCX86FXSTATE)pvMem512;
9057 PX86FXSTATE pDst = &pVCpu->cpum.GstCtx.XState.x87;
9058
9059 /*
9060 * Calc the requested mask
9061 */
9062 uint8_t bUnmapInfoHdr;
9063 PX86XSAVEHDR pHdrDst = &pVCpu->cpum.GstCtx.XState.Hdr;
9064 PCX86XSAVEHDR pHdrSrc;
9065 rcStrict = iemMemMap(pVCpu, (void **)&pHdrSrc, &bUnmapInfoHdr, sizeof(*pHdrSrc), iEffSeg, GCPtrEff + 512,
9066 IEM_ACCESS_DATA_R, 0 /* checked above */);
9067 if (rcStrict != VINF_SUCCESS)
9068 return rcStrict;
9069
9070 uint64_t const fReqComponents = RT_MAKE_U64(pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.edx) & pVCpu->cpum.GstCtx.aXcr[0];
9071 AssertLogRelReturn(!(fReqComponents & ~(XSAVE_C_X87 | XSAVE_C_SSE | XSAVE_C_YMM)), VERR_IEM_ASPECT_NOT_IMPLEMENTED);
9072 //uint64_t const fXInUse = pVCpu->cpum.GstCtx.aXcr[0];
9073 uint64_t const fRstorMask = pHdrSrc->bmXState;
9074 uint64_t const fCompMask = pHdrSrc->bmXComp;
9075
9076 AssertLogRelReturn(!(fCompMask & XSAVE_C_X), VERR_IEM_ASPECT_NOT_IMPLEMENTED);
9077
9078 uint32_t const cXmmRegs = enmEffOpSize == IEMMODE_64BIT ? 16 : 8;
9079
9080 /* We won't need this any longer. */
9081 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfoHdr);
9082 if (rcStrict != VINF_SUCCESS)
9083 return rcStrict;
9084
9085 /*
9086 * Load the X87 state.
9087 */
9088 if (fReqComponents & XSAVE_C_X87)
9089 {
9090 if (fRstorMask & XSAVE_C_X87)
9091 {
9092 pDst->FCW = pSrc->FCW;
9093 pDst->FSW = pSrc->FSW;
9094 pDst->FTW = pSrc->FTW & UINT16_C(0xff);
9095 pDst->FOP = pSrc->FOP;
9096 pDst->FPUIP = pSrc->FPUIP;
9097 pDst->CS = pSrc->CS;
9098 pDst->FPUDP = pSrc->FPUDP;
9099 pDst->DS = pSrc->DS;
9100 if (enmEffOpSize == IEMMODE_64BIT)
9101 {
9102 /* Load upper 16-bits of FPUIP (IP:CS:Rsvd1) and FPUDP (DP:DS:Rsvd2). */
9103 pDst->Rsrvd1 = pSrc->Rsrvd1;
9104 pDst->Rsrvd2 = pSrc->Rsrvd2;
9105 }
9106 else
9107 {
9108 pDst->Rsrvd1 = 0;
9109 pDst->Rsrvd2 = 0;
9110 }
9111 for (uint32_t i = 0; i < RT_ELEMENTS(pDst->aRegs); i++)
9112 {
9113 pDst->aRegs[i].au32[0] = pSrc->aRegs[i].au32[0];
9114 pDst->aRegs[i].au32[1] = pSrc->aRegs[i].au32[1];
9115 pDst->aRegs[i].au32[2] = pSrc->aRegs[i].au32[2] & UINT32_C(0xffff);
9116 pDst->aRegs[i].au32[3] = 0;
9117 }
9118
9119 pDst->FCW &= ~X86_FCW_ZERO_MASK | X86_FCW_IC_MASK; /* Intel 10980xe allows setting the IC bit. Win 3.11 CALC.EXE sets it. */
9120 iemFpuRecalcExceptionStatus(pDst);
9121
9122 if (pDst->FSW & X86_FSW_ES)
9123 Log11(("xrstor: %04x:%08RX64: loading state with pending FPU exception (FSW=%#x)\n",
9124 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pSrc->FSW));
9125 }
9126 else
9127 {
9128 pDst->FCW = 0x37f;
9129 pDst->FSW = 0;
9130 pDst->FTW = 0x00; /* 0 - empty. */
9131 pDst->FPUDP = 0;
9132 pDst->DS = 0; //??
9133 pDst->Rsrvd2= 0;
9134 pDst->FPUIP = 0;
9135 pDst->CS = 0; //??
9136 pDst->Rsrvd1= 0;
9137 pDst->FOP = 0;
9138 for (uint32_t i = 0; i < RT_ELEMENTS(pSrc->aRegs); i++)
9139 {
9140 pDst->aRegs[i].au32[0] = 0;
9141 pDst->aRegs[i].au32[1] = 0;
9142 pDst->aRegs[i].au32[2] = 0;
9143 pDst->aRegs[i].au32[3] = 0;
9144 }
9145 }
9146 pHdrDst->bmXState |= XSAVE_C_X87; /* playing safe for now */
9147 }
9148
9149 /* MXCSR */
9150 if (fReqComponents & (XSAVE_C_SSE | XSAVE_C_YMM))
9151 {
9152 if (fRstorMask & (XSAVE_C_SSE | XSAVE_C_YMM))
9153 pDst->MXCSR = pSrc->MXCSR;
9154 else
9155 pDst->MXCSR = 0x1f80;
9156 }
9157
9158 /* XMM registers. */
9159 if (fReqComponents & XSAVE_C_SSE)
9160 {
9161 if (fRstorMask & XSAVE_C_SSE)
9162 {
9163 for (uint32_t i = 0; i < cXmmRegs; i++)
9164 pDst->aXMM[i] = pSrc->aXMM[i];
9165 /** @todo Testcase: What happens to the reserved XMM registers? Untouched,
9166 * right? */
9167 }
9168 else
9169 {
9170 for (uint32_t i = 0; i < cXmmRegs; i++)
9171 {
9172 pDst->aXMM[i].au64[0] = 0;
9173 pDst->aXMM[i].au64[1] = 0;
9174 }
9175 }
9176 pHdrDst->bmXState |= XSAVE_C_SSE; /* playing safe for now */
9177 }
9178
9179 /* Unmap the x87 state bits (so we've don't run out of mapping). */
9180 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfoMem512);
9181 if (rcStrict != VINF_SUCCESS)
9182 return rcStrict;
9183
9184 /*
9185 * Restore AVX state.
9186 */
9187 if (fReqComponents & XSAVE_C_YMM)
9188 {
9189 AssertLogRelReturn(pVCpu->cpum.GstCtx.aoffXState[XSAVE_C_YMM_BIT] != UINT16_MAX, VERR_IEM_IPE_9);
9190 PX86XSAVEYMMHI pCompDst = CPUMCTX_XSAVE_C_PTR(IEM_GET_CTX(pVCpu), XSAVE_C_YMM_BIT, PX86XSAVEYMMHI);
9191
9192 if (fRstorMask & XSAVE_C_YMM)
9193 {
9194 /** @todo testcase: xsave64 vs xsave32 wrt XSAVE_C_YMM. */
9195 uint8_t bUnmapInfoComp;
9196 PCX86XSAVEYMMHI pCompSrc;
9197 rcStrict = iemMemMap(pVCpu, (void **)&pCompSrc, &bUnmapInfoComp, sizeof(*pCompDst),
9198 iEffSeg, GCPtrEff + pVCpu->cpum.GstCtx.aoffXState[XSAVE_C_YMM_BIT],
9199 IEM_ACCESS_DATA_R, 0 /* checked above */);
9200 if (rcStrict != VINF_SUCCESS)
9201 return rcStrict;
9202
9203 for (uint32_t i = 0; i < cXmmRegs; i++)
9204 {
9205 pCompDst->aYmmHi[i].au64[0] = pCompSrc->aYmmHi[i].au64[0];
9206 pCompDst->aYmmHi[i].au64[1] = pCompSrc->aYmmHi[i].au64[1];
9207 }
9208
9209 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfoComp);
9210 if (rcStrict != VINF_SUCCESS)
9211 return rcStrict;
9212 }
9213 else
9214 {
9215 for (uint32_t i = 0; i < cXmmRegs; i++)
9216 {
9217 pCompDst->aYmmHi[i].au64[0] = 0;
9218 pCompDst->aYmmHi[i].au64[1] = 0;
9219 }
9220 }
9221 pHdrDst->bmXState |= XSAVE_C_YMM; /* playing safe for now */
9222 }
9223
9224 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9225}
9226
9227
9228
9229
9230/**
9231 * Implements 'STMXCSR'.
9232 *
9233 * @param iEffSeg The effective segment register for @a GCPtrEff.
9234 * @param GCPtrEff The address of the image.
9235 */
9236IEM_CIMPL_DEF_2(iemCImpl_stmxcsr, uint8_t, iEffSeg, RTGCPTR, GCPtrEff)
9237{
9238 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX);
9239
9240 /*
9241 * Raise exceptions.
9242 */
9243 if ( !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_EM)
9244 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSFXSR))
9245 {
9246 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS))
9247 {
9248 /*
9249 * Do the job.
9250 */
9251 VBOXSTRICTRC rcStrict = iemMemStoreDataU32(pVCpu, iEffSeg, GCPtrEff, pVCpu->cpum.GstCtx.XState.x87.MXCSR);
9252 if (rcStrict == VINF_SUCCESS)
9253 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9254 return rcStrict;
9255 }
9256 return iemRaiseDeviceNotAvailable(pVCpu);
9257 }
9258 return iemRaiseUndefinedOpcode(pVCpu);
9259}
9260
9261
9262/**
9263 * Implements 'VSTMXCSR'.
9264 *
9265 * @param iEffSeg The effective segment register for @a GCPtrEff.
9266 * @param GCPtrEff The address of the image.
9267 */
9268IEM_CIMPL_DEF_2(iemCImpl_vstmxcsr, uint8_t, iEffSeg, RTGCPTR, GCPtrEff)
9269{
9270 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_XCRx);
9271
9272 /*
9273 * Raise exceptions.
9274 */
9275 if ( ( !IEM_IS_GUEST_CPU_AMD(pVCpu)
9276 ? (pVCpu->cpum.GstCtx.aXcr[0] & (XSAVE_C_SSE | XSAVE_C_YMM)) == (XSAVE_C_SSE | XSAVE_C_YMM)
9277 : !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_EM)) /* AMD Jaguar CPU (f0x16,m0,s1) behaviour */
9278 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSXSAVE))
9279 {
9280 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS))
9281 {
9282 /*
9283 * Do the job.
9284 */
9285 VBOXSTRICTRC rcStrict = iemMemStoreDataU32(pVCpu, iEffSeg, GCPtrEff, pVCpu->cpum.GstCtx.XState.x87.MXCSR);
9286 if (rcStrict == VINF_SUCCESS)
9287 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9288 return rcStrict;
9289 }
9290 return iemRaiseDeviceNotAvailable(pVCpu);
9291 }
9292 return iemRaiseUndefinedOpcode(pVCpu);
9293}
9294
9295
9296/**
9297 * Implements 'LDMXCSR'.
9298 *
9299 * @param iEffSeg The effective segment register for @a GCPtrEff.
9300 * @param GCPtrEff The address of the image.
9301 */
9302IEM_CIMPL_DEF_2(iemCImpl_ldmxcsr, uint8_t, iEffSeg, RTGCPTR, GCPtrEff)
9303{
9304 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX);
9305
9306 /*
9307 * Raise exceptions.
9308 */
9309 /** @todo testcase - order of LDMXCSR faults. Does \#PF, \#GP and \#SS
9310 * happen after or before \#UD and \#EM? */
9311 if ( !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_EM)
9312 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSFXSR))
9313 {
9314 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS))
9315 {
9316 /*
9317 * Do the job.
9318 */
9319 uint32_t fNewMxCsr;
9320 VBOXSTRICTRC rcStrict = iemMemFetchDataU32(pVCpu, &fNewMxCsr, iEffSeg, GCPtrEff);
9321 if (rcStrict == VINF_SUCCESS)
9322 {
9323 uint32_t const fMxCsrMask = CPUMGetGuestMxCsrMask(pVCpu->CTX_SUFF(pVM));
9324 if (!(fNewMxCsr & ~fMxCsrMask))
9325 {
9326 pVCpu->cpum.GstCtx.XState.x87.MXCSR = fNewMxCsr;
9327 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9328 }
9329 Log(("ldmxcsr: New MXCSR=%#RX32 & ~MASK=%#RX32 = %#RX32 -> #GP(0)\n",
9330 fNewMxCsr, fMxCsrMask, fNewMxCsr & ~fMxCsrMask));
9331 return iemRaiseGeneralProtectionFault0(pVCpu);
9332 }
9333 return rcStrict;
9334 }
9335 return iemRaiseDeviceNotAvailable(pVCpu);
9336 }
9337 return iemRaiseUndefinedOpcode(pVCpu);
9338}
9339
9340
9341/**
9342 * Implements 'VSTMXCSR'.
9343 *
9344 * @param iEffSeg The effective segment register for @a GCPtrEff.
9345 * @param GCPtrEff The address of the image.
9346 */
9347IEM_CIMPL_DEF_2(iemCImpl_vldmxcsr, uint8_t, iEffSeg, RTGCPTR, GCPtrEff)
9348{
9349 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_XCRx);
9350
9351 /*
9352 * Raise exceptions.
9353 */
9354 if ( ( !IEM_IS_GUEST_CPU_AMD(pVCpu)
9355 ? (pVCpu->cpum.GstCtx.aXcr[0] & (XSAVE_C_SSE | XSAVE_C_YMM)) == (XSAVE_C_SSE | XSAVE_C_YMM)
9356 : !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_EM))
9357 && (pVCpu->cpum.GstCtx.cr4 & X86_CR4_OSXSAVE))
9358 {
9359 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_TS))
9360 {
9361 /*
9362 * Do the job.
9363 */
9364 uint32_t fNewMxCsr;
9365 VBOXSTRICTRC rcStrict = iemMemFetchDataU32(pVCpu, &fNewMxCsr, iEffSeg, GCPtrEff);
9366 if (rcStrict == VINF_SUCCESS)
9367 {
9368 uint32_t const fMxCsrMask = CPUMGetGuestMxCsrMask(pVCpu->CTX_SUFF(pVM));
9369 if (!(fNewMxCsr & ~fMxCsrMask))
9370 {
9371 pVCpu->cpum.GstCtx.XState.x87.MXCSR = fNewMxCsr;
9372 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9373 }
9374 Log(("ldmxcsr: New MXCSR=%#RX32 & ~MASK=%#RX32 = %#RX32 -> #GP(0)\n",
9375 fNewMxCsr, fMxCsrMask, fNewMxCsr & ~fMxCsrMask));
9376 return iemRaiseGeneralProtectionFault0(pVCpu);
9377 }
9378 return rcStrict;
9379 }
9380 return iemRaiseDeviceNotAvailable(pVCpu);
9381 }
9382 return iemRaiseUndefinedOpcode(pVCpu);
9383}
9384
9385
9386/**
9387 * Commmon routine for fnstenv and fnsave.
9388 *
9389 * @param pVCpu The cross context virtual CPU structure of the calling thread.
9390 * @param enmEffOpSize The effective operand size.
9391 * @param uPtr Where to store the state.
9392 */
9393static void iemCImplCommonFpuStoreEnv(PVMCPUCC pVCpu, IEMMODE enmEffOpSize, RTPTRUNION uPtr)
9394{
9395 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87);
9396 PCX86FXSTATE pSrcX87 = &pVCpu->cpum.GstCtx.XState.x87;
9397 if (enmEffOpSize == IEMMODE_16BIT)
9398 {
9399 uPtr.pu16[0] = pSrcX87->FCW;
9400 uPtr.pu16[1] = pSrcX87->FSW;
9401 uPtr.pu16[2] = iemFpuCalcFullFtw(pSrcX87);
9402 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
9403 {
9404 /** @todo Testcase: How does this work when the FPUIP/CS was saved in
9405 * protected mode or long mode and we save it in real mode? And vice
9406 * versa? And with 32-bit operand size? I think CPU is storing the
9407 * effective address ((CS << 4) + IP) in the offset register and not
9408 * doing any address calculations here. */
9409 uPtr.pu16[3] = (uint16_t)pSrcX87->FPUIP;
9410 uPtr.pu16[4] = ((pSrcX87->FPUIP >> 4) & UINT16_C(0xf000)) | pSrcX87->FOP;
9411 uPtr.pu16[5] = (uint16_t)pSrcX87->FPUDP;
9412 uPtr.pu16[6] = (pSrcX87->FPUDP >> 4) & UINT16_C(0xf000);
9413 }
9414 else
9415 {
9416 uPtr.pu16[3] = pSrcX87->FPUIP;
9417 uPtr.pu16[4] = pSrcX87->CS;
9418 uPtr.pu16[5] = pSrcX87->FPUDP;
9419 uPtr.pu16[6] = pSrcX87->DS;
9420 }
9421 }
9422 else
9423 {
9424 /** @todo Testcase: what is stored in the "gray" areas? (figure 8-9 and 8-10) */
9425 uPtr.pu16[0*2] = pSrcX87->FCW;
9426 uPtr.pu16[0*2+1] = 0xffff; /* (0xffff observed on intel skylake.) */
9427 uPtr.pu16[1*2] = pSrcX87->FSW;
9428 uPtr.pu16[1*2+1] = 0xffff;
9429 uPtr.pu16[2*2] = iemFpuCalcFullFtw(pSrcX87);
9430 uPtr.pu16[2*2+1] = 0xffff;
9431 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
9432 {
9433 uPtr.pu16[3*2] = (uint16_t)pSrcX87->FPUIP;
9434 uPtr.pu32[4] = ((pSrcX87->FPUIP & UINT32_C(0xffff0000)) >> 4) | pSrcX87->FOP;
9435 uPtr.pu16[5*2] = (uint16_t)pSrcX87->FPUDP;
9436 uPtr.pu32[6] = (pSrcX87->FPUDP & UINT32_C(0xffff0000)) >> 4;
9437 }
9438 else
9439 {
9440 uPtr.pu32[3] = pSrcX87->FPUIP;
9441 uPtr.pu16[4*2] = pSrcX87->CS;
9442 uPtr.pu16[4*2+1] = pSrcX87->FOP;
9443 uPtr.pu32[5] = pSrcX87->FPUDP;
9444 uPtr.pu16[6*2] = pSrcX87->DS;
9445 uPtr.pu16[6*2+1] = 0xffff;
9446 }
9447 }
9448}
9449
9450
9451/**
9452 * Commmon routine for fldenv and frstor
9453 *
9454 * @param pVCpu The cross context virtual CPU structure of the calling thread.
9455 * @param enmEffOpSize The effective operand size.
9456 * @param uPtr Where to store the state.
9457 */
9458static void iemCImplCommonFpuRestoreEnv(PVMCPUCC pVCpu, IEMMODE enmEffOpSize, RTCPTRUNION uPtr)
9459{
9460 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87);
9461 PX86FXSTATE pDstX87 = &pVCpu->cpum.GstCtx.XState.x87;
9462 if (enmEffOpSize == IEMMODE_16BIT)
9463 {
9464 pDstX87->FCW = uPtr.pu16[0];
9465 pDstX87->FSW = uPtr.pu16[1];
9466 pDstX87->FTW = uPtr.pu16[2];
9467 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
9468 {
9469 pDstX87->FPUIP = uPtr.pu16[3] | ((uint32_t)(uPtr.pu16[4] & UINT16_C(0xf000)) << 4);
9470 pDstX87->FPUDP = uPtr.pu16[5] | ((uint32_t)(uPtr.pu16[6] & UINT16_C(0xf000)) << 4);
9471 pDstX87->FOP = uPtr.pu16[4] & UINT16_C(0x07ff);
9472 pDstX87->CS = 0;
9473 pDstX87->Rsrvd1= 0;
9474 pDstX87->DS = 0;
9475 pDstX87->Rsrvd2= 0;
9476 }
9477 else
9478 {
9479 pDstX87->FPUIP = uPtr.pu16[3];
9480 pDstX87->CS = uPtr.pu16[4];
9481 pDstX87->Rsrvd1= 0;
9482 pDstX87->FPUDP = uPtr.pu16[5];
9483 pDstX87->DS = uPtr.pu16[6];
9484 pDstX87->Rsrvd2= 0;
9485 /** @todo Testcase: Is FOP cleared when doing 16-bit protected mode fldenv? */
9486 }
9487 }
9488 else
9489 {
9490 pDstX87->FCW = uPtr.pu16[0*2];
9491 pDstX87->FSW = uPtr.pu16[1*2];
9492 pDstX87->FTW = uPtr.pu16[2*2];
9493 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
9494 {
9495 pDstX87->FPUIP = uPtr.pu16[3*2] | ((uPtr.pu32[4] & UINT32_C(0x0ffff000)) << 4);
9496 pDstX87->FOP = uPtr.pu32[4] & UINT16_C(0x07ff);
9497 pDstX87->FPUDP = uPtr.pu16[5*2] | ((uPtr.pu32[6] & UINT32_C(0x0ffff000)) << 4);
9498 pDstX87->CS = 0;
9499 pDstX87->Rsrvd1= 0;
9500 pDstX87->DS = 0;
9501 pDstX87->Rsrvd2= 0;
9502 }
9503 else
9504 {
9505 pDstX87->FPUIP = uPtr.pu32[3];
9506 pDstX87->CS = uPtr.pu16[4*2];
9507 pDstX87->Rsrvd1= 0;
9508 pDstX87->FOP = uPtr.pu16[4*2+1];
9509 pDstX87->FPUDP = uPtr.pu32[5];
9510 pDstX87->DS = uPtr.pu16[6*2];
9511 pDstX87->Rsrvd2= 0;
9512 }
9513 }
9514
9515 /* Make adjustments. */
9516 pDstX87->FTW = iemFpuCompressFtw(pDstX87->FTW);
9517#ifdef LOG_ENABLED
9518 uint16_t const fOldFsw = pDstX87->FSW;
9519#endif
9520 pDstX87->FCW &= ~X86_FCW_ZERO_MASK | X86_FCW_IC_MASK; /* Intel 10980xe allows setting the IC bit. Win 3.11 CALC.EXE sets it. */
9521 iemFpuRecalcExceptionStatus(pDstX87);
9522#ifdef LOG_ENABLED
9523 if ((pDstX87->FSW & X86_FSW_ES) ^ (fOldFsw & X86_FSW_ES))
9524 Log11(("iemCImplCommonFpuRestoreEnv: %04x:%08RX64: %s FPU exception (FCW=%#x FSW=%#x -> %#x)\n",
9525 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, fOldFsw & X86_FSW_ES ? "Supressed" : "Raised",
9526 pDstX87->FCW, fOldFsw, pDstX87->FSW));
9527#endif
9528
9529 /** @todo Testcase: Check if ES and/or B are automatically cleared if no
9530 * exceptions are pending after loading the saved state? */
9531}
9532
9533
9534/**
9535 * Implements 'FNSTENV'.
9536 *
9537 * @param enmEffOpSize The operand size (only REX.W really matters).
9538 * @param iEffSeg The effective segment register for @a GCPtrEffDst.
9539 * @param GCPtrEffDst The address of the image.
9540 */
9541IEM_CIMPL_DEF_3(iemCImpl_fnstenv, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
9542{
9543 uint8_t bUnmapInfo;
9544 RTPTRUNION uPtr;
9545 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &uPtr.pv, &bUnmapInfo, enmEffOpSize == IEMMODE_16BIT ? 14 : 28,
9546 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE,
9547 enmEffOpSize == IEMMODE_16BIT ? 1 : 3 /** @todo ? */);
9548 if (rcStrict != VINF_SUCCESS)
9549 return rcStrict;
9550
9551 iemCImplCommonFpuStoreEnv(pVCpu, enmEffOpSize, uPtr);
9552
9553 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
9554 if (rcStrict != VINF_SUCCESS)
9555 return rcStrict;
9556
9557 /* Mask all math exceptions. Any possibly pending exceptions will be cleared. */
9558 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
9559 pFpuCtx->FCW |= X86_FCW_XCPT_MASK;
9560#ifdef LOG_ENABLED
9561 uint16_t fOldFsw = pFpuCtx->FSW;
9562#endif
9563 iemFpuRecalcExceptionStatus(pFpuCtx);
9564#ifdef LOG_ENABLED
9565 if ((pFpuCtx->FSW & X86_FSW_ES) ^ (fOldFsw & X86_FSW_ES))
9566 Log11(("fnstenv: %04x:%08RX64: %s FPU exception (FCW=%#x, FSW %#x -> %#x)\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
9567 fOldFsw & X86_FSW_ES ? "Supressed" : "Raised", pFpuCtx->FCW, fOldFsw, pFpuCtx->FSW));
9568#endif
9569
9570 iemHlpUsedFpu(pVCpu);
9571
9572 /* Note: C0, C1, C2 and C3 are documented as undefined, we leave them untouched! */
9573 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9574}
9575
9576
9577/**
9578 * Implements 'FNSAVE'.
9579 *
9580 * @param enmEffOpSize The operand size.
9581 * @param iEffSeg The effective segment register for @a GCPtrEffDst.
9582 * @param GCPtrEffDst The address of the image.
9583 */
9584IEM_CIMPL_DEF_3(iemCImpl_fnsave, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
9585{
9586 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87);
9587
9588 uint8_t bUnmapInfo;
9589 RTPTRUNION uPtr;
9590 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &uPtr.pv, &bUnmapInfo, enmEffOpSize == IEMMODE_16BIT ? 94 : 108,
9591 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE, 3 /** @todo ? */);
9592 if (rcStrict != VINF_SUCCESS)
9593 return rcStrict;
9594
9595 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
9596 iemCImplCommonFpuStoreEnv(pVCpu, enmEffOpSize, uPtr);
9597 PRTFLOAT80U paRegs = (PRTFLOAT80U)(uPtr.pu8 + (enmEffOpSize == IEMMODE_16BIT ? 14 : 28));
9598 for (uint32_t i = 0; i < RT_ELEMENTS(pFpuCtx->aRegs); i++)
9599 {
9600 paRegs[i].au32[0] = pFpuCtx->aRegs[i].au32[0];
9601 paRegs[i].au32[1] = pFpuCtx->aRegs[i].au32[1];
9602 paRegs[i].au16[4] = pFpuCtx->aRegs[i].au16[4];
9603 }
9604
9605 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
9606 if (rcStrict != VINF_SUCCESS)
9607 return rcStrict;
9608
9609 /* Rotate the stack to account for changed TOS. */
9610 iemFpuRotateStackSetTop(pFpuCtx, 0);
9611
9612 /*
9613 * Re-initialize the FPU context.
9614 */
9615 pFpuCtx->FCW = 0x37f;
9616 pFpuCtx->FSW = 0;
9617 pFpuCtx->FTW = 0x00; /* 0 - empty */
9618 pFpuCtx->FPUDP = 0;
9619 pFpuCtx->DS = 0;
9620 pFpuCtx->Rsrvd2= 0;
9621 pFpuCtx->FPUIP = 0;
9622 pFpuCtx->CS = 0;
9623 pFpuCtx->Rsrvd1= 0;
9624 pFpuCtx->FOP = 0;
9625
9626 iemHlpUsedFpu(pVCpu);
9627 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9628}
9629
9630
9631
9632/**
9633 * Implements 'FLDENV'.
9634 *
9635 * @param enmEffOpSize The operand size (only REX.W really matters).
9636 * @param iEffSeg The effective segment register for @a GCPtrEffSrc.
9637 * @param GCPtrEffSrc The address of the image.
9638 */
9639IEM_CIMPL_DEF_3(iemCImpl_fldenv, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
9640{
9641 uint8_t bUnmapInfo;
9642 RTCPTRUNION uPtr;
9643 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, (void **)&uPtr.pv, &bUnmapInfo, enmEffOpSize == IEMMODE_16BIT ? 14 : 28,
9644 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R,
9645 enmEffOpSize == IEMMODE_16BIT ? 1 : 3 /** @todo ?*/);
9646 if (rcStrict != VINF_SUCCESS)
9647 return rcStrict;
9648
9649 iemCImplCommonFpuRestoreEnv(pVCpu, enmEffOpSize, uPtr);
9650
9651 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
9652 if (rcStrict != VINF_SUCCESS)
9653 return rcStrict;
9654
9655 iemHlpUsedFpu(pVCpu);
9656 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9657}
9658
9659
9660/**
9661 * Implements 'FRSTOR'.
9662 *
9663 * @param enmEffOpSize The operand size.
9664 * @param iEffSeg The effective segment register for @a GCPtrEffSrc.
9665 * @param GCPtrEffSrc The address of the image.
9666 */
9667IEM_CIMPL_DEF_3(iemCImpl_frstor, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
9668{
9669 uint8_t bUnmapInfo;
9670 RTCPTRUNION uPtr;
9671 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, (void **)&uPtr.pv, &bUnmapInfo, enmEffOpSize == IEMMODE_16BIT ? 94 : 108,
9672 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R, 3 /** @todo ?*/ );
9673 if (rcStrict != VINF_SUCCESS)
9674 return rcStrict;
9675
9676 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
9677 iemCImplCommonFpuRestoreEnv(pVCpu, enmEffOpSize, uPtr);
9678 PCRTFLOAT80U paRegs = (PCRTFLOAT80U)(uPtr.pu8 + (enmEffOpSize == IEMMODE_16BIT ? 14 : 28));
9679 for (uint32_t i = 0; i < RT_ELEMENTS(pFpuCtx->aRegs); i++)
9680 {
9681 pFpuCtx->aRegs[i].au32[0] = paRegs[i].au32[0];
9682 pFpuCtx->aRegs[i].au32[1] = paRegs[i].au32[1];
9683 pFpuCtx->aRegs[i].au32[2] = paRegs[i].au16[4];
9684 pFpuCtx->aRegs[i].au32[3] = 0;
9685 }
9686
9687 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
9688 if (rcStrict != VINF_SUCCESS)
9689 return rcStrict;
9690
9691 iemHlpUsedFpu(pVCpu);
9692 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9693}
9694
9695
9696/**
9697 * Implements 'FLDCW'.
9698 *
9699 * @param u16Fcw The new FCW.
9700 */
9701IEM_CIMPL_DEF_1(iemCImpl_fldcw, uint16_t, u16Fcw)
9702{
9703 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87);
9704
9705 /** @todo Testcase: Check what happens when trying to load X86_FCW_PC_RSVD. */
9706 /** @todo Testcase: Try see what happens when trying to set undefined bits
9707 * (other than 6 and 7). Currently ignoring them. */
9708 /** @todo Testcase: Test that it raises and loweres the FPU exception bits
9709 * according to FSW. (This is what is currently implemented.) */
9710 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
9711 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. */
9712#ifdef LOG_ENABLED
9713 uint16_t fOldFsw = pFpuCtx->FSW;
9714#endif
9715 iemFpuRecalcExceptionStatus(pFpuCtx);
9716#ifdef LOG_ENABLED
9717 if ((pFpuCtx->FSW & X86_FSW_ES) ^ (fOldFsw & X86_FSW_ES))
9718 Log11(("fldcw: %04x:%08RX64: %s FPU exception (FCW=%#x, FSW %#x -> %#x)\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
9719 fOldFsw & X86_FSW_ES ? "Supressed" : "Raised", pFpuCtx->FCW, fOldFsw, pFpuCtx->FSW));
9720#endif
9721
9722 /* Note: C0, C1, C2 and C3 are documented as undefined, we leave them untouched! */
9723 iemHlpUsedFpu(pVCpu);
9724 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9725}
9726
9727
9728
9729/**
9730 * Implements the underflow case of fxch.
9731 *
9732 * @param iStReg The other stack register.
9733 * @param uFpuOpcode The FPU opcode (for simplicity).
9734 */
9735IEM_CIMPL_DEF_2(iemCImpl_fxch_underflow, uint8_t, iStReg, uint16_t, uFpuOpcode)
9736{
9737 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87);
9738
9739 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
9740 unsigned const iReg1 = X86_FSW_TOP_GET(pFpuCtx->FSW);
9741 unsigned const iReg2 = (iReg1 + iStReg) & X86_FSW_TOP_SMASK;
9742 Assert(!(RT_BIT(iReg1) & pFpuCtx->FTW) || !(RT_BIT(iReg2) & pFpuCtx->FTW));
9743
9744 /** @todo Testcase: fxch underflow. Making assumptions that underflowed
9745 * registers are read as QNaN and then exchanged. This could be
9746 * wrong... */
9747 if (pFpuCtx->FCW & X86_FCW_IM)
9748 {
9749 if (RT_BIT(iReg1) & pFpuCtx->FTW)
9750 {
9751 if (RT_BIT(iReg2) & pFpuCtx->FTW)
9752 iemFpuStoreQNan(&pFpuCtx->aRegs[0].r80);
9753 else
9754 pFpuCtx->aRegs[0].r80 = pFpuCtx->aRegs[iStReg].r80;
9755 iemFpuStoreQNan(&pFpuCtx->aRegs[iStReg].r80);
9756 }
9757 else
9758 {
9759 pFpuCtx->aRegs[iStReg].r80 = pFpuCtx->aRegs[0].r80;
9760 iemFpuStoreQNan(&pFpuCtx->aRegs[0].r80);
9761 }
9762 pFpuCtx->FSW &= ~X86_FSW_C_MASK;
9763 pFpuCtx->FSW |= X86_FSW_C1 | X86_FSW_IE | X86_FSW_SF;
9764 }
9765 else
9766 {
9767 /* raise underflow exception, don't change anything. */
9768 pFpuCtx->FSW &= ~(X86_FSW_TOP_MASK | X86_FSW_XCPT_MASK);
9769 pFpuCtx->FSW |= X86_FSW_C1 | X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B;
9770 Log11(("fxch: %04x:%08RX64: Underflow exception (FSW=%#x)\n",
9771 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pFpuCtx->FSW));
9772 }
9773
9774 iemFpuUpdateOpcodeAndIpWorkerEx(pVCpu, pFpuCtx, uFpuOpcode);
9775 iemHlpUsedFpu(pVCpu);
9776 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9777}
9778
9779
9780/**
9781 * Implements 'FCOMI', 'FCOMIP', 'FUCOMI', and 'FUCOMIP'.
9782 *
9783 * @param iStReg The other stack register.
9784 * @param fUCmp true for FUCOMI[P], false for FCOMI[P].
9785 * @param uPopAndFpuOpcode Bits 15-0: The FPU opcode.
9786 * Bit 31: Whether we should pop the stack when
9787 * done or not.
9788 */
9789IEM_CIMPL_DEF_3(iemCImpl_fcomi_fucomi, uint8_t, iStReg, bool, fUCmp, uint32_t, uPopAndFpuOpcode)
9790{
9791 Assert(iStReg < 8);
9792 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_X87);
9793
9794 /*
9795 * Raise exceptions.
9796 */
9797 if (pVCpu->cpum.GstCtx.cr0 & (X86_CR0_EM | X86_CR0_TS))
9798 return iemRaiseDeviceNotAvailable(pVCpu);
9799
9800 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
9801 uint16_t u16Fsw = pFpuCtx->FSW;
9802 if (u16Fsw & X86_FSW_ES)
9803 return iemRaiseMathFault(pVCpu);
9804
9805 /*
9806 * Check if any of the register accesses causes #SF + #IA.
9807 */
9808 bool fPop = RT_BOOL(uPopAndFpuOpcode & RT_BIT_32(31));
9809 unsigned const iReg1 = X86_FSW_TOP_GET(u16Fsw);
9810 unsigned const iReg2 = (iReg1 + iStReg) & X86_FSW_TOP_SMASK;
9811 if ((pFpuCtx->FTW & (RT_BIT(iReg1) | RT_BIT(iReg2))) == (RT_BIT(iReg1) | RT_BIT(iReg2)))
9812 {
9813 uint32_t u32Eflags;
9814 if (!fUCmp)
9815 u32Eflags = iemAImpl_fcomi_r80_by_r80(pFpuCtx, &u16Fsw, &pFpuCtx->aRegs[0].r80, &pFpuCtx->aRegs[iStReg].r80);
9816 else
9817 u32Eflags = iemAImpl_fucomi_r80_by_r80(pFpuCtx, &u16Fsw, &pFpuCtx->aRegs[0].r80, &pFpuCtx->aRegs[iStReg].r80);
9818
9819 pFpuCtx->FSW &= ~X86_FSW_C1;
9820 pFpuCtx->FSW |= u16Fsw & ~X86_FSW_TOP_MASK;
9821 if ( !(u16Fsw & X86_FSW_IE)
9822 || (pFpuCtx->FCW & X86_FCW_IM) )
9823 {
9824 pVCpu->cpum.GstCtx.eflags.u &= ~(X86_EFL_OF | X86_EFL_SF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
9825 pVCpu->cpum.GstCtx.eflags.u |= u32Eflags & (X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
9826 }
9827 }
9828 else if (pFpuCtx->FCW & X86_FCW_IM)
9829 {
9830 /* Masked underflow. */
9831 pFpuCtx->FSW &= ~X86_FSW_C1;
9832 pFpuCtx->FSW |= X86_FSW_IE | X86_FSW_SF;
9833 pVCpu->cpum.GstCtx.eflags.u &= ~(X86_EFL_OF | X86_EFL_SF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
9834 pVCpu->cpum.GstCtx.eflags.u |= X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF;
9835 }
9836 else
9837 {
9838 /* Raise underflow - don't touch EFLAGS or TOP. */
9839 pFpuCtx->FSW &= ~X86_FSW_C1;
9840 pFpuCtx->FSW |= X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B;
9841 Log11(("fxch: %04x:%08RX64: Raising IE+SF exception (FSW=%#x)\n",
9842 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pFpuCtx->FSW));
9843 fPop = false;
9844 }
9845
9846 /*
9847 * Pop if necessary.
9848 */
9849 if (fPop)
9850 {
9851 pFpuCtx->FTW &= ~RT_BIT(iReg1);
9852 iemFpuStackIncTop(pVCpu);
9853 }
9854
9855 iemFpuUpdateOpcodeAndIpWorkerEx(pVCpu, pFpuCtx, (uint16_t)uPopAndFpuOpcode);
9856 iemHlpUsedFpu(pVCpu);
9857 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9858}
9859
9860
9861/**
9862 * Implements 'RDSEED'.
9863 *
9864 * @returns VINF_SUCCESS.
9865 * @param iReg The register.
9866 * @param enmEffOpSize The operand size.
9867 */
9868IEM_CIMPL_DEF_2(iemCImpl_rdseed, uint8_t, iReg, IEMMODE, enmEffOpSize)
9869{
9870#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9871 /* Nested-guest VMX intercept. */
9872 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
9873 || !IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_RDSEED_EXIT))
9874 { /* probable */ }
9875 else
9876 {
9877 Log(("rdseed: Guest intercept -> VM-exit\n"));
9878 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_RDSEED, VMXINSTRID_RDSEED, cbInstr);
9879 }
9880#endif
9881
9882 uint32_t *pEFlags = &pVCpu->cpum.GstCtx.eflags.uBoth;
9883 switch (enmEffOpSize)
9884 {
9885 case IEMMODE_16BIT:
9886 {
9887 PFNIEMAIMPLRDRANDSEEDU16 pfnImpl = IEM_SELECT_HOST_OR_FALLBACK(fRdSeed,
9888 &iemAImpl_rdseed_u16,
9889 &iemAImpl_rdseed_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(fRdSeed,
9897 &iemAImpl_rdseed_u32,
9898 &iemAImpl_rdseed_u32_fallback);
9899 uint32_t *pu32Dst = iemGRegRefU32(pVCpu, iReg);
9900 (pfnImpl)(pu32Dst, pEFlags);
9901 iemGRegStoreU32(pVCpu, iReg, *pu32Dst);
9902 break;
9903 }
9904 case IEMMODE_64BIT:
9905 {
9906 PFNIEMAIMPLRDRANDSEEDU64 pfnImpl = IEM_SELECT_HOST_OR_FALLBACK(fRdSeed,
9907 &iemAImpl_rdseed_u64,
9908 &iemAImpl_rdseed_u64_fallback);
9909 uint64_t *pu64Dst = iemGRegRefU64(pVCpu, iReg);
9910 (pfnImpl)(pu64Dst, pEFlags);
9911 break;
9912 }
9913 IEM_NOT_REACHED_DEFAULT_CASE_RET();
9914 }
9915 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9916}
9917
9918
9919/**
9920 * Implements 'RDRAND'.
9921 *
9922 * @returns VINF_SUCCESS.
9923 * @param iReg The register.
9924 * @param enmEffOpSize The operand size.
9925 */
9926IEM_CIMPL_DEF_2(iemCImpl_rdrand, uint8_t, iReg, IEMMODE, enmEffOpSize)
9927{
9928#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9929 /* Nested-guest VMX intercept. */
9930 if ( !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
9931 || !IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_RDRAND_EXIT))
9932 { /* probable */ }
9933 else
9934 {
9935 Log(("rdrand: Guest intercept -> VM-exit\n"));
9936 IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(pVCpu, VMX_EXIT_RDRAND, VMXINSTRID_RDRAND, cbInstr);
9937 }
9938#endif
9939
9940 uint32_t *pEFlags = &pVCpu->cpum.GstCtx.eflags.uBoth;
9941 switch (enmEffOpSize)
9942 {
9943 case IEMMODE_16BIT:
9944 {
9945 PFNIEMAIMPLRDRANDSEEDU16 pfnImpl = IEM_SELECT_HOST_OR_FALLBACK(fRdRand, &iemAImpl_rdrand_u16,
9946 &iemAImpl_rdrand_u16_fallback);
9947 uint16_t *pu16Dst = iemGRegRefU16(pVCpu, iReg);
9948 (pfnImpl)(pu16Dst, pEFlags);
9949 break;
9950 }
9951 case IEMMODE_32BIT:
9952 {
9953 PFNIEMAIMPLRDRANDSEEDU32 pfnImpl = IEM_SELECT_HOST_OR_FALLBACK(fRdRand, &iemAImpl_rdrand_u32,
9954 &iemAImpl_rdrand_u32_fallback);
9955 uint32_t *pu32Dst = iemGRegRefU32(pVCpu, iReg);
9956 (pfnImpl)(pu32Dst, pEFlags);
9957 iemGRegStoreU32(pVCpu, iReg, *pu32Dst);
9958 break;
9959 }
9960 case IEMMODE_64BIT:
9961 {
9962 PFNIEMAIMPLRDRANDSEEDU64 pfnImpl = IEM_SELECT_HOST_OR_FALLBACK(fRdRand, &iemAImpl_rdrand_u64,
9963 &iemAImpl_rdrand_u64_fallback);
9964 uint64_t *pu64Dst = iemGRegRefU64(pVCpu, iReg);
9965 (pfnImpl)(pu64Dst, pEFlags);
9966 break;
9967 }
9968 IEM_NOT_REACHED_DEFAULT_CASE_RET();
9969 }
9970 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
9971}
9972
9973
9974/**
9975 * Worker for 'VMASKMOVPS / VPMASKMOVD' 128-bit 32-bit-masked load.
9976 *
9977 * @param pVCpu The cross context virtual CPU structure of the calling thread.
9978 * @param cbInstr The current instruction length.
9979 * @param iXRegDst The destination XMM register index.
9980 * @param iXRegMsk The mask XMM register index.
9981 * @param iEffSeg The effective segment.
9982 * @param GCPtrEffSrc The source memory address.
9983 */
9984static VBOXSTRICTRC iemCImpl_maskmov_load_u128_32_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iXRegDst, uint8_t iXRegMsk, uint8_t iEffSeg, RTGCPTR GCPtrEffSrc)
9985{
9986 uint32_t fAccessed = 0;
9987
9988 PRTUINT128U puDst = (PRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegDst];
9989 PCRTUINT128U puMsk = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegMsk];
9990 PCRTUINT128U puSrc;
9991
9992 for (uint32_t i = 0; i < RT_ELEMENTS(puMsk->au32); i++)
9993 {
9994 fAccessed |= puMsk->au32[i];
9995 }
9996
9997 if (fAccessed & RT_BIT(31)) {
9998 /*
9999 * Access the source memory.
10000 */
10001 uint8_t bUnmapInfo;
10002 void *pvMemSrc;
10003 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemSrc, &bUnmapInfo, sizeof(*puSrc),
10004 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R, 0);
10005 if (rcStrict != VINF_SUCCESS)
10006 return rcStrict;
10007
10008 puSrc = (PCRTUINT128U)pvMemSrc;
10009
10010 for (uint32_t i = 0; i < RT_ELEMENTS(puSrc->au32); i++)
10011 {
10012 puDst->au32[i] = (puMsk->au32[i] & RT_BIT(31)) ? puSrc->au32[i] : 0;
10013 }
10014 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[0] = 0;
10015 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[1] = 0;
10016
10017 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10018 if (rcStrict != VINF_SUCCESS)
10019 return rcStrict;
10020 }
10021 else
10022 {
10023 puDst->au64[0] = 0;
10024 puDst->au64[1] = 0;
10025 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[0] = 0;
10026 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[1] = 0;
10027 }
10028
10029 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10030}
10031
10032
10033
10034/**
10035 * Worker for 'VMASKMOVPS / VPMASKMOVD' 256-bit 32-bit-masked load.
10036 *
10037 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10038 * @param cbInstr The current instruction length.
10039 * @param iYRegDst The destination YMM register index.
10040 * @param iYRegMsk The mask YMM register index.
10041 * @param iEffSeg The effective segment.
10042 * @param GCPtrEffSrc The source memory address.
10043 */
10044static VBOXSTRICTRC iemCImpl_maskmov_load_u256_32_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iYRegDst, uint8_t iYRegMsk, uint8_t iEffSeg, RTGCPTR GCPtrEffSrc)
10045{
10046 uint32_t fAccessed = 0;
10047
10048 PRTUINT128U puDstLo = (PRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegDst];
10049 PRTUINT128U puDstHi = (PRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegDst];
10050 PCRTUINT128U puMskLo = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegMsk];
10051 PCRTUINT128U puMskHi = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegMsk];
10052 PCRTUINT256U puSrc;
10053
10054 for (uint32_t i = 0; i < RT_ELEMENTS(puMskLo->au32); i++)
10055 {
10056 fAccessed |= puMskLo->au32[i] | puMskHi->au32[i];
10057 }
10058
10059 if (fAccessed & RT_BIT(31)) {
10060 /*
10061 * Access the source memory.
10062 */
10063 uint8_t bUnmapInfo;
10064 void *pvMemSrc;
10065 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemSrc, &bUnmapInfo, sizeof(*puSrc),
10066 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R, 0);
10067 if (rcStrict != VINF_SUCCESS)
10068 return rcStrict;
10069
10070 puSrc = (PCRTUINT256U)pvMemSrc;
10071
10072 uint8_t const iHalf = RT_ELEMENTS(puSrc->au32) / 2;
10073
10074 for (uint32_t i = 0; i < iHalf; i++)
10075 {
10076 puDstLo->au32[i] = (puMskLo->au32[i] & RT_BIT(31)) ? puSrc->au32[i] : 0;
10077 }
10078 for (uint32_t i = iHalf; i < RT_ELEMENTS(puSrc->au32); i++)
10079 {
10080 puDstHi->au32[i - iHalf] = (puMskHi->au32[i - iHalf] & RT_BIT(31)) ? puSrc->au32[i] : 0;
10081 }
10082
10083 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10084 if (rcStrict != VINF_SUCCESS)
10085 return rcStrict;
10086 }
10087 else
10088 {
10089 puDstLo->au64[0] = 0;
10090 puDstLo->au64[1] = 0;
10091 puDstHi->au64[0] = 0;
10092 puDstHi->au64[1] = 0;
10093 }
10094
10095 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10096}
10097
10098
10099/**
10100 * Worker for 'VMASKMOVPS / VPMASKMOVD' 128-bit 32-bit-masked store.
10101 *
10102 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10103 * @param cbInstr The current instruction length.
10104 * @param iEffSeg The effective segment.
10105 * @param GCPtrEffDst The destination memory address.
10106 * @param iXRegMsk The mask XMM register index.
10107 * @param iXRegSrc The source XMM register index.
10108 */
10109static VBOXSTRICTRC iemCImpl_maskmov_store_u128_32_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrEffDst, uint8_t iXRegMsk, uint8_t iXRegSrc)
10110{
10111 uint32_t fAccessed = 0;
10112
10113 PRTUINT128U puDst;
10114 PCRTUINT128U puMsk = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegMsk];
10115 PCRTUINT128U puSrc = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegSrc];
10116
10117 for (uint32_t i = 0; i < RT_ELEMENTS(puMsk->au32); i++)
10118 {
10119 fAccessed |= puMsk->au32[i];
10120 }
10121
10122 if (fAccessed & RT_BIT(31)) {
10123 /*
10124 * Access the destination memory.
10125 */
10126 uint8_t bUnmapInfo;
10127 void *pvMemDst;
10128 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemDst, &bUnmapInfo, sizeof(*puDst),
10129 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_RW, 0);
10130 if (rcStrict != VINF_SUCCESS)
10131 return rcStrict;
10132
10133 puDst = (PRTUINT128U)pvMemDst;
10134
10135 for (uint32_t i = 0; i < RT_ELEMENTS(puDst->au32); i++)
10136 {
10137 if (puMsk->au32[i] & RT_BIT(31))
10138 puDst->au32[i] = puSrc->au32[i];
10139 }
10140
10141 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10142 if (rcStrict != VINF_SUCCESS)
10143 return rcStrict;
10144 }
10145
10146 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10147}
10148
10149
10150
10151/**
10152 * Worker for 'VMASKMOVPS / VPMASKMOVD' 256-bit 32-bit-masked store.
10153 *
10154 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10155 * @param cbInstr The current instruction length.
10156 * @param iEffSeg The effective segment.
10157 * @param GCPtrEffDst The destination memory address.
10158 * @param iYRegMsk The mask YMM register index.
10159 * @param iYRegSrc The source YMM register index.
10160 */
10161static VBOXSTRICTRC iemCImpl_maskmov_store_u256_32_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrEffDst, uint8_t iYRegMsk, uint8_t iYRegSrc)
10162{
10163 uint32_t fAccessed = 0;
10164
10165 PRTUINT256U puDst;
10166 PCRTUINT128U puMskLo = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegMsk];
10167 PCRTUINT128U puMskHi = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegMsk];
10168 PCRTUINT128U puSrcLo = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegSrc];
10169 PCRTUINT128U puSrcHi = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegSrc];
10170
10171 for (uint32_t i = 0; i < RT_ELEMENTS(puMskLo->au32); i++)
10172 {
10173 fAccessed |= puMskLo->au32[i] | puMskHi->au32[i];
10174 }
10175
10176 if (fAccessed & RT_BIT(31)) {
10177 /*
10178 * Access the destination memory.
10179 */
10180 uint8_t bUnmapInfo;
10181 void *pvMemDst;
10182 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemDst, &bUnmapInfo, sizeof(*puDst),
10183 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_RW, 0);
10184 if (rcStrict != VINF_SUCCESS)
10185 return rcStrict;
10186
10187 puDst = (PRTUINT256U)pvMemDst;
10188
10189 uint8_t const iHalf = RT_ELEMENTS(puDst->au32) / 2;
10190
10191 for (uint32_t i = 0; i < iHalf; i++)
10192 {
10193 if (puMskLo->au32[i] & RT_BIT(31))
10194 puDst->au32[i] = puSrcLo->au32[i];
10195 }
10196 for (uint32_t i = iHalf; i < RT_ELEMENTS(puDst->au32); i++)
10197 {
10198 if (puMskHi->au32[i - iHalf] & RT_BIT(31))
10199 puDst->au32[i] = puSrcHi->au32[i - iHalf];
10200 }
10201
10202 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10203 if (rcStrict != VINF_SUCCESS)
10204 return rcStrict;
10205 }
10206
10207 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10208}
10209
10210
10211/**
10212 * Worker for 'VMASKMOVPD / VPMASKMOVQ' 128-bit 64-bit-masked load.
10213 *
10214 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10215 * @param cbInstr The current instruction length.
10216 * @param iXRegDst The destination XMM register index.
10217 * @param iXRegMsk The mask XMM register index.
10218 * @param iEffSeg The effective segment.
10219 * @param GCPtrEffSrc The source memory address.
10220 */
10221static VBOXSTRICTRC iemCImpl_maskmov_load_u128_64_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iXRegDst, uint8_t iXRegMsk, uint8_t iEffSeg, RTGCPTR GCPtrEffSrc)
10222{
10223 uint64_t fAccessed = 0;
10224
10225 PRTUINT128U puDst = (PRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegDst];
10226 PCRTUINT128U puMsk = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegMsk];
10227 PCRTUINT128U puSrc;
10228
10229 for (uint32_t i = 0; i < RT_ELEMENTS(puMsk->au64); i++)
10230 {
10231 fAccessed |= puMsk->au64[i];
10232 }
10233
10234 if (fAccessed & RT_BIT_64(63)) {
10235 /*
10236 * Access the source memory.
10237 */
10238 uint8_t bUnmapInfo;
10239 void *pvMemSrc;
10240 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemSrc, &bUnmapInfo, sizeof(*puSrc),
10241 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R, 0);
10242 if (rcStrict != VINF_SUCCESS)
10243 return rcStrict;
10244
10245 puSrc = (PCRTUINT128U)pvMemSrc;
10246
10247 for (uint32_t i = 0; i < RT_ELEMENTS(puSrc->au64); i++)
10248 {
10249 puDst->au64[i] = (puMsk->au64[i] & RT_BIT_64(63)) ? puSrc->au64[i] : 0;
10250 }
10251 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[0] = 0;
10252 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[1] = 0;
10253
10254 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10255 if (rcStrict != VINF_SUCCESS)
10256 return rcStrict;
10257 }
10258 else
10259 {
10260 puDst->au64[0] = 0;
10261 puDst->au64[1] = 0;
10262 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[0] = 0;
10263 pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iXRegDst].au64[1] = 0;
10264 }
10265
10266 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10267}
10268
10269
10270
10271/**
10272 * Worker for 'VMASKMOVPD / VPMASKMOVQ' 256-bit 64-bit-masked load.
10273 *
10274 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10275 * @param cbInstr The current instruction length.
10276 * @param iYRegDst The destination YMM register index.
10277 * @param iYRegMsk The mask YMM register index.
10278 * @param iEffSeg The effective segment.
10279 * @param GCPtrEffSrc The source memory address.
10280 */
10281static VBOXSTRICTRC iemCImpl_maskmov_load_u256_64_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iYRegDst, uint8_t iYRegMsk, uint8_t iEffSeg, RTGCPTR GCPtrEffSrc)
10282{
10283 uint64_t fAccessed = 0;
10284
10285 PRTUINT128U puDstLo = (PRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegDst];
10286 PRTUINT128U puDstHi = (PRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegDst];
10287 PCRTUINT128U puMskLo = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegMsk];
10288 PCRTUINT128U puMskHi = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegMsk];
10289 PCRTUINT256U puSrc;
10290
10291 for (uint32_t i = 0; i < RT_ELEMENTS(puMskLo->au64); i++)
10292 {
10293 fAccessed |= puMskLo->au64[i] | puMskHi->au64[i];
10294 }
10295
10296 if (fAccessed & RT_BIT_64(63)) {
10297 /*
10298 * Access the source memory.
10299 */
10300 uint8_t bUnmapInfo;
10301 void *pvMemSrc;
10302 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemSrc, &bUnmapInfo, sizeof(*puSrc),
10303 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R, 0);
10304 if (rcStrict != VINF_SUCCESS)
10305 return rcStrict;
10306
10307 puSrc = (PCRTUINT256U)pvMemSrc;
10308
10309 uint8_t const iHalf = RT_ELEMENTS(puSrc->au64) / 2;
10310
10311 for (uint32_t i = 0; i < iHalf; i++)
10312 {
10313 puDstLo->au64[i] = (puMskLo->au64[i] & RT_BIT_64(63)) ? puSrc->au64[i] : 0;
10314 }
10315 for (uint32_t i = iHalf; i < RT_ELEMENTS(puSrc->au64); i++)
10316 {
10317 puDstHi->au64[i - iHalf] = (puMskHi->au64[i - iHalf] & RT_BIT_64(63)) ? puSrc->au64[i] : 0;
10318 }
10319
10320 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10321 if (rcStrict != VINF_SUCCESS)
10322 return rcStrict;
10323 }
10324 else
10325 {
10326 puDstLo->au64[0] = 0;
10327 puDstLo->au64[1] = 0;
10328 puDstHi->au64[0] = 0;
10329 puDstHi->au64[1] = 0;
10330 }
10331
10332 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10333}
10334
10335
10336/**
10337 * Worker for 'VMASKMOVPD / VPMASKMOVQ' 128-bit 64-bit-masked store.
10338 *
10339 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10340 * @param cbInstr The current instruction length.
10341 * @param iEffSeg The effective segment.
10342 * @param GCPtrEffDst The destination memory address.
10343 * @param iXRegMsk The mask XMM register index.
10344 * @param iXRegSrc The source XMM register index.
10345 */
10346static VBOXSTRICTRC iemCImpl_maskmov_store_u128_64_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrEffDst, uint8_t iXRegMsk, uint8_t iXRegSrc)
10347{
10348 uint64_t fAccessed = 0;
10349
10350 PRTUINT128U puDst;
10351 PCRTUINT128U puMsk = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegMsk];
10352 PCRTUINT128U puSrc = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iXRegSrc];
10353
10354 for (uint32_t i = 0; i < RT_ELEMENTS(puMsk->au64); i++)
10355 {
10356 fAccessed |= puMsk->au64[i];
10357 }
10358
10359 if (fAccessed & RT_BIT_64(63)) {
10360 /*
10361 * Access the destination memory.
10362 */
10363 uint8_t bUnmapInfo;
10364 void *pvMemDst;
10365 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemDst, &bUnmapInfo, sizeof(*puDst),
10366 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_RW, 0);
10367 if (rcStrict != VINF_SUCCESS)
10368 return rcStrict;
10369
10370 puDst = (PRTUINT128U)pvMemDst;
10371
10372 for (uint32_t i = 0; i < RT_ELEMENTS(puDst->au64); i++)
10373 {
10374 if (puMsk->au64[i] & RT_BIT_64(63))
10375 puDst->au64[i] = puSrc->au64[i];
10376 }
10377
10378 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10379 if (rcStrict != VINF_SUCCESS)
10380 return rcStrict;
10381 }
10382
10383 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10384}
10385
10386
10387
10388/**
10389 * Worker for 'VMASKMOVPD / VPMASKMOVQ' 256-bit 64-bit-masked store.
10390 *
10391 * @param pVCpu The cross context virtual CPU structure of the calling thread.
10392 * @param cbInstr The current instruction length.
10393 * @param iEffSeg The effective segment.
10394 * @param GCPtrEffDst The destination memory address.
10395 * @param iYRegMsk The mask YMM register index.
10396 * @param iYRegSrc The source YMM register index.
10397 */
10398static VBOXSTRICTRC iemCImpl_maskmov_store_u256_64_worker(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrEffDst, uint8_t iYRegMsk, uint8_t iYRegSrc)
10399{
10400 uint64_t fAccessed = 0;
10401
10402 PRTUINT256U puDst;
10403 PCRTUINT128U puMskLo = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegMsk];
10404 PCRTUINT128U puMskHi = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegMsk];
10405 PCRTUINT128U puSrcLo = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.x87.aXMM[iYRegSrc];
10406 PCRTUINT128U puSrcHi = (PCRTUINT128U)&pVCpu->cpum.GstCtx.XState.u.YmmHi.aYmmHi[iYRegSrc];
10407
10408 for (uint32_t i = 0; i < RT_ELEMENTS(puMskLo->au64); i++)
10409 {
10410 fAccessed |= puMskLo->au64[i] | puMskHi->au64[i];
10411 }
10412
10413 if (fAccessed & RT_BIT_64(63)) {
10414 /*
10415 * Access the destination memory.
10416 */
10417 uint8_t bUnmapInfo;
10418 void *pvMemDst;
10419 VBOXSTRICTRC rcStrict = iemMemMap(pVCpu, &pvMemDst, &bUnmapInfo, sizeof(*puDst),
10420 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_RW, 0);
10421 if (rcStrict != VINF_SUCCESS)
10422 return rcStrict;
10423
10424 puDst = (PRTUINT256U)pvMemDst;
10425
10426 uint8_t const iHalf = RT_ELEMENTS(puDst->au64) / 2;
10427
10428 for (uint32_t i = 0; i < iHalf; i++)
10429 {
10430 if (puMskLo->au64[i] & RT_BIT_64(63))
10431 puDst->au64[i] = puSrcLo->au64[i];
10432 }
10433 for (uint32_t i = iHalf; i < RT_ELEMENTS(puDst->au64); i++)
10434 {
10435 if (puMskHi->au64[i - iHalf] & RT_BIT_64(63))
10436 puDst->au64[i] = puSrcHi->au64[i - iHalf];
10437 }
10438
10439 rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
10440 if (rcStrict != VINF_SUCCESS)
10441 return rcStrict;
10442 }
10443
10444 return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
10445}
10446
10447
10448/**
10449 * Implements 'VMASKMOVPS' 128-bit 32-bit-masked load.
10450 *
10451 * @param iXRegDst The destination XMM register index.
10452 * @param iXRegMsk The mask XMM register index.
10453 * @param iEffSeg The effective segment.
10454 * @param GCPtrEffSrc The source memory address.
10455 */
10456IEM_CIMPL_DEF_4(iemCImpl_vmaskmovps_load_u128, uint8_t, iXRegDst, uint8_t, iXRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10457{
10458 return iemCImpl_maskmov_load_u128_32_worker(pVCpu, cbInstr, iXRegDst, iXRegMsk, iEffSeg, GCPtrEffSrc);
10459}
10460
10461
10462/**
10463 * Implements 'VMASKMOVPS' 256-bit 32-bit-masked load.
10464 *
10465 * @param iYRegDst The destination YMM register index.
10466 * @param iYRegMsk The mask YMM register index.
10467 * @param iEffSeg The effective segment.
10468 * @param GCPtrEffSrc The source memory address.
10469 */
10470IEM_CIMPL_DEF_4(iemCImpl_vmaskmovps_load_u256, uint8_t, iYRegDst, uint8_t, iYRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10471{
10472 return iemCImpl_maskmov_load_u256_32_worker(pVCpu, cbInstr, iYRegDst, iYRegMsk, iEffSeg, GCPtrEffSrc);
10473}
10474
10475
10476/**
10477 * Implements 'VMASKMOVPS' 128-bit 32-bit-masked store.
10478 *
10479 * @param iEffSeg The effective segment.
10480 * @param GCPtrEffDst The destination memory address.
10481 * @param iXRegMsk The mask XMM register index.
10482 * @param iXRegSrc The source XMM register index.
10483 */
10484IEM_CIMPL_DEF_4(iemCImpl_vmaskmovps_store_u128, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iXRegMsk, uint8_t, iXRegSrc)
10485{
10486 return iemCImpl_maskmov_store_u128_32_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iXRegMsk, iXRegSrc);
10487}
10488
10489
10490/**
10491 * Implements 'VMASKMOVPS' 256-bit 32-bit-masked store.
10492 *
10493 * @param iEffSeg The effective segment.
10494 * @param GCPtrEffDst The destination memory address.
10495 * @param iYRegMsk The mask YMM register index.
10496 * @param iYRegSrc The source YMM register index.
10497 */
10498IEM_CIMPL_DEF_4(iemCImpl_vmaskmovps_store_u256, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iYRegMsk, uint8_t, iYRegSrc)
10499{
10500 return iemCImpl_maskmov_store_u256_32_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iYRegMsk, iYRegSrc);
10501}
10502
10503
10504/**
10505 * Implements 'VPMASKMOVD' 128-bit 32-bit-masked load.
10506 *
10507 * @param iXRegDst The destination XMM register index.
10508 * @param iXRegMsk The mask XMM register index.
10509 * @param iEffSeg The effective segment.
10510 * @param GCPtrEffSrc The source memory address.
10511 */
10512IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovd_load_u128, uint8_t, iXRegDst, uint8_t, iXRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10513{
10514 return iemCImpl_maskmov_load_u128_32_worker(pVCpu, cbInstr, iXRegDst, iXRegMsk, iEffSeg, GCPtrEffSrc);
10515}
10516
10517
10518/**
10519 * Implements 'VPMASKMOVD' 256-bit 32-bit-masked load.
10520 *
10521 * @param iYRegDst The destination YMM register index.
10522 * @param iYRegMsk The mask YMM register index.
10523 * @param iEffSeg The effective segment.
10524 * @param GCPtrEffSrc The source memory address.
10525 */
10526IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovd_load_u256, uint8_t, iYRegDst, uint8_t, iYRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10527{
10528 return iemCImpl_maskmov_load_u256_32_worker(pVCpu, cbInstr, iYRegDst, iYRegMsk, iEffSeg, GCPtrEffSrc);
10529}
10530
10531
10532/**
10533 * Implements 'VPMASKMOVD' 128-bit 32-bit-masked store.
10534 *
10535 * @param iEffSeg The effective segment.
10536 * @param GCPtrEffDst The destination memory address.
10537 * @param iXRegMsk The mask XMM register index.
10538 * @param iXRegSrc The source XMM register index.
10539 */
10540IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovd_store_u128, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iXRegMsk, uint8_t, iXRegSrc)
10541{
10542 return iemCImpl_maskmov_store_u128_32_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iXRegMsk, iXRegSrc);
10543}
10544
10545
10546/**
10547 * Implements 'VPMASKMOVD' 256-bit 32-bit-masked store.
10548 *
10549 * @param iEffSeg The effective segment.
10550 * @param GCPtrEffDst The destination memory address.
10551 * @param iYRegMsk The mask YMM register index.
10552 * @param iYRegSrc The source YMM register index.
10553 */
10554IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovd_store_u256, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iYRegMsk, uint8_t, iYRegSrc)
10555{
10556 return iemCImpl_maskmov_store_u256_32_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iYRegMsk, iYRegSrc);
10557}
10558
10559
10560/**
10561 * Implements 'VMASKMOVPD' 128-bit 64-bit-masked load.
10562 *
10563 * @param iXRegDst The destination XMM register index.
10564 * @param iXRegMsk The mask XMM register index.
10565 * @param iEffSeg The effective segment.
10566 * @param GCPtrEffSrc The source memory address.
10567 */
10568IEM_CIMPL_DEF_4(iemCImpl_vmaskmovpd_load_u128, uint8_t, iXRegDst, uint8_t, iXRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10569{
10570 return iemCImpl_maskmov_load_u128_64_worker(pVCpu, cbInstr, iXRegDst, iXRegMsk, iEffSeg, GCPtrEffSrc);
10571}
10572
10573
10574/**
10575 * Implements 'VMASKMOVPD' 256-bit 64-bit-masked load.
10576 *
10577 * @param iYRegDst The destination YMM register index.
10578 * @param iYRegMsk The mask YMM register index.
10579 * @param iEffSeg The effective segment.
10580 * @param GCPtrEffSrc The source memory address.
10581 */
10582IEM_CIMPL_DEF_4(iemCImpl_vmaskmovpd_load_u256, uint8_t, iYRegDst, uint8_t, iYRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10583{
10584 return iemCImpl_maskmov_load_u256_64_worker(pVCpu, cbInstr, iYRegDst, iYRegMsk, iEffSeg, GCPtrEffSrc);
10585}
10586
10587
10588/**
10589 * Implements 'VMASKMOVPD' 128-bit 64-bit-masked store.
10590 *
10591 * @param iEffSeg The effective segment.
10592 * @param GCPtrEffDst The destination memory address.
10593 * @param iXRegMsk The mask XMM register index.
10594 * @param iXRegSrc The source XMM register index.
10595 */
10596IEM_CIMPL_DEF_4(iemCImpl_vmaskmovpd_store_u128, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iXRegMsk, uint8_t, iXRegSrc)
10597{
10598 return iemCImpl_maskmov_store_u128_64_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iXRegMsk, iXRegSrc);
10599}
10600
10601
10602/**
10603 * Implements 'VMASKMOVPD' 256-bit 64-bit-masked store.
10604 *
10605 * @param iEffSeg The effective segment.
10606 * @param GCPtrEffDst The destination memory address.
10607 * @param iYRegMsk The mask YMM register index.
10608 * @param iYRegSrc The source YMM register index.
10609 */
10610IEM_CIMPL_DEF_4(iemCImpl_vmaskmovpd_store_u256, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iYRegMsk, uint8_t, iYRegSrc)
10611{
10612 return iemCImpl_maskmov_store_u256_64_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iYRegMsk, iYRegSrc);
10613}
10614
10615
10616/**
10617 * Implements 'VPMASKMOVQ' 128-bit 64-bit-masked load.
10618 *
10619 * @param iXRegDst The destination XMM register index.
10620 * @param iXRegMsk The mask XMM register index.
10621 * @param iEffSeg The effective segment.
10622 * @param GCPtrEffSrc The source memory address.
10623 */
10624IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovq_load_u128, uint8_t, iXRegDst, uint8_t, iXRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10625{
10626 return iemCImpl_maskmov_load_u128_64_worker(pVCpu, cbInstr, iXRegDst, iXRegMsk, iEffSeg, GCPtrEffSrc);
10627}
10628
10629
10630/**
10631 * Implements 'VPMASKMOVQ' 256-bit 64-bit-masked load.
10632 *
10633 * @param iYRegDst The destination YMM register index.
10634 * @param iYRegMsk The mask YMM register index.
10635 * @param iEffSeg The effective segment.
10636 * @param GCPtrEffSrc The source memory address.
10637 */
10638IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovq_load_u256, uint8_t, iYRegDst, uint8_t, iYRegMsk, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
10639{
10640 return iemCImpl_maskmov_load_u256_64_worker(pVCpu, cbInstr, iYRegDst, iYRegMsk, iEffSeg, GCPtrEffSrc);
10641}
10642
10643
10644/**
10645 * Implements 'VPMASKMOVQ' 128-bit 64-bit-masked store.
10646 *
10647 * @param iEffSeg The effective segment.
10648 * @param GCPtrEffDst The destination memory address.
10649 * @param iXRegMsk The mask XMM register index.
10650 * @param iXRegSrc The source XMM register index.
10651 */
10652IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovq_store_u128, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iXRegMsk, uint8_t, iXRegSrc)
10653{
10654 return iemCImpl_maskmov_store_u128_64_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iXRegMsk, iXRegSrc);
10655}
10656
10657
10658/**
10659 * Implements 'VPMASKMOVQ' 256-bit 64-bit-masked store.
10660 *
10661 * @param iEffSeg The effective segment.
10662 * @param GCPtrEffDst The destination memory address.
10663 * @param iYRegMsk The mask YMM register index.
10664 * @param iYRegSrc The source YMM register index.
10665 */
10666IEM_CIMPL_DEF_4(iemCImpl_vpmaskmovq_store_u256, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, uint8_t, iYRegMsk, uint8_t, iYRegSrc)
10667{
10668 return iemCImpl_maskmov_store_u256_64_worker(pVCpu, cbInstr, iEffSeg, GCPtrEffDst, iYRegMsk, iYRegSrc);
10669}
10670
10671
10672/** @} */
10673
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