VirtualBox

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

Last change on this file since 62534 was 62478, checked in by vboxsync, 8 years ago

(C) 2016

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

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