VirtualBox

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

Last change on this file since 66526 was 66462, checked in by vboxsync, 8 years ago

IEM,bs3-cpu-generated-1: Made the current testcases pass on AMD.

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