VirtualBox

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

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

IEM: SMSW and LMSW.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 73.0 KB
Line 
1/* $Id: IEMAllCImpl.cpp.h 36838 2011-04-25 14:17:54Z 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 */
679IEM_CIMPL_DEF_2(iemCImpl_FarJmp, uint16_t, uSel, uint32_t, offSeg)
680{
681 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
682
683 /*
684 * Real mode and V8086 mode are easy. The only snag seems to be that
685 * CS.limit doesn't change and the limit check is done against the current
686 * limit.
687 */
688 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
689 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
690 {
691 if (offSeg > pCtx->csHid.u32Limit)
692 return iemRaiseGeneralProtectionFault0(pIemCpu);
693
694 if (pIemCpu->enmEffOpSize == IEMMODE_16BIT) /** @todo WRONG, must pass this. */
695 pCtx->rip = offSeg;
696 else
697 pCtx->rip = offSeg & UINT16_MAX;
698 pCtx->cs = uSel;
699 pCtx->csHid.u64Base = (uint32_t)uSel << 4;
700 /** @todo REM reset the accessed bit (see on jmp far16 after disabling
701 * PE. Check with VT-x and AMD-V. */
702#ifdef IEM_VERIFICATION_MODE
703 pCtx->csHid.Attr.u &= ~X86_SEL_TYPE_ACCESSED;
704#endif
705 return VINF_SUCCESS;
706 }
707
708 /*
709 * Protected mode. Need to parse the specified descriptor...
710 */
711 if (!(uSel & (X86_SEL_MASK | X86_SEL_LDT)))
712 {
713 Log(("jmpf %04x:%08x -> invalid selector, #GP(0)\n", uSel, offSeg));
714 return iemRaiseGeneralProtectionFault0(pIemCpu);
715 }
716
717 /* Fetch the descriptor. */
718 IEMSELDESC Desc;
719 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uSel);
720 if (rcStrict != VINF_SUCCESS)
721 return rcStrict;
722
723 /* Is it there? */
724 if (!Desc.Legacy.Gen.u1Present)
725 {
726 Log(("jmpf %04x:%08x -> segment not present\n", uSel, offSeg));
727 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uSel);
728 }
729
730 /*
731 * Deal with it according to its type.
732 */
733 if (Desc.Legacy.Gen.u1DescType)
734 {
735 /* Only code segments. */
736 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE))
737 {
738 Log(("jmpf %04x:%08x -> not a code selector (u4Type=%#x).\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
739 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
740 }
741
742 /* L vs D. */
743 if ( Desc.Legacy.Gen.u1Long
744 && Desc.Legacy.Gen.u1DefBig
745 && IEM_IS_LONG_MODE(pIemCpu))
746 {
747 Log(("jmpf %04x:%08x -> both L and D are set.\n", uSel, offSeg));
748 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
749 }
750
751 /* DPL/RPL/CPL check, where conforming segments makes a difference. */
752 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF))
753 {
754 if (Desc.Legacy.Gen.u2Dpl > pIemCpu->uCpl)
755 {
756 Log(("jmpf %04x:%08x -> DPL violation (conforming); DPL=%d CPL=%u\n",
757 uSel, offSeg, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
758 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
759 }
760 }
761 else
762 {
763 if (Desc.Legacy.Gen.u2Dpl != pIemCpu->uCpl)
764 {
765 Log(("jmpf %04x:%08x -> CPL != DPL; DPL=%d CPL=%u\n", uSel, offSeg, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
766 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
767 }
768 if ((uSel & X86_SEL_RPL) > pIemCpu->uCpl)
769 {
770 Log(("jmpf %04x:%08x -> RPL > DPL; RPL=%d CPL=%u\n", uSel, offSeg, (uSel & X86_SEL_RPL), pIemCpu->uCpl));
771 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
772 }
773 }
774
775 /* Limit check. (Should alternatively check for non-canonical addresses
776 here, but that is ruled out by offSeg being 32-bit, right?) */
777 uint64_t u64Base;
778 uint32_t cbLimit = X86DESC_LIMIT(Desc.Legacy);
779 if (Desc.Legacy.Gen.u1Granularity)
780 cbLimit = (cbLimit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
781 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
782 u64Base = 0;
783 else
784 {
785 if (offSeg > cbLimit)
786 {
787 Log(("jmpf %04x:%08x -> out of bounds (%#x)\n", uSel, offSeg, cbLimit));
788 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
789 }
790 u64Base = X86DESC_BASE(Desc.Legacy);
791 }
792
793 /*
794 * Ok, everything checked out fine. Now set the accessed bit before
795 * committing the result into CS, CSHID and RIP.
796 */
797 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
798 {
799 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uSel);
800 if (rcStrict != VINF_SUCCESS)
801 return rcStrict;
802#ifdef IEM_VERIFICATION_MODE /** @todo check what VT-x and AMD-V does. */
803 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
804#endif
805 }
806
807 /* commit */
808 pCtx->rip = offSeg;
809 pCtx->cs = uSel & (X86_SEL_MASK | X86_SEL_LDT);
810 pCtx->cs |= pIemCpu->uCpl; /** @todo is this right for conforming segs? or in general? */
811 pCtx->csHid.Attr.u = (Desc.Legacy.u >> (16+16+8)) & UINT32_C(0xf0ff);
812 pCtx->csHid.u32Limit = cbLimit;
813 pCtx->csHid.u64Base = u64Base;
814 /** @todo check if the hidden bits are loaded correctly for 64-bit
815 * mode. */
816 return VINF_SUCCESS;
817 }
818
819 /*
820 * System selector.
821 */
822 if (IEM_IS_LONG_MODE(pIemCpu))
823 switch (Desc.Legacy.Gen.u4Type)
824 {
825 case AMD64_SEL_TYPE_SYS_LDT:
826 case AMD64_SEL_TYPE_SYS_TSS_AVAIL:
827 case AMD64_SEL_TYPE_SYS_TSS_BUSY:
828 case AMD64_SEL_TYPE_SYS_CALL_GATE:
829 case AMD64_SEL_TYPE_SYS_INT_GATE:
830 case AMD64_SEL_TYPE_SYS_TRAP_GATE:
831 /* Call various functions to do the work. */
832 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
833 default:
834 Log(("jmpf %04x:%08x -> wrong sys selector (64-bit): %d\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
835 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
836
837 }
838 switch (Desc.Legacy.Gen.u4Type)
839 {
840 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
841 case X86_SEL_TYPE_SYS_LDT:
842 case X86_SEL_TYPE_SYS_286_CALL_GATE:
843 case X86_SEL_TYPE_SYS_TASK_GATE:
844 case X86_SEL_TYPE_SYS_286_INT_GATE:
845 case X86_SEL_TYPE_SYS_286_TRAP_GATE:
846 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
847 case X86_SEL_TYPE_SYS_386_CALL_GATE:
848 case X86_SEL_TYPE_SYS_386_INT_GATE:
849 case X86_SEL_TYPE_SYS_386_TRAP_GATE:
850 /* Call various functions to do the work. */
851 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
852
853 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
854 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
855 /* Call various functions to do the work. */
856 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
857
858 default:
859 Log(("jmpf %04x:%08x -> wrong sys selector (32-bit): %d\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
860 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
861 }
862}
863
864
865/**
866 * Implements far calls.
867 *
868 * @param uSel The selector.
869 * @param offSeg The segment offset.
870 * @param enmOpSize The operand size (in case we need it).
871 */
872IEM_CIMPL_DEF_3(iemCImpl_callf, uint16_t, uSel, uint64_t, offSeg, IEMMODE, enmOpSize)
873{
874 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
875 VBOXSTRICTRC rcStrict;
876 uint64_t uNewRsp;
877 void *pvRet;
878
879 /*
880 * Real mode and V8086 mode are easy. The only snag seems to be that
881 * CS.limit doesn't change and the limit check is done against the current
882 * limit.
883 */
884 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
885 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
886 {
887 Assert(enmOpSize == IEMMODE_16BIT || enmOpSize == IEMMODE_32BIT);
888
889 /* Check stack first - may #SS(0). */
890 rcStrict = iemMemStackPushBeginSpecial(pIemCpu, enmOpSize == IEMMODE_32BIT ? 6 : 4,
891 &pvRet, &uNewRsp);
892 if (rcStrict != VINF_SUCCESS)
893 return rcStrict;
894
895 /* Check the target address range. */
896 if (offSeg > UINT32_MAX)
897 return iemRaiseGeneralProtectionFault0(pIemCpu);
898
899 /* Everything is fine, push the return address. */
900 if (enmOpSize == IEMMODE_16BIT)
901 {
902 ((uint16_t *)pvRet)[0] = pCtx->ip + cbInstr;
903 ((uint16_t *)pvRet)[1] = pCtx->cs;
904 }
905 else
906 {
907 ((uint32_t *)pvRet)[0] = pCtx->eip + cbInstr;
908 ((uint16_t *)pvRet)[3] = pCtx->cs;
909 }
910 rcStrict = iemMemStackPushCommitSpecial(pIemCpu, pvRet, uNewRsp);
911 if (rcStrict != VINF_SUCCESS)
912 return rcStrict;
913
914 /* Branch. */
915 pCtx->rip = offSeg;
916 pCtx->cs = uSel;
917 pCtx->csHid.u64Base = (uint32_t)uSel << 4;
918 /** @todo Does REM reset the accessed bit here to? (See on jmp far16
919 * after disabling PE.) Check with VT-x and AMD-V. */
920#ifdef IEM_VERIFICATION_MODE
921 pCtx->csHid.Attr.u &= ~X86_SEL_TYPE_ACCESSED;
922#endif
923 return VINF_SUCCESS;
924 }
925
926 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
927}
928
929
930/**
931 * Implements retf.
932 *
933 * @param enmEffOpSize The effective operand size.
934 * @param cbPop The amount of arguments to pop from the stack
935 * (bytes).
936 */
937IEM_CIMPL_DEF_2(iemCImpl_retf, IEMMODE, enmEffOpSize, uint16_t, cbPop)
938{
939 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
940 VBOXSTRICTRC rcStrict;
941 uint64_t uNewRsp;
942
943 /*
944 * Real mode and V8086 mode are easy.
945 */
946 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
947 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
948 {
949 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
950 uint16_t const *pu16Frame;
951 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, enmEffOpSize == IEMMODE_32BIT ? 8 : 4,
952 (void const **)&pu16Frame, &uNewRsp);
953 if (rcStrict != VINF_SUCCESS)
954 return rcStrict;
955 uint32_t uNewEip;
956 uint16_t uNewCs;
957 if (enmEffOpSize == IEMMODE_32BIT)
958 {
959 uNewCs = pu16Frame[2];
960 uNewEip = RT_MAKE_U32(pu16Frame[0], pu16Frame[1]);
961 }
962 else
963 {
964 uNewCs = pu16Frame[1];
965 uNewEip = pu16Frame[0];
966 }
967 /** @todo check how this is supposed to work if sp=0xfffe. */
968
969 /* Check the limit of the new EIP. */
970 /** @todo Intel pseudo code only does the limit check for 16-bit
971 * operands, AMD does not make any distinction. What is right? */
972 if (uNewEip > pCtx->csHid.u32Limit)
973 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
974
975 /* commit the operation. */
976 rcStrict = iemMemStackPopCommitSpecial(pIemCpu, pu16Frame, uNewRsp);
977 if (rcStrict != VINF_SUCCESS)
978 return rcStrict;
979 pCtx->rip = uNewEip;
980 pCtx->cs = uNewCs;
981 pCtx->csHid.u64Base = (uint32_t)uNewCs << 4;
982 /** @todo do we load attribs and limit as well? */
983 if (cbPop)
984 iemRegAddToRsp(pCtx, cbPop);
985 return VINF_SUCCESS;
986 }
987
988 AssertFailed();
989 return VERR_NOT_IMPLEMENTED;
990}
991
992
993/**
994 * Implements retn.
995 *
996 * We're doing this in C because of the \#GP that might be raised if the popped
997 * program counter is out of bounds.
998 *
999 * @param enmEffOpSize The effective operand size.
1000 * @param cbPop The amount of arguments to pop from the stack
1001 * (bytes).
1002 */
1003IEM_CIMPL_DEF_2(iemCImpl_retn, IEMMODE, enmEffOpSize, uint16_t, cbPop)
1004{
1005 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1006
1007 /* Fetch the RSP from the stack. */
1008 VBOXSTRICTRC rcStrict;
1009 RTUINT64U NewRip;
1010 RTUINT64U NewRsp;
1011 NewRsp.u = pCtx->rsp;
1012 switch (enmEffOpSize)
1013 {
1014 case IEMMODE_16BIT:
1015 NewRip.u = 0;
1016 rcStrict = iemMemStackPopU16Ex(pIemCpu, &NewRip.Words.w0, &NewRsp);
1017 break;
1018 case IEMMODE_32BIT:
1019 NewRip.u = 0;
1020 rcStrict = iemMemStackPopU32Ex(pIemCpu, &NewRip.DWords.dw0, &NewRsp);
1021 break;
1022 case IEMMODE_64BIT:
1023 rcStrict = iemMemStackPopU64Ex(pIemCpu, &NewRip.u, &NewRsp);
1024 break;
1025 IEM_NOT_REACHED_DEFAULT_CASE_RET();
1026 }
1027 if (rcStrict != VINF_SUCCESS)
1028 return rcStrict;
1029
1030 /* Check the new RSP before loading it. */
1031 /** @todo Should test this as the intel+amd pseudo code doesn't mention half
1032 * of it. The canonical test is performed here and for call. */
1033 if (enmEffOpSize != IEMMODE_64BIT)
1034 {
1035 if (NewRip.DWords.dw0 > pCtx->csHid.u32Limit)
1036 {
1037 Log(("retn newrip=%llx - out of bounds (%x) -> #GP\n", NewRip.u, pCtx->csHid.u32Limit));
1038 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
1039 }
1040 }
1041 else
1042 {
1043 if (!IEM_IS_CANONICAL(NewRip.u))
1044 {
1045 Log(("retn newrip=%llx - not canonical -> #GP\n", NewRip.u));
1046 return iemRaiseNotCanonical(pIemCpu);
1047 }
1048 }
1049
1050 /* Commit it. */
1051 pCtx->rip = NewRip.u;
1052 pCtx->rsp = NewRsp.u;
1053 if (cbPop)
1054 iemRegAddToRsp(pCtx, cbPop);
1055
1056 return VINF_SUCCESS;
1057}
1058
1059
1060/**
1061 * Implements int3 and int XX.
1062 *
1063 * @param u8Int The interrupt vector number.
1064 * @param fIsBpInstr Is it the breakpoint instruction.
1065 */
1066IEM_CIMPL_DEF_2(iemCImpl_int, uint8_t, u8Int, bool, fIsBpInstr)
1067{
1068 /** @todo we should call TRPM to do this job. */
1069 VBOXSTRICTRC rcStrict;
1070 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1071
1072 /*
1073 * Real mode is easy.
1074 */
1075 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
1076 && IEM_IS_REAL_MODE(pIemCpu))
1077 {
1078 /* read the IDT entry. */
1079 if (pCtx->idtr.cbIdt < UINT32_C(4) * u8Int + 3)
1080 return iemRaiseGeneralProtectionFault(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Int << X86_TRAP_ERR_SEL_SHIFT));
1081 RTFAR16 Idte;
1082 rcStrict = iemMemFetchDataU32(pIemCpu, (uint32_t *)&Idte, UINT8_MAX, pCtx->idtr.pIdt + UINT32_C(4) * u8Int);
1083 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
1084 return rcStrict;
1085
1086 /* push the stack frame. */
1087 uint16_t *pu16Frame;
1088 uint64_t uNewRsp;
1089 rcStrict = iemMemStackPushBeginSpecial(pIemCpu, 6, (void **)&pu16Frame, &uNewRsp);
1090 if (rcStrict != VINF_SUCCESS)
1091 return rcStrict;
1092
1093 pu16Frame[2] = (uint16_t)pCtx->eflags.u;
1094 pu16Frame[1] = (uint16_t)pCtx->cs;
1095 pu16Frame[0] = pCtx->ip + cbInstr;
1096 rcStrict = iemMemStackPushCommitSpecial(pIemCpu, pu16Frame, uNewRsp);
1097 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
1098 return rcStrict;
1099
1100 /* load the vector address into cs:ip. */
1101 pCtx->cs = Idte.sel;
1102 pCtx->csHid.u64Base = (uint32_t)Idte.sel << 4;
1103 /** @todo do we load attribs and limit as well? Should we check against limit like far jump? */
1104 pCtx->rip = Idte.off;
1105 pCtx->eflags.Bits.u1IF = 0;
1106 return VINF_SUCCESS;
1107 }
1108
1109 AssertFailed();
1110 return VERR_NOT_IMPLEMENTED;
1111}
1112
1113
1114/**
1115 * Implements iret.
1116 *
1117 * @param enmEffOpSize The effective operand size.
1118 */
1119IEM_CIMPL_DEF_1(iemCImpl_iret, IEMMODE, enmEffOpSize)
1120{
1121 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1122 VBOXSTRICTRC rcStrict;
1123 uint64_t uNewRsp;
1124
1125 /*
1126 * Real mode is easy, V8086 mode is relative similar.
1127 */
1128 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
1129 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
1130 {
1131 /* iret throws an exception if VME isn't enabled. */
1132 if ( pCtx->eflags.Bits.u1VM
1133 && !(pCtx->cr4 & X86_CR4_VME))
1134 return iemRaiseGeneralProtectionFault0(pIemCpu);
1135
1136 /* Do the stack bits, but don't commit RSP before everything checks
1137 out right. */
1138 union
1139 {
1140 uint32_t const *pu32;
1141 uint16_t const *pu16;
1142 void const *pv;
1143 } uFrame;
1144 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
1145 uint16_t uNewCs;
1146 uint32_t uNewEip;
1147 uint32_t uNewFlags;
1148 if (enmEffOpSize == IEMMODE_32BIT)
1149 {
1150 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 12, &uFrame.pv, &uNewRsp);
1151 if (rcStrict != VINF_SUCCESS)
1152 return rcStrict;
1153 uNewEip = uFrame.pu32[0];
1154 uNewCs = (uint16_t)uFrame.pu32[1];
1155 uNewFlags = uFrame.pu32[2];
1156 uNewFlags &= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
1157 | X86_EFL_TF | X86_EFL_IF | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT
1158 | X86_EFL_RF /*| X86_EFL_VM*/ | X86_EFL_AC /*|X86_EFL_VIF*/ /*|X86_EFL_VIP*/
1159 | X86_EFL_ID;
1160 uNewFlags |= pCtx->eflags.u & (X86_EFL_VM | X86_EFL_VIF | X86_EFL_VIP | X86_EFL_1);
1161 }
1162 else
1163 {
1164 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 6, &uFrame.pv, &uNewRsp);
1165 if (rcStrict != VINF_SUCCESS)
1166 return rcStrict;
1167 uNewEip = uFrame.pu16[0];
1168 uNewCs = uFrame.pu16[1];
1169 uNewFlags = uFrame.pu16[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 uNewFlags |= pCtx->eflags.u & (UINT16_C(0xffff0000) | X86_EFL_1);
1173 /** @todo The intel pseudo code does not indicate what happens to
1174 * reserved flags. We just ignore them. */
1175 }
1176 /** @todo Check how this is supposed to work if sp=0xfffe. */
1177
1178 /* Check the limit of the new EIP. */
1179 /** @todo Only the AMD pseudo code check the limit here, what's
1180 * right? */
1181 if (uNewEip > pCtx->csHid.u32Limit)
1182 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
1183
1184 /* V8086 checks and flag adjustments */
1185 if (pCtx->eflags.Bits.u1VM)
1186 {
1187 if (pCtx->eflags.Bits.u2IOPL == 3)
1188 {
1189 /* Preserve IOPL and clear RF. */
1190 uNewFlags &= ~(X86_EFL_IOPL | X86_EFL_RF);
1191 uNewFlags |= pCtx->eflags.u & (X86_EFL_IOPL);
1192 }
1193 else if ( enmEffOpSize == IEMMODE_16BIT
1194 && ( !(uNewFlags & X86_EFL_IF)
1195 || !pCtx->eflags.Bits.u1VIP )
1196 && !(uNewFlags & X86_EFL_TF) )
1197 {
1198 /* Move IF to VIF, clear RF and preserve IF and IOPL.*/
1199 uNewFlags &= ~X86_EFL_VIF;
1200 uNewFlags |= (uNewFlags & X86_EFL_IF) << (19 - 9);
1201 uNewFlags &= ~(X86_EFL_IF | X86_EFL_IOPL | X86_EFL_RF);
1202 uNewFlags |= pCtx->eflags.u & (X86_EFL_IF | X86_EFL_IOPL);
1203 }
1204 else
1205 return iemRaiseGeneralProtectionFault0(pIemCpu);
1206 }
1207
1208 /* commit the operation. */
1209 rcStrict = iemMemStackPopCommitSpecial(pIemCpu, uFrame.pv, uNewRsp);
1210 if (rcStrict != VINF_SUCCESS)
1211 return rcStrict;
1212 pCtx->rip = uNewEip;
1213 pCtx->cs = uNewCs;
1214 pCtx->csHid.u64Base = (uint32_t)uNewCs << 4;
1215 /** @todo do we load attribs and limit as well? */
1216 Assert(uNewFlags & X86_EFL_1);
1217 pCtx->eflags.u = uNewFlags;
1218
1219 return VINF_SUCCESS;
1220 }
1221
1222
1223 AssertFailed();
1224 return VERR_NOT_IMPLEMENTED;
1225}
1226
1227
1228/**
1229 * Common worker for 'pop SReg', 'mov SReg, GReg' and 'lXs GReg, reg/mem'.
1230 *
1231 * @param iSegReg The segment register number (valid).
1232 * @param uSel The new selector value.
1233 */
1234IEM_CIMPL_DEF_2(iemCImpl_LoadSReg, uint8_t, iSegReg, uint16_t, uSel)
1235{
1236 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1237 uint16_t *pSel = iemSRegRef(pIemCpu, iSegReg);
1238 PCPUMSELREGHID pHid = iemSRegGetHid(pIemCpu, iSegReg);
1239
1240 Assert(iSegReg <= X86_SREG_GS && iSegReg != X86_SREG_CS);
1241
1242 /*
1243 * Real mode and V8086 mode are easy.
1244 */
1245 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
1246 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
1247 {
1248 *pSel = uSel;
1249 pHid->u64Base = (uint32_t)uSel << 4;
1250 /** @todo Does the CPU actually load limits and attributes in the
1251 * real/V8086 mode segment load case? It doesn't for CS in far
1252 * jumps... Affects unreal mode. */
1253 pHid->u32Limit = 0xffff;
1254 pHid->Attr.u = 0;
1255 pHid->Attr.n.u1Present = 1;
1256 pHid->Attr.n.u1DescType = 1;
1257 pHid->Attr.n.u4Type = iSegReg != X86_SREG_CS
1258 ? X86_SEL_TYPE_RW
1259 : X86_SEL_TYPE_READ | X86_SEL_TYPE_CODE;
1260
1261 iemRegAddToRip(pIemCpu, cbInstr);
1262 return VINF_SUCCESS;
1263 }
1264
1265 /*
1266 * Protected mode.
1267 *
1268 * Check if it's a null segment selector value first, that's OK for DS, ES,
1269 * FS and GS. If not null, then we have to load and parse the descriptor.
1270 */
1271 if (!(uSel & (X86_SEL_MASK | X86_SEL_LDT)))
1272 {
1273 if (iSegReg == X86_SREG_SS)
1274 {
1275 if ( pIemCpu->enmCpuMode != IEMMODE_64BIT
1276 || pIemCpu->uCpl != 0
1277 || uSel != 0) /** @todo We cannot 'mov ss, 3' in 64-bit kernel mode, can we? */
1278 {
1279 Log(("load sreg -> invalid stack selector, #GP(0)\n", uSel));
1280 return iemRaiseGeneralProtectionFault0(pIemCpu);
1281 }
1282
1283 /* In 64-bit kernel mode, the stack can be 0 because of the way
1284 interrupts are dispatched when in kernel ctx. Just load the
1285 selector value into the register and leave the hidden bits
1286 as is. */
1287 *pSel = uSel;
1288 iemRegAddToRip(pIemCpu, cbInstr);
1289 return VINF_SUCCESS;
1290 }
1291
1292 *pSel = uSel; /* Not RPL, remember :-) */
1293 if ( pIemCpu->enmCpuMode == IEMMODE_64BIT
1294 && iSegReg != X86_SREG_FS
1295 && iSegReg != X86_SREG_GS)
1296 {
1297 /** @todo figure out what this actually does, it works. Needs
1298 * testcase! */
1299 pHid->Attr.u = 0;
1300 pHid->Attr.n.u1Present = 1;
1301 pHid->Attr.n.u1Long = 1;
1302 pHid->Attr.n.u4Type = X86_SEL_TYPE_RW;
1303 pHid->Attr.n.u2Dpl = 3;
1304 pHid->u32Limit = 0;
1305 pHid->u64Base = 0;
1306 }
1307 else
1308 {
1309 pHid->Attr.u = 0;
1310 pHid->u32Limit = 0;
1311 pHid->u64Base = 0;
1312 }
1313 iemRegAddToRip(pIemCpu, cbInstr);
1314 return VINF_SUCCESS;
1315 }
1316
1317 /* Fetch the descriptor. */
1318 IEMSELDESC Desc;
1319 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uSel);
1320 if (rcStrict != VINF_SUCCESS)
1321 return rcStrict;
1322
1323 /* Check GPs first. */
1324 if (!Desc.Legacy.Gen.u1DescType)
1325 {
1326 Log(("load sreg %d - system selector (%#x) -> #GP\n", iSegReg, uSel, Desc.Legacy.Gen.u4Type));
1327 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1328 }
1329 if (iSegReg == X86_SREG_SS) /* SS gets different treatment */
1330 {
1331 if ( (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
1332 || !(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
1333 {
1334 Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
1335 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1336 }
1337 if ( (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
1338 || !(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
1339 {
1340 Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
1341 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1342 }
1343 if ((uSel & X86_SEL_RPL) != pIemCpu->uCpl)
1344 {
1345 Log(("load sreg SS, %#x - RPL and CPL (%d) differs -> #GP\n", uSel, pIemCpu->uCpl));
1346 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1347 }
1348 if (Desc.Legacy.Gen.u2Dpl != pIemCpu->uCpl)
1349 {
1350 Log(("load sreg SS, %#x - DPL (%d) and CPL (%d) differs -> #GP\n", uSel, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
1351 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1352 }
1353 }
1354 else
1355 {
1356 if ((Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
1357 {
1358 Log(("load sreg%u, %#x - execute only segment -> #GP\n", iSegReg, uSel));
1359 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1360 }
1361 if ( (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
1362 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
1363 {
1364#if 0 /* this is what intel says. */
1365 if ( (uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl
1366 && pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
1367 {
1368 Log(("load sreg%u, %#x - both RPL (%d) and CPL (%d) are greater than DPL (%d) -> #GP\n",
1369 iSegReg, uSel, (uSel & X86_SEL_RPL), pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
1370 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1371 }
1372#else /* this is what makes more sense. */
1373 if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
1374 {
1375 Log(("load sreg%u, %#x - RPL (%d) is greater than DPL (%d) -> #GP\n",
1376 iSegReg, uSel, (uSel & X86_SEL_RPL), Desc.Legacy.Gen.u2Dpl));
1377 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1378 }
1379 if (pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
1380 {
1381 Log(("load sreg%u, %#x - CPL (%d) is greater than DPL (%d) -> #GP\n",
1382 iSegReg, uSel, pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
1383 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1384 }
1385#endif
1386 }
1387 }
1388
1389 /* Is it there? */
1390 if (!Desc.Legacy.Gen.u1Present)
1391 {
1392 Log(("load sreg%d,%#x - segment not present -> #NP\n", iSegReg, uSel));
1393 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uSel);
1394 }
1395
1396 /* The the base and limit. */
1397 uint64_t u64Base;
1398 uint32_t cbLimit = X86DESC_LIMIT(Desc.Legacy);
1399 if (Desc.Legacy.Gen.u1Granularity)
1400 cbLimit = (cbLimit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
1401
1402 if ( pIemCpu->enmCpuMode == IEMMODE_64BIT
1403 && iSegReg < X86_SREG_FS)
1404 u64Base = 0;
1405 else
1406 u64Base = X86DESC_BASE(Desc.Legacy);
1407
1408 /*
1409 * Ok, everything checked out fine. Now set the accessed bit before
1410 * committing the result into the registers.
1411 */
1412 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1413 {
1414 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uSel);
1415 if (rcStrict != VINF_SUCCESS)
1416 return rcStrict;
1417 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1418 }
1419
1420 /* commit */
1421 *pSel = uSel;
1422 pHid->Attr.u = (Desc.Legacy.u >> (16+16+8)) & UINT32_C(0xf0ff); /** @todo do we have a define for 0xf0ff? */
1423 pHid->u32Limit = cbLimit;
1424 pHid->u64Base = u64Base;
1425
1426 /** @todo check if the hidden bits are loaded correctly for 64-bit
1427 * mode. */
1428
1429 iemRegAddToRip(pIemCpu, cbInstr);
1430 return VINF_SUCCESS;
1431}
1432
1433
1434/**
1435 * Implements 'mov SReg, r/m'.
1436 *
1437 * @param iSegReg The segment register number (valid).
1438 * @param uSel The new selector value.
1439 */
1440IEM_CIMPL_DEF_2(iemCImpl_load_SReg, uint8_t, iSegReg, uint16_t, uSel)
1441{
1442 VBOXSTRICTRC rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
1443 if (rcStrict == VINF_SUCCESS)
1444 {
1445 if (iSegReg == X86_SREG_SS)
1446 {
1447 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1448 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
1449 }
1450 }
1451 return rcStrict;
1452}
1453
1454
1455/**
1456 * Implements 'pop SReg'.
1457 *
1458 * @param iSegReg The segment register number (valid).
1459 * @param enmEffOpSize The efficient operand size (valid).
1460 */
1461IEM_CIMPL_DEF_2(iemOpCImpl_pop_Sreg, uint8_t, iSegReg, IEMMODE, enmEffOpSize)
1462{
1463 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1464 VBOXSTRICTRC rcStrict;
1465
1466 /*
1467 * Read the selector off the stack and join paths with mov ss, reg.
1468 */
1469 RTUINT64U TmpRsp;
1470 TmpRsp.u = pCtx->rsp;
1471 switch (enmEffOpSize)
1472 {
1473 case IEMMODE_16BIT:
1474 {
1475 uint16_t uSel;
1476 rcStrict = iemMemStackPopU16Ex(pIemCpu, &uSel, &TmpRsp);
1477 if (rcStrict == VINF_SUCCESS)
1478 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
1479 break;
1480 }
1481
1482 case IEMMODE_32BIT:
1483 {
1484 uint32_t u32Value;
1485 rcStrict = iemMemStackPopU32Ex(pIemCpu, &u32Value, &TmpRsp);
1486 if (rcStrict == VINF_SUCCESS)
1487 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, (uint16_t)u32Value);
1488 break;
1489 }
1490
1491 case IEMMODE_64BIT:
1492 {
1493 uint64_t u64Value;
1494 rcStrict = iemMemStackPopU64Ex(pIemCpu, &u64Value, &TmpRsp);
1495 if (rcStrict == VINF_SUCCESS)
1496 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, (uint16_t)u64Value);
1497 break;
1498 }
1499 IEM_NOT_REACHED_DEFAULT_CASE_RET();
1500 }
1501
1502 /*
1503 * Commit the stack on success.
1504 */
1505 if (rcStrict == VINF_SUCCESS)
1506 {
1507 pCtx->rsp = TmpRsp.u;
1508 if (iSegReg == X86_SREG_SS)
1509 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
1510 }
1511 return rcStrict;
1512}
1513
1514
1515/**
1516 * Implements lgs, lfs, les, lds & lss.
1517 */
1518IEM_CIMPL_DEF_5(iemCImpl_load_SReg_Greg,
1519 uint16_t, uSel,
1520 uint64_t, offSeg,
1521 uint8_t, iSegReg,
1522 uint8_t, iGReg,
1523 IEMMODE, enmEffOpSize)
1524{
1525 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1526 VBOXSTRICTRC rcStrict;
1527
1528 /*
1529 * Use iemCImpl_LoadSReg to do the tricky segment register loading.
1530 */
1531 /** @todo verify and test that mov, pop and lXs works the segment
1532 * register loading in the exact same way. */
1533 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
1534 if (rcStrict == VINF_SUCCESS)
1535 {
1536 switch (enmEffOpSize)
1537 {
1538 case IEMMODE_16BIT:
1539 *(uint16_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
1540 break;
1541 case IEMMODE_32BIT:
1542 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
1543 break;
1544 case IEMMODE_64BIT:
1545 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
1546 break;
1547 IEM_NOT_REACHED_DEFAULT_CASE_RET();
1548 }
1549 }
1550
1551 return rcStrict;
1552}
1553
1554
1555/**
1556 * Implements lgdt.
1557 *
1558 * @param iEffSeg The segment of the new ldtr contents
1559 * @param GCPtrEffSrc The address of the new ldtr contents.
1560 * @param enmEffOpSize The effective operand size.
1561 */
1562IEM_CIMPL_DEF_3(iemCImpl_lgdt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc, IEMMODE, enmEffOpSize)
1563{
1564 if (pIemCpu->uCpl != 0)
1565 return iemRaiseGeneralProtectionFault0(pIemCpu);
1566 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
1567
1568 /*
1569 * Fetch the limit and base address.
1570 */
1571 uint16_t cbLimit;
1572 RTGCPTR GCPtrBase;
1573 VBOXSTRICTRC rcStrict = iemMemFetchDataXdtr(pIemCpu, &cbLimit, &GCPtrBase, iEffSeg, GCPtrEffSrc, enmEffOpSize);
1574 if (rcStrict == VINF_SUCCESS)
1575 {
1576 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1577 rcStrict = CPUMSetGuestGDTR(IEMCPU_TO_VMCPU(pIemCpu), GCPtrBase, cbLimit);
1578 else
1579 {
1580 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1581 pCtx->gdtr.cbGdt = cbLimit;
1582 pCtx->gdtr.pGdt = GCPtrBase;
1583 }
1584 if (rcStrict == VINF_SUCCESS)
1585 iemRegAddToRip(pIemCpu, cbInstr);
1586 }
1587 return rcStrict;
1588}
1589
1590
1591/**
1592 * Implements lidt.
1593 *
1594 * @param iEffSeg The segment of the new ldtr contents
1595 * @param GCPtrEffSrc The address of the new ldtr contents.
1596 * @param enmEffOpSize The effective operand size.
1597 */
1598IEM_CIMPL_DEF_3(iemCImpl_lidt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc, IEMMODE, enmEffOpSize)
1599{
1600 if (pIemCpu->uCpl != 0)
1601 return iemRaiseGeneralProtectionFault0(pIemCpu);
1602 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
1603
1604 /*
1605 * Fetch the limit and base address.
1606 */
1607 uint16_t cbLimit;
1608 RTGCPTR GCPtrBase;
1609 VBOXSTRICTRC rcStrict = iemMemFetchDataXdtr(pIemCpu, &cbLimit, &GCPtrBase, iEffSeg, GCPtrEffSrc, enmEffOpSize);
1610 if (rcStrict == VINF_SUCCESS)
1611 {
1612 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1613 rcStrict = CPUMSetGuestIDTR(IEMCPU_TO_VMCPU(pIemCpu), GCPtrBase, cbLimit);
1614 else
1615 {
1616 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1617 pCtx->idtr.cbIdt = cbLimit;
1618 pCtx->idtr.pIdt = GCPtrBase;
1619 }
1620 if (rcStrict == VINF_SUCCESS)
1621 iemRegAddToRip(pIemCpu, cbInstr);
1622 }
1623 return rcStrict;
1624}
1625
1626
1627/**
1628 * Implements mov GReg,CRx.
1629 *
1630 * @param iGReg The general register to store the CRx value in.
1631 * @param iCrReg The CRx register to read (valid).
1632 */
1633IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Cd, uint8_t, iGReg, uint8_t, iCrReg)
1634{
1635 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1636 if (pIemCpu->uCpl != 0)
1637 return iemRaiseGeneralProtectionFault0(pIemCpu);
1638 Assert(!pCtx->eflags.Bits.u1VM);
1639
1640 /* read it */
1641 uint64_t crX;
1642 switch (iCrReg)
1643 {
1644 case 0: crX = pCtx->cr0; break;
1645 case 2: crX = pCtx->cr2; break;
1646 case 3: crX = pCtx->cr3; break;
1647 case 4: crX = pCtx->cr4; break;
1648 case 8:
1649 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1650 AssertFailedReturn(VERR_NOT_IMPLEMENTED); /** @todo implement CR8 reading and writing. */
1651 else
1652 crX = 0xff;
1653 break;
1654 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
1655 }
1656
1657 /* store it */
1658 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
1659 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = crX;
1660 else
1661 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = (uint32_t)crX;
1662
1663 iemRegAddToRip(pIemCpu, cbInstr);
1664 return VINF_SUCCESS;
1665}
1666
1667
1668/**
1669 * Used to implemented 'mov CRx,GReg' and 'lmsw r/m16'.
1670 *
1671 * @param iCrReg The CRx register to write (valid).
1672 * @param uNewCrX The new value.
1673 */
1674IEM_CIMPL_DEF_2(iemCImpl_load_CrX, uint8_t, iCrReg, uint64_t, uNewCrX)
1675{
1676 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1677 PVMCPU pVCpu = IEMCPU_TO_VMCPU(pIemCpu);
1678 VBOXSTRICTRC rcStrict;
1679 int rc;
1680
1681 /*
1682 * Try store it.
1683 * Unfortunately, CPUM only does a tiny bit of the work.
1684 */
1685 switch (iCrReg)
1686 {
1687 case 0:
1688 {
1689 /*
1690 * Perform checks.
1691 */
1692 uint64_t const uOldCrX = pCtx->cr0;
1693 uNewCrX |= X86_CR0_ET; /* hardcoded */
1694
1695 /* Check for reserved bits. */
1696 uint32_t const fValid = X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS
1697 | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM
1698 | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG;
1699 if (uNewCrX & ~(uint64_t)fValid)
1700 {
1701 Log(("Trying to set reserved CR0 bits: NewCR0=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
1702 return iemRaiseGeneralProtectionFault0(pIemCpu);
1703 }
1704
1705 /* Check for invalid combinations. */
1706 if ( (uNewCrX & X86_CR0_PG)
1707 && !(uNewCrX & X86_CR0_PE) )
1708 {
1709 Log(("Trying to set CR0.PG without CR0.PE\n"));
1710 return iemRaiseGeneralProtectionFault0(pIemCpu);
1711 }
1712
1713 if ( !(uNewCrX & X86_CR0_CD)
1714 && (uNewCrX & X86_CR0_NW) )
1715 {
1716 Log(("Trying to clear CR0.CD while leaving CR0.NW set\n"));
1717 return iemRaiseGeneralProtectionFault0(pIemCpu);
1718 }
1719
1720 /* Long mode consistency checks. */
1721 if ( (uNewCrX & X86_CR0_PG)
1722 && !(uOldCrX & X86_CR0_PG)
1723 && (pCtx->msrEFER & MSR_K6_EFER_LME) )
1724 {
1725 if (!(pCtx->cr4 & X86_CR4_PAE))
1726 {
1727 Log(("Trying to enabled long mode paging without CR4.PAE set\n"));
1728 return iemRaiseGeneralProtectionFault0(pIemCpu);
1729 }
1730 if (pCtx->csHid.Attr.n.u1Long)
1731 {
1732 Log(("Trying to enabled long mode paging with a long CS descriptor loaded.\n"));
1733 return iemRaiseGeneralProtectionFault0(pIemCpu);
1734 }
1735 }
1736
1737 /** @todo check reserved PDPTR bits as AMD states. */
1738
1739 /*
1740 * Change CR0.
1741 */
1742 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1743 {
1744 rc = CPUMSetGuestCR0(pVCpu, uNewCrX);
1745 AssertRCSuccessReturn(rc, RT_FAILURE_NP(rc) ? rc : VERR_INTERNAL_ERROR_3);
1746 }
1747 else
1748 pCtx->cr0 = uNewCrX;
1749 Assert(pCtx->cr0 == uNewCrX);
1750
1751 /*
1752 * Change EFER.LMA if entering or leaving long mode.
1753 */
1754 if ( (uNewCrX & X86_CR0_PG) != (uOldCrX & X86_CR0_PG)
1755 && (pCtx->msrEFER & MSR_K6_EFER_LME) )
1756 {
1757 uint64_t NewEFER = pCtx->msrEFER;
1758 if (uNewCrX & X86_CR0_PG)
1759 NewEFER |= MSR_K6_EFER_LME;
1760 else
1761 NewEFER &= ~MSR_K6_EFER_LME;
1762
1763 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1764 CPUMSetGuestEFER(pVCpu, NewEFER);
1765 else
1766 pCtx->msrEFER = NewEFER;
1767 Assert(pCtx->msrEFER == NewEFER);
1768 }
1769
1770 /*
1771 * Inform PGM.
1772 */
1773 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1774 {
1775 if ( (uNewCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
1776 != (uOldCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) )
1777 {
1778 rc = PGMFlushTLB(pVCpu, pCtx->cr3, true /* global */);
1779 AssertRCReturn(rc, rc);
1780 /* ignore informational status codes */
1781 }
1782 rcStrict = PGMChangeMode(pVCpu, pCtx->cr0, pCtx->cr4, pCtx->msrEFER);
1783 /** @todo Status code management. */
1784 }
1785 else
1786 rcStrict = VINF_SUCCESS;
1787 break;
1788 }
1789
1790 /*
1791 * CR2 can be changed without any restrictions.
1792 */
1793 case 2:
1794 pCtx->cr2 = uNewCrX;
1795 rcStrict = VINF_SUCCESS;
1796 break;
1797
1798 /*
1799 * CR3 is relatively simple, although AMD and Intel have different
1800 * accounts of how setting reserved bits are handled. We take intel's
1801 * word for the lower bits and AMD's for the high bits (63:52).
1802 */
1803 /** @todo Testcase: Setting reserved bits in CR3, especially before
1804 * enabling paging. */
1805 case 3:
1806 {
1807 /* check / mask the value. */
1808 if (uNewCrX & UINT64_C(0xfff0000000000000))
1809 {
1810 Log(("Trying to load CR3 with invalid high bits set: %#llx\n", uNewCrX));
1811 return iemRaiseGeneralProtectionFault0(pIemCpu);
1812 }
1813
1814 uint64_t fValid;
1815 if ( (pCtx->cr4 & X86_CR4_PAE)
1816 && (pCtx->msrEFER & MSR_K6_EFER_LME))
1817 fValid = UINT64_C(0x000ffffffffff014);
1818 else if (pCtx->cr4 & X86_CR4_PAE)
1819 fValid = UINT64_C(0xfffffff4);
1820 else
1821 fValid = UINT64_C(0xfffff014);
1822 if (uNewCrX & ~fValid)
1823 {
1824 Log(("Automatically clearing reserved bits in CR3 load: NewCR3=%#llx ClearedBits=%#llx\n",
1825 uNewCrX, uNewCrX & ~fValid));
1826 uNewCrX &= fValid;
1827 }
1828
1829 /** @todo If we're in PAE mode we should check the PDPTRs for
1830 * invalid bits. */
1831
1832 /* Make the change. */
1833 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1834 {
1835 rc = CPUMSetGuestCR3(pVCpu, uNewCrX);
1836 AssertRCSuccessReturn(rc, rc);
1837 }
1838 else
1839 pCtx->cr3 = uNewCrX;
1840
1841 /* Inform PGM. */
1842 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1843 {
1844 if (pCtx->cr0 & X86_CR0_PG)
1845 {
1846 rc = PGMFlushTLB(pVCpu, pCtx->cr3, !(pCtx->cr3 & X86_CR4_PGE));
1847 AssertRCReturn(rc, rc);
1848 /* ignore informational status codes */
1849 /** @todo status code management */
1850 }
1851 }
1852 rcStrict = VINF_SUCCESS;
1853 break;
1854 }
1855
1856 /*
1857 * CR4 is a bit more tedious as there are bits which cannot be cleared
1858 * under some circumstances and such.
1859 */
1860 case 4:
1861 {
1862 uint64_t const uOldCrX = pCtx->cr0;
1863
1864 /* reserved bits */
1865 uint32_t fValid = X86_CR4_VME | X86_CR4_PVI
1866 | X86_CR4_TSD | X86_CR4_DE
1867 | X86_CR4_PSE | X86_CR4_PAE
1868 | X86_CR4_MCE | X86_CR4_PGE
1869 | X86_CR4_PCE | X86_CR4_OSFSXR
1870 | X86_CR4_OSXMMEEXCPT;
1871 //if (xxx)
1872 // fValid |= X86_CR4_VMXE;
1873 //if (xxx)
1874 // fValid |= X86_CR4_OSXSAVE;
1875 if (uNewCrX & ~(uint64_t)fValid)
1876 {
1877 Log(("Trying to set reserved CR4 bits: NewCR4=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
1878 return iemRaiseGeneralProtectionFault0(pIemCpu);
1879 }
1880
1881 /* long mode checks. */
1882 if ( (uOldCrX & X86_CR4_PAE)
1883 && !(uNewCrX & X86_CR4_PAE)
1884 && (pCtx->msrEFER & MSR_K6_EFER_LMA) )
1885 {
1886 Log(("Trying to set clear CR4.PAE while long mode is active\n"));
1887 return iemRaiseGeneralProtectionFault0(pIemCpu);
1888 }
1889
1890
1891 /*
1892 * Change it.
1893 */
1894 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1895 {
1896 rc = CPUMSetGuestCR4(pVCpu, uNewCrX);
1897 AssertRCSuccessReturn(rc, rc);
1898 }
1899 else
1900 pCtx->cr4 = uNewCrX;
1901 Assert(pCtx->cr4 == uNewCrX);
1902
1903 /*
1904 * Notify SELM and PGM.
1905 */
1906 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1907 {
1908 /* SELM - VME may change things wrt to the TSS shadowing. */
1909 if ((uNewCrX ^ uOldCrX) & X86_CR4_VME)
1910 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);
1911
1912 /* PGM - flushing and mode. */
1913 if ( (uNewCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
1914 != (uOldCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) )
1915 {
1916 rc = PGMFlushTLB(pVCpu, pCtx->cr3, true /* global */);
1917 AssertRCReturn(rc, rc);
1918 /* ignore informational status codes */
1919 }
1920 rcStrict = PGMChangeMode(pVCpu, pCtx->cr0, pCtx->cr4, pCtx->msrEFER);
1921 /** @todo Status code management. */
1922 }
1923 else
1924 rcStrict = VINF_SUCCESS;
1925 break;
1926 }
1927
1928 /*
1929 * CR8 maps to the APIC TPR.
1930 */
1931 case 8:
1932 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1933 AssertFailedReturn(VERR_NOT_IMPLEMENTED); /** @todo implement CR8 reading and writing. */
1934 else
1935 rcStrict = VINF_SUCCESS;
1936 break;
1937
1938 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
1939 }
1940
1941 /*
1942 * Advance the RIP on success.
1943 */
1944 /** @todo Status code management. */
1945 if (rcStrict == VINF_SUCCESS)
1946 iemRegAddToRip(pIemCpu, cbInstr);
1947 return rcStrict;
1948
1949}
1950
1951
1952/**
1953 * Implements mov CRx,GReg.
1954 *
1955 * @param iCrReg The CRx register to write (valid).
1956 * @param iGReg The general register to store the CRx value in.
1957 */
1958IEM_CIMPL_DEF_2(iemCImpl_mov_Cd_Rd, uint8_t, iCrReg, uint8_t, iGReg)
1959{
1960 if (pIemCpu->uCpl != 0)
1961 return iemRaiseGeneralProtectionFault0(pIemCpu);
1962 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
1963
1964 /*
1965 * Read the new value from the source register and call common worker.
1966 */
1967 uint64_t uNewCrX;
1968 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
1969 uNewCrX = iemGRegFetchU64(pIemCpu, iGReg);
1970 else
1971 uNewCrX = iemGRegFetchU32(pIemCpu, iGReg);
1972 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, iCrReg, uNewCrX);
1973}
1974
1975
1976/**
1977 * Implements 'LMSW r/m16'
1978 *
1979 * @param u16NewMsw The new value.
1980 */
1981IEM_CIMPL_DEF_1(iemCImpl_lmsw, uint16_t, u16NewMsw)
1982{
1983 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1984
1985 if (pIemCpu->uCpl != 0)
1986 return iemRaiseGeneralProtectionFault0(pIemCpu);
1987 Assert(!pCtx->eflags.Bits.u1VM);
1988
1989 /*
1990 * Compose the new CR0 value and call common worker.
1991 */
1992 uint64_t uNewCr0 = pCtx->cr0 & ~(X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
1993 uNewCr0 |= u16NewMsw & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS);
1994 return IEM_CIMPL_CALL_2(iemCImpl_load_CrX, 0, uNewCr0);
1995}
1996
1997
1998/**
1999 * Implements 'IN eAX, port'.
2000 *
2001 * @param u16Port The source port.
2002 * @param cbReg The register size.
2003 */
2004IEM_CIMPL_DEF_2(iemCImpl_in, uint16_t, u16Port, uint8_t, cbReg)
2005{
2006 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2007
2008 /*
2009 * CPL check
2010 */
2011 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pIemCpu, pCtx, u16Port, cbReg);
2012 if (rcStrict != VINF_SUCCESS)
2013 return rcStrict;
2014
2015 /*
2016 * Perform the I/O.
2017 */
2018 uint32_t u32Value;
2019 if (IEM_VERIFICATION_ENABLED(pIemCpu))
2020 rcStrict = IOMIOPortRead(IEMCPU_TO_VM(pIemCpu), u16Port, &u32Value, cbReg);
2021 else
2022 rcStrict = iemVerifyFakeIOPortRead(pIemCpu, u16Port, &u32Value, cbReg);
2023 if (IOM_SUCCESS(rcStrict))
2024 {
2025 switch (cbReg)
2026 {
2027 case 1: pCtx->al = (uint8_t)u32Value; break;
2028 case 2: pCtx->ax = (uint16_t)u32Value; break;
2029 case 4: pCtx->rax = u32Value; break;
2030 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
2031 }
2032 iemRegAddToRip(pIemCpu, cbInstr);
2033 pIemCpu->cPotentialExits++;
2034 }
2035 /** @todo massage rcStrict. */
2036 return rcStrict;
2037}
2038
2039
2040/**
2041 * Implements 'IN eAX, DX'.
2042 *
2043 * @param cbReg The register size.
2044 */
2045IEM_CIMPL_DEF_1(iemCImpl_in_eAX_DX, uint8_t, cbReg)
2046{
2047 return IEM_CIMPL_CALL_2(iemCImpl_in, pIemCpu->CTX_SUFF(pCtx)->dx, cbReg);
2048}
2049
2050
2051/**
2052 * Implements 'OUT port, eAX'.
2053 *
2054 * @param u16Port The destination port.
2055 * @param cbReg The register size.
2056 */
2057IEM_CIMPL_DEF_2(iemCImpl_out, uint16_t, u16Port, uint8_t, cbReg)
2058{
2059 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2060
2061 /*
2062 * CPL check
2063 */
2064 if ( (pCtx->cr0 & X86_CR0_PE)
2065 && ( pIemCpu->uCpl > pCtx->eflags.Bits.u2IOPL
2066 || pCtx->eflags.Bits.u1VM) )
2067 {
2068 /** @todo I/O port permission bitmap check */
2069 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
2070 }
2071
2072 /*
2073 * Perform the I/O.
2074 */
2075 uint32_t u32Value;
2076 switch (cbReg)
2077 {
2078 case 1: u32Value = pCtx->al; break;
2079 case 2: u32Value = pCtx->ax; break;
2080 case 4: u32Value = pCtx->eax; break;
2081 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
2082 }
2083 VBOXSTRICTRC rc;
2084 if (IEM_VERIFICATION_ENABLED(pIemCpu))
2085 rc = IOMIOPortWrite(IEMCPU_TO_VM(pIemCpu), u16Port, u32Value, cbReg);
2086 else
2087 rc = iemVerifyFakeIOPortWrite(pIemCpu, u16Port, u32Value, cbReg);
2088 if (IOM_SUCCESS(rc))
2089 {
2090 iemRegAddToRip(pIemCpu, cbInstr);
2091 pIemCpu->cPotentialExits++;
2092 /** @todo massage rc. */
2093 }
2094 return rc;
2095}
2096
2097
2098/**
2099 * Implements 'OUT DX, eAX'.
2100 *
2101 * @param cbReg The register size.
2102 */
2103IEM_CIMPL_DEF_1(iemCImpl_out_DX_eAX, uint8_t, cbReg)
2104{
2105 return IEM_CIMPL_CALL_2(iemCImpl_out, pIemCpu->CTX_SUFF(pCtx)->dx, cbReg);
2106}
2107
2108
2109/**
2110 * Implements 'CLI'.
2111 */
2112IEM_CIMPL_DEF_0(iemCImpl_cli)
2113{
2114 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2115
2116 if (pCtx->cr0 & X86_CR0_PE)
2117 {
2118 uint8_t const uIopl = pCtx->eflags.Bits.u2IOPL;
2119 if (!pCtx->eflags.Bits.u1VM)
2120 {
2121 if (pIemCpu->uCpl <= uIopl)
2122 pCtx->eflags.Bits.u1IF = 0;
2123 else if ( pIemCpu->uCpl == 3
2124 && (pCtx->cr4 & X86_CR4_PVI) )
2125 pCtx->eflags.Bits.u1VIF = 0;
2126 else
2127 return iemRaiseGeneralProtectionFault0(pIemCpu);
2128 }
2129 /* V8086 */
2130 else if (uIopl == 3)
2131 pCtx->eflags.Bits.u1IF = 0;
2132 else if ( uIopl < 3
2133 && (pCtx->cr4 & X86_CR4_VME) )
2134 pCtx->eflags.Bits.u1VIF = 0;
2135 else
2136 return iemRaiseGeneralProtectionFault0(pIemCpu);
2137 }
2138 /* real mode */
2139 else
2140 pCtx->eflags.Bits.u1IF = 0;
2141 iemRegAddToRip(pIemCpu, cbInstr);
2142 return VINF_SUCCESS;
2143}
2144
2145
2146/**
2147 * Implements 'STI'.
2148 */
2149IEM_CIMPL_DEF_0(iemCImpl_sti)
2150{
2151 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2152
2153 if (pCtx->cr0 & X86_CR0_PE)
2154 {
2155 uint8_t const uIopl = pCtx->eflags.Bits.u2IOPL;
2156 if (!pCtx->eflags.Bits.u1VM)
2157 {
2158 if (pIemCpu->uCpl <= uIopl)
2159 pCtx->eflags.Bits.u1IF = 1;
2160 else if ( pIemCpu->uCpl == 3
2161 && (pCtx->cr4 & X86_CR4_PVI)
2162 && !pCtx->eflags.Bits.u1VIP )
2163 pCtx->eflags.Bits.u1VIF = 1;
2164 else
2165 return iemRaiseGeneralProtectionFault0(pIemCpu);
2166 }
2167 /* V8086 */
2168 else if (uIopl == 3)
2169 pCtx->eflags.Bits.u1IF = 1;
2170 else if ( uIopl < 3
2171 && (pCtx->cr4 & X86_CR4_VME)
2172 && !pCtx->eflags.Bits.u1VIP )
2173 pCtx->eflags.Bits.u1VIF = 1;
2174 else
2175 return iemRaiseGeneralProtectionFault0(pIemCpu);
2176 }
2177 /* real mode */
2178 else
2179 pCtx->eflags.Bits.u1IF = 1;
2180
2181 iemRegAddToRip(pIemCpu, cbInstr);
2182 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
2183 return VINF_SUCCESS;
2184}
2185
2186
2187/**
2188 * Implements 'HLT'.
2189 */
2190IEM_CIMPL_DEF_0(iemCImpl_hlt)
2191{
2192 if (pIemCpu->uCpl != 0)
2193 return iemRaiseGeneralProtectionFault0(pIemCpu);
2194 iemRegAddToRip(pIemCpu, cbInstr);
2195 return VINF_EM_HALT;
2196}
2197
2198
2199/*
2200 * Instantiate the various string operation combinations.
2201 */
2202#define OP_SIZE 8
2203#define ADDR_SIZE 16
2204#include "IEMAllCImplStrInstr.cpp.h"
2205#define OP_SIZE 8
2206#define ADDR_SIZE 32
2207#include "IEMAllCImplStrInstr.cpp.h"
2208#define OP_SIZE 8
2209#define ADDR_SIZE 64
2210#include "IEMAllCImplStrInstr.cpp.h"
2211
2212#define OP_SIZE 16
2213#define ADDR_SIZE 16
2214#include "IEMAllCImplStrInstr.cpp.h"
2215#define OP_SIZE 16
2216#define ADDR_SIZE 32
2217#include "IEMAllCImplStrInstr.cpp.h"
2218#define OP_SIZE 16
2219#define ADDR_SIZE 64
2220#include "IEMAllCImplStrInstr.cpp.h"
2221
2222#define OP_SIZE 32
2223#define ADDR_SIZE 16
2224#include "IEMAllCImplStrInstr.cpp.h"
2225#define OP_SIZE 32
2226#define ADDR_SIZE 32
2227#include "IEMAllCImplStrInstr.cpp.h"
2228#define OP_SIZE 32
2229#define ADDR_SIZE 64
2230#include "IEMAllCImplStrInstr.cpp.h"
2231
2232#define OP_SIZE 64
2233#define ADDR_SIZE 32
2234#include "IEMAllCImplStrInstr.cpp.h"
2235#define OP_SIZE 64
2236#define ADDR_SIZE 64
2237#include "IEMAllCImplStrInstr.cpp.h"
2238
2239
2240/** @} */
2241
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