VirtualBox

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

Last change on this file since 52343 was 52066, checked in by vboxsync, 11 years ago

VMM: Fixed potential bug in AMD-V NMI injection when interrupt shadowing is in effect, renamed INHIBIT_NMIS to BLOCK_NMIS to match Intel specs.

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

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