VirtualBox

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

Last change on this file since 51333 was 51182, checked in by vboxsync, 11 years ago

VMM/IEM: Implemented hardware task-switches, code path disabled.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 203.3 KB
Line 
1/* $Id: IEMAllCImpl.cpp.h 51182 2014-05-05 12:08:40Z 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 * Call a mode specific worker.
2993 */
2994 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
2995 return IEM_CIMPL_CALL_1(iemCImpl_iret_real_v8086, enmEffOpSize);
2996 if (IEM_IS_LONG_MODE(pIemCpu))
2997 return IEM_CIMPL_CALL_1(iemCImpl_iret_long, enmEffOpSize);
2998
2999 return IEM_CIMPL_CALL_1(iemCImpl_iret_prot, enmEffOpSize);
3000}
3001
3002
3003/**
3004 * Implements SYSCALL (AMD and Intel64).
3005 *
3006 * @param enmEffOpSize The effective operand size.
3007 */
3008IEM_CIMPL_DEF_0(iemCImpl_syscall)
3009{
3010 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3011
3012 /*
3013 * Check preconditions.
3014 *
3015 * Note that CPUs described in the documentation may load a few odd values
3016 * into CS and SS than we allow here. This has yet to be checked on real
3017 * hardware.
3018 */
3019 if (!(pCtx->msrEFER & MSR_K6_EFER_SCE))
3020 {
3021 Log(("syscall: Not enabled in EFER -> #UD\n"));
3022 return iemRaiseUndefinedOpcode(pIemCpu);
3023 }
3024 if (!(pCtx->cr0 & X86_CR0_PE))
3025 {
3026 Log(("syscall: Protected mode is required -> #GP(0)\n"));
3027 return iemRaiseGeneralProtectionFault0(pIemCpu);
3028 }
3029 if (IEM_IS_GUEST_CPU_INTEL(pIemCpu) && !CPUMIsGuestInLongModeEx(pCtx))
3030 {
3031 Log(("syscall: Only available in long mode on intel -> #UD\n"));
3032 return iemRaiseUndefinedOpcode(pIemCpu);
3033 }
3034
3035 /** @todo verify RPL ignoring and CS=0xfff8 (i.e. SS == 0). */
3036 /** @todo what about LDT selectors? Shouldn't matter, really. */
3037 uint16_t uNewCs = (pCtx->msrSTAR >> MSR_K6_STAR_SYSCALL_CS_SS_SHIFT) & X86_SEL_MASK_OFF_RPL;
3038 uint16_t uNewSs = uNewCs + 8;
3039 if (uNewCs == 0 || uNewSs == 0)
3040 {
3041 Log(("syscall: msrSTAR.CS = 0 or SS = 0 -> #GP(0)\n"));
3042 return iemRaiseGeneralProtectionFault0(pIemCpu);
3043 }
3044
3045 /* Long mode and legacy mode differs. */
3046 if (CPUMIsGuestInLongModeEx(pCtx))
3047 {
3048 uint64_t uNewRip = pIemCpu->enmCpuMode == IEMMODE_64BIT ? pCtx->msrLSTAR : pCtx-> msrCSTAR;
3049
3050 /* This test isn't in the docs, but I'm not trusting the guys writing
3051 the MSRs to have validated the values as canonical like they should. */
3052 if (!IEM_IS_CANONICAL(uNewRip))
3053 {
3054 Log(("syscall: Only available in long mode on intel -> #UD\n"));
3055 return iemRaiseUndefinedOpcode(pIemCpu);
3056 }
3057
3058 /*
3059 * Commit it.
3060 */
3061 Log(("syscall: %04x:%016RX64 [efl=%#llx] -> %04x:%016RX64\n", pCtx->cs, pCtx->rip, pCtx->rflags.u, uNewCs, uNewRip));
3062 pCtx->rcx = pCtx->rip + cbInstr;
3063 pCtx->rip = uNewRip;
3064
3065 pCtx->rflags.u &= ~X86_EFL_RF;
3066 pCtx->r11 = pCtx->rflags.u;
3067 pCtx->rflags.u &= ~pCtx->msrSFMASK;
3068 pCtx->rflags.u |= X86_EFL_1;
3069
3070 pCtx->cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_L | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC;
3071 pCtx->ss.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_L | X86DESCATTR_DT | X86_SEL_TYPE_RW_ACC;
3072 }
3073 else
3074 {
3075 /*
3076 * Commit it.
3077 */
3078 Log(("syscall: %04x:%08RX32 [efl=%#x] -> %04x:%08RX32\n",
3079 pCtx->cs, pCtx->eip, pCtx->eflags.u, uNewCs, (uint32_t)(pCtx->msrSTAR & MSR_K6_STAR_SYSCALL_EIP_MASK)));
3080 pCtx->rcx = pCtx->eip + cbInstr;
3081 pCtx->rip = pCtx->msrSTAR & MSR_K6_STAR_SYSCALL_EIP_MASK;
3082 pCtx->rflags.u &= ~(X86_EFL_VM | X86_EFL_IF | X86_EFL_RF);
3083
3084 pCtx->cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC;
3085 pCtx->ss.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_RW_ACC;
3086 }
3087 pCtx->cs.Sel = uNewCs;
3088 pCtx->cs.ValidSel = uNewCs;
3089 pCtx->cs.u64Base = 0;
3090 pCtx->cs.u32Limit = UINT32_MAX;
3091 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
3092
3093 pCtx->ss.Sel = uNewSs;
3094 pCtx->ss.ValidSel = uNewSs;
3095 pCtx->ss.u64Base = 0;
3096 pCtx->ss.u32Limit = UINT32_MAX;
3097 pCtx->ss.fFlags = CPUMSELREG_FLAGS_VALID;
3098
3099 return VINF_SUCCESS;
3100}
3101
3102
3103/**
3104 * Implements SYSRET (AMD and Intel64).
3105 */
3106IEM_CIMPL_DEF_0(iemCImpl_sysret)
3107
3108{
3109 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3110
3111 /*
3112 * Check preconditions.
3113 *
3114 * Note that CPUs described in the documentation may load a few odd values
3115 * into CS and SS than we allow here. This has yet to be checked on real
3116 * hardware.
3117 */
3118 if (!(pCtx->msrEFER & MSR_K6_EFER_SCE))
3119 {
3120 Log(("sysret: Not enabled in EFER -> #UD\n"));
3121 return iemRaiseUndefinedOpcode(pIemCpu);
3122 }
3123 if (IEM_IS_GUEST_CPU_INTEL(pIemCpu) && !CPUMIsGuestInLongModeEx(pCtx))
3124 {
3125 Log(("sysret: Only available in long mode on intel -> #UD\n"));
3126 return iemRaiseUndefinedOpcode(pIemCpu);
3127 }
3128 if (!(pCtx->cr0 & X86_CR0_PE))
3129 {
3130 Log(("sysret: Protected mode is required -> #GP(0)\n"));
3131 return iemRaiseGeneralProtectionFault0(pIemCpu);
3132 }
3133 if (pIemCpu->uCpl != 0)
3134 {
3135 Log(("sysret: CPL must be 0 not %u -> #GP(0)\n", pIemCpu->uCpl));
3136 return iemRaiseGeneralProtectionFault0(pIemCpu);
3137 }
3138
3139 /** @todo Does SYSRET verify CS != 0 and SS != 0? Neither is valid in ring-3. */
3140 uint16_t uNewCs = (pCtx->msrSTAR >> MSR_K6_STAR_SYSRET_CS_SS_SHIFT) & X86_SEL_MASK_OFF_RPL;
3141 uint16_t uNewSs = uNewCs + 8;
3142 if (pIemCpu->enmEffOpSize == IEMMODE_64BIT)
3143 uNewCs += 16;
3144 if (uNewCs == 0 || uNewSs == 0)
3145 {
3146 Log(("sysret: msrSTAR.CS = 0 or SS = 0 -> #GP(0)\n"));
3147 return iemRaiseGeneralProtectionFault0(pIemCpu);
3148 }
3149
3150 /*
3151 * Commit it.
3152 */
3153 if (CPUMIsGuestInLongModeEx(pCtx))
3154 {
3155 if (pIemCpu->enmEffOpSize == IEMMODE_64BIT)
3156 {
3157 Log(("sysret: %04x:%016RX64 [efl=%#llx] -> %04x:%016RX64 [r11=%#llx]\n",
3158 pCtx->cs, pCtx->rip, pCtx->rflags.u, uNewCs, pCtx->rcx, pCtx->r11));
3159 /* Note! We disregard intel manual regarding the RCX cananonical
3160 check, ask intel+xen why AMD doesn't do it. */
3161 pCtx->rip = pCtx->rcx;
3162 pCtx->cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_L | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC
3163 | (3 << X86DESCATTR_DPL_SHIFT);
3164 }
3165 else
3166 {
3167 Log(("sysret: %04x:%016RX64 [efl=%#llx] -> %04x:%08RX32 [r11=%#llx]\n",
3168 pCtx->cs, pCtx->rip, pCtx->rflags.u, uNewCs, pCtx->ecx, pCtx->r11));
3169 pCtx->rip = pCtx->ecx;
3170 pCtx->cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC
3171 | (3 << X86DESCATTR_DPL_SHIFT);
3172 }
3173 /** @todo testcase: See what kind of flags we can make SYSRET restore and
3174 * what it really ignores. RF and VM are hinted at being zero, by AMD. */
3175 pCtx->rflags.u = pCtx->r11 & (X86_EFL_POPF_BITS | X86_EFL_VIF | X86_EFL_VIP);
3176 pCtx->rflags.u |= X86_EFL_1;
3177 }
3178 else
3179 {
3180 Log(("sysret: %04x:%08RX32 [efl=%#x] -> %04x:%08RX32\n", pCtx->cs, pCtx->eip, pCtx->eflags.u, uNewCs, pCtx->ecx));
3181 pCtx->rip = pCtx->rcx;
3182 pCtx->rflags.u |= X86_EFL_IF;
3183 pCtx->cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC
3184 | (3 << X86DESCATTR_DPL_SHIFT);
3185 }
3186 pCtx->cs.Sel = uNewCs | 3;
3187 pCtx->cs.ValidSel = uNewCs | 3;
3188 pCtx->cs.u64Base = 0;
3189 pCtx->cs.u32Limit = UINT32_MAX;
3190 pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
3191
3192 pCtx->ss.Sel = uNewSs | 3;
3193 pCtx->ss.ValidSel = uNewSs | 3;
3194 pCtx->ss.fFlags = CPUMSELREG_FLAGS_VALID;
3195 /* The SS hidden bits remains unchanged says AMD. To that I say "Yeah, right!". */
3196 pCtx->ss.Attr.u |= (3 << X86DESCATTR_DPL_SHIFT);
3197 /** @todo Testcase: verify that SS.u1Long and SS.u1DefBig are left unchanged
3198 * on sysret. */
3199
3200 return VINF_SUCCESS;
3201}
3202
3203
3204/**
3205 * Common worker for 'pop SReg', 'mov SReg, GReg' and 'lXs GReg, reg/mem'.
3206 *
3207 * @param iSegReg The segment register number (valid).
3208 * @param uSel The new selector value.
3209 */
3210IEM_CIMPL_DEF_2(iemCImpl_LoadSReg, uint8_t, iSegReg, uint16_t, uSel)
3211{
3212 /*PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);*/
3213 uint16_t *pSel = iemSRegRef(pIemCpu, iSegReg);
3214 PCPUMSELREGHID pHid = iemSRegGetHid(pIemCpu, iSegReg);
3215
3216 Assert(iSegReg <= X86_SREG_GS && iSegReg != X86_SREG_CS);
3217
3218 /*
3219 * Real mode and V8086 mode are easy.
3220 */
3221 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
3222 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
3223 {
3224 *pSel = uSel;
3225 pHid->u64Base = (uint32_t)uSel << 4;
3226 pHid->ValidSel = uSel;
3227 pHid->fFlags = CPUMSELREG_FLAGS_VALID;
3228#if 0 /* AMD Volume 2, chapter 4.1 - "real mode segmentation" - states that limit and attributes are untouched. */
3229 /** @todo Does the CPU actually load limits and attributes in the
3230 * real/V8086 mode segment load case? It doesn't for CS in far
3231 * jumps... Affects unreal mode. */
3232 pHid->u32Limit = 0xffff;
3233 pHid->Attr.u = 0;
3234 pHid->Attr.n.u1Present = 1;
3235 pHid->Attr.n.u1DescType = 1;
3236 pHid->Attr.n.u4Type = iSegReg != X86_SREG_CS
3237 ? X86_SEL_TYPE_RW
3238 : X86_SEL_TYPE_READ | X86_SEL_TYPE_CODE;
3239#endif
3240 CPUMSetChangedFlags(IEMCPU_TO_VMCPU(pIemCpu), CPUM_CHANGED_HIDDEN_SEL_REGS);
3241 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3242 return VINF_SUCCESS;
3243 }
3244
3245 /*
3246 * Protected mode.
3247 *
3248 * Check if it's a null segment selector value first, that's OK for DS, ES,
3249 * FS and GS. If not null, then we have to load and parse the descriptor.
3250 */
3251 if (!(uSel & X86_SEL_MASK_OFF_RPL))
3252 {
3253 Assert(iSegReg != X86_SREG_CS); /** @todo testcase for \#UD on MOV CS, ax! */
3254 if (iSegReg == X86_SREG_SS)
3255 {
3256 /* In 64-bit kernel mode, the stack can be 0 because of the way
3257 interrupts are dispatched. AMD seems to have a slighly more
3258 relaxed relationship to SS.RPL than intel does. */
3259 /** @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! */
3260 if ( pIemCpu->enmCpuMode != IEMMODE_64BIT
3261 || pIemCpu->uCpl > 2
3262 || ( uSel != pIemCpu->uCpl
3263 && !IEM_IS_GUEST_CPU_AMD(pIemCpu)) )
3264 {
3265 Log(("load sreg %#x -> invalid stack selector, #GP(0)\n", uSel));
3266 return iemRaiseGeneralProtectionFault0(pIemCpu);
3267 }
3268 }
3269
3270 *pSel = uSel; /* Not RPL, remember :-) */
3271 iemHlpLoadNullDataSelectorProt(pIemCpu, pHid, uSel);
3272 if (iSegReg == X86_SREG_SS)
3273 pHid->Attr.u |= pIemCpu->uCpl << X86DESCATTR_DPL_SHIFT;
3274
3275 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(IEMCPU_TO_VMCPU(pIemCpu), pHid));
3276 CPUMSetChangedFlags(IEMCPU_TO_VMCPU(pIemCpu), CPUM_CHANGED_HIDDEN_SEL_REGS);
3277
3278 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3279 return VINF_SUCCESS;
3280 }
3281
3282 /* Fetch the descriptor. */
3283 IEMSELDESC Desc;
3284 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uSel, X86_XCPT_GP); /** @todo Correct exception? */
3285 if (rcStrict != VINF_SUCCESS)
3286 return rcStrict;
3287
3288 /* Check GPs first. */
3289 if (!Desc.Legacy.Gen.u1DescType)
3290 {
3291 Log(("load sreg %d - system selector (%#x) -> #GP\n", iSegReg, uSel, Desc.Legacy.Gen.u4Type));
3292 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3293 }
3294 if (iSegReg == X86_SREG_SS) /* SS gets different treatment */
3295 {
3296 if ( (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
3297 || !(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
3298 {
3299 Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
3300 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3301 }
3302 if ((uSel & X86_SEL_RPL) != pIemCpu->uCpl)
3303 {
3304 Log(("load sreg SS, %#x - RPL and CPL (%d) differs -> #GP\n", uSel, pIemCpu->uCpl));
3305 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3306 }
3307 if (Desc.Legacy.Gen.u2Dpl != pIemCpu->uCpl)
3308 {
3309 Log(("load sreg SS, %#x - DPL (%d) and CPL (%d) differs -> #GP\n", uSel, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
3310 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3311 }
3312 }
3313 else
3314 {
3315 if ((Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
3316 {
3317 Log(("load sreg%u, %#x - execute only segment -> #GP\n", iSegReg, uSel));
3318 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3319 }
3320 if ( (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
3321 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
3322 {
3323#if 0 /* this is what intel says. */
3324 if ( (uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl
3325 && pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
3326 {
3327 Log(("load sreg%u, %#x - both RPL (%d) and CPL (%d) are greater than DPL (%d) -> #GP\n",
3328 iSegReg, uSel, (uSel & X86_SEL_RPL), pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
3329 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3330 }
3331#else /* this is what makes more sense. */
3332 if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
3333 {
3334 Log(("load sreg%u, %#x - RPL (%d) is greater than DPL (%d) -> #GP\n",
3335 iSegReg, uSel, (uSel & X86_SEL_RPL), Desc.Legacy.Gen.u2Dpl));
3336 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3337 }
3338 if (pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
3339 {
3340 Log(("load sreg%u, %#x - CPL (%d) is greater than DPL (%d) -> #GP\n",
3341 iSegReg, uSel, pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
3342 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
3343 }
3344#endif
3345 }
3346 }
3347
3348 /* Is it there? */
3349 if (!Desc.Legacy.Gen.u1Present)
3350 {
3351 Log(("load sreg%d,%#x - segment not present -> #NP\n", iSegReg, uSel));
3352 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uSel);
3353 }
3354
3355 /* The base and limit. */
3356 uint32_t cbLimit = X86DESC_LIMIT_G(&Desc.Legacy);
3357 uint64_t u64Base;
3358 if ( pIemCpu->enmCpuMode == IEMMODE_64BIT
3359 && iSegReg < X86_SREG_FS)
3360 u64Base = 0;
3361 else
3362 u64Base = X86DESC_BASE(&Desc.Legacy);
3363
3364 /*
3365 * Ok, everything checked out fine. Now set the accessed bit before
3366 * committing the result into the registers.
3367 */
3368 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
3369 {
3370 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uSel);
3371 if (rcStrict != VINF_SUCCESS)
3372 return rcStrict;
3373 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
3374 }
3375
3376 /* commit */
3377 *pSel = uSel;
3378 pHid->Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
3379 pHid->u32Limit = cbLimit;
3380 pHid->u64Base = u64Base;
3381 pHid->ValidSel = uSel;
3382 pHid->fFlags = CPUMSELREG_FLAGS_VALID;
3383
3384 /** @todo check if the hidden bits are loaded correctly for 64-bit
3385 * mode. */
3386 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(IEMCPU_TO_VMCPU(pIemCpu), pHid));
3387
3388 CPUMSetChangedFlags(IEMCPU_TO_VMCPU(pIemCpu), CPUM_CHANGED_HIDDEN_SEL_REGS);
3389 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3390 return VINF_SUCCESS;
3391}
3392
3393
3394/**
3395 * Implements 'mov SReg, r/m'.
3396 *
3397 * @param iSegReg The segment register number (valid).
3398 * @param uSel The new selector value.
3399 */
3400IEM_CIMPL_DEF_2(iemCImpl_load_SReg, uint8_t, iSegReg, uint16_t, uSel)
3401{
3402 VBOXSTRICTRC rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
3403 if (rcStrict == VINF_SUCCESS)
3404 {
3405 if (iSegReg == X86_SREG_SS)
3406 {
3407 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3408 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
3409 }
3410 }
3411 return rcStrict;
3412}
3413
3414
3415/**
3416 * Implements 'pop SReg'.
3417 *
3418 * @param iSegReg The segment register number (valid).
3419 * @param enmEffOpSize The efficient operand size (valid).
3420 */
3421IEM_CIMPL_DEF_2(iemCImpl_pop_Sreg, uint8_t, iSegReg, IEMMODE, enmEffOpSize)
3422{
3423 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3424 VBOXSTRICTRC rcStrict;
3425
3426 /*
3427 * Read the selector off the stack and join paths with mov ss, reg.
3428 */
3429 RTUINT64U TmpRsp;
3430 TmpRsp.u = pCtx->rsp;
3431 switch (enmEffOpSize)
3432 {
3433 case IEMMODE_16BIT:
3434 {
3435 uint16_t uSel;
3436 rcStrict = iemMemStackPopU16Ex(pIemCpu, &uSel, &TmpRsp);
3437 if (rcStrict == VINF_SUCCESS)
3438 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
3439 break;
3440 }
3441
3442 case IEMMODE_32BIT:
3443 {
3444 uint32_t u32Value;
3445 rcStrict = iemMemStackPopU32Ex(pIemCpu, &u32Value, &TmpRsp);
3446 if (rcStrict == VINF_SUCCESS)
3447 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, (uint16_t)u32Value);
3448 break;
3449 }
3450
3451 case IEMMODE_64BIT:
3452 {
3453 uint64_t u64Value;
3454 rcStrict = iemMemStackPopU64Ex(pIemCpu, &u64Value, &TmpRsp);
3455 if (rcStrict == VINF_SUCCESS)
3456 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, (uint16_t)u64Value);
3457 break;
3458 }
3459 IEM_NOT_REACHED_DEFAULT_CASE_RET();
3460 }
3461
3462 /*
3463 * Commit the stack on success.
3464 */
3465 if (rcStrict == VINF_SUCCESS)
3466 {
3467 pCtx->rsp = TmpRsp.u;
3468 if (iSegReg == X86_SREG_SS)
3469 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
3470 }
3471 return rcStrict;
3472}
3473
3474
3475/**
3476 * Implements lgs, lfs, les, lds & lss.
3477 */
3478IEM_CIMPL_DEF_5(iemCImpl_load_SReg_Greg,
3479 uint16_t, uSel,
3480 uint64_t, offSeg,
3481 uint8_t, iSegReg,
3482 uint8_t, iGReg,
3483 IEMMODE, enmEffOpSize)
3484{
3485 /*PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);*/
3486 VBOXSTRICTRC rcStrict;
3487
3488 /*
3489 * Use iemCImpl_LoadSReg to do the tricky segment register loading.
3490 */
3491 /** @todo verify and test that mov, pop and lXs works the segment
3492 * register loading in the exact same way. */
3493 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
3494 if (rcStrict == VINF_SUCCESS)
3495 {
3496 switch (enmEffOpSize)
3497 {
3498 case IEMMODE_16BIT:
3499 *(uint16_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
3500 break;
3501 case IEMMODE_32BIT:
3502 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
3503 break;
3504 case IEMMODE_64BIT:
3505 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
3506 break;
3507 IEM_NOT_REACHED_DEFAULT_CASE_RET();
3508 }
3509 }
3510
3511 return rcStrict;
3512}
3513
3514
3515/**
3516 * Helper for VERR, VERW, LAR, and LSL and loads the descriptor into memory.
3517 *
3518 * @retval VINF_SUCCESS on success.
3519 * @retval VINF_IEM_SELECTOR_NOT_OK if the selector isn't ok.
3520 * @retval iemMemFetchSysU64 return value.
3521 *
3522 * @param pIemCpu The IEM state of the calling EMT.
3523 * @param uSel The selector value.
3524 * @param fAllowSysDesc Whether system descriptors are OK or not.
3525 * @param pDesc Where to return the descriptor on success.
3526 */
3527static VBOXSTRICTRC iemCImpl_LoadDescHelper(PIEMCPU pIemCpu, uint16_t uSel, bool fAllowSysDesc, PIEMSELDESC pDesc)
3528{
3529 pDesc->Long.au64[0] = 0;
3530 pDesc->Long.au64[1] = 0;
3531
3532 if (!(uSel & X86_SEL_MASK_OFF_RPL)) /** @todo test this on 64-bit. */
3533 return VINF_IEM_SELECTOR_NOT_OK;
3534
3535 /* Within the table limits? */
3536 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3537 RTGCPTR GCPtrBase;
3538 if (uSel & X86_SEL_LDT)
3539 {
3540 if ( !pCtx->ldtr.Attr.n.u1Present
3541 || (uSel | X86_SEL_RPL_LDT) > pCtx->ldtr.u32Limit )
3542 return VINF_IEM_SELECTOR_NOT_OK;
3543 GCPtrBase = pCtx->ldtr.u64Base;
3544 }
3545 else
3546 {
3547 if ((uSel | X86_SEL_RPL_LDT) > pCtx->gdtr.cbGdt)
3548 return VINF_IEM_SELECTOR_NOT_OK;
3549 GCPtrBase = pCtx->gdtr.pGdt;
3550 }
3551
3552 /* Fetch the descriptor. */
3553 VBOXSTRICTRC rcStrict = iemMemFetchSysU64(pIemCpu, &pDesc->Legacy.u, UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK));
3554 if (rcStrict != VINF_SUCCESS)
3555 return rcStrict;
3556 if (!pDesc->Legacy.Gen.u1DescType)
3557 {
3558 if (!fAllowSysDesc)
3559 return VINF_IEM_SELECTOR_NOT_OK;
3560 if (CPUMIsGuestInLongModeEx(pCtx))
3561 {
3562 rcStrict = iemMemFetchSysU64(pIemCpu, &pDesc->Long.au64[1], UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK) + 8);
3563 if (rcStrict != VINF_SUCCESS)
3564 return rcStrict;
3565 }
3566
3567 }
3568
3569 return VINF_SUCCESS;
3570}
3571
3572
3573/**
3574 * Implements verr (fWrite = false) and verw (fWrite = true).
3575 */
3576IEM_CIMPL_DEF_2(iemCImpl_VerX, uint16_t, uSel, bool, fWrite)
3577{
3578 Assert(!IEM_IS_REAL_OR_V86_MODE(pIemCpu));
3579
3580 /** @todo figure whether the accessed bit is set or not. */
3581
3582 bool fAccessible = true;
3583 IEMSELDESC Desc;
3584 VBOXSTRICTRC rcStrict = iemCImpl_LoadDescHelper(pIemCpu, uSel, false /*fAllowSysDesc*/, &Desc);
3585 if (rcStrict == VINF_SUCCESS)
3586 {
3587 /* Check the descriptor, order doesn't matter much here. */
3588 if ( !Desc.Legacy.Gen.u1DescType
3589 || !Desc.Legacy.Gen.u1Present)
3590 fAccessible = false;
3591 else
3592 {
3593 if ( fWrite
3594 ? (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE)) != X86_SEL_TYPE_WRITE
3595 : (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
3596 fAccessible = false;
3597
3598 /** @todo testcase for the conforming behavior. */
3599 if ( (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
3600 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
3601 {
3602 if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
3603 fAccessible = false;
3604 else if (pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
3605 fAccessible = false;
3606 }
3607 }
3608
3609 }
3610 else if (rcStrict == VINF_IEM_SELECTOR_NOT_OK)
3611 fAccessible = false;
3612 else
3613 return rcStrict;
3614
3615 /* commit */
3616 pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1ZF = fAccessible;
3617
3618 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3619 return VINF_SUCCESS;
3620}
3621
3622
3623/**
3624 * Implements LAR and LSL with 64-bit operand size.
3625 *
3626 * @returns VINF_SUCCESS.
3627 * @param pu16Dst Pointer to the destination register.
3628 * @param uSel The selector to load details for.
3629 * @param pEFlags Pointer to the eflags register.
3630 * @param fIsLar true = LAR, false = LSL.
3631 */
3632IEM_CIMPL_DEF_4(iemCImpl_LarLsl_u64, uint64_t *, pu64Dst, uint16_t, uSel, uint32_t *, pEFlags, bool, fIsLar)
3633{
3634 Assert(!IEM_IS_REAL_OR_V86_MODE(pIemCpu));
3635
3636 /** @todo figure whether the accessed bit is set or not. */
3637
3638 bool fDescOk = true;
3639 IEMSELDESC Desc;
3640 VBOXSTRICTRC rcStrict = iemCImpl_LoadDescHelper(pIemCpu, uSel, false /*fAllowSysDesc*/, &Desc);
3641 if (rcStrict == VINF_SUCCESS)
3642 {
3643 /*
3644 * Check the descriptor type.
3645 */
3646 if (!Desc.Legacy.Gen.u1DescType)
3647 {
3648 if (CPUMIsGuestInLongModeEx(pIemCpu->CTX_SUFF(pCtx)))
3649 {
3650 if (Desc.Long.Gen.u5Zeros)
3651 fDescOk = false;
3652 else
3653 switch (Desc.Long.Gen.u4Type)
3654 {
3655 /** @todo Intel lists 0 as valid for LSL, verify whether that's correct */
3656 case AMD64_SEL_TYPE_SYS_TSS_AVAIL:
3657 case AMD64_SEL_TYPE_SYS_TSS_BUSY:
3658 case AMD64_SEL_TYPE_SYS_LDT: /** @todo Intel lists this as invalid for LAR, AMD and 32-bit does otherwise. */
3659 break;
3660 case AMD64_SEL_TYPE_SYS_CALL_GATE:
3661 fDescOk = fIsLar;
3662 break;
3663 default:
3664 fDescOk = false;
3665 break;
3666 }
3667 }
3668 else
3669 {
3670 switch (Desc.Long.Gen.u4Type)
3671 {
3672 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
3673 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
3674 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
3675 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
3676 case X86_SEL_TYPE_SYS_LDT:
3677 break;
3678 case X86_SEL_TYPE_SYS_286_CALL_GATE:
3679 case X86_SEL_TYPE_SYS_TASK_GATE:
3680 case X86_SEL_TYPE_SYS_386_CALL_GATE:
3681 fDescOk = fIsLar;
3682 break;
3683 default:
3684 fDescOk = false;
3685 break;
3686 }
3687 }
3688 }
3689 if (fDescOk)
3690 {
3691 /*
3692 * Check the RPL/DPL/CPL interaction..
3693 */
3694 /** @todo testcase for the conforming behavior. */
3695 if ( (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF)) != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF)
3696 || !Desc.Legacy.Gen.u1DescType)
3697 {
3698 if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
3699 fDescOk = false;
3700 else if (pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
3701 fDescOk = false;
3702 }
3703 }
3704
3705 if (fDescOk)
3706 {
3707 /*
3708 * All fine, start committing the result.
3709 */
3710 if (fIsLar)
3711 *pu64Dst = Desc.Legacy.au32[1] & UINT32_C(0x00ffff00);
3712 else
3713 *pu64Dst = X86DESC_LIMIT_G(&Desc.Legacy);
3714 }
3715
3716 }
3717 else if (rcStrict == VINF_IEM_SELECTOR_NOT_OK)
3718 fDescOk = false;
3719 else
3720 return rcStrict;
3721
3722 /* commit flags value and advance rip. */
3723 pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1ZF = fDescOk;
3724 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3725
3726 return VINF_SUCCESS;
3727}
3728
3729
3730/**
3731 * Implements LAR and LSL with 16-bit operand size.
3732 *
3733 * @returns VINF_SUCCESS.
3734 * @param pu16Dst Pointer to the destination register.
3735 * @param u16Sel The selector to load details for.
3736 * @param pEFlags Pointer to the eflags register.
3737 * @param fIsLar true = LAR, false = LSL.
3738 */
3739IEM_CIMPL_DEF_4(iemCImpl_LarLsl_u16, uint16_t *, pu16Dst, uint16_t, uSel, uint32_t *, pEFlags, bool, fIsLar)
3740{
3741 uint64_t u64TmpDst = *pu16Dst;
3742 IEM_CIMPL_CALL_4(iemCImpl_LarLsl_u64, &u64TmpDst, uSel, pEFlags, fIsLar);
3743 *pu16Dst = (uint16_t)u64TmpDst;
3744 return VINF_SUCCESS;
3745}
3746
3747
3748/**
3749 * Implements lgdt.
3750 *
3751 * @param iEffSeg The segment of the new gdtr contents
3752 * @param GCPtrEffSrc The address of the new gdtr contents.
3753 * @param enmEffOpSize The effective operand size.
3754 */
3755IEM_CIMPL_DEF_3(iemCImpl_lgdt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc, IEMMODE, enmEffOpSize)
3756{
3757 if (pIemCpu->uCpl != 0)
3758 return iemRaiseGeneralProtectionFault0(pIemCpu);
3759 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
3760
3761 /*
3762 * Fetch the limit and base address.
3763 */
3764 uint16_t cbLimit;
3765 RTGCPTR GCPtrBase;
3766 VBOXSTRICTRC rcStrict = iemMemFetchDataXdtr(pIemCpu, &cbLimit, &GCPtrBase, iEffSeg, GCPtrEffSrc, enmEffOpSize);
3767 if (rcStrict == VINF_SUCCESS)
3768 {
3769 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
3770 rcStrict = CPUMSetGuestGDTR(IEMCPU_TO_VMCPU(pIemCpu), GCPtrBase, cbLimit);
3771 else
3772 {
3773 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3774 pCtx->gdtr.cbGdt = cbLimit;
3775 pCtx->gdtr.pGdt = GCPtrBase;
3776 }
3777 if (rcStrict == VINF_SUCCESS)
3778 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3779 }
3780 return rcStrict;
3781}
3782
3783
3784/**
3785 * Implements sgdt.
3786 *
3787 * @param iEffSeg The segment where to store the gdtr content.
3788 * @param GCPtrEffDst The address where to store the gdtr content.
3789 * @param enmEffOpSize The effective operand size.
3790 */
3791IEM_CIMPL_DEF_3(iemCImpl_sgdt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, IEMMODE, enmEffOpSize)
3792{
3793 /*
3794 * Join paths with sidt.
3795 * Note! No CPL or V8086 checks here, it's a really sad story, ask Intel if
3796 * you really must know.
3797 */
3798 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3799 VBOXSTRICTRC rcStrict = iemMemStoreDataXdtr(pIemCpu, pCtx->gdtr.cbGdt, pCtx->gdtr.pGdt, iEffSeg, GCPtrEffDst, enmEffOpSize);
3800 if (rcStrict == VINF_SUCCESS)
3801 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3802 return rcStrict;
3803}
3804
3805
3806/**
3807 * Implements lidt.
3808 *
3809 * @param iEffSeg The segment of the new idtr contents
3810 * @param GCPtrEffSrc The address of the new idtr contents.
3811 * @param enmEffOpSize The effective operand size.
3812 */
3813IEM_CIMPL_DEF_3(iemCImpl_lidt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc, IEMMODE, enmEffOpSize)
3814{
3815 if (pIemCpu->uCpl != 0)
3816 return iemRaiseGeneralProtectionFault0(pIemCpu);
3817 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
3818
3819 /*
3820 * Fetch the limit and base address.
3821 */
3822 uint16_t cbLimit;
3823 RTGCPTR GCPtrBase;
3824 VBOXSTRICTRC rcStrict = iemMemFetchDataXdtr(pIemCpu, &cbLimit, &GCPtrBase, iEffSeg, GCPtrEffSrc, enmEffOpSize);
3825 if (rcStrict == VINF_SUCCESS)
3826 {
3827 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
3828 CPUMSetGuestIDTR(IEMCPU_TO_VMCPU(pIemCpu), GCPtrBase, cbLimit);
3829 else
3830 {
3831 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3832 pCtx->idtr.cbIdt = cbLimit;
3833 pCtx->idtr.pIdt = GCPtrBase;
3834 }
3835 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3836 }
3837 return rcStrict;
3838}
3839
3840
3841/**
3842 * Implements sidt.
3843 *
3844 * @param iEffSeg The segment where to store the idtr content.
3845 * @param GCPtrEffDst The address where to store the idtr content.
3846 * @param enmEffOpSize The effective operand size.
3847 */
3848IEM_CIMPL_DEF_3(iemCImpl_sidt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst, IEMMODE, enmEffOpSize)
3849{
3850 /*
3851 * Join paths with sgdt.
3852 * Note! No CPL or V8086 checks here, it's a really sad story, ask Intel if
3853 * you really must know.
3854 */
3855 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3856 VBOXSTRICTRC rcStrict = iemMemStoreDataXdtr(pIemCpu, pCtx->idtr.cbIdt, pCtx->idtr.pIdt, iEffSeg, GCPtrEffDst, enmEffOpSize);
3857 if (rcStrict == VINF_SUCCESS)
3858 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3859 return rcStrict;
3860}
3861
3862
3863/**
3864 * Implements lldt.
3865 *
3866 * @param uNewLdt The new LDT selector value.
3867 */
3868IEM_CIMPL_DEF_1(iemCImpl_lldt, uint16_t, uNewLdt)
3869{
3870 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3871
3872 /*
3873 * Check preconditions.
3874 */
3875 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
3876 {
3877 Log(("lldt %04x - real or v8086 mode -> #GP(0)\n", uNewLdt));
3878 return iemRaiseUndefinedOpcode(pIemCpu);
3879 }
3880 if (pIemCpu->uCpl != 0)
3881 {
3882 Log(("lldt %04x - CPL is %d -> #GP(0)\n", uNewLdt, pIemCpu->uCpl));
3883 return iemRaiseGeneralProtectionFault0(pIemCpu);
3884 }
3885 if (uNewLdt & X86_SEL_LDT)
3886 {
3887 Log(("lldt %04x - LDT selector -> #GP\n", uNewLdt));
3888 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewLdt);
3889 }
3890
3891 /*
3892 * Now, loading a NULL selector is easy.
3893 */
3894 if (!(uNewLdt & X86_SEL_MASK_OFF_RPL))
3895 {
3896 Log(("lldt %04x: Loading NULL selector.\n", uNewLdt));
3897 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
3898 CPUMSetGuestLDTR(IEMCPU_TO_VMCPU(pIemCpu), uNewLdt);
3899 else
3900 pCtx->ldtr.Sel = uNewLdt;
3901 pCtx->ldtr.ValidSel = uNewLdt;
3902 pCtx->ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
3903 if (IEM_FULL_VERIFICATION_REM_ENABLED(pIemCpu))
3904 {
3905 pCtx->ldtr.Attr.u = X86DESCATTR_UNUSABLE;
3906 pCtx->ldtr.u64Base = pCtx->ldtr.u32Limit = 0; /* For verfication against REM. */
3907 }
3908 else if (IEM_IS_GUEST_CPU_AMD(pIemCpu))
3909 {
3910 /* AMD-V seems to leave the base and limit alone. */
3911 pCtx->ldtr.Attr.u = X86DESCATTR_UNUSABLE;
3912 }
3913 else if (!IEM_FULL_VERIFICATION_REM_ENABLED(pIemCpu))
3914 {
3915 /* VT-x (Intel 3960x) seems to be doing the following. */
3916 pCtx->ldtr.Attr.u = X86DESCATTR_UNUSABLE | X86DESCATTR_G | X86DESCATTR_D;
3917 pCtx->ldtr.u64Base = 0;
3918 pCtx->ldtr.u32Limit = UINT32_MAX;
3919 }
3920
3921 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3922 return VINF_SUCCESS;
3923 }
3924
3925 /*
3926 * Read the descriptor.
3927 */
3928 IEMSELDESC Desc;
3929 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uNewLdt, X86_XCPT_GP); /** @todo Correct exception? */
3930 if (rcStrict != VINF_SUCCESS)
3931 return rcStrict;
3932
3933 /* Check GPs first. */
3934 if (Desc.Legacy.Gen.u1DescType)
3935 {
3936 Log(("lldt %#x - not system selector (type %x) -> #GP\n", uNewLdt, Desc.Legacy.Gen.u4Type));
3937 return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
3938 }
3939 if (Desc.Legacy.Gen.u4Type != X86_SEL_TYPE_SYS_LDT)
3940 {
3941 Log(("lldt %#x - not LDT selector (type %x) -> #GP\n", uNewLdt, Desc.Legacy.Gen.u4Type));
3942 return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
3943 }
3944 uint64_t u64Base;
3945 if (!IEM_IS_LONG_MODE(pIemCpu))
3946 u64Base = X86DESC_BASE(&Desc.Legacy);
3947 else
3948 {
3949 if (Desc.Long.Gen.u5Zeros)
3950 {
3951 Log(("lldt %#x - u5Zeros=%#x -> #GP\n", uNewLdt, Desc.Long.Gen.u5Zeros));
3952 return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
3953 }
3954
3955 u64Base = X86DESC64_BASE(&Desc.Long);
3956 if (!IEM_IS_CANONICAL(u64Base))
3957 {
3958 Log(("lldt %#x - non-canonical base address %#llx -> #GP\n", uNewLdt, u64Base));
3959 return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & X86_SEL_MASK_OFF_RPL);
3960 }
3961 }
3962
3963 /* NP */
3964 if (!Desc.Legacy.Gen.u1Present)
3965 {
3966 Log(("lldt %#x - segment not present -> #NP\n", uNewLdt));
3967 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uNewLdt);
3968 }
3969
3970 /*
3971 * It checks out alright, update the registers.
3972 */
3973/** @todo check if the actual value is loaded or if the RPL is dropped */
3974 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
3975 CPUMSetGuestLDTR(IEMCPU_TO_VMCPU(pIemCpu), uNewLdt & X86_SEL_MASK_OFF_RPL);
3976 else
3977 pCtx->ldtr.Sel = uNewLdt & X86_SEL_MASK_OFF_RPL;
3978 pCtx->ldtr.ValidSel = uNewLdt & X86_SEL_MASK_OFF_RPL;
3979 pCtx->ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
3980 pCtx->ldtr.Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
3981 pCtx->ldtr.u32Limit = X86DESC_LIMIT_G(&Desc.Legacy);
3982 pCtx->ldtr.u64Base = u64Base;
3983
3984 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
3985 return VINF_SUCCESS;
3986}
3987
3988
3989/**
3990 * Implements lldt.
3991 *
3992 * @param uNewLdt The new LDT selector value.
3993 */
3994IEM_CIMPL_DEF_1(iemCImpl_ltr, uint16_t, uNewTr)
3995{
3996 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3997
3998 /*
3999 * Check preconditions.
4000 */
4001 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
4002 {
4003 Log(("ltr %04x - real or v8086 mode -> #GP(0)\n", uNewTr));
4004 return iemRaiseUndefinedOpcode(pIemCpu);
4005 }
4006 if (pIemCpu->uCpl != 0)
4007 {
4008 Log(("ltr %04x - CPL is %d -> #GP(0)\n", uNewTr, pIemCpu->uCpl));
4009 return iemRaiseGeneralProtectionFault0(pIemCpu);
4010 }
4011 if (uNewTr & X86_SEL_LDT)
4012 {
4013 Log(("ltr %04x - LDT selector -> #GP\n", uNewTr));
4014 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewTr);
4015 }
4016 if (!(uNewTr & X86_SEL_MASK_OFF_RPL))
4017 {
4018 Log(("ltr %04x - NULL selector -> #GP(0)\n", uNewTr));
4019 return iemRaiseGeneralProtectionFault0(pIemCpu);
4020 }
4021
4022 /*
4023 * Read the descriptor.
4024 */
4025 IEMSELDESC Desc;
4026 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uNewTr, X86_XCPT_GP); /** @todo Correct exception? */
4027 if (rcStrict != VINF_SUCCESS)
4028 return rcStrict;
4029
4030 /* Check GPs first. */
4031 if (Desc.Legacy.Gen.u1DescType)
4032 {
4033 Log(("ltr %#x - not system selector (type %x) -> #GP\n", uNewTr, Desc.Legacy.Gen.u4Type));
4034 return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
4035 }
4036 if ( Desc.Legacy.Gen.u4Type != X86_SEL_TYPE_SYS_386_TSS_AVAIL /* same as AMD64_SEL_TYPE_SYS_TSS_AVAIL */
4037 && ( Desc.Legacy.Gen.u4Type != X86_SEL_TYPE_SYS_286_TSS_AVAIL
4038 || IEM_IS_LONG_MODE(pIemCpu)) )
4039 {
4040 Log(("ltr %#x - not an available TSS selector (type %x) -> #GP\n", uNewTr, Desc.Legacy.Gen.u4Type));
4041 return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
4042 }
4043 uint64_t u64Base;
4044 if (!IEM_IS_LONG_MODE(pIemCpu))
4045 u64Base = X86DESC_BASE(&Desc.Legacy);
4046 else
4047 {
4048 if (Desc.Long.Gen.u5Zeros)
4049 {
4050 Log(("ltr %#x - u5Zeros=%#x -> #GP\n", uNewTr, Desc.Long.Gen.u5Zeros));
4051 return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
4052 }
4053
4054 u64Base = X86DESC64_BASE(&Desc.Long);
4055 if (!IEM_IS_CANONICAL(u64Base))
4056 {
4057 Log(("ltr %#x - non-canonical base address %#llx -> #GP\n", uNewTr, u64Base));
4058 return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & X86_SEL_MASK_OFF_RPL);
4059 }
4060 }
4061
4062 /* NP */
4063 if (!Desc.Legacy.Gen.u1Present)
4064 {
4065 Log(("ltr %#x - segment not present -> #NP\n", uNewTr));
4066 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uNewTr);
4067 }
4068
4069 /*
4070 * Set it busy.
4071 * Note! Intel says this should lock down the whole descriptor, but we'll
4072 * restrict our selves to 32-bit for now due to lack of inline
4073 * assembly and such.
4074 */
4075 void *pvDesc;
4076 rcStrict = iemMemMap(pIemCpu, &pvDesc, 8, UINT8_MAX, pCtx->gdtr.pGdt + (uNewTr & X86_SEL_MASK_OFF_RPL), IEM_ACCESS_DATA_RW);
4077 if (rcStrict != VINF_SUCCESS)
4078 return rcStrict;
4079 switch ((uintptr_t)pvDesc & 3)
4080 {
4081 case 0: ASMAtomicBitSet(pvDesc, 40 + 1); break;
4082 case 1: ASMAtomicBitSet((uint8_t *)pvDesc + 3, 40 + 1 - 24); break;
4083 case 2: ASMAtomicBitSet((uint8_t *)pvDesc + 2, 40 + 1 - 16); break;
4084 case 3: ASMAtomicBitSet((uint8_t *)pvDesc + 1, 40 + 1 - 8); break;
4085 }
4086 rcStrict = iemMemCommitAndUnmap(pIemCpu, pvDesc, IEM_ACCESS_DATA_RW);
4087 if (rcStrict != VINF_SUCCESS)
4088 return rcStrict;
4089 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_SYS_TSS_BUSY_MASK;
4090
4091 /*
4092 * It checks out alright, update the registers.
4093 */
4094/** @todo check if the actual value is loaded or if the RPL is dropped */
4095 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4096 CPUMSetGuestTR(IEMCPU_TO_VMCPU(pIemCpu), uNewTr & X86_SEL_MASK_OFF_RPL);
4097 else
4098 pCtx->tr.Sel = uNewTr & X86_SEL_MASK_OFF_RPL;
4099 pCtx->tr.ValidSel = uNewTr & X86_SEL_MASK_OFF_RPL;
4100 pCtx->tr.fFlags = CPUMSELREG_FLAGS_VALID;
4101 pCtx->tr.Attr.u = X86DESC_GET_HID_ATTR(&Desc.Legacy);
4102 pCtx->tr.u32Limit = X86DESC_LIMIT_G(&Desc.Legacy);
4103 pCtx->tr.u64Base = u64Base;
4104
4105 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4106 return VINF_SUCCESS;
4107}
4108
4109
4110/**
4111 * Implements mov GReg,CRx.
4112 *
4113 * @param iGReg The general register to store the CRx value in.
4114 * @param iCrReg The CRx register to read (valid).
4115 */
4116IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Cd, uint8_t, iGReg, uint8_t, iCrReg)
4117{
4118 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4119 if (pIemCpu->uCpl != 0)
4120 return iemRaiseGeneralProtectionFault0(pIemCpu);
4121 Assert(!pCtx->eflags.Bits.u1VM);
4122
4123 /* read it */
4124 uint64_t crX;
4125 switch (iCrReg)
4126 {
4127 case 0: crX = pCtx->cr0; break;
4128 case 2: crX = pCtx->cr2; break;
4129 case 3: crX = pCtx->cr3; break;
4130 case 4: crX = pCtx->cr4; break;
4131 case 8:
4132 {
4133 uint8_t uTpr;
4134 int rc = PDMApicGetTPR(IEMCPU_TO_VMCPU(pIemCpu), &uTpr, NULL, NULL);
4135 if (RT_SUCCESS(rc))
4136 crX = uTpr >> 4;
4137 else
4138 crX = 0;
4139 break;
4140 }
4141 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
4142 }
4143
4144 /* store it */
4145 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
4146 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = crX;
4147 else
4148 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = (uint32_t)crX;
4149
4150 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4151 return VINF_SUCCESS;
4152}
4153
4154
4155/**
4156 * Used to implemented 'mov CRx,GReg' and 'lmsw r/m16'.
4157 *
4158 * @param iCrReg The CRx register to write (valid).
4159 * @param uNewCrX The new value.
4160 */
4161IEM_CIMPL_DEF_2(iemCImpl_load_CrX, uint8_t, iCrReg, uint64_t, uNewCrX)
4162{
4163 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4164 PVMCPU pVCpu = IEMCPU_TO_VMCPU(pIemCpu);
4165 VBOXSTRICTRC rcStrict;
4166 int rc;
4167
4168 /*
4169 * Try store it.
4170 * Unfortunately, CPUM only does a tiny bit of the work.
4171 */
4172 switch (iCrReg)
4173 {
4174 case 0:
4175 {
4176 /*
4177 * Perform checks.
4178 */
4179 uint64_t const uOldCrX = pCtx->cr0;
4180 uNewCrX |= X86_CR0_ET; /* hardcoded */
4181
4182 /* Check for reserved bits. */
4183 uint32_t const fValid = X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS
4184 | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM
4185 | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG;
4186 if (uNewCrX & ~(uint64_t)fValid)
4187 {
4188 Log(("Trying to set reserved CR0 bits: NewCR0=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
4189 return iemRaiseGeneralProtectionFault0(pIemCpu);
4190 }
4191
4192 /* Check for invalid combinations. */
4193 if ( (uNewCrX & X86_CR0_PG)
4194 && !(uNewCrX & X86_CR0_PE) )
4195 {
4196 Log(("Trying to set CR0.PG without CR0.PE\n"));
4197 return iemRaiseGeneralProtectionFault0(pIemCpu);
4198 }
4199
4200 if ( !(uNewCrX & X86_CR0_CD)
4201 && (uNewCrX & X86_CR0_NW) )
4202 {
4203 Log(("Trying to clear CR0.CD while leaving CR0.NW set\n"));
4204 return iemRaiseGeneralProtectionFault0(pIemCpu);
4205 }
4206
4207 /* Long mode consistency checks. */
4208 if ( (uNewCrX & X86_CR0_PG)
4209 && !(uOldCrX & X86_CR0_PG)
4210 && (pCtx->msrEFER & MSR_K6_EFER_LME) )
4211 {
4212 if (!(pCtx->cr4 & X86_CR4_PAE))
4213 {
4214 Log(("Trying to enabled long mode paging without CR4.PAE set\n"));
4215 return iemRaiseGeneralProtectionFault0(pIemCpu);
4216 }
4217 if (pCtx->cs.Attr.n.u1Long)
4218 {
4219 Log(("Trying to enabled long mode paging with a long CS descriptor loaded.\n"));
4220 return iemRaiseGeneralProtectionFault0(pIemCpu);
4221 }
4222 }
4223
4224 /** @todo check reserved PDPTR bits as AMD states. */
4225
4226 /*
4227 * Change CR0.
4228 */
4229 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4230 CPUMSetGuestCR0(pVCpu, uNewCrX);
4231 else
4232 pCtx->cr0 = uNewCrX;
4233 Assert(pCtx->cr0 == uNewCrX);
4234
4235 /*
4236 * Change EFER.LMA if entering or leaving long mode.
4237 */
4238 if ( (uNewCrX & X86_CR0_PG) != (uOldCrX & X86_CR0_PG)
4239 && (pCtx->msrEFER & MSR_K6_EFER_LME) )
4240 {
4241 uint64_t NewEFER = pCtx->msrEFER;
4242 if (uNewCrX & X86_CR0_PG)
4243 NewEFER |= MSR_K6_EFER_LMA;
4244 else
4245 NewEFER &= ~MSR_K6_EFER_LMA;
4246
4247 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4248 CPUMSetGuestEFER(pVCpu, NewEFER);
4249 else
4250 pCtx->msrEFER = NewEFER;
4251 Assert(pCtx->msrEFER == NewEFER);
4252 }
4253
4254 /*
4255 * Inform PGM.
4256 */
4257 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4258 {
4259 if ( (uNewCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
4260 != (uOldCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) )
4261 {
4262 rc = PGMFlushTLB(pVCpu, pCtx->cr3, true /* global */);
4263 AssertRCReturn(rc, rc);
4264 /* ignore informational status codes */
4265 }
4266 rcStrict = PGMChangeMode(pVCpu, pCtx->cr0, pCtx->cr4, pCtx->msrEFER);
4267 }
4268 else
4269 rcStrict = VINF_SUCCESS;
4270
4271#ifdef IN_RC
4272 /* Return to ring-3 for rescheduling if WP or AM changes. */
4273 if ( rcStrict == VINF_SUCCESS
4274 && ( (uNewCrX & (X86_CR0_WP | X86_CR0_AM))
4275 != (uOldCrX & (X86_CR0_WP | X86_CR0_AM))) )
4276 rcStrict = VINF_EM_RESCHEDULE;
4277#endif
4278 break;
4279 }
4280
4281 /*
4282 * CR2 can be changed without any restrictions.
4283 */
4284 case 2:
4285 pCtx->cr2 = uNewCrX;
4286 rcStrict = VINF_SUCCESS;
4287 break;
4288
4289 /*
4290 * CR3 is relatively simple, although AMD and Intel have different
4291 * accounts of how setting reserved bits are handled. We take intel's
4292 * word for the lower bits and AMD's for the high bits (63:52).
4293 */
4294 /** @todo Testcase: Setting reserved bits in CR3, especially before
4295 * enabling paging. */
4296 case 3:
4297 {
4298 /* check / mask the value. */
4299 if (uNewCrX & UINT64_C(0xfff0000000000000))
4300 {
4301 Log(("Trying to load CR3 with invalid high bits set: %#llx\n", uNewCrX));
4302 return iemRaiseGeneralProtectionFault0(pIemCpu);
4303 }
4304
4305 uint64_t fValid;
4306 if ( (pCtx->cr4 & X86_CR4_PAE)
4307 && (pCtx->msrEFER & MSR_K6_EFER_LME))
4308 fValid = UINT64_C(0x000ffffffffff014);
4309 else if (pCtx->cr4 & X86_CR4_PAE)
4310 fValid = UINT64_C(0xfffffff4);
4311 else
4312 fValid = UINT64_C(0xfffff014);
4313 if (uNewCrX & ~fValid)
4314 {
4315 Log(("Automatically clearing reserved bits in CR3 load: NewCR3=%#llx ClearedBits=%#llx\n",
4316 uNewCrX, uNewCrX & ~fValid));
4317 uNewCrX &= fValid;
4318 }
4319
4320 /** @todo If we're in PAE mode we should check the PDPTRs for
4321 * invalid bits. */
4322
4323 /* Make the change. */
4324 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4325 {
4326 rc = CPUMSetGuestCR3(pVCpu, uNewCrX);
4327 AssertRCSuccessReturn(rc, rc);
4328 }
4329 else
4330 pCtx->cr3 = uNewCrX;
4331
4332 /* Inform PGM. */
4333 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4334 {
4335 if (pCtx->cr0 & X86_CR0_PG)
4336 {
4337 rc = PGMFlushTLB(pVCpu, pCtx->cr3, !(pCtx->cr4 & X86_CR4_PGE));
4338 AssertRCReturn(rc, rc);
4339 /* ignore informational status codes */
4340 }
4341 }
4342 rcStrict = VINF_SUCCESS;
4343 break;
4344 }
4345
4346 /*
4347 * CR4 is a bit more tedious as there are bits which cannot be cleared
4348 * under some circumstances and such.
4349 */
4350 case 4:
4351 {
4352 uint64_t const uOldCrX = pCtx->cr4;
4353
4354 /** @todo Shouldn't this look at the guest CPUID bits to determine
4355 * valid bits? e.g. if guest CPUID doesn't allow X86_CR4_OSXMMEEXCPT, we
4356 * should #GP(0). */
4357 /* reserved bits */
4358 uint32_t fValid = X86_CR4_VME | X86_CR4_PVI
4359 | X86_CR4_TSD | X86_CR4_DE
4360 | X86_CR4_PSE | X86_CR4_PAE
4361 | X86_CR4_MCE | X86_CR4_PGE
4362 | X86_CR4_PCE | X86_CR4_OSFSXR
4363 | X86_CR4_OSXMMEEXCPT;
4364 //if (xxx)
4365 // fValid |= X86_CR4_VMXE;
4366 //if (xxx)
4367 // fValid |= X86_CR4_OSXSAVE;
4368 if (uNewCrX & ~(uint64_t)fValid)
4369 {
4370 Log(("Trying to set reserved CR4 bits: NewCR4=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
4371 return iemRaiseGeneralProtectionFault0(pIemCpu);
4372 }
4373
4374 /* long mode checks. */
4375 if ( (uOldCrX & X86_CR4_PAE)
4376 && !(uNewCrX & X86_CR4_PAE)
4377 && CPUMIsGuestInLongModeEx(pCtx) )
4378 {
4379 Log(("Trying to set clear CR4.PAE while long mode is active\n"));
4380 return iemRaiseGeneralProtectionFault0(pIemCpu);
4381 }
4382
4383
4384 /*
4385 * Change it.
4386 */
4387 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4388 {
4389 rc = CPUMSetGuestCR4(pVCpu, uNewCrX);
4390 AssertRCSuccessReturn(rc, rc);
4391 }
4392 else
4393 pCtx->cr4 = uNewCrX;
4394 Assert(pCtx->cr4 == uNewCrX);
4395
4396 /*
4397 * Notify SELM and PGM.
4398 */
4399 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4400 {
4401 /* SELM - VME may change things wrt to the TSS shadowing. */
4402 if ((uNewCrX ^ uOldCrX) & X86_CR4_VME)
4403 {
4404 Log(("iemCImpl_load_CrX: VME %d -> %d => Setting VMCPU_FF_SELM_SYNC_TSS\n",
4405 RT_BOOL(uOldCrX & X86_CR4_VME), RT_BOOL(uNewCrX & X86_CR4_VME) ));
4406#ifdef VBOX_WITH_RAW_MODE
4407 if (!HMIsEnabled(IEMCPU_TO_VM(pIemCpu)))
4408 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);
4409#endif
4410 }
4411
4412 /* PGM - flushing and mode. */
4413 if ((uNewCrX ^ uOldCrX) & (X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE))
4414 {
4415 rc = PGMFlushTLB(pVCpu, pCtx->cr3, true /* global */);
4416 AssertRCReturn(rc, rc);
4417 /* ignore informational status codes */
4418 }
4419 rcStrict = PGMChangeMode(pVCpu, pCtx->cr0, pCtx->cr4, pCtx->msrEFER);
4420 }
4421 else
4422 rcStrict = VINF_SUCCESS;
4423 break;
4424 }
4425
4426 /*
4427 * CR8 maps to the APIC TPR.
4428 */
4429 case 8:
4430 if (uNewCrX & ~(uint64_t)0xf)
4431 {
4432 Log(("Trying to set reserved CR8 bits (%#RX64)\n", uNewCrX));
4433 return iemRaiseGeneralProtectionFault0(pIemCpu);
4434 }
4435
4436 if (!IEM_FULL_VERIFICATION_ENABLED(pIemCpu))
4437 PDMApicSetTPR(IEMCPU_TO_VMCPU(pIemCpu), (uint8_t)uNewCrX << 4);
4438 rcStrict = VINF_SUCCESS;
4439 break;
4440
4441 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
4442 }
4443
4444 /*
4445 * Advance the RIP on success.
4446 */
4447 if (RT_SUCCESS(rcStrict))
4448 {
4449 if (rcStrict != VINF_SUCCESS)
4450 rcStrict = iemSetPassUpStatus(pIemCpu, rcStrict);
4451 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4452 }
4453
4454 return rcStrict;
4455}
4456
4457
4458/**
4459 * Implements mov CRx,GReg.
4460 *
4461 * @param iCrReg The CRx register to write (valid).
4462 * @param iGReg The general register to load the DRx value from.
4463 */
4464IEM_CIMPL_DEF_2(iemCImpl_mov_Cd_Rd, uint8_t, iCrReg, uint8_t, iGReg)
4465{
4466 if (pIemCpu->uCpl != 0)
4467 return iemRaiseGeneralProtectionFault0(pIemCpu);
4468 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
4469
4470 /*
4471 * Read the new value from the source register and call common worker.
4472 */
4473 uint64_t uNewCrX;
4474 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
4475 uNewCrX = iemGRegFetchU64(pIemCpu, iGReg);
4476 else
4477 uNewCrX = iemGRegFetchU32(pIemCpu, iGReg);
4478 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, iCrReg, uNewCrX);
4479}
4480
4481
4482/**
4483 * Implements 'LMSW r/m16'
4484 *
4485 * @param u16NewMsw The new value.
4486 */
4487IEM_CIMPL_DEF_1(iemCImpl_lmsw, uint16_t, u16NewMsw)
4488{
4489 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4490
4491 if (pIemCpu->uCpl != 0)
4492 return iemRaiseGeneralProtectionFault0(pIemCpu);
4493 Assert(!pCtx->eflags.Bits.u1VM);
4494
4495 /*
4496 * Compose the new CR0 value and call common worker.
4497 */
4498 uint64_t uNewCr0 = pCtx->cr0 & ~(X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
4499 uNewCr0 |= u16NewMsw & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
4500 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, /*cr*/ 0, uNewCr0);
4501}
4502
4503
4504/**
4505 * Implements 'CLTS'.
4506 */
4507IEM_CIMPL_DEF_0(iemCImpl_clts)
4508{
4509 if (pIemCpu->uCpl != 0)
4510 return iemRaiseGeneralProtectionFault0(pIemCpu);
4511
4512 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4513 uint64_t uNewCr0 = pCtx->cr0;
4514 uNewCr0 &= ~X86_CR0_TS;
4515 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, /*cr*/ 0, uNewCr0);
4516}
4517
4518
4519/**
4520 * Implements mov GReg,DRx.
4521 *
4522 * @param iGReg The general register to store the DRx value in.
4523 * @param iDrReg The DRx register to read (0-7).
4524 */
4525IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Dd, uint8_t, iGReg, uint8_t, iDrReg)
4526{
4527 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4528
4529 /*
4530 * Check preconditions.
4531 */
4532
4533 /* Raise GPs. */
4534 if (pIemCpu->uCpl != 0)
4535 return iemRaiseGeneralProtectionFault0(pIemCpu);
4536 Assert(!pCtx->eflags.Bits.u1VM);
4537
4538 if ( (iDrReg == 4 || iDrReg == 5)
4539 && (pCtx->cr4 & X86_CR4_DE) )
4540 {
4541 Log(("mov r%u,dr%u: CR4.DE=1 -> #GP(0)\n", iGReg, iDrReg));
4542 return iemRaiseGeneralProtectionFault0(pIemCpu);
4543 }
4544
4545 /* Raise #DB if general access detect is enabled. */
4546 if (pCtx->dr[7] & X86_DR7_GD)
4547 {
4548 Log(("mov r%u,dr%u: DR7.GD=1 -> #DB\n", iGReg, iDrReg));
4549 return iemRaiseDebugException(pIemCpu);
4550 }
4551
4552 /*
4553 * Read the debug register and store it in the specified general register.
4554 */
4555 uint64_t drX;
4556 switch (iDrReg)
4557 {
4558 case 0: drX = pCtx->dr[0]; break;
4559 case 1: drX = pCtx->dr[1]; break;
4560 case 2: drX = pCtx->dr[2]; break;
4561 case 3: drX = pCtx->dr[3]; break;
4562 case 6:
4563 case 4:
4564 drX = pCtx->dr[6];
4565 drX |= X86_DR6_RA1_MASK;
4566 drX &= ~X86_DR6_RAZ_MASK;
4567 break;
4568 case 7:
4569 case 5:
4570 drX = pCtx->dr[7];
4571 drX |=X86_DR7_RA1_MASK;
4572 drX &= ~X86_DR7_RAZ_MASK;
4573 break;
4574 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
4575 }
4576
4577 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
4578 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = drX;
4579 else
4580 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = (uint32_t)drX;
4581
4582 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4583 return VINF_SUCCESS;
4584}
4585
4586
4587/**
4588 * Implements mov DRx,GReg.
4589 *
4590 * @param iDrReg The DRx register to write (valid).
4591 * @param iGReg The general register to load the DRx value from.
4592 */
4593IEM_CIMPL_DEF_2(iemCImpl_mov_Dd_Rd, uint8_t, iDrReg, uint8_t, iGReg)
4594{
4595 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4596
4597 /*
4598 * Check preconditions.
4599 */
4600 if (pIemCpu->uCpl != 0)
4601 return iemRaiseGeneralProtectionFault0(pIemCpu);
4602 Assert(!pCtx->eflags.Bits.u1VM);
4603
4604 if (iDrReg == 4 || iDrReg == 5)
4605 {
4606 if (pCtx->cr4 & X86_CR4_DE)
4607 {
4608 Log(("mov dr%u,r%u: CR4.DE=1 -> #GP(0)\n", iDrReg, iGReg));
4609 return iemRaiseGeneralProtectionFault0(pIemCpu);
4610 }
4611 iDrReg += 2;
4612 }
4613
4614 /* Raise #DB if general access detect is enabled. */
4615 /** @todo is \#DB/DR7.GD raised before any reserved high bits in DR7/DR6
4616 * \#GP? */
4617 if (pCtx->dr[7] & X86_DR7_GD)
4618 {
4619 Log(("mov dr%u,r%u: DR7.GD=1 -> #DB\n", iDrReg, iGReg));
4620 return iemRaiseDebugException(pIemCpu);
4621 }
4622
4623 /*
4624 * Read the new value from the source register.
4625 */
4626 uint64_t uNewDrX;
4627 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
4628 uNewDrX = iemGRegFetchU64(pIemCpu, iGReg);
4629 else
4630 uNewDrX = iemGRegFetchU32(pIemCpu, iGReg);
4631
4632 /*
4633 * Adjust it.
4634 */
4635 switch (iDrReg)
4636 {
4637 case 0:
4638 case 1:
4639 case 2:
4640 case 3:
4641 /* nothing to adjust */
4642 break;
4643
4644 case 6:
4645 if (uNewDrX & X86_DR6_MBZ_MASK)
4646 {
4647 Log(("mov dr%u,%#llx: DR6 high bits are not zero -> #GP(0)\n", iDrReg, uNewDrX));
4648 return iemRaiseGeneralProtectionFault0(pIemCpu);
4649 }
4650 uNewDrX |= X86_DR6_RA1_MASK;
4651 uNewDrX &= ~X86_DR6_RAZ_MASK;
4652 break;
4653
4654 case 7:
4655 if (uNewDrX & X86_DR7_MBZ_MASK)
4656 {
4657 Log(("mov dr%u,%#llx: DR7 high bits are not zero -> #GP(0)\n", iDrReg, uNewDrX));
4658 return iemRaiseGeneralProtectionFault0(pIemCpu);
4659 }
4660 uNewDrX |= X86_DR7_RA1_MASK;
4661 uNewDrX &= ~X86_DR7_RAZ_MASK;
4662 break;
4663
4664 IEM_NOT_REACHED_DEFAULT_CASE_RET();
4665 }
4666
4667 /*
4668 * Do the actual setting.
4669 */
4670 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4671 {
4672 int rc = CPUMSetGuestDRx(IEMCPU_TO_VMCPU(pIemCpu), iDrReg, uNewDrX);
4673 AssertRCSuccessReturn(rc, RT_SUCCESS_NP(rc) ? VERR_INTERNAL_ERROR : rc);
4674 }
4675 else
4676 pCtx->dr[iDrReg] = uNewDrX;
4677
4678 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4679 return VINF_SUCCESS;
4680}
4681
4682
4683/**
4684 * Implements 'INVLPG m'.
4685 *
4686 * @param GCPtrPage The effective address of the page to invalidate.
4687 * @remarks Updates the RIP.
4688 */
4689IEM_CIMPL_DEF_1(iemCImpl_invlpg, uint8_t, GCPtrPage)
4690{
4691 /* ring-0 only. */
4692 if (pIemCpu->uCpl != 0)
4693 return iemRaiseGeneralProtectionFault0(pIemCpu);
4694 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
4695
4696 int rc = PGMInvalidatePage(IEMCPU_TO_VMCPU(pIemCpu), GCPtrPage);
4697 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4698
4699 if (rc == VINF_SUCCESS)
4700 return VINF_SUCCESS;
4701 if (rc == VINF_PGM_SYNC_CR3)
4702 return iemSetPassUpStatus(pIemCpu, rc);
4703
4704 AssertMsg(rc == VINF_EM_RAW_EMULATE_INSTR || RT_FAILURE_NP(rc), ("%Rrc\n", rc));
4705 Log(("PGMInvalidatePage(%RGv) -> %Rrc\n", rc));
4706 return rc;
4707}
4708
4709
4710/**
4711 * Implements RDTSC.
4712 */
4713IEM_CIMPL_DEF_0(iemCImpl_rdtsc)
4714{
4715 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4716
4717 /*
4718 * Check preconditions.
4719 */
4720 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_EDX(X86_CPUID_FEATURE_EDX_TSC))
4721 return iemRaiseUndefinedOpcode(pIemCpu);
4722
4723 if ( (pCtx->cr4 & X86_CR4_TSD)
4724 && pIemCpu->uCpl != 0)
4725 {
4726 Log(("rdtsc: CR4.TSD and CPL=%u -> #GP(0)\n", pIemCpu->uCpl));
4727 return iemRaiseGeneralProtectionFault0(pIemCpu);
4728 }
4729
4730 /*
4731 * Do the job.
4732 */
4733 uint64_t uTicks = TMCpuTickGet(IEMCPU_TO_VMCPU(pIemCpu));
4734 pCtx->rax = (uint32_t)uTicks;
4735 pCtx->rdx = uTicks >> 32;
4736#ifdef IEM_VERIFICATION_MODE_FULL
4737 pIemCpu->fIgnoreRaxRdx = true;
4738#endif
4739
4740 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4741 return VINF_SUCCESS;
4742}
4743
4744
4745/**
4746 * Implements RDMSR.
4747 */
4748IEM_CIMPL_DEF_0(iemCImpl_rdmsr)
4749{
4750 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4751
4752 /*
4753 * Check preconditions.
4754 */
4755 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_EDX(X86_CPUID_FEATURE_EDX_MSR))
4756 return iemRaiseUndefinedOpcode(pIemCpu);
4757 if (pIemCpu->uCpl != 0)
4758 return iemRaiseGeneralProtectionFault0(pIemCpu);
4759
4760 /*
4761 * Do the job.
4762 */
4763 RTUINT64U uValue;
4764 int rc = CPUMQueryGuestMsr(IEMCPU_TO_VMCPU(pIemCpu), pCtx->ecx, &uValue.u);
4765 if (rc != VINF_SUCCESS)
4766 {
4767#ifdef IN_RING3
4768 static uint32_t s_cTimes = 0;
4769 if (s_cTimes++ < 10)
4770 LogRel(("IEM: rdmsr(%#x) -> GP(0)\n", pCtx->ecx));
4771#endif
4772 Log(("IEM: rdmsr(%#x) -> GP(0)\n", pCtx->ecx));
4773 AssertMsgReturn(rc == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", rc), VERR_IPE_UNEXPECTED_STATUS);
4774 return iemRaiseGeneralProtectionFault0(pIemCpu);
4775 }
4776
4777 pCtx->rax = uValue.s.Lo;
4778 pCtx->rdx = uValue.s.Hi;
4779
4780 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4781 return VINF_SUCCESS;
4782}
4783
4784
4785/**
4786 * Implements WRMSR.
4787 */
4788IEM_CIMPL_DEF_0(iemCImpl_wrmsr)
4789{
4790 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4791
4792 /*
4793 * Check preconditions.
4794 */
4795 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_EDX(X86_CPUID_FEATURE_EDX_MSR))
4796 return iemRaiseUndefinedOpcode(pIemCpu);
4797 if (pIemCpu->uCpl != 0)
4798 return iemRaiseGeneralProtectionFault0(pIemCpu);
4799
4800 /*
4801 * Do the job.
4802 */
4803 RTUINT64U uValue;
4804 uValue.s.Lo = pCtx->eax;
4805 uValue.s.Hi = pCtx->edx;
4806
4807 int rc;
4808 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4809 rc = CPUMSetGuestMsr(IEMCPU_TO_VMCPU(pIemCpu), pCtx->ecx, uValue.u);
4810 else
4811 {
4812 CPUMCTX CtxTmp = *pCtx;
4813 rc = CPUMSetGuestMsr(IEMCPU_TO_VMCPU(pIemCpu), pCtx->ecx, uValue.u);
4814 PCPUMCTX pCtx2 = CPUMQueryGuestCtxPtr(IEMCPU_TO_VMCPU(pIemCpu));
4815 *pCtx = *pCtx2;
4816 *pCtx2 = CtxTmp;
4817 }
4818 if (rc != VINF_SUCCESS)
4819 {
4820#ifdef IN_RING3
4821 static uint32_t s_cTimes = 0;
4822 if (s_cTimes++ < 10)
4823 LogRel(("IEM: wrmsr(%#x,%#x`%08x) -> GP(0)\n", pCtx->ecx, uValue.s.Hi, uValue.s.Lo));
4824#endif
4825 Log(("IEM: wrmsr(%#x,%#x`%08x) -> GP(0)\n", pCtx->ecx, uValue.s.Hi, uValue.s.Lo));
4826 AssertMsgReturn(rc == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", rc), VERR_IPE_UNEXPECTED_STATUS);
4827 return iemRaiseGeneralProtectionFault0(pIemCpu);
4828 }
4829
4830 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4831 return VINF_SUCCESS;
4832}
4833
4834
4835/**
4836 * Implements 'IN eAX, port'.
4837 *
4838 * @param u16Port The source port.
4839 * @param cbReg The register size.
4840 */
4841IEM_CIMPL_DEF_2(iemCImpl_in, uint16_t, u16Port, uint8_t, cbReg)
4842{
4843 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4844
4845 /*
4846 * CPL check
4847 */
4848 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pIemCpu, pCtx, u16Port, cbReg);
4849 if (rcStrict != VINF_SUCCESS)
4850 return rcStrict;
4851
4852 /*
4853 * Perform the I/O.
4854 */
4855 uint32_t u32Value;
4856 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4857 rcStrict = IOMIOPortRead(IEMCPU_TO_VM(pIemCpu), IEMCPU_TO_VMCPU(pIemCpu), u16Port, &u32Value, cbReg);
4858 else
4859 rcStrict = iemVerifyFakeIOPortRead(pIemCpu, u16Port, &u32Value, cbReg);
4860 if (IOM_SUCCESS(rcStrict))
4861 {
4862 switch (cbReg)
4863 {
4864 case 1: pCtx->al = (uint8_t)u32Value; break;
4865 case 2: pCtx->ax = (uint16_t)u32Value; break;
4866 case 4: pCtx->rax = u32Value; break;
4867 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
4868 }
4869 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4870 pIemCpu->cPotentialExits++;
4871 if (rcStrict != VINF_SUCCESS)
4872 rcStrict = iemSetPassUpStatus(pIemCpu, rcStrict);
4873 Assert(rcStrict == VINF_SUCCESS); /* assumed below */
4874
4875 /*
4876 * Check for I/O breakpoints.
4877 */
4878 uint32_t const uDr7 = pCtx->dr[7];
4879 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
4880 && X86_DR7_ANY_RW_IO(uDr7)
4881 && (pCtx->cr4 & X86_CR4_DE))
4882 || DBGFBpIsHwIoArmed(IEMCPU_TO_VM(pIemCpu))))
4883 {
4884 rcStrict = DBGFBpCheckIo(IEMCPU_TO_VM(pIemCpu), IEMCPU_TO_VMCPU(pIemCpu), pCtx, u16Port, cbReg);
4885 if (rcStrict == VINF_EM_RAW_GUEST_TRAP)
4886 rcStrict = iemRaiseDebugException(pIemCpu);
4887 }
4888 }
4889
4890 return rcStrict;
4891}
4892
4893
4894/**
4895 * Implements 'IN eAX, DX'.
4896 *
4897 * @param cbReg The register size.
4898 */
4899IEM_CIMPL_DEF_1(iemCImpl_in_eAX_DX, uint8_t, cbReg)
4900{
4901 return IEM_CIMPL_CALL_2(iemCImpl_in, pIemCpu->CTX_SUFF(pCtx)->dx, cbReg);
4902}
4903
4904
4905/**
4906 * Implements 'OUT port, eAX'.
4907 *
4908 * @param u16Port The destination port.
4909 * @param cbReg The register size.
4910 */
4911IEM_CIMPL_DEF_2(iemCImpl_out, uint16_t, u16Port, uint8_t, cbReg)
4912{
4913 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4914
4915 /*
4916 * CPL check
4917 */
4918 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pIemCpu, pCtx, u16Port, cbReg);
4919 if (rcStrict != VINF_SUCCESS)
4920 return rcStrict;
4921
4922 /*
4923 * Perform the I/O.
4924 */
4925 uint32_t u32Value;
4926 switch (cbReg)
4927 {
4928 case 1: u32Value = pCtx->al; break;
4929 case 2: u32Value = pCtx->ax; break;
4930 case 4: u32Value = pCtx->eax; break;
4931 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
4932 }
4933 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
4934 rcStrict = IOMIOPortWrite(IEMCPU_TO_VM(pIemCpu), IEMCPU_TO_VMCPU(pIemCpu), u16Port, u32Value, cbReg);
4935 else
4936 rcStrict = iemVerifyFakeIOPortWrite(pIemCpu, u16Port, u32Value, cbReg);
4937 if (IOM_SUCCESS(rcStrict))
4938 {
4939 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
4940 pIemCpu->cPotentialExits++;
4941 if (rcStrict != VINF_SUCCESS)
4942 rcStrict = iemSetPassUpStatus(pIemCpu, rcStrict);
4943 Assert(rcStrict == VINF_SUCCESS); /* assumed below */
4944
4945 /*
4946 * Check for I/O breakpoints.
4947 */
4948 uint32_t const uDr7 = pCtx->dr[7];
4949 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
4950 && X86_DR7_ANY_RW_IO(uDr7)
4951 && (pCtx->cr4 & X86_CR4_DE))
4952 || DBGFBpIsHwIoArmed(IEMCPU_TO_VM(pIemCpu))))
4953 {
4954 rcStrict = DBGFBpCheckIo(IEMCPU_TO_VM(pIemCpu), IEMCPU_TO_VMCPU(pIemCpu), pCtx, u16Port, cbReg);
4955 if (rcStrict == VINF_EM_RAW_GUEST_TRAP)
4956 rcStrict = iemRaiseDebugException(pIemCpu);
4957 }
4958 }
4959 return rcStrict;
4960}
4961
4962
4963/**
4964 * Implements 'OUT DX, eAX'.
4965 *
4966 * @param cbReg The register size.
4967 */
4968IEM_CIMPL_DEF_1(iemCImpl_out_DX_eAX, uint8_t, cbReg)
4969{
4970 return IEM_CIMPL_CALL_2(iemCImpl_out, pIemCpu->CTX_SUFF(pCtx)->dx, cbReg);
4971}
4972
4973
4974/**
4975 * Implements 'CLI'.
4976 */
4977IEM_CIMPL_DEF_0(iemCImpl_cli)
4978{
4979 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4980 uint32_t fEfl = IEMMISC_GET_EFL(pIemCpu, pCtx);
4981 uint32_t const fEflOld = fEfl;
4982 if (pCtx->cr0 & X86_CR0_PE)
4983 {
4984 uint8_t const uIopl = X86_EFL_GET_IOPL(fEfl);
4985 if (!(fEfl & X86_EFL_VM))
4986 {
4987 if (pIemCpu->uCpl <= uIopl)
4988 fEfl &= ~X86_EFL_IF;
4989 else if ( pIemCpu->uCpl == 3
4990 && (pCtx->cr4 & X86_CR4_PVI) )
4991 fEfl &= ~X86_EFL_VIF;
4992 else
4993 return iemRaiseGeneralProtectionFault0(pIemCpu);
4994 }
4995 /* V8086 */
4996 else if (uIopl == 3)
4997 fEfl &= ~X86_EFL_IF;
4998 else if ( uIopl < 3
4999 && (pCtx->cr4 & X86_CR4_VME) )
5000 fEfl &= ~X86_EFL_VIF;
5001 else
5002 return iemRaiseGeneralProtectionFault0(pIemCpu);
5003 }
5004 /* real mode */
5005 else
5006 fEfl &= ~X86_EFL_IF;
5007
5008 /* Commit. */
5009 IEMMISC_SET_EFL(pIemCpu, pCtx, fEfl);
5010 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5011 Log2(("CLI: %#x -> %#x\n", fEflOld, fEfl)); NOREF(fEflOld);
5012 return VINF_SUCCESS;
5013}
5014
5015
5016/**
5017 * Implements 'STI'.
5018 */
5019IEM_CIMPL_DEF_0(iemCImpl_sti)
5020{
5021 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5022 uint32_t fEfl = IEMMISC_GET_EFL(pIemCpu, pCtx);
5023 uint32_t const fEflOld = fEfl;
5024
5025 if (pCtx->cr0 & X86_CR0_PE)
5026 {
5027 uint8_t const uIopl = X86_EFL_GET_IOPL(fEfl);
5028 if (!(fEfl & X86_EFL_VM))
5029 {
5030 if (pIemCpu->uCpl <= uIopl)
5031 fEfl |= X86_EFL_IF;
5032 else if ( pIemCpu->uCpl == 3
5033 && (pCtx->cr4 & X86_CR4_PVI)
5034 && !(fEfl & X86_EFL_VIP) )
5035 fEfl |= X86_EFL_VIF;
5036 else
5037 return iemRaiseGeneralProtectionFault0(pIemCpu);
5038 }
5039 /* V8086 */
5040 else if (uIopl == 3)
5041 fEfl |= X86_EFL_IF;
5042 else if ( uIopl < 3
5043 && (pCtx->cr4 & X86_CR4_VME)
5044 && !(fEfl & X86_EFL_VIP) )
5045 fEfl |= X86_EFL_VIF;
5046 else
5047 return iemRaiseGeneralProtectionFault0(pIemCpu);
5048 }
5049 /* real mode */
5050 else
5051 fEfl |= X86_EFL_IF;
5052
5053 /* Commit. */
5054 IEMMISC_SET_EFL(pIemCpu, pCtx, fEfl);
5055 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5056 if ((!(fEflOld & X86_EFL_IF) && (fEfl & X86_EFL_IF)) || IEM_FULL_VERIFICATION_REM_ENABLED(pIemCpu))
5057 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
5058 Log2(("STI: %#x -> %#x\n", fEflOld, fEfl));
5059 return VINF_SUCCESS;
5060}
5061
5062
5063/**
5064 * Implements 'HLT'.
5065 */
5066IEM_CIMPL_DEF_0(iemCImpl_hlt)
5067{
5068 if (pIemCpu->uCpl != 0)
5069 return iemRaiseGeneralProtectionFault0(pIemCpu);
5070 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5071 return VINF_EM_HALT;
5072}
5073
5074
5075/**
5076 * Implements 'MONITOR'.
5077 */
5078IEM_CIMPL_DEF_1(iemCImpl_monitor, uint8_t, iEffSeg)
5079{
5080 /*
5081 * Permission checks.
5082 */
5083 if (pIemCpu->uCpl != 0)
5084 {
5085 Log2(("monitor: CPL != 0\n"));
5086 return iemRaiseUndefinedOpcode(pIemCpu); /** @todo MSR[0xC0010015].MonMwaitUserEn if we care. */
5087 }
5088 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_ECX(X86_CPUID_FEATURE_ECX_MONITOR))
5089 {
5090 Log2(("monitor: Not in CPUID\n"));
5091 return iemRaiseUndefinedOpcode(pIemCpu);
5092 }
5093
5094 /*
5095 * Gather the operands and validate them.
5096 */
5097 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5098 RTGCPTR GCPtrMem = pIemCpu->enmCpuMode == IEMMODE_64BIT ? pCtx->rax : pCtx->eax;
5099 uint32_t uEcx = pCtx->ecx;
5100 uint32_t uEdx = pCtx->edx;
5101/** @todo Test whether EAX or ECX is processed first, i.e. do we get \#PF or
5102 * \#GP first. */
5103 if (uEcx != 0)
5104 {
5105 Log2(("monitor rax=%RX64, ecx=%RX32, edx=%RX32; ECX != 0 -> #GP(0)\n", GCPtrMem, uEcx, uEdx));
5106 return iemRaiseGeneralProtectionFault0(pIemCpu);
5107 }
5108
5109 VBOXSTRICTRC rcStrict = iemMemApplySegment(pIemCpu, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, iEffSeg, 1, &GCPtrMem);
5110 if (rcStrict != VINF_SUCCESS)
5111 return rcStrict;
5112
5113 RTGCPHYS GCPhysMem;
5114 rcStrict = iemMemPageTranslateAndCheckAccess(pIemCpu, GCPtrMem, IEM_ACCESS_TYPE_READ | IEM_ACCESS_WHAT_DATA, &GCPhysMem);
5115 if (rcStrict != VINF_SUCCESS)
5116 return rcStrict;
5117
5118 /*
5119 * Call EM to prepare the monitor/wait.
5120 */
5121 rcStrict = EMMonitorWaitPrepare(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rax, pCtx->rcx, pCtx->rdx, GCPhysMem);
5122 Assert(rcStrict == VINF_SUCCESS);
5123
5124 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5125 return rcStrict;
5126}
5127
5128
5129/**
5130 * Implements 'MWAIT'.
5131 */
5132IEM_CIMPL_DEF_0(iemCImpl_mwait)
5133{
5134 /*
5135 * Permission checks.
5136 */
5137 if (pIemCpu->uCpl != 0)
5138 {
5139 Log2(("mwait: CPL != 0\n"));
5140 /** @todo MSR[0xC0010015].MonMwaitUserEn if we care. (Remember to check
5141 * EFLAGS.VM then.) */
5142 return iemRaiseUndefinedOpcode(pIemCpu);
5143 }
5144 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_ECX(X86_CPUID_FEATURE_ECX_MONITOR))
5145 {
5146 Log2(("mwait: Not in CPUID\n"));
5147 return iemRaiseUndefinedOpcode(pIemCpu);
5148 }
5149
5150 /*
5151 * Gather the operands and validate them.
5152 */
5153 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5154 uint32_t uEax = pCtx->eax;
5155 uint32_t uEcx = pCtx->ecx;
5156 if (uEcx != 0)
5157 {
5158 /* Only supported extension is break on IRQ when IF=0. */
5159 if (uEcx > 1)
5160 {
5161 Log2(("mwait eax=%RX32, ecx=%RX32; ECX > 1 -> #GP(0)\n", uEax, uEcx));
5162 return iemRaiseGeneralProtectionFault0(pIemCpu);
5163 }
5164 uint32_t fMWaitFeatures = 0;
5165 uint32_t uIgnore = 0;
5166 CPUMGetGuestCpuId(IEMCPU_TO_VMCPU(pIemCpu), 5, &uIgnore, &uIgnore, &fMWaitFeatures, &uIgnore);
5167 if ( (fMWaitFeatures & (X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
5168 != (X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
5169 {
5170 Log2(("mwait eax=%RX32, ecx=%RX32; break-on-IRQ-IF=0 extension not enabled -> #GP(0)\n", uEax, uEcx));
5171 return iemRaiseGeneralProtectionFault0(pIemCpu);
5172 }
5173 }
5174
5175 /*
5176 * Call EM to prepare the monitor/wait.
5177 */
5178 VBOXSTRICTRC rcStrict = EMMonitorWaitPerform(IEMCPU_TO_VMCPU(pIemCpu), uEax, uEcx);
5179
5180 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5181 return rcStrict;
5182}
5183
5184
5185/**
5186 * Implements 'SWAPGS'.
5187 */
5188IEM_CIMPL_DEF_0(iemCImpl_swapgs)
5189{
5190 Assert(pIemCpu->enmCpuMode == IEMMODE_64BIT); /* Caller checks this. */
5191
5192 /*
5193 * Permission checks.
5194 */
5195 if (pIemCpu->uCpl != 0)
5196 {
5197 Log2(("swapgs: CPL != 0\n"));
5198 return iemRaiseUndefinedOpcode(pIemCpu);
5199 }
5200
5201 /*
5202 * Do the job.
5203 */
5204 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5205 uint64_t uOtherGsBase = pCtx->msrKERNELGSBASE;
5206 pCtx->msrKERNELGSBASE = pCtx->gs.u64Base;
5207 pCtx->gs.u64Base = uOtherGsBase;
5208
5209 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5210 return VINF_SUCCESS;
5211}
5212
5213
5214/**
5215 * Implements 'CPUID'.
5216 */
5217IEM_CIMPL_DEF_0(iemCImpl_cpuid)
5218{
5219 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5220
5221 CPUMGetGuestCpuId(IEMCPU_TO_VMCPU(pIemCpu), pCtx->eax, &pCtx->eax, &pCtx->ebx, &pCtx->ecx, &pCtx->edx);
5222 pCtx->rax &= UINT32_C(0xffffffff);
5223 pCtx->rbx &= UINT32_C(0xffffffff);
5224 pCtx->rcx &= UINT32_C(0xffffffff);
5225 pCtx->rdx &= UINT32_C(0xffffffff);
5226
5227 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5228 return VINF_SUCCESS;
5229}
5230
5231
5232/**
5233 * Implements 'AAD'.
5234 *
5235 * @param bImm The immediate operand.
5236 */
5237IEM_CIMPL_DEF_1(iemCImpl_aad, uint8_t, bImm)
5238{
5239 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5240
5241 uint16_t const ax = pCtx->ax;
5242 uint8_t const al = (uint8_t)ax + (uint8_t)(ax >> 8) * bImm;
5243 pCtx->ax = al;
5244 iemHlpUpdateArithEFlagsU8(pIemCpu, al,
5245 X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF,
5246 X86_EFL_OF | X86_EFL_AF | X86_EFL_CF);
5247
5248 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5249 return VINF_SUCCESS;
5250}
5251
5252
5253/**
5254 * Implements 'AAM'.
5255 *
5256 * @param bImm The immediate operand. Cannot be 0.
5257 */
5258IEM_CIMPL_DEF_1(iemCImpl_aam, uint8_t, bImm)
5259{
5260 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5261 Assert(bImm != 0); /* #DE on 0 is handled in the decoder. */
5262
5263 uint16_t const ax = pCtx->ax;
5264 uint8_t const al = (uint8_t)ax % bImm;
5265 uint8_t const ah = (uint8_t)ax / bImm;
5266 pCtx->ax = (ah << 8) + al;
5267 iemHlpUpdateArithEFlagsU8(pIemCpu, al,
5268 X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF,
5269 X86_EFL_OF | X86_EFL_AF | X86_EFL_CF);
5270
5271 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5272 return VINF_SUCCESS;
5273}
5274
5275
5276/**
5277 * Implements 'DAA'.
5278 */
5279IEM_CIMPL_DEF_0(iemCImpl_daa)
5280{
5281 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5282
5283 uint8_t const al = pCtx->al;
5284 bool const fCarry = pCtx->eflags.Bits.u1CF;
5285
5286 if ( pCtx->eflags.Bits.u1AF
5287 || (al & 0xf) >= 10)
5288 {
5289 pCtx->al = al + 6;
5290 pCtx->eflags.Bits.u1AF = 1;
5291 }
5292 else
5293 pCtx->eflags.Bits.u1AF = 0;
5294
5295 if (al >= 0x9a || fCarry)
5296 {
5297 pCtx->al += 0x60;
5298 pCtx->eflags.Bits.u1CF = 1;
5299 }
5300 else
5301 pCtx->eflags.Bits.u1CF = 0;
5302
5303 iemHlpUpdateArithEFlagsU8(pIemCpu, pCtx->al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
5304 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5305 return VINF_SUCCESS;
5306}
5307
5308
5309/**
5310 * Implements 'DAS'.
5311 */
5312IEM_CIMPL_DEF_0(iemCImpl_das)
5313{
5314 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5315
5316 uint8_t const uInputAL = pCtx->al;
5317 bool const fCarry = pCtx->eflags.Bits.u1CF;
5318
5319 if ( pCtx->eflags.Bits.u1AF
5320 || (uInputAL & 0xf) >= 10)
5321 {
5322 pCtx->eflags.Bits.u1AF = 1;
5323 if (uInputAL < 6)
5324 pCtx->eflags.Bits.u1CF = 1;
5325 pCtx->al = uInputAL - 6;
5326 }
5327 else
5328 {
5329 pCtx->eflags.Bits.u1AF = 0;
5330 pCtx->eflags.Bits.u1CF = 0;
5331 }
5332
5333 if (uInputAL >= 0x9a || fCarry)
5334 {
5335 pCtx->al -= 0x60;
5336 pCtx->eflags.Bits.u1CF = 1;
5337 }
5338
5339 iemHlpUpdateArithEFlagsU8(pIemCpu, pCtx->al, X86_EFL_SF | X86_EFL_ZF | X86_EFL_PF, X86_EFL_OF);
5340 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5341 return VINF_SUCCESS;
5342}
5343
5344
5345
5346
5347/*
5348 * Instantiate the various string operation combinations.
5349 */
5350#define OP_SIZE 8
5351#define ADDR_SIZE 16
5352#include "IEMAllCImplStrInstr.cpp.h"
5353#define OP_SIZE 8
5354#define ADDR_SIZE 32
5355#include "IEMAllCImplStrInstr.cpp.h"
5356#define OP_SIZE 8
5357#define ADDR_SIZE 64
5358#include "IEMAllCImplStrInstr.cpp.h"
5359
5360#define OP_SIZE 16
5361#define ADDR_SIZE 16
5362#include "IEMAllCImplStrInstr.cpp.h"
5363#define OP_SIZE 16
5364#define ADDR_SIZE 32
5365#include "IEMAllCImplStrInstr.cpp.h"
5366#define OP_SIZE 16
5367#define ADDR_SIZE 64
5368#include "IEMAllCImplStrInstr.cpp.h"
5369
5370#define OP_SIZE 32
5371#define ADDR_SIZE 16
5372#include "IEMAllCImplStrInstr.cpp.h"
5373#define OP_SIZE 32
5374#define ADDR_SIZE 32
5375#include "IEMAllCImplStrInstr.cpp.h"
5376#define OP_SIZE 32
5377#define ADDR_SIZE 64
5378#include "IEMAllCImplStrInstr.cpp.h"
5379
5380#define OP_SIZE 64
5381#define ADDR_SIZE 32
5382#include "IEMAllCImplStrInstr.cpp.h"
5383#define OP_SIZE 64
5384#define ADDR_SIZE 64
5385#include "IEMAllCImplStrInstr.cpp.h"
5386
5387
5388/**
5389 * Implements 'FINIT' and 'FNINIT'.
5390 *
5391 * @param fCheckXcpts Whether to check for umasked pending exceptions or
5392 * not.
5393 */
5394IEM_CIMPL_DEF_1(iemCImpl_finit, bool, fCheckXcpts)
5395{
5396 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5397
5398 if (pCtx->cr0 & (X86_CR0_EM | X86_CR0_TS))
5399 return iemRaiseDeviceNotAvailable(pIemCpu);
5400
5401 NOREF(fCheckXcpts); /** @todo trigger pending exceptions:
5402 if (fCheckXcpts && TODO )
5403 return iemRaiseMathFault(pIemCpu);
5404 */
5405
5406 if (iemFRegIsFxSaveFormat(pIemCpu))
5407 {
5408 pCtx->fpu.FCW = 0x37f;
5409 pCtx->fpu.FSW = 0;
5410 pCtx->fpu.FTW = 0x00; /* 0 - empty. */
5411 pCtx->fpu.FPUDP = 0;
5412 pCtx->fpu.DS = 0; //??
5413 pCtx->fpu.Rsrvd2= 0;
5414 pCtx->fpu.FPUIP = 0;
5415 pCtx->fpu.CS = 0; //??
5416 pCtx->fpu.Rsrvd1= 0;
5417 pCtx->fpu.FOP = 0;
5418 }
5419 else
5420 {
5421 PX86FPUSTATE pFpu = (PX86FPUSTATE)&pCtx->fpu;
5422 pFpu->FCW = 0x37f;
5423 pFpu->FSW = 0;
5424 pFpu->FTW = 0xffff; /* 11 - empty */
5425 pFpu->FPUOO = 0; //??
5426 pFpu->FPUOS = 0; //??
5427 pFpu->FPUIP = 0;
5428 pFpu->CS = 0; //??
5429 pFpu->FOP = 0;
5430 }
5431
5432 iemHlpUsedFpu(pIemCpu);
5433 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5434 return VINF_SUCCESS;
5435}
5436
5437
5438/**
5439 * Implements 'FXSAVE'.
5440 *
5441 * @param iEffSeg The effective segment.
5442 * @param GCPtrEff The address of the image.
5443 * @param enmEffOpSize The operand size (only REX.W really matters).
5444 */
5445IEM_CIMPL_DEF_3(iemCImpl_fxsave, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
5446{
5447 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5448
5449 /*
5450 * Raise exceptions.
5451 */
5452 if (pCtx->cr0 & X86_CR0_EM)
5453 return iemRaiseUndefinedOpcode(pIemCpu);
5454 if (pCtx->cr0 & (X86_CR0_TS | X86_CR0_EM))
5455 return iemRaiseDeviceNotAvailable(pIemCpu);
5456 if (GCPtrEff & 15)
5457 {
5458 /** @todo CPU/VM detection possible! \#AC might not be signal for
5459 * all/any misalignment sizes, intel says its an implementation detail. */
5460 if ( (pCtx->cr0 & X86_CR0_AM)
5461 && pCtx->eflags.Bits.u1AC
5462 && pIemCpu->uCpl == 3)
5463 return iemRaiseAlignmentCheckException(pIemCpu);
5464 return iemRaiseGeneralProtectionFault0(pIemCpu);
5465 }
5466 AssertReturn(iemFRegIsFxSaveFormat(pIemCpu), VERR_IEM_IPE_2);
5467
5468 /*
5469 * Access the memory.
5470 */
5471 void *pvMem512;
5472 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, &pvMem512, 512, iEffSeg, GCPtrEff, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5473 if (rcStrict != VINF_SUCCESS)
5474 return rcStrict;
5475 PX86FXSTATE pDst = (PX86FXSTATE)pvMem512;
5476
5477 /*
5478 * Store the registers.
5479 */
5480 /** @todo CPU/VM detection possible! If CR4.OSFXSR=0 MXCSR it's
5481 * implementation specific whether MXCSR and XMM0-XMM7 are saved. */
5482
5483 /* common for all formats */
5484 pDst->FCW = pCtx->fpu.FCW;
5485 pDst->FSW = pCtx->fpu.FSW;
5486 pDst->FTW = pCtx->fpu.FTW & UINT16_C(0xff);
5487 pDst->FOP = pCtx->fpu.FOP;
5488 pDst->MXCSR = pCtx->fpu.MXCSR;
5489 pDst->MXCSR_MASK = pCtx->fpu.MXCSR_MASK;
5490 for (uint32_t i = 0; i < RT_ELEMENTS(pDst->aRegs); i++)
5491 {
5492 /** @todo Testcase: What actually happens to the 6 reserved bytes? I'm clearing
5493 * them for now... */
5494 pDst->aRegs[i].au32[0] = pCtx->fpu.aRegs[i].au32[0];
5495 pDst->aRegs[i].au32[1] = pCtx->fpu.aRegs[i].au32[1];
5496 pDst->aRegs[i].au32[2] = pCtx->fpu.aRegs[i].au32[2] & UINT32_C(0xffff);
5497 pDst->aRegs[i].au32[3] = 0;
5498 }
5499
5500 /* FPU IP, CS, DP and DS. */
5501 /** @todo FPU IP, CS, DP and DS cannot be implemented correctly without extra
5502 * state information. :-/
5503 * Storing zeros now to prevent any potential leakage of host info. */
5504 pDst->FPUIP = 0;
5505 pDst->CS = 0;
5506 pDst->Rsrvd1 = 0;
5507 pDst->FPUDP = 0;
5508 pDst->DS = 0;
5509 pDst->Rsrvd2 = 0;
5510
5511 /* XMM registers. */
5512 if ( !(pCtx->msrEFER & MSR_K6_EFER_FFXSR)
5513 || pIemCpu->enmCpuMode != IEMMODE_64BIT
5514 || pIemCpu->uCpl != 0)
5515 {
5516 uint32_t cXmmRegs = enmEffOpSize == IEMMODE_64BIT ? 16 : 8;
5517 for (uint32_t i = 0; i < cXmmRegs; i++)
5518 pDst->aXMM[i] = pCtx->fpu.aXMM[i];
5519 /** @todo Testcase: What happens to the reserved XMM registers? Untouched,
5520 * right? */
5521 }
5522
5523 /*
5524 * Commit the memory.
5525 */
5526 rcStrict = iemMemCommitAndUnmap(pIemCpu, pvMem512, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5527 if (rcStrict != VINF_SUCCESS)
5528 return rcStrict;
5529
5530 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5531 return VINF_SUCCESS;
5532}
5533
5534
5535/**
5536 * Implements 'FXRSTOR'.
5537 *
5538 * @param GCPtrEff The address of the image.
5539 * @param enmEffOpSize The operand size (only REX.W really matters).
5540 */
5541IEM_CIMPL_DEF_3(iemCImpl_fxrstor, uint8_t, iEffSeg, RTGCPTR, GCPtrEff, IEMMODE, enmEffOpSize)
5542{
5543 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5544
5545 /*
5546 * Raise exceptions.
5547 */
5548 if (pCtx->cr0 & X86_CR0_EM)
5549 return iemRaiseUndefinedOpcode(pIemCpu);
5550 if (pCtx->cr0 & (X86_CR0_TS | X86_CR0_EM))
5551 return iemRaiseDeviceNotAvailable(pIemCpu);
5552 if (GCPtrEff & 15)
5553 {
5554 /** @todo CPU/VM detection possible! \#AC might not be signal for
5555 * all/any misalignment sizes, intel says its an implementation detail. */
5556 if ( (pCtx->cr0 & X86_CR0_AM)
5557 && pCtx->eflags.Bits.u1AC
5558 && pIemCpu->uCpl == 3)
5559 return iemRaiseAlignmentCheckException(pIemCpu);
5560 return iemRaiseGeneralProtectionFault0(pIemCpu);
5561 }
5562 AssertReturn(iemFRegIsFxSaveFormat(pIemCpu), VERR_IEM_IPE_2);
5563
5564 /*
5565 * Access the memory.
5566 */
5567 void *pvMem512;
5568 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, &pvMem512, 512, iEffSeg, GCPtrEff, IEM_ACCESS_DATA_R);
5569 if (rcStrict != VINF_SUCCESS)
5570 return rcStrict;
5571 PCX86FXSTATE pSrc = (PCX86FXSTATE)pvMem512;
5572
5573 /*
5574 * Check the state for stuff which will GP(0).
5575 */
5576 uint32_t const fMXCSR = pSrc->MXCSR;
5577 uint32_t const fMXCSR_MASK = pCtx->fpu.MXCSR_MASK ? pCtx->fpu.MXCSR_MASK : UINT32_C(0xffbf);
5578 if (fMXCSR & ~fMXCSR_MASK)
5579 {
5580 Log(("fxrstor: MXCSR=%#x (MXCSR_MASK=%#x) -> #GP(0)\n", fMXCSR, fMXCSR_MASK));
5581 return iemRaiseGeneralProtectionFault0(pIemCpu);
5582 }
5583
5584 /*
5585 * Load the registers.
5586 */
5587 /** @todo CPU/VM detection possible! If CR4.OSFXSR=0 MXCSR it's
5588 * implementation specific whether MXCSR and XMM0-XMM7 are restored. */
5589
5590 /* common for all formats */
5591 pCtx->fpu.FCW = pSrc->FCW;
5592 pCtx->fpu.FSW = pSrc->FSW;
5593 pCtx->fpu.FTW = pSrc->FTW & UINT16_C(0xff);
5594 pCtx->fpu.FOP = pSrc->FOP;
5595 pCtx->fpu.MXCSR = fMXCSR;
5596 /* (MXCSR_MASK is read-only) */
5597 for (uint32_t i = 0; i < RT_ELEMENTS(pSrc->aRegs); i++)
5598 {
5599 pCtx->fpu.aRegs[i].au32[0] = pSrc->aRegs[i].au32[0];
5600 pCtx->fpu.aRegs[i].au32[1] = pSrc->aRegs[i].au32[1];
5601 pCtx->fpu.aRegs[i].au32[2] = pSrc->aRegs[i].au32[2] & UINT32_C(0xffff);
5602 pCtx->fpu.aRegs[i].au32[3] = 0;
5603 }
5604
5605 /* FPU IP, CS, DP and DS. */
5606 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
5607 {
5608 pCtx->fpu.FPUIP = pSrc->FPUIP;
5609 pCtx->fpu.CS = pSrc->CS;
5610 pCtx->fpu.Rsrvd1 = pSrc->Rsrvd1;
5611 pCtx->fpu.FPUDP = pSrc->FPUDP;
5612 pCtx->fpu.DS = pSrc->DS;
5613 pCtx->fpu.Rsrvd2 = pSrc->Rsrvd2;
5614 }
5615 else
5616 {
5617 pCtx->fpu.FPUIP = pSrc->FPUIP;
5618 pCtx->fpu.CS = pSrc->CS;
5619 pCtx->fpu.Rsrvd1 = 0;
5620 pCtx->fpu.FPUDP = pSrc->FPUDP;
5621 pCtx->fpu.DS = pSrc->DS;
5622 pCtx->fpu.Rsrvd2 = 0;
5623 }
5624
5625 /* XMM registers. */
5626 if ( !(pCtx->msrEFER & MSR_K6_EFER_FFXSR)
5627 || pIemCpu->enmCpuMode != IEMMODE_64BIT
5628 || pIemCpu->uCpl != 0)
5629 {
5630 uint32_t cXmmRegs = enmEffOpSize == IEMMODE_64BIT ? 16 : 8;
5631 for (uint32_t i = 0; i < cXmmRegs; i++)
5632 pCtx->fpu.aXMM[i] = pSrc->aXMM[i];
5633 }
5634
5635 /*
5636 * Commit the memory.
5637 */
5638 rcStrict = iemMemCommitAndUnmap(pIemCpu, pvMem512, IEM_ACCESS_DATA_R);
5639 if (rcStrict != VINF_SUCCESS)
5640 return rcStrict;
5641
5642 iemHlpUsedFpu(pIemCpu);
5643 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5644 return VINF_SUCCESS;
5645}
5646
5647
5648/**
5649 * Commmon routine for fnstenv and fnsave.
5650 *
5651 * @param uPtr Where to store the state.
5652 * @param pCtx The CPU context.
5653 */
5654static void iemCImplCommonFpuStoreEnv(PIEMCPU pIemCpu, IEMMODE enmEffOpSize, RTPTRUNION uPtr, PCCPUMCTX pCtx)
5655{
5656 if (enmEffOpSize == IEMMODE_16BIT)
5657 {
5658 uPtr.pu16[0] = pCtx->fpu.FCW;
5659 uPtr.pu16[1] = pCtx->fpu.FSW;
5660 uPtr.pu16[2] = iemFpuCalcFullFtw(pCtx);
5661 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
5662 {
5663 /** @todo Testcase: How does this work when the FPUIP/CS was saved in
5664 * protected mode or long mode and we save it in real mode? And vice
5665 * versa? And with 32-bit operand size? I think CPU is storing the
5666 * effective address ((CS << 4) + IP) in the offset register and not
5667 * doing any address calculations here. */
5668 uPtr.pu16[3] = (uint16_t)pCtx->fpu.FPUIP;
5669 uPtr.pu16[4] = ((pCtx->fpu.FPUIP >> 4) & UINT16_C(0xf000)) | pCtx->fpu.FOP;
5670 uPtr.pu16[5] = (uint16_t)pCtx->fpu.FPUDP;
5671 uPtr.pu16[6] = (pCtx->fpu.FPUDP >> 4) & UINT16_C(0xf000);
5672 }
5673 else
5674 {
5675 uPtr.pu16[3] = pCtx->fpu.FPUIP;
5676 uPtr.pu16[4] = pCtx->fpu.CS;
5677 uPtr.pu16[5] = pCtx->fpu.FPUDP;
5678 uPtr.pu16[6] = pCtx->fpu.DS;
5679 }
5680 }
5681 else
5682 {
5683 /** @todo Testcase: what is stored in the "gray" areas? (figure 8-9 and 8-10) */
5684 uPtr.pu16[0*2] = pCtx->fpu.FCW;
5685 uPtr.pu16[1*2] = pCtx->fpu.FSW;
5686 uPtr.pu16[2*2] = iemFpuCalcFullFtw(pCtx);
5687 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
5688 {
5689 uPtr.pu16[3*2] = (uint16_t)pCtx->fpu.FPUIP;
5690 uPtr.pu32[4] = ((pCtx->fpu.FPUIP & UINT32_C(0xffff0000)) >> 4) | pCtx->fpu.FOP;
5691 uPtr.pu16[5*2] = (uint16_t)pCtx->fpu.FPUDP;
5692 uPtr.pu32[6] = (pCtx->fpu.FPUDP & UINT32_C(0xffff0000)) >> 4;
5693 }
5694 else
5695 {
5696 uPtr.pu32[3] = pCtx->fpu.FPUIP;
5697 uPtr.pu16[4*2] = pCtx->fpu.CS;
5698 uPtr.pu16[4*2+1]= pCtx->fpu.FOP;
5699 uPtr.pu32[5] = pCtx->fpu.FPUDP;
5700 uPtr.pu16[6*2] = pCtx->fpu.DS;
5701 }
5702 }
5703}
5704
5705
5706/**
5707 * Commmon routine for fldenv and frstor
5708 *
5709 * @param uPtr Where to store the state.
5710 * @param pCtx The CPU context.
5711 */
5712static void iemCImplCommonFpuRestoreEnv(PIEMCPU pIemCpu, IEMMODE enmEffOpSize, RTCPTRUNION uPtr, PCPUMCTX pCtx)
5713{
5714 if (enmEffOpSize == IEMMODE_16BIT)
5715 {
5716 pCtx->fpu.FCW = uPtr.pu16[0];
5717 pCtx->fpu.FSW = uPtr.pu16[1];
5718 pCtx->fpu.FTW = uPtr.pu16[2];
5719 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
5720 {
5721 pCtx->fpu.FPUIP = uPtr.pu16[3] | ((uint32_t)(uPtr.pu16[4] & UINT16_C(0xf000)) << 4);
5722 pCtx->fpu.FPUDP = uPtr.pu16[5] | ((uint32_t)(uPtr.pu16[6] & UINT16_C(0xf000)) << 4);
5723 pCtx->fpu.FOP = uPtr.pu16[4] & UINT16_C(0x07ff);
5724 pCtx->fpu.CS = 0;
5725 pCtx->fpu.Rsrvd1= 0;
5726 pCtx->fpu.DS = 0;
5727 pCtx->fpu.Rsrvd2= 0;
5728 }
5729 else
5730 {
5731 pCtx->fpu.FPUIP = uPtr.pu16[3];
5732 pCtx->fpu.CS = uPtr.pu16[4];
5733 pCtx->fpu.Rsrvd1= 0;
5734 pCtx->fpu.FPUDP = uPtr.pu16[5];
5735 pCtx->fpu.DS = uPtr.pu16[6];
5736 pCtx->fpu.Rsrvd2= 0;
5737 /** @todo Testcase: Is FOP cleared when doing 16-bit protected mode fldenv? */
5738 }
5739 }
5740 else
5741 {
5742 pCtx->fpu.FCW = uPtr.pu16[0*2];
5743 pCtx->fpu.FSW = uPtr.pu16[1*2];
5744 pCtx->fpu.FTW = uPtr.pu16[2*2];
5745 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
5746 {
5747 pCtx->fpu.FPUIP = uPtr.pu16[3*2] | ((uPtr.pu32[4] & UINT32_C(0x0ffff000)) << 4);
5748 pCtx->fpu.FOP = uPtr.pu32[4] & UINT16_C(0x07ff);
5749 pCtx->fpu.FPUDP = uPtr.pu16[5*2] | ((uPtr.pu32[6] & UINT32_C(0x0ffff000)) << 4);
5750 pCtx->fpu.CS = 0;
5751 pCtx->fpu.Rsrvd1= 0;
5752 pCtx->fpu.DS = 0;
5753 pCtx->fpu.Rsrvd2= 0;
5754 }
5755 else
5756 {
5757 pCtx->fpu.FPUIP = uPtr.pu32[3];
5758 pCtx->fpu.CS = uPtr.pu16[4*2];
5759 pCtx->fpu.Rsrvd1= 0;
5760 pCtx->fpu.FOP = uPtr.pu16[4*2+1];
5761 pCtx->fpu.FPUDP = uPtr.pu32[5];
5762 pCtx->fpu.DS = uPtr.pu16[6*2];
5763 pCtx->fpu.Rsrvd2= 0;
5764 }
5765 }
5766
5767 /* Make adjustments. */
5768 pCtx->fpu.FTW = iemFpuCompressFtw(pCtx->fpu.FTW);
5769 pCtx->fpu.FCW &= ~X86_FCW_ZERO_MASK;
5770 iemFpuRecalcExceptionStatus(pCtx);
5771 /** @todo Testcase: Check if ES and/or B are automatically cleared if no
5772 * exceptions are pending after loading the saved state? */
5773}
5774
5775
5776/**
5777 * Implements 'FNSTENV'.
5778 *
5779 * @param enmEffOpSize The operand size (only REX.W really matters).
5780 * @param iEffSeg The effective segment register for @a GCPtrEff.
5781 * @param GCPtrEffDst The address of the image.
5782 */
5783IEM_CIMPL_DEF_3(iemCImpl_fnstenv, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
5784{
5785 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5786 RTPTRUNION uPtr;
5787 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, &uPtr.pv, enmEffOpSize == IEMMODE_16BIT ? 14 : 28,
5788 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5789 if (rcStrict != VINF_SUCCESS)
5790 return rcStrict;
5791
5792 iemCImplCommonFpuStoreEnv(pIemCpu, enmEffOpSize, uPtr, pCtx);
5793
5794 rcStrict = iemMemCommitAndUnmap(pIemCpu, uPtr.pv, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5795 if (rcStrict != VINF_SUCCESS)
5796 return rcStrict;
5797
5798 /* Note: C0, C1, C2 and C3 are documented as undefined, we leave them untouched! */
5799 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5800 return VINF_SUCCESS;
5801}
5802
5803
5804/**
5805 * Implements 'FNSAVE'.
5806 *
5807 * @param GCPtrEffDst The address of the image.
5808 * @param enmEffOpSize The operand size.
5809 */
5810IEM_CIMPL_DEF_3(iemCImpl_fnsave, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffDst)
5811{
5812 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5813 RTPTRUNION uPtr;
5814 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, &uPtr.pv, enmEffOpSize == IEMMODE_16BIT ? 94 : 108,
5815 iEffSeg, GCPtrEffDst, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5816 if (rcStrict != VINF_SUCCESS)
5817 return rcStrict;
5818
5819 iemCImplCommonFpuStoreEnv(pIemCpu, enmEffOpSize, uPtr, pCtx);
5820 PRTFLOAT80U paRegs = (PRTFLOAT80U)(uPtr.pu8 + (enmEffOpSize == IEMMODE_16BIT ? 14 : 28));
5821 for (uint32_t i = 0; i < RT_ELEMENTS(pCtx->fpu.aRegs); i++)
5822 {
5823 paRegs[i].au32[0] = pCtx->fpu.aRegs[i].au32[0];
5824 paRegs[i].au32[1] = pCtx->fpu.aRegs[i].au32[1];
5825 paRegs[i].au16[4] = pCtx->fpu.aRegs[i].au16[4];
5826 }
5827
5828 rcStrict = iemMemCommitAndUnmap(pIemCpu, uPtr.pv, IEM_ACCESS_DATA_W | IEM_ACCESS_PARTIAL_WRITE);
5829 if (rcStrict != VINF_SUCCESS)
5830 return rcStrict;
5831
5832 /*
5833 * Re-initialize the FPU.
5834 */
5835 pCtx->fpu.FCW = 0x37f;
5836 pCtx->fpu.FSW = 0;
5837 pCtx->fpu.FTW = 0x00; /* 0 - empty */
5838 pCtx->fpu.FPUDP = 0;
5839 pCtx->fpu.DS = 0;
5840 pCtx->fpu.Rsrvd2= 0;
5841 pCtx->fpu.FPUIP = 0;
5842 pCtx->fpu.CS = 0;
5843 pCtx->fpu.Rsrvd1= 0;
5844 pCtx->fpu.FOP = 0;
5845
5846 iemHlpUsedFpu(pIemCpu);
5847 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5848 return VINF_SUCCESS;
5849}
5850
5851
5852
5853/**
5854 * Implements 'FLDENV'.
5855 *
5856 * @param enmEffOpSize The operand size (only REX.W really matters).
5857 * @param iEffSeg The effective segment register for @a GCPtrEff.
5858 * @param GCPtrEffSrc The address of the image.
5859 */
5860IEM_CIMPL_DEF_3(iemCImpl_fldenv, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
5861{
5862 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5863 RTCPTRUNION uPtr;
5864 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, (void **)&uPtr.pv, enmEffOpSize == IEMMODE_16BIT ? 14 : 28,
5865 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R);
5866 if (rcStrict != VINF_SUCCESS)
5867 return rcStrict;
5868
5869 iemCImplCommonFpuRestoreEnv(pIemCpu, enmEffOpSize, uPtr, pCtx);
5870
5871 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)uPtr.pv, IEM_ACCESS_DATA_R);
5872 if (rcStrict != VINF_SUCCESS)
5873 return rcStrict;
5874
5875 iemHlpUsedFpu(pIemCpu);
5876 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5877 return VINF_SUCCESS;
5878}
5879
5880
5881/**
5882 * Implements 'FRSTOR'.
5883 *
5884 * @param GCPtrEffSrc The address of the image.
5885 * @param enmEffOpSize The operand size.
5886 */
5887IEM_CIMPL_DEF_3(iemCImpl_frstor, IEMMODE, enmEffOpSize, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc)
5888{
5889 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5890 RTCPTRUNION uPtr;
5891 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, (void **)&uPtr.pv, enmEffOpSize == IEMMODE_16BIT ? 94 : 108,
5892 iEffSeg, GCPtrEffSrc, IEM_ACCESS_DATA_R);
5893 if (rcStrict != VINF_SUCCESS)
5894 return rcStrict;
5895
5896 iemCImplCommonFpuRestoreEnv(pIemCpu, enmEffOpSize, uPtr, pCtx);
5897 PCRTFLOAT80U paRegs = (PCRTFLOAT80U)(uPtr.pu8 + (enmEffOpSize == IEMMODE_16BIT ? 14 : 28));
5898 for (uint32_t i = 0; i < RT_ELEMENTS(pCtx->fpu.aRegs); i++)
5899 {
5900 pCtx->fpu.aRegs[i].au32[0] = paRegs[i].au32[0];
5901 pCtx->fpu.aRegs[i].au32[1] = paRegs[i].au32[1];
5902 pCtx->fpu.aRegs[i].au32[2] = paRegs[i].au16[4];
5903 pCtx->fpu.aRegs[i].au32[3] = 0;
5904 }
5905
5906 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)uPtr.pv, IEM_ACCESS_DATA_R);
5907 if (rcStrict != VINF_SUCCESS)
5908 return rcStrict;
5909
5910 iemHlpUsedFpu(pIemCpu);
5911 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5912 return VINF_SUCCESS;
5913}
5914
5915
5916/**
5917 * Implements 'FLDCW'.
5918 *
5919 * @param u16Fcw The new FCW.
5920 */
5921IEM_CIMPL_DEF_1(iemCImpl_fldcw, uint16_t, u16Fcw)
5922{
5923 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5924
5925 /** @todo Testcase: Check what happens when trying to load X86_FCW_PC_RSVD. */
5926 /** @todo Testcase: Try see what happens when trying to set undefined bits
5927 * (other than 6 and 7). Currently ignoring them. */
5928 /** @todo Testcase: Test that it raises and loweres the FPU exception bits
5929 * according to FSW. (This is was is currently implemented.) */
5930 pCtx->fpu.FCW = u16Fcw & ~X86_FCW_ZERO_MASK;
5931 iemFpuRecalcExceptionStatus(pCtx);
5932
5933 /* Note: C0, C1, C2 and C3 are documented as undefined, we leave them untouched! */
5934 iemHlpUsedFpu(pIemCpu);
5935 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5936 return VINF_SUCCESS;
5937}
5938
5939
5940
5941/**
5942 * Implements the underflow case of fxch.
5943 *
5944 * @param iStReg The other stack register.
5945 */
5946IEM_CIMPL_DEF_1(iemCImpl_fxch_underflow, uint8_t, iStReg)
5947{
5948 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5949
5950 unsigned const iReg1 = X86_FSW_TOP_GET(pCtx->fpu.FSW);
5951 unsigned const iReg2 = (iReg1 + iStReg) & X86_FSW_TOP_SMASK;
5952 Assert(!(RT_BIT(iReg1) & pCtx->fpu.FTW) || !(RT_BIT(iReg2) & pCtx->fpu.FTW));
5953
5954 /** @todo Testcase: fxch underflow. Making assumptions that underflowed
5955 * registers are read as QNaN and then exchanged. This could be
5956 * wrong... */
5957 if (pCtx->fpu.FCW & X86_FCW_IM)
5958 {
5959 if (RT_BIT(iReg1) & pCtx->fpu.FTW)
5960 {
5961 if (RT_BIT(iReg2) & pCtx->fpu.FTW)
5962 iemFpuStoreQNan(&pCtx->fpu.aRegs[0].r80);
5963 else
5964 pCtx->fpu.aRegs[0].r80 = pCtx->fpu.aRegs[iStReg].r80;
5965 iemFpuStoreQNan(&pCtx->fpu.aRegs[iStReg].r80);
5966 }
5967 else
5968 {
5969 pCtx->fpu.aRegs[iStReg].r80 = pCtx->fpu.aRegs[0].r80;
5970 iemFpuStoreQNan(&pCtx->fpu.aRegs[0].r80);
5971 }
5972 pCtx->fpu.FSW &= ~X86_FSW_C_MASK;
5973 pCtx->fpu.FSW |= X86_FSW_C1 | X86_FSW_IE | X86_FSW_SF;
5974 }
5975 else
5976 {
5977 /* raise underflow exception, don't change anything. */
5978 pCtx->fpu.FSW &= ~(X86_FSW_TOP_MASK | X86_FSW_XCPT_MASK);
5979 pCtx->fpu.FSW |= X86_FSW_C1 | X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B;
5980 }
5981
5982 iemFpuUpdateOpcodeAndIpWorker(pIemCpu, pCtx);
5983 iemHlpUsedFpu(pIemCpu);
5984 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
5985 return VINF_SUCCESS;
5986}
5987
5988
5989/**
5990 * Implements 'FCOMI', 'FCOMIP', 'FUCOMI', and 'FUCOMIP'.
5991 *
5992 * @param cToAdd 1 or 7.
5993 */
5994IEM_CIMPL_DEF_3(iemCImpl_fcomi_fucomi, uint8_t, iStReg, PFNIEMAIMPLFPUR80EFL, pfnAImpl, bool, fPop)
5995{
5996 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5997 Assert(iStReg < 8);
5998
5999 /*
6000 * Raise exceptions.
6001 */
6002 if (pCtx->cr0 & (X86_CR0_EM | X86_CR0_TS))
6003 return iemRaiseDeviceNotAvailable(pIemCpu);
6004 uint16_t u16Fsw = pCtx->fpu.FSW;
6005 if (u16Fsw & X86_FSW_ES)
6006 return iemRaiseMathFault(pIemCpu);
6007
6008 /*
6009 * Check if any of the register accesses causes #SF + #IA.
6010 */
6011 unsigned const iReg1 = X86_FSW_TOP_GET(u16Fsw);
6012 unsigned const iReg2 = (iReg1 + iStReg) & X86_FSW_TOP_SMASK;
6013 if ((pCtx->fpu.FTW & (RT_BIT(iReg1) | RT_BIT(iReg2))) == (RT_BIT(iReg1) | RT_BIT(iReg2)))
6014 {
6015 uint32_t u32Eflags = pfnAImpl(&pCtx->fpu, &u16Fsw, &pCtx->fpu.aRegs[0].r80, &pCtx->fpu.aRegs[iStReg].r80);
6016 NOREF(u32Eflags);
6017
6018 pCtx->fpu.FSW &= ~X86_FSW_C1;
6019 pCtx->fpu.FSW |= u16Fsw & ~X86_FSW_TOP_MASK;
6020 if ( !(u16Fsw & X86_FSW_IE)
6021 || (pCtx->fpu.FCW & X86_FCW_IM) )
6022 {
6023 pCtx->eflags.u &= ~(X86_EFL_OF | X86_EFL_SF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
6024 pCtx->eflags.u |= pCtx->eflags.u & (X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
6025 }
6026 }
6027 else if (pCtx->fpu.FCW & X86_FCW_IM)
6028 {
6029 /* Masked underflow. */
6030 pCtx->fpu.FSW &= ~X86_FSW_C1;
6031 pCtx->fpu.FSW |= X86_FSW_IE | X86_FSW_SF;
6032 pCtx->eflags.u &= ~(X86_EFL_OF | X86_EFL_SF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF);
6033 pCtx->eflags.u |= X86_EFL_ZF | X86_EFL_PF | X86_EFL_CF;
6034 }
6035 else
6036 {
6037 /* Raise underflow - don't touch EFLAGS or TOP. */
6038 pCtx->fpu.FSW &= ~X86_FSW_C1;
6039 pCtx->fpu.FSW |= X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B;
6040 fPop = false;
6041 }
6042
6043 /*
6044 * Pop if necessary.
6045 */
6046 if (fPop)
6047 {
6048 pCtx->fpu.FTW &= ~RT_BIT(iReg1);
6049 pCtx->fpu.FSW &= X86_FSW_TOP_MASK;
6050 pCtx->fpu.FSW |= ((iReg1 + 7) & X86_FSW_TOP_SMASK) << X86_FSW_TOP_SHIFT;
6051 }
6052
6053 iemFpuUpdateOpcodeAndIpWorker(pIemCpu, pCtx);
6054 iemHlpUsedFpu(pIemCpu);
6055 iemRegAddToRipAndClearRF(pIemCpu, cbInstr);
6056 return VINF_SUCCESS;
6057}
6058
6059/** @} */
6060
Note: See TracBrowser for help on using the repository browser.

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