VirtualBox

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

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

IEM: pop Ev; fixed the setting of accessed bit.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 72.1 KB
Line 
1/* $Id: IEMAllCImpl.cpp.h 36835 2011-04-25 00:29:01Z 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 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
803 }
804
805 /* commit */
806 pCtx->rip = offSeg;
807 pCtx->cs = uSel & (X86_SEL_MASK | X86_SEL_LDT);
808 pCtx->cs |= pIemCpu->uCpl; /** @todo is this right for conforming segs? or in general? */
809 pCtx->csHid.Attr.u = (Desc.Legacy.u >> (16+16+8)) & UINT32_C(0xf0ff);
810#ifdef IEM_VERIFICATION_MODE
811 pCtx->csHid.Attr.u &= ~(uint32_t)X86_SEL_TYPE_ACCESSED; /** @todo check what VT-x and AMD-V does here. */
812#endif
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 iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
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 iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
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 int3 and int XX.
1063 *
1064 * @param u8Int The interrupt vector number.
1065 * @param fIsBpInstr Is it the breakpoint instruction.
1066 */
1067IEM_CIMPL_DEF_2(iemCImpl_int, uint8_t, u8Int, bool, fIsBpInstr)
1068{
1069 /** @todo we should call TRPM to do this job. */
1070 VBOXSTRICTRC rcStrict;
1071 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1072
1073 /*
1074 * Real mode is easy.
1075 */
1076 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
1077 && IEM_IS_REAL_MODE(pIemCpu))
1078 {
1079 /* read the IDT entry. */
1080 if (pCtx->idtr.cbIdt < UINT32_C(4) * u8Int + 3)
1081 return iemRaiseGeneralProtectionFault(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Int << X86_TRAP_ERR_SEL_SHIFT));
1082 RTFAR16 Idte;
1083 rcStrict = iemMemFetchDataU32(pIemCpu, (uint32_t *)&Idte, UINT8_MAX, pCtx->idtr.pIdt + UINT32_C(4) * u8Int);
1084 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
1085 return rcStrict;
1086
1087 /* push the stack frame. */
1088 uint16_t *pu16Frame;
1089 uint64_t uNewRsp;
1090 rcStrict = iemMemStackPushBeginSpecial(pIemCpu, 6, (void **)&pu16Frame, &uNewRsp);
1091 if (rcStrict != VINF_SUCCESS)
1092 return rcStrict;
1093
1094 pu16Frame[2] = (uint16_t)pCtx->eflags.u;
1095 pu16Frame[1] = (uint16_t)pCtx->cs;
1096 pu16Frame[0] = pCtx->ip + cbInstr;
1097 rcStrict = iemMemStackPushCommitSpecial(pIemCpu, pu16Frame, uNewRsp);
1098 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
1099 return rcStrict;
1100
1101 /* load the vector address into cs:ip. */
1102 pCtx->cs = Idte.sel;
1103 pCtx->csHid.u64Base = (uint32_t)Idte.sel << 4;
1104 /** @todo do we load attribs and limit as well? Should we check against limit like far jump? */
1105 pCtx->rip = Idte.off;
1106 pCtx->eflags.Bits.u1IF = 0;
1107 return VINF_SUCCESS;
1108 }
1109
1110 AssertFailed();
1111 return VERR_NOT_IMPLEMENTED;
1112}
1113
1114
1115/**
1116 * Implements iret.
1117 *
1118 * @param enmEffOpSize The effective operand size.
1119 */
1120IEM_CIMPL_DEF_1(iemCImpl_iret, IEMMODE, enmEffOpSize)
1121{
1122 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1123 VBOXSTRICTRC rcStrict;
1124 uint64_t uNewRsp;
1125
1126 /*
1127 * Real mode is easy, V8086 mode is relative similar.
1128 */
1129 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
1130 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
1131 {
1132 /* iret throws an exception if VME isn't enabled. */
1133 if ( pCtx->eflags.Bits.u1VM
1134 && !(pCtx->cr4 & X86_CR4_VME))
1135 return iemRaiseGeneralProtectionFault0(pIemCpu);
1136
1137 /* Do the stack bits, but don't commit RSP before everything checks
1138 out right. */
1139 union
1140 {
1141 uint32_t const *pu32;
1142 uint16_t const *pu16;
1143 void const *pv;
1144 } uFrame;
1145 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
1146 uint16_t uNewCs;
1147 uint32_t uNewEip;
1148 uint32_t uNewFlags;
1149 if (enmEffOpSize == IEMMODE_32BIT)
1150 {
1151 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 12, &uFrame.pv, &uNewRsp);
1152 if (rcStrict != VINF_SUCCESS)
1153 return rcStrict;
1154 uNewEip = uFrame.pu32[0];
1155 uNewCs = (uint16_t)uFrame.pu32[1];
1156 uNewFlags = uFrame.pu32[2];
1157 uNewFlags &= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
1158 | X86_EFL_TF | X86_EFL_IF | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT
1159 | X86_EFL_RF /*| X86_EFL_VM*/ | X86_EFL_AC /*|X86_EFL_VIF*/ /*|X86_EFL_VIP*/
1160 | X86_EFL_ID;
1161 uNewFlags |= pCtx->eflags.u & (X86_EFL_VM | X86_EFL_VIF | X86_EFL_VIP | X86_EFL_1);
1162 }
1163 else
1164 {
1165 rcStrict = iemMemStackPopBeginSpecial(pIemCpu, 6, &uFrame.pv, &uNewRsp);
1166 if (rcStrict != VINF_SUCCESS)
1167 return rcStrict;
1168 uNewEip = uFrame.pu16[0];
1169 uNewCs = uFrame.pu16[1];
1170 uNewFlags = uFrame.pu16[2];
1171 uNewFlags &= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF
1172 | X86_EFL_TF | X86_EFL_IF | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT;
1173 uNewFlags |= pCtx->eflags.u & (UINT16_C(0xffff0000) | X86_EFL_1);
1174 /** @todo The intel pseudo code does not indicate what happens to
1175 * reserved flags. We just ignore them. */
1176 }
1177 /** @todo Check how this is supposed to work if sp=0xfffe. */
1178
1179 /* Check the limit of the new EIP. */
1180 /** @todo Only the AMD pseudo code check the limit here, what's
1181 * right? */
1182 if (uNewEip > pCtx->csHid.u32Limit)
1183 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
1184
1185 /* V8086 checks and flag adjustments */
1186 if (pCtx->eflags.Bits.u1VM)
1187 {
1188 if (pCtx->eflags.Bits.u2IOPL == 3)
1189 {
1190 /* Preserve IOPL and clear RF. */
1191 uNewFlags &= ~(X86_EFL_IOPL | X86_EFL_RF);
1192 uNewFlags |= pCtx->eflags.u & (X86_EFL_IOPL);
1193 }
1194 else if ( enmEffOpSize == IEMMODE_16BIT
1195 && ( !(uNewFlags & X86_EFL_IF)
1196 || !pCtx->eflags.Bits.u1VIP )
1197 && !(uNewFlags & X86_EFL_TF) )
1198 {
1199 /* Move IF to VIF, clear RF and preserve IF and IOPL.*/
1200 uNewFlags &= ~X86_EFL_VIF;
1201 uNewFlags |= (uNewFlags & X86_EFL_IF) << (19 - 9);
1202 uNewFlags &= ~(X86_EFL_IF | X86_EFL_IOPL | X86_EFL_RF);
1203 uNewFlags |= pCtx->eflags.u & (X86_EFL_IF | X86_EFL_IOPL);
1204 }
1205 else
1206 return iemRaiseGeneralProtectionFault0(pIemCpu);
1207 }
1208
1209 /* commit the operation. */
1210 rcStrict = iemMemStackPopCommitSpecial(pIemCpu, uFrame.pv, uNewRsp);
1211 if (rcStrict != VINF_SUCCESS)
1212 return rcStrict;
1213 pCtx->rip = uNewEip;
1214 pCtx->cs = uNewCs;
1215 pCtx->csHid.u64Base = (uint32_t)uNewCs << 4;
1216 /** @todo do we load attribs and limit as well? */
1217 Assert(uNewFlags & X86_EFL_1);
1218 pCtx->eflags.u = uNewFlags;
1219
1220 return VINF_SUCCESS;
1221 }
1222
1223
1224 AssertFailed();
1225 return VERR_NOT_IMPLEMENTED;
1226}
1227
1228
1229/**
1230 * Common worker for 'pop SReg', 'mov SReg, GReg' and 'lXs GReg, reg/mem'.
1231 *
1232 * @param iSegReg The segment register number (valid).
1233 * @param uSel The new selector value.
1234 */
1235IEM_CIMPL_DEF_2(iemCImpl_LoadSReg, uint8_t, iSegReg, uint16_t, uSel)
1236{
1237 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1238 uint16_t *pSel = iemSRegRef(pIemCpu, iSegReg);
1239 PCPUMSELREGHID pHid = iemSRegGetHid(pIemCpu, iSegReg);
1240
1241 Assert(iSegReg <= X86_SREG_GS && iSegReg != X86_SREG_CS);
1242
1243 /*
1244 * Real mode and V8086 mode are easy.
1245 */
1246 if ( pIemCpu->enmCpuMode == IEMMODE_16BIT
1247 && IEM_IS_REAL_OR_V86_MODE(pIemCpu))
1248 {
1249 *pSel = uSel;
1250 pHid->u64Base = (uint32_t)uSel << 4;
1251 /** @todo Does the CPU actually load limits and attributes in the
1252 * real/V8086 mode segment load case? It doesn't for CS in far
1253 * jumps... Affects unreal mode. */
1254 pHid->u32Limit = 0xffff;
1255 pHid->Attr.u = 0;
1256 pHid->Attr.n.u1Present = 1;
1257 pHid->Attr.n.u1DescType = 1;
1258 pHid->Attr.n.u4Type = iSegReg != X86_SREG_CS
1259 ? X86_SEL_TYPE_RW
1260 : X86_SEL_TYPE_READ | X86_SEL_TYPE_CODE;
1261
1262 iemRegAddToRip(pIemCpu, cbInstr);
1263 return VINF_SUCCESS;
1264 }
1265
1266 /*
1267 * Protected mode.
1268 *
1269 * Check if it's a null segment selector value first, that's OK for DS, ES,
1270 * FS and GS. If not null, then we have to load and parse the descriptor.
1271 */
1272 if (!(uSel & (X86_SEL_MASK | X86_SEL_LDT)))
1273 {
1274 if (iSegReg == X86_SREG_SS)
1275 {
1276 if ( pIemCpu->enmCpuMode != IEMMODE_64BIT
1277 || pIemCpu->uCpl != 0
1278 || uSel != 0) /** @todo We cannot 'mov ss, 3' in 64-bit kernel mode, can we? */
1279 {
1280 Log(("load sreg -> invalid stack selector, #GP(0)\n", uSel));
1281 return iemRaiseGeneralProtectionFault0(pIemCpu);
1282 }
1283
1284 /* In 64-bit kernel mode, the stack can be 0 because of the way
1285 interrupts are dispatched when in kernel ctx. Just load the
1286 selector value into the register and leave the hidden bits
1287 as is. */
1288 *pSel = uSel;
1289 iemRegAddToRip(pIemCpu, cbInstr);
1290 return VINF_SUCCESS;
1291 }
1292
1293 *pSel = uSel; /* Not RPL, remember :-) */
1294 if ( pIemCpu->enmCpuMode == IEMMODE_64BIT
1295 && iSegReg != X86_SREG_FS
1296 && iSegReg != X86_SREG_GS)
1297 {
1298 /** @todo figure out what this actually does, it works. Needs
1299 * testcase! */
1300 pHid->Attr.u = 0;
1301 pHid->Attr.n.u1Present = 1;
1302 pHid->Attr.n.u1Long = 1;
1303 pHid->Attr.n.u4Type = X86_SEL_TYPE_RW;
1304 pHid->Attr.n.u2Dpl = 3;
1305 pHid->u32Limit = 0;
1306 pHid->u64Base = 0;
1307 }
1308 else
1309 {
1310 pHid->Attr.u = 0;
1311 pHid->u32Limit = 0;
1312 pHid->u64Base = 0;
1313 }
1314 iemRegAddToRip(pIemCpu, cbInstr);
1315 return VINF_SUCCESS;
1316 }
1317
1318 /* Fetch the descriptor. */
1319 IEMSELDESC Desc;
1320 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, &Desc, uSel);
1321 if (rcStrict != VINF_SUCCESS)
1322 return rcStrict;
1323
1324 /* Check GPs first. */
1325 if (!Desc.Legacy.Gen.u1DescType)
1326 {
1327 Log(("load sreg %d - system selector (%#x) -> #GP\n", iSegReg, uSel, Desc.Legacy.Gen.u4Type));
1328 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1329 }
1330 if (iSegReg == X86_SREG_SS) /* SS gets different treatment */
1331 {
1332 if ( (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
1333 || !(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
1334 {
1335 Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
1336 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1337 }
1338 if ( (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
1339 || !(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
1340 {
1341 Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
1342 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1343 }
1344 if ((uSel & X86_SEL_RPL) != pIemCpu->uCpl)
1345 {
1346 Log(("load sreg SS, %#x - RPL and CPL (%d) differs -> #GP\n", uSel, pIemCpu->uCpl));
1347 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1348 }
1349 if (Desc.Legacy.Gen.u2Dpl != pIemCpu->uCpl)
1350 {
1351 Log(("load sreg SS, %#x - DPL (%d) and CPL (%d) differs -> #GP\n", uSel, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
1352 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1353 }
1354 }
1355 else
1356 {
1357 if ((Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
1358 {
1359 Log(("load sreg%u, %#x - execute only segment -> #GP\n", iSegReg, uSel));
1360 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1361 }
1362 if ( (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
1363 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
1364 {
1365#if 0 /* this is what intel says. */
1366 if ( (uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl
1367 && pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
1368 {
1369 Log(("load sreg%u, %#x - both RPL (%d) and CPL (%d) are greater than DPL (%d) -> #GP\n",
1370 iSegReg, uSel, (uSel & X86_SEL_RPL), pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
1371 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1372 }
1373#else /* this is what makes more sense. */
1374 if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
1375 {
1376 Log(("load sreg%u, %#x - RPL (%d) is greater than DPL (%d) -> #GP\n",
1377 iSegReg, uSel, (uSel & X86_SEL_RPL), Desc.Legacy.Gen.u2Dpl));
1378 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1379 }
1380 if (pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
1381 {
1382 Log(("load sreg%u, %#x - CPL (%d) is greater than DPL (%d) -> #GP\n",
1383 iSegReg, uSel, pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
1384 return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
1385 }
1386#endif
1387 }
1388 }
1389
1390 /* Is it there? */
1391 if (!Desc.Legacy.Gen.u1Present)
1392 {
1393 Log(("load sreg%d,%#x - segment not present -> #NP\n", iSegReg, uSel));
1394 return iemRaiseSelectorNotPresentBySelector(pIemCpu, uSel);
1395 }
1396
1397 /* The the base and limit. */
1398 uint64_t u64Base;
1399 uint32_t cbLimit = X86DESC_LIMIT(Desc.Legacy);
1400 if (Desc.Legacy.Gen.u1Granularity)
1401 cbLimit = (cbLimit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
1402
1403 if ( pIemCpu->enmCpuMode == IEMMODE_64BIT
1404 && iSegReg < X86_SREG_FS)
1405 u64Base = 0;
1406 else
1407 u64Base = X86DESC_BASE(Desc.Legacy);
1408
1409 /*
1410 * Ok, everything checked out fine. Now set the accessed bit before
1411 * committing the result into the registers.
1412 */
1413 if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1414 {
1415 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, uSel);
1416 if (rcStrict != VINF_SUCCESS)
1417 return rcStrict;
1418 Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1419 }
1420
1421 /* commit */
1422 *pSel = uSel;
1423 pHid->Attr.u = (Desc.Legacy.u >> (16+16+8)) & UINT32_C(0xf0ff); /** @todo do we have a define for 0xf0ff? */
1424 pHid->u32Limit = cbLimit;
1425 pHid->u64Base = u64Base;
1426
1427 /** @todo check if the hidden bits are loaded correctly for 64-bit
1428 * mode. */
1429
1430 iemRegAddToRip(pIemCpu, cbInstr);
1431 return VINF_SUCCESS;
1432}
1433
1434
1435/**
1436 * Implements 'mov SReg, r/m'.
1437 *
1438 * @param iSegReg The segment register number (valid).
1439 * @param uSel The new selector value.
1440 */
1441IEM_CIMPL_DEF_2(iemCImpl_load_SReg, uint8_t, iSegReg, uint16_t, uSel)
1442{
1443 VBOXSTRICTRC rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
1444 if (rcStrict == VINF_SUCCESS)
1445 {
1446 if (iSegReg == X86_SREG_SS)
1447 {
1448 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1449 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
1450 }
1451 }
1452 return rcStrict;
1453}
1454
1455
1456/**
1457 * Implements 'pop SReg'.
1458 *
1459 * @param iSegReg The segment register number (valid).
1460 * @param enmEffOpSize The efficient operand size (valid).
1461 */
1462IEM_CIMPL_DEF_2(iemOpCImpl_pop_Sreg, uint8_t, iSegReg, IEMMODE, enmEffOpSize)
1463{
1464 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1465 VBOXSTRICTRC rcStrict;
1466
1467 /*
1468 * Read the selector off the stack and join paths with mov ss, reg.
1469 */
1470 RTUINT64U TmpRsp;
1471 TmpRsp.u = pCtx->rsp;
1472 switch (enmEffOpSize)
1473 {
1474 case IEMMODE_16BIT:
1475 {
1476 uint16_t uSel;
1477 rcStrict = iemMemStackPopU16Ex(pIemCpu, &uSel, &TmpRsp);
1478 if (rcStrict == VINF_SUCCESS)
1479 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
1480 break;
1481 }
1482
1483 case IEMMODE_32BIT:
1484 {
1485 uint32_t u32Value;
1486 rcStrict = iemMemStackPopU32Ex(pIemCpu, &u32Value, &TmpRsp);
1487 if (rcStrict == VINF_SUCCESS)
1488 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, (uint16_t)u32Value);
1489 break;
1490 }
1491
1492 case IEMMODE_64BIT:
1493 {
1494 uint64_t u64Value;
1495 rcStrict = iemMemStackPopU64Ex(pIemCpu, &u64Value, &TmpRsp);
1496 if (rcStrict == VINF_SUCCESS)
1497 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, (uint16_t)u64Value);
1498 break;
1499 }
1500 IEM_NOT_REACHED_DEFAULT_CASE_RET();
1501 }
1502
1503 /*
1504 * Commit the stack on success.
1505 */
1506 if (rcStrict == VINF_SUCCESS)
1507 {
1508 pCtx->rsp = TmpRsp.u;
1509 if (iSegReg == X86_SREG_SS)
1510 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
1511 }
1512 return rcStrict;
1513}
1514
1515
1516/**
1517 * Implements lgs, lfs, les, lds & lss.
1518 */
1519IEM_CIMPL_DEF_5(iemCImpl_load_SReg_Greg,
1520 uint16_t, uSel,
1521 uint64_t, offSeg,
1522 uint8_t, iSegReg,
1523 uint8_t, iGReg,
1524 IEMMODE, enmEffOpSize)
1525{
1526 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1527 VBOXSTRICTRC rcStrict;
1528
1529 /*
1530 * Use iemCImpl_LoadSReg to do the tricky segment register loading.
1531 */
1532 /** @todo verify and test that mov, pop and lXs works the segment
1533 * register loading in the exact same way. */
1534 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
1535 if (rcStrict == VINF_SUCCESS)
1536 {
1537 switch (enmEffOpSize)
1538 {
1539 case IEMMODE_16BIT:
1540 *(uint16_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
1541 break;
1542 case IEMMODE_32BIT:
1543 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
1544 break;
1545 case IEMMODE_64BIT:
1546 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = offSeg;
1547 break;
1548 IEM_NOT_REACHED_DEFAULT_CASE_RET();
1549 }
1550 }
1551
1552 return rcStrict;
1553}
1554
1555
1556/**
1557 * Implements lgdt.
1558 *
1559 * @param iEffSeg The segment of the new ldtr contents
1560 * @param GCPtrEffSrc The address of the new ldtr contents.
1561 * @param enmEffOpSize The effective operand size.
1562 */
1563IEM_CIMPL_DEF_3(iemCImpl_lgdt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc, IEMMODE, enmEffOpSize)
1564{
1565 if (pIemCpu->uCpl != 0)
1566 return iemRaiseGeneralProtectionFault0(pIemCpu);
1567 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
1568
1569 /*
1570 * Fetch the limit and base address.
1571 */
1572 uint16_t cbLimit;
1573 RTGCPTR GCPtrBase;
1574 VBOXSTRICTRC rcStrict = iemMemFetchDataXdtr(pIemCpu, &cbLimit, &GCPtrBase, iEffSeg, GCPtrEffSrc, enmEffOpSize);
1575 if (rcStrict == VINF_SUCCESS)
1576 {
1577 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1578 rcStrict = CPUMSetGuestGDTR(IEMCPU_TO_VMCPU(pIemCpu), GCPtrBase, cbLimit);
1579 else
1580 {
1581 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1582 pCtx->gdtr.cbGdt = cbLimit;
1583 pCtx->gdtr.pGdt = GCPtrBase;
1584 }
1585 if (rcStrict == VINF_SUCCESS)
1586 iemRegAddToRip(pIemCpu, cbInstr);
1587 }
1588 return rcStrict;
1589}
1590
1591
1592/**
1593 * Implements lidt.
1594 *
1595 * @param iEffSeg The segment of the new ldtr contents
1596 * @param GCPtrEffSrc The address of the new ldtr contents.
1597 * @param enmEffOpSize The effective operand size.
1598 */
1599IEM_CIMPL_DEF_3(iemCImpl_lidt, uint8_t, iEffSeg, RTGCPTR, GCPtrEffSrc, IEMMODE, enmEffOpSize)
1600{
1601 if (pIemCpu->uCpl != 0)
1602 return iemRaiseGeneralProtectionFault0(pIemCpu);
1603 Assert(!pIemCpu->CTX_SUFF(pCtx)->eflags.Bits.u1VM);
1604
1605 /*
1606 * Fetch the limit and base address.
1607 */
1608 uint16_t cbLimit;
1609 RTGCPTR GCPtrBase;
1610 VBOXSTRICTRC rcStrict = iemMemFetchDataXdtr(pIemCpu, &cbLimit, &GCPtrBase, iEffSeg, GCPtrEffSrc, enmEffOpSize);
1611 if (rcStrict == VINF_SUCCESS)
1612 {
1613 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1614 rcStrict = CPUMSetGuestIDTR(IEMCPU_TO_VMCPU(pIemCpu), GCPtrBase, cbLimit);
1615 else
1616 {
1617 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1618 pCtx->idtr.cbIdt = cbLimit;
1619 pCtx->idtr.pIdt = GCPtrBase;
1620 }
1621 if (rcStrict == VINF_SUCCESS)
1622 iemRegAddToRip(pIemCpu, cbInstr);
1623 }
1624 return rcStrict;
1625}
1626
1627
1628/**
1629 * Implements mov GReg,CRx.
1630 *
1631 * @param iGReg The general register to store the CRx value in.
1632 * @param iCrReg The CRx register to read (valid).
1633 */
1634IEM_CIMPL_DEF_2(iemCImpl_mov_Rd_Cd, uint8_t, iGReg, uint8_t, iCrReg)
1635{
1636 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1637 if (pIemCpu->uCpl != 0)
1638 return iemRaiseGeneralProtectionFault0(pIemCpu);
1639 Assert(!pCtx->eflags.Bits.u1VM);
1640
1641 /* read it */
1642 uint64_t crX;
1643 switch (iCrReg)
1644 {
1645 case 0: crX = pCtx->cr0; break;
1646 case 2: crX = pCtx->cr2; break;
1647 case 3: crX = pCtx->cr3; break;
1648 case 4: crX = pCtx->cr4; break;
1649 case 8:
1650 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1651 AssertFailedReturn(VERR_NOT_IMPLEMENTED); /** @todo implement CR8 reading and writing. */
1652 else
1653 crX = 0xff;
1654 break;
1655 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
1656 }
1657
1658 /* store it */
1659 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
1660 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = crX;
1661 else
1662 *(uint64_t *)iemGRegRef(pIemCpu, iGReg) = (uint32_t)crX;
1663
1664 iemRegAddToRip(pIemCpu, cbInstr);
1665 return VINF_SUCCESS;
1666}
1667
1668
1669/**
1670 * Implements mov CRx,GReg.
1671 *
1672 * @param iCrReg The CRx register to read (valid).
1673 * @param iGReg The general register to store the CRx value in.
1674 */
1675IEM_CIMPL_DEF_2(iemCImpl_mov_Cd_Rd, uint8_t, iCrReg, uint8_t, iGReg)
1676{
1677 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1678 PVMCPU pVCpu = IEMCPU_TO_VMCPU(pIemCpu);
1679 VBOXSTRICTRC rcStrict;
1680 int rc;
1681
1682 if (pIemCpu->uCpl != 0)
1683 return iemRaiseGeneralProtectionFault0(pIemCpu);
1684 Assert(!pCtx->eflags.Bits.u1VM);
1685
1686 /*
1687 * Read the new value from the source register.
1688 */
1689 uint64_t NewCrX;
1690 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
1691 NewCrX = iemGRegFetchU64(pIemCpu, iGReg);
1692 else
1693 NewCrX = iemGRegFetchU32(pIemCpu, iGReg);
1694
1695 /*
1696 * Try store it.
1697 * Unfortunately, CPUM only does a tiny bit of the work.
1698 */
1699 switch (iCrReg)
1700 {
1701 case 0:
1702 {
1703 /*
1704 * Perform checks.
1705 */
1706 uint64_t const OldCrX = pCtx->cr0;
1707 NewCrX |= X86_CR0_ET; /* hardcoded */
1708
1709 /* Check for reserved bits. */
1710 uint32_t const fValid = X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS
1711 | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM
1712 | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG;
1713 if (NewCrX & ~(uint64_t)fValid)
1714 {
1715 Log(("Trying to set reserved CR0 bits: NewCR0=%#llx InvalidBits=%#llx\n", NewCrX, NewCrX & ~(uint64_t)fValid));
1716 return iemRaiseGeneralProtectionFault0(pIemCpu);
1717 }
1718
1719 /* Check for invalid combinations. */
1720 if ( (NewCrX & X86_CR0_PG)
1721 && !(NewCrX & X86_CR0_PE) )
1722 {
1723 Log(("Trying to set CR0.PG without CR0.PE\n"));
1724 return iemRaiseGeneralProtectionFault0(pIemCpu);
1725 }
1726
1727 if ( !(NewCrX & X86_CR0_CD)
1728 && (NewCrX & X86_CR0_NW) )
1729 {
1730 Log(("Trying to clear CR0.CD while leaving CR0.NW set\n"));
1731 return iemRaiseGeneralProtectionFault0(pIemCpu);
1732 }
1733
1734 /* Long mode consistency checks. */
1735 if ( (NewCrX & X86_CR0_PG)
1736 && !(OldCrX & X86_CR0_PG)
1737 && (pCtx->msrEFER & MSR_K6_EFER_LME) )
1738 {
1739 if (!(pCtx->cr4 & X86_CR4_PAE))
1740 {
1741 Log(("Trying to enabled long mode paging without CR4.PAE set\n"));
1742 return iemRaiseGeneralProtectionFault0(pIemCpu);
1743 }
1744 if (pCtx->csHid.Attr.n.u1Long)
1745 {
1746 Log(("Trying to enabled long mode paging with a long CS descriptor loaded.\n"));
1747 return iemRaiseGeneralProtectionFault0(pIemCpu);
1748 }
1749 }
1750
1751 /** @todo check reserved PDPTR bits as AMD states. */
1752
1753 /*
1754 * Change CR0.
1755 */
1756 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1757 {
1758 rc = CPUMSetGuestCR0(pVCpu, NewCrX);
1759 AssertRCSuccessReturn(rc, RT_FAILURE_NP(rc) ? rc : VERR_INTERNAL_ERROR_3);
1760 }
1761 else
1762 pCtx->cr0 = NewCrX;
1763 Assert(pCtx->cr0 == NewCrX);
1764
1765 /*
1766 * Change EFER.LMA if entering or leaving long mode.
1767 */
1768 if ( (NewCrX & X86_CR0_PG) != (OldCrX & X86_CR0_PG)
1769 && (pCtx->msrEFER & MSR_K6_EFER_LME) )
1770 {
1771 uint64_t NewEFER = pCtx->msrEFER;
1772 if (NewCrX & X86_CR0_PG)
1773 NewEFER |= MSR_K6_EFER_LME;
1774 else
1775 NewEFER &= ~MSR_K6_EFER_LME;
1776
1777 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1778 CPUMSetGuestEFER(pVCpu, NewEFER);
1779 else
1780 pCtx->msrEFER = NewEFER;
1781 Assert(pCtx->msrEFER == NewEFER);
1782 }
1783
1784 /*
1785 * Inform PGM.
1786 */
1787 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1788 {
1789 if ( (NewCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
1790 != (OldCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) )
1791 {
1792 rc = PGMFlushTLB(pVCpu, pCtx->cr3, true /* global */);
1793 AssertRCReturn(rc, rc);
1794 /* ignore informational status codes */
1795 }
1796 rcStrict = PGMChangeMode(pVCpu, pCtx->cr0, pCtx->cr4, pCtx->msrEFER);
1797 /** @todo Status code management. */
1798 }
1799 else
1800 rcStrict = VINF_SUCCESS;
1801 break;
1802 }
1803
1804 /*
1805 * CR2 can be changed without any restrictions.
1806 */
1807 case 2:
1808 pCtx->cr2 = NewCrX;
1809 rcStrict = VINF_SUCCESS;
1810 break;
1811
1812 /*
1813 * CR3 is relatively simple, although AMD and Intel have different
1814 * accounts of how setting reserved bits are handled. We take intel's
1815 * word for the lower bits and AMD's for the high bits (63:52).
1816 */
1817 /** @todo Testcase: Setting reserved bits in CR3, especially before
1818 * enabling paging. */
1819 case 3:
1820 {
1821 /* check / mask the value. */
1822 if (NewCrX & UINT64_C(0xfff0000000000000))
1823 {
1824 Log(("Trying to load CR3 with invalid high bits set: %#llx\n", NewCrX));
1825 return iemRaiseGeneralProtectionFault0(pIemCpu);
1826 }
1827
1828 uint64_t fValid;
1829 if ( (pCtx->cr4 & X86_CR4_PAE)
1830 && (pCtx->msrEFER & MSR_K6_EFER_LME))
1831 fValid = UINT64_C(0x000ffffffffff014);
1832 else if (pCtx->cr4 & X86_CR4_PAE)
1833 fValid = UINT64_C(0xfffffff4);
1834 else
1835 fValid = UINT64_C(0xfffff014);
1836 if (NewCrX & ~fValid)
1837 {
1838 Log(("Automatically clearing reserved bits in CR3 load: NewCR3=%#llx ClearedBits=%#llx\n",
1839 NewCrX, NewCrX & ~fValid));
1840 NewCrX &= fValid;
1841 }
1842
1843 /** @todo If we're in PAE mode we should check the PDPTRs for
1844 * invalid bits. */
1845
1846 /* Make the change. */
1847 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1848 {
1849 rc = CPUMSetGuestCR3(pVCpu, NewCrX);
1850 AssertRCSuccessReturn(rc, rc);
1851 }
1852 else
1853 pCtx->cr3 = NewCrX;
1854
1855 /* Inform PGM. */
1856 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1857 {
1858 if (pCtx->cr0 & X86_CR0_PG)
1859 {
1860 rc = PGMFlushTLB(pVCpu, pCtx->cr3, !(pCtx->cr3 & X86_CR4_PGE));
1861 AssertRCReturn(rc, rc);
1862 /* ignore informational status codes */
1863 /** @todo status code management */
1864 }
1865 }
1866 rcStrict = VINF_SUCCESS;
1867 break;
1868 }
1869
1870 /*
1871 * CR4 is a bit more tedious as there are bits which cannot be cleared
1872 * under some circumstances and such.
1873 */
1874 case 4:
1875 {
1876 uint64_t const OldCrX = pCtx->cr0;
1877
1878 /* reserved bits */
1879 uint32_t fValid = X86_CR4_VME | X86_CR4_PVI
1880 | X86_CR4_TSD | X86_CR4_DE
1881 | X86_CR4_PSE | X86_CR4_PAE
1882 | X86_CR4_MCE | X86_CR4_PGE
1883 | X86_CR4_PCE | X86_CR4_OSFSXR
1884 | X86_CR4_OSXMMEEXCPT;
1885 //if (xxx)
1886 // fValid |= X86_CR4_VMXE;
1887 //if (xxx)
1888 // fValid |= X86_CR4_OSXSAVE;
1889 if (NewCrX & ~(uint64_t)fValid)
1890 {
1891 Log(("Trying to set reserved CR4 bits: NewCR4=%#llx InvalidBits=%#llx\n", NewCrX, NewCrX & ~(uint64_t)fValid));
1892 return iemRaiseGeneralProtectionFault0(pIemCpu);
1893 }
1894
1895 /* long mode checks. */
1896 if ( (OldCrX & X86_CR4_PAE)
1897 && !(NewCrX & X86_CR4_PAE)
1898 && (pCtx->msrEFER & MSR_K6_EFER_LMA) )
1899 {
1900 Log(("Trying to set clear CR4.PAE while long mode is active\n"));
1901 return iemRaiseGeneralProtectionFault0(pIemCpu);
1902 }
1903
1904
1905 /*
1906 * Change it.
1907 */
1908 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1909 {
1910 rc = CPUMSetGuestCR4(pVCpu, NewCrX);
1911 AssertRCSuccessReturn(rc, rc);
1912 }
1913 else
1914 pCtx->cr4 = NewCrX;
1915 Assert(pCtx->cr4 == NewCrX);
1916
1917 /*
1918 * Notify SELM and PGM.
1919 */
1920 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1921 {
1922 /* SELM - VME may change things wrt to the TSS shadowing. */
1923 if ((NewCrX ^ OldCrX) & X86_CR4_VME)
1924 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);
1925
1926 /* PGM - flushing and mode. */
1927 if ( (NewCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
1928 != (OldCrX & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) )
1929 {
1930 rc = PGMFlushTLB(pVCpu, pCtx->cr3, true /* global */);
1931 AssertRCReturn(rc, rc);
1932 /* ignore informational status codes */
1933 }
1934 rcStrict = PGMChangeMode(pVCpu, pCtx->cr0, pCtx->cr4, pCtx->msrEFER);
1935 /** @todo Status code management. */
1936 }
1937 else
1938 rcStrict = VINF_SUCCESS;
1939 break;
1940 }
1941
1942 /*
1943 * CR8 maps to the APIC TPR.
1944 */
1945 case 8:
1946 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1947 AssertFailedReturn(VERR_NOT_IMPLEMENTED); /** @todo implement CR8 reading and writing. */
1948 else
1949 rcStrict = VINF_SUCCESS;
1950 break;
1951
1952 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* call checks */
1953 }
1954
1955 /*
1956 * Advance the RIP on success.
1957 */
1958 /** @todo Status code management. */
1959 if (rcStrict == VINF_SUCCESS)
1960 iemRegAddToRip(pIemCpu, cbInstr);
1961 return rcStrict;
1962}
1963
1964
1965/**
1966 * Implements 'IN eAX, port'.
1967 *
1968 * @param u16Port The source port.
1969 * @param cbReg The register size.
1970 */
1971IEM_CIMPL_DEF_2(iemCImpl_in, uint16_t, u16Port, uint8_t, cbReg)
1972{
1973 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1974
1975 /*
1976 * CPL check
1977 */
1978 VBOXSTRICTRC rcStrict = iemHlpCheckPortIOPermission(pIemCpu, pCtx, u16Port, cbReg);
1979 if (rcStrict != VINF_SUCCESS)
1980 return rcStrict;
1981
1982 /*
1983 * Perform the I/O.
1984 */
1985 uint32_t u32Value;
1986 if (IEM_VERIFICATION_ENABLED(pIemCpu))
1987 rcStrict = IOMIOPortRead(IEMCPU_TO_VM(pIemCpu), u16Port, &u32Value, cbReg);
1988 else
1989 rcStrict = iemVerifyFakeIOPortRead(pIemCpu, u16Port, &u32Value, cbReg);
1990 if (IOM_SUCCESS(rcStrict))
1991 {
1992 switch (cbReg)
1993 {
1994 case 1: pCtx->al = (uint8_t)u32Value; break;
1995 case 2: pCtx->ax = (uint16_t)u32Value; break;
1996 case 4: pCtx->rax = u32Value; break;
1997 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
1998 }
1999 iemRegAddToRip(pIemCpu, cbInstr);
2000 pIemCpu->cPotentialExits++;
2001 }
2002 /** @todo massage rcStrict. */
2003 return rcStrict;
2004}
2005
2006
2007/**
2008 * Implements 'IN eAX, DX'.
2009 *
2010 * @param cbReg The register size.
2011 */
2012IEM_CIMPL_DEF_1(iemCImpl_in_eAX_DX, uint8_t, cbReg)
2013{
2014 return IEM_CIMPL_CALL_2(iemCImpl_in, pIemCpu->CTX_SUFF(pCtx)->dx, cbReg);
2015}
2016
2017
2018/**
2019 * Implements 'OUT port, eAX'.
2020 *
2021 * @param u16Port The destination port.
2022 * @param cbReg The register size.
2023 */
2024IEM_CIMPL_DEF_2(iemCImpl_out, uint16_t, u16Port, uint8_t, cbReg)
2025{
2026 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2027
2028 /*
2029 * CPL check
2030 */
2031 if ( (pCtx->cr0 & X86_CR0_PE)
2032 && ( pIemCpu->uCpl > pCtx->eflags.Bits.u2IOPL
2033 || pCtx->eflags.Bits.u1VM) )
2034 {
2035 /** @todo I/O port permission bitmap check */
2036 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
2037 }
2038
2039 /*
2040 * Perform the I/O.
2041 */
2042 uint32_t u32Value;
2043 switch (cbReg)
2044 {
2045 case 1: u32Value = pCtx->al; break;
2046 case 2: u32Value = pCtx->ax; break;
2047 case 4: u32Value = pCtx->eax; break;
2048 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
2049 }
2050 VBOXSTRICTRC rc;
2051 if (IEM_VERIFICATION_ENABLED(pIemCpu))
2052 rc = IOMIOPortWrite(IEMCPU_TO_VM(pIemCpu), u16Port, u32Value, cbReg);
2053 else
2054 rc = iemVerifyFakeIOPortWrite(pIemCpu, u16Port, u32Value, cbReg);
2055 if (IOM_SUCCESS(rc))
2056 {
2057 iemRegAddToRip(pIemCpu, cbInstr);
2058 pIemCpu->cPotentialExits++;
2059 /** @todo massage rc. */
2060 }
2061 return rc;
2062}
2063
2064
2065/**
2066 * Implements 'OUT DX, eAX'.
2067 *
2068 * @param cbReg The register size.
2069 */
2070IEM_CIMPL_DEF_1(iemCImpl_out_DX_eAX, uint8_t, cbReg)
2071{
2072 return IEM_CIMPL_CALL_2(iemCImpl_out, pIemCpu->CTX_SUFF(pCtx)->dx, cbReg);
2073}
2074
2075
2076/**
2077 * Implements 'CLI'.
2078 */
2079IEM_CIMPL_DEF_0(iemCImpl_cli)
2080{
2081 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2082
2083 if (pCtx->cr0 & X86_CR0_PE)
2084 {
2085 uint8_t const uIopl = pCtx->eflags.Bits.u2IOPL;
2086 if (!pCtx->eflags.Bits.u1VM)
2087 {
2088 if (pIemCpu->uCpl <= uIopl)
2089 pCtx->eflags.Bits.u1IF = 0;
2090 else if ( pIemCpu->uCpl == 3
2091 && (pCtx->cr4 & X86_CR4_PVI) )
2092 pCtx->eflags.Bits.u1VIF = 0;
2093 else
2094 return iemRaiseGeneralProtectionFault0(pIemCpu);
2095 }
2096 /* V8086 */
2097 else if (uIopl == 3)
2098 pCtx->eflags.Bits.u1IF = 0;
2099 else if ( uIopl < 3
2100 && (pCtx->cr4 & X86_CR4_VME) )
2101 pCtx->eflags.Bits.u1VIF = 0;
2102 else
2103 return iemRaiseGeneralProtectionFault0(pIemCpu);
2104 }
2105 /* real mode */
2106 else
2107 pCtx->eflags.Bits.u1IF = 0;
2108 iemRegAddToRip(pIemCpu, cbInstr);
2109 return VINF_SUCCESS;
2110}
2111
2112
2113/**
2114 * Implements 'STI'.
2115 */
2116IEM_CIMPL_DEF_0(iemCImpl_sti)
2117{
2118 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2119
2120 if (pCtx->cr0 & X86_CR0_PE)
2121 {
2122 uint8_t const uIopl = pCtx->eflags.Bits.u2IOPL;
2123 if (!pCtx->eflags.Bits.u1VM)
2124 {
2125 if (pIemCpu->uCpl <= uIopl)
2126 pCtx->eflags.Bits.u1IF = 1;
2127 else if ( pIemCpu->uCpl == 3
2128 && (pCtx->cr4 & X86_CR4_PVI)
2129 && !pCtx->eflags.Bits.u1VIP )
2130 pCtx->eflags.Bits.u1VIF = 1;
2131 else
2132 return iemRaiseGeneralProtectionFault0(pIemCpu);
2133 }
2134 /* V8086 */
2135 else if (uIopl == 3)
2136 pCtx->eflags.Bits.u1IF = 1;
2137 else if ( uIopl < 3
2138 && (pCtx->cr4 & X86_CR4_VME)
2139 && !pCtx->eflags.Bits.u1VIP )
2140 pCtx->eflags.Bits.u1VIF = 1;
2141 else
2142 return iemRaiseGeneralProtectionFault0(pIemCpu);
2143 }
2144 /* real mode */
2145 else
2146 pCtx->eflags.Bits.u1IF = 1;
2147
2148 iemRegAddToRip(pIemCpu, cbInstr);
2149 EMSetInhibitInterruptsPC(IEMCPU_TO_VMCPU(pIemCpu), pCtx->rip);
2150 return VINF_SUCCESS;
2151}
2152
2153
2154/**
2155 * Implements 'HLT'.
2156 */
2157IEM_CIMPL_DEF_0(iemCImpl_hlt)
2158{
2159 if (pIemCpu->uCpl != 0)
2160 return iemRaiseGeneralProtectionFault0(pIemCpu);
2161 iemRegAddToRip(pIemCpu, cbInstr);
2162 return VINF_EM_HALT;
2163}
2164
2165
2166/*
2167 * Instantiate the various string operation combinations.
2168 */
2169#define OP_SIZE 8
2170#define ADDR_SIZE 16
2171#include "IEMAllCImplStrInstr.cpp.h"
2172#define OP_SIZE 8
2173#define ADDR_SIZE 32
2174#include "IEMAllCImplStrInstr.cpp.h"
2175#define OP_SIZE 8
2176#define ADDR_SIZE 64
2177#include "IEMAllCImplStrInstr.cpp.h"
2178
2179#define OP_SIZE 16
2180#define ADDR_SIZE 16
2181#include "IEMAllCImplStrInstr.cpp.h"
2182#define OP_SIZE 16
2183#define ADDR_SIZE 32
2184#include "IEMAllCImplStrInstr.cpp.h"
2185#define OP_SIZE 16
2186#define ADDR_SIZE 64
2187#include "IEMAllCImplStrInstr.cpp.h"
2188
2189#define OP_SIZE 32
2190#define ADDR_SIZE 16
2191#include "IEMAllCImplStrInstr.cpp.h"
2192#define OP_SIZE 32
2193#define ADDR_SIZE 32
2194#include "IEMAllCImplStrInstr.cpp.h"
2195#define OP_SIZE 32
2196#define ADDR_SIZE 64
2197#include "IEMAllCImplStrInstr.cpp.h"
2198
2199#define OP_SIZE 64
2200#define ADDR_SIZE 32
2201#include "IEMAllCImplStrInstr.cpp.h"
2202#define OP_SIZE 64
2203#define ADDR_SIZE 64
2204#include "IEMAllCImplStrInstr.cpp.h"
2205
2206
2207/** @} */
2208
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