VirtualBox

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

Last change on this file since 50653 was 49671, checked in by vboxsync, 11 years ago

IEM: Fixed several instances of iEffSeg being accessed before the decoding was over, causing iPXE to guru on us. Implemented DAS and DAA to verify the previous fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 198.8 KB
Line 
1/* $Id: IEMAllCImpl.cpp.h 49671 2013-11-26 18:09:07Z vboxsync $ */
2/** @file
3 * IEM - Instruction Implementation in C/C++ (code include).
4 */
5
6/*
7 * Copyright (C) 2011-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/** @name Misc Helpers
20 * @{
21 */
22
23
24/**
25 * Worker function for iemHlpCheckPortIOPermission, don't call directly.
26 *
27 * @returns Strict VBox status code.
28 *
29 * @param pIemCpu The IEM per CPU data.
30 * @param pCtx The register context.
31 * @param u16Port The port number.
32 * @param cbOperand The operand size.
33 */
34static VBOXSTRICTRC iemHlpCheckPortIOPermissionBitmap(PIEMCPU pIemCpu, PCCPUMCTX pCtx, uint16_t u16Port, uint8_t cbOperand)
35{
36 /* The TSS bits we're interested in are the same on 386 and AMD64. */
37 AssertCompile(AMD64_SEL_TYPE_SYS_TSS_BUSY == X86_SEL_TYPE_SYS_386_TSS_BUSY);
38 AssertCompile(AMD64_SEL_TYPE_SYS_TSS_AVAIL == X86_SEL_TYPE_SYS_386_TSS_AVAIL);
39 AssertCompileMembersAtSameOffset(X86TSS32, offIoBitmap, X86TSS64, offIoBitmap);
40 AssertCompile(sizeof(X86TSS32) == sizeof(X86TSS64));
41
42 /*
43 * Check the TSS type, 16-bit TSSes doesn't have any I/O permission bitmap.
44 */
45 Assert(!pCtx->tr.Attr.n.u1DescType);
46 if (RT_UNLIKELY( pCtx->tr.Attr.n.u4Type != AMD64_SEL_TYPE_SYS_TSS_BUSY
47 && pCtx->tr.Attr.n.u4Type != AMD64_SEL_TYPE_SYS_TSS_AVAIL))
48 {
49 Log(("iemHlpCheckPortIOPermissionBitmap: Port=%#x cb=%d - TSS type %#x (attr=%#x) has no I/O bitmap -> #GP(0)\n",
50 u16Port, cbOperand, pCtx->tr.Attr.n.u4Type, pCtx->tr.Attr.u));
51 return iemRaiseGeneralProtectionFault0(pIemCpu);
52 }
53
54 /*
55 * Read the bitmap offset (may #PF).
56 */
57 uint16_t offBitmap;
58 VBOXSTRICTRC rcStrict = iemMemFetchSysU16(pIemCpu, &offBitmap, UINT8_MAX,
59 pCtx->tr.u64Base + RT_OFFSETOF(X86TSS64, offIoBitmap));
60 if (rcStrict != VINF_SUCCESS)
61 {
62 Log(("iemHlpCheckPortIOPermissionBitmap: Error reading offIoBitmap (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
63 return rcStrict;
64 }
65
66 /*
67 * The bit range from u16Port to (u16Port + cbOperand - 1), however intel
68 * describes the CPU actually reading two bytes regardless of whether the
69 * bit range crosses a byte boundrary. Thus the + 1 in the test below.
70 */
71 uint32_t offFirstBit = (uint32_t)u16Port / 8 + offBitmap;
72 /** @todo check if real CPUs ensures that offBitmap has a minimum value of
73 * for instance sizeof(X86TSS32). */
74 if (offFirstBit + 1 > pCtx->tr.u32Limit) /* the limit is inclusive */
75 {
76 Log(("iemHlpCheckPortIOPermissionBitmap: offFirstBit=%#x + 1 is beyond u32Limit=%#x -> #GP(0)\n",
77 offFirstBit, pCtx->tr.u32Limit));
78 return iemRaiseGeneralProtectionFault0(pIemCpu);
79 }
80
81 /*
82 * Read the necessary bits.
83 */
84 /** @todo Test the assertion in the intel manual that the CPU reads two
85 * bytes. The question is how this works wrt to #PF and #GP on the
86 * 2nd byte when it's not required. */
87 uint16_t bmBytes = UINT16_MAX;
88 rcStrict = iemMemFetchSysU16(pIemCpu, &bmBytes, UINT8_MAX, pCtx->tr.u64Base + offFirstBit);
89 if (rcStrict != VINF_SUCCESS)
90 {
91 Log(("iemHlpCheckPortIOPermissionBitmap: Error reading I/O bitmap @%#x (%Rrc)\n", offFirstBit, VBOXSTRICTRC_VAL(rcStrict)));
92 return rcStrict;
93 }
94
95 /*
96 * Perform the check.
97 */
98 uint16_t fPortMask = (1 << cbOperand) - 1;
99 bmBytes >>= (u16Port & 7);
100 if (bmBytes & fPortMask)
101 {
102 Log(("iemHlpCheckPortIOPermissionBitmap: u16Port=%#x LB %u - access denied (bm=%#x mask=%#x) -> #GP(0)\n",
103 u16Port, cbOperand, bmBytes, fPortMask));
104 return iemRaiseGeneralProtectionFault0(pIemCpu);
105 }
106
107 return VINF_SUCCESS;
108}
109
110
111/**
112 * Checks if we are allowed to access the given I/O port, raising the
113 * appropriate exceptions if we aren't (or if the I/O bitmap is not
114 * accessible).
115 *
116 * @returns Strict VBox status code.
117 *
118 * @param pIemCpu The IEM per CPU data.
119 * @param pCtx The register context.
120 * @param u16Port The port number.
121 * @param cbOperand The operand size.
122 */
123DECLINLINE(VBOXSTRICTRC) iemHlpCheckPortIOPermission(PIEMCPU pIemCpu, PCCPUMCTX pCtx, uint16_t u16Port, uint8_t cbOperand)
124{
125 X86EFLAGS Efl;
126 Efl.u = IEMMISC_GET_EFL(pIemCpu, pCtx);
127 if ( (pCtx->cr0 & X86_CR0_PE)
128 && ( pIemCpu->uCpl > Efl.Bits.u2IOPL
129 || Efl.Bits.u1VM) )
130 return iemHlpCheckPortIOPermissionBitmap(pIemCpu, pCtx, u16Port, cbOperand);
131 return VINF_SUCCESS;
132}
133
134
135#if 0
136/**
137 * Calculates the parity bit.
138 *
139 * @returns true if the bit is set, false if not.
140 * @param u8Result The least significant byte of the result.
141 */
142static bool iemHlpCalcParityFlag(uint8_t u8Result)
143{
144 /*
145 * Parity is set if the number of bits in the least significant byte of
146 * the result is even.
147 */
148 uint8_t cBits;
149 cBits = u8Result & 1; /* 0 */
150 u8Result >>= 1;
151 cBits += u8Result & 1;
152 u8Result >>= 1;
153 cBits += u8Result & 1;
154 u8Result >>= 1;
155 cBits += u8Result & 1;
156 u8Result >>= 1;
157 cBits += u8Result & 1; /* 4 */
158 u8Result >>= 1;
159 cBits += u8Result & 1;
160 u8Result >>= 1;
161 cBits += u8Result & 1;
162 u8Result >>= 1;
163 cBits += u8Result & 1;
164 return !(cBits & 1);
165}
166#endif /* not used */
167
168
169/**
170 * Updates the specified flags according to a 8-bit result.
171 *
172 * @param pIemCpu The IEM state of the calling EMT.
173 * @param u8Result The result to set the flags according to.
174 * @param fToUpdate The flags to update.
175 * @param fUndefined The flags that are specified as undefined.
176 */
177static void iemHlpUpdateArithEFlagsU8(PIEMCPU pIemCpu, uint8_t u8Result, uint32_t fToUpdate, uint32_t fUndefined)
178{
179 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
180
181 uint32_t fEFlags = pCtx->eflags.u;
182 iemAImpl_test_u8(&u8Result, u8Result, &fEFlags);
183 pCtx->eflags.u &= ~(fToUpdate | fUndefined);
184 pCtx->eflags.u |= (fToUpdate | fUndefined) & fEFlags;
185#ifdef IEM_VERIFICATION_MODE_FULL
186 pIemCpu->fUndefinedEFlags |= fUndefined;
187#endif
188}
189
190
191/**
192 * Loads a NULL data selector into a selector register, both the hidden and
193 * visible parts, in protected mode.
194 *
195 * @param pIemCpu The IEM state of the calling EMT.
196 * @param pSReg Pointer to the segment register.
197 * @param uRpl The RPL.
198 */
199static void iemHlpLoadNullDataSelectorProt(PIEMCPU pIemCpu, PCPUMSELREG pSReg, RTSEL uRpl)
200{
201 /** @todo Testcase: write a testcase checking what happends when loading a NULL
202 * data selector in protected mode. */
203 pSReg->Sel = uRpl;
204 pSReg->ValidSel = uRpl;
205 pSReg->fFlags = CPUMSELREG_FLAGS_VALID;
206 if (IEM_IS_GUEST_CPU_INTEL(pIemCpu) && !IEM_FULL_VERIFICATION_REM_ENABLED(pIemCpu))
207 {
208 /* VT-x (Intel 3960x) observed doing something like this. */
209 pSReg->Attr.u = X86DESCATTR_UNUSABLE | X86DESCATTR_G | X86DESCATTR_D | (pIemCpu->uCpl << X86DESCATTR_DPL_SHIFT);
210 pSReg->u32Limit = UINT32_MAX;
211 pSReg->u64Base = 0;
212 }
213 else
214 {
215 pSReg->Attr.u = X86DESCATTR_UNUSABLE;
216 pSReg->u32Limit = 0;
217 pSReg->u64Base = 0;
218 }
219}
220
221
222/**
223 * Helper used by iret.
224 *
225 * @param uCpl The new CPL.
226 * @param pSReg Pointer to the segment register.
227 */
228static void iemHlpAdjustSelectorForNewCpl(PIEMCPU pIemCpu, uint8_t uCpl, PCPUMSELREG pSReg)
229{
230#ifdef VBOX_WITH_RAW_MODE_NOT_R0
231 if (!CPUMSELREG_ARE_HIDDEN_PARTS_VALID(IEMCPU_TO_VMCPU(pIemCpu), pSReg))
232 CPUMGuestLazyLoadHiddenSelectorReg(IEMCPU_TO_VMCPU(pIemCpu), pSReg);
233#else
234 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(IEMCPU_TO_VMCPU(pIemCpu), pSReg));
235#endif
236
237 if ( uCpl > pSReg->Attr.n.u2Dpl
238 && pSReg->Attr.n.u1DescType /* code or data, not system */
239 && (pSReg->Attr.n.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
240 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF)) /* not conforming code */
241 iemHlpLoadNullDataSelectorProt(pIemCpu, pSReg, 0);
242}
243
244
245/**
246 * Indicates that we have modified the FPU state.
247 *
248 * @param pIemCpu The IEM state of the calling EMT.
249 */
250DECLINLINE(void) iemHlpUsedFpu(PIEMCPU pIemCpu)
251{
252 CPUMSetChangedFlags(IEMCPU_TO_VMCPU(pIemCpu), CPUM_CHANGED_FPU_REM);
253}
254
255/** @} */
256
257/** @name C Implementations
258 * @{
259 */
260
261/**
262 * Implements a 16-bit popa.
263 */
264IEM_CIMPL_DEF_0(iemCImpl_popa_16)
265{
266 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
267 RTGCPTR GCPtrStart = iemRegGetEffRsp(pIemCpu, pCtx);
268 RTGCPTR GCPtrLast = GCPtrStart + 15;
269 VBOXSTRICTRC rcStrict;
270
271 /*
272 * The docs are a bit hard to comprehend here, but it looks like we wrap
273 * around in real mode as long as none of the individual "popa" crosses the
274 * end of the stack segment. In protected mode we check the whole access
275 * in one go. For efficiency, only do the word-by-word thing if we're in
276 * danger of wrapping around.
277 */
278 /** @todo do popa boundary / wrap-around checks. */
279 if (RT_UNLIKELY( IEM_IS_REAL_OR_V86_MODE(pIemCpu)
280 && (pCtx->cs.u32Limit < GCPtrLast)) ) /* ASSUMES 64-bit RTGCPTR */
281 {
282 /* word-by-word */
283 RTUINT64U TmpRsp;
284 TmpRsp.u = pCtx->rsp;
285 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->di, &TmpRsp);
286 if (rcStrict == VINF_SUCCESS)
287 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->si, &TmpRsp);
288 if (rcStrict == VINF_SUCCESS)
289 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->bp, &TmpRsp);
290 if (rcStrict == VINF_SUCCESS)
291 {
292 iemRegAddToRspEx(pIemCpu, pCtx, &TmpRsp, 2); /* sp */
293 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->bx, &TmpRsp);
294 }
295 if (rcStrict == VINF_SUCCESS)
296 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->dx, &TmpRsp);
297 if (rcStrict == VINF_SUCCESS)
298 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->cx, &TmpRsp);
299 if (rcStrict == VINF_SUCCESS)
300 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->ax, &TmpRsp);
301 if (rcStrict == VINF_SUCCESS)
302 {
303 pCtx->rsp = TmpRsp.u;
304 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
305 }
306 }
307 else
308 {
309 uint16_t const *pa16Mem = NULL;
310 rcStrict = iemMemMap(pIemCpu, (void **)&pa16Mem, 16, X86_SREG_SS, GCPtrStart, IEM_ACCESS_STACK_R);
311 if (rcStrict == VINF_SUCCESS)
312 {
313 pCtx->di = pa16Mem[7 - X86_GREG_xDI];
314 pCtx->si = pa16Mem[7 - X86_GREG_xSI];
315 pCtx->bp = pa16Mem[7 - X86_GREG_xBP];
316 /* skip sp */
317 pCtx->bx = pa16Mem[7 - X86_GREG_xBX];
318 pCtx->dx = pa16Mem[7 - X86_GREG_xDX];
319 pCtx->cx = pa16Mem[7 - X86_GREG_xCX];
320 pCtx->ax = pa16Mem[7 - X86_GREG_xAX];
321 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)pa16Mem, IEM_ACCESS_STACK_R);
322 if (rcStrict == VINF_SUCCESS)
323 {
324 iemRegAddToRsp(pIemCpu, pCtx, 16);
325 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
326 }
327 }
328 }
329 return rcStrict;
330}
331
332
333/**
334 * Implements a 32-bit popa.
335 */
336IEM_CIMPL_DEF_0(iemCImpl_popa_32)
337{
338 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
339 RTGCPTR GCPtrStart = iemRegGetEffRsp(pIemCpu, pCtx);
340 RTGCPTR GCPtrLast = GCPtrStart + 31;
341 VBOXSTRICTRC rcStrict;
342
343 /*
344 * The docs are a bit hard to comprehend here, but it looks like we wrap
345 * around in real mode as long as none of the individual "popa" crosses the
346 * end of the stack segment. In protected mode we check the whole access
347 * in one go. For efficiency, only do the word-by-word thing if we're in
348 * danger of wrapping around.
349 */
350 /** @todo do popa boundary / wrap-around checks. */
351 if (RT_UNLIKELY( IEM_IS_REAL_OR_V86_MODE(pIemCpu)
352 && (pCtx->cs.u32Limit < GCPtrLast)) ) /* ASSUMES 64-bit RTGCPTR */
353 {
354 /* word-by-word */
355 RTUINT64U TmpRsp;
356 TmpRsp.u = pCtx->rsp;
357 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->edi, &TmpRsp);
358 if (rcStrict == VINF_SUCCESS)
359 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->esi, &TmpRsp);
360 if (rcStrict == VINF_SUCCESS)
361 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->ebp, &TmpRsp);
362 if (rcStrict == VINF_SUCCESS)
363 {
364 iemRegAddToRspEx(pIemCpu, pCtx, &TmpRsp, 2); /* sp */
365 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->ebx, &TmpRsp);
366 }
367 if (rcStrict == VINF_SUCCESS)
368 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->edx, &TmpRsp);
369 if (rcStrict == VINF_SUCCESS)
370 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->ecx, &TmpRsp);
371 if (rcStrict == VINF_SUCCESS)
372 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->eax, &TmpRsp);
373 if (rcStrict == VINF_SUCCESS)
374 {
375#if 1 /** @todo what actually happens with the high bits when we're in 16-bit mode? */
376 pCtx->rdi &= UINT32_MAX;
377 pCtx->rsi &= UINT32_MAX;
378 pCtx->rbp &= UINT32_MAX;
379 pCtx->rbx &= UINT32_MAX;
380 pCtx->rdx &= UINT32_MAX;
381 pCtx->rcx &= UINT32_MAX;
382 pCtx->rax &= UINT32_MAX;
383#endif
384 pCtx->rsp = TmpRsp.u;
385 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
386 }
387 }
388 else
389 {
390 uint32_t const *pa32Mem;
391 rcStrict = iemMemMap(pIemCpu, (void **)&pa32Mem, 32, X86_SREG_SS, GCPtrStart, IEM_ACCESS_STACK_R);
392 if (rcStrict == VINF_SUCCESS)
393 {
394 pCtx->rdi = pa32Mem[7 - X86_GREG_xDI];
395 pCtx->rsi = pa32Mem[7 - X86_GREG_xSI];
396 pCtx->rbp = pa32Mem[7 - X86_GREG_xBP];
397 /* skip esp */
398 pCtx->rbx = pa32Mem[7 - X86_GREG_xBX];
399 pCtx->rdx = pa32Mem[7 - X86_GREG_xDX];
400 pCtx->rcx = pa32Mem[7 - X86_GREG_xCX];
401 pCtx->rax = pa32Mem[7 - X86_GREG_xAX];
402 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)pa32Mem, IEM_ACCESS_STACK_R);
403 if (rcStrict == VINF_SUCCESS)
404 {
405 iemRegAddToRsp(pIemCpu, pCtx, 32);
406 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
407 }
408 }
409 }
410 return rcStrict;
411}
412
413
414/**
415 * Implements a 16-bit pusha.
416 */
417IEM_CIMPL_DEF_0(iemCImpl_pusha_16)
418{
419 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
420 RTGCPTR GCPtrTop = iemRegGetEffRsp(pIemCpu, pCtx);
421 RTGCPTR GCPtrBottom = GCPtrTop - 15;
422 VBOXSTRICTRC rcStrict;
423
424 /*
425 * The docs are a bit hard to comprehend here, but it looks like we wrap
426 * around in real mode as long as none of the individual "pushd" crosses the
427 * end of the stack segment. In protected mode we check the whole access
428 * in one go. For efficiency, only do the word-by-word thing if we're in
429 * danger of wrapping around.
430 */
431 /** @todo do pusha boundary / wrap-around checks. */
432 if (RT_UNLIKELY( GCPtrBottom > GCPtrTop
433 && IEM_IS_REAL_OR_V86_MODE(pIemCpu) ) )
434 {
435 /* word-by-word */
436 RTUINT64U TmpRsp;
437 TmpRsp.u = pCtx->rsp;
438 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->ax, &TmpRsp);
439 if (rcStrict == VINF_SUCCESS)
440 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->cx, &TmpRsp);
441 if (rcStrict == VINF_SUCCESS)
442 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->dx, &TmpRsp);
443 if (rcStrict == VINF_SUCCESS)
444 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->bx, &TmpRsp);
445 if (rcStrict == VINF_SUCCESS)
446 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->sp, &TmpRsp);
447 if (rcStrict == VINF_SUCCESS)
448 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->bp, &TmpRsp);
449 if (rcStrict == VINF_SUCCESS)
450 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->si, &TmpRsp);
451 if (rcStrict == VINF_SUCCESS)
452 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->di, &TmpRsp);
453 if (rcStrict == VINF_SUCCESS)
454 {
455 pCtx->rsp = TmpRsp.u;
456 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
457 }
458 }
459 else
460 {
461 GCPtrBottom--;
462 uint16_t *pa16Mem = NULL;
463 rcStrict = iemMemMap(pIemCpu, (void **)&pa16Mem, 16, X86_SREG_SS, GCPtrBottom, IEM_ACCESS_STACK_W);
464 if (rcStrict == VINF_SUCCESS)
465 {
466 pa16Mem[7 - X86_GREG_xDI] = pCtx->di;
467 pa16Mem[7 - X86_GREG_xSI] = pCtx->si;
468 pa16Mem[7 - X86_GREG_xBP] = pCtx->bp;
469 pa16Mem[7 - X86_GREG_xSP] = pCtx->sp;
470 pa16Mem[7 - X86_GREG_xBX] = pCtx->bx;
471 pa16Mem[7 - X86_GREG_xDX] = pCtx->dx;
472 pa16Mem[7 - X86_GREG_xCX] = pCtx->cx;
473 pa16Mem[7 - X86_GREG_xAX] = pCtx->ax;
474 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)pa16Mem, IEM_ACCESS_STACK_W);
475 if (rcStrict == VINF_SUCCESS)
476 {
477 iemRegSubFromRsp(pIemCpu, pCtx, 16);
478 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
479 }
480 }
481 }
482 return rcStrict;
483}
484
485
486/**
487 * Implements a 32-bit pusha.
488 */
489IEM_CIMPL_DEF_0(iemCImpl_pusha_32)
490{
491 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
492 RTGCPTR GCPtrTop = iemRegGetEffRsp(pIemCpu, pCtx);
493 RTGCPTR GCPtrBottom = GCPtrTop - 31;
494 VBOXSTRICTRC rcStrict;
495
496 /*
497 * The docs are a bit hard to comprehend here, but it looks like we wrap
498 * around in real mode as long as none of the individual "pusha" crosses the
499 * end of the stack segment. In protected mode we check the whole access
500 * in one go. For efficiency, only do the word-by-word thing if we're in
501 * danger of wrapping around.
502 */
503 /** @todo do pusha boundary / wrap-around checks. */
504 if (RT_UNLIKELY( GCPtrBottom > GCPtrTop
505 && IEM_IS_REAL_OR_V86_MODE(pIemCpu) ) )
506 {
507 /* word-by-word */
508 RTUINT64U TmpRsp;
509 TmpRsp.u = pCtx->rsp;
510 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->eax, &TmpRsp);
511 if (rcStrict == VINF_SUCCESS)
512 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->ecx, &TmpRsp);
513 if (rcStrict == VINF_SUCCESS)
514 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->edx, &TmpRsp);
515 if (rcStrict == VINF_SUCCESS)
516 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->ebx, &TmpRsp);
517 if (rcStrict == VINF_SUCCESS)
518 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->esp, &TmpRsp);
519 if (rcStrict == VINF_SUCCESS)
520 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->ebp, &TmpRsp);
521 if (rcStrict == VINF_SUCCESS)
522 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->esi, &TmpRsp);
523 if (rcStrict == VINF_SUCCESS)
524 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->edi, &TmpRsp);
525 if (rcStrict == VINF_SUCCESS)
526 {
527 pCtx->rsp = TmpRsp.u;
528 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
529 }
530 }
531 else
532 {
533 GCPtrBottom--;
534 uint32_t *pa32Mem;
535 rcStrict = iemMemMap(pIemCpu, (void **)&pa32Mem, 32, X86_SREG_SS, GCPtrBottom, IEM_ACCESS_STACK_W);
536 if (rcStrict == VINF_SUCCESS)
537 {
538 pa32Mem[7 - X86_GREG_xDI] = pCtx->edi;
539 pa32Mem[7 - X86_GREG_xSI] = pCtx->esi;
540 pa32Mem[7 - X86_GREG_xBP] = pCtx->ebp;
541 pa32Mem[7 - X86_GREG_xSP] = pCtx->esp;
542 pa32Mem[7 - X86_GREG_xBX] = pCtx->ebx;
543 pa32Mem[7 - X86_GREG_xDX] = pCtx->edx;
544 pa32Mem[7 - X86_GREG_xCX] = pCtx->ecx;
545 pa32Mem[7 - X86_GREG_xAX] = pCtx->eax;
546 rcStrict = iemMemCommitAndUnmap(pIemCpu, pa32Mem, IEM_ACCESS_STACK_W);
547 if (rcStrict == VINF_SUCCESS)
548 {
549 iemRegSubFromRsp(pIemCpu, pCtx, 32);
550 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
551 }
552 }
553 }
554 return rcStrict;
555}
556
557
558/**
559 * Implements pushf.
560 *
561 *
562 * @param enmEffOpSize The effective operand size.
563 */
564IEM_CIMPL_DEF_1(iemCImpl_pushf, IEMMODE, enmEffOpSize)
565{
566 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
567
568 /*
569 * If we're in V8086 mode some care is required (which is why we're in
570 * doing this in a C implementation).
571 */
572 uint32_t fEfl = IEMMISC_GET_EFL(pIemCpu, pCtx);
573 if ( (fEfl & X86_EFL_VM)
574 && X86_EFL_GET_IOPL(fEfl) != 3 )
575 {
576 Assert(pCtx->cr0 & X86_CR0_PE);
577 if ( enmEffOpSize != IEMMODE_16BIT
578 || !(pCtx->cr4 & X86_CR4_VME))
579 return iemRaiseGeneralProtectionFault0(pIemCpu);
580 fEfl &= ~X86_EFL_IF; /* (RF and VM are out of range) */
581 fEfl |= (fEfl & X86_EFL_VIF) >> (19 - 9);
582 return iemMemStackPushU16(pIemCpu, (uint16_t)fEfl);
583 }
584
585 /*
586 * Ok, clear RF and VM and push the flags.
587 */
588 fEfl &= ~(X86_EFL_RF | X86_EFL_VM);
589
590 VBOXSTRICTRC rcStrict;
591 switch (enmEffOpSize)
592 {
593 case IEMMODE_16BIT:
594 rcStrict = iemMemStackPushU16(pIemCpu, (uint16_t)fEfl);
595 break;
596 case IEMMODE_32BIT:
597 rcStrict = iemMemStackPushU32(pIemCpu, fEfl);
598 break;
599 case IEMMODE_64BIT:
600 rcStrict = iemMemStackPushU64(pIemCpu, fEfl);
601 break;
602 IEM_NOT_REACHED_DEFAULT_CASE_RET();
603 }
604 if (rcStrict != VINF_SUCCESS)
605 return rcStrict;
606
607 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
608 return VINF_SUCCESS;
609}
610
611
612/**
613 * Implements popf.
614 *
615 * @param enmEffOpSize The effective operand size.
616 */
617IEM_CIMPL_DEF_1(iemCImpl_popf, IEMMODE, enmEffOpSize)
618{
619 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
620 uint32_t const fEflOld = IEMMISC_GET_EFL(pIemCpu, pCtx);
621 VBOXSTRICTRC rcStrict;
622 uint32_t fEflNew;
623
624 /*
625 * V8086 is special as usual.
626 */
627 if (fEflOld & X86_EFL_VM)
628 {
629 /*
630 * Almost anything goes if IOPL is 3.
631 */
632 if (X86_EFL_GET_IOPL(fEflOld) == 3)
633 {
634 switch (enmEffOpSize)
635 {
636 case IEMMODE_16BIT:
637 {
638 uint16_t u16Value;
639 rcStrict = iemMemStackPopU16(pIemCpu, &u16Value);
640 if (rcStrict != VINF_SUCCESS)
641 return rcStrict;
642 fEflNew = u16Value | (fEflOld & UINT32_C(0xffff0000));
643 break;
644 }
645 case IEMMODE_32BIT:
646 rcStrict = iemMemStackPopU32(pIemCpu, &fEflNew);
647 if (rcStrict != VINF_SUCCESS)
648 return rcStrict;
649 break;
650 IEM_NOT_REACHED_DEFAULT_CASE_RET();
651 }
652
653 fEflNew &= X86_EFL_POPF_BITS & ~(X86_EFL_IOPL);
654 fEflNew |= ~(X86_EFL_POPF_BITS & ~(X86_EFL_IOPL)) & fEflOld;
655 }
656 /*
657 * Interrupt flag virtualization with CR4.VME=1.
658 */
659 else if ( enmEffOpSize == IEMMODE_16BIT
660 && (pCtx->cr4 & X86_CR4_VME) )
661 {
662 uint16_t u16Value;
663 RTUINT64U TmpRsp;
664 TmpRsp.u = pCtx->rsp;
665 rcStrict = iemMemStackPopU16Ex(pIemCpu, &u16Value, &TmpRsp);
666 if (rcStrict != VINF_SUCCESS)
667 return rcStrict;
668
669 /** @todo Is the popf VME #GP(0) delivered after updating RSP+RIP
670 * or before? */
671 if ( ( (u16Value & X86_EFL_IF)
672 && (fEflOld & X86_EFL_VIP))
673 || (u16Value & X86_EFL_TF) )
674 return iemRaiseGeneralProtectionFault0(pIemCpu);
675
676 fEflNew = u16Value | (fEflOld & UINT32_C(0xffff0000) & ~X86_EFL_VIF);
677 fEflNew |= (fEflNew & X86_EFL_IF) << (19 - 9);
678 fEflNew &= X86_EFL_POPF_BITS & ~(X86_EFL_IOPL | X86_EFL_IF);
679 fEflNew |= ~(X86_EFL_POPF_BITS & ~(X86_EFL_IOPL | X86_EFL_IF)) & fEflOld;
680
681 pCtx->rsp = TmpRsp.u;
682 }
683 else
684 return iemRaiseGeneralProtectionFault0(pIemCpu);
685
686 }
687 /*
688 * Not in V8086 mode.
689 */
690 else
691 {
692 /* Pop the flags. */
693 switch (enmEffOpSize)
694 {
695 case IEMMODE_16BIT:
696 {
697 uint16_t u16Value;
698 rcStrict = iemMemStackPopU16(pIemCpu, &u16Value);
699 if (rcStrict != VINF_SUCCESS)
700 return rcStrict;
701 fEflNew = u16Value | (fEflOld & UINT32_C(0xffff0000));
702 break;
703 }
704 case IEMMODE_32BIT:
705 rcStrict = iemMemStackPopU32(pIemCpu, &fEflNew);
706 if (rcStrict != VINF_SUCCESS)
707 return rcStrict;
708 break;
709 case IEMMODE_64BIT:
710 {
711 uint64_t u64Value;
712 rcStrict = iemMemStackPopU64(pIemCpu, &u64Value);
713 if (rcStrict != VINF_SUCCESS)
714 return rcStrict;
715 fEflNew = u64Value; /** @todo testcase: Check exactly what happens if high bits are set. */
716 break;
717 }
718 IEM_NOT_REACHED_DEFAULT_CASE_RET();
719 }
720
721 /* Merge them with the current flags. */
722 if ( (fEflNew & (X86_EFL_IOPL | X86_EFL_IF)) == (fEflOld & (X86_EFL_IOPL | X86_EFL_IF))
723 || pIemCpu->uCpl == 0)
724 {
725 fEflNew &= X86_EFL_POPF_BITS;
726 fEflNew |= ~X86_EFL_POPF_BITS & fEflOld;
727 }
728 else if (pIemCpu->uCpl <= X86_EFL_GET_IOPL(fEflOld))
729 {
730 fEflNew &= X86_EFL_POPF_BITS & ~(X86_EFL_IOPL);
731 fEflNew |= ~(X86_EFL_POPF_BITS & ~(X86_EFL_IOPL)) & fEflOld;
732 }
733 else
734 {
735 fEflNew &= X86_EFL_POPF_BITS & ~(X86_EFL_IOPL | X86_EFL_IF);
736 fEflNew |= ~(X86_EFL_POPF_BITS & ~(X86_EFL_IOPL | X86_EFL_IF)) & fEflOld;
737 }
738 }
739
740 /*
741 * Commit the flags.
742 */
743 Assert(fEflNew & RT_BIT_32(1));
744 IEMMISC_SET_EFL(pIemCpu, pCtx, fEflNew);
745 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
746
747 return VINF_SUCCESS;
748}
749
750
751/**
752 * Implements an indirect call.
753 *
754 * @param uNewPC The new program counter (RIP) value (loaded from the
755 * operand).
756 * @param enmEffOpSize The effective operand size.
757 */
758IEM_CIMPL_DEF_1(iemCImpl_call_16, uint16_t, uNewPC)
759{
760 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
761 uint16_t uOldPC = pCtx->ip + cbInstr;
762 if (uNewPC > pCtx->cs.u32Limit)
763 return iemRaiseGeneralProtectionFault0(pIemCpu);
764
765 VBOXSTRICTRC rcStrict = iemMemStackPushU16(pIemCpu, uOldPC);
766 if (rcStrict != VINF_SUCCESS)
767 return rcStrict;
768
769 pCtx->rip = uNewPC;
770 pCtx->eflags.Bits.u1RF = 0;
771 return VINF_SUCCESS;
772}
773
774
775/**
776 * Implements a 16-bit relative call.
777 *
778 * @param offDisp The displacment offset.
779 */
780IEM_CIMPL_DEF_1(iemCImpl_call_rel_16, int16_t, offDisp)
781{
782 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
783 uint16_t uOldPC = pCtx->ip + cbInstr;
784 uint16_t uNewPC = uOldPC + offDisp;
785 if (uNewPC > pCtx->cs.u32Limit)
786 return iemRaiseGeneralProtectionFault0(pIemCpu);
787
788 VBOXSTRICTRC rcStrict = iemMemStackPushU16(pIemCpu, uOldPC);
789 if (rcStrict != VINF_SUCCESS)
790 return rcStrict;
791
792 pCtx->rip = uNewPC;
793 pCtx->eflags.Bits.u1RF = 0;
794 return VINF_SUCCESS;
795}
796
797
798/**
799 * Implements a 32-bit indirect call.
800 *
801 * @param uNewPC The new program counter (RIP) value (loaded from the
802 * operand).
803 * @param enmEffOpSize The effective operand size.
804 */
805IEM_CIMPL_DEF_1(iemCImpl_call_32, uint32_t, uNewPC)
806{
807 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
808 uint32_t uOldPC = pCtx->eip + cbInstr;
809 if (uNewPC > pCtx->cs.u32Limit)
810 return iemRaiseGeneralProtectionFault0(pIemCpu);
811
812 VBOXSTRICTRC rcStrict = iemMemStackPushU32(pIemCpu, uOldPC);
813 if (rcStrict != VINF_SUCCESS)
814 return rcStrict;
815
816#if defined(IN_RING3) && defined(VBOX_WITH_RAW_MODE) && defined(VBOX_WITH_CALL_RECORD)
817 /*
818 * CASM hook for recording interesting indirect calls.
819 */
820 if ( !pCtx->eflags.Bits.u1IF
821 && (pCtx->cr0 & X86_CR0_PG)
822 && !CSAMIsEnabled(IEMCPU_TO_VM(pIemCpu))
823 && pIemCpu->uCpl == 0)
824 {
825 EMSTATE enmState = EMGetState(IEMCPU_TO_VMCPU(pIemCpu));
826 if ( enmState == EMSTATE_IEM_THEN_REM
827 || enmState == EMSTATE_IEM
828 || enmState == EMSTATE_REM)
829 CSAMR3RecordCallAddress(IEMCPU_TO_VM(pIemCpu), pCtx->eip);
830 }
831#endif
832
833 pCtx->rip = uNewPC;
834 pCtx->eflags.Bits.u1RF = 0;
835 return VINF_SUCCESS;
836}
837
838
839/**
840 * Implements a 32-bit relative call.
841 *
842 * @param offDisp The displacment offset.
843 */
844IEM_CIMPL_DEF_1(iemCImpl_call_rel_32, int32_t, offDisp)
845{
846 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
847 uint32_t uOldPC = pCtx->eip + cbInstr;
848 uint32_t uNewPC = uOldPC + offDisp;
849 if (uNewPC > pCtx->cs.u32Limit)
850 return iemRaiseGeneralProtectionFault0(pIemCpu);
851
852 VBOXSTRICTRC rcStrict = iemMemStackPushU32(pIemCpu, uOldPC);
853 if (rcStrict != VINF_SUCCESS)
854 return rcStrict;
855
856 pCtx->rip = uNewPC;
857 pCtx->eflags.Bits.u1RF = 0;
858 return VINF_SUCCESS;
859}
860
861
862/**
863 * Implements a 64-bit indirect call.
864 *
865 * @param uNewPC The new program counter (RIP) value (loaded from the
866 * operand).
867 * @param enmEffOpSize The effective operand size.
868 */
869IEM_CIMPL_DEF_1(iemCImpl_call_64, uint64_t, uNewPC)
870{
871 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
872 uint64_t uOldPC = pCtx->rip + cbInstr;
873 if (!IEM_IS_CANONICAL(uNewPC))
874 return iemRaiseGeneralProtectionFault0(pIemCpu);
875
876 VBOXSTRICTRC rcStrict = iemMemStackPushU64(pIemCpu, uOldPC);
877 if (rcStrict != VINF_SUCCESS)
878 return rcStrict;
879
880 pCtx->rip = uNewPC;
881 pCtx->eflags.Bits.u1RF = 0;
882 return VINF_SUCCESS;
883}
884
885
886/**
887 * Implements a 64-bit relative call.
888 *
889 * @param offDisp The displacment offset.
890 */
891IEM_CIMPL_DEF_1(iemCImpl_call_rel_64, int64_t, offDisp)
892{
893 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
894 uint64_t uOldPC = pCtx->rip + cbInstr;
895 uint64_t uNewPC = uOldPC + offDisp;
896 if (!IEM_IS_CANONICAL(uNewPC))
897 return iemRaiseNotCanonical(pIemCpu);
898
899 VBOXSTRICTRC rcStrict = iemMemStackPushU64(pIemCpu, uOldPC);
900 if (rcStrict != VINF_SUCCESS)
901 return rcStrict;
902
903 pCtx->rip = uNewPC;
904 pCtx->eflags.Bits.u1RF = 0;
905 return VINF_SUCCESS;
906}
907
908
909/**
910 * Implements far jumps and calls thru task segments (TSS).
911 *
912 * @param uSel The selector.
913 * @param enmBranch The kind of branching we're performing.
914 * @param enmEffOpSize The effective operand size.
915 * @param pDesc The descriptor corrsponding to @a uSel. The type is
916 * call gate.
917 */
918IEM_CIMPL_DEF_4(iemCImpl_BranchTaskSegment, uint16_t, uSel, IEMBRANCH, enmBranch, IEMMODE, enmEffOpSize, PIEMSELDESC, pDesc)
919{
920 /* Call various functions to do the work. Clear RF? */
921 IEM_RETURN_ASPECT_NOT_IMPLEMENTED();
922}
923
924
925/**
926 * Implements far jumps and calls thru task gates.
927 *
928 * @param uSel The selector.
929 * @param enmBranch The kind of branching we're performing.
930 * @param enmEffOpSize The effective operand size.
931 * @param pDesc The descriptor corrsponding to @a uSel. The type is
932 * call gate.
933 */
934IEM_CIMPL_DEF_4(iemCImpl_BranchTaskGate, uint16_t, uSel, IEMBRANCH, enmBranch, IEMMODE, enmEffOpSize, PIEMSELDESC, pDesc)
935{
936 /* Call various functions to do the work. Don't clear RF */
937 IEM_RETURN_ASPECT_NOT_IMPLEMENTED();
938}
939
940
941/**
942 * Implements far jumps and calls thru call gates.
943 *
944 * @param uSel The selector.
945 * @param enmBranch The kind of branching we're performing.
946 * @param enmEffOpSize The effective operand size.
947 * @param pDesc The descriptor corrsponding to @a uSel. The type is
948 * call gate.
949 */
950IEM_CIMPL_DEF_4(iemCImpl_BranchCallGate, uint16_t, uSel, IEMBRANCH, enmBranch, IEMMODE, enmEffOpSize, PIEMSELDESC, pDesc)
951{
952 /* Call various functions to do the work. Clear RF. */
953 IEM_RETURN_ASPECT_NOT_IMPLEMENTED();
954}
955
956
957/**
958 * Implements far jumps and calls thru system selectors.
959 *
960 * @param uSel The selector.
961 * @param enmBranch The kind of branching we're performing.
962 * @param enmEffOpSize The effective operand size.
963 * @param pDesc The descriptor corrsponding to @a uSel.
964 */
965IEM_CIMPL_DEF_4(iemCImpl_BranchSysSel, uint16_t, uSel, IEMBRANCH, enmBranch, IEMMODE, enmEffOpSize, PIEMSELDESC, pDesc)
966{
967 Assert(enmBranch == IEMBRANCH_JUMP || enmBranch == IEMBRANCH_CALL);
968 Assert((uSel & X86_SEL_MASK_OFF_RPL));
969
970 if (IEM_IS_LONG_MODE(pIemCpu))
971 switch (pDesc->Legacy.Gen.u4Type)
972 {
973 case AMD64_SEL_TYPE_SYS_CALL_GATE:
974 return IEM_CIMPL_CALL_4(iemCImpl_BranchCallGate, uSel, enmBranch, enmEffOpSize, pDesc);
975
976 default:
977 case AMD64_SEL_TYPE_SYS_LDT:
978 case AMD64_SEL_TYPE_SYS_TSS_BUSY:
979 case AMD64_SEL_TYPE_SYS_TSS_AVAIL:
980 case AMD64_SEL_TYPE_SYS_TRAP_GATE:
981 case AMD64_SEL_TYPE_SYS_INT_GATE:
982 Log(("branch %04x -> wrong sys selector (64-bit): %d\n", uSel, pDesc->Legacy.Gen.u4Type));
983 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
984
985 }
986
987 switch (pDesc->Legacy.Gen.u4Type)
988 {
989 case X86_SEL_TYPE_SYS_286_CALL_GATE:
990 case X86_SEL_TYPE_SYS_386_CALL_GATE:
991 return IEM_CIMPL_CALL_4(iemCImpl_BranchCallGate, uSel, enmBranch, enmEffOpSize, pDesc);
992
993 case X86_SEL_TYPE_SYS_TASK_GATE:
994 return IEM_CIMPL_CALL_4(iemCImpl_BranchTaskGate, uSel, enmBranch, enmEffOpSize, pDesc);
995
996 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
997 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
998 return IEM_CIMPL_CALL_4(iemCImpl_BranchTaskSegment, uSel, enmBranch, enmEffOpSize, pDesc);
999
1000 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
1001 Log(("branch %04x -> busy 286 TSS\n", uSel));
1002 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1003
1004 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
1005 Log(("branch %04x -> busy 386 TSS\n", uSel));
1006 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1007
1008 default:
1009 case X86_SEL_TYPE_SYS_LDT:
1010 case X86_SEL_TYPE_SYS_286_INT_GATE:
1011 case X86_SEL_TYPE_SYS_286_TRAP_GATE:
1012 case X86_SEL_TYPE_SYS_386_INT_GATE:
1013 case X86_SEL_TYPE_SYS_386_TRAP_GATE:
1014 Log(("branch %04x -> wrong sys selector: %d\n", uSel, pDesc->Legacy.Gen.u4Type));
1015 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1016 }
1017}
1018
1019
1020/**
1021 * Implements far jumps.
1022 *
1023 * @param uSel The selector.
1024 * @param offSeg The segment offset.
1025 * @param enmEffOpSize The effective operand size.
1026 */
1027IEM_CIMPL_DEF_3(iemCImpl_FarJmp, uint16_t, uSel, uint64_t, offSeg, IEMMODE, enmEffOpSize)
1028{
1029 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1030 NOREF(cbInstr);
1031 Assert(offSeg <= UINT32_MAX);
1032
1033 /*
1034 * Real mode and V8086 mode are easy. The only snag seems to be that
1035 * CS.limit doesn't change and the limit check is done against the current
1036 * limit.
1037 */
1038 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
1039 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
1040 {
1041 if (offSeg > pCtx->cs.u32Limit)
1042 return iemRaiseGeneralProtectionFault0(pIemCpu);
1043
1044 if (enmEffOpSize == IEMMODE_16BIT) /** @todo WRONG, must pass this. */
1045 pCtx->rip = offSeg;
1046 else
1047 pCtx->rip = offSeg & UINT16_MAX;
1048 pCtx->cs.Sel = uSel;
1049 pCtx->cs.ValidSel = uSel;
1050 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
1051 pCtx->cs.u64Base = (uint32_t)uSel << 4;
1052 pCtx->eflags.Bits.u1RF = 0;
1053 return VINF_SUCCESS;
1054 }
1055
1056 /*
1057 * Protected mode. Need to parse the specified descriptor...
1058 */
1059 if (!(uSel & X86_SEL_MASK_OFF_RPL))
1060 {
1061 Log(("jmpf %04x:%08RX64 -> invalid selector, #GP(0)\n", uSel, offSeg));
1062 return iemRaiseGeneralProtectionFault0(pIemCpu);
1063 }
1064
1065 /* Fetch the descriptor. */
1066 IEMSELDESC Desc;
1067 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uSel, X86_XCPT_GP);
1068 if (rcStrict != VINF_SUCCESS)
1069 return rcStrict;
1070
1071 /* Is it there? */
1072 if (!Desc.Legacy.Gen.u1Present) /** @todo this is probably checked too early. Testcase! */
1073 {
1074 Log(("jmpf %04x:%08RX64 -> segment not present\n", uSel, offSeg));
1075 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uSel);
1076 }
1077
1078 /*
1079 * Deal with it according to its type. We do the standard code selectors
1080 * here and dispatch the system selectors to worker functions.
1081 */
1082 if (!Desc.Legacy.Gen.u1DescType)
1083 return IEM_CIMPL_CALL_4(iemCImpl_BranchSysSel, uSel, IEMBRANCH_JUMP, enmEffOpSize, &Desc);
1084
1085 /* Only code segments. */
1086 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE))
1087 {
1088 Log(("jmpf %04x:%08RX64 -> not a code selector (u4Type=%#x).\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
1089 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1090 }
1091
1092 /* L vs D. */
1093 if ( Desc.Legacy.Gen.u1Long
1094 && Desc.Legacy.Gen.u1DefBig
1095 && IEM_IS_LONG_MODE(pIemCpu))
1096 {
1097 Log(("jmpf %04x:%08RX64 -> both L and D are set.\n", uSel, offSeg));
1098 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1099 }
1100
1101 /* DPL/RPL/CPL check, where conforming segments makes a difference. */
1102 if (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF)
1103 {
1104 if (pIemCpu->uCpl < Desc.Legacy.Gen.u2Dpl)
1105 {
1106 Log(("jmpf %04x:%08RX64 -> DPL violation (conforming); DPL=%d CPL=%u\n",
1107 uSel, offSeg, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
1108 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1109 }
1110 }
1111 else
1112 {
1113 if (pIemCpu->uCpl != Desc.Legacy.Gen.u2Dpl)
1114 {
1115 Log(("jmpf %04x:%08RX64 -> CPL != DPL; DPL=%d CPL=%u\n", uSel, offSeg, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
1116 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1117 }
1118 if ((uSel & X86_SEL_RPL) > pIemCpu->uCpl)
1119 {
1120 Log(("jmpf %04x:%08RX64 -> RPL > DPL; RPL=%d CPL=%u\n", uSel, offSeg, (uSel & X86_SEL_RPL), pIemCpu->uCpl));
1121 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1122 }
1123 }
1124
1125 /* Chop the high bits if 16-bit (Intel says so). */
1126 if (enmEffOpSize == IEMMODE_16BIT)
1127 offSeg &= UINT16_MAX;
1128
1129 /* Limit check. (Should alternatively check for non-canonical addresses
1130 here, but that is ruled out by offSeg being 32-bit, right?) */
1131 uint64_t u64Base;
1132 uint32_t cbLimit = X86DESC_LIMIT_G(&Desc.Legacy);
1133 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
1134 u64Base = 0;
1135 else
1136 {
1137 if (offSeg > cbLimit)
1138 {
1139 Log(("jmpf %04x:%08RX64 -> out of bounds (%#x)\n", uSel, offSeg, cbLimit));
1140 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1141 }
1142 u64Base = X86DESC_BASE(&Desc.Legacy);
1143 }
1144
1145 /*
1146 * Ok, everything checked out fine. Now set the accessed bit before
1147 * committing the result into CS, CSHID and RIP.
1148 */
1149 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1150 {
1151 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uSel);
1152 if (rcStrict != VINF_SUCCESS)
1153 return rcStrict;
1154 /** @todo check what VT-x and AMD-V does. */
1155 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1156 }
1157
1158 /* commit */
1159 pCtx->rip = offSeg;
1160 pCtx->cs.Sel = uSel & X86_SEL_MASK_OFF_RPL;
1161 pCtx->cs.Sel |= pIemCpu->uCpl; /** @todo is this right for conforming segs? or in general? */
1162 pCtx->cs.ValidSel = pCtx->cs.Sel;
1163 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
1164 pCtx->cs.Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
1165 pCtx->cs.u32Limit = cbLimit;
1166 pCtx->cs.u64Base = u64Base;
1167 pCtx->eflags.Bits.u1RF = 0;
1168 /** @todo check if the hidden bits are loaded correctly for 64-bit
1169 * mode. */
1170 return VINF_SUCCESS;
1171}
1172
1173
1174/**
1175 * Implements far calls.
1176 *
1177 * This very similar to iemCImpl_FarJmp.
1178 *
1179 * @param uSel The selector.
1180 * @param offSeg The segment offset.
1181 * @param enmEffOpSize The operand size (in case we need it).
1182 */
1183IEM_CIMPL_DEF_3(iemCImpl_callf, uint16_t, uSel, uint64_t, offSeg, IEMMODE, enmEffOpSize)
1184{
1185 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1186 VBOXSTRICTRC rcStrict;
1187 uint64_t uNewRsp;
1188 RTPTRUNION uPtrRet;
1189
1190 /*
1191 * Real mode and V8086 mode are easy. The only snag seems to be that
1192 * CS.limit doesn't change and the limit check is done against the current
1193 * limit.
1194 */
1195 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
1196 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
1197 {
1198 Assert(enmEffOpSize == IEMMODE_16BIT || enmEffOpSize == IEMMODE_32BIT);
1199
1200 /* Check stack first - may #SS(0). */
1201 rcStrict = iemMemStackPushBeginSpecial(pIemCpu, enmEffOpSize == IEMMODE_32BIT ? 6 : 4,
1202 &uPtrRet.pv, &uNewRsp);
1203 if (rcStrict != VINF_SUCCESS)
1204 return rcStrict;
1205
1206 /* Check the target address range. */
1207 if (offSeg > UINT32_MAX)
1208 return iemRaiseGeneralProtectionFault0(pIemCpu);
1209
1210 /* Everything is fine, push the return address. */
1211 if (enmEffOpSize == IEMMODE_16BIT)
1212 {
1213 uPtrRet.pu16[0] = pCtx->ip + cbInstr;
1214 uPtrRet.pu16[1] = pCtx->cs.Sel;
1215 }
1216 else
1217 {
1218 uPtrRet.pu32[0] = pCtx->eip + cbInstr;
1219 uPtrRet.pu16[3] = pCtx->cs.Sel;
1220 }
1221 rcStrict = iemMemStackPushCommitSpecial(pIemCpu, uPtrRet.pv, uNewRsp);
1222 if (rcStrict != VINF_SUCCESS)
1223 return rcStrict;
1224
1225 /* Branch. */
1226 pCtx->rip = offSeg;
1227 pCtx->cs.Sel = uSel;
1228 pCtx->cs.ValidSel = uSel;
1229 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
1230 pCtx->cs.u64Base = (uint32_t)uSel << 4;
1231 pCtx->eflags.Bits.u1RF = 0;
1232 return VINF_SUCCESS;
1233 }
1234
1235 /*
1236 * Protected mode. Need to parse the specified descriptor...
1237 */
1238 if (!(uSel & X86_SEL_MASK_OFF_RPL))
1239 {
1240 Log(("callf %04x:%08RX64 -> invalid selector, #GP(0)\n", uSel, offSeg));
1241 return iemRaiseGeneralProtectionFault0(pIemCpu);
1242 }
1243
1244 /* Fetch the descriptor. */
1245 IEMSELDESC Desc;
1246 rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uSel, X86_XCPT_GP);
1247 if (rcStrict != VINF_SUCCESS)
1248 return rcStrict;
1249
1250 /*
1251 * Deal with it according to its type. We do the standard code selectors
1252 * here and dispatch the system selectors to worker functions.
1253 */
1254 if (!Desc.Legacy.Gen.u1DescType)
1255 return IEM_CIMPL_CALL_4(iemCImpl_BranchSysSel, uSel, IEMBRANCH_CALL, enmEffOpSize, &Desc);
1256
1257 /* Only code segments. */
1258 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE))
1259 {
1260 Log(("callf %04x:%08RX64 -> not a code selector (u4Type=%#x).\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
1261 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1262 }
1263
1264 /* L vs D. */
1265 if ( Desc.Legacy.Gen.u1Long
1266 && Desc.Legacy.Gen.u1DefBig
1267 && IEM_IS_LONG_MODE(pIemCpu))
1268 {
1269 Log(("callf %04x:%08RX64 -> both L and D are set.\n", uSel, offSeg));
1270 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1271 }
1272
1273 /* DPL/RPL/CPL check, where conforming segments makes a difference. */
1274 if (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF)
1275 {
1276 if (pIemCpu->uCpl < Desc.Legacy.Gen.u2Dpl)
1277 {
1278 Log(("callf %04x:%08RX64 -> DPL violation (conforming); DPL=%d CPL=%u\n",
1279 uSel, offSeg, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
1280 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1281 }
1282 }
1283 else
1284 {
1285 if (pIemCpu->uCpl != Desc.Legacy.Gen.u2Dpl)
1286 {
1287 Log(("callf %04x:%08RX64 -> CPL != DPL; DPL=%d CPL=%u\n", uSel, offSeg, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
1288 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1289 }
1290 if ((uSel & X86_SEL_RPL) > pIemCpu->uCpl)
1291 {
1292 Log(("callf %04x:%08RX64 -> RPL > DPL; RPL=%d CPL=%u\n", uSel, offSeg, (uSel & X86_SEL_RPL), pIemCpu->uCpl));
1293 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1294 }
1295 }
1296
1297 /* Is it there? */
1298 if (!Desc.Legacy.Gen.u1Present)
1299 {
1300 Log(("callf %04x:%08RX64 -> segment not present\n", uSel, offSeg));
1301 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uSel);
1302 }
1303
1304 /* Check stack first - may #SS(0). */
1305 /** @todo check how operand prefix affects pushing of CS! Does callf 16:32 in
1306 * 16-bit code cause a two or four byte CS to be pushed? */
1307 rcStrict = iemMemStackPushBeginSpecial(pIemCpu,
1308 enmEffOpSize == IEMMODE_64BIT ? 8+8
1309 : enmEffOpSize == IEMMODE_32BIT ? 4+4 : 2+2,
1310 &uPtrRet.pv, &uNewRsp);
1311 if (rcStrict != VINF_SUCCESS)
1312 return rcStrict;
1313
1314 /* Chop the high bits if 16-bit (Intel says so). */
1315 if (enmEffOpSize == IEMMODE_16BIT)
1316 offSeg &= UINT16_MAX;
1317
1318 /* Limit / canonical check. */
1319 uint64_t u64Base;
1320 uint32_t cbLimit = X86DESC_LIMIT_G(&Desc.Legacy);
1321 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
1322 {
1323 if (!IEM_IS_CANONICAL(offSeg))
1324 {
1325 Log(("callf %04x:%016RX64 - not canonical -> #GP\n", uSel, offSeg));
1326 return iemRaiseNotCanonical(pIemCpu);
1327 }
1328 u64Base = 0;
1329 }
1330 else
1331 {
1332 if (offSeg > cbLimit)
1333 {
1334 Log(("callf %04x:%08RX64 -> out of bounds (%#x)\n", uSel, offSeg, cbLimit));
1335 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1336 }
1337 u64Base = X86DESC_BASE(&Desc.Legacy);
1338 }
1339
1340 /*
1341 * Now set the accessed bit before
1342 * writing the return address to the stack and committing the result into
1343 * CS, CSHID and RIP.
1344 */
1345 /** @todo Testcase: Need to check WHEN exactly the accessed bit is set. */
1346 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1347 {
1348 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uSel);
1349 if (rcStrict != VINF_SUCCESS)
1350 return rcStrict;
1351 /** @todo check what VT-x and AMD-V does. */
1352 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1353 }
1354
1355 /* stack */
1356 if (enmEffOpSize == IEMMODE_16BIT)
1357 {
1358 uPtrRet.pu16[0] = pCtx->ip + cbInstr;
1359 uPtrRet.pu16[1] = pCtx->cs.Sel;
1360 }
1361 else if (enmEffOpSize == IEMMODE_32BIT)
1362 {
1363 uPtrRet.pu32[0] = pCtx->eip + cbInstr;
1364 uPtrRet.pu32[1] = pCtx->cs.Sel; /** @todo Testcase: What is written to the high word when callf is pushing CS? */
1365 }
1366 else
1367 {
1368 uPtrRet.pu64[0] = pCtx->rip + cbInstr;
1369 uPtrRet.pu64[1] = pCtx->cs.Sel; /** @todo Testcase: What is written to the high words when callf is pushing CS? */
1370 }
1371 rcStrict = iemMemStackPushCommitSpecial(pIemCpu, uPtrRet.pv, uNewRsp);
1372 if (rcStrict != VINF_SUCCESS)
1373 return rcStrict;
1374
1375 /* commit */
1376 pCtx->rip = offSeg;
1377 pCtx->cs.Sel = uSel & X86_SEL_MASK_OFF_RPL;
1378 pCtx->cs.Sel |= pIemCpu->uCpl;
1379 pCtx->cs.ValidSel = pCtx->cs.Sel;
1380 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
1381 pCtx->cs.Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
1382 pCtx->cs.u32Limit = cbLimit;
1383 pCtx->cs.u64Base = u64Base;
1384 pCtx->eflags.Bits.u1RF = 0;
1385 /** @todo check if the hidden bits are loaded correctly for 64-bit
1386 * mode. */
1387 return VINF_SUCCESS;
1388}
1389
1390
1391/**
1392 * Implements retf.
1393 *
1394 * @param enmEffOpSize The effective operand size.
1395 * @param cbPop The amount of arguments to pop from the stack
1396 * (bytes).
1397 */
1398IEM_CIMPL_DEF_2(iemCImpl_retf, IEMMODE, enmEffOpSize, uint16_t, cbPop)
1399{
1400 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1401 VBOXSTRICTRC rcStrict;
1402 RTCPTRUNION uPtrFrame;
1403 uint64_t uNewRsp;
1404 uint64_t uNewRip;
1405 uint16_t uNewCs;
1406 NOREF(cbInstr);
1407
1408 /*
1409 * Read the stack values first.
1410 */
1411 uint32_t cbRetPtr = enmEffOpSize == IEMMODE_16BIT ? 2+2
1412 : enmEffOpSize == IEMMODE_32BIT ? 4+4 : 8+8;
1413 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, cbRetPtr, &uPtrFrame.pv, &uNewRsp);
1414 if (rcStrict != VINF_SUCCESS)
1415 return rcStrict;
1416 if (enmEffOpSize == IEMMODE_16BIT)
1417 {
1418 uNewRip = uPtrFrame.pu16[0];
1419 uNewCs = uPtrFrame.pu16[1];
1420 }
1421 else if (enmEffOpSize == IEMMODE_32BIT)
1422 {
1423 uNewRip = uPtrFrame.pu32[0];
1424 uNewCs = uPtrFrame.pu16[2];
1425 }
1426 else
1427 {
1428 uNewRip = uPtrFrame.pu64[0];
1429 uNewCs = uPtrFrame.pu16[4];
1430 }
1431
1432 /*
1433 * Real mode and V8086 mode are easy.
1434 */
1435 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
1436 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
1437 {
1438 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
1439 /** @todo check how this is supposed to work if sp=0xfffe. */
1440
1441 /* Check the limit of the new EIP. */
1442 /** @todo Intel pseudo code only does the limit check for 16-bit
1443 * operands, AMD does not make any distinction. What is right? */
1444 if (uNewRip > pCtx->cs.u32Limit)
1445 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
1446
1447 /* commit the operation. */
1448 rcStrict = iemMemStackPopCommitSpecial(pIemCpu, uPtrFrame.pv, uNewRsp);
1449 if (rcStrict != VINF_SUCCESS)
1450 return rcStrict;
1451 pCtx->rip = uNewRip;
1452 pCtx->cs.Sel = uNewCs;
1453 pCtx->cs.ValidSel = uNewCs;
1454 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
1455 pCtx->cs.u64Base = (uint32_t)uNewCs << 4;
1456 pCtx->eflags.Bits.u1RF = 0;
1457 /** @todo do we load attribs and limit as well? */
1458 if (cbPop)
1459 iemRegAddToRsp(pIemCpu, pCtx, cbPop);
1460 return VINF_SUCCESS;
1461 }
1462
1463 /*
1464 * Protected mode is complicated, of course.
1465 */
1466 if (!(uNewCs & X86_SEL_MASK_OFF_RPL))
1467 {
1468 Log(("retf %04x:%08RX64 -> invalid selector, #GP(0)\n", uNewCs, uNewRip));
1469 return iemRaiseGeneralProtectionFault0(pIemCpu);
1470 }
1471
1472 /* Fetch the descriptor. */
1473 IEMSELDESC DescCs;
1474 rcStrict = iemMemFetchSelDesc(pIemCpu, &DescCs, uNewCs, X86_XCPT_GP);
1475 if (rcStrict != VINF_SUCCESS)
1476 return rcStrict;
1477
1478 /* Can only return to a code selector. */
1479 if ( !DescCs.Legacy.Gen.u1DescType
1480 || !(DescCs.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE) )
1481 {
1482 Log(("retf %04x:%08RX64 -> not a code selector (u1DescType=%u u4Type=%#x).\n",
1483 uNewCs, uNewRip, DescCs.Legacy.Gen.u1DescType, DescCs.Legacy.Gen.u4Type));
1484 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
1485 }
1486
1487 /* L vs D. */
1488 if ( DescCs.Legacy.Gen.u1Long /** @todo Testcase: far return to a selector with both L and D set. */
1489 && DescCs.Legacy.Gen.u1DefBig
1490 && IEM_IS_LONG_MODE(pIemCpu))
1491 {
1492 Log(("retf %04x:%08RX64 -> both L & D set.\n", uNewCs, uNewRip));
1493 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
1494 }
1495
1496 /* DPL/RPL/CPL checks. */
1497 if ((uNewCs & X86_SEL_RPL) < pIemCpu->uCpl)
1498 {
1499 Log(("retf %04x:%08RX64 -> RPL < CPL(%d).\n", uNewCs, uNewRip, pIemCpu->uCpl));
1500 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
1501 }
1502
1503 if (DescCs.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF)
1504 {
1505 if ((uNewCs & X86_SEL_RPL) < DescCs.Legacy.Gen.u2Dpl)
1506 {
1507 Log(("retf %04x:%08RX64 -> DPL violation (conforming); DPL=%u RPL=%u\n",
1508 uNewCs, uNewRip, DescCs.Legacy.Gen.u2Dpl, (uNewCs & X86_SEL_RPL)));
1509 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
1510 }
1511 }
1512 else
1513 {
1514 if ((uNewCs & X86_SEL_RPL) != DescCs.Legacy.Gen.u2Dpl)
1515 {
1516 Log(("retf %04x:%08RX64 -> RPL != DPL; DPL=%u RPL=%u\n",
1517 uNewCs, uNewRip, DescCs.Legacy.Gen.u2Dpl, (uNewCs & X86_SEL_RPL)));
1518 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
1519 }
1520 }
1521
1522 /* Is it there? */
1523 if (!DescCs.Legacy.Gen.u1Present)
1524 {
1525 Log(("retf %04x:%08RX64 -> segment not present\n", uNewCs, uNewRip));
1526 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uNewCs);
1527 }
1528
1529 /*
1530 * Return to outer privilege? (We'll typically have entered via a call gate.)
1531 */
1532 if ((uNewCs & X86_SEL_RPL) != pIemCpu->uCpl)
1533 {
1534 /* Read the return pointer, it comes before the parameters. */
1535 RTCPTRUNION uPtrStack;
1536 rcStrict = iemMemStackPopContinueSpecial(pIemCpu, cbPop + cbRetPtr, &uPtrStack.pv, &uNewRsp);
1537 if (rcStrict != VINF_SUCCESS)
1538 return rcStrict;
1539 uint16_t uNewOuterSs;
1540 uint64_t uNewOuterRsp;
1541 if (enmEffOpSize == IEMMODE_16BIT)
1542 {
1543 uNewOuterRsp = uPtrFrame.pu16[0];
1544 uNewOuterSs = uPtrFrame.pu16[1];
1545 }
1546 else if (enmEffOpSize == IEMMODE_32BIT)
1547 {
1548 uNewOuterRsp = uPtrFrame.pu32[0];
1549 uNewOuterSs = uPtrFrame.pu16[2];
1550 }
1551 else
1552 {
1553 uNewOuterRsp = uPtrFrame.pu64[0];
1554 uNewOuterSs = uPtrFrame.pu16[4];
1555 }
1556
1557 /* Check for NULL stack selector (invalid in ring-3 and non-long mode)
1558 and read the selector. */
1559 IEMSELDESC DescSs;
1560 if (!(uNewOuterSs & X86_SEL_MASK_OFF_RPL))
1561 {
1562 if ( !DescCs.Legacy.Gen.u1Long
1563 || (uNewOuterSs & X86_SEL_RPL) == 3)
1564 {
1565 Log(("retf %04x:%08RX64 %04x:%08RX64 -> invalid stack selector, #GP\n",
1566 uNewCs, uNewRip, uNewOuterSs, uNewOuterRsp));
1567 return iemRaiseGeneralProtectionFault0(pIemCpu);
1568 }
1569 /** @todo Testcase: Return far to ring-1 or ring-2 with SS=0. */
1570 iemMemFakeStackSelDesc(&DescSs, (uNewOuterSs & X86_SEL_RPL));
1571 }
1572 else
1573 {
1574 /* Fetch the descriptor for the new stack segment. */
1575 rcStrict = iemMemFetchSelDesc(pIemCpu, &DescSs, uNewOuterSs, X86_XCPT_GP);
1576 if (rcStrict != VINF_SUCCESS)
1577 return rcStrict;
1578 }
1579
1580 /* Check that RPL of stack and code selectors match. */
1581 if ((uNewCs & X86_SEL_RPL) != (uNewOuterSs & X86_SEL_RPL))
1582 {
1583 Log(("retf %04x:%08RX64 %04x:%08RX64 - SS.RPL != CS.RPL -> #GP(SS)\n", uNewCs, uNewRip, uNewOuterSs, uNewOuterRsp));
1584 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewOuterSs);
1585 }
1586
1587 /* Must be a writable data segment. */
1588 if ( !DescSs.Legacy.Gen.u1DescType
1589 || (DescSs.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
1590 || !(DescSs.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
1591 {
1592 Log(("retf %04x:%08RX64 %04x:%08RX64 - SS not a writable data segment (u1DescType=%u u4Type=%#x) -> #GP(SS).\n",
1593 uNewCs, uNewRip, uNewOuterSs, uNewOuterRsp, DescSs.Legacy.Gen.u1DescType, DescSs.Legacy.Gen.u4Type));
1594 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewOuterSs);
1595 }
1596
1597 /* L vs D. (Not mentioned by intel.) */
1598 if ( DescSs.Legacy.Gen.u1Long /** @todo Testcase: far return to a stack selector with both L and D set. */
1599 && DescSs.Legacy.Gen.u1DefBig
1600 && IEM_IS_LONG_MODE(pIemCpu))
1601 {
1602 Log(("retf %04x:%08RX64 %04x:%08RX64 - SS has both L & D set -> #GP(SS).\n",
1603 uNewCs, uNewRip, uNewOuterSs, uNewOuterRsp, DescSs.Legacy.Gen.u1DescType, DescSs.Legacy.Gen.u4Type));
1604 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewOuterSs);
1605 }
1606
1607 /* DPL/RPL/CPL checks. */
1608 if (DescSs.Legacy.Gen.u2Dpl != (uNewCs & X86_SEL_RPL))
1609 {
1610 Log(("retf %04x:%08RX64 %04x:%08RX64 - SS.DPL(%u) != CS.RPL (%u) -> #GP(SS).\n",
1611 uNewCs, uNewRip, uNewOuterSs, uNewOuterRsp, DescSs.Legacy.Gen.u2Dpl, uNewCs & X86_SEL_RPL));
1612 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewOuterSs);
1613 }
1614
1615 /* Is it there? */
1616 if (!DescSs.Legacy.Gen.u1Present)
1617 {
1618 Log(("retf %04x:%08RX64 %04x:%08RX64 - SS not present -> #NP(SS).\n", uNewCs, uNewRip, uNewOuterSs, uNewOuterRsp));
1619 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uNewCs);
1620 }
1621
1622 /* Calc SS limit.*/
1623 uint32_t cbLimitSs = X86DESC_LIMIT_G(&DescSs.Legacy);
1624
1625 /* Is RIP canonical or within CS.limit? */
1626 uint64_t u64Base;
1627 uint32_t cbLimitCs = X86DESC_LIMIT_G(&DescCs.Legacy);
1628
1629 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
1630 {
1631 if (!IEM_IS_CANONICAL(uNewRip))
1632 {
1633 Log(("retf %04x:%08RX64 %04x:%08RX64 - not canonical -> #GP.\n", uNewCs, uNewRip, uNewOuterSs, uNewOuterRsp));
1634 return iemRaiseNotCanonical(pIemCpu);
1635 }
1636 u64Base = 0;
1637 }
1638 else
1639 {
1640 if (uNewRip > cbLimitCs)
1641 {
1642 Log(("retf %04x:%08RX64 %04x:%08RX64 - out of bounds (%#x)-> #GP(CS).\n",
1643 uNewCs, uNewRip, uNewOuterSs, uNewOuterRsp, cbLimitCs));
1644 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
1645 }
1646 u64Base = X86DESC_BASE(&DescCs.Legacy);
1647 }
1648
1649 /*
1650 * Now set the accessed bit before
1651 * writing the return address to the stack and committing the result into
1652 * CS, CSHID and RIP.
1653 */
1654 /** @todo Testcase: Need to check WHEN exactly the CS accessed bit is set. */
1655 if (!(DescCs.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1656 {
1657 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uNewCs);
1658 if (rcStrict != VINF_SUCCESS)
1659 return rcStrict;
1660 /** @todo check what VT-x and AMD-V does. */
1661 DescCs.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1662 }
1663 /** @todo Testcase: Need to check WHEN exactly the SS accessed bit is set. */
1664 if (!(DescSs.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1665 {
1666 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uNewOuterSs);
1667 if (rcStrict != VINF_SUCCESS)
1668 return rcStrict;
1669 /** @todo check what VT-x and AMD-V does. */
1670 DescSs.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1671 }
1672
1673 /* commit */
1674 rcStrict = iemMemStackPopCommitSpecial(pIemCpu, uPtrFrame.pv, uNewRsp);
1675 if (rcStrict != VINF_SUCCESS)
1676 return rcStrict;
1677 if (enmEffOpSize == IEMMODE_16BIT)
1678 pCtx->rip = uNewRip & UINT16_MAX; /** @todo Testcase: When exactly does this occur? With call it happens prior to the limit check according to Intel... */
1679 else
1680 pCtx->rip = uNewRip;
1681 pCtx->cs.Sel = uNewCs;
1682 pCtx->cs.ValidSel = uNewCs;
1683 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
1684 pCtx->cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCs.Legacy);
1685 pCtx->cs.u32Limit = cbLimitCs;
1686 pCtx->cs.u64Base = u64Base;
1687 pCtx->rsp = uNewRsp;
1688 pCtx->ss.Sel = uNewOuterSs;
1689 pCtx->ss.ValidSel = uNewOuterSs;
1690 pCtx->ss.fFlags = CPUMSELREG_FLAGS_VALID;
1691 pCtx->ss.Attr.u = X86DESC_GET_HID_ATTR(&DescSs.Legacy);
1692 pCtx->ss.u32Limit = cbLimitSs;
1693 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
1694 pCtx->ss.u64Base = 0;
1695 else
1696 pCtx->ss.u64Base = X86DESC_BASE(&DescSs.Legacy);
1697
1698 pIemCpu->uCpl = (uNewCs & X86_SEL_RPL);
1699 iemHlpAdjustSelectorForNewCpl(pIemCpu, uNewCs & X86_SEL_RPL, &pCtx->ds);
1700 iemHlpAdjustSelectorForNewCpl(pIemCpu, uNewCs & X86_SEL_RPL, &pCtx->es);
1701 iemHlpAdjustSelectorForNewCpl(pIemCpu, uNewCs & X86_SEL_RPL, &pCtx->fs);
1702 iemHlpAdjustSelectorForNewCpl(pIemCpu, uNewCs & X86_SEL_RPL, &pCtx->gs);
1703
1704 /** @todo check if the hidden bits are loaded correctly for 64-bit
1705 * mode. */
1706
1707 if (cbPop)
1708 iemRegAddToRsp(pIemCpu, pCtx, cbPop);
1709 pCtx->eflags.Bits.u1RF = 0;
1710
1711 /* Done! */
1712 }
1713 /*
1714 * Return to the same privilege level
1715 */
1716 else
1717 {
1718 /* Limit / canonical check. */
1719 uint64_t u64Base;
1720 uint32_t cbLimitCs = X86DESC_LIMIT_G(&DescCs.Legacy);
1721
1722 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
1723 {
1724 if (!IEM_IS_CANONICAL(uNewRip))
1725 {
1726 Log(("retf %04x:%08RX64 - not canonical -> #GP\n", uNewCs, uNewRip));
1727 return iemRaiseNotCanonical(pIemCpu);
1728 }
1729 u64Base = 0;
1730 }
1731 else
1732 {
1733 if (uNewRip > cbLimitCs)
1734 {
1735 Log(("retf %04x:%08RX64 -> out of bounds (%#x)\n", uNewCs, uNewRip, cbLimitCs));
1736 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
1737 }
1738 u64Base = X86DESC_BASE(&DescCs.Legacy);
1739 }
1740
1741 /*
1742 * Now set the accessed bit before
1743 * writing the return address to the stack and committing the result into
1744 * CS, CSHID and RIP.
1745 */
1746 /** @todo Testcase: Need to check WHEN exactly the accessed bit is set. */
1747 if (!(DescCs.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1748 {
1749 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uNewCs);
1750 if (rcStrict != VINF_SUCCESS)
1751 return rcStrict;
1752 /** @todo check what VT-x and AMD-V does. */
1753 DescCs.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1754 }
1755
1756 /* commit */
1757 rcStrict = iemMemStackPopCommitSpecial(pIemCpu, uPtrFrame.pv, uNewRsp);
1758 if (rcStrict != VINF_SUCCESS)
1759 return rcStrict;
1760 if (enmEffOpSize == IEMMODE_16BIT)
1761 pCtx->rip = uNewRip & UINT16_MAX; /** @todo Testcase: When exactly does this occur? With call it happens prior to the limit check according to Intel... */
1762 else
1763 pCtx->rip = uNewRip;
1764 pCtx->cs.Sel = uNewCs;
1765 pCtx->cs.ValidSel = uNewCs;
1766 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
1767 pCtx->cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCs.Legacy);
1768 pCtx->cs.u32Limit = cbLimitCs;
1769 pCtx->cs.u64Base = u64Base;
1770 /** @todo check if the hidden bits are loaded correctly for 64-bit
1771 * mode. */
1772 if (cbPop)
1773 iemRegAddToRsp(pIemCpu, pCtx, cbPop);
1774 pCtx->eflags.Bits.u1RF = 0;
1775 }
1776 return VINF_SUCCESS;
1777}
1778
1779
1780/**
1781 * Implements retn.
1782 *
1783 * We're doing this in C because of the \#GP that might be raised if the popped
1784 * program counter is out of bounds.
1785 *
1786 * @param enmEffOpSize The effective operand size.
1787 * @param cbPop The amount of arguments to pop from the stack
1788 * (bytes).
1789 */
1790IEM_CIMPL_DEF_2(iemCImpl_retn, IEMMODE, enmEffOpSize, uint16_t, cbPop)
1791{
1792 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1793 NOREF(cbInstr);
1794
1795 /* Fetch the RSP from the stack. */
1796 VBOXSTRICTRC rcStrict;
1797 RTUINT64U NewRip;
1798 RTUINT64U NewRsp;
1799 NewRsp.u = pCtx->rsp;
1800 switch (enmEffOpSize)
1801 {
1802 case IEMMODE_16BIT:
1803 NewRip.u = 0;
1804 rcStrict = iemMemStackPopU16Ex(pIemCpu, &NewRip.Words.w0, &NewRsp);
1805 break;
1806 case IEMMODE_32BIT:
1807 NewRip.u = 0;
1808 rcStrict = iemMemStackPopU32Ex(pIemCpu, &NewRip.DWords.dw0, &NewRsp);
1809 break;
1810 case IEMMODE_64BIT:
1811 rcStrict = iemMemStackPopU64Ex(pIemCpu, &NewRip.u, &NewRsp);
1812 break;
1813 IEM_NOT_REACHED_DEFAULT_CASE_RET();
1814 }
1815 if (rcStrict != VINF_SUCCESS)
1816 return rcStrict;
1817
1818 /* Check the new RSP before loading it. */
1819 /** @todo Should test this as the intel+amd pseudo code doesn't mention half
1820 * of it. The canonical test is performed here and for call. */
1821 if (enmEffOpSize != IEMMODE_64BIT)
1822 {
1823 if (NewRip.DWords.dw0 > pCtx->cs.u32Limit)
1824 {
1825 Log(("retn newrip=%llx - out of bounds (%x) -> #GP\n", NewRip.u, pCtx->cs.u32Limit));
1826 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
1827 }
1828 }
1829 else
1830 {
1831 if (!IEM_IS_CANONICAL(NewRip.u))
1832 {
1833 Log(("retn newrip=%llx - not canonical -> #GP\n", NewRip.u));
1834 return iemRaiseNotCanonical(pIemCpu);
1835 }
1836 }
1837
1838 /* Commit it. */
1839 pCtx->rip = NewRip.u;
1840 pCtx->rsp = NewRsp.u;
1841 if (cbPop)
1842 iemRegAddToRsp(pIemCpu, pCtx, cbPop);
1843 pCtx->eflags.Bits.u1RF = 0;
1844
1845 return VINF_SUCCESS;
1846}
1847
1848
1849/**
1850 * Implements enter.
1851 *
1852 * We're doing this in C because the instruction is insane, even for the
1853 * u8NestingLevel=0 case dealing with the stack is tedious.
1854 *
1855 * @param enmEffOpSize The effective operand size.
1856 */
1857IEM_CIMPL_DEF_3(iemCImpl_enter, IEMMODE, enmEffOpSize, uint16_t, cbFrame, uint8_t, cParameters)
1858{
1859 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1860
1861 /* Push RBP, saving the old value in TmpRbp. */
1862 RTUINT64U NewRsp; NewRsp.u = pCtx->rsp;
1863 RTUINT64U TmpRbp; TmpRbp.u = pCtx->rbp;
1864 RTUINT64U NewRbp;
1865 VBOXSTRICTRC rcStrict;
1866 if (enmEffOpSize == IEMMODE_64BIT)
1867 {
1868 rcStrict = iemMemStackPushU64Ex(pIemCpu, TmpRbp.u, &NewRsp);
1869 NewRbp = NewRsp;
1870 }
1871 else if (pCtx->ss.Attr.n.u1DefBig)
1872 {
1873 rcStrict = iemMemStackPushU32Ex(pIemCpu, TmpRbp.DWords.dw0, &NewRsp);
1874 NewRbp = NewRsp;
1875 }
1876 else
1877 {
1878 rcStrict = iemMemStackPushU16Ex(pIemCpu, TmpRbp.Words.w0, &NewRsp);
1879 NewRbp = TmpRbp;
1880 NewRbp.Words.w0 = NewRsp.Words.w0;
1881 }
1882 if (rcStrict != VINF_SUCCESS)
1883 return rcStrict;
1884
1885 /* Copy the parameters (aka nesting levels by Intel). */
1886 cParameters &= 0x1f;
1887 if (cParameters > 0)
1888 {
1889 switch (enmEffOpSize)
1890 {
1891 case IEMMODE_16BIT:
1892 if (pCtx->ss.Attr.n.u1DefBig)
1893 TmpRbp.DWords.dw0 -= 2;
1894 else
1895 TmpRbp.Words.w0 -= 2;
1896 do
1897 {
1898 uint16_t u16Tmp;
1899 rcStrict = iemMemStackPopU16Ex(pIemCpu, &u16Tmp, &TmpRbp);
1900 if (rcStrict != VINF_SUCCESS)
1901 break;
1902 rcStrict = iemMemStackPushU16Ex(pIemCpu, u16Tmp, &NewRsp);
1903 } while (--cParameters > 0 && rcStrict == VINF_SUCCESS);
1904 break;
1905
1906 case IEMMODE_32BIT:
1907 if (pCtx->ss.Attr.n.u1DefBig)
1908 TmpRbp.DWords.dw0 -= 4;
1909 else
1910 TmpRbp.Words.w0 -= 4;
1911 do
1912 {
1913 uint32_t u32Tmp;
1914 rcStrict = iemMemStackPopU32Ex(pIemCpu, &u32Tmp, &TmpRbp);
1915 if (rcStrict != VINF_SUCCESS)
1916 break;
1917 rcStrict = iemMemStackPushU32Ex(pIemCpu, u32Tmp, &NewRsp);
1918 } while (--cParameters > 0 && rcStrict == VINF_SUCCESS);
1919 break;
1920
1921 case IEMMODE_64BIT:
1922 TmpRbp.u -= 8;
1923 do
1924 {
1925 uint64_t u64Tmp;
1926 rcStrict = iemMemStackPopU64Ex(pIemCpu, &u64Tmp, &TmpRbp);
1927 if (rcStrict != VINF_SUCCESS)
1928 break;
1929 rcStrict = iemMemStackPushU64Ex(pIemCpu, u64Tmp, &NewRsp);
1930 } while (--cParameters > 0 && rcStrict == VINF_SUCCESS);
1931 break;
1932
1933 IEM_NOT_REACHED_DEFAULT_CASE_RET();
1934 }
1935 if (rcStrict != VINF_SUCCESS)
1936 return VINF_SUCCESS;
1937
1938 /* Push the new RBP */
1939 if (enmEffOpSize == IEMMODE_64BIT)
1940 rcStrict = iemMemStackPushU64Ex(pIemCpu, NewRbp.u, &NewRsp);
1941 else if (pCtx->ss.Attr.n.u1DefBig)
1942 rcStrict = iemMemStackPushU32Ex(pIemCpu, NewRbp.DWords.dw0, &NewRsp);
1943 else
1944 rcStrict = iemMemStackPushU16Ex(pIemCpu, NewRbp.Words.w0, &NewRsp);
1945 if (rcStrict != VINF_SUCCESS)
1946 return rcStrict;
1947
1948 }
1949
1950 /* Recalc RSP. */
1951 iemRegSubFromRspEx(pIemCpu, pCtx, &NewRsp, cbFrame);
1952
1953 /** @todo Should probe write access at the new RSP according to AMD. */
1954
1955 /* Commit it. */
1956 pCtx->rbp = NewRbp.u;
1957 pCtx->rsp = NewRsp.u;
1958 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
1959
1960 return VINF_SUCCESS;
1961}
1962
1963
1964
1965/**
1966 * Implements leave.
1967 *
1968 * We're doing this in C because messing with the stack registers is annoying
1969 * since they depends on SS attributes.
1970 *
1971 * @param enmEffOpSize The effective operand size.
1972 */
1973IEM_CIMPL_DEF_1(iemCImpl_leave, IEMMODE, enmEffOpSize)
1974{
1975 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1976
1977 /* Calculate the intermediate RSP from RBP and the stack attributes. */
1978 RTUINT64U NewRsp;
1979 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
1980 NewRsp.u = pCtx->rbp;
1981 else if (pCtx->ss.Attr.n.u1DefBig)
1982 NewRsp.u = pCtx->ebp;
1983 else
1984 {
1985 /** @todo Check that LEAVE actually preserve the high EBP bits. */
1986 NewRsp.u = pCtx->rsp;
1987 NewRsp.Words.w0 = pCtx->bp;
1988 }
1989
1990 /* Pop RBP according to the operand size. */
1991 VBOXSTRICTRC rcStrict;
1992 RTUINT64U NewRbp;
1993 switch (enmEffOpSize)
1994 {
1995 case IEMMODE_16BIT:
1996 NewRbp.u = pCtx->rbp;
1997 rcStrict = iemMemStackPopU16Ex(pIemCpu, &NewRbp.Words.w0, &NewRsp);
1998 break;
1999 case IEMMODE_32BIT:
2000 NewRbp.u = 0;
2001 rcStrict = iemMemStackPopU32Ex(pIemCpu, &NewRbp.DWords.dw0, &NewRsp);
2002 break;
2003 case IEMMODE_64BIT:
2004 rcStrict = iemMemStackPopU64Ex(pIemCpu, &NewRbp.u, &NewRsp);
2005 break;
2006 IEM_NOT_REACHED_DEFAULT_CASE_RET();
2007 }
2008 if (rcStrict != VINF_SUCCESS)
2009 return rcStrict;
2010
2011
2012 /* Commit it. */
2013 pCtx->rbp = NewRbp.u;
2014 pCtx->rsp = NewRsp.u;
2015 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
2016
2017 return VINF_SUCCESS;
2018}
2019
2020
2021/**
2022 * Implements int3 and int XX.
2023 *
2024 * @param u8Int The interrupt vector number.
2025 * @param fIsBpInstr Is it the breakpoint instruction.
2026 */
2027IEM_CIMPL_DEF_2(iemCImpl_int, uint8_t, u8Int, bool, fIsBpInstr)
2028{
2029 Assert(pIemCpu->cXcptRecursions == 0);
2030 return iemRaiseXcptOrInt(pIemCpu,
2031 cbInstr,
2032 u8Int,
2033 (fIsBpInstr ? IEM_XCPT_FLAGS_BP_INSTR : 0) | IEM_XCPT_FLAGS_T_SOFT_INT,
2034 0,
2035 0);
2036}
2037
2038
2039/**
2040 * Implements iret for real mode and V8086 mode.
2041 *
2042 * @param enmEffOpSize The effective operand size.
2043 */
2044IEM_CIMPL_DEF_1(iemCImpl_iret_real_v8086, IEMMODE, enmEffOpSize)
2045{
2046 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2047 X86EFLAGS Efl;
2048 Efl.u = IEMMISC_GET_EFL(pIemCpu, pCtx);
2049 NOREF(cbInstr);
2050
2051 /*
2052 * iret throws an exception if VME isn't enabled.
2053 */
2054 if ( Efl.Bits.u1VM
2055 && Efl.Bits.u2IOPL != 3
2056 && !(pCtx->cr4 & X86_CR4_VME))
2057 return iemRaiseGeneralProtectionFault0(pIemCpu);
2058
2059 /*
2060 * Do the stack bits, but don't commit RSP before everything checks
2061 * out right.
2062 */
2063 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
2064 VBOXSTRICTRC rcStrict;
2065 RTCPTRUNION uFrame;
2066 uint16_t uNewCs;
2067 uint32_t uNewEip;
2068 uint32_t uNewFlags;
2069 uint64_t uNewRsp;
2070 if (enmEffOpSize == IEMMODE_32BIT)
2071 {
2072 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 12, &uFrame.pv, &uNewRsp);
2073 if (rcStrict != VINF_SUCCESS)
2074 return rcStrict;
2075 uNewEip = uFrame.pu32[0];
2076 if (uNewEip > UINT16_MAX)
2077 return iemRaiseGeneralProtectionFault0(pIemCpu);
2078
2079 uNewCs = (uint16_t)uFrame.pu32[1];
2080 uNewFlags = uFrame.pu32[2];
2081 uNewFlags &= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
2082 | X86_EFL_TF | X86_EFL_IF | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT
2083 | X86_EFL_RF /*| X86_EFL_VM*/ | X86_EFL_AC /*|X86_EFL_VIF*/ /*|X86_EFL_VIP*/
2084 | X86_EFL_ID;
2085 uNewFlags |= Efl.u & (X86_EFL_VM | X86_EFL_VIF | X86_EFL_VIP | X86_EFL_1);
2086 }
2087 else
2088 {
2089 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 6, &uFrame.pv, &uNewRsp);
2090 if (rcStrict != VINF_SUCCESS)
2091 return rcStrict;
2092 uNewEip = uFrame.pu16[0];
2093 uNewCs = uFrame.pu16[1];
2094 uNewFlags = uFrame.pu16[2];
2095 uNewFlags &= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
2096 | X86_EFL_TF | X86_EFL_IF | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT;
2097 uNewFlags |= Efl.u & (UINT32_C(0xffff0000) | X86_EFL_1);
2098 /** @todo The intel pseudo code does not indicate what happens to
2099 * reserved flags. We just ignore them. */
2100 }
2101 /** @todo Check how this is supposed to work if sp=0xfffe. */
2102
2103 /*
2104 * Check the limit of the new EIP.
2105 */
2106 /** @todo Only the AMD pseudo code check the limit here, what's
2107 * right? */
2108 if (uNewEip > pCtx->cs.u32Limit)
2109 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
2110
2111 /*
2112 * V8086 checks and flag adjustments
2113 */
2114 if (Efl.Bits.u1VM)
2115 {
2116 if (Efl.Bits.u2IOPL == 3)
2117 {
2118 /* Preserve IOPL and clear RF. */
2119 uNewFlags &= ~(X86_EFL_IOPL | X86_EFL_RF);
2120 uNewFlags |= Efl.u & (X86_EFL_IOPL);
2121 }
2122 else if ( enmEffOpSize == IEMMODE_16BIT
2123 && ( !(uNewFlags & X86_EFL_IF)
2124 || !Efl.Bits.u1VIP )
2125 && !(uNewFlags & X86_EFL_TF) )
2126 {
2127 /* Move IF to VIF, clear RF and preserve IF and IOPL.*/
2128 uNewFlags &= ~X86_EFL_VIF;
2129 uNewFlags |= (uNewFlags & X86_EFL_IF) << (19 - 9);
2130 uNewFlags &= ~(X86_EFL_IF | X86_EFL_IOPL | X86_EFL_RF);
2131 uNewFlags |= Efl.u & (X86_EFL_IF | X86_EFL_IOPL);
2132 }
2133 else
2134 return iemRaiseGeneralProtectionFault0(pIemCpu);
2135 }
2136
2137 /*
2138 * Commit the operation.
2139 */
2140 rcStrict = iemMemStackPopCommitSpecial(pIemCpu, uFrame.pv, uNewRsp);
2141 if (rcStrict != VINF_SUCCESS)
2142 return rcStrict;
2143#ifdef DBGFTRACE_ENABLED
2144 RTTraceBufAddMsgF(IEMCPU_TO_VM(pIemCpu)->CTX_SUFF(hTraceBuf), "iret/rm %04x:%04x -> %04x:%04x %x %04llx",
2145 pCtx->cs.Sel, pCtx->eip, uNewCs, uNewEip, uNewFlags, uNewRsp);
2146#endif
2147
2148 pCtx->rip = uNewEip;
2149 pCtx->cs.Sel = uNewCs;
2150 pCtx->cs.ValidSel = uNewCs;
2151 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
2152 pCtx->cs.u64Base = (uint32_t)uNewCs << 4;
2153 /** @todo do we load attribs and limit as well? */
2154 Assert(uNewFlags & X86_EFL_1);
2155 IEMMISC_SET_EFL(pIemCpu, pCtx, uNewFlags);
2156
2157 return VINF_SUCCESS;
2158}
2159
2160
2161/**
2162 * Loads a segment register when entering V8086 mode.
2163 *
2164 * @param pSReg The segment register.
2165 * @param uSeg The segment to load.
2166 */
2167static void iemCImplCommonV8086LoadSeg(PCPUMSELREG pSReg, uint16_t uSeg)
2168{
2169 pSReg->Sel = uSeg;
2170 pSReg->ValidSel = uSeg;
2171 pSReg->fFlags = CPUMSELREG_FLAGS_VALID;
2172 pSReg->u64Base = (uint32_t)uSeg << 4;
2173 pSReg->u32Limit = 0xffff;
2174 pSReg->Attr.u = X86_SEL_TYPE_RW_ACC | RT_BIT(4) /*!sys*/ | RT_BIT(7) /*P*/ | (3 /*DPL*/ << 5); /* VT-x wants 0xf3 */
2175 /** @todo Testcase: Check if VT-x really needs this and what it does itself when
2176 * IRET'ing to V8086. */
2177}
2178
2179
2180/**
2181 * Implements iret for protected mode returning to V8086 mode.
2182 *
2183 * @param pCtx Pointer to the CPU context.
2184 * @param uNewEip The new EIP.
2185 * @param uNewCs The new CS.
2186 * @param uNewFlags The new EFLAGS.
2187 * @param uNewRsp The RSP after the initial IRET frame.
2188 *
2189 * @note This can only be a 32-bit iret du to the X86_EFL_VM position.
2190 */
2191IEM_CIMPL_DEF_5(iemCImpl_iret_prot_v8086, PCPUMCTX, pCtx, uint32_t, uNewEip, uint16_t, uNewCs,
2192 uint32_t, uNewFlags, uint64_t, uNewRsp)
2193{
2194 /*
2195 * Pop the V8086 specific frame bits off the stack.
2196 */
2197 VBOXSTRICTRC rcStrict;
2198 RTCPTRUNION uFrame;
2199 rcStrict = iemMemStackPopContinueSpecial(pIemCpu, 24, &uFrame.pv, &uNewRsp);
2200 if (rcStrict != VINF_SUCCESS)
2201 return rcStrict;
2202 uint32_t uNewEsp = uFrame.pu32[0];
2203 uint16_t uNewSs = uFrame.pu32[1];
2204 uint16_t uNewEs = uFrame.pu32[2];
2205 uint16_t uNewDs = uFrame.pu32[3];
2206 uint16_t uNewFs = uFrame.pu32[4];
2207 uint16_t uNewGs = uFrame.pu32[5];
2208 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)uFrame.pv, IEM_ACCESS_STACK_R); /* don't use iemMemStackPopCommitSpecial here. */
2209 if (rcStrict != VINF_SUCCESS)
2210 return rcStrict;
2211
2212 /*
2213 * Commit the operation.
2214 */
2215 uNewFlags &= X86_EFL_LIVE_MASK;
2216 uNewFlags |= X86_EFL_RA1_MASK;
2217#ifdef DBGFTRACE_ENABLED
2218 RTTraceBufAddMsgF(IEMCPU_TO_VM(pIemCpu)->CTX_SUFF(hTraceBuf), "iret/p/v %04x:%08x -> %04x:%04x %x %04x:%04x",
2219 pCtx->cs.Sel, pCtx->eip, uNewCs, uNewEip, uNewFlags, uNewSs, uNewEsp);
2220#endif
2221
2222 IEMMISC_SET_EFL(pIemCpu, pCtx, uNewFlags);
2223 iemCImplCommonV8086LoadSeg(&pCtx->cs, uNewCs);
2224 iemCImplCommonV8086LoadSeg(&pCtx->ss, uNewSs);
2225 iemCImplCommonV8086LoadSeg(&pCtx->es, uNewEs);
2226 iemCImplCommonV8086LoadSeg(&pCtx->ds, uNewDs);
2227 iemCImplCommonV8086LoadSeg(&pCtx->fs, uNewFs);
2228 iemCImplCommonV8086LoadSeg(&pCtx->gs, uNewGs);
2229 pCtx->rip = uNewEip;
2230 pCtx->rsp = uNewEsp;
2231 pIemCpu->uCpl = 3;
2232
2233 return VINF_SUCCESS;
2234}
2235
2236
2237/**
2238 * Implements iret for protected mode returning via a nested task.
2239 *
2240 * @param enmEffOpSize The effective operand size.
2241 */
2242IEM_CIMPL_DEF_1(iemCImpl_iret_prot_NestedTask, IEMMODE, enmEffOpSize)
2243{
2244 IEM_RETURN_ASPECT_NOT_IMPLEMENTED();
2245}
2246
2247
2248/**
2249 * Implements iret for protected mode
2250 *
2251 * @param enmEffOpSize The effective operand size.
2252 */
2253IEM_CIMPL_DEF_1(iemCImpl_iret_prot, IEMMODE, enmEffOpSize)
2254{
2255 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2256 NOREF(cbInstr);
2257
2258 /*
2259 * Nested task return.
2260 */
2261 if (pCtx->eflags.Bits.u1NT)
2262 return IEM_CIMPL_CALL_1(iemCImpl_iret_prot_NestedTask, enmEffOpSize);
2263
2264 /*
2265 * Normal return.
2266 *
2267 * Do the stack bits, but don't commit RSP before everything checks
2268 * out right.
2269 */
2270 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
2271 VBOXSTRICTRC rcStrict;
2272 RTCPTRUNION uFrame;
2273 uint16_t uNewCs;
2274 uint32_t uNewEip;
2275 uint32_t uNewFlags;
2276 uint64_t uNewRsp;
2277 if (enmEffOpSize == IEMMODE_32BIT)
2278 {
2279 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 12, &uFrame.pv, &uNewRsp);
2280 if (rcStrict != VINF_SUCCESS)
2281 return rcStrict;
2282 uNewEip = uFrame.pu32[0];
2283 uNewCs = (uint16_t)uFrame.pu32[1];
2284 uNewFlags = uFrame.pu32[2];
2285 }
2286 else
2287 {
2288 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 6, &uFrame.pv, &uNewRsp);
2289 if (rcStrict != VINF_SUCCESS)
2290 return rcStrict;
2291 uNewEip = uFrame.pu16[0];
2292 uNewCs = uFrame.pu16[1];
2293 uNewFlags = uFrame.pu16[2];
2294 }
2295 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)uFrame.pv, IEM_ACCESS_STACK_R); /* don't use iemMemStackPopCommitSpecial here. */
2296 if (rcStrict != VINF_SUCCESS)
2297 return rcStrict;
2298
2299 /*
2300 * We're hopefully not returning to V8086 mode...
2301 */
2302 if ( (uNewFlags & X86_EFL_VM)
2303 && pIemCpu->uCpl == 0)
2304 {
2305 Assert(enmEffOpSize == IEMMODE_32BIT);
2306 return IEM_CIMPL_CALL_5(iemCImpl_iret_prot_v8086, pCtx, uNewEip, uNewCs, uNewFlags, uNewRsp);
2307 }
2308
2309 /*
2310 * Protected mode.
2311 */
2312 /* Read the CS descriptor. */
2313 if (!(uNewCs & X86_SEL_MASK_OFF_RPL))
2314 {
2315 Log(("iret %04x:%08x -> invalid CS selector, #GP(0)\n", uNewCs, uNewEip));
2316 return iemRaiseGeneralProtectionFault0(pIemCpu);
2317 }
2318
2319 IEMSELDESC DescCS;
2320 rcStrict = iemMemFetchSelDesc(pIemCpu, &DescCS, uNewCs, X86_XCPT_GP);
2321 if (rcStrict != VINF_SUCCESS)
2322 {
2323 Log(("iret %04x:%08x - rcStrict=%Rrc when fetching CS\n", uNewCs, uNewEip, VBOXSTRICTRC_VAL(rcStrict)));
2324 return rcStrict;
2325 }
2326
2327 /* Must be a code descriptor. */
2328 if (!DescCS.Legacy.Gen.u1DescType)
2329 {
2330 Log(("iret %04x:%08x - CS is system segment (%#x) -> #GP\n", uNewCs, uNewEip, DescCS.Legacy.Gen.u4Type));
2331 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
2332 }
2333 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE))
2334 {
2335 Log(("iret %04x:%08x - not code segment (%#x) -> #GP\n", uNewCs, uNewEip, DescCS.Legacy.Gen.u4Type));
2336 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
2337 }
2338
2339#ifdef VBOX_WITH_RAW_MODE_NOT_R0
2340 /* Raw ring-0 and ring-1 compression adjustments for PATM performance tricks and other CS leaks. */
2341 PVM pVM = IEMCPU_TO_VM(pIemCpu);
2342 if (EMIsRawRing0Enabled(pVM) && !HMIsEnabled(pVM))
2343 {
2344 if ((uNewCs & X86_SEL_RPL) == 1)
2345 {
2346 if ( pIemCpu->uCpl == 0
2347 && ( !EMIsRawRing1Enabled(pVM)
2348 || pCtx->cs.Sel == (uNewCs & X86_SEL_MASK_OFF_RPL)) )
2349 {
2350 Log(("iret: Ring-0 compression fix: uNewCS=%#x -> %#x\n", uNewCs, uNewCs & X86_SEL_MASK_OFF_RPL));
2351 uNewCs &= X86_SEL_MASK_OFF_RPL;
2352 }
2353# ifdef LOG_ENABLED
2354 else if (pIemCpu->uCpl <= 1 && EMIsRawRing1Enabled(pVM))
2355 Log(("iret: uNewCs=%#x genuine return to ring-1.\n", uNewCs));
2356# endif
2357 }
2358 else if ( (uNewCs & X86_SEL_RPL) == 2
2359 && EMIsRawRing1Enabled(pVM)
2360 && pIemCpu->uCpl <= 1)
2361 {
2362 Log(("iret: Ring-1 compression fix: uNewCS=%#x -> %#x\n", uNewCs, (uNewCs & X86_SEL_MASK_OFF_RPL) | 1));
2363 uNewCs = (uNewCs & X86_SEL_MASK_OFF_RPL) | 2;
2364 }
2365 }
2366#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
2367
2368
2369 /* Privilege checks. */
2370 if ((uNewCs & X86_SEL_RPL) < pIemCpu->uCpl)
2371 {
2372 Log(("iret %04x:%08x - RPL < CPL (%d) -> #GP\n", uNewCs, uNewEip, pIemCpu->uCpl));
2373 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
2374 }
2375 if ( (DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF)
2376 && (uNewCs & X86_SEL_RPL) < DescCS.Legacy.Gen.u2Dpl)
2377 {
2378 Log(("iret %04x:%08x - RPL < DPL (%d) -> #GP\n", uNewCs, uNewEip, DescCS.Legacy.Gen.u2Dpl));
2379 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
2380 }
2381
2382 /* Present? */
2383 if (!DescCS.Legacy.Gen.u1Present)
2384 {
2385 Log(("iret %04x:%08x - CS not present -> #NP\n", uNewCs, uNewEip));
2386 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uNewCs);
2387 }
2388
2389 uint32_t cbLimitCS = X86DESC_LIMIT_G(&DescCS.Legacy);
2390
2391 /*
2392 * Return to outer level?
2393 */
2394 if ((uNewCs & X86_SEL_RPL) != pIemCpu->uCpl)
2395 {
2396 uint16_t uNewSS;
2397 uint32_t uNewESP;
2398 if (enmEffOpSize == IEMMODE_32BIT)
2399 {
2400 rcStrict = iemMemStackPopContinueSpecial(pIemCpu, 8, &uFrame.pv, &uNewRsp);
2401 if (rcStrict != VINF_SUCCESS)
2402 return rcStrict;
2403 uNewESP = uFrame.pu32[0];
2404 uNewSS = (uint16_t)uFrame.pu32[1];
2405 }
2406 else
2407 {
2408 rcStrict = iemMemStackPopContinueSpecial(pIemCpu, 8, &uFrame.pv, &uNewRsp);
2409 if (rcStrict != VINF_SUCCESS)
2410 return rcStrict;
2411 uNewESP = uFrame.pu16[0];
2412 uNewSS = uFrame.pu16[1];
2413 }
2414 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)uFrame.pv, IEM_ACCESS_STACK_R);
2415 if (rcStrict != VINF_SUCCESS)
2416 return rcStrict;
2417
2418 /* Read the SS descriptor. */
2419 if (!(uNewSS & X86_SEL_MASK_OFF_RPL))
2420 {
2421 Log(("iret %04x:%08x/%04x:%08x -> invalid SS selector, #GP(0)\n", uNewCs, uNewEip, uNewSS, uNewESP));
2422 return iemRaiseGeneralProtectionFault0(pIemCpu);
2423 }
2424
2425 IEMSELDESC DescSS;
2426 rcStrict = iemMemFetchSelDesc(pIemCpu, &DescSS, uNewSS, X86_XCPT_GP); /** @todo Correct exception? */
2427 if (rcStrict != VINF_SUCCESS)
2428 {
2429 Log(("iret %04x:%08x/%04x:%08x - %Rrc when fetching SS\n",
2430 uNewCs, uNewEip, uNewSS, uNewESP, VBOXSTRICTRC_VAL(rcStrict)));
2431 return rcStrict;
2432 }
2433
2434 /* Privilege checks. */
2435 if ((uNewSS & X86_SEL_RPL) != (uNewCs & X86_SEL_RPL))
2436 {
2437 Log(("iret %04x:%08x/%04x:%08x -> SS.RPL != CS.RPL -> #GP\n", uNewCs, uNewEip, uNewSS, uNewESP));
2438 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewSS);
2439 }
2440 if (DescSS.Legacy.Gen.u2Dpl != (uNewCs & X86_SEL_RPL))
2441 {
2442 Log(("iret %04x:%08x/%04x:%08x -> SS.DPL (%d) != CS.RPL -> #GP\n",
2443 uNewCs, uNewEip, uNewSS, uNewESP, DescSS.Legacy.Gen.u2Dpl));
2444 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewSS);
2445 }
2446
2447 /* Must be a writeable data segment descriptor. */
2448 if (!DescSS.Legacy.Gen.u1DescType)
2449 {
2450 Log(("iret %04x:%08x/%04x:%08x -> SS is system segment (%#x) -> #GP\n",
2451 uNewCs, uNewEip, uNewSS, uNewESP, DescSS.Legacy.Gen.u4Type));
2452 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewSS);
2453 }
2454 if ((DescSS.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE)) != X86_SEL_TYPE_WRITE)
2455 {
2456 Log(("iret %04x:%08x/%04x:%08x - not writable data segment (%#x) -> #GP\n",
2457 uNewCs, uNewEip, uNewSS, uNewESP, DescSS.Legacy.Gen.u4Type));
2458 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewSS);
2459 }
2460
2461 /* Present? */
2462 if (!DescSS.Legacy.Gen.u1Present)
2463 {
2464 Log(("iret %04x:%08x/%04x:%08x -> SS not present -> #SS\n", uNewCs, uNewEip, uNewSS, uNewESP));
2465 return iemRaiseStackSelectorNotPresentBySelector(pIemCpu, uNewSS);
2466 }
2467
2468 uint32_t cbLimitSs = X86DESC_LIMIT_G(&DescSS.Legacy);
2469
2470 /* Check EIP. */
2471 if (uNewEip > cbLimitCS)
2472 {
2473 Log(("iret %04x:%08x/%04x:%08x -> EIP is out of bounds (%#x) -> #GP(0)\n",
2474 uNewCs, uNewEip, uNewSS, uNewESP, cbLimitCS));
2475 return iemRaiseSelectorBoundsBySelector(pIemCpu, uNewCs);
2476 }
2477
2478 /*
2479 * Commit the changes, marking CS and SS accessed first since
2480 * that may fail.
2481 */
2482 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
2483 {
2484 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uNewCs);
2485 if (rcStrict != VINF_SUCCESS)
2486 return rcStrict;
2487 DescCS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
2488 }
2489 if (!(DescSS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
2490 {
2491 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uNewSS);
2492 if (rcStrict != VINF_SUCCESS)
2493 return rcStrict;
2494 DescSS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
2495 }
2496
2497 uint32_t fEFlagsMask = X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
2498 | X86_EFL_TF | X86_EFL_DF | X86_EFL_OF | X86_EFL_NT;
2499 if (enmEffOpSize != IEMMODE_16BIT)
2500 fEFlagsMask |= X86_EFL_RF | X86_EFL_AC | X86_EFL_ID;
2501 if (pIemCpu->uCpl == 0)
2502 fEFlagsMask |= X86_EFL_IF | X86_EFL_IOPL | X86_EFL_VIF | X86_EFL_VIP; /* VM is 0 */
2503 else if (pIemCpu->uCpl <= pCtx->eflags.Bits.u2IOPL)
2504 fEFlagsMask |= X86_EFL_IF;
2505 uint32_t fEFlagsNew = IEMMISC_GET_EFL(pIemCpu, pCtx);
2506 fEFlagsNew &= ~fEFlagsMask;
2507 fEFlagsNew |= uNewFlags & fEFlagsMask;
2508#ifdef DBGFTRACE_ENABLED
2509 RTTraceBufAddMsgF(IEMCPU_TO_VM(pIemCpu)->CTX_SUFF(hTraceBuf), "iret/%up%u %04x:%08x -> %04x:%04x %x %04x:%04x",
2510 pIemCpu->uCpl, uNewCs & X86_SEL_RPL, pCtx->cs.Sel, pCtx->eip,
2511 uNewCs, uNewEip, uNewFlags, uNewSS, uNewESP);
2512#endif
2513
2514 IEMMISC_SET_EFL(pIemCpu, pCtx, fEFlagsNew);
2515 pCtx->rip = uNewEip;
2516 pCtx->cs.Sel = uNewCs;
2517 pCtx->cs.ValidSel = uNewCs;
2518 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
2519 pCtx->cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCS.Legacy);
2520 pCtx->cs.u32Limit = cbLimitCS;
2521 pCtx->cs.u64Base = X86DESC_BASE(&DescCS.Legacy);
2522 if (!pCtx->cs.Attr.n.u1DefBig)
2523 pCtx->sp = (uint16_t)uNewESP;
2524 else
2525 pCtx->rsp = uNewESP;
2526 pCtx->ss.Sel = uNewSS;
2527 pCtx->ss.ValidSel = uNewSS;
2528 pCtx->ss.fFlags = CPUMSELREG_FLAGS_VALID;
2529 pCtx->ss.Attr.u = X86DESC_GET_HID_ATTR(&DescSS.Legacy);
2530 pCtx->ss.u32Limit = cbLimitSs;
2531 pCtx->ss.u64Base = X86DESC_BASE(&DescSS.Legacy);
2532
2533 pIemCpu->uCpl = uNewCs & X86_SEL_RPL;
2534 iemHlpAdjustSelectorForNewCpl(pIemCpu, uNewCs & X86_SEL_RPL, &pCtx->ds);
2535 iemHlpAdjustSelectorForNewCpl(pIemCpu, uNewCs & X86_SEL_RPL, &pCtx->es);
2536 iemHlpAdjustSelectorForNewCpl(pIemCpu, uNewCs & X86_SEL_RPL, &pCtx->fs);
2537 iemHlpAdjustSelectorForNewCpl(pIemCpu, uNewCs & X86_SEL_RPL, &pCtx->gs);
2538
2539 /* Done! */
2540
2541 }
2542 /*
2543 * Return to the same level.
2544 */
2545 else
2546 {
2547 /* Check EIP. */
2548 if (uNewEip > cbLimitCS)
2549 {
2550 Log(("iret %04x:%08x - EIP is out of bounds (%#x) -> #GP(0)\n", uNewCs, uNewEip, cbLimitCS));
2551 return iemRaiseSelectorBoundsBySelector(pIemCpu, uNewCs);
2552 }
2553
2554 /*
2555 * Commit the changes, marking CS first since it may fail.
2556 */
2557 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
2558 {
2559 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uNewCs);
2560 if (rcStrict != VINF_SUCCESS)
2561 return rcStrict;
2562 DescCS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
2563 }
2564
2565 X86EFLAGS NewEfl;
2566 NewEfl.u = IEMMISC_GET_EFL(pIemCpu, pCtx);
2567 uint32_t fEFlagsMask = X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
2568 | X86_EFL_TF | X86_EFL_DF | X86_EFL_OF | X86_EFL_NT;
2569 if (enmEffOpSize != IEMMODE_16BIT)
2570 fEFlagsMask |= X86_EFL_RF | X86_EFL_AC | X86_EFL_ID;
2571 if (pIemCpu->uCpl == 0)
2572 fEFlagsMask |= X86_EFL_IF | X86_EFL_IOPL | X86_EFL_VIF | X86_EFL_VIP; /* VM is 0 */
2573 else if (pIemCpu->uCpl <= NewEfl.Bits.u2IOPL)
2574 fEFlagsMask |= X86_EFL_IF;
2575 NewEfl.u &= ~fEFlagsMask;
2576 NewEfl.u |= fEFlagsMask & uNewFlags;
2577#ifdef DBGFTRACE_ENABLED
2578 RTTraceBufAddMsgF(IEMCPU_TO_VM(pIemCpu)->CTX_SUFF(hTraceBuf), "iret/%up %04x:%08x -> %04x:%04x %x %04x:%04llx",
2579 pIemCpu->uCpl, pCtx->cs.Sel, pCtx->eip,
2580 uNewCs, uNewEip, uNewFlags, pCtx->ss.Sel, uNewRsp);
2581#endif
2582
2583 IEMMISC_SET_EFL(pIemCpu, pCtx, NewEfl.u);
2584 pCtx->rip = uNewEip;
2585 pCtx->cs.Sel = uNewCs;
2586 pCtx->cs.ValidSel = uNewCs;
2587 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
2588 pCtx->cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCS.Legacy);
2589 pCtx->cs.u32Limit = cbLimitCS;
2590 pCtx->cs.u64Base = X86DESC_BASE(&DescCS.Legacy);
2591 pCtx->rsp = uNewRsp;
2592 /* Done! */
2593 }
2594 return VINF_SUCCESS;
2595}
2596
2597
2598/**
2599 * Implements iret for long mode
2600 *
2601 * @param enmEffOpSize The effective operand size.
2602 */
2603IEM_CIMPL_DEF_1(iemCImpl_iret_long, IEMMODE, enmEffOpSize)
2604{
2605 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2606 NOREF(cbInstr);
2607
2608 /*
2609 * Nested task return is not supported in long mode.
2610 */
2611 if (pCtx->eflags.Bits.u1NT)
2612 {
2613 Log(("iretq with NT=1 (eflags=%#x) -> #GP(0)\n", pCtx->eflags.u));
2614 return iemRaiseGeneralProtectionFault0(pIemCpu);
2615 }
2616
2617 /*
2618 * Normal return.
2619 *
2620 * Do the stack bits, but don't commit RSP before everything checks
2621 * out right.
2622 */
2623 VBOXSTRICTRC rcStrict;
2624 RTCPTRUNION uFrame;
2625 uint64_t uNewRip;
2626 uint16_t uNewCs;
2627 uint16_t uNewSs;
2628 uint32_t uNewFlags;
2629 uint64_t uNewRsp;
2630 if (enmEffOpSize == IEMMODE_64BIT)
2631 {
2632 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 5*8, &uFrame.pv, &uNewRsp);
2633 if (rcStrict != VINF_SUCCESS)
2634 return rcStrict;
2635 uNewRip = uFrame.pu64[0];
2636 uNewCs = (uint16_t)uFrame.pu64[1];
2637 uNewFlags = (uint32_t)uFrame.pu64[2];
2638 uNewRsp = uFrame.pu64[3];
2639 uNewSs = (uint16_t)uFrame.pu64[4];
2640 }
2641 else if (enmEffOpSize == IEMMODE_32BIT)
2642 {
2643 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 5*4, &uFrame.pv, &uNewRsp);
2644 if (rcStrict != VINF_SUCCESS)
2645 return rcStrict;
2646 uNewRip = uFrame.pu32[0];
2647 uNewCs = (uint16_t)uFrame.pu32[1];
2648 uNewFlags = uFrame.pu32[2];
2649 uNewRsp = uFrame.pu32[3];
2650 uNewSs = (uint16_t)uFrame.pu32[4];
2651 }
2652 else
2653 {
2654 Assert(enmEffOpSize == IEMMODE_16BIT);
2655 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 5*2, &uFrame.pv, &uNewRsp);
2656 if (rcStrict != VINF_SUCCESS)
2657 return rcStrict;
2658 uNewRip = uFrame.pu16[0];
2659 uNewCs = uFrame.pu16[1];
2660 uNewFlags = uFrame.pu16[2];
2661 uNewRsp = uFrame.pu16[3];
2662 uNewSs = uFrame.pu16[4];
2663 }
2664 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)uFrame.pv, IEM_ACCESS_STACK_R); /* don't use iemMemStackPopCommitSpecial here. */
2665 if (rcStrict != VINF_SUCCESS)
2666 return rcStrict;
2667 Log2(("iretq stack: cs:rip=%04x:%016RX16 rflags=%016RX16 ss:rsp=%04x:%016RX16\n",
2668 uNewCs, uNewRip, uNewFlags, uNewSs, uNewRsp));
2669
2670 /*
2671 * Check stuff.
2672 */
2673 /* Read the CS descriptor. */
2674 if (!(uNewCs & X86_SEL_MASK_OFF_RPL))
2675 {
2676 Log(("iret %04x:%016RX64/%04x:%016RX64 -> invalid CS selector, #GP(0)\n", uNewCs, uNewRip, uNewSs, uNewRsp));
2677 return iemRaiseGeneralProtectionFault0(pIemCpu);
2678 }
2679
2680 IEMSELDESC DescCS;
2681 rcStrict = iemMemFetchSelDesc(pIemCpu, &DescCS, uNewCs, X86_XCPT_GP);
2682 if (rcStrict != VINF_SUCCESS)
2683 {
2684 Log(("iret %04x:%016RX64/%04x:%016RX64 - rcStrict=%Rrc when fetching CS\n",
2685 uNewCs, uNewRip, uNewSs, uNewRsp, VBOXSTRICTRC_VAL(rcStrict)));
2686 return rcStrict;
2687 }
2688
2689 /* Must be a code descriptor. */
2690 if ( !DescCS.Legacy.Gen.u1DescType
2691 || !(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE))
2692 {
2693 Log(("iret %04x:%016RX64/%04x:%016RX64 - CS is not a code segment T=%u T=%#xu -> #GP\n",
2694 uNewCs, uNewRip, uNewSs, uNewRsp, DescCS.Legacy.Gen.u1DescType, DescCS.Legacy.Gen.u4Type));
2695 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
2696 }
2697
2698 /* Privilege checks. */
2699 uint8_t const uNewCpl = uNewCs & X86_SEL_RPL;
2700 if ((uNewCs & X86_SEL_RPL) < pIemCpu->uCpl)
2701 {
2702 Log(("iret %04x:%016RX64/%04x:%016RX64 - RPL < CPL (%d) -> #GP\n", uNewCs, uNewRip, uNewSs, uNewRsp, pIemCpu->uCpl));
2703 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
2704 }
2705 if ( (DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF)
2706 && (uNewCs & X86_SEL_RPL) < DescCS.Legacy.Gen.u2Dpl)
2707 {
2708 Log(("iret %04x:%016RX64/%04x:%016RX64 - RPL < DPL (%d) -> #GP\n",
2709 uNewCs, uNewRip, uNewSs, uNewRsp, DescCS.Legacy.Gen.u2Dpl));
2710 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCs);
2711 }
2712
2713 /* Present? */
2714 if (!DescCS.Legacy.Gen.u1Present)
2715 {
2716 Log(("iret %04x:%016RX64/%04x:%016RX64 - CS not present -> #NP\n", uNewCs, uNewRip, uNewSs, uNewRsp));
2717 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uNewCs);
2718 }
2719
2720 uint32_t cbLimitCS = X86DESC_LIMIT_G(&DescCS.Legacy);
2721
2722 /* Read the SS descriptor. */
2723 IEMSELDESC DescSS;
2724 if (!(uNewSs & X86_SEL_MASK_OFF_RPL))
2725 {
2726 if ( !DescCS.Legacy.Gen.u1Long
2727 || DescCS.Legacy.Gen.u1DefBig /** @todo exactly how does iret (and others) behave with u1Long=1 and u1DefBig=1? \#GP(sel)? */
2728 || uNewCpl > 2) /** @todo verify SS=0 impossible for ring-3. */
2729 {
2730 Log(("iret %04x:%016RX64/%04x:%016RX64 -> invalid SS selector, #GP(0)\n", uNewCs, uNewRip, uNewSs, uNewRsp));
2731 return iemRaiseGeneralProtectionFault0(pIemCpu);
2732 }
2733 DescSS.Legacy.u = 0;
2734 }
2735 else
2736 {
2737 rcStrict = iemMemFetchSelDesc(pIemCpu, &DescSS, uNewSs, X86_XCPT_GP); /** @todo Correct exception? */
2738 if (rcStrict != VINF_SUCCESS)
2739 {
2740 Log(("iret %04x:%016RX64/%04x:%016RX64 - %Rrc when fetching SS\n",
2741 uNewCs, uNewRip, uNewSs, uNewRsp, VBOXSTRICTRC_VAL(rcStrict)));
2742 return rcStrict;
2743 }
2744 }
2745
2746 /* Privilege checks. */
2747 if ((uNewSs & X86_SEL_RPL) != (uNewCs & X86_SEL_RPL))
2748 {
2749 Log(("iret %04x:%016RX64/%04x:%016RX64 -> SS.RPL != CS.RPL -> #GP\n", uNewCs, uNewRip, uNewSs, uNewRsp));
2750 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewSs);
2751 }
2752
2753 uint32_t cbLimitSs;
2754 if (!(uNewSs & X86_SEL_MASK_OFF_RPL))
2755 cbLimitSs = UINT32_MAX;
2756 else
2757 {
2758 if (DescSS.Legacy.Gen.u2Dpl != (uNewCs & X86_SEL_RPL))
2759 {
2760 Log(("iret %04x:%016RX64/%04x:%016RX64 -> SS.DPL (%d) != CS.RPL -> #GP\n",
2761 uNewCs, uNewRip, uNewSs, uNewRsp, DescSS.Legacy.Gen.u2Dpl));
2762 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewSs);
2763 }
2764
2765 /* Must be a writeable data segment descriptor. */
2766 if (!DescSS.Legacy.Gen.u1DescType)
2767 {
2768 Log(("iret %04x:%016RX64/%04x:%016RX64 -> SS is system segment (%#x) -> #GP\n",
2769 uNewCs, uNewRip, uNewSs, uNewRsp, DescSS.Legacy.Gen.u4Type));
2770 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewSs);
2771 }
2772 if ((DescSS.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE)) != X86_SEL_TYPE_WRITE)
2773 {
2774 Log(("iret %04x:%016RX64/%04x:%016RX64 - not writable data segment (%#x) -> #GP\n",
2775 uNewCs, uNewRip, uNewSs, uNewRsp, DescSS.Legacy.Gen.u4Type));
2776 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewSs);
2777 }
2778
2779 /* Present? */
2780 if (!DescSS.Legacy.Gen.u1Present)
2781 {
2782 Log(("iret %04x:%016RX64/%04x:%016RX64 -> SS not present -> #SS\n", uNewCs, uNewRip, uNewSs, uNewRsp));
2783 return iemRaiseStackSelectorNotPresentBySelector(pIemCpu, uNewSs);
2784 }
2785 cbLimitSs = X86DESC_LIMIT_G(&DescSS.Legacy);
2786 }
2787
2788 /* Check EIP. */
2789 if (DescCS.Legacy.Gen.u1Long)
2790 {
2791 if (!IEM_IS_CANONICAL(uNewRip))
2792 {
2793 Log(("iret %04x:%016RX64/%04x:%016RX64 -> RIP is not canonical -> #GP(0)\n",
2794 uNewCs, uNewRip, uNewSs, uNewRsp));
2795 return iemRaiseSelectorBoundsBySelector(pIemCpu, uNewCs);
2796 }
2797 }
2798 else
2799 {
2800 if (uNewRip > cbLimitCS)
2801 {
2802 Log(("iret %04x:%016RX64/%04x:%016RX64 -> EIP is out of bounds (%#x) -> #GP(0)\n",
2803 uNewCs, uNewRip, uNewSs, uNewRsp, cbLimitCS));
2804 return iemRaiseSelectorBoundsBySelector(pIemCpu, uNewCs);
2805 }
2806 }
2807
2808 /*
2809 * Commit the changes, marking CS and SS accessed first since
2810 * that may fail.
2811 */
2812 /** @todo where exactly are these actually marked accessed by a real CPU? */
2813 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
2814 {
2815 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uNewCs);
2816 if (rcStrict != VINF_SUCCESS)
2817 return rcStrict;
2818 DescCS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
2819 }
2820 if (!(DescSS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
2821 {
2822 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uNewSs);
2823 if (rcStrict != VINF_SUCCESS)
2824 return rcStrict;
2825 DescSS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
2826 }
2827
2828 uint32_t fEFlagsMask = X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
2829 | X86_EFL_TF | X86_EFL_DF | X86_EFL_OF | X86_EFL_NT;
2830 if (enmEffOpSize != IEMMODE_16BIT)
2831 fEFlagsMask |= X86_EFL_RF | X86_EFL_AC | X86_EFL_ID;
2832 if (pIemCpu->uCpl == 0)
2833 fEFlagsMask |= X86_EFL_IF | X86_EFL_IOPL | X86_EFL_VIF | X86_EFL_VIP; /* VM is ignored */
2834 else if (pIemCpu->uCpl <= pCtx->eflags.Bits.u2IOPL)
2835 fEFlagsMask |= X86_EFL_IF;
2836 uint32_t fEFlagsNew = IEMMISC_GET_EFL(pIemCpu, pCtx);
2837 fEFlagsNew &= ~fEFlagsMask;
2838 fEFlagsNew |= uNewFlags & fEFlagsMask;
2839#ifdef DBGFTRACE_ENABLED
2840 RTTraceBufAddMsgF(IEMCPU_TO_VM(pIemCpu)->CTX_SUFF(hTraceBuf), "iret/%ul%u %08llx -> %04x:%04llx %llx %04x:%04llx",
2841 pIemCpu->uCpl, uNewCpl, pCtx->rip, uNewCs, uNewRip, uNewFlags, uNewSs, uNewRsp);
2842#endif
2843
2844 IEMMISC_SET_EFL(pIemCpu, pCtx, fEFlagsNew);
2845 pCtx->rip = uNewRip;
2846 pCtx->cs.Sel = uNewCs;
2847 pCtx->cs.ValidSel = uNewCs;
2848 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
2849 pCtx->cs.Attr.u = X86DESC_GET_HID_ATTR(&DescCS.Legacy);
2850 pCtx->cs.u32Limit = cbLimitCS;
2851 pCtx->cs.u64Base = X86DESC_BASE(&DescCS.Legacy);
2852 if (pCtx->cs.Attr.n.u1Long || pCtx->cs.Attr.n.u1DefBig)
2853 pCtx->rsp = uNewRsp;
2854 else
2855 pCtx->sp = (uint16_t)uNewRsp;
2856 pCtx->ss.Sel = uNewSs;
2857 pCtx->ss.ValidSel = uNewSs;
2858 if (!(uNewSs & X86_SEL_MASK_OFF_RPL))
2859 {
2860 pCtx->ss.fFlags = CPUMSELREG_FLAGS_VALID;
2861 pCtx->ss.Attr.u = X86DESCATTR_UNUSABLE | (uNewCpl << X86DESCATTR_DPL_SHIFT);
2862 pCtx->ss.u32Limit = UINT32_MAX;
2863 pCtx->ss.u64Base = 0;
2864 Log2(("iretq new SS: NULL\n"));
2865 }
2866 else
2867 {
2868 pCtx->ss.fFlags = CPUMSELREG_FLAGS_VALID;
2869 pCtx->ss.Attr.u = X86DESC_GET_HID_ATTR(&DescSS.Legacy);
2870 pCtx->ss.u32Limit = cbLimitSs;
2871 pCtx->ss.u64Base = X86DESC_BASE(&DescSS.Legacy);
2872 Log2(("iretq new SS: base=%#RX64 lim=%#x attr=%#x\n", pCtx->ss.u64Base, pCtx->ss.u32Limit, pCtx->ss.Attr.u));
2873 }
2874
2875 if (pIemCpu->uCpl != uNewCpl)
2876 {
2877 pIemCpu->uCpl = uNewCpl;
2878 iemHlpAdjustSelectorForNewCpl(pIemCpu, uNewCpl, &pCtx->ds);
2879 iemHlpAdjustSelectorForNewCpl(pIemCpu, uNewCpl, &pCtx->es);
2880 iemHlpAdjustSelectorForNewCpl(pIemCpu, uNewCpl, &pCtx->fs);
2881 iemHlpAdjustSelectorForNewCpl(pIemCpu, uNewCpl, &pCtx->gs);
2882 }
2883
2884 return VINF_SUCCESS;
2885}
2886
2887
2888/**
2889 * Implements iret.
2890 *
2891 * @param enmEffOpSize The effective operand size.
2892 */
2893IEM_CIMPL_DEF_1(iemCImpl_iret, IEMMODE, enmEffOpSize)
2894{
2895 /*
2896 * Call a mode specific worker.
2897 */
2898 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
2899 return IEM_CIMPL_CALL_1(iemCImpl_iret_real_v8086, enmEffOpSize);
2900 if (IEM_IS_LONG_MODE(pIemCpu))
2901 return IEM_CIMPL_CALL_1(iemCImpl_iret_long, enmEffOpSize);
2902
2903 return IEM_CIMPL_CALL_1(iemCImpl_iret_prot, enmEffOpSize);
2904}
2905
2906
2907/**
2908 * Implements SYSCALL (AMD and Intel64).
2909 *
2910 * @param enmEffOpSize The effective operand size.
2911 */
2912IEM_CIMPL_DEF_0(iemCImpl_syscall)
2913{
2914 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2915
2916 /*
2917 * Check preconditions.
2918 *
2919 * Note that CPUs described in the documentation may load a few odd values
2920 * into CS and SS than we allow here. This has yet to be checked on real
2921 * hardware.
2922 */
2923 if (!(pCtx->msrEFER & MSR_K6_EFER_SCE))
2924 {
2925 Log(("syscall: Not enabled in EFER -> #UD\n"));
2926 return iemRaiseUndefinedOpcode(pIemCpu);
2927 }
2928 if (!(pCtx->cr0 & X86_CR0_PE))
2929 {
2930 Log(("syscall: Protected mode is required -> #GP(0)\n"));
2931 return iemRaiseGeneralProtectionFault0(pIemCpu);
2932 }
2933 if (IEM_IS_GUEST_CPU_INTEL(pIemCpu) && !CPUMIsGuestInLongModeEx(pCtx))
2934 {
2935 Log(("syscall: Only available in long mode on intel -> #UD\n"));
2936 return iemRaiseUndefinedOpcode(pIemCpu);
2937 }
2938
2939 /** @todo verify RPL ignoring and CS=0xfff8 (i.e. SS == 0). */
2940 /** @todo what about LDT selectors? Shouldn't matter, really. */
2941 uint16_t uNewCs = (pCtx->msrSTAR >> MSR_K6_STAR_SYSCALL_CS_SS_SHIFT) & X86_SEL_MASK_OFF_RPL;
2942 uint16_t uNewSs = uNewCs + 8;
2943 if (uNewCs == 0 || uNewSs == 0)
2944 {
2945 Log(("syscall: msrSTAR.CS = 0 or SS = 0 -> #GP(0)\n"));
2946 return iemRaiseGeneralProtectionFault0(pIemCpu);
2947 }
2948
2949 /* Long mode and legacy mode differs. */
2950 if (CPUMIsGuestInLongModeEx(pCtx))
2951 {
2952 uint64_t uNewRip = pIemCpu->enmCpuMode == IEMMODE_64BIT ? pCtx->msrLSTAR : pCtx-> msrCSTAR;
2953
2954 /* This test isn't in the docs, but I'm not trusting the guys writing
2955 the MSRs to have validated the values as canonical like they should. */
2956 if (!IEM_IS_CANONICAL(uNewRip))
2957 {
2958 Log(("syscall: Only available in long mode on intel -> #UD\n"));
2959 return iemRaiseUndefinedOpcode(pIemCpu);
2960 }
2961
2962 /*
2963 * Commit it.
2964 */
2965 Log(("syscall: %04x:%016RX64 [efl=%#llx] -> %04x:%016RX64\n", pCtx->cs, pCtx->rip, pCtx->rflags.u, uNewCs, uNewRip));
2966 pCtx->rcx = pCtx->rip + cbInstr;
2967 pCtx->rip = uNewRip;
2968
2969 pCtx->rflags.u &= ~X86_EFL_RF;
2970 pCtx->r11 = pCtx->rflags.u;
2971 pCtx->rflags.u &= ~pCtx->msrSFMASK;
2972 pCtx->rflags.u |= X86_EFL_1;
2973
2974 pCtx->cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_L | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC;
2975 pCtx->ss.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_L | X86DESCATTR_DT | X86_SEL_TYPE_RW_ACC;
2976 }
2977 else
2978 {
2979 /*
2980 * Commit it.
2981 */
2982 Log(("syscall: %04x:%08RX32 [efl=%#x] -> %04x:%08RX32\n",
2983 pCtx->cs, pCtx->eip, pCtx->eflags.u, uNewCs, (uint32_t)(pCtx->msrSTAR & MSR_K6_STAR_SYSCALL_EIP_MASK)));
2984 pCtx->rcx = pCtx->eip + cbInstr;
2985 pCtx->rip = pCtx->msrSTAR & MSR_K6_STAR_SYSCALL_EIP_MASK;
2986 pCtx->rflags.u &= ~(X86_EFL_VM | X86_EFL_IF | X86_EFL_RF);
2987
2988 pCtx->cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC;
2989 pCtx->ss.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_RW_ACC;
2990 }
2991 pCtx->cs.Sel = uNewCs;
2992 pCtx->cs.ValidSel = uNewCs;
2993 pCtx->cs.u64Base = 0;
2994 pCtx->cs.u32Limit = UINT32_MAX;
2995 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
2996
2997 pCtx->ss.Sel = uNewSs;
2998 pCtx->ss.ValidSel = uNewSs;
2999 pCtx->ss.u64Base = 0;
3000 pCtx->ss.u32Limit = UINT32_MAX;
3001 pCtx->ss.fFlags = CPUMSELREG_FLAGS_VALID;
3002
3003 return VINF_SUCCESS;
3004}
3005
3006
3007/**
3008 * Implements SYSRET (AMD and Intel64).
3009 */
3010IEM_CIMPL_DEF_0(iemCImpl_sysret)
3011
3012{
3013 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3014
3015 /*
3016 * Check preconditions.
3017 *
3018 * Note that CPUs described in the documentation may load a few odd values
3019 * into CS and SS than we allow here. This has yet to be checked on real
3020 * hardware.
3021 */
3022 if (!(pCtx->msrEFER & MSR_K6_EFER_SCE))
3023 {
3024 Log(("sysret: Not enabled in EFER -> #UD\n"));
3025 return iemRaiseUndefinedOpcode(pIemCpu);
3026 }
3027 if (IEM_IS_GUEST_CPU_INTEL(pIemCpu) && !CPUMIsGuestInLongModeEx(pCtx))
3028 {
3029 Log(("sysret: Only available in long mode on intel -> #UD\n"));
3030 return iemRaiseUndefinedOpcode(pIemCpu);
3031 }
3032 if (!(pCtx->cr0 & X86_CR0_PE))
3033 {
3034 Log(("sysret: Protected mode is required -> #GP(0)\n"));
3035 return iemRaiseGeneralProtectionFault0(pIemCpu);
3036 }
3037 if (pIemCpu->uCpl != 0)
3038 {
3039 Log(("sysret: CPL must be 0 not %u -> #GP(0)\n", pIemCpu->uCpl));
3040 return iemRaiseGeneralProtectionFault0(pIemCpu);
3041 }
3042
3043 /** @todo Does SYSRET verify CS != 0 and SS != 0? Neither is valid in ring-3. */
3044 uint16_t uNewCs = (pCtx->msrSTAR >> MSR_K6_STAR_SYSRET_CS_SS_SHIFT) & X86_SEL_MASK_OFF_RPL;
3045 uint16_t uNewSs = uNewCs + 8;
3046 if (pIemCpu->enmEffOpSize == IEMMODE_64BIT)
3047 uNewCs += 16;
3048 if (uNewCs == 0 || uNewSs == 0)
3049 {
3050 Log(("sysret: msrSTAR.CS = 0 or SS = 0 -> #GP(0)\n"));
3051 return iemRaiseGeneralProtectionFault0(pIemCpu);
3052 }
3053
3054 /*
3055 * Commit it.
3056 */
3057 if (CPUMIsGuestInLongModeEx(pCtx))
3058 {
3059 if (pIemCpu->enmEffOpSize == IEMMODE_64BIT)
3060 {
3061 Log(("sysret: %04x:%016RX64 [efl=%#llx] -> %04x:%016RX64 [r11=%#llx]\n",
3062 pCtx->cs, pCtx->rip, pCtx->rflags.u, uNewCs, pCtx->rcx, pCtx->r11));
3063 /* Note! We disregard intel manual regarding the RCX cananonical
3064 check, ask intel+xen why AMD doesn't do it. */
3065 pCtx->rip = pCtx->rcx;
3066 pCtx->cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_L | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC
3067 | (3 << X86DESCATTR_DPL_SHIFT);
3068 }
3069 else
3070 {
3071 Log(("sysret: %04x:%016RX64 [efl=%#llx] -> %04x:%08RX32 [r11=%#llx]\n",
3072 pCtx->cs, pCtx->rip, pCtx->rflags.u, uNewCs, pCtx->ecx, pCtx->r11));
3073 pCtx->rip = pCtx->ecx;
3074 pCtx->cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC
3075 | (3 << X86DESCATTR_DPL_SHIFT);
3076 }
3077 /** @todo testcase: See what kind of flags we can make SYSRET restore and
3078 * what it really ignores. RF and VM are hinted at being zero, by AMD. */
3079 pCtx->rflags.u = pCtx->r11 & (X86_EFL_POPF_BITS | X86_EFL_VIF | X86_EFL_VIP);
3080 pCtx->rflags.u |= X86_EFL_1;
3081 }
3082 else
3083 {
3084 Log(("sysret: %04x:%08RX32 [efl=%#x] -> %04x:%08RX32\n", pCtx->cs, pCtx->eip, pCtx->eflags.u, uNewCs, pCtx->ecx));
3085 pCtx->rip = pCtx->rcx;
3086 pCtx->rflags.u |= X86_EFL_IF;
3087 pCtx->cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC
3088 | (3 << X86DESCATTR_DPL_SHIFT);
3089 }
3090 pCtx->cs.Sel = uNewCs | 3;
3091 pCtx->cs.ValidSel = uNewCs | 3;
3092 pCtx->cs.u64Base = 0;
3093 pCtx->cs.u32Limit = UINT32_MAX;
3094 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
3095
3096 pCtx->ss.Sel = uNewSs | 3;
3097 pCtx->ss.ValidSel = uNewSs | 3;
3098 pCtx->ss.fFlags = CPUMSELREG_FLAGS_VALID;
3099 /* The SS hidden bits remains unchanged says AMD. To that I say "Yeah, right!". */
3100 pCtx->ss.Attr.u |= (3 << X86DESCATTR_DPL_SHIFT);
3101 /** @todo Testcase: verify that SS.u1Long and SS.u1DefBig are left unchanged
3102 * on sysret. */
3103
3104 return VINF_SUCCESS;
3105}
3106
3107
3108/**
3109 * Common worker for 'pop SReg', 'mov SReg, GReg' and 'lXs GReg, reg/mem'.
3110 *
3111 * @param iSegReg The segment register number (valid).
3112 * @param uSel The new selector value.
3113 */
3114IEM_CIMPL_DEF_2(iemCImpl_LoadSReg, uint8_t, iSegReg, uint16_t, uSel)
3115{
3116 /*PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);*/
3117 uint16_t *pSel = iemSRegRef(pIemCpu, iSegReg);
3118 PCPUMSELREGHID pHid = iemSRegGetHid(pIemCpu, iSegReg);
3119
3120 Assert(iSegReg <= X86_SREG_GS && iSegReg != X86_SREG_CS);
3121
3122 /*
3123 * Real mode and V8086 mode are easy.
3124 */
3125 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
3126 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
3127 {
3128 *pSel = uSel;
3129 pHid->u64Base = (uint32_t)uSel << 4;
3130 pHid->ValidSel = uSel;
3131 pHid->fFlags = CPUMSELREG_FLAGS_VALID;
3132#if 0 /* AMD Volume 2, chapter 4.1 - "real mode segmentation" - states that limit and attributes are untouched. */
3133 /** @todo Does the CPU actually load limits and attributes in the
3134 * real/V8086 mode segment load case? It doesn't for CS in far
3135 * jumps... Affects unreal mode. */
3136 pHid->u32Limit = 0xffff;
3137 pHid->Attr.u = 0;
3138 pHid->Attr.n.u1Present = 1;
3139 pHid->Attr.n.u1DescType = 1;
3140 pHid->Attr.n.u4Type = iSegReg != X86_SREG_CS
3141 ? X86_SEL_TYPE_RW
3142 : X86_SEL_TYPE_READ | X86_SEL_TYPE_CODE;
3143#endif
3144 CPUMSetChangedFlags(IEMCPU_TO_VMCPU(pIemCpu), CPUM_CHANGED_HIDDEN_SEL_REGS);
3145 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3146 return VINF_SUCCESS;
3147 }
3148
3149 /*
3150 * Protected mode.
3151 *
3152 * Check if it's a null segment selector value first, that's OK for DS, ES,
3153 * FS and GS. If not null, then we have to load and parse the descriptor.
3154 */
3155 if (!(uSel & X86_SEL_MASK_OFF_RPL))
3156 {
3157 Assert(iSegReg != X86_SREG_CS); /** @todo testcase for \#UD on MOV CS, ax! */
3158 if (iSegReg == X86_SREG_SS)
3159 {
3160 /* In 64-bit kernel mode, the stack can be 0 because of the way
3161 interrupts are dispatched. AMD seems to have a slighly more
3162 relaxed relationship to SS.RPL than intel does. */
3163 /** @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! */
3164 if ( pIemCpu->enmCpuMode != IEMMODE_64BIT
3165 || pIemCpu->uCpl > 2
3166 || ( uSel != pIemCpu->uCpl
3167 && !IEM_IS_GUEST_CPU_AMD(pIemCpu)) )
3168 {
3169 Log(("load sreg %#x -> invalid stack selector, #GP(0)\n", uSel));
3170 return iemRaiseGeneralProtectionFault0(pIemCpu);
3171 }
3172 }
3173
3174 *pSel = uSel; /* Not RPL, remember :-) */
3175 iemHlpLoadNullDataSelectorProt(pIemCpu, pHid, uSel);
3176 if (iSegReg == X86_SREG_SS)
3177 pHid->Attr.u |= pIemCpu->uCpl << X86DESCATTR_DPL_SHIFT;
3178
3179 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(IEMCPU_TO_VMCPU(pIemCpu), pHid));
3180 CPUMSetChangedFlags(IEMCPU_TO_VMCPU(pIemCpu), CPUM_CHANGED_HIDDEN_SEL_REGS);
3181
3182 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3183 return VINF_SUCCESS;
3184 }
3185
3186 /* Fetch the descriptor. */
3187 IEMSELDESC Desc;
3188 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uSel, X86_XCPT_GP); /** @todo Correct exception? */
3189 if (rcStrict != VINF_SUCCESS)
3190 return rcStrict;
3191
3192 /* Check GPs first. */
3193 if (!Desc.Legacy.Gen.u1DescType)
3194 {
3195 Log(("load sreg %d - system selector (%#x) -> #GP\n", iSegReg, uSel, Desc.Legacy.Gen.u4Type));
3196 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3197 }
3198 if (iSegReg == X86_SREG_SS) /* SS gets different treatment */
3199 {
3200 if ( (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
3201 || !(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
3202 {
3203 Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
3204 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3205 }
3206 if ((uSel & X86_SEL_RPL) != pIemCpu->uCpl)
3207 {
3208 Log(("load sreg SS, %#x - RPL and CPL (%d) differs -> #GP\n", uSel, pIemCpu->uCpl));
3209 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3210 }
3211 if (Desc.Legacy.Gen.u2Dpl != pIemCpu->uCpl)
3212 {
3213 Log(("load sreg SS, %#x - DPL (%d) and CPL (%d) differs -> #GP\n", uSel, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
3214 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3215 }
3216 }
3217 else
3218 {
3219 if ((Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
3220 {
3221 Log(("load sreg%u, %#x - execute only segment -> #GP\n", iSegReg, uSel));
3222 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3223 }
3224 if ( (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
3225 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
3226 {
3227#if 0 /* this is what intel says. */
3228 if ( (uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl
3229 && pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
3230 {
3231 Log(("load sreg%u, %#x - both RPL (%d) and CPL (%d) are greater than DPL (%d) -> #GP\n",
3232 iSegReg, uSel, (uSel & X86_SEL_RPL), pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
3233 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3234 }
3235#else /* this is what makes more sense. */
3236 if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
3237 {
3238 Log(("load sreg%u, %#x - RPL (%d) is greater than DPL (%d) -> #GP\n",
3239 iSegReg, uSel, (uSel & X86_SEL_RPL), Desc.Legacy.Gen.u2Dpl));
3240 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3241 }
3242 if (pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
3243 {
3244 Log(("load sreg%u, %#x - CPL (%d) is greater than DPL (%d) -> #GP\n",
3245 iSegReg, uSel, pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
3246 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3247 }
3248#endif
3249 }
3250 }
3251
3252 /* Is it there? */
3253 if (!Desc.Legacy.Gen.u1Present)
3254 {
3255 Log(("load sreg%d,%#x - segment not present -> #NP\n", iSegReg, uSel));
3256 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uSel);
3257 }
3258
3259 /* The base and limit. */
3260 uint32_t cbLimit = X86DESC_LIMIT_G(&Desc.Legacy);
3261 uint64_t u64Base;
3262 if ( pIemCpu->enmCpuMode == IEMMODE_64BIT
3263 && iSegReg < X86_SREG_FS)
3264 u64Base = 0;
3265 else
3266 u64Base = X86DESC_BASE(&Desc.Legacy);
3267
3268 /*
3269 * Ok, everything checked out fine. Now set the accessed bit before
3270 * committing the result into the registers.
3271 */
3272 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
3273 {
3274 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uSel);
3275 if (rcStrict != VINF_SUCCESS)
3276 return rcStrict;
3277 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
3278 }
3279
3280 /* commit */
3281 *pSel = uSel;
3282 pHid->Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
3283 pHid->u32Limit = cbLimit;
3284 pHid->u64Base = u64Base;
3285 pHid->ValidSel = uSel;
3286 pHid->fFlags = CPUMSELREG_FLAGS_VALID;
3287
3288 /** @todo check if the hidden bits are loaded correctly for 64-bit
3289 * mode. */
3290 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(IEMCPU_TO_VMCPU(pIemCpu), pHid));
3291
3292 CPUMSetChangedFlags(IEMCPU_TO_VMCPU(pIemCpu), CPUM_CHANGED_HIDDEN_SEL_REGS);
3293 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3294 return VINF_SUCCESS;
3295}
3296
3297
3298/**
3299 * Implements 'mov SReg, r/m'.
3300 *
3301 * @param iSegReg The segment register number (valid).
3302 * @param uSel The new selector value.
3303 */
3304IEM_CIMPL_DEF_2(iemCImpl_load_SReg, uint8_t, iSegReg, uint16_t, uSel)
3305{
3306 VBOXSTRICTRC rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
3307 if (rcStrict == VINF_SUCCESS)
3308 {
3309 if (iSegReg == X86_SREG_SS)
3310 {
3311 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3312 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
3313 }
3314 }
3315 return rcStrict;
3316}
3317
3318
3319/**
3320 * Implements 'pop SReg'.
3321 *
3322 * @param iSegReg The segment register number (valid).
3323 * @param enmEffOpSize The efficient operand size (valid).
3324 */
3325IEM_CIMPL_DEF_2(iemCImpl_pop_Sreg, uint8_t, iSegReg, IEMMODE, enmEffOpSize)
3326{
3327 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3328 VBOXSTRICTRC rcStrict;
3329
3330 /*
3331 * Read the selector off the stack and join paths with mov ss, reg.
3332 */
3333 RTUINT64U TmpRsp;
3334 TmpRsp.u = pCtx->rsp;
3335 switch (enmEffOpSize)
3336 {
3337 case IEMMODE_16BIT:
3338 {
3339 uint16_t uSel;
3340 rcStrict = iemMemStackPopU16Ex(pIemCpu, &uSel, &TmpRsp);
3341 if (rcStrict == VINF_SUCCESS)
3342 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
3343 break;
3344 }
3345
3346 case IEMMODE_32BIT:
3347 {
3348 uint32_t u32Value;
3349 rcStrict = iemMemStackPopU32Ex(pIemCpu, &u32Value, &TmpRsp);
3350 if (rcStrict == VINF_SUCCESS)
3351 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, (uint16_t)u32Value);
3352 break;
3353 }
3354
3355 case IEMMODE_64BIT:
3356 {
3357 uint64_t u64Value;
3358 rcStrict = iemMemStackPopU64Ex(pIemCpu, &u64Value, &TmpRsp);
3359 if (rcStrict == VINF_SUCCESS)
3360 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, (uint16_t)u64Value);
3361 break;
3362 }
3363 IEM_NOT_REACHED_DEFAULT_CASE_RET();
3364 }
3365
3366 /*
3367 * Commit the stack on success.
3368 */
3369 if (rcStrict == VINF_SUCCESS)
3370 {
3371 pCtx->rsp = TmpRsp.u;
3372 if (iSegReg == X86_SREG_SS)
3373 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
3374 }
3375 return rcStrict;
3376}
3377
3378
3379/**
3380 * Implements lgs, lfs, les, lds & lss.
3381 */
3382IEM_CIMPL_DEF_5(iemCImpl_load_SReg_Greg,
3383 uint16_t, uSel,
3384 uint64_t, offSeg,
3385 uint8_t, iSegReg,
3386 uint8_t, iGReg,
3387 IEMMODE, enmEffOpSize)
3388{
3389 /*PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);*/
3390 VBOXSTRICTRC rcStrict;
3391
3392 /*
3393 * Use iemCImpl_LoadSReg to do the tricky segment register loading.
3394 */
3395 /** @todo verify and test that mov, pop and lXs works the segment
3396 * register loading in the exact same way. */
3397 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
3398 if (rcStrict == VINF_SUCCESS)
3399 {
3400 switch (enmEffOpSize)
3401 {
3402 case IEMMODE_16BIT:
3403 *(uint16_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
3404 break;
3405 case IEMMODE_32BIT:
3406 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
3407 break;
3408 case IEMMODE_64BIT:
3409 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
3410 break;
3411 IEM_NOT_REACHED_DEFAULT_CASE_RET();
3412 }
3413 }
3414
3415 return rcStrict;
3416}
3417
3418
3419/**
3420 * Helper for VERR, VERW, LAR, and LSL and loads the descriptor into memory.
3421 *
3422 * @retval VINF_SUCCESS on success.
3423 * @retval VINF_IEM_SELECTOR_NOT_OK if the selector isn't ok.
3424 * @retval iemMemFetchSysU64 return value.
3425 *
3426 * @param pIemCpu The IEM state of the calling EMT.
3427 * @param uSel The selector value.
3428 * @param fAllowSysDesc Whether system descriptors are OK or not.
3429 * @param pDesc Where to return the descriptor on success.
3430 */
3431static VBOXSTRICTRC iemCImpl_LoadDescHelper(PIEMCPU pIemCpu, uint16_t uSel, bool fAllowSysDesc, PIEMSELDESC pDesc)
3432{
3433 pDesc->Long.au64[0] = 0;
3434 pDesc->Long.au64[1] = 0;
3435
3436 if (!(uSel & X86_SEL_MASK_OFF_RPL)) /** @todo test this on 64-bit. */
3437 return VINF_IEM_SELECTOR_NOT_OK;
3438
3439 /* Within the table limits? */
3440 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3441 RTGCPTR GCPtrBase;
3442 if (uSel & X86_SEL_LDT)
3443 {
3444 if ( !pCtx->ldtr.Attr.n.u1Present
3445 || (uSel | X86_SEL_RPL_LDT) > pCtx->ldtr.u32Limit )
3446 return VINF_IEM_SELECTOR_NOT_OK;
3447 GCPtrBase = pCtx->ldtr.u64Base;
3448 }
3449 else
3450 {
3451 if ((uSel | X86_SEL_RPL_LDT) > pCtx->gdtr.cbGdt)
3452 return VINF_IEM_SELECTOR_NOT_OK;
3453 GCPtrBase = pCtx->gdtr.pGdt;
3454 }
3455
3456 /* Fetch the descriptor. */
3457 VBOXSTRICTRC rcStrict = iemMemFetchSysU64(pIemCpu, &pDesc->Legacy.u, UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK));
3458 if (rcStrict != VINF_SUCCESS)
3459 return rcStrict;
3460 if (!pDesc->Legacy.Gen.u1DescType)
3461 {
3462 if (!fAllowSysDesc)
3463 return VINF_IEM_SELECTOR_NOT_OK;
3464 if (CPUMIsGuestInLongModeEx(pCtx))
3465 {
3466 rcStrict = iemMemFetchSysU64(pIemCpu, &pDesc->Long.au64[1], UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK) + 8);
3467 if (rcStrict != VINF_SUCCESS)
3468 return rcStrict;
3469 }
3470
3471 }
3472
3473 return VINF_SUCCESS;
3474}
3475
3476
3477/**
3478 * Implements verr (fWrite = false) and verw (fWrite = true).
3479 */
3480IEM_CIMPL_DEF_2(iemCImpl_VerX, uint16_t, uSel, bool, fWrite)
3481{
3482 Assert(!IEM_IS_REAL_OR_V86_MODE(pIemCpu));
3483
3484 /** @todo figure whether the accessed bit is set or not. */
3485
3486 bool fAccessible = true;
3487 IEMSELDESC Desc;
3488 VBOXSTRICTRC rcStrict = iemCImpl_LoadDescHelper(pIemCpu, uSel, false /*fAllowSysDesc*/, &Desc);
3489 if (rcStrict == VINF_SUCCESS)
3490 {
3491 /* Check the descriptor, order doesn't matter much here. */
3492 if ( !Desc.Legacy.Gen.u1DescType
3493 || !Desc.Legacy.Gen.u1Present)
3494 fAccessible = false;
3495 else
3496 {
3497 if ( fWrite
3498 ? (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE)) != X86_SEL_TYPE_WRITE
3499 : (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
3500 fAccessible = false;
3501
3502 /** @todo testcase for the conforming behavior. */
3503 if ( (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
3504 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
3505 {
3506 if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
3507 fAccessible = false;
3508 else if (pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
3509 fAccessible = false;
3510 }
3511 }
3512
3513 }
3514 else if (rcStrict == VINF_IEM_SELECTOR_NOT_OK)
3515 fAccessible = false;
3516 else
3517 return rcStrict;
3518
3519 /* commit */
3520 pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1ZF = fAccessible;
3521
3522 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3523 return VINF_SUCCESS;
3524}
3525
3526
3527/**
3528 * Implements LAR and LSL with 64-bit operand size.
3529 *
3530 * @returns VINF_SUCCESS.
3531 * @param pu16Dst Pointer to the destination register.
3532 * @param uSel The selector to load details for.
3533 * @param pEFlags Pointer to the eflags register.
3534 * @param fIsLar true = LAR, false = LSL.
3535 */
3536IEM_CIMPL_DEF_4(iemCImpl_LarLsl_u64, uint64_t *, pu64Dst, uint16_t, uSel, uint32_t *, pEFlags, bool, fIsLar)
3537{
3538 Assert(!IEM_IS_REAL_OR_V86_MODE(pIemCpu));
3539
3540 /** @todo figure whether the accessed bit is set or not. */
3541
3542 bool fDescOk = true;
3543 IEMSELDESC Desc;
3544 VBOXSTRICTRC rcStrict = iemCImpl_LoadDescHelper(pIemCpu, uSel, false /*fAllowSysDesc*/, &Desc);
3545 if (rcStrict == VINF_SUCCESS)
3546 {
3547 /*
3548 * Check the descriptor type.
3549 */
3550 if (!Desc.Legacy.Gen.u1DescType)
3551 {
3552 if (CPUMIsGuestInLongModeEx(pIemCpu->CTX_SUFF(pCtx)))
3553 {
3554 if (Desc.Long.Gen.u5Zeros)
3555 fDescOk = false;
3556 else
3557 switch (Desc.Long.Gen.u4Type)
3558 {
3559 /** @todo Intel lists 0 as valid for LSL, verify whether that's correct */
3560 case AMD64_SEL_TYPE_SYS_TSS_AVAIL:
3561 case AMD64_SEL_TYPE_SYS_TSS_BUSY:
3562 case AMD64_SEL_TYPE_SYS_LDT: /** @todo Intel lists this as invalid for LAR, AMD and 32-bit does otherwise. */
3563 break;
3564 case AMD64_SEL_TYPE_SYS_CALL_GATE:
3565 fDescOk = fIsLar;
3566 break;
3567 default:
3568 fDescOk = false;
3569 break;
3570 }
3571 }
3572 else
3573 {
3574 switch (Desc.Long.Gen.u4Type)
3575 {
3576 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
3577 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
3578 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
3579 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
3580 case X86_SEL_TYPE_SYS_LDT:
3581 break;
3582 case X86_SEL_TYPE_SYS_286_CALL_GATE:
3583 case X86_SEL_TYPE_SYS_TASK_GATE:
3584 case X86_SEL_TYPE_SYS_386_CALL_GATE:
3585 fDescOk = fIsLar;
3586 break;
3587 default:
3588 fDescOk = false;
3589 break;
3590 }
3591 }
3592 }
3593 if (fDescOk)
3594 {
3595 /*
3596 * Check the RPL/DPL/CPL interaction..
3597 */
3598 /** @todo testcase for the conforming behavior. */
3599 if ( (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF)) != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF)
3600 || !Desc.Legacy.Gen.u1DescType)
3601 {
3602 if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
3603 fDescOk = false;
3604 else if (pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
3605 fDescOk = false;
3606 }
3607 }
3608
3609 if (fDescOk)
3610 {
3611 /*
3612 * All fine, start committing the result.
3613 */
3614 if (fIsLar)
3615 *pu64Dst = Desc.Legacy.au32[1] & UINT32_C(0x00ffff00);
3616 else
3617 *pu64Dst = X86DESC_LIMIT_G(&Desc.Legacy);
3618 }
3619
3620 }
3621 else if (rcStrict == VINF_IEM_SELECTOR_NOT_OK)
3622 fDescOk = false;
3623 else
3624 return rcStrict;
3625
3626 /* commit flags value and advance rip. */
3627 pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1ZF = fDescOk;
3628 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3629
3630 return VINF_SUCCESS;
3631}
3632
3633
3634/**
3635 * Implements LAR and LSL with 16-bit operand size.
3636 *
3637 * @returns VINF_SUCCESS.
3638 * @param pu16Dst Pointer to the destination register.
3639 * @param u16Sel The selector to load details for.
3640 * @param pEFlags Pointer to the eflags register.
3641 * @param fIsLar true = LAR, false = LSL.
3642 */
3643IEM_CIMPL_DEF_4(iemCImpl_LarLsl_u16, uint16_t *, pu16Dst, uint16_t, uSel, uint32_t *, pEFlags, bool, fIsLar)
3644{
3645 uint64_t u64TmpDst = *pu16Dst;
3646 IEM_CIMPL_CALL_4(iemCImpl_LarLsl_u64, &u64TmpDst, uSel, pEFlags, fIsLar);
3647 *pu16Dst = (uint16_t)u64TmpDst;
3648 return VINF_SUCCESS;
3649}
3650
3651
3652/**
3653 * Implements lgdt.
3654 *
3655 * @param iEffSeg The segment of the new gdtr contents
3656 * @param GCPtrEffSrc The address of the new gdtr contents.
3657 * @param enmEffOpSize The effective operand size.
3658 */
3659IEM_CIMPL_DEF_3(iemCImpl_lgdt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc, IEMMODE, enmEffOpSize)
3660{
3661 if (pIemCpu->uCpl != 0)
3662 return iemRaiseGeneralProtectionFault0(pIemCpu);
3663 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
3664
3665 /*
3666 * Fetch the limit and base address.
3667 */
3668 uint16_t cbLimit;
3669 RTGCPTR GCPtrBase;
3670 VBOXSTRICTRC rcStrict = iemMemFetchDataXdtr(pIemCpu, &cbLimit, &GCPtrBase, iEffSeg, GCPtrEffSrc, enmEffOpSize);
3671 if (rcStrict == VINF_SUCCESS)
3672 {
3673 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
3674 rcStrict = CPUMSetGuestGDTR(IEMCPU_TO_VMCPU(pIemCpu), GCPtrBase, cbLimit);
3675 else
3676 {
3677 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3678 pCtx->gdtr.cbGdt = cbLimit;
3679 pCtx->gdtr.pGdt = GCPtrBase;
3680 }
3681 if (rcStrict == VINF_SUCCESS)
3682 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3683 }
3684 return rcStrict;
3685}
3686
3687
3688/**
3689 * Implements sgdt.
3690 *
3691 * @param iEffSeg The segment where to store the gdtr content.
3692 * @param GCPtrEffDst The address where to store the gdtr content.
3693 * @param enmEffOpSize The effective operand size.
3694 */
3695IEM_CIMPL_DEF_3(iemCImpl_sgdt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, IEMMODE, enmEffOpSize)
3696{
3697 /*
3698 * Join paths with sidt.
3699 * Note! No CPL or V8086 checks here, it's a really sad story, ask Intel if
3700 * you really must know.
3701 */
3702 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3703 VBOXSTRICTRC rcStrict = iemMemStoreDataXdtr(pIemCpu, pCtx->gdtr.cbGdt, pCtx->gdtr.pGdt, iEffSeg, GCPtrEffDst, enmEffOpSize);
3704 if (rcStrict == VINF_SUCCESS)
3705 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3706 return rcStrict;
3707}
3708
3709
3710/**
3711 * Implements lidt.
3712 *
3713 * @param iEffSeg The segment of the new idtr contents
3714 * @param GCPtrEffSrc The address of the new idtr contents.
3715 * @param enmEffOpSize The effective operand size.
3716 */
3717IEM_CIMPL_DEF_3(iemCImpl_lidt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc, IEMMODE, enmEffOpSize)
3718{
3719 if (pIemCpu->uCpl != 0)
3720 return iemRaiseGeneralProtectionFault0(pIemCpu);
3721 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
3722
3723 /*
3724 * Fetch the limit and base address.
3725 */
3726 uint16_t cbLimit;
3727 RTGCPTR GCPtrBase;
3728 VBOXSTRICTRC rcStrict = iemMemFetchDataXdtr(pIemCpu, &cbLimit, &GCPtrBase, iEffSeg, GCPtrEffSrc, enmEffOpSize);
3729 if (rcStrict == VINF_SUCCESS)
3730 {
3731 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
3732 CPUMSetGuestIDTR(IEMCPU_TO_VMCPU(pIemCpu), GCPtrBase, cbLimit);
3733 else
3734 {
3735 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3736 pCtx->idtr.cbIdt = cbLimit;
3737 pCtx->idtr.pIdt = GCPtrBase;
3738 }
3739 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3740 }
3741 return rcStrict;
3742}
3743
3744
3745/**
3746 * Implements sidt.
3747 *
3748 * @param iEffSeg The segment where to store the idtr content.
3749 * @param GCPtrEffDst The address where to store the idtr content.
3750 * @param enmEffOpSize The effective operand size.
3751 */
3752IEM_CIMPL_DEF_3(iemCImpl_sidt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, IEMMODE, enmEffOpSize)
3753{
3754 /*
3755 * Join paths with sgdt.
3756 * Note! No CPL or V8086 checks here, it's a really sad story, ask Intel if
3757 * you really must know.
3758 */
3759 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3760 VBOXSTRICTRC rcStrict = iemMemStoreDataXdtr(pIemCpu, pCtx->idtr.cbIdt, pCtx->idtr.pIdt, iEffSeg, GCPtrEffDst, enmEffOpSize);
3761 if (rcStrict == VINF_SUCCESS)
3762 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3763 return rcStrict;
3764}
3765
3766
3767/**
3768 * Implements lldt.
3769 *
3770 * @param uNewLdt The new LDT selector value.
3771 */
3772IEM_CIMPL_DEF_1(iemCImpl_lldt, uint16_t, uNewLdt)
3773{
3774 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3775
3776 /*
3777 * Check preconditions.
3778 */
3779 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
3780 {
3781 Log(("lldt %04x - real or v8086 mode -> #GP(0)\n", uNewLdt));
3782 return iemRaiseUndefinedOpcode(pIemCpu);
3783 }
3784 if (pIemCpu->uCpl != 0)
3785 {
3786 Log(("lldt %04x - CPL is %d -> #GP(0)\n", uNewLdt, pIemCpu->uCpl));
3787 return iemRaiseGeneralProtectionFault0(pIemCpu);
3788 }
3789 if (uNewLdt & X86_SEL_LDT)
3790 {
3791 Log(("lldt %04x - LDT selector -> #GP\n", uNewLdt));
3792 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewLdt);
3793 }
3794
3795 /*
3796 * Now, loading a NULL selector is easy.
3797 */
3798 if (!(uNewLdt & X86_SEL_MASK_OFF_RPL))
3799 {
3800 Log(("lldt %04x: Loading NULL selector.\n", uNewLdt));
3801 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
3802 CPUMSetGuestLDTR(IEMCPU_TO_VMCPU(pIemCpu), uNewLdt);
3803 else
3804 pCtx->ldtr.Sel = uNewLdt;
3805 pCtx->ldtr.ValidSel = uNewLdt;
3806 pCtx->ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
3807 if (IEM_FULL_VERIFICATION_REM_ENABLED(pIemCpu))
3808 {
3809 pCtx->ldtr.Attr.u = X86DESCATTR_UNUSABLE;
3810 pCtx->ldtr.u64Base = pCtx->ldtr.u32Limit = 0; /* For verfication against REM. */
3811 }
3812 else if (IEM_IS_GUEST_CPU_AMD(pIemCpu))
3813 {
3814 /* AMD-V seems to leave the base and limit alone. */
3815 pCtx->ldtr.Attr.u = X86DESCATTR_UNUSABLE;
3816 }
3817 else if (!IEM_FULL_VERIFICATION_REM_ENABLED(pIemCpu))
3818 {
3819 /* VT-x (Intel 3960x) seems to be doing the following. */
3820 pCtx->ldtr.Attr.u = X86DESCATTR_UNUSABLE | X86DESCATTR_G | X86DESCATTR_D;
3821 pCtx->ldtr.u64Base = 0;
3822 pCtx->ldtr.u32Limit = UINT32_MAX;
3823 }
3824
3825 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3826 return VINF_SUCCESS;
3827 }
3828
3829 /*
3830 * Read the descriptor.
3831 */
3832 IEMSELDESC Desc;
3833 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uNewLdt, X86_XCPT_GP); /** @todo Correct exception? */
3834 if (rcStrict != VINF_SUCCESS)
3835 return rcStrict;
3836
3837 /* Check GPs first. */
3838 if (Desc.Legacy.Gen.u1DescType)
3839 {
3840 Log(("lldt %#x - not system selector (type %x) -> #GP\n", uNewLdt, Desc.Legacy.Gen.u4Type));
3841 return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
3842 }
3843 if (Desc.Legacy.Gen.u4Type != X86_SEL_TYPE_SYS_LDT)
3844 {
3845 Log(("lldt %#x - not LDT selector (type %x) -> #GP\n", uNewLdt, Desc.Legacy.Gen.u4Type));
3846 return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
3847 }
3848 uint64_t u64Base;
3849 if (!IEM_IS_LONG_MODE(pIemCpu))
3850 u64Base = X86DESC_BASE(&Desc.Legacy);
3851 else
3852 {
3853 if (Desc.Long.Gen.u5Zeros)
3854 {
3855 Log(("lldt %#x - u5Zeros=%#x -> #GP\n", uNewLdt, Desc.Long.Gen.u5Zeros));
3856 return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
3857 }
3858
3859 u64Base = X86DESC64_BASE(&Desc.Long);
3860 if (!IEM_IS_CANONICAL(u64Base))
3861 {
3862 Log(("lldt %#x - non-canonical base address %#llx -> #GP\n", uNewLdt, u64Base));
3863 return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
3864 }
3865 }
3866
3867 /* NP */
3868 if (!Desc.Legacy.Gen.u1Present)
3869 {
3870 Log(("lldt %#x - segment not present -> #NP\n", uNewLdt));
3871 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uNewLdt);
3872 }
3873
3874 /*
3875 * It checks out alright, update the registers.
3876 */
3877/** @todo check if the actual value is loaded or if the RPL is dropped */
3878 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
3879 CPUMSetGuestLDTR(IEMCPU_TO_VMCPU(pIemCpu), uNewLdt & X86_SEL_MASK_OFF_RPL);
3880 else
3881 pCtx->ldtr.Sel = uNewLdt & X86_SEL_MASK_OFF_RPL;
3882 pCtx->ldtr.ValidSel = uNewLdt & X86_SEL_MASK_OFF_RPL;
3883 pCtx->ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
3884 pCtx->ldtr.Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
3885 pCtx->ldtr.u32Limit = X86DESC_LIMIT_G(&Desc.Legacy);
3886 pCtx->ldtr.u64Base = u64Base;
3887
3888 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3889 return VINF_SUCCESS;
3890}
3891
3892
3893/**
3894 * Implements lldt.
3895 *
3896 * @param uNewLdt The new LDT selector value.
3897 */
3898IEM_CIMPL_DEF_1(iemCImpl_ltr, uint16_t, uNewTr)
3899{
3900 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3901
3902 /*
3903 * Check preconditions.
3904 */
3905 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
3906 {
3907 Log(("ltr %04x - real or v8086 mode -> #GP(0)\n", uNewTr));
3908 return iemRaiseUndefinedOpcode(pIemCpu);
3909 }
3910 if (pIemCpu->uCpl != 0)
3911 {
3912 Log(("ltr %04x - CPL is %d -> #GP(0)\n", uNewTr, pIemCpu->uCpl));
3913 return iemRaiseGeneralProtectionFault0(pIemCpu);
3914 }
3915 if (uNewTr & X86_SEL_LDT)
3916 {
3917 Log(("ltr %04x - LDT selector -> #GP\n", uNewTr));
3918 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewTr);
3919 }
3920 if (!(uNewTr & X86_SEL_MASK_OFF_RPL))
3921 {
3922 Log(("ltr %04x - NULL selector -> #GP(0)\n", uNewTr));
3923 return iemRaiseGeneralProtectionFault0(pIemCpu);
3924 }
3925
3926 /*
3927 * Read the descriptor.
3928 */
3929 IEMSELDESC Desc;
3930 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uNewTr, X86_XCPT_GP); /** @todo Correct exception? */
3931 if (rcStrict != VINF_SUCCESS)
3932 return rcStrict;
3933
3934 /* Check GPs first. */
3935 if (Desc.Legacy.Gen.u1DescType)
3936 {
3937 Log(("ltr %#x - not system selector (type %x) -> #GP\n", uNewTr, Desc.Legacy.Gen.u4Type));
3938 return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
3939 }
3940 if ( Desc.Legacy.Gen.u4Type != X86_SEL_TYPE_SYS_386_TSS_AVAIL /* same as AMD64_SEL_TYPE_SYS_TSS_AVAIL */
3941 && ( Desc.Legacy.Gen.u4Type != X86_SEL_TYPE_SYS_286_TSS_AVAIL
3942 || IEM_IS_LONG_MODE(pIemCpu)) )
3943 {
3944 Log(("ltr %#x - not an available TSS selector (type %x) -> #GP\n", uNewTr, Desc.Legacy.Gen.u4Type));
3945 return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
3946 }
3947 uint64_t u64Base;
3948 if (!IEM_IS_LONG_MODE(pIemCpu))
3949 u64Base = X86DESC_BASE(&Desc.Legacy);
3950 else
3951 {
3952 if (Desc.Long.Gen.u5Zeros)
3953 {
3954 Log(("ltr %#x - u5Zeros=%#x -> #GP\n", uNewTr, Desc.Long.Gen.u5Zeros));
3955 return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
3956 }
3957
3958 u64Base = X86DESC64_BASE(&Desc.Long);
3959 if (!IEM_IS_CANONICAL(u64Base))
3960 {
3961 Log(("ltr %#x - non-canonical base address %#llx -> #GP\n", uNewTr, u64Base));
3962 return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
3963 }
3964 }
3965
3966 /* NP */
3967 if (!Desc.Legacy.Gen.u1Present)
3968 {
3969 Log(("ltr %#x - segment not present -> #NP\n", uNewTr));
3970 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uNewTr);
3971 }
3972
3973 /*
3974 * Set it busy.
3975 * Note! Intel says this should lock down the whole descriptor, but we'll
3976 * restrict our selves to 32-bit for now due to lack of inline
3977 * assembly and such.
3978 */
3979 void *pvDesc;
3980 rcStrict = iemMemMap(pIemCpu, &pvDesc, 8, UINT8_MAX, pCtx->gdtr.pGdt + (uNewTr & X86_SEL_MASK_OFF_RPL), IEM_ACCESS_DATA_RW);
3981 if (rcStrict != VINF_SUCCESS)
3982 return rcStrict;
3983 switch ((uintptr_t)pvDesc & 3)
3984 {
3985 case 0: ASMAtomicBitSet(pvDesc, 40 + 1); break;
3986 case 1: ASMAtomicBitSet((uint8_t *)pvDesc + 3, 40 + 1 - 24); break;
3987 case 2: ASMAtomicBitSet((uint8_t *)pvDesc + 2, 40 + 1 - 16); break;
3988 case 3: ASMAtomicBitSet((uint8_t *)pvDesc + 1, 40 + 1 - 8); break;
3989 }
3990 rcStrict = iemMemCommitAndUnmap(pIemCpu, pvDesc, IEM_ACCESS_DATA_RW);
3991 if (rcStrict != VINF_SUCCESS)
3992 return rcStrict;
3993 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_SYS_TSS_BUSY_MASK;
3994
3995 /*
3996 * It checks out alright, update the registers.
3997 */
3998/** @todo check if the actual value is loaded or if the RPL is dropped */
3999 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4000 CPUMSetGuestTR(IEMCPU_TO_VMCPU(pIemCpu), uNewTr & X86_SEL_MASK_OFF_RPL);
4001 else
4002 pCtx->tr.Sel = uNewTr & X86_SEL_MASK_OFF_RPL;
4003 pCtx->tr.ValidSel = uNewTr & X86_SEL_MASK_OFF_RPL;
4004 pCtx->tr.fFlags = CPUMSELREG_FLAGS_VALID;
4005 pCtx->tr.Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
4006 pCtx->tr.u32Limit = X86DESC_LIMIT_G(&Desc.Legacy);
4007 pCtx->tr.u64Base = u64Base;
4008
4009 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4010 return VINF_SUCCESS;
4011}
4012
4013
4014/**
4015 * Implements mov GReg,CRx.
4016 *
4017 * @param iGReg The general register to store the CRx value in.
4018 * @param iCrReg The CRx register to read (valid).
4019 */
4020IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Cd, uint8_t, iGReg, uint8_t, iCrReg)
4021{
4022 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4023 if (pIemCpu->uCpl != 0)
4024 return iemRaiseGeneralProtectionFault0(pIemCpu);
4025 Assert(!pCtx->eflags.Bits.u1VM);
4026
4027 /* read it */
4028 uint64_t crX;
4029 switch (iCrReg)
4030 {
4031 case 0: crX = pCtx->cr0; break;
4032 case 2: crX = pCtx->cr2; break;
4033 case 3: crX = pCtx->cr3; break;
4034 case 4: crX = pCtx->cr4; break;
4035 case 8:
4036 {
4037 uint8_t uTpr;
4038 int rc = PDMApicGetTPR(IEMCPU_TO_VMCPU(pIemCpu), &uTpr, NULL, NULL);
4039 if (RT_SUCCESS(rc))
4040 crX = uTpr >> 4;
4041 else
4042 crX = 0;
4043 break;
4044 }
4045 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
4046 }
4047
4048 /* store it */
4049 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
4050 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = crX;
4051 else
4052 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = (uint32_t)crX;
4053
4054 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4055 return VINF_SUCCESS;
4056}
4057
4058
4059/**
4060 * Used to implemented 'mov CRx,GReg' and 'lmsw r/m16'.
4061 *
4062 * @param iCrReg The CRx register to write (valid).
4063 * @param uNewCrX The new value.
4064 */
4065IEM_CIMPL_DEF_2(iemCImpl_load_CrX, uint8_t, iCrReg, uint64_t, uNewCrX)
4066{
4067 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4068 PVMCPU pVCpu = IEMCPU_TO_VMCPU(pIemCpu);
4069 VBOXSTRICTRC rcStrict;
4070 int rc;
4071
4072 /*
4073 * Try store it.
4074 * Unfortunately, CPUM only does a tiny bit of the work.
4075 */
4076 switch (iCrReg)
4077 {
4078 case 0:
4079 {
4080 /*
4081 * Perform checks.
4082 */
4083 uint64_t const uOldCrX = pCtx->cr0;
4084 uNewCrX |= X86_CR0_ET; /* hardcoded */
4085
4086 /* Check for reserved bits. */
4087 uint32_t const fValid = X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS
4088 | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM
4089 | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG;
4090 if (uNewCrX & ~(uint64_t)fValid)
4091 {
4092 Log(("Trying to set reserved CR0 bits: NewCR0=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
4093 return iemRaiseGeneralProtectionFault0(pIemCpu);
4094 }
4095
4096 /* Check for invalid combinations. */
4097 if ( (uNewCrX & X86_CR0_PG)
4098 && !(uNewCrX & X86_CR0_PE) )
4099 {
4100 Log(("Trying to set CR0.PG without CR0.PE\n"));
4101 return iemRaiseGeneralProtectionFault0(pIemCpu);
4102 }
4103
4104 if ( !(uNewCrX & X86_CR0_CD)
4105 && (uNewCrX & X86_CR0_NW) )
4106 {
4107 Log(("Trying to clear CR0.CD while leaving CR0.NW set\n"));
4108 return iemRaiseGeneralProtectionFault0(pIemCpu);
4109 }
4110
4111 /* Long mode consistency checks. */
4112 if ( (uNewCrX & X86_CR0_PG)
4113 && !(uOldCrX & X86_CR0_PG)
4114 && (pCtx->msrEFER & MSR_K6_EFER_LME) )
4115 {
4116 if (!(pCtx->cr4 & X86_CR4_PAE))
4117 {
4118 Log(("Trying to enabled long mode paging without CR4.PAE set\n"));
4119 return iemRaiseGeneralProtectionFault0(pIemCpu);
4120 }
4121 if (pCtx->cs.Attr.n.u1Long)
4122 {
4123 Log(("Trying to enabled long mode paging with a long CS descriptor loaded.\n"));
4124 return iemRaiseGeneralProtectionFault0(pIemCpu);
4125 }
4126 }
4127
4128 /** @todo check reserved PDPTR bits as AMD states. */
4129
4130 /*
4131 * Change CR0.
4132 */
4133 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4134 CPUMSetGuestCR0(pVCpu, uNewCrX);
4135 else
4136 pCtx->cr0 = uNewCrX;
4137 Assert(pCtx->cr0 == uNewCrX);
4138
4139 /*
4140 * Change EFER.LMA if entering or leaving long mode.
4141 */
4142 if ( (uNewCrX & X86_CR0_PG) != (uOldCrX & X86_CR0_PG)
4143 && (pCtx->msrEFER & MSR_K6_EFER_LME) )
4144 {
4145 uint64_t NewEFER = pCtx->msrEFER;
4146 if (uNewCrX & X86_CR0_PG)
4147 NewEFER |= MSR_K6_EFER_LMA;
4148 else
4149 NewEFER &= ~MSR_K6_EFER_LMA;
4150
4151 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4152 CPUMSetGuestEFER(pVCpu, NewEFER);
4153 else
4154 pCtx->msrEFER = NewEFER;
4155 Assert(pCtx->msrEFER == NewEFER);
4156 }
4157
4158 /*
4159 * Inform PGM.
4160 */
4161 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4162 {
4163 if ( (uNewCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
4164 != (uOldCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) )
4165 {
4166 rc = PGMFlushTLB(pVCpu, pCtx->cr3, true /* global */);
4167 AssertRCReturn(rc, rc);
4168 /* ignore informational status codes */
4169 }
4170 rcStrict = PGMChangeMode(pVCpu, pCtx->cr0, pCtx->cr4, pCtx->msrEFER);
4171 }
4172 else
4173 rcStrict = VINF_SUCCESS;
4174
4175#ifdef IN_RC
4176 /* Return to ring-3 for rescheduling if WP or AM changes. */
4177 if ( rcStrict == VINF_SUCCESS
4178 && ( (uNewCrX & (X86_CR0_WP | X86_CR0_AM))
4179 != (uOldCrX & (X86_CR0_WP | X86_CR0_AM))) )
4180 rcStrict = VINF_EM_RESCHEDULE;
4181#endif
4182 break;
4183 }
4184
4185 /*
4186 * CR2 can be changed without any restrictions.
4187 */
4188 case 2:
4189 pCtx->cr2 = uNewCrX;
4190 rcStrict = VINF_SUCCESS;
4191 break;
4192
4193 /*
4194 * CR3 is relatively simple, although AMD and Intel have different
4195 * accounts of how setting reserved bits are handled. We take intel's
4196 * word for the lower bits and AMD's for the high bits (63:52).
4197 */
4198 /** @todo Testcase: Setting reserved bits in CR3, especially before
4199 * enabling paging. */
4200 case 3:
4201 {
4202 /* check / mask the value. */
4203 if (uNewCrX & UINT64_C(0xfff0000000000000))
4204 {
4205 Log(("Trying to load CR3 with invalid high bits set: %#llx\n", uNewCrX));
4206 return iemRaiseGeneralProtectionFault0(pIemCpu);
4207 }
4208
4209 uint64_t fValid;
4210 if ( (pCtx->cr4 & X86_CR4_PAE)
4211 && (pCtx->msrEFER & MSR_K6_EFER_LME))
4212 fValid = UINT64_C(0x000ffffffffff014);
4213 else if (pCtx->cr4 & X86_CR4_PAE)
4214 fValid = UINT64_C(0xfffffff4);
4215 else
4216 fValid = UINT64_C(0xfffff014);
4217 if (uNewCrX & ~fValid)
4218 {
4219 Log(("Automatically clearing reserved bits in CR3 load: NewCR3=%#llx ClearedBits=%#llx\n",
4220 uNewCrX, uNewCrX & ~fValid));
4221 uNewCrX &= fValid;
4222 }
4223
4224 /** @todo If we're in PAE mode we should check the PDPTRs for
4225 * invalid bits. */
4226
4227 /* Make the change. */
4228 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4229 {
4230 rc = CPUMSetGuestCR3(pVCpu, uNewCrX);
4231 AssertRCSuccessReturn(rc, rc);
4232 }
4233 else
4234 pCtx->cr3 = uNewCrX;
4235
4236 /* Inform PGM. */
4237 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4238 {
4239 if (pCtx->cr0 & X86_CR0_PG)
4240 {
4241 rc = PGMFlushTLB(pVCpu, pCtx->cr3, !(pCtx->cr4 & X86_CR4_PGE));
4242 AssertRCReturn(rc, rc);
4243 /* ignore informational status codes */
4244 }
4245 }
4246 rcStrict = VINF_SUCCESS;
4247 break;
4248 }
4249
4250 /*
4251 * CR4 is a bit more tedious as there are bits which cannot be cleared
4252 * under some circumstances and such.
4253 */
4254 case 4:
4255 {
4256 uint64_t const uOldCrX = pCtx->cr4;
4257
4258 /* reserved bits */
4259 uint32_t fValid = X86_CR4_VME | X86_CR4_PVI
4260 | X86_CR4_TSD | X86_CR4_DE
4261 | X86_CR4_PSE | X86_CR4_PAE
4262 | X86_CR4_MCE | X86_CR4_PGE
4263 | X86_CR4_PCE | X86_CR4_OSFSXR
4264 | X86_CR4_OSXMMEEXCPT;
4265 //if (xxx)
4266 // fValid |= X86_CR4_VMXE;
4267 //if (xxx)
4268 // fValid |= X86_CR4_OSXSAVE;
4269 if (uNewCrX & ~(uint64_t)fValid)
4270 {
4271 Log(("Trying to set reserved CR4 bits: NewCR4=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
4272 return iemRaiseGeneralProtectionFault0(pIemCpu);
4273 }
4274
4275 /* long mode checks. */
4276 if ( (uOldCrX & X86_CR4_PAE)
4277 && !(uNewCrX & X86_CR4_PAE)
4278 && CPUMIsGuestInLongModeEx(pCtx) )
4279 {
4280 Log(("Trying to set clear CR4.PAE while long mode is active\n"));
4281 return iemRaiseGeneralProtectionFault0(pIemCpu);
4282 }
4283
4284
4285 /*
4286 * Change it.
4287 */
4288 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4289 {
4290 rc = CPUMSetGuestCR4(pVCpu, uNewCrX);
4291 AssertRCSuccessReturn(rc, rc);
4292 }
4293 else
4294 pCtx->cr4 = uNewCrX;
4295 Assert(pCtx->cr4 == uNewCrX);
4296
4297 /*
4298 * Notify SELM and PGM.
4299 */
4300 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4301 {
4302 /* SELM - VME may change things wrt to the TSS shadowing. */
4303 if ((uNewCrX ^ uOldCrX) & X86_CR4_VME)
4304 {
4305 Log(("iemCImpl_load_CrX: VME %d -> %d => Setting VMCPU_FF_SELM_SYNC_TSS\n",
4306 RT_BOOL(uOldCrX & X86_CR4_VME), RT_BOOL(uNewCrX & X86_CR4_VME) ));
4307#ifdef VBOX_WITH_RAW_MODE
4308 if (!HMIsEnabled(IEMCPU_TO_VM(pIemCpu)))
4309 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);
4310#endif
4311 }
4312
4313 /* PGM - flushing and mode. */
4314 if ((uNewCrX ^ uOldCrX) & (X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE))
4315 {
4316 rc = PGMFlushTLB(pVCpu, pCtx->cr3, true /* global */);
4317 AssertRCReturn(rc, rc);
4318 /* ignore informational status codes */
4319 }
4320 rcStrict = PGMChangeMode(pVCpu, pCtx->cr0, pCtx->cr4, pCtx->msrEFER);
4321 }
4322 else
4323 rcStrict = VINF_SUCCESS;
4324 break;
4325 }
4326
4327 /*
4328 * CR8 maps to the APIC TPR.
4329 */
4330 case 8:
4331 if (uNewCrX & ~(uint64_t)0xf)
4332 {
4333 Log(("Trying to set reserved CR8 bits (%#RX64)\n", uNewCrX));
4334 return iemRaiseGeneralProtectionFault0(pIemCpu);
4335 }
4336
4337 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4338 PDMApicSetTPR(IEMCPU_TO_VMCPU(pIemCpu), (uint8_t)uNewCrX << 4);
4339 rcStrict = VINF_SUCCESS;
4340 break;
4341
4342 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
4343 }
4344
4345 /*
4346 * Advance the RIP on success.
4347 */
4348 if (RT_SUCCESS(rcStrict))
4349 {
4350 if (rcStrict != VINF_SUCCESS)
4351 rcStrict = iemSetPassUpStatus(pIemCpu, rcStrict);
4352 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4353 }
4354
4355 return rcStrict;
4356}
4357
4358
4359/**
4360 * Implements mov CRx,GReg.
4361 *
4362 * @param iCrReg The CRx register to write (valid).
4363 * @param iGReg The general register to load the DRx value from.
4364 */
4365IEM_CIMPL_DEF_2(iemCImpl_mov_Cd_Rd, uint8_t, iCrReg, uint8_t, iGReg)
4366{
4367 if (pIemCpu->uCpl != 0)
4368 return iemRaiseGeneralProtectionFault0(pIemCpu);
4369 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
4370
4371 /*
4372 * Read the new value from the source register and call common worker.
4373 */
4374 uint64_t uNewCrX;
4375 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
4376 uNewCrX = iemGRegFetchU64(pIemCpu, iGReg);
4377 else
4378 uNewCrX = iemGRegFetchU32(pIemCpu, iGReg);
4379 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, iCrReg, uNewCrX);
4380}
4381
4382
4383/**
4384 * Implements 'LMSW r/m16'
4385 *
4386 * @param u16NewMsw The new value.
4387 */
4388IEM_CIMPL_DEF_1(iemCImpl_lmsw, uint16_t, u16NewMsw)
4389{
4390 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4391
4392 if (pIemCpu->uCpl != 0)
4393 return iemRaiseGeneralProtectionFault0(pIemCpu);
4394 Assert(!pCtx->eflags.Bits.u1VM);
4395
4396 /*
4397 * Compose the new CR0 value and call common worker.
4398 */
4399 uint64_t uNewCr0 = pCtx->cr0 & ~(X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
4400 uNewCr0 |= u16NewMsw & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
4401 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, /*cr*/ 0, uNewCr0);
4402}
4403
4404
4405/**
4406 * Implements 'CLTS'.
4407 */
4408IEM_CIMPL_DEF_0(iemCImpl_clts)
4409{
4410 if (pIemCpu->uCpl != 0)
4411 return iemRaiseGeneralProtectionFault0(pIemCpu);
4412
4413 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4414 uint64_t uNewCr0 = pCtx->cr0;
4415 uNewCr0 &= ~X86_CR0_TS;
4416 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, /*cr*/ 0, uNewCr0);
4417}
4418
4419
4420/**
4421 * Implements mov GReg,DRx.
4422 *
4423 * @param iGReg The general register to store the DRx value in.
4424 * @param iDrReg The DRx register to read (0-7).
4425 */
4426IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Dd, uint8_t, iGReg, uint8_t, iDrReg)
4427{
4428 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4429
4430 /*
4431 * Check preconditions.
4432 */
4433
4434 /* Raise GPs. */
4435 if (pIemCpu->uCpl != 0)
4436 return iemRaiseGeneralProtectionFault0(pIemCpu);
4437 Assert(!pCtx->eflags.Bits.u1VM);
4438
4439 if ( (iDrReg == 4 || iDrReg == 5)
4440 && (pCtx->cr4 & X86_CR4_DE) )
4441 {
4442 Log(("mov r%u,dr%u: CR4.DE=1 -> #GP(0)\n", iGReg, iDrReg));
4443 return iemRaiseGeneralProtectionFault0(pIemCpu);
4444 }
4445
4446 /* Raise #DB if general access detect is enabled. */
4447 if (pCtx->dr[7] & X86_DR7_GD)
4448 {
4449 Log(("mov r%u,dr%u: DR7.GD=1 -> #DB\n", iGReg, iDrReg));
4450 return iemRaiseDebugException(pIemCpu);
4451 }
4452
4453 /*
4454 * Read the debug register and store it in the specified general register.
4455 */
4456 uint64_t drX;
4457 switch (iDrReg)
4458 {
4459 case 0: drX = pCtx->dr[0]; break;
4460 case 1: drX = pCtx->dr[1]; break;
4461 case 2: drX = pCtx->dr[2]; break;
4462 case 3: drX = pCtx->dr[3]; break;
4463 case 6:
4464 case 4:
4465 drX = pCtx->dr[6];
4466 drX |= X86_DR6_RA1_MASK;
4467 drX &= ~X86_DR6_RAZ_MASK;
4468 break;
4469 case 7:
4470 case 5:
4471 drX = pCtx->dr[7];
4472 drX |=X86_DR7_RA1_MASK;
4473 drX &= ~X86_DR7_RAZ_MASK;
4474 break;
4475 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
4476 }
4477
4478 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
4479 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = drX;
4480 else
4481 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = (uint32_t)drX;
4482
4483 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4484 return VINF_SUCCESS;
4485}
4486
4487
4488/**
4489 * Implements mov DRx,GReg.
4490 *
4491 * @param iDrReg The DRx register to write (valid).
4492 * @param iGReg The general register to load the DRx value from.
4493 */
4494IEM_CIMPL_DEF_2(iemCImpl_mov_Dd_Rd, uint8_t, iDrReg, uint8_t, iGReg)
4495{
4496 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4497
4498 /*
4499 * Check preconditions.
4500 */
4501 if (pIemCpu->uCpl != 0)
4502 return iemRaiseGeneralProtectionFault0(pIemCpu);
4503 Assert(!pCtx->eflags.Bits.u1VM);
4504
4505 if (iDrReg == 4 || iDrReg == 5)
4506 {
4507 if (pCtx->cr4 & X86_CR4_DE)
4508 {
4509 Log(("mov dr%u,r%u: CR4.DE=1 -> #GP(0)\n", iDrReg, iGReg));
4510 return iemRaiseGeneralProtectionFault0(pIemCpu);
4511 }
4512 iDrReg += 2;
4513 }
4514
4515 /* Raise #DB if general access detect is enabled. */
4516 /** @todo is \#DB/DR7.GD raised before any reserved high bits in DR7/DR6
4517 * \#GP? */
4518 if (pCtx->dr[7] & X86_DR7_GD)
4519 {
4520 Log(("mov dr%u,r%u: DR7.GD=1 -> #DB\n", iDrReg, iGReg));
4521 return iemRaiseDebugException(pIemCpu);
4522 }
4523
4524 /*
4525 * Read the new value from the source register.
4526 */
4527 uint64_t uNewDrX;
4528 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
4529 uNewDrX = iemGRegFetchU64(pIemCpu, iGReg);
4530 else
4531 uNewDrX = iemGRegFetchU32(pIemCpu, iGReg);
4532
4533 /*
4534 * Adjust it.
4535 */
4536 switch (iDrReg)
4537 {
4538 case 0:
4539 case 1:
4540 case 2:
4541 case 3:
4542 /* nothing to adjust */
4543 break;
4544
4545 case 6:
4546 if (uNewDrX & X86_DR6_MBZ_MASK)
4547 {
4548 Log(("mov dr%u,%#llx: DR6 high bits are not zero -> #GP(0)\n", iDrReg, uNewDrX));
4549 return iemRaiseGeneralProtectionFault0(pIemCpu);
4550 }
4551 uNewDrX |= X86_DR6_RA1_MASK;
4552 uNewDrX &= ~X86_DR6_RAZ_MASK;
4553 break;
4554
4555 case 7:
4556 if (uNewDrX & X86_DR7_MBZ_MASK)
4557 {
4558 Log(("mov dr%u,%#llx: DR7 high bits are not zero -> #GP(0)\n", iDrReg, uNewDrX));
4559 return iemRaiseGeneralProtectionFault0(pIemCpu);
4560 }
4561 uNewDrX |= X86_DR7_RA1_MASK;
4562 uNewDrX &= ~X86_DR7_RAZ_MASK;
4563 break;
4564
4565 IEM_NOT_REACHED_DEFAULT_CASE_RET();
4566 }
4567
4568 /*
4569 * Do the actual setting.
4570 */
4571 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4572 {
4573 int rc = CPUMSetGuestDRx(IEMCPU_TO_VMCPU(pIemCpu), iDrReg, uNewDrX);
4574 AssertRCSuccessReturn(rc, RT_SUCCESS_NP(rc) ? VERR_INTERNAL_ERROR : rc);
4575 }
4576 else
4577 pCtx->dr[iDrReg] = uNewDrX;
4578
4579 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4580 return VINF_SUCCESS;
4581}
4582
4583
4584/**
4585 * Implements 'INVLPG m'.
4586 *
4587 * @param GCPtrPage The effective address of the page to invalidate.
4588 * @remarks Updates the RIP.
4589 */
4590IEM_CIMPL_DEF_1(iemCImpl_invlpg, uint8_t, GCPtrPage)
4591{
4592 /* ring-0 only. */
4593 if (pIemCpu->uCpl != 0)
4594 return iemRaiseGeneralProtectionFault0(pIemCpu);
4595 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
4596
4597 int rc = PGMInvalidatePage(IEMCPU_TO_VMCPU(pIemCpu), GCPtrPage);
4598 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4599
4600 if (rc == VINF_SUCCESS)
4601 return VINF_SUCCESS;
4602 if (rc == VINF_PGM_SYNC_CR3)
4603 return iemSetPassUpStatus(pIemCpu, rc);
4604
4605 AssertMsg(rc == VINF_EM_RAW_EMULATE_INSTR || RT_FAILURE_NP(rc), ("%Rrc\n", rc));
4606 Log(("PGMInvalidatePage(%RGv) -> %Rrc\n", rc));
4607 return rc;
4608}
4609
4610
4611/**
4612 * Implements RDTSC.
4613 */
4614IEM_CIMPL_DEF_0(iemCImpl_rdtsc)
4615{
4616 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4617
4618 /*
4619 * Check preconditions.
4620 */
4621 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_EDX(X86_CPUID_FEATURE_EDX_TSC))
4622 return iemRaiseUndefinedOpcode(pIemCpu);
4623
4624 if ( (pCtx->cr4 & X86_CR4_TSD)
4625 && pIemCpu->uCpl != 0)
4626 {
4627 Log(("rdtsc: CR4.TSD and CPL=%u -> #GP(0)\n", pIemCpu->uCpl));
4628 return iemRaiseGeneralProtectionFault0(pIemCpu);
4629 }
4630
4631 /*
4632 * Do the job.
4633 */
4634 uint64_t uTicks = TMCpuTickGet(IEMCPU_TO_VMCPU(pIemCpu));
4635 pCtx->rax = (uint32_t)uTicks;
4636 pCtx->rdx = uTicks >> 32;
4637#ifdef IEM_VERIFICATION_MODE_FULL
4638 pIemCpu->fIgnoreRaxRdx = true;
4639#endif
4640
4641 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4642 return VINF_SUCCESS;
4643}
4644
4645
4646/**
4647 * Implements RDMSR.
4648 */
4649IEM_CIMPL_DEF_0(iemCImpl_rdmsr)
4650{
4651 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4652
4653 /*
4654 * Check preconditions.
4655 */
4656 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_EDX(X86_CPUID_FEATURE_EDX_MSR))
4657 return iemRaiseUndefinedOpcode(pIemCpu);
4658 if (pIemCpu->uCpl != 0)
4659 return iemRaiseGeneralProtectionFault0(pIemCpu);
4660
4661 /*
4662 * Do the job.
4663 */
4664 RTUINT64U uValue;
4665 int rc = CPUMQueryGuestMsr(IEMCPU_TO_VMCPU(pIemCpu), pCtx->ecx, &uValue.u);
4666 if (rc != VINF_SUCCESS)
4667 {
4668#ifdef IN_RING3
4669 static uint32_t s_cTimes = 0;
4670 if (s_cTimes++ < 10)
4671 LogRel(("IEM: rdmsr(%#x) -> GP(0)\n", pCtx->ecx));
4672#endif
4673 Log(("IEM: rdmsr(%#x) -> GP(0)\n", pCtx->ecx));
4674 AssertMsgReturn(rc == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", rc), VERR_IPE_UNEXPECTED_STATUS);
4675 return iemRaiseGeneralProtectionFault0(pIemCpu);
4676 }
4677
4678 pCtx->rax = uValue.s.Lo;
4679 pCtx->rdx = uValue.s.Hi;
4680
4681 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4682 return VINF_SUCCESS;
4683}
4684
4685
4686/**
4687 * Implements WRMSR.
4688 */
4689IEM_CIMPL_DEF_0(iemCImpl_wrmsr)
4690{
4691 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4692
4693 /*
4694 * Check preconditions.
4695 */
4696 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_EDX(X86_CPUID_FEATURE_EDX_MSR))
4697 return iemRaiseUndefinedOpcode(pIemCpu);
4698 if (pIemCpu->uCpl != 0)
4699 return iemRaiseGeneralProtectionFault0(pIemCpu);
4700
4701 /*
4702 * Do the job.
4703 */
4704 RTUINT64U uValue;
4705 uValue.s.Lo = pCtx->eax;
4706 uValue.s.Hi = pCtx->edx;
4707
4708 int rc;
4709 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4710 rc = CPUMSetGuestMsr(IEMCPU_TO_VMCPU(pIemCpu), pCtx->ecx, uValue.u);
4711 else
4712 {
4713 CPUMCTX CtxTmp = *pCtx;
4714 rc = CPUMSetGuestMsr(IEMCPU_TO_VMCPU(pIemCpu), pCtx->ecx, uValue.u);
4715 PCPUMCTX pCtx2 = CPUMQueryGuestCtxPtr(IEMCPU_TO_VMCPU(pIemCpu));
4716 *pCtx = *pCtx2;
4717 *pCtx2 = CtxTmp;
4718 }
4719 if (rc != VINF_SUCCESS)
4720 {
4721#ifdef IN_RING3
4722 static uint32_t s_cTimes = 0;
4723 if (s_cTimes++ < 10)
4724 LogRel(("IEM: wrmsr(%#x,%#x`%08x) -> GP(0)\n", pCtx->ecx, uValue.s.Hi, uValue.s.Lo));
4725#endif
4726 Log(("IEM: wrmsr(%#x,%#x`%08x) -> GP(0)\n", pCtx->ecx, uValue.s.Hi, uValue.s.Lo));
4727 AssertMsgReturn(rc == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", rc), VERR_IPE_UNEXPECTED_STATUS);
4728 return iemRaiseGeneralProtectionFault0(pIemCpu);
4729 }
4730
4731 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4732 return VINF_SUCCESS;
4733}
4734
4735
4736/**
4737 * Implements 'IN eAX, port'.
4738 *
4739 * @param u16Port The source port.
4740 * @param cbReg The register size.
4741 */
4742IEM_CIMPL_DEF_2(iemCImpl_in, uint16_t, u16Port, uint8_t, cbReg)
4743{
4744 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4745
4746 /*
4747 * CPL check
4748 */
4749 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pIemCpu, pCtx, u16Port, cbReg);
4750 if (rcStrict != VINF_SUCCESS)
4751 return rcStrict;
4752
4753 /*
4754 * Perform the I/O.
4755 */
4756 uint32_t u32Value;
4757 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4758 rcStrict = IOMIOPortRead(IEMCPU_TO_VM(pIemCpu), IEMCPU_TO_VMCPU(pIemCpu), u16Port, &u32Value, cbReg);
4759 else
4760 rcStrict = iemVerifyFakeIOPortRead(pIemCpu, u16Port, &u32Value, cbReg);
4761 if (IOM_SUCCESS(rcStrict))
4762 {
4763 switch (cbReg)
4764 {
4765 case 1: pCtx->al = (uint8_t)u32Value; break;
4766 case 2: pCtx->ax = (uint16_t)u32Value; break;
4767 case 4: pCtx->rax = u32Value; break;
4768 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
4769 }
4770 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4771 pIemCpu->cPotentialExits++;
4772 if (rcStrict != VINF_SUCCESS)
4773 rcStrict = iemSetPassUpStatus(pIemCpu, rcStrict);
4774 Assert(rcStrict == VINF_SUCCESS); /* assumed below */
4775
4776 /*
4777 * Check for I/O breakpoints.
4778 */
4779 uint32_t const uDr7 = pCtx->dr[7];
4780 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
4781 && X86_DR7_ANY_RW_IO(uDr7)
4782 && (pCtx->cr4 & X86_CR4_DE))
4783 || DBGFBpIsHwIoArmed(IEMCPU_TO_VM(pIemCpu))))
4784 {
4785 rcStrict = DBGFBpCheckIo(IEMCPU_TO_VM(pIemCpu), IEMCPU_TO_VMCPU(pIemCpu), pCtx, u16Port, cbReg);
4786 if (rcStrict == VINF_EM_RAW_GUEST_TRAP)
4787 rcStrict = iemRaiseDebugException(pIemCpu);
4788 }
4789 }
4790
4791 return rcStrict;
4792}
4793
4794
4795/**
4796 * Implements 'IN eAX, DX'.
4797 *
4798 * @param cbReg The register size.
4799 */
4800IEM_CIMPL_DEF_1(iemCImpl_in_eAX_DX, uint8_t, cbReg)
4801{
4802 return IEM_CIMPL_CALL_2(iemCImpl_in, pIemCpu->CTX_SUFF(pCtx)->dx, cbReg);
4803}
4804
4805
4806/**
4807 * Implements 'OUT port, eAX'.
4808 *
4809 * @param u16Port The destination port.
4810 * @param cbReg The register size.
4811 */
4812IEM_CIMPL_DEF_2(iemCImpl_out, uint16_t, u16Port, uint8_t, cbReg)
4813{
4814 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4815
4816 /*
4817 * CPL check
4818 */
4819 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pIemCpu, pCtx, u16Port, cbReg);
4820 if (rcStrict != VINF_SUCCESS)
4821 return rcStrict;
4822
4823 /*
4824 * Perform the I/O.
4825 */
4826 uint32_t u32Value;
4827 switch (cbReg)
4828 {
4829 case 1: u32Value = pCtx->al; break;
4830 case 2: u32Value = pCtx->ax; break;
4831 case 4: u32Value = pCtx->eax; break;
4832 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
4833 }
4834 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4835 rcStrict = IOMIOPortWrite(IEMCPU_TO_VM(pIemCpu), IEMCPU_TO_VMCPU(pIemCpu), u16Port, u32Value, cbReg);
4836 else
4837 rcStrict = iemVerifyFakeIOPortWrite(pIemCpu, u16Port, u32Value, cbReg);
4838 if (IOM_SUCCESS(rcStrict))
4839 {
4840 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4841 pIemCpu->cPotentialExits++;
4842 if (rcStrict != VINF_SUCCESS)
4843 rcStrict = iemSetPassUpStatus(pIemCpu, rcStrict);
4844 Assert(rcStrict == VINF_SUCCESS); /* assumed below */
4845
4846 /*
4847 * Check for I/O breakpoints.
4848 */
4849 uint32_t const uDr7 = pCtx->dr[7];
4850 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
4851 && X86_DR7_ANY_RW_IO(uDr7)
4852 && (pCtx->cr4 & X86_CR4_DE))
4853 || DBGFBpIsHwIoArmed(IEMCPU_TO_VM(pIemCpu))))
4854 {
4855 rcStrict = DBGFBpCheckIo(IEMCPU_TO_VM(pIemCpu), IEMCPU_TO_VMCPU(pIemCpu), pCtx, u16Port, cbReg);
4856 if (rcStrict == VINF_EM_RAW_GUEST_TRAP)
4857 rcStrict = iemRaiseDebugException(pIemCpu);
4858 }
4859 }
4860 return rcStrict;
4861}
4862
4863
4864/**
4865 * Implements 'OUT DX, eAX'.
4866 *
4867 * @param cbReg The register size.
4868 */
4869IEM_CIMPL_DEF_1(iemCImpl_out_DX_eAX, uint8_t, cbReg)
4870{
4871 return IEM_CIMPL_CALL_2(iemCImpl_out, pIemCpu->CTX_SUFF(pCtx)->dx, cbReg);
4872}
4873
4874
4875/**
4876 * Implements 'CLI'.
4877 */
4878IEM_CIMPL_DEF_0(iemCImpl_cli)
4879{
4880 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4881 uint32_t fEfl = IEMMISC_GET_EFL(pIemCpu, pCtx);
4882 uint32_t const fEflOld = fEfl;
4883 if (pCtx->cr0 & X86_CR0_PE)
4884 {
4885 uint8_t const uIopl = X86_EFL_GET_IOPL(fEfl);
4886 if (!(fEfl & X86_EFL_VM))
4887 {
4888 if (pIemCpu->uCpl <= uIopl)
4889 fEfl &= ~X86_EFL_IF;
4890 else if ( pIemCpu->uCpl == 3
4891 && (pCtx->cr4 & X86_CR4_PVI) )
4892 fEfl &= ~X86_EFL_VIF;
4893 else
4894 return iemRaiseGeneralProtectionFault0(pIemCpu);
4895 }
4896 /* V8086 */
4897 else if (uIopl == 3)
4898 fEfl &= ~X86_EFL_IF;
4899 else if ( uIopl < 3
4900 && (pCtx->cr4 & X86_CR4_VME) )
4901 fEfl &= ~X86_EFL_VIF;
4902 else
4903 return iemRaiseGeneralProtectionFault0(pIemCpu);
4904 }
4905 /* real mode */
4906 else
4907 fEfl &= ~X86_EFL_IF;
4908
4909 /* Commit. */
4910 IEMMISC_SET_EFL(pIemCpu, pCtx, fEfl);
4911 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4912 Log2(("CLI: %#x -> %#x\n", fEflOld, fEfl)); NOREF(fEflOld);
4913 return VINF_SUCCESS;
4914}
4915
4916
4917/**
4918 * Implements 'STI'.
4919 */
4920IEM_CIMPL_DEF_0(iemCImpl_sti)
4921{
4922 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4923 uint32_t fEfl = IEMMISC_GET_EFL(pIemCpu, pCtx);
4924 uint32_t const fEflOld = fEfl;
4925
4926 if (pCtx->cr0 & X86_CR0_PE)
4927 {
4928 uint8_t const uIopl = X86_EFL_GET_IOPL(fEfl);
4929 if (!(fEfl & X86_EFL_VM))
4930 {
4931 if (pIemCpu->uCpl <= uIopl)
4932 fEfl |= X86_EFL_IF;
4933 else if ( pIemCpu->uCpl == 3
4934 && (pCtx->cr4 & X86_CR4_PVI)
4935 && !(fEfl & X86_EFL_VIP) )
4936 fEfl |= X86_EFL_VIF;
4937 else
4938 return iemRaiseGeneralProtectionFault0(pIemCpu);
4939 }
4940 /* V8086 */
4941 else if (uIopl == 3)
4942 fEfl |= X86_EFL_IF;
4943 else if ( uIopl < 3
4944 && (pCtx->cr4 & X86_CR4_VME)
4945 && !(fEfl & X86_EFL_VIP) )
4946 fEfl |= X86_EFL_VIF;
4947 else
4948 return iemRaiseGeneralProtectionFault0(pIemCpu);
4949 }
4950 /* real mode */
4951 else
4952 fEfl |= X86_EFL_IF;
4953
4954 /* Commit. */
4955 IEMMISC_SET_EFL(pIemCpu, pCtx, fEfl);
4956 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4957 if ((!(fEflOld & X86_EFL_IF) && (fEfl & X86_EFL_IF)) || IEM_FULL_VERIFICATION_REM_ENABLED(pIemCpu))
4958 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
4959 Log2(("STI: %#x -> %#x\n", fEflOld, fEfl));
4960 return VINF_SUCCESS;
4961}
4962
4963
4964/**
4965 * Implements 'HLT'.
4966 */
4967IEM_CIMPL_DEF_0(iemCImpl_hlt)
4968{
4969 if (pIemCpu->uCpl != 0)
4970 return iemRaiseGeneralProtectionFault0(pIemCpu);
4971 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4972 return VINF_EM_HALT;
4973}
4974
4975
4976/**
4977 * Implements 'MONITOR'.
4978 */
4979IEM_CIMPL_DEF_1(iemCImpl_monitor, uint8_t, iEffSeg)
4980{
4981 /*
4982 * Permission checks.
4983 */
4984 if (pIemCpu->uCpl != 0)
4985 {
4986 Log2(("monitor: CPL != 0\n"));
4987 return iemRaiseUndefinedOpcode(pIemCpu); /** @todo MSR[0xC0010015].MonMwaitUserEn if we care. */
4988 }
4989 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_ECX(X86_CPUID_FEATURE_ECX_MONITOR))
4990 {
4991 Log2(("monitor: Not in CPUID\n"));
4992 return iemRaiseUndefinedOpcode(pIemCpu);
4993 }
4994
4995 /*
4996 * Gather the operands and validate them.
4997 */
4998 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4999 RTGCPTR GCPtrMem = pIemCpu->enmCpuMode == IEMMODE_64BIT ? pCtx->rax : pCtx->eax;
5000 uint32_t uEcx = pCtx->ecx;
5001 uint32_t uEdx = pCtx->edx;
5002/** @todo Test whether EAX or ECX is processed first, i.e. do we get \#PF or
5003 * \#GP first. */
5004 if (uEcx != 0)
5005 {
5006 Log2(("monitor rax=%RX64, ecx=%RX32, edx=%RX32; ECX != 0 -> #GP(0)\n", GCPtrMem, uEcx, uEdx));
5007 return iemRaiseGeneralProtectionFault0(pIemCpu);
5008 }
5009
5010 VBOXSTRICTRC rcStrict = iemMemApplySegment(pIemCpu, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, iEffSeg, 1, &GCPtrMem);
5011 if (rcStrict != VINF_SUCCESS)
5012 return rcStrict;
5013
5014 RTGCPHYS GCPhysMem;
5015 rcStrict = iemMemPageTranslateAndCheckAccess(pIemCpu, GCPtrMem, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, &GCPhysMem);
5016 if (rcStrict != VINF_SUCCESS)
5017 return rcStrict;
5018
5019 /*
5020 * Call EM to prepare the monitor/wait.
5021 */
5022 rcStrict = EMMonitorWaitPrepare(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rax, pCtx->rcx, pCtx->rdx, GCPhysMem);
5023 Assert(rcStrict == VINF_SUCCESS);
5024
5025 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5026 return rcStrict;
5027}
5028
5029
5030/**
5031 * Implements 'MWAIT'.
5032 */
5033IEM_CIMPL_DEF_0(iemCImpl_mwait)
5034{
5035 /*
5036 * Permission checks.
5037 */
5038 if (pIemCpu->uCpl != 0)
5039 {
5040 Log2(("mwait: CPL != 0\n"));
5041 /** @todo MSR[0xC0010015].MonMwaitUserEn if we care. (Remember to check
5042 * EFLAGS.VM then.) */
5043 return iemRaiseUndefinedOpcode(pIemCpu);
5044 }
5045 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_ECX(X86_CPUID_FEATURE_ECX_MONITOR))
5046 {
5047 Log2(("mwait: Not in CPUID\n"));
5048 return iemRaiseUndefinedOpcode(pIemCpu);
5049 }
5050
5051 /*
5052 * Gather the operands and validate them.
5053 */
5054 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5055 uint32_t uEax = pCtx->eax;
5056 uint32_t uEcx = pCtx->ecx;
5057 if (uEcx != 0)
5058 {
5059 /* Only supported extension is break on IRQ when IF=0. */
5060 if (uEcx > 1)
5061 {
5062 Log2(("mwait eax=%RX32, ecx=%RX32; ECX > 1 -> #GP(0)\n", uEax, uEcx));
5063 return iemRaiseGeneralProtectionFault0(pIemCpu);
5064 }
5065 uint32_t fMWaitFeatures = 0;
5066 uint32_t uIgnore = 0;
5067 CPUMGetGuestCpuId(IEMCPU_TO_VMCPU(pIemCpu), 5, &uIgnore, &uIgnore, &fMWaitFeatures, &uIgnore);
5068 if ( (fMWaitFeatures & (X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
5069 != (X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
5070 {
5071 Log2(("mwait eax=%RX32, ecx=%RX32; break-on-IRQ-IF=0 extension not enabled -> #GP(0)\n", uEax, uEcx));
5072 return iemRaiseGeneralProtectionFault0(pIemCpu);
5073 }
5074 }
5075
5076 /*
5077 * Call EM to prepare the monitor/wait.
5078 */
5079 VBOXSTRICTRC rcStrict = EMMonitorWaitPerform(IEMCPU_TO_VMCPU(pIemCpu), uEax, uEcx);
5080
5081 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5082 return rcStrict;
5083}
5084
5085
5086/**
5087 * Implements 'SWAPGS'.
5088 */
5089IEM_CIMPL_DEF_0(iemCImpl_swapgs)
5090{
5091 Assert(pIemCpu->enmCpuMode == IEMMODE_64BIT); /* Caller checks this. */
5092
5093 /*
5094 * Permission checks.
5095 */
5096 if (pIemCpu->uCpl != 0)
5097 {
5098 Log2(("swapgs: CPL != 0\n"));
5099 return iemRaiseUndefinedOpcode(pIemCpu);
5100 }
5101
5102 /*
5103 * Do the job.
5104 */
5105 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5106 uint64_t uOtherGsBase = pCtx->msrKERNELGSBASE;
5107 pCtx->msrKERNELGSBASE = pCtx->gs.u64Base;
5108 pCtx->gs.u64Base = uOtherGsBase;
5109
5110 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5111 return VINF_SUCCESS;
5112}
5113
5114
5115/**
5116 * Implements 'CPUID'.
5117 */
5118IEM_CIMPL_DEF_0(iemCImpl_cpuid)
5119{
5120 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5121
5122 CPUMGetGuestCpuId(IEMCPU_TO_VMCPU(pIemCpu), pCtx->eax, &pCtx->eax, &pCtx->ebx, &pCtx->ecx, &pCtx->edx);
5123 pCtx->rax &= UINT32_C(0xffffffff);
5124 pCtx->rbx &= UINT32_C(0xffffffff);
5125 pCtx->rcx &= UINT32_C(0xffffffff);
5126 pCtx->rdx &= UINT32_C(0xffffffff);
5127
5128 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5129 return VINF_SUCCESS;
5130}
5131
5132
5133/**
5134 * Implements 'AAD'.
5135 *
5136 * @param bImm The immediate operand.
5137 */
5138IEM_CIMPL_DEF_1(iemCImpl_aad, uint8_t, bImm)
5139{
5140 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5141
5142 uint16_t const ax = pCtx->ax;
5143 uint8_t const al = (uint8_t)ax + (uint8_t)(ax >> 8) * bImm;
5144 pCtx->ax = al;
5145 iemHlpUpdateArithEFlagsU8(pIemCpu, al,
5146 X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF,
5147 X86_EFL_OF | X86_EFL_AF | X86_EFL_CF);
5148
5149 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5150 return VINF_SUCCESS;
5151}
5152
5153
5154/**
5155 * Implements 'AAM'.
5156 *
5157 * @param bImm The immediate operand. Cannot be 0.
5158 */
5159IEM_CIMPL_DEF_1(iemCImpl_aam, uint8_t, bImm)
5160{
5161 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5162 Assert(bImm != 0); /* #DE on 0 is handled in the decoder. */
5163
5164 uint16_t const ax = pCtx->ax;
5165 uint8_t const al = (uint8_t)ax % bImm;
5166 uint8_t const ah = (uint8_t)ax / bImm;
5167 pCtx->ax = (ah << 8) + al;
5168 iemHlpUpdateArithEFlagsU8(pIemCpu, al,
5169 X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF,
5170 X86_EFL_OF | X86_EFL_AF | X86_EFL_CF);
5171
5172 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5173 return VINF_SUCCESS;
5174}
5175
5176
5177/**
5178 * Implements 'DAA'.
5179 */
5180IEM_CIMPL_DEF_0(iemCImpl_daa)
5181{
5182 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5183
5184 uint8_t const al = pCtx->al;
5185 bool const fCarry = pCtx->eflags.Bits.u1CF;
5186
5187 if ( pCtx->eflags.Bits.u1AF
5188 || (al & 0xf) >= 10)
5189 {
5190 pCtx->al = al + 6;
5191 pCtx->eflags.Bits.u1AF = 1;
5192 }
5193 else
5194 pCtx->eflags.Bits.u1AF = 0;
5195
5196 if (al >= 0x9a || fCarry)
5197 {
5198 pCtx->al += 0x60;
5199 pCtx->eflags.Bits.u1CF = 1;
5200 }
5201 else
5202 pCtx->eflags.Bits.u1CF = 0;
5203
5204 iemHlpUpdateArithEFlagsU8(pIemCpu, pCtx->al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
5205 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5206 return VINF_SUCCESS;
5207}
5208
5209
5210/**
5211 * Implements 'DAS'.
5212 */
5213IEM_CIMPL_DEF_0(iemCImpl_das)
5214{
5215 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5216
5217 uint8_t const uInputAL = pCtx->al;
5218 bool const fCarry = pCtx->eflags.Bits.u1CF;
5219
5220 if ( pCtx->eflags.Bits.u1AF
5221 || (uInputAL & 0xf) >= 10)
5222 {
5223 pCtx->eflags.Bits.u1AF = 1;
5224 if (uInputAL < 6)
5225 pCtx->eflags.Bits.u1CF = 1;
5226 pCtx->al = uInputAL - 6;
5227 }
5228 else
5229 {
5230 pCtx->eflags.Bits.u1AF = 0;
5231 pCtx->eflags.Bits.u1CF = 0;
5232 }
5233
5234 if (uInputAL >= 0x9a || fCarry)
5235 {
5236 pCtx->al -= 0x60;
5237 pCtx->eflags.Bits.u1CF = 1;
5238 }
5239
5240 iemHlpUpdateArithEFlagsU8(pIemCpu, pCtx->al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
5241 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5242 return VINF_SUCCESS;
5243}
5244
5245
5246
5247
5248/*
5249 * Instantiate the various string operation combinations.
5250 */
5251#define OP_SIZE 8
5252#define ADDR_SIZE 16
5253#include "IEMAllCImplStrInstr.cpp.h"
5254#define OP_SIZE 8
5255#define ADDR_SIZE 32
5256#include "IEMAllCImplStrInstr.cpp.h"
5257#define OP_SIZE 8
5258#define ADDR_SIZE 64
5259#include "IEMAllCImplStrInstr.cpp.h"
5260
5261#define OP_SIZE 16
5262#define ADDR_SIZE 16
5263#include "IEMAllCImplStrInstr.cpp.h"
5264#define OP_SIZE 16
5265#define ADDR_SIZE 32
5266#include "IEMAllCImplStrInstr.cpp.h"
5267#define OP_SIZE 16
5268#define ADDR_SIZE 64
5269#include "IEMAllCImplStrInstr.cpp.h"
5270
5271#define OP_SIZE 32
5272#define ADDR_SIZE 16
5273#include "IEMAllCImplStrInstr.cpp.h"
5274#define OP_SIZE 32
5275#define ADDR_SIZE 32
5276#include "IEMAllCImplStrInstr.cpp.h"
5277#define OP_SIZE 32
5278#define ADDR_SIZE 64
5279#include "IEMAllCImplStrInstr.cpp.h"
5280
5281#define OP_SIZE 64
5282#define ADDR_SIZE 32
5283#include "IEMAllCImplStrInstr.cpp.h"
5284#define OP_SIZE 64
5285#define ADDR_SIZE 64
5286#include "IEMAllCImplStrInstr.cpp.h"
5287
5288
5289/**
5290 * Implements 'FINIT' and 'FNINIT'.
5291 *
5292 * @param fCheckXcpts Whether to check for umasked pending exceptions or
5293 * not.
5294 */
5295IEM_CIMPL_DEF_1(iemCImpl_finit, bool, fCheckXcpts)
5296{
5297 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5298
5299 if (pCtx->cr0 & (X86_CR0_EM | X86_CR0_TS))
5300 return iemRaiseDeviceNotAvailable(pIemCpu);
5301
5302 NOREF(fCheckXcpts); /** @todo trigger pending exceptions:
5303 if (fCheckXcpts && TODO )
5304 return iemRaiseMathFault(pIemCpu);
5305 */
5306
5307 if (iemFRegIsFxSaveFormat(pIemCpu))
5308 {
5309 pCtx->fpu.FCW = 0x37f;
5310 pCtx->fpu.FSW = 0;
5311 pCtx->fpu.FTW = 0x00; /* 0 - empty. */
5312 pCtx->fpu.FPUDP = 0;
5313 pCtx->fpu.DS = 0; //??
5314 pCtx->fpu.Rsrvd2= 0;
5315 pCtx->fpu.FPUIP = 0;
5316 pCtx->fpu.CS = 0; //??
5317 pCtx->fpu.Rsrvd1= 0;
5318 pCtx->fpu.FOP = 0;
5319 }
5320 else
5321 {
5322 PX86FPUSTATE pFpu = (PX86FPUSTATE)&pCtx->fpu;
5323 pFpu->FCW = 0x37f;
5324 pFpu->FSW = 0;
5325 pFpu->FTW = 0xffff; /* 11 - empty */
5326 pFpu->FPUOO = 0; //??
5327 pFpu->FPUOS = 0; //??
5328 pFpu->FPUIP = 0;
5329 pFpu->CS = 0; //??
5330 pFpu->FOP = 0;
5331 }
5332
5333 iemHlpUsedFpu(pIemCpu);
5334 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5335 return VINF_SUCCESS;
5336}
5337
5338
5339/**
5340 * Implements 'FXSAVE'.
5341 *
5342 * @param iEffSeg The effective segment.
5343 * @param GCPtrEff The address of the image.
5344 * @param enmEffOpSize The operand size (only REX.W really matters).
5345 */
5346IEM_CIMPL_DEF_3(iemCImpl_fxsave, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
5347{
5348 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5349
5350 /*
5351 * Raise exceptions.
5352 */
5353 if (pCtx->cr0 & X86_CR0_EM)
5354 return iemRaiseUndefinedOpcode(pIemCpu);
5355 if (pCtx->cr0 & (X86_CR0_TS | X86_CR0_EM))
5356 return iemRaiseDeviceNotAvailable(pIemCpu);
5357 if (GCPtrEff & 15)
5358 {
5359 /** @todo CPU/VM detection possible! \#AC might not be signal for
5360 * all/any misalignment sizes, intel says its an implementation detail. */
5361 if ( (pCtx->cr0 & X86_CR0_AM)
5362 && pCtx->eflags.Bits.u1AC
5363 && pIemCpu->uCpl == 3)
5364 return iemRaiseAlignmentCheckException(pIemCpu);
5365 return iemRaiseGeneralProtectionFault0(pIemCpu);
5366 }
5367 AssertReturn(iemFRegIsFxSaveFormat(pIemCpu), VERR_IEM_IPE_2);
5368
5369 /*
5370 * Access the memory.
5371 */
5372 void *pvMem512;
5373 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, &pvMem512, 512, iEffSeg, GCPtrEff, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5374 if (rcStrict != VINF_SUCCESS)
5375 return rcStrict;
5376 PX86FXSTATE pDst = (PX86FXSTATE)pvMem512;
5377
5378 /*
5379 * Store the registers.
5380 */
5381 /** @todo CPU/VM detection possible! If CR4.OSFXSR=0 MXCSR it's
5382 * implementation specific whether MXCSR and XMM0-XMM7 are saved. */
5383
5384 /* common for all formats */
5385 pDst->FCW = pCtx->fpu.FCW;
5386 pDst->FSW = pCtx->fpu.FSW;
5387 pDst->FTW = pCtx->fpu.FTW & UINT16_C(0xff);
5388 pDst->FOP = pCtx->fpu.FOP;
5389 pDst->MXCSR = pCtx->fpu.MXCSR;
5390 pDst->MXCSR_MASK = pCtx->fpu.MXCSR_MASK;
5391 for (uint32_t i = 0; i < RT_ELEMENTS(pDst->aRegs); i++)
5392 {
5393 /** @todo Testcase: What actually happens to the 6 reserved bytes? I'm clearing
5394 * them for now... */
5395 pDst->aRegs[i].au32[0] = pCtx->fpu.aRegs[i].au32[0];
5396 pDst->aRegs[i].au32[1] = pCtx->fpu.aRegs[i].au32[1];
5397 pDst->aRegs[i].au32[2] = pCtx->fpu.aRegs[i].au32[2] & UINT32_C(0xffff);
5398 pDst->aRegs[i].au32[3] = 0;
5399 }
5400
5401 /* FPU IP, CS, DP and DS. */
5402 /** @todo FPU IP, CS, DP and DS cannot be implemented correctly without extra
5403 * state information. :-/
5404 * Storing zeros now to prevent any potential leakage of host info. */
5405 pDst->FPUIP = 0;
5406 pDst->CS = 0;
5407 pDst->Rsrvd1 = 0;
5408 pDst->FPUDP = 0;
5409 pDst->DS = 0;
5410 pDst->Rsrvd2 = 0;
5411
5412 /* XMM registers. */
5413 if ( !(pCtx->msrEFER & MSR_K6_EFER_FFXSR)
5414 || pIemCpu->enmCpuMode != IEMMODE_64BIT
5415 || pIemCpu->uCpl != 0)
5416 {
5417 uint32_t cXmmRegs = enmEffOpSize == IEMMODE_64BIT ? 16 : 8;
5418 for (uint32_t i = 0; i < cXmmRegs; i++)
5419 pDst->aXMM[i] = pCtx->fpu.aXMM[i];
5420 /** @todo Testcase: What happens to the reserved XMM registers? Untouched,
5421 * right? */
5422 }
5423
5424 /*
5425 * Commit the memory.
5426 */
5427 rcStrict = iemMemCommitAndUnmap(pIemCpu, pvMem512, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5428 if (rcStrict != VINF_SUCCESS)
5429 return rcStrict;
5430
5431 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5432 return VINF_SUCCESS;
5433}
5434
5435
5436/**
5437 * Implements 'FXRSTOR'.
5438 *
5439 * @param GCPtrEff The address of the image.
5440 * @param enmEffOpSize The operand size (only REX.W really matters).
5441 */
5442IEM_CIMPL_DEF_3(iemCImpl_fxrstor, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
5443{
5444 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5445
5446 /*
5447 * Raise exceptions.
5448 */
5449 if (pCtx->cr0 & X86_CR0_EM)
5450 return iemRaiseUndefinedOpcode(pIemCpu);
5451 if (pCtx->cr0 & (X86_CR0_TS | X86_CR0_EM))
5452 return iemRaiseDeviceNotAvailable(pIemCpu);
5453 if (GCPtrEff & 15)
5454 {
5455 /** @todo CPU/VM detection possible! \#AC might not be signal for
5456 * all/any misalignment sizes, intel says its an implementation detail. */
5457 if ( (pCtx->cr0 & X86_CR0_AM)
5458 && pCtx->eflags.Bits.u1AC
5459 && pIemCpu->uCpl == 3)
5460 return iemRaiseAlignmentCheckException(pIemCpu);
5461 return iemRaiseGeneralProtectionFault0(pIemCpu);
5462 }
5463 AssertReturn(iemFRegIsFxSaveFormat(pIemCpu), VERR_IEM_IPE_2);
5464
5465 /*
5466 * Access the memory.
5467 */
5468 void *pvMem512;
5469 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, &pvMem512, 512, iEffSeg, GCPtrEff, IEM_ACCESS_DATA_R);
5470 if (rcStrict != VINF_SUCCESS)
5471 return rcStrict;
5472 PCX86FXSTATE pSrc = (PCX86FXSTATE)pvMem512;
5473
5474 /*
5475 * Check the state for stuff which will GP(0).
5476 */
5477 uint32_t const fMXCSR = pSrc->MXCSR;
5478 uint32_t const fMXCSR_MASK = pCtx->fpu.MXCSR_MASK ? pCtx->fpu.MXCSR_MASK : UINT32_C(0xffbf);
5479 if (fMXCSR & ~fMXCSR_MASK)
5480 {
5481 Log(("fxrstor: MXCSR=%#x (MXCSR_MASK=%#x) -> #GP(0)\n", fMXCSR, fMXCSR_MASK));
5482 return iemRaiseGeneralProtectionFault0(pIemCpu);
5483 }
5484
5485 /*
5486 * Load the registers.
5487 */
5488 /** @todo CPU/VM detection possible! If CR4.OSFXSR=0 MXCSR it's
5489 * implementation specific whether MXCSR and XMM0-XMM7 are restored. */
5490
5491 /* common for all formats */
5492 pCtx->fpu.FCW = pSrc->FCW;
5493 pCtx->fpu.FSW = pSrc->FSW;
5494 pCtx->fpu.FTW = pSrc->FTW & UINT16_C(0xff);
5495 pCtx->fpu.FOP = pSrc->FOP;
5496 pCtx->fpu.MXCSR = fMXCSR;
5497 /* (MXCSR_MASK is read-only) */
5498 for (uint32_t i = 0; i < RT_ELEMENTS(pSrc->aRegs); i++)
5499 {
5500 pCtx->fpu.aRegs[i].au32[0] = pSrc->aRegs[i].au32[0];
5501 pCtx->fpu.aRegs[i].au32[1] = pSrc->aRegs[i].au32[1];
5502 pCtx->fpu.aRegs[i].au32[2] = pSrc->aRegs[i].au32[2] & UINT32_C(0xffff);
5503 pCtx->fpu.aRegs[i].au32[3] = 0;
5504 }
5505
5506 /* FPU IP, CS, DP and DS. */
5507 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
5508 {
5509 pCtx->fpu.FPUIP = pSrc->FPUIP;
5510 pCtx->fpu.CS = pSrc->CS;
5511 pCtx->fpu.Rsrvd1 = pSrc->Rsrvd1;
5512 pCtx->fpu.FPUDP = pSrc->FPUDP;
5513 pCtx->fpu.DS = pSrc->DS;
5514 pCtx->fpu.Rsrvd2 = pSrc->Rsrvd2;
5515 }
5516 else
5517 {
5518 pCtx->fpu.FPUIP = pSrc->FPUIP;
5519 pCtx->fpu.CS = pSrc->CS;
5520 pCtx->fpu.Rsrvd1 = 0;
5521 pCtx->fpu.FPUDP = pSrc->FPUDP;
5522 pCtx->fpu.DS = pSrc->DS;
5523 pCtx->fpu.Rsrvd2 = 0;
5524 }
5525
5526 /* XMM registers. */
5527 if ( !(pCtx->msrEFER & MSR_K6_EFER_FFXSR)
5528 || pIemCpu->enmCpuMode != IEMMODE_64BIT
5529 || pIemCpu->uCpl != 0)
5530 {
5531 uint32_t cXmmRegs = enmEffOpSize == IEMMODE_64BIT ? 16 : 8;
5532 for (uint32_t i = 0; i < cXmmRegs; i++)
5533 pCtx->fpu.aXMM[i] = pSrc->aXMM[i];
5534 }
5535
5536 /*
5537 * Commit the memory.
5538 */
5539 rcStrict = iemMemCommitAndUnmap(pIemCpu, pvMem512, IEM_ACCESS_DATA_R);
5540 if (rcStrict != VINF_SUCCESS)
5541 return rcStrict;
5542
5543 iemHlpUsedFpu(pIemCpu);
5544 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5545 return VINF_SUCCESS;
5546}
5547
5548
5549/**
5550 * Commmon routine for fnstenv and fnsave.
5551 *
5552 * @param uPtr Where to store the state.
5553 * @param pCtx The CPU context.
5554 */
5555static void iemCImplCommonFpuStoreEnv(PIEMCPU pIemCpu, IEMMODE enmEffOpSize, RTPTRUNION uPtr, PCCPUMCTX pCtx)
5556{
5557 if (enmEffOpSize == IEMMODE_16BIT)
5558 {
5559 uPtr.pu16[0] = pCtx->fpu.FCW;
5560 uPtr.pu16[1] = pCtx->fpu.FSW;
5561 uPtr.pu16[2] = iemFpuCalcFullFtw(pCtx);
5562 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
5563 {
5564 /** @todo Testcase: How does this work when the FPUIP/CS was saved in
5565 * protected mode or long mode and we save it in real mode? And vice
5566 * versa? And with 32-bit operand size? I think CPU is storing the
5567 * effective address ((CS << 4) + IP) in the offset register and not
5568 * doing any address calculations here. */
5569 uPtr.pu16[3] = (uint16_t)pCtx->fpu.FPUIP;
5570 uPtr.pu16[4] = ((pCtx->fpu.FPUIP >> 4) & UINT16_C(0xf000)) | pCtx->fpu.FOP;
5571 uPtr.pu16[5] = (uint16_t)pCtx->fpu.FPUDP;
5572 uPtr.pu16[6] = (pCtx->fpu.FPUDP >> 4) & UINT16_C(0xf000);
5573 }
5574 else
5575 {
5576 uPtr.pu16[3] = pCtx->fpu.FPUIP;
5577 uPtr.pu16[4] = pCtx->fpu.CS;
5578 uPtr.pu16[5] = pCtx->fpu.FPUDP;
5579 uPtr.pu16[6] = pCtx->fpu.DS;
5580 }
5581 }
5582 else
5583 {
5584 /** @todo Testcase: what is stored in the "gray" areas? (figure 8-9 and 8-10) */
5585 uPtr.pu16[0*2] = pCtx->fpu.FCW;
5586 uPtr.pu16[1*2] = pCtx->fpu.FSW;
5587 uPtr.pu16[2*2] = iemFpuCalcFullFtw(pCtx);
5588 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
5589 {
5590 uPtr.pu16[3*2] = (uint16_t)pCtx->fpu.FPUIP;
5591 uPtr.pu32[4] = ((pCtx->fpu.FPUIP & UINT32_C(0xffff0000)) >> 4) | pCtx->fpu.FOP;
5592 uPtr.pu16[5*2] = (uint16_t)pCtx->fpu.FPUDP;
5593 uPtr.pu32[6] = (pCtx->fpu.FPUDP & UINT32_C(0xffff0000)) >> 4;
5594 }
5595 else
5596 {
5597 uPtr.pu32[3] = pCtx->fpu.FPUIP;
5598 uPtr.pu16[4*2] = pCtx->fpu.CS;
5599 uPtr.pu16[4*2+1]= pCtx->fpu.FOP;
5600 uPtr.pu32[5] = pCtx->fpu.FPUDP;
5601 uPtr.pu16[6*2] = pCtx->fpu.DS;
5602 }
5603 }
5604}
5605
5606
5607/**
5608 * Commmon routine for fldenv and frstor
5609 *
5610 * @param uPtr Where to store the state.
5611 * @param pCtx The CPU context.
5612 */
5613static void iemCImplCommonFpuRestoreEnv(PIEMCPU pIemCpu, IEMMODE enmEffOpSize, RTCPTRUNION uPtr, PCPUMCTX pCtx)
5614{
5615 if (enmEffOpSize == IEMMODE_16BIT)
5616 {
5617 pCtx->fpu.FCW = uPtr.pu16[0];
5618 pCtx->fpu.FSW = uPtr.pu16[1];
5619 pCtx->fpu.FTW = uPtr.pu16[2];
5620 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
5621 {
5622 pCtx->fpu.FPUIP = uPtr.pu16[3] | ((uint32_t)(uPtr.pu16[4] & UINT16_C(0xf000)) << 4);
5623 pCtx->fpu.FPUDP = uPtr.pu16[5] | ((uint32_t)(uPtr.pu16[6] & UINT16_C(0xf000)) << 4);
5624 pCtx->fpu.FOP = uPtr.pu16[4] & UINT16_C(0x07ff);
5625 pCtx->fpu.CS = 0;
5626 pCtx->fpu.Rsrvd1= 0;
5627 pCtx->fpu.DS = 0;
5628 pCtx->fpu.Rsrvd2= 0;
5629 }
5630 else
5631 {
5632 pCtx->fpu.FPUIP = uPtr.pu16[3];
5633 pCtx->fpu.CS = uPtr.pu16[4];
5634 pCtx->fpu.Rsrvd1= 0;
5635 pCtx->fpu.FPUDP = uPtr.pu16[5];
5636 pCtx->fpu.DS = uPtr.pu16[6];
5637 pCtx->fpu.Rsrvd2= 0;
5638 /** @todo Testcase: Is FOP cleared when doing 16-bit protected mode fldenv? */
5639 }
5640 }
5641 else
5642 {
5643 pCtx->fpu.FCW = uPtr.pu16[0*2];
5644 pCtx->fpu.FSW = uPtr.pu16[1*2];
5645 pCtx->fpu.FTW = uPtr.pu16[2*2];
5646 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
5647 {
5648 pCtx->fpu.FPUIP = uPtr.pu16[3*2] | ((uPtr.pu32[4] & UINT32_C(0x0ffff000)) << 4);
5649 pCtx->fpu.FOP = uPtr.pu32[4] & UINT16_C(0x07ff);
5650 pCtx->fpu.FPUDP = uPtr.pu16[5*2] | ((uPtr.pu32[6] & UINT32_C(0x0ffff000)) << 4);
5651 pCtx->fpu.CS = 0;
5652 pCtx->fpu.Rsrvd1= 0;
5653 pCtx->fpu.DS = 0;
5654 pCtx->fpu.Rsrvd2= 0;
5655 }
5656 else
5657 {
5658 pCtx->fpu.FPUIP = uPtr.pu32[3];
5659 pCtx->fpu.CS = uPtr.pu16[4*2];
5660 pCtx->fpu.Rsrvd1= 0;
5661 pCtx->fpu.FOP = uPtr.pu16[4*2+1];
5662 pCtx->fpu.FPUDP = uPtr.pu32[5];
5663 pCtx->fpu.DS = uPtr.pu16[6*2];
5664 pCtx->fpu.Rsrvd2= 0;
5665 }
5666 }
5667
5668 /* Make adjustments. */
5669 pCtx->fpu.FTW = iemFpuCompressFtw(pCtx->fpu.FTW);
5670 pCtx->fpu.FCW &= ~X86_FCW_ZERO_MASK;
5671 iemFpuRecalcExceptionStatus(pCtx);
5672 /** @todo Testcase: Check if ES and/or B are automatically cleared if no
5673 * exceptions are pending after loading the saved state? */
5674}
5675
5676
5677/**
5678 * Implements 'FNSTENV'.
5679 *
5680 * @param enmEffOpSize The operand size (only REX.W really matters).
5681 * @param iEffSeg The effective segment register for @a GCPtrEff.
5682 * @param GCPtrEffDst The address of the image.
5683 */
5684IEM_CIMPL_DEF_3(iemCImpl_fnstenv, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
5685{
5686 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5687 RTPTRUNION uPtr;
5688 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, &uPtr.pv, enmEffOpSize == IEMMODE_16BIT ? 14 : 28,
5689 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5690 if (rcStrict != VINF_SUCCESS)
5691 return rcStrict;
5692
5693 iemCImplCommonFpuStoreEnv(pIemCpu, enmEffOpSize, uPtr, pCtx);
5694
5695 rcStrict = iemMemCommitAndUnmap(pIemCpu, uPtr.pv, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5696 if (rcStrict != VINF_SUCCESS)
5697 return rcStrict;
5698
5699 /* Note: C0, C1, C2 and C3 are documented as undefined, we leave them untouched! */
5700 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5701 return VINF_SUCCESS;
5702}
5703
5704
5705/**
5706 * Implements 'FNSAVE'.
5707 *
5708 * @param GCPtrEffDst The address of the image.
5709 * @param enmEffOpSize The operand size.
5710 */
5711IEM_CIMPL_DEF_3(iemCImpl_fnsave, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
5712{
5713 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5714 RTPTRUNION uPtr;
5715 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, &uPtr.pv, enmEffOpSize == IEMMODE_16BIT ? 94 : 108,
5716 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5717 if (rcStrict != VINF_SUCCESS)
5718 return rcStrict;
5719
5720 iemCImplCommonFpuStoreEnv(pIemCpu, enmEffOpSize, uPtr, pCtx);
5721 PRTFLOAT80U paRegs = (PRTFLOAT80U)(uPtr.pu8 + (enmEffOpSize == IEMMODE_16BIT ? 14 : 28));
5722 for (uint32_t i = 0; i < RT_ELEMENTS(pCtx->fpu.aRegs); i++)
5723 {
5724 paRegs[i].au32[0] = pCtx->fpu.aRegs[i].au32[0];
5725 paRegs[i].au32[1] = pCtx->fpu.aRegs[i].au32[1];
5726 paRegs[i].au16[4] = pCtx->fpu.aRegs[i].au16[4];
5727 }
5728
5729 rcStrict = iemMemCommitAndUnmap(pIemCpu, uPtr.pv, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5730 if (rcStrict != VINF_SUCCESS)
5731 return rcStrict;
5732
5733 /*
5734 * Re-initialize the FPU.
5735 */
5736 pCtx->fpu.FCW = 0x37f;
5737 pCtx->fpu.FSW = 0;
5738 pCtx->fpu.FTW = 0x00; /* 0 - empty */
5739 pCtx->fpu.FPUDP = 0;
5740 pCtx->fpu.DS = 0;
5741 pCtx->fpu.Rsrvd2= 0;
5742 pCtx->fpu.FPUIP = 0;
5743 pCtx->fpu.CS = 0;
5744 pCtx->fpu.Rsrvd1= 0;
5745 pCtx->fpu.FOP = 0;
5746
5747 iemHlpUsedFpu(pIemCpu);
5748 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5749 return VINF_SUCCESS;
5750}
5751
5752
5753
5754/**
5755 * Implements 'FLDENV'.
5756 *
5757 * @param enmEffOpSize The operand size (only REX.W really matters).
5758 * @param iEffSeg The effective segment register for @a GCPtrEff.
5759 * @param GCPtrEffSrc The address of the image.
5760 */
5761IEM_CIMPL_DEF_3(iemCImpl_fldenv, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
5762{
5763 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5764 RTCPTRUNION uPtr;
5765 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, (void **)&uPtr.pv, enmEffOpSize == IEMMODE_16BIT ? 14 : 28,
5766 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R);
5767 if (rcStrict != VINF_SUCCESS)
5768 return rcStrict;
5769
5770 iemCImplCommonFpuRestoreEnv(pIemCpu, enmEffOpSize, uPtr, pCtx);
5771
5772 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)uPtr.pv, IEM_ACCESS_DATA_R);
5773 if (rcStrict != VINF_SUCCESS)
5774 return rcStrict;
5775
5776 iemHlpUsedFpu(pIemCpu);
5777 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5778 return VINF_SUCCESS;
5779}
5780
5781
5782/**
5783 * Implements 'FRSTOR'.
5784 *
5785 * @param GCPtrEffSrc The address of the image.
5786 * @param enmEffOpSize The operand size.
5787 */
5788IEM_CIMPL_DEF_3(iemCImpl_frstor, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
5789{
5790 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5791 RTCPTRUNION uPtr;
5792 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, (void **)&uPtr.pv, enmEffOpSize == IEMMODE_16BIT ? 94 : 108,
5793 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R);
5794 if (rcStrict != VINF_SUCCESS)
5795 return rcStrict;
5796
5797 iemCImplCommonFpuRestoreEnv(pIemCpu, enmEffOpSize, uPtr, pCtx);
5798 PCRTFLOAT80U paRegs = (PCRTFLOAT80U)(uPtr.pu8 + (enmEffOpSize == IEMMODE_16BIT ? 14 : 28));
5799 for (uint32_t i = 0; i < RT_ELEMENTS(pCtx->fpu.aRegs); i++)
5800 {
5801 pCtx->fpu.aRegs[i].au32[0] = paRegs[i].au32[0];
5802 pCtx->fpu.aRegs[i].au32[1] = paRegs[i].au32[1];
5803 pCtx->fpu.aRegs[i].au32[2] = paRegs[i].au16[4];
5804 pCtx->fpu.aRegs[i].au32[3] = 0;
5805 }
5806
5807 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)uPtr.pv, IEM_ACCESS_DATA_R);
5808 if (rcStrict != VINF_SUCCESS)
5809 return rcStrict;
5810
5811 iemHlpUsedFpu(pIemCpu);
5812 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5813 return VINF_SUCCESS;
5814}
5815
5816
5817/**
5818 * Implements 'FLDCW'.
5819 *
5820 * @param u16Fcw The new FCW.
5821 */
5822IEM_CIMPL_DEF_1(iemCImpl_fldcw, uint16_t, u16Fcw)
5823{
5824 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5825
5826 /** @todo Testcase: Check what happens when trying to load X86_FCW_PC_RSVD. */
5827 /** @todo Testcase: Try see what happens when trying to set undefined bits
5828 * (other than 6 and 7). Currently ignoring them. */
5829 /** @todo Testcase: Test that it raises and loweres the FPU exception bits
5830 * according to FSW. (This is was is currently implemented.) */
5831 pCtx->fpu.FCW = u16Fcw & ~X86_FCW_ZERO_MASK;
5832 iemFpuRecalcExceptionStatus(pCtx);
5833
5834 /* Note: C0, C1, C2 and C3 are documented as undefined, we leave them untouched! */
5835 iemHlpUsedFpu(pIemCpu);
5836 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5837 return VINF_SUCCESS;
5838}
5839
5840
5841
5842/**
5843 * Implements the underflow case of fxch.
5844 *
5845 * @param iStReg The other stack register.
5846 */
5847IEM_CIMPL_DEF_1(iemCImpl_fxch_underflow, uint8_t, iStReg)
5848{
5849 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5850
5851 unsigned const iReg1 = X86_FSW_TOP_GET(pCtx->fpu.FSW);
5852 unsigned const iReg2 = (iReg1 + iStReg) & X86_FSW_TOP_SMASK;
5853 Assert(!(RT_BIT(iReg1) & pCtx->fpu.FTW) || !(RT_BIT(iReg2) & pCtx->fpu.FTW));
5854
5855 /** @todo Testcase: fxch underflow. Making assumptions that underflowed
5856 * registers are read as QNaN and then exchanged. This could be
5857 * wrong... */
5858 if (pCtx->fpu.FCW & X86_FCW_IM)
5859 {
5860 if (RT_BIT(iReg1) & pCtx->fpu.FTW)
5861 {
5862 if (RT_BIT(iReg2) & pCtx->fpu.FTW)
5863 iemFpuStoreQNan(&pCtx->fpu.aRegs[0].r80);
5864 else
5865 pCtx->fpu.aRegs[0].r80 = pCtx->fpu.aRegs[iStReg].r80;
5866 iemFpuStoreQNan(&pCtx->fpu.aRegs[iStReg].r80);
5867 }
5868 else
5869 {
5870 pCtx->fpu.aRegs[iStReg].r80 = pCtx->fpu.aRegs[0].r80;
5871 iemFpuStoreQNan(&pCtx->fpu.aRegs[0].r80);
5872 }
5873 pCtx->fpu.FSW &= ~X86_FSW_C_MASK;
5874 pCtx->fpu.FSW |= X86_FSW_C1 | X86_FSW_IE | X86_FSW_SF;
5875 }
5876 else
5877 {
5878 /* raise underflow exception, don't change anything. */
5879 pCtx->fpu.FSW &= ~(X86_FSW_TOP_MASK | X86_FSW_XCPT_MASK);
5880 pCtx->fpu.FSW |= X86_FSW_C1 | X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B;
5881 }
5882
5883 iemFpuUpdateOpcodeAndIpWorker(pIemCpu, pCtx);
5884 iemHlpUsedFpu(pIemCpu);
5885 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5886 return VINF_SUCCESS;
5887}
5888
5889
5890/**
5891 * Implements 'FCOMI', 'FCOMIP', 'FUCOMI', and 'FUCOMIP'.
5892 *
5893 * @param cToAdd 1 or 7.
5894 */
5895IEM_CIMPL_DEF_3(iemCImpl_fcomi_fucomi, uint8_t, iStReg, PFNIEMAIMPLFPUR80EFL, pfnAImpl, bool, fPop)
5896{
5897 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5898 Assert(iStReg < 8);
5899
5900 /*
5901 * Raise exceptions.
5902 */
5903 if (pCtx->cr0 & (X86_CR0_EM | X86_CR0_TS))
5904 return iemRaiseDeviceNotAvailable(pIemCpu);
5905 uint16_t u16Fsw = pCtx->fpu.FSW;
5906 if (u16Fsw & X86_FSW_ES)
5907 return iemRaiseMathFault(pIemCpu);
5908
5909 /*
5910 * Check if any of the register accesses causes #SF + #IA.
5911 */
5912 unsigned const iReg1 = X86_FSW_TOP_GET(u16Fsw);
5913 unsigned const iReg2 = (iReg1 + iStReg) & X86_FSW_TOP_SMASK;
5914 if ((pCtx->fpu.FTW & (RT_BIT(iReg1) | RT_BIT(iReg2))) == (RT_BIT(iReg1) | RT_BIT(iReg2)))
5915 {
5916 uint32_t u32Eflags = pfnAImpl(&pCtx->fpu, &u16Fsw, &pCtx->fpu.aRegs[0].r80, &pCtx->fpu.aRegs[iStReg].r80);
5917 NOREF(u32Eflags);
5918
5919 pCtx->fpu.FSW &= ~X86_FSW_C1;
5920 pCtx->fpu.FSW |= u16Fsw & ~X86_FSW_TOP_MASK;
5921 if ( !(u16Fsw & X86_FSW_IE)
5922 || (pCtx->fpu.FCW & X86_FCW_IM) )
5923 {
5924 pCtx->eflags.u &= ~(X86_EFL_OF | X86_EFL_SF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
5925 pCtx->eflags.u |= pCtx->eflags.u & (X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
5926 }
5927 }
5928 else if (pCtx->fpu.FCW & X86_FCW_IM)
5929 {
5930 /* Masked underflow. */
5931 pCtx->fpu.FSW &= ~X86_FSW_C1;
5932 pCtx->fpu.FSW |= X86_FSW_IE | X86_FSW_SF;
5933 pCtx->eflags.u &= ~(X86_EFL_OF | X86_EFL_SF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
5934 pCtx->eflags.u |= X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF;
5935 }
5936 else
5937 {
5938 /* Raise underflow - don't touch EFLAGS or TOP. */
5939 pCtx->fpu.FSW &= ~X86_FSW_C1;
5940 pCtx->fpu.FSW |= X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B;
5941 fPop = false;
5942 }
5943
5944 /*
5945 * Pop if necessary.
5946 */
5947 if (fPop)
5948 {
5949 pCtx->fpu.FTW &= ~RT_BIT(iReg1);
5950 pCtx->fpu.FSW &= X86_FSW_TOP_MASK;
5951 pCtx->fpu.FSW |= ((iReg1 + 7) & X86_FSW_TOP_SMASK) << X86_FSW_TOP_SHIFT;
5952 }
5953
5954 iemFpuUpdateOpcodeAndIpWorker(pIemCpu, pCtx);
5955 iemHlpUsedFpu(pIemCpu);
5956 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5957 return VINF_SUCCESS;
5958}
5959
5960/** @} */
5961
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use