VirtualBox

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

Last change on this file since 37079 was 37079, checked in by vboxsync, 14 years ago

IEM: Implemented the bare minimum of protected mode interrupt handling (dispatching + iret).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 94.0 KB
Line 
1/* $Id: IEMAllCImpl.cpp.h 37079 2011-05-13 15:35:03Z vboxsync $ */
2/** @file
3 * IEM - Instruction Implementation in C/C++ (code include).
4 */
5
6/*
7 * Copyright (C) 2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/** @name Misc Helpers
20 * @{
21 */
22
23/**
24 * Checks if we are allowed to access the given I/O port, raising the
25 * appropriate exceptions if we aren't (or if the I/O bitmap is not
26 * accessible).
27 *
28 * @returns Strict VBox status code.
29 *
30 * @param pIemCpu The IEM per CPU data.
31 * @param pCtx The register context.
32 * @param u16Port The port number.
33 * @param cbOperand The operand size.
34 */
35DECLINLINE(VBOXSTRICTRC) iemHlpCheckPortIOPermission(PIEMCPU pIemCpu, PCCPUMCTX pCtx, uint16_t u16Port, uint8_t cbOperand)
36{
37 if ( (pCtx->cr0 & X86_CR0_PE)
38 && ( pIemCpu->uCpl > pCtx->eflags.Bits.u2IOPL
39 || pCtx->eflags.Bits.u1VM) )
40 {
41 /** @todo I/O port permission bitmap check */
42 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
43 }
44 return VINF_SUCCESS;
45}
46
47/** @} */
48
49/** @name C Implementations
50 * @{
51 */
52
53/**
54 * Implements a 16-bit popa.
55 */
56IEM_CIMPL_DEF_0(iemCImpl_popa_16)
57{
58 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
59 RTGCPTR GCPtrStart = iemRegGetEffRsp(pCtx);
60 RTGCPTR GCPtrLast = GCPtrStart + 15;
61 VBOXSTRICTRC rcStrict;
62
63 /*
64 * The docs are a bit hard to comprehend here, but it looks like we wrap
65 * around in real mode as long as none of the individual "popa" crosses the
66 * end of the stack segment. In protected mode we check the whole access
67 * in one go. For efficiency, only do the word-by-word thing if we're in
68 * danger of wrapping around.
69 */
70 /** @todo do popa boundary / wrap-around checks. */
71 if (RT_UNLIKELY( IEM_IS_REAL_OR_V86_MODE(pIemCpu)
72 && (pCtx->csHid.u32Limit < GCPtrLast)) ) /* ASSUMES 64-bit RTGCPTR */
73 {
74 /* word-by-word */
75 RTUINT64U TmpRsp;
76 TmpRsp.u = pCtx->rsp;
77 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->di, &TmpRsp);
78 if (rcStrict == VINF_SUCCESS)
79 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->si, &TmpRsp);
80 if (rcStrict == VINF_SUCCESS)
81 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->bp, &TmpRsp);
82 if (rcStrict == VINF_SUCCESS)
83 {
84 iemRegAddToRspEx(&TmpRsp, 2, pCtx); /* sp */
85 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->bx, &TmpRsp);
86 }
87 if (rcStrict == VINF_SUCCESS)
88 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->dx, &TmpRsp);
89 if (rcStrict == VINF_SUCCESS)
90 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->cx, &TmpRsp);
91 if (rcStrict == VINF_SUCCESS)
92 rcStrict = iemMemStackPopU16Ex(pIemCpu, &pCtx->ax, &TmpRsp);
93 if (rcStrict == VINF_SUCCESS)
94 {
95 pCtx->rsp = TmpRsp.u;
96 iemRegAddToRip(pIemCpu, cbInstr);
97 }
98 }
99 else
100 {
101 uint16_t const *pa16Mem = NULL;
102 rcStrict = iemMemMap(pIemCpu, (void **)&pa16Mem, 16, X86_SREG_SS, GCPtrStart, IEM_ACCESS_STACK_R);
103 if (rcStrict == VINF_SUCCESS)
104 {
105 pCtx->di = pa16Mem[7 - X86_GREG_xDI];
106 pCtx->si = pa16Mem[7 - X86_GREG_xSI];
107 pCtx->bp = pa16Mem[7 - X86_GREG_xBP];
108 /* skip sp */
109 pCtx->bx = pa16Mem[7 - X86_GREG_xBX];
110 pCtx->dx = pa16Mem[7 - X86_GREG_xDX];
111 pCtx->cx = pa16Mem[7 - X86_GREG_xCX];
112 pCtx->ax = pa16Mem[7 - X86_GREG_xAX];
113 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)pa16Mem, IEM_ACCESS_STACK_R);
114 if (rcStrict == VINF_SUCCESS)
115 {
116 iemRegAddToRsp(pCtx, 16);
117 iemRegAddToRip(pIemCpu, cbInstr);
118 }
119 }
120 }
121 return rcStrict;
122}
123
124
125/**
126 * Implements a 32-bit popa.
127 */
128IEM_CIMPL_DEF_0(iemCImpl_popa_32)
129{
130 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
131 RTGCPTR GCPtrStart = iemRegGetEffRsp(pCtx);
132 RTGCPTR GCPtrLast = GCPtrStart + 31;
133 VBOXSTRICTRC rcStrict;
134
135 /*
136 * The docs are a bit hard to comprehend here, but it looks like we wrap
137 * around in real mode as long as none of the individual "popa" crosses the
138 * end of the stack segment. In protected mode we check the whole access
139 * in one go. For efficiency, only do the word-by-word thing if we're in
140 * danger of wrapping around.
141 */
142 /** @todo do popa boundary / wrap-around checks. */
143 if (RT_UNLIKELY( IEM_IS_REAL_OR_V86_MODE(pIemCpu)
144 && (pCtx->csHid.u32Limit < GCPtrLast)) ) /* ASSUMES 64-bit RTGCPTR */
145 {
146 /* word-by-word */
147 RTUINT64U TmpRsp;
148 TmpRsp.u = pCtx->rsp;
149 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->edi, &TmpRsp);
150 if (rcStrict == VINF_SUCCESS)
151 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->esi, &TmpRsp);
152 if (rcStrict == VINF_SUCCESS)
153 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->ebp, &TmpRsp);
154 if (rcStrict == VINF_SUCCESS)
155 {
156 iemRegAddToRspEx(&TmpRsp, 2, pCtx); /* sp */
157 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->ebx, &TmpRsp);
158 }
159 if (rcStrict == VINF_SUCCESS)
160 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->edx, &TmpRsp);
161 if (rcStrict == VINF_SUCCESS)
162 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->ecx, &TmpRsp);
163 if (rcStrict == VINF_SUCCESS)
164 rcStrict = iemMemStackPopU32Ex(pIemCpu, &pCtx->eax, &TmpRsp);
165 if (rcStrict == VINF_SUCCESS)
166 {
167#if 1 /** @todo what actually happens with the high bits when we're in 16-bit mode? */
168 pCtx->rdi &= UINT32_MAX;
169 pCtx->rsi &= UINT32_MAX;
170 pCtx->rbp &= UINT32_MAX;
171 pCtx->rbx &= UINT32_MAX;
172 pCtx->rdx &= UINT32_MAX;
173 pCtx->rcx &= UINT32_MAX;
174 pCtx->rax &= UINT32_MAX;
175#endif
176 pCtx->rsp = TmpRsp.u;
177 iemRegAddToRip(pIemCpu, cbInstr);
178 }
179 }
180 else
181 {
182 uint32_t const *pa32Mem;
183 rcStrict = iemMemMap(pIemCpu, (void **)&pa32Mem, 32, X86_SREG_SS, GCPtrStart, IEM_ACCESS_STACK_R);
184 if (rcStrict == VINF_SUCCESS)
185 {
186 pCtx->rdi = pa32Mem[7 - X86_GREG_xDI];
187 pCtx->rsi = pa32Mem[7 - X86_GREG_xSI];
188 pCtx->rbp = pa32Mem[7 - X86_GREG_xBP];
189 /* skip esp */
190 pCtx->rbx = pa32Mem[7 - X86_GREG_xBX];
191 pCtx->rdx = pa32Mem[7 - X86_GREG_xDX];
192 pCtx->rcx = pa32Mem[7 - X86_GREG_xCX];
193 pCtx->rax = pa32Mem[7 - X86_GREG_xAX];
194 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)pa32Mem, IEM_ACCESS_STACK_R);
195 if (rcStrict == VINF_SUCCESS)
196 {
197 iemRegAddToRsp(pCtx, 32);
198 iemRegAddToRip(pIemCpu, cbInstr);
199 }
200 }
201 }
202 return rcStrict;
203}
204
205
206/**
207 * Implements a 16-bit pusha.
208 */
209IEM_CIMPL_DEF_0(iemCImpl_pusha_16)
210{
211 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
212 RTGCPTR GCPtrTop = iemRegGetEffRsp(pCtx);
213 RTGCPTR GCPtrBottom = GCPtrTop - 15;
214 VBOXSTRICTRC rcStrict;
215
216 /*
217 * The docs are a bit hard to comprehend here, but it looks like we wrap
218 * around in real mode as long as none of the individual "pushd" crosses the
219 * end of the stack segment. In protected mode we check the whole access
220 * in one go. For efficiency, only do the word-by-word thing if we're in
221 * danger of wrapping around.
222 */
223 /** @todo do pusha boundary / wrap-around checks. */
224 if (RT_UNLIKELY( GCPtrBottom > GCPtrTop
225 && IEM_IS_REAL_OR_V86_MODE(pIemCpu) ) )
226 {
227 /* word-by-word */
228 RTUINT64U TmpRsp;
229 TmpRsp.u = pCtx->rsp;
230 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->ax, &TmpRsp);
231 if (rcStrict == VINF_SUCCESS)
232 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->cx, &TmpRsp);
233 if (rcStrict == VINF_SUCCESS)
234 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->dx, &TmpRsp);
235 if (rcStrict == VINF_SUCCESS)
236 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->bx, &TmpRsp);
237 if (rcStrict == VINF_SUCCESS)
238 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->sp, &TmpRsp);
239 if (rcStrict == VINF_SUCCESS)
240 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->bp, &TmpRsp);
241 if (rcStrict == VINF_SUCCESS)
242 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->si, &TmpRsp);
243 if (rcStrict == VINF_SUCCESS)
244 rcStrict = iemMemStackPushU16Ex(pIemCpu, pCtx->di, &TmpRsp);
245 if (rcStrict == VINF_SUCCESS)
246 {
247 pCtx->rsp = TmpRsp.u;
248 iemRegAddToRip(pIemCpu, cbInstr);
249 }
250 }
251 else
252 {
253 GCPtrBottom--;
254 uint16_t *pa16Mem = NULL;
255 rcStrict = iemMemMap(pIemCpu, (void **)&pa16Mem, 16, X86_SREG_SS, GCPtrBottom, IEM_ACCESS_STACK_W);
256 if (rcStrict == VINF_SUCCESS)
257 {
258 pa16Mem[7 - X86_GREG_xDI] = pCtx->di;
259 pa16Mem[7 - X86_GREG_xSI] = pCtx->si;
260 pa16Mem[7 - X86_GREG_xBP] = pCtx->bp;
261 pa16Mem[7 - X86_GREG_xSP] = pCtx->sp;
262 pa16Mem[7 - X86_GREG_xBX] = pCtx->bx;
263 pa16Mem[7 - X86_GREG_xDX] = pCtx->dx;
264 pa16Mem[7 - X86_GREG_xCX] = pCtx->cx;
265 pa16Mem[7 - X86_GREG_xAX] = pCtx->ax;
266 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)pa16Mem, IEM_ACCESS_STACK_W);
267 if (rcStrict == VINF_SUCCESS)
268 {
269 iemRegSubFromRsp(pCtx, 16);
270 iemRegAddToRip(pIemCpu, cbInstr);
271 }
272 }
273 }
274 return rcStrict;
275}
276
277
278/**
279 * Implements a 32-bit pusha.
280 */
281IEM_CIMPL_DEF_0(iemCImpl_pusha_32)
282{
283 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
284 RTGCPTR GCPtrTop = iemRegGetEffRsp(pCtx);
285 RTGCPTR GCPtrBottom = GCPtrTop - 31;
286 VBOXSTRICTRC rcStrict;
287
288 /*
289 * The docs are a bit hard to comprehend here, but it looks like we wrap
290 * around in real mode as long as none of the individual "pusha" crosses the
291 * end of the stack segment. In protected mode we check the whole access
292 * in one go. For efficiency, only do the word-by-word thing if we're in
293 * danger of wrapping around.
294 */
295 /** @todo do pusha boundary / wrap-around checks. */
296 if (RT_UNLIKELY( GCPtrBottom > GCPtrTop
297 && IEM_IS_REAL_OR_V86_MODE(pIemCpu) ) )
298 {
299 /* word-by-word */
300 RTUINT64U TmpRsp;
301 TmpRsp.u = pCtx->rsp;
302 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->eax, &TmpRsp);
303 if (rcStrict == VINF_SUCCESS)
304 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->ecx, &TmpRsp);
305 if (rcStrict == VINF_SUCCESS)
306 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->edx, &TmpRsp);
307 if (rcStrict == VINF_SUCCESS)
308 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->ebx, &TmpRsp);
309 if (rcStrict == VINF_SUCCESS)
310 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->esp, &TmpRsp);
311 if (rcStrict == VINF_SUCCESS)
312 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->ebp, &TmpRsp);
313 if (rcStrict == VINF_SUCCESS)
314 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->esi, &TmpRsp);
315 if (rcStrict == VINF_SUCCESS)
316 rcStrict = iemMemStackPushU32Ex(pIemCpu, pCtx->edi, &TmpRsp);
317 if (rcStrict == VINF_SUCCESS)
318 {
319 pCtx->rsp = TmpRsp.u;
320 iemRegAddToRip(pIemCpu, cbInstr);
321 }
322 }
323 else
324 {
325 GCPtrBottom--;
326 uint32_t *pa32Mem;
327 rcStrict = iemMemMap(pIemCpu, (void **)&pa32Mem, 32, X86_SREG_SS, GCPtrBottom, IEM_ACCESS_STACK_W);
328 if (rcStrict == VINF_SUCCESS)
329 {
330 pa32Mem[7 - X86_GREG_xDI] = pCtx->edi;
331 pa32Mem[7 - X86_GREG_xSI] = pCtx->esi;
332 pa32Mem[7 - X86_GREG_xBP] = pCtx->ebp;
333 pa32Mem[7 - X86_GREG_xSP] = pCtx->esp;
334 pa32Mem[7 - X86_GREG_xBX] = pCtx->ebx;
335 pa32Mem[7 - X86_GREG_xDX] = pCtx->edx;
336 pa32Mem[7 - X86_GREG_xCX] = pCtx->ecx;
337 pa32Mem[7 - X86_GREG_xAX] = pCtx->eax;
338 rcStrict = iemMemCommitAndUnmap(pIemCpu, pa32Mem, IEM_ACCESS_STACK_W);
339 if (rcStrict == VINF_SUCCESS)
340 {
341 iemRegSubFromRsp(pCtx, 32);
342 iemRegAddToRip(pIemCpu, cbInstr);
343 }
344 }
345 }
346 return rcStrict;
347}
348
349
350/**
351 * Implements pushf.
352 *
353 *
354 * @param enmEffOpSize The effective operand size.
355 */
356IEM_CIMPL_DEF_1(iemCImpl_pushf, IEMMODE, enmEffOpSize)
357{
358 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
359
360 /*
361 * If we're in V8086 mode some care is required (which is why we're in
362 * doing this in a C implementation).
363 */
364 uint32_t fEfl = pCtx->eflags.u;
365 if ( (fEfl & X86_EFL_VM)
366 && X86_EFL_GET_IOPL(fEfl) != 3 )
367 {
368 Assert(pCtx->cr0 & X86_CR0_PE);
369 if ( enmEffOpSize != IEMMODE_16BIT
370 || !(pCtx->cr4 & X86_CR4_VME))
371 return iemRaiseGeneralProtectionFault0(pIemCpu);
372 fEfl &= ~X86_EFL_IF; /* (RF and VM are out of range) */
373 fEfl |= (fEfl & X86_EFL_VIF) >> (19 - 9);
374 return iemMemStackPushU16(pIemCpu, (uint16_t)fEfl);
375 }
376
377 /*
378 * Ok, clear RF and VM and push the flags.
379 */
380 fEfl &= ~(X86_EFL_RF | X86_EFL_VM);
381
382 VBOXSTRICTRC rcStrict;
383 switch (enmEffOpSize)
384 {
385 case IEMMODE_16BIT:
386 rcStrict = iemMemStackPushU16(pIemCpu, (uint16_t)fEfl);
387 break;
388 case IEMMODE_32BIT:
389 rcStrict = iemMemStackPushU32(pIemCpu, fEfl);
390 break;
391 case IEMMODE_64BIT:
392 rcStrict = iemMemStackPushU64(pIemCpu, fEfl);
393 break;
394 IEM_NOT_REACHED_DEFAULT_CASE_RET();
395 }
396 if (rcStrict != VINF_SUCCESS)
397 return rcStrict;
398
399 iemRegAddToRip(pIemCpu, cbInstr);
400 return VINF_SUCCESS;
401}
402
403
404/**
405 * Implements popf.
406 *
407 * @param enmEffOpSize The effective operand size.
408 */
409IEM_CIMPL_DEF_1(iemCImpl_popf, IEMMODE, enmEffOpSize)
410{
411 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
412 uint32_t const fEflOld = pCtx->eflags.u;
413 VBOXSTRICTRC rcStrict;
414 uint32_t fEflNew;
415
416 /*
417 * V8086 is special as usual.
418 */
419 if (fEflOld & X86_EFL_VM)
420 {
421 /*
422 * Almost anything goes if IOPL is 3.
423 */
424 if (X86_EFL_GET_IOPL(fEflOld) == 3)
425 {
426 switch (enmEffOpSize)
427 {
428 case IEMMODE_16BIT:
429 {
430 uint16_t u16Value;
431 rcStrict = iemMemStackPopU16(pIemCpu, &u16Value);
432 if (rcStrict != VINF_SUCCESS)
433 return rcStrict;
434 fEflNew = u16Value | (fEflOld & UINT32_C(0xffff0000));
435 break;
436 }
437 case IEMMODE_32BIT:
438 rcStrict = iemMemStackPopU32(pIemCpu, &fEflNew);
439 if (rcStrict != VINF_SUCCESS)
440 return rcStrict;
441 break;
442 IEM_NOT_REACHED_DEFAULT_CASE_RET();
443 }
444
445 fEflNew &= X86_EFL_POPF_BITS & ~(X86_EFL_IOPL);
446 fEflNew |= ~(X86_EFL_POPF_BITS & ~(X86_EFL_IOPL)) & fEflOld;
447 }
448 /*
449 * Interrupt flag virtualization with CR4.VME=1.
450 */
451 else if ( enmEffOpSize == IEMMODE_16BIT
452 && (pCtx->cr4 & X86_CR4_VME) )
453 {
454 uint16_t u16Value;
455 RTUINT64U TmpRsp;
456 TmpRsp.u = pCtx->rsp;
457 rcStrict = iemMemStackPopU16Ex(pIemCpu, &u16Value, &TmpRsp);
458 if (rcStrict != VINF_SUCCESS)
459 return rcStrict;
460
461 /** @todo Is the popf VME #GP(0) delivered after updating RSP+RIP
462 * or before? */
463 if ( ( (u16Value & X86_EFL_IF)
464 && (fEflOld & X86_EFL_VIP))
465 || (u16Value & X86_EFL_TF) )
466 return iemRaiseGeneralProtectionFault0(pIemCpu);
467
468 fEflNew = u16Value | (fEflOld & UINT32_C(0xffff0000) & ~X86_EFL_VIF);
469 fEflNew |= (fEflNew & X86_EFL_IF) << (19 - 9);
470 fEflNew &= X86_EFL_POPF_BITS & ~(X86_EFL_IOPL | X86_EFL_IF);
471 fEflNew |= ~(X86_EFL_POPF_BITS & ~(X86_EFL_IOPL | X86_EFL_IF)) & fEflOld;
472
473 pCtx->rsp = TmpRsp.u;
474 }
475 else
476 return iemRaiseGeneralProtectionFault0(pIemCpu);
477
478 }
479 /*
480 * Not in V8086 mode.
481 */
482 else
483 {
484 /* Pop the flags. */
485 switch (enmEffOpSize)
486 {
487 case IEMMODE_16BIT:
488 {
489 uint16_t u16Value;
490 rcStrict = iemMemStackPopU16(pIemCpu, &u16Value);
491 if (rcStrict != VINF_SUCCESS)
492 return rcStrict;
493 fEflNew = u16Value | (fEflOld & UINT32_C(0xffff0000));
494 break;
495 }
496 case IEMMODE_32BIT:
497 case IEMMODE_64BIT:
498 rcStrict = iemMemStackPopU32(pIemCpu, &fEflNew);
499 if (rcStrict != VINF_SUCCESS)
500 return rcStrict;
501 break;
502 IEM_NOT_REACHED_DEFAULT_CASE_RET();
503 }
504
505 /* Merge them with the current flags. */
506 if ( (fEflNew & (X86_EFL_IOPL | X86_EFL_IF)) == (fEflOld & (X86_EFL_IOPL | X86_EFL_IF))
507 || pIemCpu->uCpl == 0)
508 {
509 fEflNew &= X86_EFL_POPF_BITS;
510 fEflNew |= ~X86_EFL_POPF_BITS & fEflOld;
511 }
512 else if (pIemCpu->uCpl <= X86_EFL_GET_IOPL(fEflOld))
513 {
514 fEflNew &= X86_EFL_POPF_BITS & ~(X86_EFL_IOPL);
515 fEflNew |= ~(X86_EFL_POPF_BITS & ~(X86_EFL_IOPL)) & fEflOld;
516 }
517 else
518 {
519 fEflNew &= X86_EFL_POPF_BITS & ~(X86_EFL_IOPL | X86_EFL_IF);
520 fEflNew |= ~(X86_EFL_POPF_BITS & ~(X86_EFL_IOPL | X86_EFL_IF)) & fEflOld;
521 }
522 }
523
524 /*
525 * Commit the flags.
526 */
527 Assert(fEflNew & RT_BIT_32(1));
528 pCtx->eflags.u = fEflNew;
529 iemRegAddToRip(pIemCpu, cbInstr);
530
531 return VINF_SUCCESS;
532}
533
534
535/**
536 * Implements an indirect call.
537 *
538 * @param uNewPC The new program counter (RIP) value (loaded from the
539 * operand).
540 * @param enmEffOpSize The effective operand size.
541 */
542IEM_CIMPL_DEF_1(iemCImpl_call_16, uint16_t, uNewPC)
543{
544 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
545 uint16_t uOldPC = pCtx->ip + cbInstr;
546 if (uNewPC > pCtx->csHid.u32Limit)
547 return iemRaiseGeneralProtectionFault0(pIemCpu);
548
549 VBOXSTRICTRC rcStrict = iemMemStackPushU16(pIemCpu, uOldPC);
550 if (rcStrict != VINF_SUCCESS)
551 return rcStrict;
552
553 pCtx->rip = uNewPC;
554 return VINF_SUCCESS;
555
556}
557
558
559/**
560 * Implements a 16-bit relative call.
561 *
562 * @param offDisp The displacment offset.
563 */
564IEM_CIMPL_DEF_1(iemCImpl_call_rel_16, int16_t, offDisp)
565{
566 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
567 uint16_t uOldPC = pCtx->ip + cbInstr;
568 uint16_t uNewPC = uOldPC + offDisp;
569 if (uNewPC > pCtx->csHid.u32Limit)
570 return iemRaiseGeneralProtectionFault0(pIemCpu);
571
572 VBOXSTRICTRC rcStrict = iemMemStackPushU16(pIemCpu, uOldPC);
573 if (rcStrict != VINF_SUCCESS)
574 return rcStrict;
575
576 pCtx->rip = uNewPC;
577 return VINF_SUCCESS;
578}
579
580
581/**
582 * Implements a 32-bit indirect call.
583 *
584 * @param uNewPC The new program counter (RIP) value (loaded from the
585 * operand).
586 * @param enmEffOpSize The effective operand size.
587 */
588IEM_CIMPL_DEF_1(iemCImpl_call_32, uint32_t, uNewPC)
589{
590 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
591 uint32_t uOldPC = pCtx->eip + cbInstr;
592 if (uNewPC > pCtx->csHid.u32Limit)
593 return iemRaiseGeneralProtectionFault0(pIemCpu);
594
595 VBOXSTRICTRC rcStrict = iemMemStackPushU32(pIemCpu, uOldPC);
596 if (rcStrict != VINF_SUCCESS)
597 return rcStrict;
598
599 pCtx->rip = uNewPC;
600 return VINF_SUCCESS;
601
602}
603
604
605/**
606 * Implements a 32-bit relative call.
607 *
608 * @param offDisp The displacment offset.
609 */
610IEM_CIMPL_DEF_1(iemCImpl_call_rel_32, int32_t, offDisp)
611{
612 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
613 uint32_t uOldPC = pCtx->eip + cbInstr;
614 uint32_t uNewPC = uOldPC + offDisp;
615 if (uNewPC > pCtx->csHid.u32Limit)
616 return iemRaiseGeneralProtectionFault0(pIemCpu);
617
618 VBOXSTRICTRC rcStrict = iemMemStackPushU32(pIemCpu, uOldPC);
619 if (rcStrict != VINF_SUCCESS)
620 return rcStrict;
621
622 pCtx->rip = uNewPC;
623 return VINF_SUCCESS;
624}
625
626
627/**
628 * Implements a 64-bit indirect call.
629 *
630 * @param uNewPC The new program counter (RIP) value (loaded from the
631 * operand).
632 * @param enmEffOpSize The effective operand size.
633 */
634IEM_CIMPL_DEF_1(iemCImpl_call_64, uint64_t, uNewPC)
635{
636 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
637 uint64_t uOldPC = pCtx->rip + cbInstr;
638 if (!IEM_IS_CANONICAL(uNewPC))
639 return iemRaiseGeneralProtectionFault0(pIemCpu);
640
641 VBOXSTRICTRC rcStrict = iemMemStackPushU64(pIemCpu, uOldPC);
642 if (rcStrict != VINF_SUCCESS)
643 return rcStrict;
644
645 pCtx->rip = uNewPC;
646 return VINF_SUCCESS;
647
648}
649
650
651/**
652 * Implements a 64-bit relative call.
653 *
654 * @param offDisp The displacment offset.
655 */
656IEM_CIMPL_DEF_1(iemCImpl_call_rel_64, int64_t, offDisp)
657{
658 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
659 uint64_t uOldPC = pCtx->rip + cbInstr;
660 uint64_t uNewPC = uOldPC + offDisp;
661 if (!IEM_IS_CANONICAL(uNewPC))
662 return iemRaiseNotCanonical(pIemCpu);
663
664 VBOXSTRICTRC rcStrict = iemMemStackPushU64(pIemCpu, uOldPC);
665 if (rcStrict != VINF_SUCCESS)
666 return rcStrict;
667
668 pCtx->rip = uNewPC;
669 return VINF_SUCCESS;
670}
671
672
673/**
674 * Implements far jumps.
675 *
676 * @param uSel The selector.
677 * @param offSeg The segment offset.
678 * @param enmEffOpSize The effective operand size.
679 */
680IEM_CIMPL_DEF_3(iemCImpl_FarJmp, uint16_t, uSel, uint32_t, offSeg, IEMMODE, enmEffOpSize)
681{
682 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
683
684 /*
685 * Real mode and V8086 mode are easy. The only snag seems to be that
686 * CS.limit doesn't change and the limit check is done against the current
687 * limit.
688 */
689 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
690 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
691 {
692 if (offSeg > pCtx->csHid.u32Limit)
693 return iemRaiseGeneralProtectionFault0(pIemCpu);
694
695 if (enmEffOpSize == IEMMODE_16BIT) /** @todo WRONG, must pass this. */
696 pCtx->rip = offSeg;
697 else
698 pCtx->rip = offSeg & UINT16_MAX;
699 pCtx->cs = uSel;
700 pCtx->csHid.u64Base = (uint32_t)uSel << 4;
701 /** @todo REM reset the accessed bit (see on jmp far16 after disabling
702 * PE. Check with VT-x and AMD-V. */
703#ifdef IEM_VERIFICATION_MODE
704 pCtx->csHid.Attr.u &= ~X86_SEL_TYPE_ACCESSED;
705#endif
706 return VINF_SUCCESS;
707 }
708
709 /*
710 * Protected mode. Need to parse the specified descriptor...
711 */
712 if (!(uSel & (X86_SEL_MASK | X86_SEL_LDT)))
713 {
714 Log(("jmpf %04x:%08x -> invalid selector, #GP(0)\n", uSel, offSeg));
715 return iemRaiseGeneralProtectionFault0(pIemCpu);
716 }
717
718 /* Fetch the descriptor. */
719 IEMSELDESC Desc;
720 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uSel);
721 if (rcStrict != VINF_SUCCESS)
722 return rcStrict;
723
724 /* Is it there? */
725 if (!Desc.Legacy.Gen.u1Present) /** @todo this is probably checked too early. Testcase! */
726 {
727 Log(("jmpf %04x:%08x -> segment not present\n", uSel, offSeg));
728 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uSel);
729 }
730
731 /*
732 * Deal with it according to its type.
733 */
734 if (Desc.Legacy.Gen.u1DescType)
735 {
736 /* Only code segments. */
737 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE))
738 {
739 Log(("jmpf %04x:%08x -> not a code selector (u4Type=%#x).\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
740 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
741 }
742
743 /* L vs D. */
744 if ( Desc.Legacy.Gen.u1Long
745 && Desc.Legacy.Gen.u1DefBig
746 && IEM_IS_LONG_MODE(pIemCpu))
747 {
748 Log(("jmpf %04x:%08x -> both L and D are set.\n", uSel, offSeg));
749 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
750 }
751
752 /* DPL/RPL/CPL check, where conforming segments makes a difference. */
753 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF))
754 {
755 if (Desc.Legacy.Gen.u2Dpl > pIemCpu->uCpl)
756 {
757 Log(("jmpf %04x:%08x -> DPL violation (conforming); DPL=%d CPL=%u\n",
758 uSel, offSeg, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
759 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
760 }
761 }
762 else
763 {
764 if (Desc.Legacy.Gen.u2Dpl != pIemCpu->uCpl)
765 {
766 Log(("jmpf %04x:%08x -> CPL != DPL; DPL=%d CPL=%u\n", uSel, offSeg, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
767 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
768 }
769 if ((uSel & X86_SEL_RPL) > pIemCpu->uCpl)
770 {
771 Log(("jmpf %04x:%08x -> RPL > DPL; RPL=%d CPL=%u\n", uSel, offSeg, (uSel & X86_SEL_RPL), pIemCpu->uCpl));
772 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
773 }
774 }
775
776 /* Limit check. (Should alternatively check for non-canonical addresses
777 here, but that is ruled out by offSeg being 32-bit, right?) */
778 uint64_t u64Base;
779 uint32_t cbLimit = X86DESC_LIMIT(Desc.Legacy);
780 if (Desc.Legacy.Gen.u1Granularity)
781 cbLimit = (cbLimit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
782 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
783 u64Base = 0;
784 else
785 {
786 if (offSeg > cbLimit)
787 {
788 Log(("jmpf %04x:%08x -> out of bounds (%#x)\n", uSel, offSeg, cbLimit));
789 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
790 }
791 u64Base = X86DESC_BASE(Desc.Legacy);
792 }
793
794 /*
795 * Ok, everything checked out fine. Now set the accessed bit before
796 * committing the result into CS, CSHID and RIP.
797 */
798 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
799 {
800 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uSel);
801 if (rcStrict != VINF_SUCCESS)
802 return rcStrict;
803#ifdef IEM_VERIFICATION_MODE /** @todo check what VT-x and AMD-V does. */
804 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
805#endif
806 }
807
808 /* commit */
809 pCtx->rip = offSeg;
810 pCtx->cs = uSel & (X86_SEL_MASK | X86_SEL_LDT);
811 pCtx->cs |= pIemCpu->uCpl; /** @todo is this right for conforming segs? or in general? */
812 pCtx->csHid.Attr.u = (Desc.Legacy.u >> (16+16+8)) & UINT32_C(0xf0ff);
813 pCtx->csHid.u32Limit = cbLimit;
814 pCtx->csHid.u64Base = u64Base;
815 /** @todo check if the hidden bits are loaded correctly for 64-bit
816 * mode. */
817 return VINF_SUCCESS;
818 }
819
820 /*
821 * System selector.
822 */
823 if (IEM_IS_LONG_MODE(pIemCpu))
824 switch (Desc.Legacy.Gen.u4Type)
825 {
826 case AMD64_SEL_TYPE_SYS_LDT:
827 case AMD64_SEL_TYPE_SYS_TSS_AVAIL:
828 case AMD64_SEL_TYPE_SYS_TSS_BUSY:
829 case AMD64_SEL_TYPE_SYS_CALL_GATE:
830 case AMD64_SEL_TYPE_SYS_INT_GATE:
831 case AMD64_SEL_TYPE_SYS_TRAP_GATE:
832 /* Call various functions to do the work. */
833 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
834 default:
835 Log(("jmpf %04x:%08x -> wrong sys selector (64-bit): %d\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
836 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
837
838 }
839 switch (Desc.Legacy.Gen.u4Type)
840 {
841 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
842 case X86_SEL_TYPE_SYS_LDT:
843 case X86_SEL_TYPE_SYS_286_CALL_GATE:
844 case X86_SEL_TYPE_SYS_TASK_GATE:
845 case X86_SEL_TYPE_SYS_286_INT_GATE:
846 case X86_SEL_TYPE_SYS_286_TRAP_GATE:
847 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
848 case X86_SEL_TYPE_SYS_386_CALL_GATE:
849 case X86_SEL_TYPE_SYS_386_INT_GATE:
850 case X86_SEL_TYPE_SYS_386_TRAP_GATE:
851 /* Call various functions to do the work. */
852 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
853
854 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
855 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
856 /* Call various functions to do the work. */
857 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
858
859 default:
860 Log(("jmpf %04x:%08x -> wrong sys selector (32-bit): %d\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
861 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
862 }
863}
864
865
866/**
867 * Implements far calls.
868 *
869 * @param uSel The selector.
870 * @param offSeg The segment offset.
871 * @param enmOpSize The operand size (in case we need it).
872 */
873IEM_CIMPL_DEF_3(iemCImpl_callf, uint16_t, uSel, uint64_t, offSeg, IEMMODE, enmOpSize)
874{
875 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
876 VBOXSTRICTRC rcStrict;
877 uint64_t uNewRsp;
878 void *pvRet;
879
880 /*
881 * Real mode and V8086 mode are easy. The only snag seems to be that
882 * CS.limit doesn't change and the limit check is done against the current
883 * limit.
884 */
885 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
886 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
887 {
888 Assert(enmOpSize == IEMMODE_16BIT || enmOpSize == IEMMODE_32BIT);
889
890 /* Check stack first - may #SS(0). */
891 rcStrict = iemMemStackPushBeginSpecial(pIemCpu, enmOpSize == IEMMODE_32BIT ? 6 : 4,
892 &pvRet, &uNewRsp);
893 if (rcStrict != VINF_SUCCESS)
894 return rcStrict;
895
896 /* Check the target address range. */
897 if (offSeg > UINT32_MAX)
898 return iemRaiseGeneralProtectionFault0(pIemCpu);
899
900 /* Everything is fine, push the return address. */
901 if (enmOpSize == IEMMODE_16BIT)
902 {
903 ((uint16_t *)pvRet)[0] = pCtx->ip + cbInstr;
904 ((uint16_t *)pvRet)[1] = pCtx->cs;
905 }
906 else
907 {
908 ((uint32_t *)pvRet)[0] = pCtx->eip + cbInstr;
909 ((uint16_t *)pvRet)[3] = pCtx->cs;
910 }
911 rcStrict = iemMemStackPushCommitSpecial(pIemCpu, pvRet, uNewRsp);
912 if (rcStrict != VINF_SUCCESS)
913 return rcStrict;
914
915 /* Branch. */
916 pCtx->rip = offSeg;
917 pCtx->cs = uSel;
918 pCtx->csHid.u64Base = (uint32_t)uSel << 4;
919 /** @todo Does REM reset the accessed bit here to? (See on jmp far16
920 * after disabling PE.) Check with VT-x and AMD-V. */
921#ifdef IEM_VERIFICATION_MODE
922 pCtx->csHid.Attr.u &= ~X86_SEL_TYPE_ACCESSED;
923#endif
924 return VINF_SUCCESS;
925 }
926
927 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
928}
929
930
931/**
932 * Implements retf.
933 *
934 * @param enmEffOpSize The effective operand size.
935 * @param cbPop The amount of arguments to pop from the stack
936 * (bytes).
937 */
938IEM_CIMPL_DEF_2(iemCImpl_retf, IEMMODE, enmEffOpSize, uint16_t, cbPop)
939{
940 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
941 VBOXSTRICTRC rcStrict;
942 uint64_t uNewRsp;
943
944 /*
945 * Real mode and V8086 mode are easy.
946 */
947 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
948 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
949 {
950 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
951 uint16_t const *pu16Frame;
952 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, enmEffOpSize == IEMMODE_32BIT ? 8 : 4,
953 (void const **)&pu16Frame, &uNewRsp);
954 if (rcStrict != VINF_SUCCESS)
955 return rcStrict;
956 uint32_t uNewEip;
957 uint16_t uNewCS;
958 if (enmEffOpSize == IEMMODE_32BIT)
959 {
960 uNewCS = pu16Frame[2];
961 uNewEip = RT_MAKE_U32(pu16Frame[0], pu16Frame[1]);
962 }
963 else
964 {
965 uNewCS = pu16Frame[1];
966 uNewEip = pu16Frame[0];
967 }
968 /** @todo check how this is supposed to work if sp=0xfffe. */
969
970 /* Check the limit of the new EIP. */
971 /** @todo Intel pseudo code only does the limit check for 16-bit
972 * operands, AMD does not make any distinction. What is right? */
973 if (uNewEip > pCtx->csHid.u32Limit)
974 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
975
976 /* commit the operation. */
977 rcStrict = iemMemStackPopCommitSpecial(pIemCpu, pu16Frame, uNewRsp);
978 if (rcStrict != VINF_SUCCESS)
979 return rcStrict;
980 pCtx->rip = uNewEip;
981 pCtx->cs = uNewCS;
982 pCtx->csHid.u64Base = (uint32_t)uNewCS << 4;
983 /** @todo do we load attribs and limit as well? */
984 if (cbPop)
985 iemRegAddToRsp(pCtx, cbPop);
986 return VINF_SUCCESS;
987 }
988
989 AssertFailed();
990 return VERR_NOT_IMPLEMENTED;
991}
992
993
994/**
995 * Implements retn.
996 *
997 * We're doing this in C because of the \#GP that might be raised if the popped
998 * program counter is out of bounds.
999 *
1000 * @param enmEffOpSize The effective operand size.
1001 * @param cbPop The amount of arguments to pop from the stack
1002 * (bytes).
1003 */
1004IEM_CIMPL_DEF_2(iemCImpl_retn, IEMMODE, enmEffOpSize, uint16_t, cbPop)
1005{
1006 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1007
1008 /* Fetch the RSP from the stack. */
1009 VBOXSTRICTRC rcStrict;
1010 RTUINT64U NewRip;
1011 RTUINT64U NewRsp;
1012 NewRsp.u = pCtx->rsp;
1013 switch (enmEffOpSize)
1014 {
1015 case IEMMODE_16BIT:
1016 NewRip.u = 0;
1017 rcStrict = iemMemStackPopU16Ex(pIemCpu, &NewRip.Words.w0, &NewRsp);
1018 break;
1019 case IEMMODE_32BIT:
1020 NewRip.u = 0;
1021 rcStrict = iemMemStackPopU32Ex(pIemCpu, &NewRip.DWords.dw0, &NewRsp);
1022 break;
1023 case IEMMODE_64BIT:
1024 rcStrict = iemMemStackPopU64Ex(pIemCpu, &NewRip.u, &NewRsp);
1025 break;
1026 IEM_NOT_REACHED_DEFAULT_CASE_RET();
1027 }
1028 if (rcStrict != VINF_SUCCESS)
1029 return rcStrict;
1030
1031 /* Check the new RSP before loading it. */
1032 /** @todo Should test this as the intel+amd pseudo code doesn't mention half
1033 * of it. The canonical test is performed here and for call. */
1034 if (enmEffOpSize != IEMMODE_64BIT)
1035 {
1036 if (NewRip.DWords.dw0 > pCtx->csHid.u32Limit)
1037 {
1038 Log(("retn newrip=%llx - out of bounds (%x) -> #GP\n", NewRip.u, pCtx->csHid.u32Limit));
1039 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
1040 }
1041 }
1042 else
1043 {
1044 if (!IEM_IS_CANONICAL(NewRip.u))
1045 {
1046 Log(("retn newrip=%llx - not canonical -> #GP\n", NewRip.u));
1047 return iemRaiseNotCanonical(pIemCpu);
1048 }
1049 }
1050
1051 /* Commit it. */
1052 pCtx->rip = NewRip.u;
1053 pCtx->rsp = NewRsp.u;
1054 if (cbPop)
1055 iemRegAddToRsp(pCtx, cbPop);
1056
1057 return VINF_SUCCESS;
1058}
1059
1060
1061/**
1062 * Implements leave.
1063 *
1064 * We're doing this in C because messing with the stack registers is annoying
1065 * since they depends on SS attributes.
1066 *
1067 * @param enmEffOpSize The effective operand size.
1068 */
1069IEM_CIMPL_DEF_1(iemCImpl_leave, IEMMODE, enmEffOpSize)
1070{
1071 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1072
1073 /* Calculate the intermediate RSP from RBP and the stack attributes. */
1074 RTUINT64U NewRsp;
1075 if (pCtx->ssHid.Attr.n.u1Long)
1076 {
1077 /** @todo Check that LEAVE actually preserve the high EBP bits. */
1078 NewRsp.u = pCtx->rsp;
1079 NewRsp.Words.w0 = pCtx->bp;
1080 }
1081 else if (pCtx->ssHid.Attr.n.u1DefBig)
1082 NewRsp.u = pCtx->ebp;
1083 else
1084 NewRsp.u = pCtx->rbp;
1085
1086 /* Pop RBP according to the operand size. */
1087 VBOXSTRICTRC rcStrict;
1088 RTUINT64U NewRbp;
1089 switch (enmEffOpSize)
1090 {
1091 case IEMMODE_16BIT:
1092 NewRbp.u = pCtx->rbp;
1093 rcStrict = iemMemStackPopU16Ex(pIemCpu, &NewRbp.Words.w0, &NewRsp);
1094 break;
1095 case IEMMODE_32BIT:
1096 NewRbp.u = 0;
1097 rcStrict = iemMemStackPopU32Ex(pIemCpu, &NewRbp.DWords.dw0, &NewRsp);
1098 break;
1099 case IEMMODE_64BIT:
1100 rcStrict = iemMemStackPopU64Ex(pIemCpu, &NewRbp.u, &NewRsp);
1101 break;
1102 IEM_NOT_REACHED_DEFAULT_CASE_RET();
1103 }
1104 if (rcStrict != VINF_SUCCESS)
1105 return rcStrict;
1106
1107
1108 /* Commit it. */
1109 pCtx->rbp = NewRbp.u;
1110 pCtx->rsp = NewRsp.u;
1111 iemRegAddToRip(pIemCpu, cbInstr);
1112
1113 return VINF_SUCCESS;
1114}
1115
1116
1117/**
1118 * Implements int3 and int XX.
1119 *
1120 * @param u8Int The interrupt vector number.
1121 * @param fIsBpInstr Is it the breakpoint instruction.
1122 */
1123IEM_CIMPL_DEF_2(iemCImpl_int, uint8_t, u8Int, bool, fIsBpInstr)
1124{
1125 Assert(pIemCpu->cXcptRecursions == 0);
1126 return iemRaiseXcptOrInt(pIemCpu,
1127 cbInstr,
1128 u8Int,
1129 (fIsBpInstr ? IEM_XCPT_FLAGS_BP_INSTR : 0) | IEM_XCPT_FLAGS_T_SOFT_INT,
1130 0,
1131 0);
1132}
1133
1134
1135/**
1136 * Implements iret for real mode and V8086 mode.
1137 *
1138 * @param enmEffOpSize The effective operand size.
1139 */
1140IEM_CIMPL_DEF_1(iemCImpl_iret_real_v8086, IEMMODE, enmEffOpSize)
1141{
1142 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1143
1144 /*
1145 * iret throws an exception if VME isn't enabled.
1146 */
1147 if ( pCtx->eflags.Bits.u1VM
1148 && !(pCtx->cr4 & X86_CR4_VME))
1149 return iemRaiseGeneralProtectionFault0(pIemCpu);
1150
1151 /*
1152 * Do the stack bits, but don't commit RSP before everything checks
1153 * out right.
1154 */
1155 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
1156 VBOXSTRICTRC rcStrict;
1157 RTCPTRUNION uFrame;
1158 uint16_t uNewCS;
1159 uint32_t uNewEip;
1160 uint32_t uNewFlags;
1161 uint64_t uNewRsp;
1162 if (enmEffOpSize == IEMMODE_32BIT)
1163 {
1164 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 12, &uFrame.pv, &uNewRsp);
1165 if (rcStrict != VINF_SUCCESS)
1166 return rcStrict;
1167 uNewEip = uFrame.pu32[0];
1168 uNewCS = (uint16_t)uFrame.pu32[1];
1169 uNewFlags = uFrame.pu32[2];
1170 uNewFlags &= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
1171 | X86_EFL_TF | X86_EFL_IF | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT
1172 | X86_EFL_RF /*| X86_EFL_VM*/ | X86_EFL_AC /*|X86_EFL_VIF*/ /*|X86_EFL_VIP*/
1173 | X86_EFL_ID;
1174 uNewFlags |= pCtx->eflags.u & (X86_EFL_VM | X86_EFL_VIF | X86_EFL_VIP | X86_EFL_1);
1175 }
1176 else
1177 {
1178 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 6, &uFrame.pv, &uNewRsp);
1179 if (rcStrict != VINF_SUCCESS)
1180 return rcStrict;
1181 uNewEip = uFrame.pu16[0];
1182 uNewCS = uFrame.pu16[1];
1183 uNewFlags = uFrame.pu16[2];
1184 uNewFlags &= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
1185 | X86_EFL_TF | X86_EFL_IF | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT;
1186 uNewFlags |= pCtx->eflags.u & (UINT32_C(0xffff0000) | X86_EFL_1);
1187 /** @todo The intel pseudo code does not indicate what happens to
1188 * reserved flags. We just ignore them. */
1189 }
1190 /** @todo Check how this is supposed to work if sp=0xfffe. */
1191
1192 /*
1193 * Check the limit of the new EIP.
1194 */
1195 /** @todo Only the AMD pseudo code check the limit here, what's
1196 * right? */
1197 if (uNewEip > pCtx->csHid.u32Limit)
1198 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
1199
1200 /*
1201 * V8086 checks and flag adjustments
1202 */
1203 if (pCtx->eflags.Bits.u1VM)
1204 {
1205 if (pCtx->eflags.Bits.u2IOPL == 3)
1206 {
1207 /* Preserve IOPL and clear RF. */
1208 uNewFlags &= ~(X86_EFL_IOPL | X86_EFL_RF);
1209 uNewFlags |= pCtx->eflags.u & (X86_EFL_IOPL);
1210 }
1211 else if ( enmEffOpSize == IEMMODE_16BIT
1212 && ( !(uNewFlags & X86_EFL_IF)
1213 || !pCtx->eflags.Bits.u1VIP )
1214 && !(uNewFlags & X86_EFL_TF) )
1215 {
1216 /* Move IF to VIF, clear RF and preserve IF and IOPL.*/
1217 uNewFlags &= ~X86_EFL_VIF;
1218 uNewFlags |= (uNewFlags & X86_EFL_IF) << (19 - 9);
1219 uNewFlags &= ~(X86_EFL_IF | X86_EFL_IOPL | X86_EFL_RF);
1220 uNewFlags |= pCtx->eflags.u & (X86_EFL_IF | X86_EFL_IOPL);
1221 }
1222 else
1223 return iemRaiseGeneralProtectionFault0(pIemCpu);
1224 }
1225
1226 /*
1227 * Commit the operation.
1228 */
1229 rcStrict = iemMemStackPopCommitSpecial(pIemCpu, uFrame.pv, uNewRsp);
1230 if (rcStrict != VINF_SUCCESS)
1231 return rcStrict;
1232 pCtx->rip = uNewEip;
1233 pCtx->cs = uNewCS;
1234 pCtx->csHid.u64Base = (uint32_t)uNewCS << 4;
1235 /** @todo do we load attribs and limit as well? */
1236 Assert(uNewFlags & X86_EFL_1);
1237 pCtx->eflags.u = uNewFlags;
1238
1239 return VINF_SUCCESS;
1240}
1241
1242
1243/**
1244 * Implements iret for protected mode
1245 *
1246 * @param enmEffOpSize The effective operand size.
1247 */
1248IEM_CIMPL_DEF_1(iemCImpl_iret_prot, IEMMODE, enmEffOpSize)
1249{
1250 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1251
1252 /*
1253 * Nested task return.
1254 */
1255 if (pCtx->eflags.Bits.u1NT)
1256 {
1257 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
1258 }
1259 /*
1260 * Normal return.
1261 */
1262 else
1263 {
1264 /*
1265 * Do the stack bits, but don't commit RSP before everything checks
1266 * out right.
1267 */
1268 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
1269 VBOXSTRICTRC rcStrict;
1270 RTCPTRUNION uFrame;
1271 uint16_t uNewCS;
1272 uint32_t uNewEip;
1273 uint32_t uNewFlags;
1274 uint64_t uNewRsp;
1275 if (enmEffOpSize == IEMMODE_32BIT)
1276 {
1277 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 12, &uFrame.pv, &uNewRsp);
1278 if (rcStrict != VINF_SUCCESS)
1279 return rcStrict;
1280 uNewEip = uFrame.pu32[0];
1281 uNewCS = (uint16_t)uFrame.pu32[1];
1282 uNewFlags = uFrame.pu32[2];
1283 }
1284 else
1285 {
1286 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 6, &uFrame.pv, &uNewRsp);
1287 if (rcStrict != VINF_SUCCESS)
1288 return rcStrict;
1289 uNewEip = uFrame.pu16[0];
1290 uNewCS = uFrame.pu16[1];
1291 uNewFlags = uFrame.pu16[2];
1292 }
1293 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)uFrame.pv, IEM_ACCESS_STACK_R); /* don't use iemMemStackPopCommitSpecial here. */
1294 if (rcStrict != VINF_SUCCESS)
1295 return rcStrict;
1296
1297 /*
1298 * What are we returning to?
1299 */
1300 if ( (uNewFlags & X86_EFL_VM)
1301 && pIemCpu->uCpl == 0)
1302 {
1303 /* V8086 mode! */
1304 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
1305 }
1306 else
1307 {
1308 /*
1309 * Protected mode.
1310 */
1311 /* Read the CS descriptor. */
1312 if (!(uNewCS & (X86_SEL_MASK | X86_SEL_LDT)))
1313 {
1314 Log(("iret %04x:%08x -> invalid CS selector, #GP(0)\n", uNewCS, uNewEip));
1315 return iemRaiseGeneralProtectionFault0(pIemCpu);
1316 }
1317
1318 IEMSELDESC DescCS;
1319 rcStrict = iemMemFetchSelDesc(pIemCpu, &DescCS, uNewCS);
1320 if (rcStrict != VINF_SUCCESS)
1321 return rcStrict;
1322
1323 /* Must be a code descriptor. */
1324 if (!DescCS.Legacy.Gen.u1DescType)
1325 {
1326 Log(("iret %04x:%08x - CS is system segment (%#x) -> #GP\n", uNewCS, uNewEip, DescCS.Legacy.Gen.u4Type));
1327 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCS);
1328 }
1329 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE))
1330 {
1331 Log(("iret %04x:%08x - not code segment (%#x) -> #GP\n", uNewCS, uNewEip, DescCS.Legacy.Gen.u4Type));
1332 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCS);
1333 }
1334
1335 /* Privilege checks. */
1336 if ((uNewCS & X86_SEL_RPL) < pIemCpu->uCpl)
1337 {
1338 Log(("iret %04x:%08x - RPL < CPL (%d) -> #GP\n", uNewCS, uNewEip, pIemCpu->uCpl));
1339 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCS);
1340 }
1341 if ( (DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF)
1342 && (uNewCS & X86_SEL_RPL) < DescCS.Legacy.Gen.u2Dpl)
1343 {
1344 Log(("iret %04x:%08x - RPL < DPL (%d) -> #GP\n", uNewCS, uNewEip, DescCS.Legacy.Gen.u2Dpl));
1345 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewCS);
1346 }
1347
1348 /* Present? */
1349 if (!DescCS.Legacy.Gen.u1Present)
1350 {
1351 Log(("iret %04x:%08x - CS not present -> #NP\n", uNewCS, uNewEip));
1352 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uNewCS);
1353 }
1354
1355 uint32_t cbLimitCS = X86DESC_LIMIT(DescCS.Legacy);
1356 if (DescCS.Legacy.Gen.u1Granularity)
1357 cbLimitCS = (cbLimitCS << PAGE_SHIFT) | PAGE_OFFSET_MASK;
1358
1359 /*
1360 * Different level?
1361 */
1362 if ((uNewCS & X86_SEL_RPL) != pIemCpu->uCpl)
1363 {
1364 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
1365 }
1366 /*
1367 * Same level.
1368 */
1369 else
1370 {
1371 /* Check EIP. */
1372 if (uNewEip > cbLimitCS)
1373 {
1374 Log(("iret %04x:%08x - EIP is out of bounds (%#x) -> #GP(0)\n", uNewCS, uNewEip, cbLimitCS));
1375 return iemRaiseSelectorBoundsBySelector(pIemCpu, uNewCS);
1376 }
1377
1378 /*
1379 * Commit the changes, marking CS first since it may fail.
1380 */
1381 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1382 {
1383 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uNewCS);
1384 if (rcStrict != VINF_SUCCESS)
1385 return rcStrict;
1386 DescCS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1387 }
1388
1389 pCtx->rip = uNewEip;
1390 pCtx->cs = uNewCS;
1391 pCtx->csHid.Attr.u = X86DESC_GET_HID_ATTR(DescCS.Legacy);
1392 pCtx->csHid.u32Limit = cbLimitCS;
1393 pCtx->csHid.u64Base = X86DESC_BASE(DescCS.Legacy);
1394 pCtx->rsp = uNewRsp;
1395
1396 uint32_t fEFlagsMask = X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
1397 | X86_EFL_TF | X86_EFL_DF | X86_EFL_OF | X86_EFL_NT;
1398 if (enmEffOpSize != IEMMODE_16BIT)
1399 fEFlagsMask |= X86_EFL_RF | X86_EFL_AC | X86_EFL_ID;
1400 if (pIemCpu->uCpl == 0)
1401 fEFlagsMask |= X86_EFL_IF | X86_EFL_IOPL | X86_EFL_VIF | X86_EFL_VIP; /* VM is 0 */
1402 else if (pIemCpu->uCpl <= pCtx->eflags.Bits.u2IOPL)
1403 fEFlagsMask |= X86_EFL_IF;
1404 pCtx->eflags.u &= ~fEFlagsMask;
1405 pCtx->eflags.u |= fEFlagsMask & uNewFlags;
1406 /* Done! */
1407 }
1408 }
1409 }
1410
1411 return VINF_SUCCESS;
1412}
1413
1414
1415/**
1416 * Implements iret for long mode
1417 *
1418 * @param enmEffOpSize The effective operand size.
1419 */
1420IEM_CIMPL_DEF_1(iemCImpl_iret_long, IEMMODE, enmEffOpSize)
1421{
1422 //PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1423 //VBOXSTRICTRC rcStrict;
1424 //uint64_t uNewRsp;
1425
1426 return VERR_NOT_IMPLEMENTED;
1427}
1428
1429
1430/**
1431 * Implements iret.
1432 *
1433 * @param enmEffOpSize The effective operand size.
1434 */
1435IEM_CIMPL_DEF_1(iemCImpl_iret, IEMMODE, enmEffOpSize)
1436{
1437 /*
1438 * Call a mode specific worker.
1439 */
1440 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
1441 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
1442 return IEM_CIMPL_CALL_1(iemCImpl_iret_real_v8086, enmEffOpSize);
1443 if (IEM_IS_LONG_MODE(pIemCpu))
1444 return IEM_CIMPL_CALL_1(iemCImpl_iret_long, enmEffOpSize);
1445
1446 return IEM_CIMPL_CALL_1(iemCImpl_iret_prot, enmEffOpSize);
1447}
1448
1449
1450/**
1451 * Common worker for 'pop SReg', 'mov SReg, GReg' and 'lXs GReg, reg/mem'.
1452 *
1453 * @param iSegReg The segment register number (valid).
1454 * @param uSel The new selector value.
1455 */
1456IEM_CIMPL_DEF_2(iemCImpl_LoadSReg, uint8_t, iSegReg, uint16_t, uSel)
1457{
1458 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1459 uint16_t *pSel = iemSRegRef(pIemCpu, iSegReg);
1460 PCPUMSELREGHID pHid = iemSRegGetHid(pIemCpu, iSegReg);
1461
1462 Assert(iSegReg <= X86_SREG_GS && iSegReg != X86_SREG_CS);
1463
1464 /*
1465 * Real mode and V8086 mode are easy.
1466 */
1467 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
1468 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
1469 {
1470 *pSel = uSel;
1471 pHid->u64Base = (uint32_t)uSel << 4;
1472 /** @todo Does the CPU actually load limits and attributes in the
1473 * real/V8086 mode segment load case? It doesn't for CS in far
1474 * jumps... Affects unreal mode. */
1475 pHid->u32Limit = 0xffff;
1476 pHid->Attr.u = 0;
1477 pHid->Attr.n.u1Present = 1;
1478 pHid->Attr.n.u1DescType = 1;
1479 pHid->Attr.n.u4Type = iSegReg != X86_SREG_CS
1480 ? X86_SEL_TYPE_RW
1481 : X86_SEL_TYPE_READ | X86_SEL_TYPE_CODE;
1482
1483 iemRegAddToRip(pIemCpu, cbInstr);
1484 return VINF_SUCCESS;
1485 }
1486
1487 /*
1488 * Protected mode.
1489 *
1490 * Check if it's a null segment selector value first, that's OK for DS, ES,
1491 * FS and GS. If not null, then we have to load and parse the descriptor.
1492 */
1493 if (!(uSel & (X86_SEL_MASK | X86_SEL_LDT)))
1494 {
1495 if (iSegReg == X86_SREG_SS)
1496 {
1497 if ( pIemCpu->enmCpuMode != IEMMODE_64BIT
1498 || pIemCpu->uCpl != 0
1499 || uSel != 0) /** @todo We cannot 'mov ss, 3' in 64-bit kernel mode, can we? */
1500 {
1501 Log(("load sreg -> invalid stack selector, #GP(0)\n", uSel));
1502 return iemRaiseGeneralProtectionFault0(pIemCpu);
1503 }
1504
1505 /* In 64-bit kernel mode, the stack can be 0 because of the way
1506 interrupts are dispatched when in kernel ctx. Just load the
1507 selector value into the register and leave the hidden bits
1508 as is. */
1509 *pSel = uSel;
1510 iemRegAddToRip(pIemCpu, cbInstr);
1511 return VINF_SUCCESS;
1512 }
1513
1514 *pSel = uSel; /* Not RPL, remember :-) */
1515 if ( pIemCpu->enmCpuMode == IEMMODE_64BIT
1516 && iSegReg != X86_SREG_FS
1517 && iSegReg != X86_SREG_GS)
1518 {
1519 /** @todo figure out what this actually does, it works. Needs
1520 * testcase! */
1521 pHid->Attr.u = 0;
1522 pHid->Attr.n.u1Present = 1;
1523 pHid->Attr.n.u1Long = 1;
1524 pHid->Attr.n.u4Type = X86_SEL_TYPE_RW;
1525 pHid->Attr.n.u2Dpl = 3;
1526 pHid->u32Limit = 0;
1527 pHid->u64Base = 0;
1528 }
1529 else
1530 {
1531 pHid->Attr.u = 0;
1532 pHid->u32Limit = 0;
1533 pHid->u64Base = 0;
1534 }
1535 iemRegAddToRip(pIemCpu, cbInstr);
1536 return VINF_SUCCESS;
1537 }
1538
1539 /* Fetch the descriptor. */
1540 IEMSELDESC Desc;
1541 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uSel);
1542 if (rcStrict != VINF_SUCCESS)
1543 return rcStrict;
1544
1545 /* Check GPs first. */
1546 if (!Desc.Legacy.Gen.u1DescType)
1547 {
1548 Log(("load sreg %d - system selector (%#x) -> #GP\n", iSegReg, uSel, Desc.Legacy.Gen.u4Type));
1549 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1550 }
1551 if (iSegReg == X86_SREG_SS) /* SS gets different treatment */
1552 {
1553 if ( (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
1554 || !(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
1555 {
1556 Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
1557 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1558 }
1559 if ( (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
1560 || !(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
1561 {
1562 Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
1563 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1564 }
1565 if ((uSel & X86_SEL_RPL) != pIemCpu->uCpl)
1566 {
1567 Log(("load sreg SS, %#x - RPL and CPL (%d) differs -> #GP\n", uSel, pIemCpu->uCpl));
1568 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1569 }
1570 if (Desc.Legacy.Gen.u2Dpl != pIemCpu->uCpl)
1571 {
1572 Log(("load sreg SS, %#x - DPL (%d) and CPL (%d) differs -> #GP\n", uSel, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
1573 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1574 }
1575 }
1576 else
1577 {
1578 if ((Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
1579 {
1580 Log(("load sreg%u, %#x - execute only segment -> #GP\n", iSegReg, uSel));
1581 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1582 }
1583 if ( (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
1584 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
1585 {
1586#if 0 /* this is what intel says. */
1587 if ( (uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl
1588 && pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
1589 {
1590 Log(("load sreg%u, %#x - both RPL (%d) and CPL (%d) are greater than DPL (%d) -> #GP\n",
1591 iSegReg, uSel, (uSel & X86_SEL_RPL), pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
1592 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1593 }
1594#else /* this is what makes more sense. */
1595 if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
1596 {
1597 Log(("load sreg%u, %#x - RPL (%d) is greater than DPL (%d) -> #GP\n",
1598 iSegReg, uSel, (uSel & X86_SEL_RPL), Desc.Legacy.Gen.u2Dpl));
1599 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1600 }
1601 if (pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
1602 {
1603 Log(("load sreg%u, %#x - CPL (%d) is greater than DPL (%d) -> #GP\n",
1604 iSegReg, uSel, pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
1605 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
1606 }
1607#endif
1608 }
1609 }
1610
1611 /* Is it there? */
1612 if (!Desc.Legacy.Gen.u1Present)
1613 {
1614 Log(("load sreg%d,%#x - segment not present -> #NP\n", iSegReg, uSel));
1615 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uSel);
1616 }
1617
1618 /* The the base and limit. */
1619 uint64_t u64Base;
1620 uint32_t cbLimit = X86DESC_LIMIT(Desc.Legacy);
1621 if (Desc.Legacy.Gen.u1Granularity)
1622 cbLimit = (cbLimit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
1623
1624 if ( pIemCpu->enmCpuMode == IEMMODE_64BIT
1625 && iSegReg < X86_SREG_FS)
1626 u64Base = 0;
1627 else
1628 u64Base = X86DESC_BASE(Desc.Legacy);
1629
1630 /*
1631 * Ok, everything checked out fine. Now set the accessed bit before
1632 * committing the result into the registers.
1633 */
1634 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1635 {
1636 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uSel);
1637 if (rcStrict != VINF_SUCCESS)
1638 return rcStrict;
1639 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1640 }
1641
1642 /* commit */
1643 *pSel = uSel;
1644 pHid->Attr.u = (Desc.Legacy.u >> (16+16+8)) & UINT32_C(0xf0ff); /** @todo do we have a define for 0xf0ff? */
1645 pHid->u32Limit = cbLimit;
1646 pHid->u64Base = u64Base;
1647
1648 /** @todo check if the hidden bits are loaded correctly for 64-bit
1649 * mode. */
1650
1651 iemRegAddToRip(pIemCpu, cbInstr);
1652 return VINF_SUCCESS;
1653}
1654
1655
1656/**
1657 * Implements 'mov SReg, r/m'.
1658 *
1659 * @param iSegReg The segment register number (valid).
1660 * @param uSel The new selector value.
1661 */
1662IEM_CIMPL_DEF_2(iemCImpl_load_SReg, uint8_t, iSegReg, uint16_t, uSel)
1663{
1664 VBOXSTRICTRC rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
1665 if (rcStrict == VINF_SUCCESS)
1666 {
1667 if (iSegReg == X86_SREG_SS)
1668 {
1669 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1670 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
1671 }
1672 }
1673 return rcStrict;
1674}
1675
1676
1677/**
1678 * Implements 'pop SReg'.
1679 *
1680 * @param iSegReg The segment register number (valid).
1681 * @param enmEffOpSize The efficient operand size (valid).
1682 */
1683IEM_CIMPL_DEF_2(iemCImpl_pop_Sreg, uint8_t, iSegReg, IEMMODE, enmEffOpSize)
1684{
1685 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1686 VBOXSTRICTRC rcStrict;
1687
1688 /*
1689 * Read the selector off the stack and join paths with mov ss, reg.
1690 */
1691 RTUINT64U TmpRsp;
1692 TmpRsp.u = pCtx->rsp;
1693 switch (enmEffOpSize)
1694 {
1695 case IEMMODE_16BIT:
1696 {
1697 uint16_t uSel;
1698 rcStrict = iemMemStackPopU16Ex(pIemCpu, &uSel, &TmpRsp);
1699 if (rcStrict == VINF_SUCCESS)
1700 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
1701 break;
1702 }
1703
1704 case IEMMODE_32BIT:
1705 {
1706 uint32_t u32Value;
1707 rcStrict = iemMemStackPopU32Ex(pIemCpu, &u32Value, &TmpRsp);
1708 if (rcStrict == VINF_SUCCESS)
1709 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, (uint16_t)u32Value);
1710 break;
1711 }
1712
1713 case IEMMODE_64BIT:
1714 {
1715 uint64_t u64Value;
1716 rcStrict = iemMemStackPopU64Ex(pIemCpu, &u64Value, &TmpRsp);
1717 if (rcStrict == VINF_SUCCESS)
1718 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, (uint16_t)u64Value);
1719 break;
1720 }
1721 IEM_NOT_REACHED_DEFAULT_CASE_RET();
1722 }
1723
1724 /*
1725 * Commit the stack on success.
1726 */
1727 if (rcStrict == VINF_SUCCESS)
1728 {
1729 pCtx->rsp = TmpRsp.u;
1730 if (iSegReg == X86_SREG_SS)
1731 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
1732 }
1733 return rcStrict;
1734}
1735
1736
1737/**
1738 * Implements lgs, lfs, les, lds & lss.
1739 */
1740IEM_CIMPL_DEF_5(iemCImpl_load_SReg_Greg,
1741 uint16_t, uSel,
1742 uint64_t, offSeg,
1743 uint8_t, iSegReg,
1744 uint8_t, iGReg,
1745 IEMMODE, enmEffOpSize)
1746{
1747 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1748 VBOXSTRICTRC rcStrict;
1749
1750 /*
1751 * Use iemCImpl_LoadSReg to do the tricky segment register loading.
1752 */
1753 /** @todo verify and test that mov, pop and lXs works the segment
1754 * register loading in the exact same way. */
1755 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
1756 if (rcStrict == VINF_SUCCESS)
1757 {
1758 switch (enmEffOpSize)
1759 {
1760 case IEMMODE_16BIT:
1761 *(uint16_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
1762 break;
1763 case IEMMODE_32BIT:
1764 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
1765 break;
1766 case IEMMODE_64BIT:
1767 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
1768 break;
1769 IEM_NOT_REACHED_DEFAULT_CASE_RET();
1770 }
1771 }
1772
1773 return rcStrict;
1774}
1775
1776
1777/**
1778 * Implements lgdt.
1779 *
1780 * @param iEffSeg The segment of the new ldtr contents
1781 * @param GCPtrEffSrc The address of the new ldtr contents.
1782 * @param enmEffOpSize The effective operand size.
1783 */
1784IEM_CIMPL_DEF_3(iemCImpl_lgdt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc, IEMMODE, enmEffOpSize)
1785{
1786 if (pIemCpu->uCpl != 0)
1787 return iemRaiseGeneralProtectionFault0(pIemCpu);
1788 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
1789
1790 /*
1791 * Fetch the limit and base address.
1792 */
1793 uint16_t cbLimit;
1794 RTGCPTR GCPtrBase;
1795 VBOXSTRICTRC rcStrict = iemMemFetchDataXdtr(pIemCpu, &cbLimit, &GCPtrBase, iEffSeg, GCPtrEffSrc, enmEffOpSize);
1796 if (rcStrict == VINF_SUCCESS)
1797 {
1798 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
1799 rcStrict = CPUMSetGuestGDTR(IEMCPU_TO_VMCPU(pIemCpu), GCPtrBase, cbLimit);
1800 else
1801 {
1802 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1803 pCtx->gdtr.cbGdt = cbLimit;
1804 pCtx->gdtr.pGdt = GCPtrBase;
1805 }
1806 if (rcStrict == VINF_SUCCESS)
1807 iemRegAddToRip(pIemCpu, cbInstr);
1808 }
1809 return rcStrict;
1810}
1811
1812
1813/**
1814 * Implements lidt.
1815 *
1816 * @param iEffSeg The segment of the new ldtr contents
1817 * @param GCPtrEffSrc The address of the new ldtr contents.
1818 * @param enmEffOpSize The effective operand size.
1819 */
1820IEM_CIMPL_DEF_3(iemCImpl_lidt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc, IEMMODE, enmEffOpSize)
1821{
1822 if (pIemCpu->uCpl != 0)
1823 return iemRaiseGeneralProtectionFault0(pIemCpu);
1824 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
1825
1826 /*
1827 * Fetch the limit and base address.
1828 */
1829 uint16_t cbLimit;
1830 RTGCPTR GCPtrBase;
1831 VBOXSTRICTRC rcStrict = iemMemFetchDataXdtr(pIemCpu, &cbLimit, &GCPtrBase, iEffSeg, GCPtrEffSrc, enmEffOpSize);
1832 if (rcStrict == VINF_SUCCESS)
1833 {
1834 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
1835 rcStrict = CPUMSetGuestIDTR(IEMCPU_TO_VMCPU(pIemCpu), GCPtrBase, cbLimit);
1836 else
1837 {
1838 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1839 pCtx->idtr.cbIdt = cbLimit;
1840 pCtx->idtr.pIdt = GCPtrBase;
1841 }
1842 if (rcStrict == VINF_SUCCESS)
1843 iemRegAddToRip(pIemCpu, cbInstr);
1844 }
1845 return rcStrict;
1846}
1847
1848
1849/**
1850 * Implements lldt.
1851 *
1852 * @param uNewLdt The new LDT selector value.
1853 */
1854IEM_CIMPL_DEF_1(iemCImpl_lldt, uint16_t, uNewLdt)
1855{
1856 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1857
1858 /*
1859 * Check preconditions.
1860 */
1861 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
1862 {
1863 Log(("lldt %04x - real or v8086 mode -> #GP(0)\n", uNewLdt));
1864 return iemRaiseUndefinedOpcode(pIemCpu);
1865 }
1866 if (pIemCpu->uCpl != 0)
1867 {
1868 Log(("lldt %04x - CPL is %d -> #GP(0)\n", uNewLdt, pIemCpu->uCpl));
1869 return iemRaiseGeneralProtectionFault0(pIemCpu);
1870 }
1871 if (uNewLdt & X86_SEL_LDT)
1872 {
1873 Log(("lldt %04x - LDT selector -> #GP\n", uNewLdt));
1874 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewLdt);
1875 }
1876
1877 /*
1878 * Now, loading a NULL selector is easy.
1879 */
1880 if ((uNewLdt & X86_SEL_MASK) == 0)
1881 {
1882 Log(("lldt %04x: Loading NULL selector.\n", uNewLdt));
1883 /** @todo check if the actual value is loaded or if it's always 0. */
1884 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
1885 CPUMSetGuestLDTR(IEMCPU_TO_VMCPU(pIemCpu), 0);
1886 else
1887 pCtx->ldtr = 0;
1888 pCtx->ldtrHid.Attr.u = 0;
1889 pCtx->ldtrHid.u64Base = 0;
1890 pCtx->ldtrHid.u32Limit = 0;
1891
1892 iemRegAddToRip(pIemCpu, cbInstr);
1893 return VINF_SUCCESS;
1894 }
1895
1896 /*
1897 * Read the descriptor.
1898 */
1899 IEMSELDESC Desc;
1900 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uNewLdt);
1901 if (rcStrict != VINF_SUCCESS)
1902 return rcStrict;
1903
1904 /* Check GPs first. */
1905 if (Desc.Legacy.Gen.u1DescType)
1906 {
1907 Log(("lldt %#x - not system selector (type %x) -> #GP\n", uNewLdt, Desc.Legacy.Gen.u4Type));
1908 return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & X86_SEL_MASK);
1909 }
1910 if (Desc.Legacy.Gen.u4Type != X86_SEL_TYPE_SYS_LDT)
1911 {
1912 Log(("lldt %#x - not LDT selector (type %x) -> #GP\n", uNewLdt, Desc.Legacy.Gen.u4Type));
1913 return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & X86_SEL_MASK);
1914 }
1915 uint64_t u64Base;
1916 if (!IEM_IS_LONG_MODE(pIemCpu))
1917 u64Base = X86DESC_BASE(Desc.Legacy);
1918 else
1919 {
1920 if (Desc.Long.Gen.u5Zeros)
1921 {
1922 Log(("lldt %#x - u5Zeros=%#x -> #GP\n", uNewLdt, Desc.Long.Gen.u5Zeros));
1923 return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & X86_SEL_MASK);
1924 }
1925
1926 u64Base = X86DESC64_BASE(Desc.Long);
1927 if (!IEM_IS_CANONICAL(u64Base))
1928 {
1929 Log(("lldt %#x - non-canonical base address %#llx -> #GP\n", uNewLdt, u64Base));
1930 return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & X86_SEL_MASK);
1931 }
1932 }
1933
1934 /* NP */
1935 if (!Desc.Legacy.Gen.u1Present)
1936 {
1937 Log(("lldt %#x - segment not present -> #NP\n", uNewLdt));
1938 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uNewLdt);
1939 }
1940
1941 /*
1942 * It checks out alright, update the registers.
1943 */
1944/** @todo check if the actual value is loaded or if the RPL is dropped */
1945 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
1946 CPUMSetGuestLDTR(IEMCPU_TO_VMCPU(pIemCpu), uNewLdt & X86_SEL_MASK);
1947 else
1948 pCtx->ldtr = uNewLdt & X86_SEL_MASK;
1949 pCtx->ldtrHid.Attr.u = X86DESC_GET_HID_ATTR(Desc.Legacy);
1950 pCtx->ldtrHid.u32Limit = X86DESC_LIMIT(Desc.Legacy);
1951 pCtx->ldtrHid.u64Base = u64Base;
1952
1953 iemRegAddToRip(pIemCpu, cbInstr);
1954 return VINF_SUCCESS;
1955}
1956
1957
1958/**
1959 * Implements lldt.
1960 *
1961 * @param uNewLdt The new LDT selector value.
1962 */
1963IEM_CIMPL_DEF_1(iemCImpl_ltr, uint16_t, uNewTr)
1964{
1965 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1966
1967 /*
1968 * Check preconditions.
1969 */
1970 if (IEM_IS_REAL_OR_V86_MODE(pIemCpu))
1971 {
1972 Log(("ltr %04x - real or v8086 mode -> #GP(0)\n", uNewTr));
1973 return iemRaiseUndefinedOpcode(pIemCpu);
1974 }
1975 if (pIemCpu->uCpl != 0)
1976 {
1977 Log(("ltr %04x - CPL is %d -> #GP(0)\n", uNewTr, pIemCpu->uCpl));
1978 return iemRaiseGeneralProtectionFault0(pIemCpu);
1979 }
1980 if (uNewTr & X86_SEL_LDT)
1981 {
1982 Log(("ltr %04x - LDT selector -> #GP\n", uNewTr));
1983 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewTr);
1984 }
1985 if ((uNewTr & X86_SEL_MASK) == 0)
1986 {
1987 Log(("ltr %04x - NULL selector -> #GP(0)\n", uNewTr));
1988 return iemRaiseGeneralProtectionFault0(pIemCpu);
1989 }
1990
1991 /*
1992 * Read the descriptor.
1993 */
1994 IEMSELDESC Desc;
1995 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uNewTr);
1996 if (rcStrict != VINF_SUCCESS)
1997 return rcStrict;
1998
1999 /* Check GPs first. */
2000 if (Desc.Legacy.Gen.u1DescType)
2001 {
2002 Log(("ltr %#x - not system selector (type %x) -> #GP\n", uNewTr, Desc.Legacy.Gen.u4Type));
2003 return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & X86_SEL_MASK);
2004 }
2005 if ( Desc.Legacy.Gen.u4Type != X86_SEL_TYPE_SYS_386_TSS_AVAIL /* same as AMD64_SEL_TYPE_SYS_TSS_AVAIL */
2006 && ( Desc.Legacy.Gen.u4Type != X86_SEL_TYPE_SYS_286_TSS_AVAIL
2007 || IEM_IS_LONG_MODE(pIemCpu)) )
2008 {
2009 Log(("ltr %#x - not an available TSS selector (type %x) -> #GP\n", uNewTr, Desc.Legacy.Gen.u4Type));
2010 return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & X86_SEL_MASK);
2011 }
2012 uint64_t u64Base;
2013 if (!IEM_IS_LONG_MODE(pIemCpu))
2014 u64Base = X86DESC_BASE(Desc.Legacy);
2015 else
2016 {
2017 if (Desc.Long.Gen.u5Zeros)
2018 {
2019 Log(("ltr %#x - u5Zeros=%#x -> #GP\n", uNewTr, Desc.Long.Gen.u5Zeros));
2020 return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & X86_SEL_MASK);
2021 }
2022
2023 u64Base = X86DESC64_BASE(Desc.Long);
2024 if (!IEM_IS_CANONICAL(u64Base))
2025 {
2026 Log(("ltr %#x - non-canonical base address %#llx -> #GP\n", uNewTr, u64Base));
2027 return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & X86_SEL_MASK);
2028 }
2029 }
2030
2031 /* NP */
2032 if (!Desc.Legacy.Gen.u1Present)
2033 {
2034 Log(("ltr %#x - segment not present -> #NP\n", uNewTr));
2035 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uNewTr);
2036 }
2037
2038 /*
2039 * Set it busy.
2040 * Note! Intel says this should lock down the whole descriptor, but we'll
2041 * restrict our selves to 32-bit for now due to lack of inline
2042 * assembly and such.
2043 */
2044 void *pvDesc;
2045 rcStrict = iemMemMap(pIemCpu, &pvDesc, 8, UINT8_MAX, pCtx->gdtr.pGdt, IEM_ACCESS_DATA_RW);
2046 if (rcStrict != VINF_SUCCESS)
2047 return rcStrict;
2048 switch ((uintptr_t)pvDesc & 3)
2049 {
2050 case 0: ASMAtomicBitSet(pvDesc, 40 + 1); break;
2051 case 1: ASMAtomicBitSet((uint8_t *)pvDesc + 3, 40 + 1 - 24); break;
2052 case 2: ASMAtomicBitSet((uint8_t *)pvDesc + 3, 40 + 1 - 16); break;
2053 case 3: ASMAtomicBitSet((uint8_t *)pvDesc + 3, 40 + 1 - 8); break;
2054 }
2055 rcStrict = iemMemMap(pIemCpu, &pvDesc, 8, UINT8_MAX, pCtx->gdtr.pGdt, IEM_ACCESS_DATA_RW);
2056 if (rcStrict != VINF_SUCCESS)
2057 return rcStrict;
2058 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_SYS_TSS_BUSY_MASK;
2059
2060 /*
2061 * It checks out alright, update the registers.
2062 */
2063/** @todo check if the actual value is loaded or if the RPL is dropped */
2064 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2065 CPUMSetGuestTR(IEMCPU_TO_VMCPU(pIemCpu), uNewTr & X86_SEL_MASK);
2066 else
2067 pCtx->tr = uNewTr & X86_SEL_MASK;
2068 pCtx->trHid.Attr.u = X86DESC_GET_HID_ATTR(Desc.Legacy);
2069 pCtx->trHid.u32Limit = X86DESC_LIMIT(Desc.Legacy);
2070 pCtx->trHid.u64Base = u64Base;
2071
2072 iemRegAddToRip(pIemCpu, cbInstr);
2073 return VINF_SUCCESS;
2074}
2075
2076
2077/**
2078 * Implements mov GReg,CRx.
2079 *
2080 * @param iGReg The general register to store the CRx value in.
2081 * @param iCrReg The CRx register to read (valid).
2082 */
2083IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Cd, uint8_t, iGReg, uint8_t, iCrReg)
2084{
2085 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2086 if (pIemCpu->uCpl != 0)
2087 return iemRaiseGeneralProtectionFault0(pIemCpu);
2088 Assert(!pCtx->eflags.Bits.u1VM);
2089
2090 /* read it */
2091 uint64_t crX;
2092 switch (iCrReg)
2093 {
2094 case 0: crX = pCtx->cr0; break;
2095 case 2: crX = pCtx->cr2; break;
2096 case 3: crX = pCtx->cr3; break;
2097 case 4: crX = pCtx->cr4; break;
2098 case 8:
2099 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2100 AssertFailedReturn(VERR_NOT_IMPLEMENTED); /** @todo implement CR8 reading and writing. */
2101 else
2102 crX = 0xff;
2103 break;
2104 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
2105 }
2106
2107 /* store it */
2108 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
2109 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = crX;
2110 else
2111 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = (uint32_t)crX;
2112
2113 iemRegAddToRip(pIemCpu, cbInstr);
2114 return VINF_SUCCESS;
2115}
2116
2117
2118/**
2119 * Used to implemented 'mov CRx,GReg' and 'lmsw r/m16'.
2120 *
2121 * @param iCrReg The CRx register to write (valid).
2122 * @param uNewCrX The new value.
2123 */
2124IEM_CIMPL_DEF_2(iemCImpl_load_CrX, uint8_t, iCrReg, uint64_t, uNewCrX)
2125{
2126 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2127 PVMCPU pVCpu = IEMCPU_TO_VMCPU(pIemCpu);
2128 VBOXSTRICTRC rcStrict;
2129 int rc;
2130
2131 /*
2132 * Try store it.
2133 * Unfortunately, CPUM only does a tiny bit of the work.
2134 */
2135 switch (iCrReg)
2136 {
2137 case 0:
2138 {
2139 /*
2140 * Perform checks.
2141 */
2142 uint64_t const uOldCrX = pCtx->cr0;
2143 uNewCrX |= X86_CR0_ET; /* hardcoded */
2144
2145 /* Check for reserved bits. */
2146 uint32_t const fValid = X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS
2147 | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM
2148 | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG;
2149 if (uNewCrX & ~(uint64_t)fValid)
2150 {
2151 Log(("Trying to set reserved CR0 bits: NewCR0=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
2152 return iemRaiseGeneralProtectionFault0(pIemCpu);
2153 }
2154
2155 /* Check for invalid combinations. */
2156 if ( (uNewCrX & X86_CR0_PG)
2157 && !(uNewCrX & X86_CR0_PE) )
2158 {
2159 Log(("Trying to set CR0.PG without CR0.PE\n"));
2160 return iemRaiseGeneralProtectionFault0(pIemCpu);
2161 }
2162
2163 if ( !(uNewCrX & X86_CR0_CD)
2164 && (uNewCrX & X86_CR0_NW) )
2165 {
2166 Log(("Trying to clear CR0.CD while leaving CR0.NW set\n"));
2167 return iemRaiseGeneralProtectionFault0(pIemCpu);
2168 }
2169
2170 /* Long mode consistency checks. */
2171 if ( (uNewCrX & X86_CR0_PG)
2172 && !(uOldCrX & X86_CR0_PG)
2173 && (pCtx->msrEFER & MSR_K6_EFER_LME) )
2174 {
2175 if (!(pCtx->cr4 & X86_CR4_PAE))
2176 {
2177 Log(("Trying to enabled long mode paging without CR4.PAE set\n"));
2178 return iemRaiseGeneralProtectionFault0(pIemCpu);
2179 }
2180 if (pCtx->csHid.Attr.n.u1Long)
2181 {
2182 Log(("Trying to enabled long mode paging with a long CS descriptor loaded.\n"));
2183 return iemRaiseGeneralProtectionFault0(pIemCpu);
2184 }
2185 }
2186
2187 /** @todo check reserved PDPTR bits as AMD states. */
2188
2189 /*
2190 * Change CR0.
2191 */
2192 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2193 {
2194 rc = CPUMSetGuestCR0(pVCpu, uNewCrX);
2195 AssertRCSuccessReturn(rc, RT_FAILURE_NP(rc) ? rc : VERR_INTERNAL_ERROR_3);
2196 }
2197 else
2198 pCtx->cr0 = uNewCrX;
2199 Assert(pCtx->cr0 == uNewCrX);
2200
2201 /*
2202 * Change EFER.LMA if entering or leaving long mode.
2203 */
2204 if ( (uNewCrX & X86_CR0_PG) != (uOldCrX & X86_CR0_PG)
2205 && (pCtx->msrEFER & MSR_K6_EFER_LME) )
2206 {
2207 uint64_t NewEFER = pCtx->msrEFER;
2208 if (uNewCrX & X86_CR0_PG)
2209 NewEFER |= MSR_K6_EFER_LME;
2210 else
2211 NewEFER &= ~MSR_K6_EFER_LME;
2212
2213 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2214 CPUMSetGuestEFER(pVCpu, NewEFER);
2215 else
2216 pCtx->msrEFER = NewEFER;
2217 Assert(pCtx->msrEFER == NewEFER);
2218 }
2219
2220 /*
2221 * Inform PGM.
2222 */
2223 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2224 {
2225 if ( (uNewCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
2226 != (uOldCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) )
2227 {
2228 rc = PGMFlushTLB(pVCpu, pCtx->cr3, true /* global */);
2229 AssertRCReturn(rc, rc);
2230 /* ignore informational status codes */
2231 }
2232 rcStrict = PGMChangeMode(pVCpu, pCtx->cr0, pCtx->cr4, pCtx->msrEFER);
2233 /** @todo Status code management. */
2234 }
2235 else
2236 rcStrict = VINF_SUCCESS;
2237 break;
2238 }
2239
2240 /*
2241 * CR2 can be changed without any restrictions.
2242 */
2243 case 2:
2244 pCtx->cr2 = uNewCrX;
2245 rcStrict = VINF_SUCCESS;
2246 break;
2247
2248 /*
2249 * CR3 is relatively simple, although AMD and Intel have different
2250 * accounts of how setting reserved bits are handled. We take intel's
2251 * word for the lower bits and AMD's for the high bits (63:52).
2252 */
2253 /** @todo Testcase: Setting reserved bits in CR3, especially before
2254 * enabling paging. */
2255 case 3:
2256 {
2257 /* check / mask the value. */
2258 if (uNewCrX & UINT64_C(0xfff0000000000000))
2259 {
2260 Log(("Trying to load CR3 with invalid high bits set: %#llx\n", uNewCrX));
2261 return iemRaiseGeneralProtectionFault0(pIemCpu);
2262 }
2263
2264 uint64_t fValid;
2265 if ( (pCtx->cr4 & X86_CR4_PAE)
2266 && (pCtx->msrEFER & MSR_K6_EFER_LME))
2267 fValid = UINT64_C(0x000ffffffffff014);
2268 else if (pCtx->cr4 & X86_CR4_PAE)
2269 fValid = UINT64_C(0xfffffff4);
2270 else
2271 fValid = UINT64_C(0xfffff014);
2272 if (uNewCrX & ~fValid)
2273 {
2274 Log(("Automatically clearing reserved bits in CR3 load: NewCR3=%#llx ClearedBits=%#llx\n",
2275 uNewCrX, uNewCrX & ~fValid));
2276 uNewCrX &= fValid;
2277 }
2278
2279 /** @todo If we're in PAE mode we should check the PDPTRs for
2280 * invalid bits. */
2281
2282 /* Make the change. */
2283 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2284 {
2285 rc = CPUMSetGuestCR3(pVCpu, uNewCrX);
2286 AssertRCSuccessReturn(rc, rc);
2287 }
2288 else
2289 pCtx->cr3 = uNewCrX;
2290
2291 /* Inform PGM. */
2292 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2293 {
2294 if (pCtx->cr0 & X86_CR0_PG)
2295 {
2296 rc = PGMFlushTLB(pVCpu, pCtx->cr3, !(pCtx->cr3 & X86_CR4_PGE));
2297 AssertRCReturn(rc, rc);
2298 /* ignore informational status codes */
2299 /** @todo status code management */
2300 }
2301 }
2302 rcStrict = VINF_SUCCESS;
2303 break;
2304 }
2305
2306 /*
2307 * CR4 is a bit more tedious as there are bits which cannot be cleared
2308 * under some circumstances and such.
2309 */
2310 case 4:
2311 {
2312 uint64_t const uOldCrX = pCtx->cr0;
2313
2314 /* reserved bits */
2315 uint32_t fValid = X86_CR4_VME | X86_CR4_PVI
2316 | X86_CR4_TSD | X86_CR4_DE
2317 | X86_CR4_PSE | X86_CR4_PAE
2318 | X86_CR4_MCE | X86_CR4_PGE
2319 | X86_CR4_PCE | X86_CR4_OSFSXR
2320 | X86_CR4_OSXMMEEXCPT;
2321 //if (xxx)
2322 // fValid |= X86_CR4_VMXE;
2323 //if (xxx)
2324 // fValid |= X86_CR4_OSXSAVE;
2325 if (uNewCrX & ~(uint64_t)fValid)
2326 {
2327 Log(("Trying to set reserved CR4 bits: NewCR4=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
2328 return iemRaiseGeneralProtectionFault0(pIemCpu);
2329 }
2330
2331 /* long mode checks. */
2332 if ( (uOldCrX & X86_CR4_PAE)
2333 && !(uNewCrX & X86_CR4_PAE)
2334 && (pCtx->msrEFER & MSR_K6_EFER_LMA) )
2335 {
2336 Log(("Trying to set clear CR4.PAE while long mode is active\n"));
2337 return iemRaiseGeneralProtectionFault0(pIemCpu);
2338 }
2339
2340
2341 /*
2342 * Change it.
2343 */
2344 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2345 {
2346 rc = CPUMSetGuestCR4(pVCpu, uNewCrX);
2347 AssertRCSuccessReturn(rc, rc);
2348 }
2349 else
2350 pCtx->cr4 = uNewCrX;
2351 Assert(pCtx->cr4 == uNewCrX);
2352
2353 /*
2354 * Notify SELM and PGM.
2355 */
2356 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2357 {
2358 /* SELM - VME may change things wrt to the TSS shadowing. */
2359 if ((uNewCrX ^ uOldCrX) & X86_CR4_VME)
2360 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);
2361
2362 /* PGM - flushing and mode. */
2363 if ( (uNewCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
2364 != (uOldCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) )
2365 {
2366 rc = PGMFlushTLB(pVCpu, pCtx->cr3, true /* global */);
2367 AssertRCReturn(rc, rc);
2368 /* ignore informational status codes */
2369 }
2370 rcStrict = PGMChangeMode(pVCpu, pCtx->cr0, pCtx->cr4, pCtx->msrEFER);
2371 /** @todo Status code management. */
2372 }
2373 else
2374 rcStrict = VINF_SUCCESS;
2375 break;
2376 }
2377
2378 /*
2379 * CR8 maps to the APIC TPR.
2380 */
2381 case 8:
2382 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2383 AssertFailedReturn(VERR_NOT_IMPLEMENTED); /** @todo implement CR8 reading and writing. */
2384 else
2385 rcStrict = VINF_SUCCESS;
2386 break;
2387
2388 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
2389 }
2390
2391 /*
2392 * Advance the RIP on success.
2393 */
2394 /** @todo Status code management. */
2395 if (rcStrict == VINF_SUCCESS)
2396 iemRegAddToRip(pIemCpu, cbInstr);
2397 return rcStrict;
2398
2399}
2400
2401
2402/**
2403 * Implements mov CRx,GReg.
2404 *
2405 * @param iCrReg The CRx register to write (valid).
2406 * @param iGReg The general register to load the DRx value from.
2407 */
2408IEM_CIMPL_DEF_2(iemCImpl_mov_Cd_Rd, uint8_t, iCrReg, uint8_t, iGReg)
2409{
2410 if (pIemCpu->uCpl != 0)
2411 return iemRaiseGeneralProtectionFault0(pIemCpu);
2412 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
2413
2414 /*
2415 * Read the new value from the source register and call common worker.
2416 */
2417 uint64_t uNewCrX;
2418 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
2419 uNewCrX = iemGRegFetchU64(pIemCpu, iGReg);
2420 else
2421 uNewCrX = iemGRegFetchU32(pIemCpu, iGReg);
2422 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, iCrReg, uNewCrX);
2423}
2424
2425
2426/**
2427 * Implements 'LMSW r/m16'
2428 *
2429 * @param u16NewMsw The new value.
2430 */
2431IEM_CIMPL_DEF_1(iemCImpl_lmsw, uint16_t, u16NewMsw)
2432{
2433 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2434
2435 if (pIemCpu->uCpl != 0)
2436 return iemRaiseGeneralProtectionFault0(pIemCpu);
2437 Assert(!pCtx->eflags.Bits.u1VM);
2438
2439 /*
2440 * Compose the new CR0 value and call common worker.
2441 */
2442 uint64_t uNewCr0 = pCtx->cr0 & ~(X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
2443 uNewCr0 |= u16NewMsw & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
2444 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, /*cr*/ 0, uNewCr0);
2445}
2446
2447
2448/**
2449 * Implements 'CLTS'.
2450 */
2451IEM_CIMPL_DEF_0(iemCImpl_clts)
2452{
2453 if (pIemCpu->uCpl != 0)
2454 return iemRaiseGeneralProtectionFault0(pIemCpu);
2455
2456 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2457 uint64_t uNewCr0 = pCtx->cr0;
2458 uNewCr0 &= ~X86_CR0_TS;
2459 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, /*cr*/ 0, uNewCr0);
2460}
2461
2462
2463/**
2464 * Implements mov GReg,DRx.
2465 *
2466 * @param iGReg The general register to store the DRx value in.
2467 * @param iDrReg The DRx register to read (0-7).
2468 */
2469IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Dd, uint8_t, iGReg, uint8_t, iDrReg)
2470{
2471 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2472
2473 /*
2474 * Check preconditions.
2475 */
2476
2477 /* Raise GPs. */
2478 if (pIemCpu->uCpl != 0)
2479 return iemRaiseGeneralProtectionFault0(pIemCpu);
2480 Assert(!pCtx->eflags.Bits.u1VM);
2481
2482 if ( (iDrReg == 4 || iDrReg == 5)
2483 && (pCtx->cr4 & X86_CR4_DE) )
2484 {
2485 Log(("mov r%u,dr%u: CR4.DE=1 -> #GP(0)\n", iGReg, iDrReg));
2486 return iemRaiseGeneralProtectionFault0(pIemCpu);
2487 }
2488
2489 /* Raise #DB if general access detect is enabled. */
2490 if (pCtx->dr[7] & X86_DR7_GD)
2491 {
2492 Log(("mov r%u,dr%u: DR7.GD=1 -> #DB\n", iGReg, iDrReg));
2493 return iemRaiseDebugException(pIemCpu);
2494 }
2495
2496 /*
2497 * Read the debug register and store it in the specified general register.
2498 */
2499 uint64_t drX;
2500 switch (iDrReg)
2501 {
2502 case 0: drX = pCtx->dr[0]; break;
2503 case 1: drX = pCtx->dr[1]; break;
2504 case 2: drX = pCtx->dr[2]; break;
2505 case 3: drX = pCtx->dr[3]; break;
2506 case 6:
2507 case 4:
2508 drX = pCtx->dr[6];
2509 drX &= ~RT_BIT_32(12);
2510 drX |= UINT32_C(0xffff0ff0);
2511 break;
2512 case 7:
2513 case 5:
2514 drX = pCtx->dr[7];
2515 drX &= ~(RT_BIT_32(11) | RT_BIT_32(12) | RT_BIT_32(14) | RT_BIT_32(15));
2516 drX |= RT_BIT_32(10);
2517 break;
2518 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
2519 }
2520
2521 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
2522 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = drX;
2523 else
2524 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = (uint32_t)drX;
2525
2526 iemRegAddToRip(pIemCpu, cbInstr);
2527 return VINF_SUCCESS;
2528}
2529
2530
2531/**
2532 * Implements mov DRx,GReg.
2533 *
2534 * @param iDrReg The DRx register to write (valid).
2535 * @param iGReg The general register to load the DRx value from.
2536 */
2537IEM_CIMPL_DEF_2(iemCImpl_mov_Dd_Rd, uint8_t, iDrReg, uint8_t, iGReg)
2538{
2539 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2540
2541 /*
2542 * Check preconditions.
2543 */
2544 if (pIemCpu->uCpl != 0)
2545 return iemRaiseGeneralProtectionFault0(pIemCpu);
2546 Assert(!pCtx->eflags.Bits.u1VM);
2547
2548 if ( (iDrReg == 4 || iDrReg == 5)
2549 && (pCtx->cr4 & X86_CR4_DE) )
2550 {
2551 Log(("mov dr%u,r%u: CR4.DE=1 -> #GP(0)\n", iDrReg, iGReg));
2552 return iemRaiseGeneralProtectionFault0(pIemCpu);
2553 }
2554
2555 /* Raise #DB if general access detect is enabled. */
2556 /** @todo is \#DB/DR7.GD raised before any reserved high bits in DR7/DR6
2557 * \#GP? */
2558 if (pCtx->dr[7] & X86_DR7_GD)
2559 {
2560 Log(("mov dr%u,r%u: DR7.GD=1 -> #DB\n", iDrReg, iGReg));
2561 return iemRaiseDebugException(pIemCpu);
2562 }
2563
2564 /*
2565 * Read the new value from the source register.
2566 */
2567 uint64_t uNewDrX;
2568 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
2569 uNewDrX = iemGRegFetchU64(pIemCpu, iGReg);
2570 else
2571 uNewDrX = iemGRegFetchU32(pIemCpu, iGReg);
2572
2573 /*
2574 * Adjust it.
2575 */
2576 switch (iDrReg)
2577 {
2578 case 0:
2579 case 1:
2580 case 2:
2581 case 3:
2582 /* nothing to adjust */
2583 break;
2584
2585 case 6:
2586 case 4:
2587 if (uNewDrX & UINT64_C(0xffffffff00000000))
2588 {
2589 Log(("mov dr%u,%#llx: DR6 high bits are not zero -> #GP(0)\n", iDrReg, uNewDrX));
2590 return iemRaiseGeneralProtectionFault0(pIemCpu);
2591 }
2592 uNewDrX &= ~RT_BIT_32(12);
2593 uNewDrX |= UINT32_C(0xffff0ff0);
2594 break;
2595
2596 case 7:
2597 case 5:
2598 if (uNewDrX & UINT64_C(0xffffffff00000000))
2599 {
2600 Log(("mov dr%u,%#llx: DR7 high bits are not zero -> #GP(0)\n", iDrReg, uNewDrX));
2601 return iemRaiseGeneralProtectionFault0(pIemCpu);
2602 }
2603 uNewDrX &= ~(RT_BIT_32(11) | RT_BIT_32(12) | RT_BIT_32(14) | RT_BIT_32(15));
2604 uNewDrX |= RT_BIT_32(10);
2605 break;
2606
2607 IEM_NOT_REACHED_DEFAULT_CASE_RET();
2608 }
2609
2610 /*
2611 * Do the actual setting.
2612 */
2613 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2614 {
2615 int rc = CPUMSetGuestDRx(IEMCPU_TO_VMCPU(pIemCpu), iDrReg, uNewDrX);
2616 AssertRCSuccessReturn(rc, RT_SUCCESS_NP(rc) ? VERR_INTERNAL_ERROR : rc);
2617 }
2618 else
2619 pCtx->dr[iDrReg] = uNewDrX;
2620
2621 iemRegAddToRip(pIemCpu, cbInstr);
2622 return VINF_SUCCESS;
2623}
2624
2625
2626/**
2627 * Implements RDTSC.
2628 */
2629IEM_CIMPL_DEF_0(iemCImpl_rdtsc)
2630{
2631 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2632
2633 /*
2634 * Check preconditions.
2635 */
2636 if (!IEM_IS_INTEL_CPUID_FEATURE_PRESENT_EDX(X86_CPUID_FEATURE_EDX_TSC))
2637 return iemRaiseUndefinedOpcode(pIemCpu);
2638
2639 if ( (pCtx->cr4 & X86_CR4_TSD)
2640 && pIemCpu->uCpl != 0)
2641 {
2642 Log(("rdtsc: CR4.TSD and CPL=%u -> #GP(0)\n", pIemCpu->uCpl));
2643 return iemRaiseGeneralProtectionFault0(pIemCpu);
2644 }
2645
2646 /*
2647 * Do the job.
2648 */
2649 uint64_t uTicks = TMCpuTickGet(IEMCPU_TO_VMCPU(pIemCpu));
2650 pCtx->rax = (uint32_t)uTicks;
2651 pCtx->rdx = uTicks >> 32;
2652#ifdef IEM_VERIFICATION_MODE
2653 pIemCpu->fIgnoreRaxRdx = true;
2654#endif
2655
2656 iemRegAddToRip(pIemCpu, cbInstr);
2657 return VINF_SUCCESS;
2658}
2659
2660
2661/**
2662 * Implements 'IN eAX, port'.
2663 *
2664 * @param u16Port The source port.
2665 * @param cbReg The register size.
2666 */
2667IEM_CIMPL_DEF_2(iemCImpl_in, uint16_t, u16Port, uint8_t, cbReg)
2668{
2669 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2670
2671 /*
2672 * CPL check
2673 */
2674 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pIemCpu, pCtx, u16Port, cbReg);
2675 if (rcStrict != VINF_SUCCESS)
2676 return rcStrict;
2677
2678 /*
2679 * Perform the I/O.
2680 */
2681 uint32_t u32Value;
2682 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2683 rcStrict = IOMIOPortRead(IEMCPU_TO_VM(pIemCpu), u16Port, &u32Value, cbReg);
2684 else
2685 rcStrict = iemVerifyFakeIOPortRead(pIemCpu, u16Port, &u32Value, cbReg);
2686 if (IOM_SUCCESS(rcStrict))
2687 {
2688 switch (cbReg)
2689 {
2690 case 1: pCtx->al = (uint8_t)u32Value; break;
2691 case 2: pCtx->ax = (uint16_t)u32Value; break;
2692 case 4: pCtx->rax = u32Value; break;
2693 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
2694 }
2695 iemRegAddToRip(pIemCpu, cbInstr);
2696 pIemCpu->cPotentialExits++;
2697 }
2698 /** @todo massage rcStrict. */
2699 return rcStrict;
2700}
2701
2702
2703/**
2704 * Implements 'IN eAX, DX'.
2705 *
2706 * @param cbReg The register size.
2707 */
2708IEM_CIMPL_DEF_1(iemCImpl_in_eAX_DX, uint8_t, cbReg)
2709{
2710 return IEM_CIMPL_CALL_2(iemCImpl_in, pIemCpu->CTX_SUFF(pCtx)->dx, cbReg);
2711}
2712
2713
2714/**
2715 * Implements 'OUT port, eAX'.
2716 *
2717 * @param u16Port The destination port.
2718 * @param cbReg The register size.
2719 */
2720IEM_CIMPL_DEF_2(iemCImpl_out, uint16_t, u16Port, uint8_t, cbReg)
2721{
2722 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2723
2724 /*
2725 * CPL check
2726 */
2727 if ( (pCtx->cr0 & X86_CR0_PE)
2728 && ( pIemCpu->uCpl > pCtx->eflags.Bits.u2IOPL
2729 || pCtx->eflags.Bits.u1VM) )
2730 {
2731 /** @todo I/O port permission bitmap check */
2732 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
2733 }
2734
2735 /*
2736 * Perform the I/O.
2737 */
2738 uint32_t u32Value;
2739 switch (cbReg)
2740 {
2741 case 1: u32Value = pCtx->al; break;
2742 case 2: u32Value = pCtx->ax; break;
2743 case 4: u32Value = pCtx->eax; break;
2744 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
2745 }
2746 VBOXSTRICTRC rc;
2747 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
2748 rc = IOMIOPortWrite(IEMCPU_TO_VM(pIemCpu), u16Port, u32Value, cbReg);
2749 else
2750 rc = iemVerifyFakeIOPortWrite(pIemCpu, u16Port, u32Value, cbReg);
2751 if (IOM_SUCCESS(rc))
2752 {
2753 iemRegAddToRip(pIemCpu, cbInstr);
2754 pIemCpu->cPotentialExits++;
2755 /** @todo massage rc. */
2756 }
2757 return rc;
2758}
2759
2760
2761/**
2762 * Implements 'OUT DX, eAX'.
2763 *
2764 * @param cbReg The register size.
2765 */
2766IEM_CIMPL_DEF_1(iemCImpl_out_DX_eAX, uint8_t, cbReg)
2767{
2768 return IEM_CIMPL_CALL_2(iemCImpl_out, pIemCpu->CTX_SUFF(pCtx)->dx, cbReg);
2769}
2770
2771
2772/**
2773 * Implements 'CLI'.
2774 */
2775IEM_CIMPL_DEF_0(iemCImpl_cli)
2776{
2777 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2778
2779 if (pCtx->cr0 & X86_CR0_PE)
2780 {
2781 uint8_t const uIopl = pCtx->eflags.Bits.u2IOPL;
2782 if (!pCtx->eflags.Bits.u1VM)
2783 {
2784 if (pIemCpu->uCpl <= uIopl)
2785 pCtx->eflags.Bits.u1IF = 0;
2786 else if ( pIemCpu->uCpl == 3
2787 && (pCtx->cr4 & X86_CR4_PVI) )
2788 pCtx->eflags.Bits.u1VIF = 0;
2789 else
2790 return iemRaiseGeneralProtectionFault0(pIemCpu);
2791 }
2792 /* V8086 */
2793 else if (uIopl == 3)
2794 pCtx->eflags.Bits.u1IF = 0;
2795 else if ( uIopl < 3
2796 && (pCtx->cr4 & X86_CR4_VME) )
2797 pCtx->eflags.Bits.u1VIF = 0;
2798 else
2799 return iemRaiseGeneralProtectionFault0(pIemCpu);
2800 }
2801 /* real mode */
2802 else
2803 pCtx->eflags.Bits.u1IF = 0;
2804 iemRegAddToRip(pIemCpu, cbInstr);
2805 return VINF_SUCCESS;
2806}
2807
2808
2809/**
2810 * Implements 'STI'.
2811 */
2812IEM_CIMPL_DEF_0(iemCImpl_sti)
2813{
2814 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2815
2816 if (pCtx->cr0 & X86_CR0_PE)
2817 {
2818 uint8_t const uIopl = pCtx->eflags.Bits.u2IOPL;
2819 if (!pCtx->eflags.Bits.u1VM)
2820 {
2821 if (pIemCpu->uCpl <= uIopl)
2822 pCtx->eflags.Bits.u1IF = 1;
2823 else if ( pIemCpu->uCpl == 3
2824 && (pCtx->cr4 & X86_CR4_PVI)
2825 && !pCtx->eflags.Bits.u1VIP )
2826 pCtx->eflags.Bits.u1VIF = 1;
2827 else
2828 return iemRaiseGeneralProtectionFault0(pIemCpu);
2829 }
2830 /* V8086 */
2831 else if (uIopl == 3)
2832 pCtx->eflags.Bits.u1IF = 1;
2833 else if ( uIopl < 3
2834 && (pCtx->cr4 & X86_CR4_VME)
2835 && !pCtx->eflags.Bits.u1VIP )
2836 pCtx->eflags.Bits.u1VIF = 1;
2837 else
2838 return iemRaiseGeneralProtectionFault0(pIemCpu);
2839 }
2840 /* real mode */
2841 else
2842 pCtx->eflags.Bits.u1IF = 1;
2843
2844 iemRegAddToRip(pIemCpu, cbInstr);
2845 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
2846 return VINF_SUCCESS;
2847}
2848
2849
2850/**
2851 * Implements 'HLT'.
2852 */
2853IEM_CIMPL_DEF_0(iemCImpl_hlt)
2854{
2855 if (pIemCpu->uCpl != 0)
2856 return iemRaiseGeneralProtectionFault0(pIemCpu);
2857 iemRegAddToRip(pIemCpu, cbInstr);
2858 return VINF_EM_HALT;
2859}
2860
2861
2862/**
2863 * Implements 'CPUID'.
2864 */
2865IEM_CIMPL_DEF_0(iemCImpl_cpuid)
2866{
2867 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2868
2869 CPUMGetGuestCpuId(IEMCPU_TO_VMCPU(pIemCpu), pCtx->eax, &pCtx->eax, &pCtx->ebx, &pCtx->ecx, &pCtx->edx);
2870 pCtx->rax &= UINT32_C(0xffffffff);
2871 pCtx->rbx &= UINT32_C(0xffffffff);
2872 pCtx->rcx &= UINT32_C(0xffffffff);
2873 pCtx->rdx &= UINT32_C(0xffffffff);
2874
2875 iemRegAddToRip(pIemCpu, cbInstr);
2876 return VINF_SUCCESS;
2877}
2878
2879
2880/*
2881 * Instantiate the various string operation combinations.
2882 */
2883#define OP_SIZE 8
2884#define ADDR_SIZE 16
2885#include "IEMAllCImplStrInstr.cpp.h"
2886#define OP_SIZE 8
2887#define ADDR_SIZE 32
2888#include "IEMAllCImplStrInstr.cpp.h"
2889#define OP_SIZE 8
2890#define ADDR_SIZE 64
2891#include "IEMAllCImplStrInstr.cpp.h"
2892
2893#define OP_SIZE 16
2894#define ADDR_SIZE 16
2895#include "IEMAllCImplStrInstr.cpp.h"
2896#define OP_SIZE 16
2897#define ADDR_SIZE 32
2898#include "IEMAllCImplStrInstr.cpp.h"
2899#define OP_SIZE 16
2900#define ADDR_SIZE 64
2901#include "IEMAllCImplStrInstr.cpp.h"
2902
2903#define OP_SIZE 32
2904#define ADDR_SIZE 16
2905#include "IEMAllCImplStrInstr.cpp.h"
2906#define OP_SIZE 32
2907#define ADDR_SIZE 32
2908#include "IEMAllCImplStrInstr.cpp.h"
2909#define OP_SIZE 32
2910#define ADDR_SIZE 64
2911#include "IEMAllCImplStrInstr.cpp.h"
2912
2913#define OP_SIZE 64
2914#define ADDR_SIZE 32
2915#include "IEMAllCImplStrInstr.cpp.h"
2916#define OP_SIZE 64
2917#define ADDR_SIZE 64
2918#include "IEMAllCImplStrInstr.cpp.h"
2919
2920
2921/**
2922 * Implements 'FINIT' and 'FNINIT'.
2923 *
2924 * @param fCheckXcpts Whether to check for umasked pending exceptions or
2925 * not.
2926 */
2927IEM_CIMPL_DEF_1(iemCImpl_finit, bool, fCheckXcpts)
2928{
2929 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2930
2931 if (pCtx->cr0 & (X86_CR0_EM | X86_CR0_TS))
2932 return iemRaiseDeviceNotAvailable(pIemCpu);
2933 /** @todo trigger pending exceptions:
2934 if (fCheckXcpts && TODO )
2935 return iemRaiseMathFault(pIemCpu);
2936 */
2937
2938 if (iemFRegIsFxSaveFormat(pIemCpu))
2939 {
2940 pCtx->fpu.FCW = 0x37f;
2941 pCtx->fpu.FSW = 0;
2942 pCtx->fpu.FTW = 0x00; /* 0 - empty. */
2943 pCtx->fpu.FPUDP = 0;
2944 pCtx->fpu.DS = 0; //??
2945 pCtx->fpu.FPUIP = 0;
2946 pCtx->fpu.CS = 0; //??
2947 pCtx->fpu.FOP = 0;
2948 }
2949 else
2950 {
2951 PX86FPUSTATE pFpu = (PX86FPUSTATE)&pCtx->fpu;
2952 pFpu->FCW = 0x37f;
2953 pFpu->FSW = 0;
2954 pFpu->FTW = 0xffff; /* 11 - empty */
2955 pFpu->FPUOO = 0; //??
2956 pFpu->FPUOS = 0; //??
2957 pFpu->FPUIP = 0;
2958 pFpu->CS = 0; //??
2959 pFpu->FOP = 0;
2960 }
2961
2962 iemRegAddToRip(pIemCpu, cbInstr);
2963 return VINF_SUCCESS;
2964}
2965
2966
2967/** @} */
2968
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