VirtualBox

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

Last change on this file since 51083 was 50863, checked in by vboxsync, 11 years ago

VMM/IEMAllCImpl: Comment clarification about reserved bits in CR4 for raising GP.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 199.0 KB
Line 
1/* $Id: IEMAllCImpl.cpp.h 50863 2014-03-25 12:56:50Z 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 /** @todo Shouldn't this look at the guest CPUID bits to determine
4259 * valid bits? e.g. if guest CPUID doesn't allow X86_CR4_OSXMMEEXCPT, we
4260 * should #GP(0). */
4261 /* reserved bits */
4262 uint32_t fValid = X86_CR4_VME | X86_CR4_PVI
4263 | X86_CR4_TSD | X86_CR4_DE
4264 | X86_CR4_PSE | X86_CR4_PAE
4265 | X86_CR4_MCE | X86_CR4_PGE
4266 | X86_CR4_PCE | X86_CR4_OSFSXR
4267 | X86_CR4_OSXMMEEXCPT;
4268 //if (xxx)
4269 // fValid |= X86_CR4_VMXE;
4270 //if (xxx)
4271 // fValid |= X86_CR4_OSXSAVE;
4272 if (uNewCrX & ~(uint64_t)fValid)
4273 {
4274 Log(("Trying to set reserved CR4 bits: NewCR4=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
4275 return iemRaiseGeneralProtectionFault0(pIemCpu);
4276 }
4277
4278 /* long mode checks. */
4279 if ( (uOldCrX & X86_CR4_PAE)
4280 && !(uNewCrX & X86_CR4_PAE)
4281 && CPUMIsGuestInLongModeEx(pCtx) )
4282 {
4283 Log(("Trying to set clear CR4.PAE while long mode is active\n"));
4284 return iemRaiseGeneralProtectionFault0(pIemCpu);
4285 }
4286
4287
4288 /*
4289 * Change it.
4290 */
4291 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4292 {
4293 rc = CPUMSetGuestCR4(pVCpu, uNewCrX);
4294 AssertRCSuccessReturn(rc, rc);
4295 }
4296 else
4297 pCtx->cr4 = uNewCrX;
4298 Assert(pCtx->cr4 == uNewCrX);
4299
4300 /*
4301 * Notify SELM and PGM.
4302 */
4303 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4304 {
4305 /* SELM - VME may change things wrt to the TSS shadowing. */
4306 if ((uNewCrX ^ uOldCrX) & X86_CR4_VME)
4307 {
4308 Log(("iemCImpl_load_CrX: VME %d -> %d => Setting VMCPU_FF_SELM_SYNC_TSS\n",
4309 RT_BOOL(uOldCrX & X86_CR4_VME), RT_BOOL(uNewCrX & X86_CR4_VME) ));
4310#ifdef VBOX_WITH_RAW_MODE
4311 if (!HMIsEnabled(IEMCPU_TO_VM(pIemCpu)))
4312 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);
4313#endif
4314 }
4315
4316 /* PGM - flushing and mode. */
4317 if ((uNewCrX ^ uOldCrX) & (X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE))
4318 {
4319 rc = PGMFlushTLB(pVCpu, pCtx->cr3, true /* global */);
4320 AssertRCReturn(rc, rc);
4321 /* ignore informational status codes */
4322 }
4323 rcStrict = PGMChangeMode(pVCpu, pCtx->cr0, pCtx->cr4, pCtx->msrEFER);
4324 }
4325 else
4326 rcStrict = VINF_SUCCESS;
4327 break;
4328 }
4329
4330 /*
4331 * CR8 maps to the APIC TPR.
4332 */
4333 case 8:
4334 if (uNewCrX & ~(uint64_t)0xf)
4335 {
4336 Log(("Trying to set reserved CR8 bits (%#RX64)\n", uNewCrX));
4337 return iemRaiseGeneralProtectionFault0(pIemCpu);
4338 }
4339
4340 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4341 PDMApicSetTPR(IEMCPU_TO_VMCPU(pIemCpu), (uint8_t)uNewCrX << 4);
4342 rcStrict = VINF_SUCCESS;
4343 break;
4344
4345 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
4346 }
4347
4348 /*
4349 * Advance the RIP on success.
4350 */
4351 if (RT_SUCCESS(rcStrict))
4352 {
4353 if (rcStrict != VINF_SUCCESS)
4354 rcStrict = iemSetPassUpStatus(pIemCpu, rcStrict);
4355 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4356 }
4357
4358 return rcStrict;
4359}
4360
4361
4362/**
4363 * Implements mov CRx,GReg.
4364 *
4365 * @param iCrReg The CRx register to write (valid).
4366 * @param iGReg The general register to load the DRx value from.
4367 */
4368IEM_CIMPL_DEF_2(iemCImpl_mov_Cd_Rd, uint8_t, iCrReg, uint8_t, iGReg)
4369{
4370 if (pIemCpu->uCpl != 0)
4371 return iemRaiseGeneralProtectionFault0(pIemCpu);
4372 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
4373
4374 /*
4375 * Read the new value from the source register and call common worker.
4376 */
4377 uint64_t uNewCrX;
4378 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
4379 uNewCrX = iemGRegFetchU64(pIemCpu, iGReg);
4380 else
4381 uNewCrX = iemGRegFetchU32(pIemCpu, iGReg);
4382 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, iCrReg, uNewCrX);
4383}
4384
4385
4386/**
4387 * Implements 'LMSW r/m16'
4388 *
4389 * @param u16NewMsw The new value.
4390 */
4391IEM_CIMPL_DEF_1(iemCImpl_lmsw, uint16_t, u16NewMsw)
4392{
4393 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4394
4395 if (pIemCpu->uCpl != 0)
4396 return iemRaiseGeneralProtectionFault0(pIemCpu);
4397 Assert(!pCtx->eflags.Bits.u1VM);
4398
4399 /*
4400 * Compose the new CR0 value and call common worker.
4401 */
4402 uint64_t uNewCr0 = pCtx->cr0 & ~(X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
4403 uNewCr0 |= u16NewMsw & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
4404 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, /*cr*/ 0, uNewCr0);
4405}
4406
4407
4408/**
4409 * Implements 'CLTS'.
4410 */
4411IEM_CIMPL_DEF_0(iemCImpl_clts)
4412{
4413 if (pIemCpu->uCpl != 0)
4414 return iemRaiseGeneralProtectionFault0(pIemCpu);
4415
4416 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4417 uint64_t uNewCr0 = pCtx->cr0;
4418 uNewCr0 &= ~X86_CR0_TS;
4419 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, /*cr*/ 0, uNewCr0);
4420}
4421
4422
4423/**
4424 * Implements mov GReg,DRx.
4425 *
4426 * @param iGReg The general register to store the DRx value in.
4427 * @param iDrReg The DRx register to read (0-7).
4428 */
4429IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Dd, uint8_t, iGReg, uint8_t, iDrReg)
4430{
4431 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4432
4433 /*
4434 * Check preconditions.
4435 */
4436
4437 /* Raise GPs. */
4438 if (pIemCpu->uCpl != 0)
4439 return iemRaiseGeneralProtectionFault0(pIemCpu);
4440 Assert(!pCtx->eflags.Bits.u1VM);
4441
4442 if ( (iDrReg == 4 || iDrReg == 5)
4443 && (pCtx->cr4 & X86_CR4_DE) )
4444 {
4445 Log(("mov r%u,dr%u: CR4.DE=1 -> #GP(0)\n", iGReg, iDrReg));
4446 return iemRaiseGeneralProtectionFault0(pIemCpu);
4447 }
4448
4449 /* Raise #DB if general access detect is enabled. */
4450 if (pCtx->dr[7] & X86_DR7_GD)
4451 {
4452 Log(("mov r%u,dr%u: DR7.GD=1 -> #DB\n", iGReg, iDrReg));
4453 return iemRaiseDebugException(pIemCpu);
4454 }
4455
4456 /*
4457 * Read the debug register and store it in the specified general register.
4458 */
4459 uint64_t drX;
4460 switch (iDrReg)
4461 {
4462 case 0: drX = pCtx->dr[0]; break;
4463 case 1: drX = pCtx->dr[1]; break;
4464 case 2: drX = pCtx->dr[2]; break;
4465 case 3: drX = pCtx->dr[3]; break;
4466 case 6:
4467 case 4:
4468 drX = pCtx->dr[6];
4469 drX |= X86_DR6_RA1_MASK;
4470 drX &= ~X86_DR6_RAZ_MASK;
4471 break;
4472 case 7:
4473 case 5:
4474 drX = pCtx->dr[7];
4475 drX |=X86_DR7_RA1_MASK;
4476 drX &= ~X86_DR7_RAZ_MASK;
4477 break;
4478 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
4479 }
4480
4481 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
4482 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = drX;
4483 else
4484 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = (uint32_t)drX;
4485
4486 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4487 return VINF_SUCCESS;
4488}
4489
4490
4491/**
4492 * Implements mov DRx,GReg.
4493 *
4494 * @param iDrReg The DRx register to write (valid).
4495 * @param iGReg The general register to load the DRx value from.
4496 */
4497IEM_CIMPL_DEF_2(iemCImpl_mov_Dd_Rd, uint8_t, iDrReg, uint8_t, iGReg)
4498{
4499 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4500
4501 /*
4502 * Check preconditions.
4503 */
4504 if (pIemCpu->uCpl != 0)
4505 return iemRaiseGeneralProtectionFault0(pIemCpu);
4506 Assert(!pCtx->eflags.Bits.u1VM);
4507
4508 if (iDrReg == 4 || iDrReg == 5)
4509 {
4510 if (pCtx->cr4 & X86_CR4_DE)
4511 {
4512 Log(("mov dr%u,r%u: CR4.DE=1 -> #GP(0)\n", iDrReg, iGReg));
4513 return iemRaiseGeneralProtectionFault0(pIemCpu);
4514 }
4515 iDrReg += 2;
4516 }
4517
4518 /* Raise #DB if general access detect is enabled. */
4519 /** @todo is \#DB/DR7.GD raised before any reserved high bits in DR7/DR6
4520 * \#GP? */
4521 if (pCtx->dr[7] & X86_DR7_GD)
4522 {
4523 Log(("mov dr%u,r%u: DR7.GD=1 -> #DB\n", iDrReg, iGReg));
4524 return iemRaiseDebugException(pIemCpu);
4525 }
4526
4527 /*
4528 * Read the new value from the source register.
4529 */
4530 uint64_t uNewDrX;
4531 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
4532 uNewDrX = iemGRegFetchU64(pIemCpu, iGReg);
4533 else
4534 uNewDrX = iemGRegFetchU32(pIemCpu, iGReg);
4535
4536 /*
4537 * Adjust it.
4538 */
4539 switch (iDrReg)
4540 {
4541 case 0:
4542 case 1:
4543 case 2:
4544 case 3:
4545 /* nothing to adjust */
4546 break;
4547
4548 case 6:
4549 if (uNewDrX & X86_DR6_MBZ_MASK)
4550 {
4551 Log(("mov dr%u,%#llx: DR6 high bits are not zero -> #GP(0)\n", iDrReg, uNewDrX));
4552 return iemRaiseGeneralProtectionFault0(pIemCpu);
4553 }
4554 uNewDrX |= X86_DR6_RA1_MASK;
4555 uNewDrX &= ~X86_DR6_RAZ_MASK;
4556 break;
4557
4558 case 7:
4559 if (uNewDrX & X86_DR7_MBZ_MASK)
4560 {
4561 Log(("mov dr%u,%#llx: DR7 high bits are not zero -> #GP(0)\n", iDrReg, uNewDrX));
4562 return iemRaiseGeneralProtectionFault0(pIemCpu);
4563 }
4564 uNewDrX |= X86_DR7_RA1_MASK;
4565 uNewDrX &= ~X86_DR7_RAZ_MASK;
4566 break;
4567
4568 IEM_NOT_REACHED_DEFAULT_CASE_RET();
4569 }
4570
4571 /*
4572 * Do the actual setting.
4573 */
4574 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4575 {
4576 int rc = CPUMSetGuestDRx(IEMCPU_TO_VMCPU(pIemCpu), iDrReg, uNewDrX);
4577 AssertRCSuccessReturn(rc, RT_SUCCESS_NP(rc) ? VERR_INTERNAL_ERROR : rc);
4578 }
4579 else
4580 pCtx->dr[iDrReg] = uNewDrX;
4581
4582 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4583 return VINF_SUCCESS;
4584}
4585
4586
4587/**
4588 * Implements 'INVLPG m'.
4589 *
4590 * @param GCPtrPage The effective address of the page to invalidate.
4591 * @remarks Updates the RIP.
4592 */
4593IEM_CIMPL_DEF_1(iemCImpl_invlpg, uint8_t, GCPtrPage)
4594{
4595 /* ring-0 only. */
4596 if (pIemCpu->uCpl != 0)
4597 return iemRaiseGeneralProtectionFault0(pIemCpu);
4598 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
4599
4600 int rc = PGMInvalidatePage(IEMCPU_TO_VMCPU(pIemCpu), GCPtrPage);
4601 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4602
4603 if (rc == VINF_SUCCESS)
4604 return VINF_SUCCESS;
4605 if (rc == VINF_PGM_SYNC_CR3)
4606 return iemSetPassUpStatus(pIemCpu, rc);
4607
4608 AssertMsg(rc == VINF_EM_RAW_EMULATE_INSTR || RT_FAILURE_NP(rc), ("%Rrc\n", rc));
4609 Log(("PGMInvalidatePage(%RGv) -> %Rrc\n", rc));
4610 return rc;
4611}
4612
4613
4614/**
4615 * Implements RDTSC.
4616 */
4617IEM_CIMPL_DEF_0(iemCImpl_rdtsc)
4618{
4619 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4620
4621 /*
4622 * Check preconditions.
4623 */
4624 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_EDX(X86_CPUID_FEATURE_EDX_TSC))
4625 return iemRaiseUndefinedOpcode(pIemCpu);
4626
4627 if ( (pCtx->cr4 & X86_CR4_TSD)
4628 && pIemCpu->uCpl != 0)
4629 {
4630 Log(("rdtsc: CR4.TSD and CPL=%u -> #GP(0)\n", pIemCpu->uCpl));
4631 return iemRaiseGeneralProtectionFault0(pIemCpu);
4632 }
4633
4634 /*
4635 * Do the job.
4636 */
4637 uint64_t uTicks = TMCpuTickGet(IEMCPU_TO_VMCPU(pIemCpu));
4638 pCtx->rax = (uint32_t)uTicks;
4639 pCtx->rdx = uTicks >> 32;
4640#ifdef IEM_VERIFICATION_MODE_FULL
4641 pIemCpu->fIgnoreRaxRdx = true;
4642#endif
4643
4644 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4645 return VINF_SUCCESS;
4646}
4647
4648
4649/**
4650 * Implements RDMSR.
4651 */
4652IEM_CIMPL_DEF_0(iemCImpl_rdmsr)
4653{
4654 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4655
4656 /*
4657 * Check preconditions.
4658 */
4659 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_EDX(X86_CPUID_FEATURE_EDX_MSR))
4660 return iemRaiseUndefinedOpcode(pIemCpu);
4661 if (pIemCpu->uCpl != 0)
4662 return iemRaiseGeneralProtectionFault0(pIemCpu);
4663
4664 /*
4665 * Do the job.
4666 */
4667 RTUINT64U uValue;
4668 int rc = CPUMQueryGuestMsr(IEMCPU_TO_VMCPU(pIemCpu), pCtx->ecx, &uValue.u);
4669 if (rc != VINF_SUCCESS)
4670 {
4671#ifdef IN_RING3
4672 static uint32_t s_cTimes = 0;
4673 if (s_cTimes++ < 10)
4674 LogRel(("IEM: rdmsr(%#x) -> GP(0)\n", pCtx->ecx));
4675#endif
4676 Log(("IEM: rdmsr(%#x) -> GP(0)\n", pCtx->ecx));
4677 AssertMsgReturn(rc == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", rc), VERR_IPE_UNEXPECTED_STATUS);
4678 return iemRaiseGeneralProtectionFault0(pIemCpu);
4679 }
4680
4681 pCtx->rax = uValue.s.Lo;
4682 pCtx->rdx = uValue.s.Hi;
4683
4684 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4685 return VINF_SUCCESS;
4686}
4687
4688
4689/**
4690 * Implements WRMSR.
4691 */
4692IEM_CIMPL_DEF_0(iemCImpl_wrmsr)
4693{
4694 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4695
4696 /*
4697 * Check preconditions.
4698 */
4699 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_EDX(X86_CPUID_FEATURE_EDX_MSR))
4700 return iemRaiseUndefinedOpcode(pIemCpu);
4701 if (pIemCpu->uCpl != 0)
4702 return iemRaiseGeneralProtectionFault0(pIemCpu);
4703
4704 /*
4705 * Do the job.
4706 */
4707 RTUINT64U uValue;
4708 uValue.s.Lo = pCtx->eax;
4709 uValue.s.Hi = pCtx->edx;
4710
4711 int rc;
4712 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4713 rc = CPUMSetGuestMsr(IEMCPU_TO_VMCPU(pIemCpu), pCtx->ecx, uValue.u);
4714 else
4715 {
4716 CPUMCTX CtxTmp = *pCtx;
4717 rc = CPUMSetGuestMsr(IEMCPU_TO_VMCPU(pIemCpu), pCtx->ecx, uValue.u);
4718 PCPUMCTX pCtx2 = CPUMQueryGuestCtxPtr(IEMCPU_TO_VMCPU(pIemCpu));
4719 *pCtx = *pCtx2;
4720 *pCtx2 = CtxTmp;
4721 }
4722 if (rc != VINF_SUCCESS)
4723 {
4724#ifdef IN_RING3
4725 static uint32_t s_cTimes = 0;
4726 if (s_cTimes++ < 10)
4727 LogRel(("IEM: wrmsr(%#x,%#x`%08x) -> GP(0)\n", pCtx->ecx, uValue.s.Hi, uValue.s.Lo));
4728#endif
4729 Log(("IEM: wrmsr(%#x,%#x`%08x) -> GP(0)\n", pCtx->ecx, uValue.s.Hi, uValue.s.Lo));
4730 AssertMsgReturn(rc == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", rc), VERR_IPE_UNEXPECTED_STATUS);
4731 return iemRaiseGeneralProtectionFault0(pIemCpu);
4732 }
4733
4734 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4735 return VINF_SUCCESS;
4736}
4737
4738
4739/**
4740 * Implements 'IN eAX, port'.
4741 *
4742 * @param u16Port The source port.
4743 * @param cbReg The register size.
4744 */
4745IEM_CIMPL_DEF_2(iemCImpl_in, uint16_t, u16Port, uint8_t, cbReg)
4746{
4747 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4748
4749 /*
4750 * CPL check
4751 */
4752 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pIemCpu, pCtx, u16Port, cbReg);
4753 if (rcStrict != VINF_SUCCESS)
4754 return rcStrict;
4755
4756 /*
4757 * Perform the I/O.
4758 */
4759 uint32_t u32Value;
4760 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4761 rcStrict = IOMIOPortRead(IEMCPU_TO_VM(pIemCpu), IEMCPU_TO_VMCPU(pIemCpu), u16Port, &u32Value, cbReg);
4762 else
4763 rcStrict = iemVerifyFakeIOPortRead(pIemCpu, u16Port, &u32Value, cbReg);
4764 if (IOM_SUCCESS(rcStrict))
4765 {
4766 switch (cbReg)
4767 {
4768 case 1: pCtx->al = (uint8_t)u32Value; break;
4769 case 2: pCtx->ax = (uint16_t)u32Value; break;
4770 case 4: pCtx->rax = u32Value; break;
4771 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
4772 }
4773 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4774 pIemCpu->cPotentialExits++;
4775 if (rcStrict != VINF_SUCCESS)
4776 rcStrict = iemSetPassUpStatus(pIemCpu, rcStrict);
4777 Assert(rcStrict == VINF_SUCCESS); /* assumed below */
4778
4779 /*
4780 * Check for I/O breakpoints.
4781 */
4782 uint32_t const uDr7 = pCtx->dr[7];
4783 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
4784 && X86_DR7_ANY_RW_IO(uDr7)
4785 && (pCtx->cr4 & X86_CR4_DE))
4786 || DBGFBpIsHwIoArmed(IEMCPU_TO_VM(pIemCpu))))
4787 {
4788 rcStrict = DBGFBpCheckIo(IEMCPU_TO_VM(pIemCpu), IEMCPU_TO_VMCPU(pIemCpu), pCtx, u16Port, cbReg);
4789 if (rcStrict == VINF_EM_RAW_GUEST_TRAP)
4790 rcStrict = iemRaiseDebugException(pIemCpu);
4791 }
4792 }
4793
4794 return rcStrict;
4795}
4796
4797
4798/**
4799 * Implements 'IN eAX, DX'.
4800 *
4801 * @param cbReg The register size.
4802 */
4803IEM_CIMPL_DEF_1(iemCImpl_in_eAX_DX, uint8_t, cbReg)
4804{
4805 return IEM_CIMPL_CALL_2(iemCImpl_in, pIemCpu->CTX_SUFF(pCtx)->dx, cbReg);
4806}
4807
4808
4809/**
4810 * Implements 'OUT port, eAX'.
4811 *
4812 * @param u16Port The destination port.
4813 * @param cbReg The register size.
4814 */
4815IEM_CIMPL_DEF_2(iemCImpl_out, uint16_t, u16Port, uint8_t, cbReg)
4816{
4817 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4818
4819 /*
4820 * CPL check
4821 */
4822 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pIemCpu, pCtx, u16Port, cbReg);
4823 if (rcStrict != VINF_SUCCESS)
4824 return rcStrict;
4825
4826 /*
4827 * Perform the I/O.
4828 */
4829 uint32_t u32Value;
4830 switch (cbReg)
4831 {
4832 case 1: u32Value = pCtx->al; break;
4833 case 2: u32Value = pCtx->ax; break;
4834 case 4: u32Value = pCtx->eax; break;
4835 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
4836 }
4837 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4838 rcStrict = IOMIOPortWrite(IEMCPU_TO_VM(pIemCpu), IEMCPU_TO_VMCPU(pIemCpu), u16Port, u32Value, cbReg);
4839 else
4840 rcStrict = iemVerifyFakeIOPortWrite(pIemCpu, u16Port, u32Value, cbReg);
4841 if (IOM_SUCCESS(rcStrict))
4842 {
4843 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4844 pIemCpu->cPotentialExits++;
4845 if (rcStrict != VINF_SUCCESS)
4846 rcStrict = iemSetPassUpStatus(pIemCpu, rcStrict);
4847 Assert(rcStrict == VINF_SUCCESS); /* assumed below */
4848
4849 /*
4850 * Check for I/O breakpoints.
4851 */
4852 uint32_t const uDr7 = pCtx->dr[7];
4853 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
4854 && X86_DR7_ANY_RW_IO(uDr7)
4855 && (pCtx->cr4 & X86_CR4_DE))
4856 || DBGFBpIsHwIoArmed(IEMCPU_TO_VM(pIemCpu))))
4857 {
4858 rcStrict = DBGFBpCheckIo(IEMCPU_TO_VM(pIemCpu), IEMCPU_TO_VMCPU(pIemCpu), pCtx, u16Port, cbReg);
4859 if (rcStrict == VINF_EM_RAW_GUEST_TRAP)
4860 rcStrict = iemRaiseDebugException(pIemCpu);
4861 }
4862 }
4863 return rcStrict;
4864}
4865
4866
4867/**
4868 * Implements 'OUT DX, eAX'.
4869 *
4870 * @param cbReg The register size.
4871 */
4872IEM_CIMPL_DEF_1(iemCImpl_out_DX_eAX, uint8_t, cbReg)
4873{
4874 return IEM_CIMPL_CALL_2(iemCImpl_out, pIemCpu->CTX_SUFF(pCtx)->dx, cbReg);
4875}
4876
4877
4878/**
4879 * Implements 'CLI'.
4880 */
4881IEM_CIMPL_DEF_0(iemCImpl_cli)
4882{
4883 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4884 uint32_t fEfl = IEMMISC_GET_EFL(pIemCpu, pCtx);
4885 uint32_t const fEflOld = fEfl;
4886 if (pCtx->cr0 & X86_CR0_PE)
4887 {
4888 uint8_t const uIopl = X86_EFL_GET_IOPL(fEfl);
4889 if (!(fEfl & X86_EFL_VM))
4890 {
4891 if (pIemCpu->uCpl <= uIopl)
4892 fEfl &= ~X86_EFL_IF;
4893 else if ( pIemCpu->uCpl == 3
4894 && (pCtx->cr4 & X86_CR4_PVI) )
4895 fEfl &= ~X86_EFL_VIF;
4896 else
4897 return iemRaiseGeneralProtectionFault0(pIemCpu);
4898 }
4899 /* V8086 */
4900 else if (uIopl == 3)
4901 fEfl &= ~X86_EFL_IF;
4902 else if ( uIopl < 3
4903 && (pCtx->cr4 & X86_CR4_VME) )
4904 fEfl &= ~X86_EFL_VIF;
4905 else
4906 return iemRaiseGeneralProtectionFault0(pIemCpu);
4907 }
4908 /* real mode */
4909 else
4910 fEfl &= ~X86_EFL_IF;
4911
4912 /* Commit. */
4913 IEMMISC_SET_EFL(pIemCpu, pCtx, fEfl);
4914 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4915 Log2(("CLI: %#x -> %#x\n", fEflOld, fEfl)); NOREF(fEflOld);
4916 return VINF_SUCCESS;
4917}
4918
4919
4920/**
4921 * Implements 'STI'.
4922 */
4923IEM_CIMPL_DEF_0(iemCImpl_sti)
4924{
4925 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4926 uint32_t fEfl = IEMMISC_GET_EFL(pIemCpu, pCtx);
4927 uint32_t const fEflOld = fEfl;
4928
4929 if (pCtx->cr0 & X86_CR0_PE)
4930 {
4931 uint8_t const uIopl = X86_EFL_GET_IOPL(fEfl);
4932 if (!(fEfl & X86_EFL_VM))
4933 {
4934 if (pIemCpu->uCpl <= uIopl)
4935 fEfl |= X86_EFL_IF;
4936 else if ( pIemCpu->uCpl == 3
4937 && (pCtx->cr4 & X86_CR4_PVI)
4938 && !(fEfl & X86_EFL_VIP) )
4939 fEfl |= X86_EFL_VIF;
4940 else
4941 return iemRaiseGeneralProtectionFault0(pIemCpu);
4942 }
4943 /* V8086 */
4944 else if (uIopl == 3)
4945 fEfl |= X86_EFL_IF;
4946 else if ( uIopl < 3
4947 && (pCtx->cr4 & X86_CR4_VME)
4948 && !(fEfl & X86_EFL_VIP) )
4949 fEfl |= X86_EFL_VIF;
4950 else
4951 return iemRaiseGeneralProtectionFault0(pIemCpu);
4952 }
4953 /* real mode */
4954 else
4955 fEfl |= X86_EFL_IF;
4956
4957 /* Commit. */
4958 IEMMISC_SET_EFL(pIemCpu, pCtx, fEfl);
4959 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4960 if ((!(fEflOld & X86_EFL_IF) && (fEfl & X86_EFL_IF)) || IEM_FULL_VERIFICATION_REM_ENABLED(pIemCpu))
4961 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
4962 Log2(("STI: %#x -> %#x\n", fEflOld, fEfl));
4963 return VINF_SUCCESS;
4964}
4965
4966
4967/**
4968 * Implements 'HLT'.
4969 */
4970IEM_CIMPL_DEF_0(iemCImpl_hlt)
4971{
4972 if (pIemCpu->uCpl != 0)
4973 return iemRaiseGeneralProtectionFault0(pIemCpu);
4974 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4975 return VINF_EM_HALT;
4976}
4977
4978
4979/**
4980 * Implements 'MONITOR'.
4981 */
4982IEM_CIMPL_DEF_1(iemCImpl_monitor, uint8_t, iEffSeg)
4983{
4984 /*
4985 * Permission checks.
4986 */
4987 if (pIemCpu->uCpl != 0)
4988 {
4989 Log2(("monitor: CPL != 0\n"));
4990 return iemRaiseUndefinedOpcode(pIemCpu); /** @todo MSR[0xC0010015].MonMwaitUserEn if we care. */
4991 }
4992 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_ECX(X86_CPUID_FEATURE_ECX_MONITOR))
4993 {
4994 Log2(("monitor: Not in CPUID\n"));
4995 return iemRaiseUndefinedOpcode(pIemCpu);
4996 }
4997
4998 /*
4999 * Gather the operands and validate them.
5000 */
5001 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5002 RTGCPTR GCPtrMem = pIemCpu->enmCpuMode == IEMMODE_64BIT ? pCtx->rax : pCtx->eax;
5003 uint32_t uEcx = pCtx->ecx;
5004 uint32_t uEdx = pCtx->edx;
5005/** @todo Test whether EAX or ECX is processed first, i.e. do we get \#PF or
5006 * \#GP first. */
5007 if (uEcx != 0)
5008 {
5009 Log2(("monitor rax=%RX64, ecx=%RX32, edx=%RX32; ECX != 0 -> #GP(0)\n", GCPtrMem, uEcx, uEdx));
5010 return iemRaiseGeneralProtectionFault0(pIemCpu);
5011 }
5012
5013 VBOXSTRICTRC rcStrict = iemMemApplySegment(pIemCpu, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, iEffSeg, 1, &GCPtrMem);
5014 if (rcStrict != VINF_SUCCESS)
5015 return rcStrict;
5016
5017 RTGCPHYS GCPhysMem;
5018 rcStrict = iemMemPageTranslateAndCheckAccess(pIemCpu, GCPtrMem, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, &GCPhysMem);
5019 if (rcStrict != VINF_SUCCESS)
5020 return rcStrict;
5021
5022 /*
5023 * Call EM to prepare the monitor/wait.
5024 */
5025 rcStrict = EMMonitorWaitPrepare(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rax, pCtx->rcx, pCtx->rdx, GCPhysMem);
5026 Assert(rcStrict == VINF_SUCCESS);
5027
5028 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5029 return rcStrict;
5030}
5031
5032
5033/**
5034 * Implements 'MWAIT'.
5035 */
5036IEM_CIMPL_DEF_0(iemCImpl_mwait)
5037{
5038 /*
5039 * Permission checks.
5040 */
5041 if (pIemCpu->uCpl != 0)
5042 {
5043 Log2(("mwait: CPL != 0\n"));
5044 /** @todo MSR[0xC0010015].MonMwaitUserEn if we care. (Remember to check
5045 * EFLAGS.VM then.) */
5046 return iemRaiseUndefinedOpcode(pIemCpu);
5047 }
5048 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_ECX(X86_CPUID_FEATURE_ECX_MONITOR))
5049 {
5050 Log2(("mwait: Not in CPUID\n"));
5051 return iemRaiseUndefinedOpcode(pIemCpu);
5052 }
5053
5054 /*
5055 * Gather the operands and validate them.
5056 */
5057 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5058 uint32_t uEax = pCtx->eax;
5059 uint32_t uEcx = pCtx->ecx;
5060 if (uEcx != 0)
5061 {
5062 /* Only supported extension is break on IRQ when IF=0. */
5063 if (uEcx > 1)
5064 {
5065 Log2(("mwait eax=%RX32, ecx=%RX32; ECX > 1 -> #GP(0)\n", uEax, uEcx));
5066 return iemRaiseGeneralProtectionFault0(pIemCpu);
5067 }
5068 uint32_t fMWaitFeatures = 0;
5069 uint32_t uIgnore = 0;
5070 CPUMGetGuestCpuId(IEMCPU_TO_VMCPU(pIemCpu), 5, &uIgnore, &uIgnore, &fMWaitFeatures, &uIgnore);
5071 if ( (fMWaitFeatures & (X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
5072 != (X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
5073 {
5074 Log2(("mwait eax=%RX32, ecx=%RX32; break-on-IRQ-IF=0 extension not enabled -> #GP(0)\n", uEax, uEcx));
5075 return iemRaiseGeneralProtectionFault0(pIemCpu);
5076 }
5077 }
5078
5079 /*
5080 * Call EM to prepare the monitor/wait.
5081 */
5082 VBOXSTRICTRC rcStrict = EMMonitorWaitPerform(IEMCPU_TO_VMCPU(pIemCpu), uEax, uEcx);
5083
5084 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5085 return rcStrict;
5086}
5087
5088
5089/**
5090 * Implements 'SWAPGS'.
5091 */
5092IEM_CIMPL_DEF_0(iemCImpl_swapgs)
5093{
5094 Assert(pIemCpu->enmCpuMode == IEMMODE_64BIT); /* Caller checks this. */
5095
5096 /*
5097 * Permission checks.
5098 */
5099 if (pIemCpu->uCpl != 0)
5100 {
5101 Log2(("swapgs: CPL != 0\n"));
5102 return iemRaiseUndefinedOpcode(pIemCpu);
5103 }
5104
5105 /*
5106 * Do the job.
5107 */
5108 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5109 uint64_t uOtherGsBase = pCtx->msrKERNELGSBASE;
5110 pCtx->msrKERNELGSBASE = pCtx->gs.u64Base;
5111 pCtx->gs.u64Base = uOtherGsBase;
5112
5113 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5114 return VINF_SUCCESS;
5115}
5116
5117
5118/**
5119 * Implements 'CPUID'.
5120 */
5121IEM_CIMPL_DEF_0(iemCImpl_cpuid)
5122{
5123 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5124
5125 CPUMGetGuestCpuId(IEMCPU_TO_VMCPU(pIemCpu), pCtx->eax, &pCtx->eax, &pCtx->ebx, &pCtx->ecx, &pCtx->edx);
5126 pCtx->rax &= UINT32_C(0xffffffff);
5127 pCtx->rbx &= UINT32_C(0xffffffff);
5128 pCtx->rcx &= UINT32_C(0xffffffff);
5129 pCtx->rdx &= UINT32_C(0xffffffff);
5130
5131 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5132 return VINF_SUCCESS;
5133}
5134
5135
5136/**
5137 * Implements 'AAD'.
5138 *
5139 * @param bImm The immediate operand.
5140 */
5141IEM_CIMPL_DEF_1(iemCImpl_aad, uint8_t, bImm)
5142{
5143 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5144
5145 uint16_t const ax = pCtx->ax;
5146 uint8_t const al = (uint8_t)ax + (uint8_t)(ax >> 8) * bImm;
5147 pCtx->ax = al;
5148 iemHlpUpdateArithEFlagsU8(pIemCpu, al,
5149 X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF,
5150 X86_EFL_OF | X86_EFL_AF | X86_EFL_CF);
5151
5152 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5153 return VINF_SUCCESS;
5154}
5155
5156
5157/**
5158 * Implements 'AAM'.
5159 *
5160 * @param bImm The immediate operand. Cannot be 0.
5161 */
5162IEM_CIMPL_DEF_1(iemCImpl_aam, uint8_t, bImm)
5163{
5164 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5165 Assert(bImm != 0); /* #DE on 0 is handled in the decoder. */
5166
5167 uint16_t const ax = pCtx->ax;
5168 uint8_t const al = (uint8_t)ax % bImm;
5169 uint8_t const ah = (uint8_t)ax / bImm;
5170 pCtx->ax = (ah << 8) + al;
5171 iemHlpUpdateArithEFlagsU8(pIemCpu, al,
5172 X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF,
5173 X86_EFL_OF | X86_EFL_AF | X86_EFL_CF);
5174
5175 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5176 return VINF_SUCCESS;
5177}
5178
5179
5180/**
5181 * Implements 'DAA'.
5182 */
5183IEM_CIMPL_DEF_0(iemCImpl_daa)
5184{
5185 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5186
5187 uint8_t const al = pCtx->al;
5188 bool const fCarry = pCtx->eflags.Bits.u1CF;
5189
5190 if ( pCtx->eflags.Bits.u1AF
5191 || (al & 0xf) >= 10)
5192 {
5193 pCtx->al = al + 6;
5194 pCtx->eflags.Bits.u1AF = 1;
5195 }
5196 else
5197 pCtx->eflags.Bits.u1AF = 0;
5198
5199 if (al >= 0x9a || fCarry)
5200 {
5201 pCtx->al += 0x60;
5202 pCtx->eflags.Bits.u1CF = 1;
5203 }
5204 else
5205 pCtx->eflags.Bits.u1CF = 0;
5206
5207 iemHlpUpdateArithEFlagsU8(pIemCpu, pCtx->al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
5208 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5209 return VINF_SUCCESS;
5210}
5211
5212
5213/**
5214 * Implements 'DAS'.
5215 */
5216IEM_CIMPL_DEF_0(iemCImpl_das)
5217{
5218 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5219
5220 uint8_t const uInputAL = pCtx->al;
5221 bool const fCarry = pCtx->eflags.Bits.u1CF;
5222
5223 if ( pCtx->eflags.Bits.u1AF
5224 || (uInputAL & 0xf) >= 10)
5225 {
5226 pCtx->eflags.Bits.u1AF = 1;
5227 if (uInputAL < 6)
5228 pCtx->eflags.Bits.u1CF = 1;
5229 pCtx->al = uInputAL - 6;
5230 }
5231 else
5232 {
5233 pCtx->eflags.Bits.u1AF = 0;
5234 pCtx->eflags.Bits.u1CF = 0;
5235 }
5236
5237 if (uInputAL >= 0x9a || fCarry)
5238 {
5239 pCtx->al -= 0x60;
5240 pCtx->eflags.Bits.u1CF = 1;
5241 }
5242
5243 iemHlpUpdateArithEFlagsU8(pIemCpu, pCtx->al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
5244 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5245 return VINF_SUCCESS;
5246}
5247
5248
5249
5250
5251/*
5252 * Instantiate the various string operation combinations.
5253 */
5254#define OP_SIZE 8
5255#define ADDR_SIZE 16
5256#include "IEMAllCImplStrInstr.cpp.h"
5257#define OP_SIZE 8
5258#define ADDR_SIZE 32
5259#include "IEMAllCImplStrInstr.cpp.h"
5260#define OP_SIZE 8
5261#define ADDR_SIZE 64
5262#include "IEMAllCImplStrInstr.cpp.h"
5263
5264#define OP_SIZE 16
5265#define ADDR_SIZE 16
5266#include "IEMAllCImplStrInstr.cpp.h"
5267#define OP_SIZE 16
5268#define ADDR_SIZE 32
5269#include "IEMAllCImplStrInstr.cpp.h"
5270#define OP_SIZE 16
5271#define ADDR_SIZE 64
5272#include "IEMAllCImplStrInstr.cpp.h"
5273
5274#define OP_SIZE 32
5275#define ADDR_SIZE 16
5276#include "IEMAllCImplStrInstr.cpp.h"
5277#define OP_SIZE 32
5278#define ADDR_SIZE 32
5279#include "IEMAllCImplStrInstr.cpp.h"
5280#define OP_SIZE 32
5281#define ADDR_SIZE 64
5282#include "IEMAllCImplStrInstr.cpp.h"
5283
5284#define OP_SIZE 64
5285#define ADDR_SIZE 32
5286#include "IEMAllCImplStrInstr.cpp.h"
5287#define OP_SIZE 64
5288#define ADDR_SIZE 64
5289#include "IEMAllCImplStrInstr.cpp.h"
5290
5291
5292/**
5293 * Implements 'FINIT' and 'FNINIT'.
5294 *
5295 * @param fCheckXcpts Whether to check for umasked pending exceptions or
5296 * not.
5297 */
5298IEM_CIMPL_DEF_1(iemCImpl_finit, bool, fCheckXcpts)
5299{
5300 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5301
5302 if (pCtx->cr0 & (X86_CR0_EM | X86_CR0_TS))
5303 return iemRaiseDeviceNotAvailable(pIemCpu);
5304
5305 NOREF(fCheckXcpts); /** @todo trigger pending exceptions:
5306 if (fCheckXcpts && TODO )
5307 return iemRaiseMathFault(pIemCpu);
5308 */
5309
5310 if (iemFRegIsFxSaveFormat(pIemCpu))
5311 {
5312 pCtx->fpu.FCW = 0x37f;
5313 pCtx->fpu.FSW = 0;
5314 pCtx->fpu.FTW = 0x00; /* 0 - empty. */
5315 pCtx->fpu.FPUDP = 0;
5316 pCtx->fpu.DS = 0; //??
5317 pCtx->fpu.Rsrvd2= 0;
5318 pCtx->fpu.FPUIP = 0;
5319 pCtx->fpu.CS = 0; //??
5320 pCtx->fpu.Rsrvd1= 0;
5321 pCtx->fpu.FOP = 0;
5322 }
5323 else
5324 {
5325 PX86FPUSTATE pFpu = (PX86FPUSTATE)&pCtx->fpu;
5326 pFpu->FCW = 0x37f;
5327 pFpu->FSW = 0;
5328 pFpu->FTW = 0xffff; /* 11 - empty */
5329 pFpu->FPUOO = 0; //??
5330 pFpu->FPUOS = 0; //??
5331 pFpu->FPUIP = 0;
5332 pFpu->CS = 0; //??
5333 pFpu->FOP = 0;
5334 }
5335
5336 iemHlpUsedFpu(pIemCpu);
5337 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5338 return VINF_SUCCESS;
5339}
5340
5341
5342/**
5343 * Implements 'FXSAVE'.
5344 *
5345 * @param iEffSeg The effective segment.
5346 * @param GCPtrEff The address of the image.
5347 * @param enmEffOpSize The operand size (only REX.W really matters).
5348 */
5349IEM_CIMPL_DEF_3(iemCImpl_fxsave, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
5350{
5351 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5352
5353 /*
5354 * Raise exceptions.
5355 */
5356 if (pCtx->cr0 & X86_CR0_EM)
5357 return iemRaiseUndefinedOpcode(pIemCpu);
5358 if (pCtx->cr0 & (X86_CR0_TS | X86_CR0_EM))
5359 return iemRaiseDeviceNotAvailable(pIemCpu);
5360 if (GCPtrEff & 15)
5361 {
5362 /** @todo CPU/VM detection possible! \#AC might not be signal for
5363 * all/any misalignment sizes, intel says its an implementation detail. */
5364 if ( (pCtx->cr0 & X86_CR0_AM)
5365 && pCtx->eflags.Bits.u1AC
5366 && pIemCpu->uCpl == 3)
5367 return iemRaiseAlignmentCheckException(pIemCpu);
5368 return iemRaiseGeneralProtectionFault0(pIemCpu);
5369 }
5370 AssertReturn(iemFRegIsFxSaveFormat(pIemCpu), VERR_IEM_IPE_2);
5371
5372 /*
5373 * Access the memory.
5374 */
5375 void *pvMem512;
5376 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, &pvMem512, 512, iEffSeg, GCPtrEff, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5377 if (rcStrict != VINF_SUCCESS)
5378 return rcStrict;
5379 PX86FXSTATE pDst = (PX86FXSTATE)pvMem512;
5380
5381 /*
5382 * Store the registers.
5383 */
5384 /** @todo CPU/VM detection possible! If CR4.OSFXSR=0 MXCSR it's
5385 * implementation specific whether MXCSR and XMM0-XMM7 are saved. */
5386
5387 /* common for all formats */
5388 pDst->FCW = pCtx->fpu.FCW;
5389 pDst->FSW = pCtx->fpu.FSW;
5390 pDst->FTW = pCtx->fpu.FTW & UINT16_C(0xff);
5391 pDst->FOP = pCtx->fpu.FOP;
5392 pDst->MXCSR = pCtx->fpu.MXCSR;
5393 pDst->MXCSR_MASK = pCtx->fpu.MXCSR_MASK;
5394 for (uint32_t i = 0; i < RT_ELEMENTS(pDst->aRegs); i++)
5395 {
5396 /** @todo Testcase: What actually happens to the 6 reserved bytes? I'm clearing
5397 * them for now... */
5398 pDst->aRegs[i].au32[0] = pCtx->fpu.aRegs[i].au32[0];
5399 pDst->aRegs[i].au32[1] = pCtx->fpu.aRegs[i].au32[1];
5400 pDst->aRegs[i].au32[2] = pCtx->fpu.aRegs[i].au32[2] & UINT32_C(0xffff);
5401 pDst->aRegs[i].au32[3] = 0;
5402 }
5403
5404 /* FPU IP, CS, DP and DS. */
5405 /** @todo FPU IP, CS, DP and DS cannot be implemented correctly without extra
5406 * state information. :-/
5407 * Storing zeros now to prevent any potential leakage of host info. */
5408 pDst->FPUIP = 0;
5409 pDst->CS = 0;
5410 pDst->Rsrvd1 = 0;
5411 pDst->FPUDP = 0;
5412 pDst->DS = 0;
5413 pDst->Rsrvd2 = 0;
5414
5415 /* XMM registers. */
5416 if ( !(pCtx->msrEFER & MSR_K6_EFER_FFXSR)
5417 || pIemCpu->enmCpuMode != IEMMODE_64BIT
5418 || pIemCpu->uCpl != 0)
5419 {
5420 uint32_t cXmmRegs = enmEffOpSize == IEMMODE_64BIT ? 16 : 8;
5421 for (uint32_t i = 0; i < cXmmRegs; i++)
5422 pDst->aXMM[i] = pCtx->fpu.aXMM[i];
5423 /** @todo Testcase: What happens to the reserved XMM registers? Untouched,
5424 * right? */
5425 }
5426
5427 /*
5428 * Commit the memory.
5429 */
5430 rcStrict = iemMemCommitAndUnmap(pIemCpu, pvMem512, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5431 if (rcStrict != VINF_SUCCESS)
5432 return rcStrict;
5433
5434 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5435 return VINF_SUCCESS;
5436}
5437
5438
5439/**
5440 * Implements 'FXRSTOR'.
5441 *
5442 * @param GCPtrEff The address of the image.
5443 * @param enmEffOpSize The operand size (only REX.W really matters).
5444 */
5445IEM_CIMPL_DEF_3(iemCImpl_fxrstor, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
5446{
5447 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5448
5449 /*
5450 * Raise exceptions.
5451 */
5452 if (pCtx->cr0 & X86_CR0_EM)
5453 return iemRaiseUndefinedOpcode(pIemCpu);
5454 if (pCtx->cr0 & (X86_CR0_TS | X86_CR0_EM))
5455 return iemRaiseDeviceNotAvailable(pIemCpu);
5456 if (GCPtrEff & 15)
5457 {
5458 /** @todo CPU/VM detection possible! \#AC might not be signal for
5459 * all/any misalignment sizes, intel says its an implementation detail. */
5460 if ( (pCtx->cr0 & X86_CR0_AM)
5461 && pCtx->eflags.Bits.u1AC
5462 && pIemCpu->uCpl == 3)
5463 return iemRaiseAlignmentCheckException(pIemCpu);
5464 return iemRaiseGeneralProtectionFault0(pIemCpu);
5465 }
5466 AssertReturn(iemFRegIsFxSaveFormat(pIemCpu), VERR_IEM_IPE_2);
5467
5468 /*
5469 * Access the memory.
5470 */
5471 void *pvMem512;
5472 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, &pvMem512, 512, iEffSeg, GCPtrEff, IEM_ACCESS_DATA_R);
5473 if (rcStrict != VINF_SUCCESS)
5474 return rcStrict;
5475 PCX86FXSTATE pSrc = (PCX86FXSTATE)pvMem512;
5476
5477 /*
5478 * Check the state for stuff which will GP(0).
5479 */
5480 uint32_t const fMXCSR = pSrc->MXCSR;
5481 uint32_t const fMXCSR_MASK = pCtx->fpu.MXCSR_MASK ? pCtx->fpu.MXCSR_MASK : UINT32_C(0xffbf);
5482 if (fMXCSR & ~fMXCSR_MASK)
5483 {
5484 Log(("fxrstor: MXCSR=%#x (MXCSR_MASK=%#x) -> #GP(0)\n", fMXCSR, fMXCSR_MASK));
5485 return iemRaiseGeneralProtectionFault0(pIemCpu);
5486 }
5487
5488 /*
5489 * Load the registers.
5490 */
5491 /** @todo CPU/VM detection possible! If CR4.OSFXSR=0 MXCSR it's
5492 * implementation specific whether MXCSR and XMM0-XMM7 are restored. */
5493
5494 /* common for all formats */
5495 pCtx->fpu.FCW = pSrc->FCW;
5496 pCtx->fpu.FSW = pSrc->FSW;
5497 pCtx->fpu.FTW = pSrc->FTW & UINT16_C(0xff);
5498 pCtx->fpu.FOP = pSrc->FOP;
5499 pCtx->fpu.MXCSR = fMXCSR;
5500 /* (MXCSR_MASK is read-only) */
5501 for (uint32_t i = 0; i < RT_ELEMENTS(pSrc->aRegs); i++)
5502 {
5503 pCtx->fpu.aRegs[i].au32[0] = pSrc->aRegs[i].au32[0];
5504 pCtx->fpu.aRegs[i].au32[1] = pSrc->aRegs[i].au32[1];
5505 pCtx->fpu.aRegs[i].au32[2] = pSrc->aRegs[i].au32[2] & UINT32_C(0xffff);
5506 pCtx->fpu.aRegs[i].au32[3] = 0;
5507 }
5508
5509 /* FPU IP, CS, DP and DS. */
5510 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
5511 {
5512 pCtx->fpu.FPUIP = pSrc->FPUIP;
5513 pCtx->fpu.CS = pSrc->CS;
5514 pCtx->fpu.Rsrvd1 = pSrc->Rsrvd1;
5515 pCtx->fpu.FPUDP = pSrc->FPUDP;
5516 pCtx->fpu.DS = pSrc->DS;
5517 pCtx->fpu.Rsrvd2 = pSrc->Rsrvd2;
5518 }
5519 else
5520 {
5521 pCtx->fpu.FPUIP = pSrc->FPUIP;
5522 pCtx->fpu.CS = pSrc->CS;
5523 pCtx->fpu.Rsrvd1 = 0;
5524 pCtx->fpu.FPUDP = pSrc->FPUDP;
5525 pCtx->fpu.DS = pSrc->DS;
5526 pCtx->fpu.Rsrvd2 = 0;
5527 }
5528
5529 /* XMM registers. */
5530 if ( !(pCtx->msrEFER & MSR_K6_EFER_FFXSR)
5531 || pIemCpu->enmCpuMode != IEMMODE_64BIT
5532 || pIemCpu->uCpl != 0)
5533 {
5534 uint32_t cXmmRegs = enmEffOpSize == IEMMODE_64BIT ? 16 : 8;
5535 for (uint32_t i = 0; i < cXmmRegs; i++)
5536 pCtx->fpu.aXMM[i] = pSrc->aXMM[i];
5537 }
5538
5539 /*
5540 * Commit the memory.
5541 */
5542 rcStrict = iemMemCommitAndUnmap(pIemCpu, pvMem512, IEM_ACCESS_DATA_R);
5543 if (rcStrict != VINF_SUCCESS)
5544 return rcStrict;
5545
5546 iemHlpUsedFpu(pIemCpu);
5547 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5548 return VINF_SUCCESS;
5549}
5550
5551
5552/**
5553 * Commmon routine for fnstenv and fnsave.
5554 *
5555 * @param uPtr Where to store the state.
5556 * @param pCtx The CPU context.
5557 */
5558static void iemCImplCommonFpuStoreEnv(PIEMCPU pIemCpu, IEMMODE enmEffOpSize, RTPTRUNION uPtr, PCCPUMCTX pCtx)
5559{
5560 if (enmEffOpSize == IEMMODE_16BIT)
5561 {
5562 uPtr.pu16[0] = pCtx->fpu.FCW;
5563 uPtr.pu16[1] = pCtx->fpu.FSW;
5564 uPtr.pu16[2] = iemFpuCalcFullFtw(pCtx);
5565 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
5566 {
5567 /** @todo Testcase: How does this work when the FPUIP/CS was saved in
5568 * protected mode or long mode and we save it in real mode? And vice
5569 * versa? And with 32-bit operand size? I think CPU is storing the
5570 * effective address ((CS << 4) + IP) in the offset register and not
5571 * doing any address calculations here. */
5572 uPtr.pu16[3] = (uint16_t)pCtx->fpu.FPUIP;
5573 uPtr.pu16[4] = ((pCtx->fpu.FPUIP >> 4) & UINT16_C(0xf000)) | pCtx->fpu.FOP;
5574 uPtr.pu16[5] = (uint16_t)pCtx->fpu.FPUDP;
5575 uPtr.pu16[6] = (pCtx->fpu.FPUDP >> 4) & UINT16_C(0xf000);
5576 }
5577 else
5578 {
5579 uPtr.pu16[3] = pCtx->fpu.FPUIP;
5580 uPtr.pu16[4] = pCtx->fpu.CS;
5581 uPtr.pu16[5] = pCtx->fpu.FPUDP;
5582 uPtr.pu16[6] = pCtx->fpu.DS;
5583 }
5584 }
5585 else
5586 {
5587 /** @todo Testcase: what is stored in the "gray" areas? (figure 8-9 and 8-10) */
5588 uPtr.pu16[0*2] = pCtx->fpu.FCW;
5589 uPtr.pu16[1*2] = pCtx->fpu.FSW;
5590 uPtr.pu16[2*2] = iemFpuCalcFullFtw(pCtx);
5591 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
5592 {
5593 uPtr.pu16[3*2] = (uint16_t)pCtx->fpu.FPUIP;
5594 uPtr.pu32[4] = ((pCtx->fpu.FPUIP & UINT32_C(0xffff0000)) >> 4) | pCtx->fpu.FOP;
5595 uPtr.pu16[5*2] = (uint16_t)pCtx->fpu.FPUDP;
5596 uPtr.pu32[6] = (pCtx->fpu.FPUDP & UINT32_C(0xffff0000)) >> 4;
5597 }
5598 else
5599 {
5600 uPtr.pu32[3] = pCtx->fpu.FPUIP;
5601 uPtr.pu16[4*2] = pCtx->fpu.CS;
5602 uPtr.pu16[4*2+1]= pCtx->fpu.FOP;
5603 uPtr.pu32[5] = pCtx->fpu.FPUDP;
5604 uPtr.pu16[6*2] = pCtx->fpu.DS;
5605 }
5606 }
5607}
5608
5609
5610/**
5611 * Commmon routine for fldenv and frstor
5612 *
5613 * @param uPtr Where to store the state.
5614 * @param pCtx The CPU context.
5615 */
5616static void iemCImplCommonFpuRestoreEnv(PIEMCPU pIemCpu, IEMMODE enmEffOpSize, RTCPTRUNION uPtr, PCPUMCTX pCtx)
5617{
5618 if (enmEffOpSize == IEMMODE_16BIT)
5619 {
5620 pCtx->fpu.FCW = uPtr.pu16[0];
5621 pCtx->fpu.FSW = uPtr.pu16[1];
5622 pCtx->fpu.FTW = uPtr.pu16[2];
5623 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
5624 {
5625 pCtx->fpu.FPUIP = uPtr.pu16[3] | ((uint32_t)(uPtr.pu16[4] & UINT16_C(0xf000)) << 4);
5626 pCtx->fpu.FPUDP = uPtr.pu16[5] | ((uint32_t)(uPtr.pu16[6] & UINT16_C(0xf000)) << 4);
5627 pCtx->fpu.FOP = uPtr.pu16[4] & UINT16_C(0x07ff);
5628 pCtx->fpu.CS = 0;
5629 pCtx->fpu.Rsrvd1= 0;
5630 pCtx->fpu.DS = 0;
5631 pCtx->fpu.Rsrvd2= 0;
5632 }
5633 else
5634 {
5635 pCtx->fpu.FPUIP = uPtr.pu16[3];
5636 pCtx->fpu.CS = uPtr.pu16[4];
5637 pCtx->fpu.Rsrvd1= 0;
5638 pCtx->fpu.FPUDP = uPtr.pu16[5];
5639 pCtx->fpu.DS = uPtr.pu16[6];
5640 pCtx->fpu.Rsrvd2= 0;
5641 /** @todo Testcase: Is FOP cleared when doing 16-bit protected mode fldenv? */
5642 }
5643 }
5644 else
5645 {
5646 pCtx->fpu.FCW = uPtr.pu16[0*2];
5647 pCtx->fpu.FSW = uPtr.pu16[1*2];
5648 pCtx->fpu.FTW = uPtr.pu16[2*2];
5649 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
5650 {
5651 pCtx->fpu.FPUIP = uPtr.pu16[3*2] | ((uPtr.pu32[4] & UINT32_C(0x0ffff000)) << 4);
5652 pCtx->fpu.FOP = uPtr.pu32[4] & UINT16_C(0x07ff);
5653 pCtx->fpu.FPUDP = uPtr.pu16[5*2] | ((uPtr.pu32[6] & UINT32_C(0x0ffff000)) << 4);
5654 pCtx->fpu.CS = 0;
5655 pCtx->fpu.Rsrvd1= 0;
5656 pCtx->fpu.DS = 0;
5657 pCtx->fpu.Rsrvd2= 0;
5658 }
5659 else
5660 {
5661 pCtx->fpu.FPUIP = uPtr.pu32[3];
5662 pCtx->fpu.CS = uPtr.pu16[4*2];
5663 pCtx->fpu.Rsrvd1= 0;
5664 pCtx->fpu.FOP = uPtr.pu16[4*2+1];
5665 pCtx->fpu.FPUDP = uPtr.pu32[5];
5666 pCtx->fpu.DS = uPtr.pu16[6*2];
5667 pCtx->fpu.Rsrvd2= 0;
5668 }
5669 }
5670
5671 /* Make adjustments. */
5672 pCtx->fpu.FTW = iemFpuCompressFtw(pCtx->fpu.FTW);
5673 pCtx->fpu.FCW &= ~X86_FCW_ZERO_MASK;
5674 iemFpuRecalcExceptionStatus(pCtx);
5675 /** @todo Testcase: Check if ES and/or B are automatically cleared if no
5676 * exceptions are pending after loading the saved state? */
5677}
5678
5679
5680/**
5681 * Implements 'FNSTENV'.
5682 *
5683 * @param enmEffOpSize The operand size (only REX.W really matters).
5684 * @param iEffSeg The effective segment register for @a GCPtrEff.
5685 * @param GCPtrEffDst The address of the image.
5686 */
5687IEM_CIMPL_DEF_3(iemCImpl_fnstenv, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
5688{
5689 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5690 RTPTRUNION uPtr;
5691 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, &uPtr.pv, enmEffOpSize == IEMMODE_16BIT ? 14 : 28,
5692 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5693 if (rcStrict != VINF_SUCCESS)
5694 return rcStrict;
5695
5696 iemCImplCommonFpuStoreEnv(pIemCpu, enmEffOpSize, uPtr, pCtx);
5697
5698 rcStrict = iemMemCommitAndUnmap(pIemCpu, uPtr.pv, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5699 if (rcStrict != VINF_SUCCESS)
5700 return rcStrict;
5701
5702 /* Note: C0, C1, C2 and C3 are documented as undefined, we leave them untouched! */
5703 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5704 return VINF_SUCCESS;
5705}
5706
5707
5708/**
5709 * Implements 'FNSAVE'.
5710 *
5711 * @param GCPtrEffDst The address of the image.
5712 * @param enmEffOpSize The operand size.
5713 */
5714IEM_CIMPL_DEF_3(iemCImpl_fnsave, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
5715{
5716 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5717 RTPTRUNION uPtr;
5718 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, &uPtr.pv, enmEffOpSize == IEMMODE_16BIT ? 94 : 108,
5719 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5720 if (rcStrict != VINF_SUCCESS)
5721 return rcStrict;
5722
5723 iemCImplCommonFpuStoreEnv(pIemCpu, enmEffOpSize, uPtr, pCtx);
5724 PRTFLOAT80U paRegs = (PRTFLOAT80U)(uPtr.pu8 + (enmEffOpSize == IEMMODE_16BIT ? 14 : 28));
5725 for (uint32_t i = 0; i < RT_ELEMENTS(pCtx->fpu.aRegs); i++)
5726 {
5727 paRegs[i].au32[0] = pCtx->fpu.aRegs[i].au32[0];
5728 paRegs[i].au32[1] = pCtx->fpu.aRegs[i].au32[1];
5729 paRegs[i].au16[4] = pCtx->fpu.aRegs[i].au16[4];
5730 }
5731
5732 rcStrict = iemMemCommitAndUnmap(pIemCpu, uPtr.pv, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5733 if (rcStrict != VINF_SUCCESS)
5734 return rcStrict;
5735
5736 /*
5737 * Re-initialize the FPU.
5738 */
5739 pCtx->fpu.FCW = 0x37f;
5740 pCtx->fpu.FSW = 0;
5741 pCtx->fpu.FTW = 0x00; /* 0 - empty */
5742 pCtx->fpu.FPUDP = 0;
5743 pCtx->fpu.DS = 0;
5744 pCtx->fpu.Rsrvd2= 0;
5745 pCtx->fpu.FPUIP = 0;
5746 pCtx->fpu.CS = 0;
5747 pCtx->fpu.Rsrvd1= 0;
5748 pCtx->fpu.FOP = 0;
5749
5750 iemHlpUsedFpu(pIemCpu);
5751 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5752 return VINF_SUCCESS;
5753}
5754
5755
5756
5757/**
5758 * Implements 'FLDENV'.
5759 *
5760 * @param enmEffOpSize The operand size (only REX.W really matters).
5761 * @param iEffSeg The effective segment register for @a GCPtrEff.
5762 * @param GCPtrEffSrc The address of the image.
5763 */
5764IEM_CIMPL_DEF_3(iemCImpl_fldenv, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
5765{
5766 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5767 RTCPTRUNION uPtr;
5768 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, (void **)&uPtr.pv, enmEffOpSize == IEMMODE_16BIT ? 14 : 28,
5769 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R);
5770 if (rcStrict != VINF_SUCCESS)
5771 return rcStrict;
5772
5773 iemCImplCommonFpuRestoreEnv(pIemCpu, enmEffOpSize, uPtr, pCtx);
5774
5775 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)uPtr.pv, IEM_ACCESS_DATA_R);
5776 if (rcStrict != VINF_SUCCESS)
5777 return rcStrict;
5778
5779 iemHlpUsedFpu(pIemCpu);
5780 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5781 return VINF_SUCCESS;
5782}
5783
5784
5785/**
5786 * Implements 'FRSTOR'.
5787 *
5788 * @param GCPtrEffSrc The address of the image.
5789 * @param enmEffOpSize The operand size.
5790 */
5791IEM_CIMPL_DEF_3(iemCImpl_frstor, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
5792{
5793 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5794 RTCPTRUNION uPtr;
5795 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, (void **)&uPtr.pv, enmEffOpSize == IEMMODE_16BIT ? 94 : 108,
5796 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R);
5797 if (rcStrict != VINF_SUCCESS)
5798 return rcStrict;
5799
5800 iemCImplCommonFpuRestoreEnv(pIemCpu, enmEffOpSize, uPtr, pCtx);
5801 PCRTFLOAT80U paRegs = (PCRTFLOAT80U)(uPtr.pu8 + (enmEffOpSize == IEMMODE_16BIT ? 14 : 28));
5802 for (uint32_t i = 0; i < RT_ELEMENTS(pCtx->fpu.aRegs); i++)
5803 {
5804 pCtx->fpu.aRegs[i].au32[0] = paRegs[i].au32[0];
5805 pCtx->fpu.aRegs[i].au32[1] = paRegs[i].au32[1];
5806 pCtx->fpu.aRegs[i].au32[2] = paRegs[i].au16[4];
5807 pCtx->fpu.aRegs[i].au32[3] = 0;
5808 }
5809
5810 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)uPtr.pv, IEM_ACCESS_DATA_R);
5811 if (rcStrict != VINF_SUCCESS)
5812 return rcStrict;
5813
5814 iemHlpUsedFpu(pIemCpu);
5815 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5816 return VINF_SUCCESS;
5817}
5818
5819
5820/**
5821 * Implements 'FLDCW'.
5822 *
5823 * @param u16Fcw The new FCW.
5824 */
5825IEM_CIMPL_DEF_1(iemCImpl_fldcw, uint16_t, u16Fcw)
5826{
5827 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5828
5829 /** @todo Testcase: Check what happens when trying to load X86_FCW_PC_RSVD. */
5830 /** @todo Testcase: Try see what happens when trying to set undefined bits
5831 * (other than 6 and 7). Currently ignoring them. */
5832 /** @todo Testcase: Test that it raises and loweres the FPU exception bits
5833 * according to FSW. (This is was is currently implemented.) */
5834 pCtx->fpu.FCW = u16Fcw & ~X86_FCW_ZERO_MASK;
5835 iemFpuRecalcExceptionStatus(pCtx);
5836
5837 /* Note: C0, C1, C2 and C3 are documented as undefined, we leave them untouched! */
5838 iemHlpUsedFpu(pIemCpu);
5839 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5840 return VINF_SUCCESS;
5841}
5842
5843
5844
5845/**
5846 * Implements the underflow case of fxch.
5847 *
5848 * @param iStReg The other stack register.
5849 */
5850IEM_CIMPL_DEF_1(iemCImpl_fxch_underflow, uint8_t, iStReg)
5851{
5852 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5853
5854 unsigned const iReg1 = X86_FSW_TOP_GET(pCtx->fpu.FSW);
5855 unsigned const iReg2 = (iReg1 + iStReg) & X86_FSW_TOP_SMASK;
5856 Assert(!(RT_BIT(iReg1) & pCtx->fpu.FTW) || !(RT_BIT(iReg2) & pCtx->fpu.FTW));
5857
5858 /** @todo Testcase: fxch underflow. Making assumptions that underflowed
5859 * registers are read as QNaN and then exchanged. This could be
5860 * wrong... */
5861 if (pCtx->fpu.FCW & X86_FCW_IM)
5862 {
5863 if (RT_BIT(iReg1) & pCtx->fpu.FTW)
5864 {
5865 if (RT_BIT(iReg2) & pCtx->fpu.FTW)
5866 iemFpuStoreQNan(&pCtx->fpu.aRegs[0].r80);
5867 else
5868 pCtx->fpu.aRegs[0].r80 = pCtx->fpu.aRegs[iStReg].r80;
5869 iemFpuStoreQNan(&pCtx->fpu.aRegs[iStReg].r80);
5870 }
5871 else
5872 {
5873 pCtx->fpu.aRegs[iStReg].r80 = pCtx->fpu.aRegs[0].r80;
5874 iemFpuStoreQNan(&pCtx->fpu.aRegs[0].r80);
5875 }
5876 pCtx->fpu.FSW &= ~X86_FSW_C_MASK;
5877 pCtx->fpu.FSW |= X86_FSW_C1 | X86_FSW_IE | X86_FSW_SF;
5878 }
5879 else
5880 {
5881 /* raise underflow exception, don't change anything. */
5882 pCtx->fpu.FSW &= ~(X86_FSW_TOP_MASK | X86_FSW_XCPT_MASK);
5883 pCtx->fpu.FSW |= X86_FSW_C1 | X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B;
5884 }
5885
5886 iemFpuUpdateOpcodeAndIpWorker(pIemCpu, pCtx);
5887 iemHlpUsedFpu(pIemCpu);
5888 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5889 return VINF_SUCCESS;
5890}
5891
5892
5893/**
5894 * Implements 'FCOMI', 'FCOMIP', 'FUCOMI', and 'FUCOMIP'.
5895 *
5896 * @param cToAdd 1 or 7.
5897 */
5898IEM_CIMPL_DEF_3(iemCImpl_fcomi_fucomi, uint8_t, iStReg, PFNIEMAIMPLFPUR80EFL, pfnAImpl, bool, fPop)
5899{
5900 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5901 Assert(iStReg < 8);
5902
5903 /*
5904 * Raise exceptions.
5905 */
5906 if (pCtx->cr0 & (X86_CR0_EM | X86_CR0_TS))
5907 return iemRaiseDeviceNotAvailable(pIemCpu);
5908 uint16_t u16Fsw = pCtx->fpu.FSW;
5909 if (u16Fsw & X86_FSW_ES)
5910 return iemRaiseMathFault(pIemCpu);
5911
5912 /*
5913 * Check if any of the register accesses causes #SF + #IA.
5914 */
5915 unsigned const iReg1 = X86_FSW_TOP_GET(u16Fsw);
5916 unsigned const iReg2 = (iReg1 + iStReg) & X86_FSW_TOP_SMASK;
5917 if ((pCtx->fpu.FTW & (RT_BIT(iReg1) | RT_BIT(iReg2))) == (RT_BIT(iReg1) | RT_BIT(iReg2)))
5918 {
5919 uint32_t u32Eflags = pfnAImpl(&pCtx->fpu, &u16Fsw, &pCtx->fpu.aRegs[0].r80, &pCtx->fpu.aRegs[iStReg].r80);
5920 NOREF(u32Eflags);
5921
5922 pCtx->fpu.FSW &= ~X86_FSW_C1;
5923 pCtx->fpu.FSW |= u16Fsw & ~X86_FSW_TOP_MASK;
5924 if ( !(u16Fsw & X86_FSW_IE)
5925 || (pCtx->fpu.FCW & X86_FCW_IM) )
5926 {
5927 pCtx->eflags.u &= ~(X86_EFL_OF | X86_EFL_SF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
5928 pCtx->eflags.u |= pCtx->eflags.u & (X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
5929 }
5930 }
5931 else if (pCtx->fpu.FCW & X86_FCW_IM)
5932 {
5933 /* Masked underflow. */
5934 pCtx->fpu.FSW &= ~X86_FSW_C1;
5935 pCtx->fpu.FSW |= X86_FSW_IE | X86_FSW_SF;
5936 pCtx->eflags.u &= ~(X86_EFL_OF | X86_EFL_SF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
5937 pCtx->eflags.u |= X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF;
5938 }
5939 else
5940 {
5941 /* Raise underflow - don't touch EFLAGS or TOP. */
5942 pCtx->fpu.FSW &= ~X86_FSW_C1;
5943 pCtx->fpu.FSW |= X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B;
5944 fPop = false;
5945 }
5946
5947 /*
5948 * Pop if necessary.
5949 */
5950 if (fPop)
5951 {
5952 pCtx->fpu.FTW &= ~RT_BIT(iReg1);
5953 pCtx->fpu.FSW &= X86_FSW_TOP_MASK;
5954 pCtx->fpu.FSW |= ((iReg1 + 7) & X86_FSW_TOP_SMASK) << X86_FSW_TOP_SHIFT;
5955 }
5956
5957 iemFpuUpdateOpcodeAndIpWorker(pIemCpu, pCtx);
5958 iemHlpUsedFpu(pIemCpu);
5959 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5960 return VINF_SUCCESS;
5961}
5962
5963/** @} */
5964
Note: See TracBrowser for help on using the repository browser.

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