VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/IEMAll.cpp@ 37955

Last change on this file since 37955 was 37955, checked in by vboxsync, 13 years ago

Moved VBox/x86.h/mac to iprt/x86.h/mac.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 225.7 KB
Line 
1/* $Id: IEMAll.cpp 37955 2011-07-14 12:23:02Z vboxsync $ */
2/** @file
3 * IEM - Interpreted Execution Manager - All Contexts.
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/** @page pg_iem IEM - Interpreted Execution Manager
20 *
21 * The interpreted exeuction manager (IEM) is for executing short guest code
22 * sequences that are causing too many exits / virtualization traps. It will
23 * also be used to interpret single instructions, thus replacing the selective
24 * interpreters in EM and IOM.
25 *
26 * Design goals:
27 * - Relatively small footprint, although we favour speed and correctness
28 * over size.
29 * - Reasonably fast.
30 * - Correctly handle lock prefixed instructions.
31 * - Complete instruction set - eventually.
32 * - Refactorable into a recompiler, maybe.
33 * - Replace EMInterpret*.
34 *
35 * Using the existing disassembler has been considered, however this is thought
36 * to conflict with speed as the disassembler chews things a bit too much while
37 * leaving us with a somewhat complicated state to interpret afterwards.
38 *
39 *
40 * The current code is very much work in progress. You've been warned!
41 *
42 */
43
44/*******************************************************************************
45* Header Files *
46*******************************************************************************/
47#define LOG_GROUP LOG_GROUP_IEM
48#include <VBox/vmm/iem.h>
49#include <VBox/vmm/pgm.h>
50#include <VBox/vmm/iom.h>
51#include <VBox/vmm/em.h>
52#include <VBox/vmm/tm.h>
53#include <VBox/vmm/dbgf.h>
54#ifdef IEM_VERIFICATION_MODE
55# include <VBox/vmm/rem.h>
56# include <VBox/vmm/mm.h>
57#endif
58#include "IEMInternal.h"
59#include <VBox/vmm/vm.h>
60#include <VBox/log.h>
61#include <VBox/err.h>
62#include <VBox/param.h>
63#include <iprt/assert.h>
64#include <iprt/string.h>
65#include <iprt/x86.h>
66
67
68/*******************************************************************************
69* Structures and Typedefs *
70*******************************************************************************/
71/**
72 * Generic pointer union.
73 * @todo move me to iprt/types.h
74 */
75typedef union RTPTRUNION
76{
77 /** Pointer into the void... */
78 void *pv;
79 /** Pointer to a 8-bit unsigned value. */
80 uint8_t *pu8;
81 /** Pointer to a 16-bit unsigned value. */
82 uint16_t *pu16;
83 /** Pointer to a 32-bit unsigned value. */
84 uint32_t *pu32;
85 /** Pointer to a 64-bit unsigned value. */
86 uint64_t *pu64;
87} RTPTRUNION;
88/** Pointer to a pointer union. */
89typedef RTPTRUNION *PRTPTRUNION;
90
91/**
92 * Generic const pointer union.
93 * @todo move me to iprt/types.h
94 */
95typedef union RTCPTRUNION
96{
97 /** Pointer into the void... */
98 void const *pv;
99 /** Pointer to a 8-bit unsigned value. */
100 uint8_t const *pu8;
101 /** Pointer to a 16-bit unsigned value. */
102 uint16_t const *pu16;
103 /** Pointer to a 32-bit unsigned value. */
104 uint32_t const *pu32;
105 /** Pointer to a 64-bit unsigned value. */
106 uint64_t const *pu64;
107} RTCPTRUNION;
108/** Pointer to a const pointer union. */
109typedef RTCPTRUNION *PRTCPTRUNION;
110
111/** @typedef PFNIEMOP
112 * Pointer to an opcode decoder function.
113 */
114
115/** @def FNIEMOP_DEF
116 * Define an opcode decoder function.
117 *
118 * We're using macors for this so that adding and removing parameters as well as
119 * tweaking compiler specific attributes becomes easier. See FNIEMOP_CALL
120 *
121 * @param a_Name The function name.
122 */
123
124
125#if defined(__GNUC__) && defined(RT_ARCH_X86)
126typedef VBOXSTRICTRC (__attribute__((__fastcall__)) * PFNIEMOP)(PIEMCPU pIemCpu);
127# define FNIEMOP_DEF(a_Name) \
128 static VBOXSTRICTRC __attribute__((__fastcall__, __nothrow__)) a_Name (PIEMCPU pIemCpu)
129# define FNIEMOP_DEF_1(a_Name, a_Type0, a_Name0) \
130 static VBOXSTRICTRC __attribute__((__fastcall__, __nothrow__)) a_Name(PIEMCPU pIemCpu, a_Type0 a_Name0)
131# define FNIEMOP_DEF_2(a_Name, a_Type0, a_Name0, a_Type1, a_Name1) \
132 static VBOXSTRICTRC __attribute__((__fastcall__, __nothrow__)) a_Name(PIEMCPU pIemCpu, a_Type0 a_Name0, a_Type1 a_Name1)
133
134#elif defined(_MSC_VER) && defined(RT_ARCH_X86)
135typedef VBOXSTRICTRC (__fastcall * PFNIEMOP)(PIEMCPU pIemCpu);
136# define FNIEMOP_DEF(a_Name) \
137 static /*__declspec(naked)*/ VBOXSTRICTRC __fastcall a_Name(PIEMCPU pIemCpu) RT_NO_THROW
138# define FNIEMOP_DEF_1(a_Name, a_Type0, a_Name0) \
139 static /*__declspec(naked)*/ VBOXSTRICTRC __fastcall a_Name(PIEMCPU pIemCpu, a_Type0 a_Name0) RT_NO_THROW
140# define FNIEMOP_DEF_2(a_Name, a_Type0, a_Name0, a_Type1, a_Name1) \
141 static /*__declspec(naked)*/ VBOXSTRICTRC __fastcall a_Name(PIEMCPU pIemCpu, a_Type0 a_Name0, a_Type1 a_Name1) RT_NO_THROW
142
143#elif defined(__GNUC__)
144typedef VBOXSTRICTRC (* PFNIEMOP)(PIEMCPU pIemCpu);
145# define FNIEMOP_DEF(a_Name) \
146 static VBOXSTRICTRC __attribute__((__nothrow__)) a_Name(PIEMCPU pIemCpu)
147# define FNIEMOP_DEF_1(a_Name, a_Type0, a_Name0) \
148 static VBOXSTRICTRC __attribute__((__nothrow__)) a_Name(PIEMCPU pIemCpu, a_Type0 a_Name0)
149# define FNIEMOP_DEF_2(a_Name, a_Type0, a_Name0, a_Type1, a_Name1) \
150 static VBOXSTRICTRC __attribute__((__nothrow__)) a_Name(PIEMCPU pIemCpu, a_Type0 a_Name0, a_Type1 a_Name1)
151
152#else
153typedef VBOXSTRICTRC (* PFNIEMOP)(PIEMCPU pIemCpu);
154# define FNIEMOP_DEF(a_Name) \
155 static VBOXSTRICTRC a_Name(PIEMCPU pIemCpu) RT_NO_THROW
156# define FNIEMOP_DEF_1(a_Name, a_Type0, a_Name0) \
157 static VBOXSTRICTRC a_Name(PIEMCPU pIemCpu, a_Type0 a_Name0) RT_NO_THROW
158# define FNIEMOP_DEF_2(a_Name, a_Type0, a_Name0, a_Type1, a_Name1) \
159 static VBOXSTRICTRC a_Name(PIEMCPU pIemCpu, a_Type0 a_Name0, a_Type1 a_Name1) RT_NO_THROW
160
161#endif
162
163
164/**
165 * Selector descriptor table entry as fetched by iemMemFetchSelDesc.
166 */
167typedef union IEMSELDESC
168{
169 /** The legacy view. */
170 X86DESC Legacy;
171 /** The long mode view. */
172 X86DESC64 Long;
173} IEMSELDESC;
174/** Pointer to a selector descriptor table entry. */
175typedef IEMSELDESC *PIEMSELDESC;
176
177
178/*******************************************************************************
179* Defined Constants And Macros *
180*******************************************************************************/
181/** @name IEM status codes.
182 *
183 * Not quite sure how this will play out in the end, just aliasing safe status
184 * codes for now.
185 *
186 * @{ */
187#define VINF_IEM_RAISED_XCPT VINF_EM_RESCHEDULE
188/** @} */
189
190/** Temporary hack to disable the double execution. Will be removed in favor
191 * of a dedicated execution mode in EM. */
192//#define IEM_VERIFICATION_MODE_NO_REM
193
194/** Used to shut up GCC warnings about variables that 'may be used uninitialized'
195 * due to GCC lacking knowledge about the value range of a switch. */
196#define IEM_NOT_REACHED_DEFAULT_CASE_RET() default: AssertFailedReturn(VERR_INTERNAL_ERROR_4)
197
198/**
199 * Call an opcode decoder function.
200 *
201 * We're using macors for this so that adding and removing parameters can be
202 * done as we please. See FNIEMOP_DEF.
203 */
204#define FNIEMOP_CALL(a_pfn) (a_pfn)(pIemCpu)
205
206/**
207 * Call a common opcode decoder function taking one extra argument.
208 *
209 * We're using macors for this so that adding and removing parameters can be
210 * done as we please. See FNIEMOP_DEF_1.
211 */
212#define FNIEMOP_CALL_1(a_pfn, a0) (a_pfn)(pIemCpu, a0)
213
214/**
215 * Call a common opcode decoder function taking one extra argument.
216 *
217 * We're using macors for this so that adding and removing parameters can be
218 * done as we please. See FNIEMOP_DEF_1.
219 */
220#define FNIEMOP_CALL_2(a_pfn, a0, a1) (a_pfn)(pIemCpu, a0, a1)
221
222/**
223 * Check if we're currently executing in real or virtual 8086 mode.
224 *
225 * @returns @c true if it is, @c false if not.
226 * @param a_pIemCpu The IEM state of the current CPU.
227 */
228#define IEM_IS_REAL_OR_V86_MODE(a_pIemCpu) (CPUMIsGuestInRealOrV86ModeEx((a_pIemCpu)->CTX_SUFF(pCtx)))
229
230/**
231 * Check if we're currently executing in long mode.
232 *
233 * @returns @c true if it is, @c false if not.
234 * @param a_pIemCpu The IEM state of the current CPU.
235 */
236#define IEM_IS_LONG_MODE(a_pIemCpu) (CPUMIsGuestInLongModeEx((a_pIemCpu)->CTX_SUFF(pCtx)))
237
238/**
239 * Check if we're currently executing in real mode.
240 *
241 * @returns @c true if it is, @c false if not.
242 * @param a_pIemCpu The IEM state of the current CPU.
243 */
244#define IEM_IS_REAL_MODE(a_pIemCpu) (CPUMIsGuestInRealModeEx((a_pIemCpu)->CTX_SUFF(pCtx)))
245
246/**
247 * Tests if an AMD CPUID feature (extended) is marked present - ECX.
248 */
249#define IEM_IS_AMD_CPUID_FEATURE_PRESENT_ECX(a_fEcx) iemRegIsAmdCpuIdFeaturePresent(pIemCpu, 0, (a_fEcx))
250
251/**
252 * Checks if a intel CPUID feature is present.
253 */
254#define IEM_IS_INTEL_CPUID_FEATURE_PRESENT_EDX(a_fEdx) \
255 ( ((a_fEdx) & (X86_CPUID_FEATURE_EDX_TSC | 0)) \
256 || iemRegIsIntelCpuIdFeaturePresent(pIemCpu, (a_fEdx), 0) )
257
258/**
259 * Check if the address is canonical.
260 */
261#define IEM_IS_CANONICAL(a_u64Addr) ((uint64_t)(a_u64Addr) + UINT64_C(0x800000000000) < UINT64_C(0x1000000000000))
262
263
264/*******************************************************************************
265* Global Variables *
266*******************************************************************************/
267extern const PFNIEMOP g_apfnOneByteMap[256]; /* not static since we need to forward declare it. */
268
269
270/** Function table for the ADD instruction. */
271static const IEMOPBINSIZES g_iemAImpl_add =
272{
273 iemAImpl_add_u8, iemAImpl_add_u8_locked,
274 iemAImpl_add_u16, iemAImpl_add_u16_locked,
275 iemAImpl_add_u32, iemAImpl_add_u32_locked,
276 iemAImpl_add_u64, iemAImpl_add_u64_locked
277};
278
279/** Function table for the ADC instruction. */
280static const IEMOPBINSIZES g_iemAImpl_adc =
281{
282 iemAImpl_adc_u8, iemAImpl_adc_u8_locked,
283 iemAImpl_adc_u16, iemAImpl_adc_u16_locked,
284 iemAImpl_adc_u32, iemAImpl_adc_u32_locked,
285 iemAImpl_adc_u64, iemAImpl_adc_u64_locked
286};
287
288/** Function table for the SUB instruction. */
289static const IEMOPBINSIZES g_iemAImpl_sub =
290{
291 iemAImpl_sub_u8, iemAImpl_sub_u8_locked,
292 iemAImpl_sub_u16, iemAImpl_sub_u16_locked,
293 iemAImpl_sub_u32, iemAImpl_sub_u32_locked,
294 iemAImpl_sub_u64, iemAImpl_sub_u64_locked
295};
296
297/** Function table for the SBB instruction. */
298static const IEMOPBINSIZES g_iemAImpl_sbb =
299{
300 iemAImpl_sbb_u8, iemAImpl_sbb_u8_locked,
301 iemAImpl_sbb_u16, iemAImpl_sbb_u16_locked,
302 iemAImpl_sbb_u32, iemAImpl_sbb_u32_locked,
303 iemAImpl_sbb_u64, iemAImpl_sbb_u64_locked
304};
305
306/** Function table for the OR instruction. */
307static const IEMOPBINSIZES g_iemAImpl_or =
308{
309 iemAImpl_or_u8, iemAImpl_or_u8_locked,
310 iemAImpl_or_u16, iemAImpl_or_u16_locked,
311 iemAImpl_or_u32, iemAImpl_or_u32_locked,
312 iemAImpl_or_u64, iemAImpl_or_u64_locked
313};
314
315/** Function table for the XOR instruction. */
316static const IEMOPBINSIZES g_iemAImpl_xor =
317{
318 iemAImpl_xor_u8, iemAImpl_xor_u8_locked,
319 iemAImpl_xor_u16, iemAImpl_xor_u16_locked,
320 iemAImpl_xor_u32, iemAImpl_xor_u32_locked,
321 iemAImpl_xor_u64, iemAImpl_xor_u64_locked
322};
323
324/** Function table for the AND instruction. */
325static const IEMOPBINSIZES g_iemAImpl_and =
326{
327 iemAImpl_and_u8, iemAImpl_and_u8_locked,
328 iemAImpl_and_u16, iemAImpl_and_u16_locked,
329 iemAImpl_and_u32, iemAImpl_and_u32_locked,
330 iemAImpl_and_u64, iemAImpl_and_u64_locked
331};
332
333/** Function table for the CMP instruction.
334 * @remarks Making operand order ASSUMPTIONS.
335 */
336static const IEMOPBINSIZES g_iemAImpl_cmp =
337{
338 iemAImpl_cmp_u8, NULL,
339 iemAImpl_cmp_u16, NULL,
340 iemAImpl_cmp_u32, NULL,
341 iemAImpl_cmp_u64, NULL
342};
343
344/** Function table for the TEST instruction.
345 * @remarks Making operand order ASSUMPTIONS.
346 */
347static const IEMOPBINSIZES g_iemAImpl_test =
348{
349 iemAImpl_test_u8, NULL,
350 iemAImpl_test_u16, NULL,
351 iemAImpl_test_u32, NULL,
352 iemAImpl_test_u64, NULL
353};
354
355/** Function table for the BT instruction. */
356static const IEMOPBINSIZES g_iemAImpl_bt =
357{
358 NULL, NULL,
359 iemAImpl_bt_u16, NULL,
360 iemAImpl_bt_u32, NULL,
361 iemAImpl_bt_u64, NULL
362};
363
364/** Function table for the BTC instruction. */
365static const IEMOPBINSIZES g_iemAImpl_btc =
366{
367 NULL, NULL,
368 iemAImpl_btc_u16, iemAImpl_btc_u16_locked,
369 iemAImpl_btc_u32, iemAImpl_btc_u32_locked,
370 iemAImpl_btc_u64, iemAImpl_btc_u64_locked
371};
372
373/** Function table for the BTR instruction. */
374static const IEMOPBINSIZES g_iemAImpl_btr =
375{
376 NULL, NULL,
377 iemAImpl_btr_u16, iemAImpl_btr_u16_locked,
378 iemAImpl_btr_u32, iemAImpl_btr_u32_locked,
379 iemAImpl_btr_u64, iemAImpl_btr_u64_locked
380};
381
382/** Function table for the BTS instruction. */
383static const IEMOPBINSIZES g_iemAImpl_bts =
384{
385 NULL, NULL,
386 iemAImpl_bts_u16, iemAImpl_bts_u16_locked,
387 iemAImpl_bts_u32, iemAImpl_bts_u32_locked,
388 iemAImpl_bts_u64, iemAImpl_bts_u64_locked
389};
390
391/** Function table for the BSF instruction. */
392static const IEMOPBINSIZES g_iemAImpl_bsf =
393{
394 NULL, NULL,
395 iemAImpl_bsf_u16, NULL,
396 iemAImpl_bsf_u32, NULL,
397 iemAImpl_bsf_u64, NULL
398};
399
400/** Function table for the BSR instruction. */
401static const IEMOPBINSIZES g_iemAImpl_bsr =
402{
403 NULL, NULL,
404 iemAImpl_bsr_u16, NULL,
405 iemAImpl_bsr_u32, NULL,
406 iemAImpl_bsr_u64, NULL
407};
408
409/** Function table for the IMUL instruction. */
410static const IEMOPBINSIZES g_iemAImpl_imul_two =
411{
412 NULL, NULL,
413 iemAImpl_imul_two_u16, NULL,
414 iemAImpl_imul_two_u32, NULL,
415 iemAImpl_imul_two_u64, NULL
416};
417
418/** Group 1 /r lookup table. */
419static const PCIEMOPBINSIZES g_apIemImplGrp1[8] =
420{
421 &g_iemAImpl_add,
422 &g_iemAImpl_or,
423 &g_iemAImpl_adc,
424 &g_iemAImpl_sbb,
425 &g_iemAImpl_and,
426 &g_iemAImpl_sub,
427 &g_iemAImpl_xor,
428 &g_iemAImpl_cmp
429};
430
431/** Function table for the INC instruction. */
432static const IEMOPUNARYSIZES g_iemAImpl_inc =
433{
434 iemAImpl_inc_u8, iemAImpl_inc_u8_locked,
435 iemAImpl_inc_u16, iemAImpl_inc_u16_locked,
436 iemAImpl_inc_u32, iemAImpl_inc_u32_locked,
437 iemAImpl_inc_u64, iemAImpl_inc_u64_locked
438};
439
440/** Function table for the DEC instruction. */
441static const IEMOPUNARYSIZES g_iemAImpl_dec =
442{
443 iemAImpl_dec_u8, iemAImpl_dec_u8_locked,
444 iemAImpl_dec_u16, iemAImpl_dec_u16_locked,
445 iemAImpl_dec_u32, iemAImpl_dec_u32_locked,
446 iemAImpl_dec_u64, iemAImpl_dec_u64_locked
447};
448
449/** Function table for the NEG instruction. */
450static const IEMOPUNARYSIZES g_iemAImpl_neg =
451{
452 iemAImpl_neg_u8, iemAImpl_neg_u8_locked,
453 iemAImpl_neg_u16, iemAImpl_neg_u16_locked,
454 iemAImpl_neg_u32, iemAImpl_neg_u32_locked,
455 iemAImpl_neg_u64, iemAImpl_neg_u64_locked
456};
457
458/** Function table for the NOT instruction. */
459static const IEMOPUNARYSIZES g_iemAImpl_not =
460{
461 iemAImpl_not_u8, iemAImpl_not_u8_locked,
462 iemAImpl_not_u16, iemAImpl_not_u16_locked,
463 iemAImpl_not_u32, iemAImpl_not_u32_locked,
464 iemAImpl_not_u64, iemAImpl_not_u64_locked
465};
466
467
468/** Function table for the ROL instruction. */
469static const IEMOPSHIFTSIZES g_iemAImpl_rol =
470{
471 iemAImpl_rol_u8,
472 iemAImpl_rol_u16,
473 iemAImpl_rol_u32,
474 iemAImpl_rol_u64
475};
476
477/** Function table for the ROR instruction. */
478static const IEMOPSHIFTSIZES g_iemAImpl_ror =
479{
480 iemAImpl_ror_u8,
481 iemAImpl_ror_u16,
482 iemAImpl_ror_u32,
483 iemAImpl_ror_u64
484};
485
486/** Function table for the RCL instruction. */
487static const IEMOPSHIFTSIZES g_iemAImpl_rcl =
488{
489 iemAImpl_rcl_u8,
490 iemAImpl_rcl_u16,
491 iemAImpl_rcl_u32,
492 iemAImpl_rcl_u64
493};
494
495/** Function table for the RCR instruction. */
496static const IEMOPSHIFTSIZES g_iemAImpl_rcr =
497{
498 iemAImpl_rcr_u8,
499 iemAImpl_rcr_u16,
500 iemAImpl_rcr_u32,
501 iemAImpl_rcr_u64
502};
503
504/** Function table for the SHL instruction. */
505static const IEMOPSHIFTSIZES g_iemAImpl_shl =
506{
507 iemAImpl_shl_u8,
508 iemAImpl_shl_u16,
509 iemAImpl_shl_u32,
510 iemAImpl_shl_u64
511};
512
513/** Function table for the SHR instruction. */
514static const IEMOPSHIFTSIZES g_iemAImpl_shr =
515{
516 iemAImpl_shr_u8,
517 iemAImpl_shr_u16,
518 iemAImpl_shr_u32,
519 iemAImpl_shr_u64
520};
521
522/** Function table for the SAR instruction. */
523static const IEMOPSHIFTSIZES g_iemAImpl_sar =
524{
525 iemAImpl_sar_u8,
526 iemAImpl_sar_u16,
527 iemAImpl_sar_u32,
528 iemAImpl_sar_u64
529};
530
531
532/** Function table for the MUL instruction. */
533static const IEMOPMULDIVSIZES g_iemAImpl_mul =
534{
535 iemAImpl_mul_u8,
536 iemAImpl_mul_u16,
537 iemAImpl_mul_u32,
538 iemAImpl_mul_u64
539};
540
541/** Function table for the IMUL instruction working implicitly on rAX. */
542static const IEMOPMULDIVSIZES g_iemAImpl_imul =
543{
544 iemAImpl_imul_u8,
545 iemAImpl_imul_u16,
546 iemAImpl_imul_u32,
547 iemAImpl_imul_u64
548};
549
550/** Function table for the DIV instruction. */
551static const IEMOPMULDIVSIZES g_iemAImpl_div =
552{
553 iemAImpl_div_u8,
554 iemAImpl_div_u16,
555 iemAImpl_div_u32,
556 iemAImpl_div_u64
557};
558
559/** Function table for the MUL instruction. */
560static const IEMOPMULDIVSIZES g_iemAImpl_idiv =
561{
562 iemAImpl_idiv_u8,
563 iemAImpl_idiv_u16,
564 iemAImpl_idiv_u32,
565 iemAImpl_idiv_u64
566};
567
568/** Function table for the SHLD instruction */
569static const IEMOPSHIFTDBLSIZES g_iemAImpl_shld =
570{
571 iemAImpl_shld_u16,
572 iemAImpl_shld_u32,
573 iemAImpl_shld_u64,
574};
575
576/** Function table for the SHRD instruction */
577static const IEMOPSHIFTDBLSIZES g_iemAImpl_shrd =
578{
579 iemAImpl_shrd_u16,
580 iemAImpl_shrd_u32,
581 iemAImpl_shrd_u64,
582};
583
584
585/*******************************************************************************
586* Internal Functions *
587*******************************************************************************/
588static VBOXSTRICTRC iemRaiseTaskSwitchFaultCurrentTSS(PIEMCPU pIemCpu);
589static VBOXSTRICTRC iemRaiseSelectorNotPresent(PIEMCPU pIemCpu, uint32_t iSegReg, uint32_t fAccess);
590static VBOXSTRICTRC iemRaiseSelectorNotPresentBySelector(PIEMCPU pIemCpu, uint16_t uSel);
591static VBOXSTRICTRC iemRaiseSelectorNotPresentWithErr(PIEMCPU pIemCpu, uint16_t uErr);
592static VBOXSTRICTRC iemRaiseGeneralProtectionFault(PIEMCPU pIemCpu, uint16_t uErr);
593static VBOXSTRICTRC iemRaiseGeneralProtectionFault0(PIEMCPU pIemCpu);
594static VBOXSTRICTRC iemRaiseGeneralProtectionFaultBySelector(PIEMCPU pIemCpu, RTSEL uSel);
595static VBOXSTRICTRC iemRaiseSelectorBounds(PIEMCPU pIemCpu, uint32_t iSegReg, uint32_t fAccess);
596static VBOXSTRICTRC iemRaiseSelectorBoundsBySelector(PIEMCPU pIemCpu, RTSEL Sel);
597static VBOXSTRICTRC iemRaiseSelectorInvalidAccess(PIEMCPU pIemCpu, uint32_t iSegReg, uint32_t fAccess);
598static VBOXSTRICTRC iemRaisePageFault(PIEMCPU pIemCpu, RTGCPTR GCPtrWhere, uint32_t fAccess, int rc);
599static VBOXSTRICTRC iemMemMap(PIEMCPU pIemCpu, void **ppvMem, size_t cbMem, uint8_t iSegReg, RTGCPTR GCPtrMem, uint32_t fAccess);
600static VBOXSTRICTRC iemMemCommitAndUnmap(PIEMCPU pIemCpu, void *pvMem, uint32_t fAccess);
601static VBOXSTRICTRC iemMemFetchDataU32(PIEMCPU pIemCpu, uint32_t *pu32Dst, uint8_t iSegReg, RTGCPTR GCPtrMem);
602static VBOXSTRICTRC iemMemFetchDataU64(PIEMCPU pIemCpu, uint64_t *pu64Dst, uint8_t iSegReg, RTGCPTR GCPtrMem);
603static VBOXSTRICTRC iemMemFetchSelDesc(PIEMCPU pIemCpu, PIEMSELDESC pDesc, uint16_t uSel);
604static VBOXSTRICTRC iemMemStackPushCommitSpecial(PIEMCPU pIemCpu, void *pvMem, uint64_t uNewRsp);
605static VBOXSTRICTRC iemMemStackPushBeginSpecial(PIEMCPU pIemCpu, size_t cbMem, void **ppvMem, uint64_t *puNewRsp);
606static VBOXSTRICTRC iemMemMarkSelDescAccessed(PIEMCPU pIemCpu, uint16_t uSel);
607static uint16_t iemSRegFetchU16(PIEMCPU pIemCpu, uint8_t iSegReg);
608
609#ifdef IEM_VERIFICATION_MODE
610static PIEMVERIFYEVTREC iemVerifyAllocRecord(PIEMCPU pIemCpu);
611#endif
612static VBOXSTRICTRC iemVerifyFakeIOPortRead(PIEMCPU pIemCpu, RTIOPORT Port, uint32_t *pu32Value, size_t cbValue);
613static VBOXSTRICTRC iemVerifyFakeIOPortWrite(PIEMCPU pIemCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue);
614
615
616/**
617 * Initializes the decoder state.
618 *
619 * @param pIemCpu The per CPU IEM state.
620 */
621DECLINLINE(void) iemInitDecode(PIEMCPU pIemCpu)
622{
623 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
624
625 pIemCpu->uCpl = CPUMGetGuestCPL(IEMCPU_TO_VMCPU(pIemCpu), CPUMCTX2CORE(pCtx));
626 IEMMODE enmMode = CPUMIsGuestIn64BitCodeEx(pCtx)
627 ? IEMMODE_64BIT
628 : pCtx->csHid.Attr.n.u1DefBig /** @todo check if this is correct... */
629 ? IEMMODE_32BIT
630 : IEMMODE_16BIT;
631 pIemCpu->enmCpuMode = enmMode;
632 pIemCpu->enmDefAddrMode = enmMode; /** @todo check if this is correct... */
633 pIemCpu->enmEffAddrMode = enmMode;
634 pIemCpu->enmDefOpSize = enmMode; /** @todo check if this is correct... */
635 pIemCpu->enmEffOpSize = enmMode;
636 pIemCpu->fPrefixes = 0;
637 pIemCpu->uRexReg = 0;
638 pIemCpu->uRexB = 0;
639 pIemCpu->uRexIndex = 0;
640 pIemCpu->iEffSeg = X86_SREG_DS;
641 pIemCpu->offOpcode = 0;
642 pIemCpu->cbOpcode = 0;
643 pIemCpu->cActiveMappings = 0;
644 pIemCpu->iNextMapping = 0;
645}
646
647
648/**
649 * Prefetch opcodes the first time when starting executing.
650 *
651 * @returns Strict VBox status code.
652 * @param pIemCpu The IEM state.
653 */
654static VBOXSTRICTRC iemInitDecoderAndPrefetchOpcodes(PIEMCPU pIemCpu)
655{
656#ifdef IEM_VERIFICATION_MODE
657 uint8_t const cbOldOpcodes = pIemCpu->cbOpcode;
658#endif
659 iemInitDecode(pIemCpu);
660
661 /*
662 * What we're doing here is very similar to iemMemMap/iemMemBounceBufferMap.
663 *
664 * First translate CS:rIP to a physical address.
665 */
666 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
667 uint32_t cbToTryRead;
668 RTGCPTR GCPtrPC;
669 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
670 {
671 cbToTryRead = PAGE_SIZE;
672 GCPtrPC = pCtx->rip;
673 if (!IEM_IS_CANONICAL(GCPtrPC))
674 return iemRaiseGeneralProtectionFault0(pIemCpu);
675 cbToTryRead = PAGE_SIZE - (GCPtrPC & PAGE_OFFSET_MASK);
676 }
677 else
678 {
679 uint32_t GCPtrPC32 = pCtx->eip;
680 Assert(!(GCPtrPC32 & ~(uint32_t)UINT16_MAX) || pIemCpu->enmCpuMode == IEMMODE_32BIT);
681 if (GCPtrPC32 > pCtx->csHid.u32Limit)
682 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
683 cbToTryRead = pCtx->csHid.u32Limit - GCPtrPC32 + 1;
684 GCPtrPC = pCtx->csHid.u64Base + GCPtrPC32;
685 }
686
687 RTGCPHYS GCPhys;
688 uint64_t fFlags;
689 int rc = PGMGstGetPage(IEMCPU_TO_VMCPU(pIemCpu), GCPtrPC, &fFlags, &GCPhys);
690 if (RT_FAILURE(rc))
691 return iemRaisePageFault(pIemCpu, GCPtrPC, IEM_ACCESS_INSTRUCTION, rc);
692 if ((fFlags & X86_PTE_US) && pIemCpu->uCpl == 2)
693 return iemRaisePageFault(pIemCpu, GCPtrPC, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
694 if ((fFlags & X86_PTE_PAE_NX) && (pCtx->msrEFER & MSR_K6_EFER_NXE))
695 return iemRaisePageFault(pIemCpu, GCPtrPC, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
696 GCPhys |= GCPtrPC & PAGE_OFFSET_MASK;
697 /** @todo Check reserved bits and such stuff. PGM is better at doing
698 * that, so do it when implementing the guest virtual address
699 * TLB... */
700
701#ifdef IEM_VERIFICATION_MODE
702 /*
703 * Optimistic optimization: Use unconsumed opcode bytes from the previous
704 * instruction.
705 */
706 /** @todo optimize this differently by not using PGMPhysRead. */
707 RTGCPHYS const offPrevOpcodes = GCPhys - pIemCpu->GCPhysOpcodes;
708 pIemCpu->GCPhysOpcodes = GCPhys;
709 if ( offPrevOpcodes < cbOldOpcodes
710 && PAGE_SIZE - (GCPhys & PAGE_OFFSET_MASK) > sizeof(pIemCpu->abOpcode))
711 {
712 uint8_t cbNew = cbOldOpcodes - (uint8_t)offPrevOpcodes;
713 memmove(&pIemCpu->abOpcode[0], &pIemCpu->abOpcode[offPrevOpcodes], cbNew);
714 pIemCpu->cbOpcode = cbNew;
715 return VINF_SUCCESS;
716 }
717#endif
718
719 /*
720 * Read the bytes at this address.
721 */
722 uint32_t cbLeftOnPage = PAGE_SIZE - (GCPtrPC & PAGE_OFFSET_MASK);
723 if (cbToTryRead > cbLeftOnPage)
724 cbToTryRead = cbLeftOnPage;
725 if (cbToTryRead > sizeof(pIemCpu->abOpcode))
726 cbToTryRead = sizeof(pIemCpu->abOpcode);
727 /** @todo patch manager */
728 if (!pIemCpu->fByPassHandlers)
729 rc = PGMPhysRead(IEMCPU_TO_VM(pIemCpu), GCPhys, pIemCpu->abOpcode, cbToTryRead);
730 else
731 rc = PGMPhysSimpleReadGCPhys(IEMCPU_TO_VM(pIemCpu), pIemCpu->abOpcode, GCPhys, cbToTryRead);
732 if (rc != VINF_SUCCESS)
733 return rc;
734 pIemCpu->cbOpcode = cbToTryRead;
735
736 return VINF_SUCCESS;
737}
738
739
740/**
741 * Try fetch at least @a cbMin bytes more opcodes, raise the appropriate
742 * exception if it fails.
743 *
744 * @returns Strict VBox status code.
745 * @param pIemCpu The IEM state.
746 * @param cbMin Where to return the opcode byte.
747 */
748static VBOXSTRICTRC iemOpcodeFetchMoreBytes(PIEMCPU pIemCpu, size_t cbMin)
749{
750 /*
751 * What we're doing here is very similar to iemMemMap/iemMemBounceBufferMap.
752 *
753 * First translate CS:rIP to a physical address.
754 */
755 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
756 uint8_t cbLeft = pIemCpu->cbOpcode - pIemCpu->offOpcode; Assert(cbLeft < cbMin);
757 uint32_t cbToTryRead;
758 RTGCPTR GCPtrNext;
759 if (pIemCpu->enmCpuMode == IEMMODE_64BIT)
760 {
761 cbToTryRead = PAGE_SIZE;
762 GCPtrNext = pCtx->rip + pIemCpu->cbOpcode;
763 if (!IEM_IS_CANONICAL(GCPtrNext))
764 return iemRaiseGeneralProtectionFault0(pIemCpu);
765 cbToTryRead = PAGE_SIZE - (GCPtrNext & PAGE_OFFSET_MASK);
766 Assert(cbToTryRead >= cbMin - cbLeft); /* ASSUMPTION based on iemInitDecoderAndPrefetchOpcodes. */
767 }
768 else
769 {
770 uint32_t GCPtrNext32 = pCtx->eip;
771 Assert(!(GCPtrNext32 & ~(uint32_t)UINT16_MAX) || pIemCpu->enmCpuMode == IEMMODE_32BIT);
772 GCPtrNext32 += pIemCpu->cbOpcode;
773 if (GCPtrNext32 > pCtx->csHid.u32Limit)
774 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
775 cbToTryRead = pCtx->csHid.u32Limit - GCPtrNext32 + 1;
776 if (cbToTryRead < cbMin - cbLeft)
777 return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
778 GCPtrNext = pCtx->csHid.u64Base + GCPtrNext32;
779 }
780
781 RTGCPHYS GCPhys;
782 uint64_t fFlags;
783 int rc = PGMGstGetPage(IEMCPU_TO_VMCPU(pIemCpu), GCPtrNext, &fFlags, &GCPhys);
784 if (RT_FAILURE(rc))
785 return iemRaisePageFault(pIemCpu, GCPtrNext, IEM_ACCESS_INSTRUCTION, rc);
786 if ((fFlags & X86_PTE_US) && pIemCpu->uCpl == 2)
787 return iemRaisePageFault(pIemCpu, GCPtrNext, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
788 if ((fFlags & X86_PTE_PAE_NX) && (pCtx->msrEFER & MSR_K6_EFER_NXE))
789 return iemRaisePageFault(pIemCpu, GCPtrNext, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
790 GCPhys |= GCPtrNext & PAGE_OFFSET_MASK;
791 //Log(("GCPtrNext=%RGv GCPhys=%RGp cbOpcodes=%#x\n", GCPtrNext, GCPhys, pIemCpu->cbOpcode));
792 /** @todo Check reserved bits and such stuff. PGM is better at doing
793 * that, so do it when implementing the guest virtual address
794 * TLB... */
795
796 /*
797 * Read the bytes at this address.
798 */
799 uint32_t cbLeftOnPage = PAGE_SIZE - (GCPtrNext & PAGE_OFFSET_MASK);
800 if (cbToTryRead > cbLeftOnPage)
801 cbToTryRead = cbLeftOnPage;
802 if (cbToTryRead > sizeof(pIemCpu->abOpcode) - pIemCpu->cbOpcode)
803 cbToTryRead = sizeof(pIemCpu->abOpcode) - pIemCpu->cbOpcode;
804 Assert(cbToTryRead >= cbMin - cbLeft);
805 if (!pIemCpu->fByPassHandlers)
806 rc = PGMPhysRead(IEMCPU_TO_VM(pIemCpu), GCPhys, &pIemCpu->abOpcode[pIemCpu->cbOpcode], cbToTryRead);
807 else
808 rc = PGMPhysSimpleReadGCPhys(IEMCPU_TO_VM(pIemCpu), &pIemCpu->abOpcode[pIemCpu->cbOpcode], GCPhys, cbToTryRead);
809 if (rc != VINF_SUCCESS)
810 return rc;
811 pIemCpu->cbOpcode += cbToTryRead;
812 //Log(("%.*Rhxs\n", pIemCpu->cbOpcode, pIemCpu->abOpcode));
813
814 return VINF_SUCCESS;
815}
816
817
818/**
819 * Deals with the problematic cases that iemOpcodeGetNextByte doesn't like.
820 *
821 * @returns Strict VBox status code.
822 * @param pIemCpu The IEM state.
823 * @param pb Where to return the opcode byte.
824 */
825DECL_NO_INLINE(static, VBOXSTRICTRC) iemOpcodeGetNextByteSlow(PIEMCPU pIemCpu, uint8_t *pb)
826{
827 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pIemCpu, 1);
828 if (rcStrict == VINF_SUCCESS)
829 {
830 uint8_t offOpcode = pIemCpu->offOpcode;
831 *pb = pIemCpu->abOpcode[offOpcode];
832 pIemCpu->offOpcode = offOpcode + 1;
833 }
834 else
835 *pb = 0;
836 return rcStrict;
837}
838
839
840/**
841 * Deals with the problematic cases that iemOpcodeGetNextS8SxU16 doesn't like.
842 *
843 * @returns Strict VBox status code.
844 * @param pIemCpu The IEM state.
845 * @param pu16 Where to return the opcode dword.
846 */
847DECL_NO_INLINE(static, VBOXSTRICTRC) iemOpcodeGetNextS8SxU16Slow(PIEMCPU pIemCpu, uint16_t *pu16)
848{
849 uint8_t u8;
850 VBOXSTRICTRC rcStrict = iemOpcodeGetNextByteSlow(pIemCpu, &u8);
851 if (rcStrict == VINF_SUCCESS)
852 *pu16 = (int8_t)u8;
853 return rcStrict;
854}
855
856
857/**
858 * Deals with the problematic cases that iemOpcodeGetNextU16 doesn't like.
859 *
860 * @returns Strict VBox status code.
861 * @param pIemCpu The IEM state.
862 * @param pu16 Where to return the opcode word.
863 */
864DECL_NO_INLINE(static, VBOXSTRICTRC) iemOpcodeGetNextU16Slow(PIEMCPU pIemCpu, uint16_t *pu16)
865{
866 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pIemCpu, 2);
867 if (rcStrict == VINF_SUCCESS)
868 {
869 uint8_t offOpcode = pIemCpu->offOpcode;
870 *pu16 = RT_MAKE_U16(pIemCpu->abOpcode[offOpcode], pIemCpu->abOpcode[offOpcode + 1]);
871 pIemCpu->offOpcode = offOpcode + 2;
872 }
873 else
874 *pu16 = 0;
875 return rcStrict;
876}
877
878
879/**
880 * Deals with the problematic cases that iemOpcodeGetNextU32 doesn't like.
881 *
882 * @returns Strict VBox status code.
883 * @param pIemCpu The IEM state.
884 * @param pu32 Where to return the opcode dword.
885 */
886DECL_NO_INLINE(static, VBOXSTRICTRC) iemOpcodeGetNextU32Slow(PIEMCPU pIemCpu, uint32_t *pu32)
887{
888 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pIemCpu, 4);
889 if (rcStrict == VINF_SUCCESS)
890 {
891 uint8_t offOpcode = pIemCpu->offOpcode;
892 *pu32 = RT_MAKE_U32_FROM_U8(pIemCpu->abOpcode[offOpcode],
893 pIemCpu->abOpcode[offOpcode + 1],
894 pIemCpu->abOpcode[offOpcode + 2],
895 pIemCpu->abOpcode[offOpcode + 3]);
896 pIemCpu->offOpcode = offOpcode + 4;
897 }
898 else
899 *pu32 = 0;
900 return rcStrict;
901}
902
903
904/**
905 * Deals with the problematic cases that iemOpcodeGetNextS32SxU64 doesn't like.
906 *
907 * @returns Strict VBox status code.
908 * @param pIemCpu The IEM state.
909 * @param pu64 Where to return the opcode qword.
910 */
911DECL_NO_INLINE(static, VBOXSTRICTRC) iemOpcodeGetNextS32SxU64Slow(PIEMCPU pIemCpu, uint64_t *pu64)
912{
913 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pIemCpu, 4);
914 if (rcStrict == VINF_SUCCESS)
915 {
916 uint8_t offOpcode = pIemCpu->offOpcode;
917 *pu64 = (int32_t)RT_MAKE_U32_FROM_U8(pIemCpu->abOpcode[offOpcode],
918 pIemCpu->abOpcode[offOpcode + 1],
919 pIemCpu->abOpcode[offOpcode + 2],
920 pIemCpu->abOpcode[offOpcode + 3]);
921 pIemCpu->offOpcode = offOpcode + 4;
922 }
923 else
924 *pu64 = 0;
925 return rcStrict;
926}
927
928
929/**
930 * Deals with the problematic cases that iemOpcodeGetNextU64 doesn't like.
931 *
932 * @returns Strict VBox status code.
933 * @param pIemCpu The IEM state.
934 * @param pu64 Where to return the opcode qword.
935 */
936DECL_NO_INLINE(static, VBOXSTRICTRC) iemOpcodeGetNextU64Slow(PIEMCPU pIemCpu, uint64_t *pu64)
937{
938 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pIemCpu, 8);
939 if (rcStrict == VINF_SUCCESS)
940 {
941 uint8_t offOpcode = pIemCpu->offOpcode;
942 *pu64 = RT_MAKE_U64_FROM_U8(pIemCpu->abOpcode[offOpcode],
943 pIemCpu->abOpcode[offOpcode + 1],
944 pIemCpu->abOpcode[offOpcode + 2],
945 pIemCpu->abOpcode[offOpcode + 3],
946 pIemCpu->abOpcode[offOpcode + 4],
947 pIemCpu->abOpcode[offOpcode + 5],
948 pIemCpu->abOpcode[offOpcode + 6],
949 pIemCpu->abOpcode[offOpcode + 7]);
950 pIemCpu->offOpcode = offOpcode + 8;
951 }
952 else
953 *pu64 = 0;
954 return rcStrict;
955}
956
957
958/**
959 * Fetches the next opcode byte.
960 *
961 * @returns Strict VBox status code.
962 * @param pIemCpu The IEM state.
963 * @param pu8 Where to return the opcode byte.
964 */
965DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextU8(PIEMCPU pIemCpu, uint8_t *pu8)
966{
967 uint8_t const offOpcode = pIemCpu->offOpcode;
968 if (RT_UNLIKELY(offOpcode >= pIemCpu->cbOpcode))
969 return iemOpcodeGetNextByteSlow(pIemCpu, pu8);
970
971 *pu8 = pIemCpu->abOpcode[offOpcode];
972 pIemCpu->offOpcode = offOpcode + 1;
973 return VINF_SUCCESS;
974}
975
976/**
977 * Fetches the next opcode byte, returns automatically on failure.
978 *
979 * @param a_pu8 Where to return the opcode byte.
980 * @remark Implicitly references pIemCpu.
981 */
982#define IEM_OPCODE_GET_NEXT_U8(a_pu8) \
983 do \
984 { \
985 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextU8(pIemCpu, (a_pu8)); \
986 if (rcStrict2 != VINF_SUCCESS) \
987 return rcStrict2; \
988 } while (0)
989
990
991/**
992 * Fetches the next signed byte from the opcode stream.
993 *
994 * @returns Strict VBox status code.
995 * @param pIemCpu The IEM state.
996 * @param pi8 Where to return the signed byte.
997 */
998DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextS8(PIEMCPU pIemCpu, int8_t *pi8)
999{
1000 return iemOpcodeGetNextU8(pIemCpu, (uint8_t *)pi8);
1001}
1002
1003/**
1004 * Fetches the next signed byte from the opcode stream, returning automatically
1005 * on failure.
1006 *
1007 * @param pi8 Where to return the signed byte.
1008 * @remark Implicitly references pIemCpu.
1009 */
1010#define IEM_OPCODE_GET_NEXT_S8(a_pi8) \
1011 do \
1012 { \
1013 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextS8(pIemCpu, (a_pi8)); \
1014 if (rcStrict2 != VINF_SUCCESS) \
1015 return rcStrict2; \
1016 } while (0)
1017
1018
1019/**
1020 * Fetches the next signed byte from the opcode stream, extending it to
1021 * unsigned 16-bit.
1022 *
1023 * @returns Strict VBox status code.
1024 * @param pIemCpu The IEM state.
1025 * @param pu16 Where to return the unsigned word.
1026 */
1027DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextS8SxU16(PIEMCPU pIemCpu, uint16_t *pu16)
1028{
1029 uint8_t const offOpcode = pIemCpu->offOpcode;
1030 if (RT_UNLIKELY(offOpcode >= pIemCpu->cbOpcode))
1031 return iemOpcodeGetNextS8SxU16Slow(pIemCpu, pu16);
1032
1033 *pu16 = (int8_t)pIemCpu->abOpcode[offOpcode];
1034 pIemCpu->offOpcode = offOpcode + 1;
1035 return VINF_SUCCESS;
1036}
1037
1038
1039/**
1040 * Fetches the next signed byte from the opcode stream and sign-extending it to
1041 * a word, returning automatically on failure.
1042 *
1043 * @param pu16 Where to return the word.
1044 * @remark Implicitly references pIemCpu.
1045 */
1046#define IEM_OPCODE_GET_NEXT_S8_SX_U16(a_pu16) \
1047 do \
1048 { \
1049 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextS8SxU16(pIemCpu, (a_pu16)); \
1050 if (rcStrict2 != VINF_SUCCESS) \
1051 return rcStrict2; \
1052 } while (0)
1053
1054
1055/**
1056 * Fetches the next opcode word.
1057 *
1058 * @returns Strict VBox status code.
1059 * @param pIemCpu The IEM state.
1060 * @param pu16 Where to return the opcode word.
1061 */
1062DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextU16(PIEMCPU pIemCpu, uint16_t *pu16)
1063{
1064 uint8_t const offOpcode = pIemCpu->offOpcode;
1065 if (RT_UNLIKELY(offOpcode + 2 > pIemCpu->cbOpcode))
1066 return iemOpcodeGetNextU16Slow(pIemCpu, pu16);
1067
1068 *pu16 = RT_MAKE_U16(pIemCpu->abOpcode[offOpcode], pIemCpu->abOpcode[offOpcode + 1]);
1069 pIemCpu->offOpcode = offOpcode + 2;
1070 return VINF_SUCCESS;
1071}
1072
1073/**
1074 * Fetches the next opcode word, returns automatically on failure.
1075 *
1076 * @param a_pu16 Where to return the opcode word.
1077 * @remark Implicitly references pIemCpu.
1078 */
1079#define IEM_OPCODE_GET_NEXT_U16(a_pu16) \
1080 do \
1081 { \
1082 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextU16(pIemCpu, (a_pu16)); \
1083 if (rcStrict2 != VINF_SUCCESS) \
1084 return rcStrict2; \
1085 } while (0)
1086
1087
1088/**
1089 * Fetches the next signed word from the opcode stream.
1090 *
1091 * @returns Strict VBox status code.
1092 * @param pIemCpu The IEM state.
1093 * @param pi16 Where to return the signed word.
1094 */
1095DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextS16(PIEMCPU pIemCpu, int16_t *pi16)
1096{
1097 return iemOpcodeGetNextU16(pIemCpu, (uint16_t *)pi16);
1098}
1099
1100/**
1101 * Fetches the next signed word from the opcode stream, returning automatically
1102 * on failure.
1103 *
1104 * @param pi16 Where to return the signed word.
1105 * @remark Implicitly references pIemCpu.
1106 */
1107#define IEM_OPCODE_GET_NEXT_S16(a_pi16) \
1108 do \
1109 { \
1110 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextS16(pIemCpu, (a_pi16)); \
1111 if (rcStrict2 != VINF_SUCCESS) \
1112 return rcStrict2; \
1113 } while (0)
1114
1115
1116/**
1117 * Fetches the next opcode dword.
1118 *
1119 * @returns Strict VBox status code.
1120 * @param pIemCpu The IEM state.
1121 * @param pu32 Where to return the opcode double word.
1122 */
1123DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextU32(PIEMCPU pIemCpu, uint32_t *pu32)
1124{
1125 uint8_t const offOpcode = pIemCpu->offOpcode;
1126 if (RT_UNLIKELY(offOpcode + 4 > pIemCpu->cbOpcode))
1127 return iemOpcodeGetNextU32Slow(pIemCpu, pu32);
1128
1129 *pu32 = RT_MAKE_U32_FROM_U8(pIemCpu->abOpcode[offOpcode],
1130 pIemCpu->abOpcode[offOpcode + 1],
1131 pIemCpu->abOpcode[offOpcode + 2],
1132 pIemCpu->abOpcode[offOpcode + 3]);
1133 pIemCpu->offOpcode = offOpcode + 4;
1134 return VINF_SUCCESS;
1135}
1136
1137/**
1138 * Fetches the next opcode dword, returns automatically on failure.
1139 *
1140 * @param a_u32 Where to return the opcode dword.
1141 * @remark Implicitly references pIemCpu.
1142 */
1143#define IEM_OPCODE_GET_NEXT_U32(a_pu32) \
1144 do \
1145 { \
1146 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextU32(pIemCpu, (a_pu32)); \
1147 if (rcStrict2 != VINF_SUCCESS) \
1148 return rcStrict2; \
1149 } while (0)
1150
1151
1152/**
1153 * Fetches the next signed double word from the opcode stream.
1154 *
1155 * @returns Strict VBox status code.
1156 * @param pIemCpu The IEM state.
1157 * @param pi32 Where to return the signed double word.
1158 */
1159DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextS32(PIEMCPU pIemCpu, int32_t *pi32)
1160{
1161 return iemOpcodeGetNextU32(pIemCpu, (uint32_t *)pi32);
1162}
1163
1164/**
1165 * Fetches the next signed double word from the opcode stream, returning
1166 * automatically on failure.
1167 *
1168 * @param pi32 Where to return the signed double word.
1169 * @remark Implicitly references pIemCpu.
1170 */
1171#define IEM_OPCODE_GET_NEXT_S32(a_pi32) \
1172 do \
1173 { \
1174 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextS32(pIemCpu, (a_pi32)); \
1175 if (rcStrict2 != VINF_SUCCESS) \
1176 return rcStrict2; \
1177 } while (0)
1178
1179
1180/**
1181 * Fetches the next opcode dword, sign extending it into a quad word.
1182 *
1183 * @returns Strict VBox status code.
1184 * @param pIemCpu The IEM state.
1185 * @param pu64 Where to return the opcode quad word.
1186 */
1187DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextS32SxU64(PIEMCPU pIemCpu, uint64_t *pu64)
1188{
1189 uint8_t const offOpcode = pIemCpu->offOpcode;
1190 if (RT_UNLIKELY(offOpcode + 4 > pIemCpu->cbOpcode))
1191 return iemOpcodeGetNextS32SxU64Slow(pIemCpu, pu64);
1192
1193 int32_t i32 = RT_MAKE_U32_FROM_U8(pIemCpu->abOpcode[offOpcode],
1194 pIemCpu->abOpcode[offOpcode + 1],
1195 pIemCpu->abOpcode[offOpcode + 2],
1196 pIemCpu->abOpcode[offOpcode + 3]);
1197 *pu64 = i32;
1198 pIemCpu->offOpcode = offOpcode + 4;
1199 return VINF_SUCCESS;
1200}
1201
1202/**
1203 * Fetches the next opcode double word and sign extends it to a quad word,
1204 * returns automatically on failure.
1205 *
1206 * @param a_pu64 Where to return the opcode quad word.
1207 * @remark Implicitly references pIemCpu.
1208 */
1209#define IEM_OPCODE_GET_NEXT_S32_SX_U64(a_pu64) \
1210 do \
1211 { \
1212 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextS32SxU64(pIemCpu, (a_pu64)); \
1213 if (rcStrict2 != VINF_SUCCESS) \
1214 return rcStrict2; \
1215 } while (0)
1216
1217
1218/**
1219 * Fetches the next opcode qword.
1220 *
1221 * @returns Strict VBox status code.
1222 * @param pIemCpu The IEM state.
1223 * @param pu64 Where to return the opcode qword.
1224 */
1225DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextU64(PIEMCPU pIemCpu, uint64_t *pu64)
1226{
1227 uint8_t const offOpcode = pIemCpu->offOpcode;
1228 if (RT_UNLIKELY(offOpcode + 8 > pIemCpu->cbOpcode))
1229 return iemOpcodeGetNextU64Slow(pIemCpu, pu64);
1230
1231 *pu64 = RT_MAKE_U64_FROM_U8(pIemCpu->abOpcode[offOpcode],
1232 pIemCpu->abOpcode[offOpcode + 1],
1233 pIemCpu->abOpcode[offOpcode + 2],
1234 pIemCpu->abOpcode[offOpcode + 3],
1235 pIemCpu->abOpcode[offOpcode + 4],
1236 pIemCpu->abOpcode[offOpcode + 5],
1237 pIemCpu->abOpcode[offOpcode + 6],
1238 pIemCpu->abOpcode[offOpcode + 7]);
1239 pIemCpu->offOpcode = offOpcode + 8;
1240 return VINF_SUCCESS;
1241}
1242
1243/**
1244 * Fetches the next opcode quad word, returns automatically on failure.
1245 *
1246 * @param a_pu64 Where to return the opcode quad word.
1247 * @remark Implicitly references pIemCpu.
1248 */
1249#define IEM_OPCODE_GET_NEXT_U64(a_pu64) \
1250 do \
1251 { \
1252 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextU64(pIemCpu, (a_pu64)); \
1253 if (rcStrict2 != VINF_SUCCESS) \
1254 return rcStrict2; \
1255 } while (0)
1256
1257
1258/** @name Misc Worker Functions.
1259 * @{
1260 */
1261
1262
1263/**
1264 * Validates a new SS segment.
1265 *
1266 * @returns VBox strict status code.
1267 * @param pIemCpu The IEM per CPU instance data.
1268 * @param pCtx The CPU context.
1269 * @param NewSS The new SS selctor.
1270 * @param uCpl The CPL to load the stack for.
1271 * @param pDesc Where to return the descriptor.
1272 */
1273static VBOXSTRICTRC iemMiscValidateNewSS(PIEMCPU pIemCpu, PCCPUMCTX pCtx, RTSEL NewSS, uint8_t uCpl, PIEMSELDESC pDesc)
1274{
1275 /* Null selectors are not allowed (we're not called for dispatching
1276 interrupts with SS=0 in long mode). */
1277 if (!(NewSS & (X86_SEL_MASK | X86_SEL_LDT)))
1278 {
1279 Log(("iemMiscValidateNewSSandRsp: #x - null selector -> #GP(0)\n", NewSS));
1280 return iemRaiseGeneralProtectionFault0(pIemCpu);
1281 }
1282
1283 /*
1284 * Read the descriptor.
1285 */
1286 VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, pDesc, NewSS);
1287 if (rcStrict != VINF_SUCCESS)
1288 return rcStrict;
1289
1290 /*
1291 * Perform the descriptor validation documented for LSS, POP SS and MOV SS.
1292 */
1293 if (!pDesc->Legacy.Gen.u1DescType)
1294 {
1295 Log(("iemMiscValidateNewSSandRsp: %#x - system selector -> #GP\n", NewSS, pDesc->Legacy.Gen.u4Type));
1296 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, NewSS);
1297 }
1298
1299 if ( (pDesc->Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
1300 || !(pDesc->Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
1301 {
1302 Log(("iemMiscValidateNewSSandRsp: %#x - code or read only (%#x) -> #GP\n", NewSS, pDesc->Legacy.Gen.u4Type));
1303 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, NewSS);
1304 }
1305 if ( (pDesc->Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
1306 || !(pDesc->Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
1307 {
1308 Log(("iemMiscValidateNewSSandRsp: %#x - code or read only (%#x) -> #GP\n", NewSS, pDesc->Legacy.Gen.u4Type));
1309 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, NewSS);
1310 }
1311 /** @todo testcase: check if the TSS.ssX RPL is checked. */
1312 if ((NewSS & X86_SEL_RPL) != uCpl)
1313 {
1314 Log(("iemMiscValidateNewSSandRsp: %#x - RPL and CPL (%d) differs -> #GP\n", NewSS, uCpl));
1315 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, NewSS);
1316 }
1317 if (pDesc->Legacy.Gen.u2Dpl != uCpl)
1318 {
1319 Log(("iemMiscValidateNewSSandRsp: %#x - DPL (%d) and CPL (%d) differs -> #GP\n", NewSS, pDesc->Legacy.Gen.u2Dpl, uCpl));
1320 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, NewSS);
1321 }
1322
1323 /* Is it there? */
1324 /** @todo testcase: Is this checked before the canonical / limit check below? */
1325 if (!pDesc->Legacy.Gen.u1Present)
1326 {
1327 Log(("iemMiscValidateNewSSandRsp: %#x - segment not present -> #NP\n", NewSS));
1328 return iemRaiseSelectorNotPresentBySelector(pIemCpu, NewSS);
1329 }
1330
1331 return VINF_SUCCESS;
1332}
1333
1334
1335/** @} */
1336
1337/** @name Raising Exceptions.
1338 *
1339 * @{
1340 */
1341
1342/** @name IEM_XCPT_FLAGS_XXX - flags for iemRaiseXcptOrInt.
1343 * @{ */
1344/** CPU exception. */
1345#define IEM_XCPT_FLAGS_T_CPU_XCPT RT_BIT_32(0)
1346/** External interrupt (from PIC, APIC, whatever). */
1347#define IEM_XCPT_FLAGS_T_EXT_INT RT_BIT_32(1)
1348/** Software interrupt (int, into or bound). */
1349#define IEM_XCPT_FLAGS_T_SOFT_INT RT_BIT_32(2)
1350/** Takes an error code. */
1351#define IEM_XCPT_FLAGS_ERR RT_BIT_32(3)
1352/** Takes a CR2. */
1353#define IEM_XCPT_FLAGS_CR2 RT_BIT_32(4)
1354/** Generated by the breakpoint instruction. */
1355#define IEM_XCPT_FLAGS_BP_INSTR RT_BIT_32(5)
1356/** @} */
1357
1358/**
1359 * Loads the specified stack far pointer from the TSS.
1360 *
1361 * @returns VBox strict status code.
1362 * @param pIemCpu The IEM per CPU instance data.
1363 * @param pCtx The CPU context.
1364 * @param uCpl The CPL to load the stack for.
1365 * @param pSelSS Where to return the new stack segment.
1366 * @param puEsp Where to return the new stack pointer.
1367 */
1368static VBOXSTRICTRC iemRaiseLoadStackFromTss32Or16(PIEMCPU pIemCpu, PCCPUMCTX pCtx, uint8_t uCpl,
1369 PRTSEL pSelSS, uint32_t *puEsp)
1370{
1371 VBOXSTRICTRC rcStrict;
1372 Assert(uCpl < 4);
1373 *puEsp = 0; /* make gcc happy */
1374 *pSelSS = 0; /* make gcc happy */
1375
1376 switch (pCtx->trHid.Attr.n.u4Type)
1377 {
1378 /*
1379 * 16-bit TSS (X86TSS16).
1380 */
1381 case X86_SEL_TYPE_SYS_286_TSS_AVAIL: AssertFailed();
1382 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
1383 {
1384 uint32_t off = uCpl * 4 + 2;
1385 if (off + 4 > pCtx->trHid.u32Limit)
1386 {
1387 Log(("LoadStackFromTss32Or16: out of bounds! uCpl=%d, u32Limit=%#x TSS16\n", uCpl, pCtx->trHid.u32Limit));
1388 return iemRaiseTaskSwitchFaultCurrentTSS(pIemCpu);
1389 }
1390
1391 uint32_t u32Tmp;
1392 rcStrict = iemMemFetchDataU32(pIemCpu, &u32Tmp, UINT8_MAX, pCtx->trHid.u64Base + off);
1393 if (rcStrict == VINF_SUCCESS)
1394 {
1395 *puEsp = RT_LOWORD(u32Tmp);
1396 *pSelSS = RT_HIWORD(u32Tmp);
1397 return VINF_SUCCESS;
1398 }
1399 break;
1400 }
1401
1402 /*
1403 * 32-bit TSS (X86TSS32).
1404 */
1405 case X86_SEL_TYPE_SYS_386_TSS_AVAIL: AssertFailed();
1406 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
1407 {
1408 uint32_t off = uCpl * 8 + 4;
1409 if (off + 7 > pCtx->trHid.u32Limit)
1410 {
1411 Log(("LoadStackFromTss32Or16: out of bounds! uCpl=%d, u32Limit=%#x TSS16\n", uCpl, pCtx->trHid.u32Limit));
1412 return iemRaiseTaskSwitchFaultCurrentTSS(pIemCpu);
1413 }
1414
1415 uint64_t u64Tmp;
1416 rcStrict = iemMemFetchDataU64(pIemCpu, &u64Tmp, UINT8_MAX, pCtx->trHid.u64Base + off);
1417 if (rcStrict == VINF_SUCCESS)
1418 {
1419 *puEsp = u64Tmp & UINT32_MAX;
1420 *pSelSS = (RTSEL)(u64Tmp >> 32);
1421 return VINF_SUCCESS;
1422 }
1423 break;
1424 }
1425
1426 default:
1427 AssertFailedReturn(VERR_INTERNAL_ERROR_2);
1428 }
1429 return rcStrict;
1430}
1431
1432
1433/**
1434 * Adjust the CPU state according to the exception being raised.
1435 *
1436 * @param pCtx The CPU context.
1437 * @param u8Vector The exception that has been raised.
1438 */
1439DECLINLINE(void) iemRaiseXcptAdjustState(PCPUMCTX pCtx, uint8_t u8Vector)
1440{
1441 switch (u8Vector)
1442 {
1443 case X86_XCPT_DB:
1444 pCtx->dr[7] &= ~X86_DR7_GD;
1445 break;
1446 /** @todo Read the AMD and Intel exception reference... */
1447 }
1448}
1449
1450
1451/**
1452 * Implements exceptions and interrupts for real mode.
1453 *
1454 * @returns VBox strict status code.
1455 * @param pIemCpu The IEM per CPU instance data.
1456 * @param pCtx The CPU context.
1457 * @param cbInstr The number of bytes to offset rIP by in the return
1458 * address.
1459 * @param u8Vector The interrupt / exception vector number.
1460 * @param fFlags The flags.
1461 * @param uErr The error value if IEM_XCPT_FLAGS_ERR is set.
1462 * @param uCr2 The CR2 value if IEM_XCPT_FLAGS_CR2 is set.
1463 */
1464static VBOXSTRICTRC
1465iemRaiseXcptOrIntInRealMode(PIEMCPU pIemCpu,
1466 PCPUMCTX pCtx,
1467 uint8_t cbInstr,
1468 uint8_t u8Vector,
1469 uint32_t fFlags,
1470 uint16_t uErr,
1471 uint64_t uCr2)
1472{
1473 AssertReturn(pIemCpu->enmCpuMode == IEMMODE_16BIT, VERR_INTERNAL_ERROR_3);
1474
1475 /*
1476 * Read the IDT entry.
1477 */
1478 if (pCtx->idtr.cbIdt < UINT32_C(4) * u8Vector + 3)
1479 {
1480 Log(("RaiseXcptOrIntInRealMode: %#x is out of bounds (%#x)\n", u8Vector, pCtx->idtr.cbIdt));
1481 return iemRaiseGeneralProtectionFault(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Vector << X86_TRAP_ERR_SEL_SHIFT));
1482 }
1483 RTFAR16 Idte;
1484 VBOXSTRICTRC rcStrict = iemMemFetchDataU32(pIemCpu, (uint32_t *)&Idte, UINT8_MAX,
1485 pCtx->idtr.pIdt + UINT32_C(4) * u8Vector);
1486 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
1487 return rcStrict;
1488
1489 /*
1490 * Push the stack frame.
1491 */
1492 uint16_t *pu16Frame;
1493 uint64_t uNewRsp;
1494 rcStrict = iemMemStackPushBeginSpecial(pIemCpu, 6, (void **)&pu16Frame, &uNewRsp);
1495 if (rcStrict != VINF_SUCCESS)
1496 return rcStrict;
1497
1498 pu16Frame[2] = (uint16_t)pCtx->eflags.u;
1499 pu16Frame[1] = (uint16_t)pCtx->cs;
1500 pu16Frame[0] = pCtx->ip + cbInstr;
1501 rcStrict = iemMemStackPushCommitSpecial(pIemCpu, pu16Frame, uNewRsp);
1502 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
1503 return rcStrict;
1504
1505 /*
1506 * Load the vector address into cs:ip and make exception specific state
1507 * adjustments.
1508 */
1509 pCtx->cs = Idte.sel;
1510 pCtx->csHid.u64Base = (uint32_t)Idte.sel << 4;
1511 /** @todo do we load attribs and limit as well? Should we check against limit like far jump? */
1512 pCtx->rip = Idte.off;
1513 pCtx->eflags.Bits.u1IF = 0;
1514
1515 /** @todo do we actually do this in real mode? */
1516 if (fFlags & IEM_XCPT_FLAGS_T_CPU_XCPT)
1517 iemRaiseXcptAdjustState(pCtx, u8Vector);
1518
1519 return fFlags & IEM_XCPT_FLAGS_T_CPU_XCPT ? VINF_IEM_RAISED_XCPT : VINF_SUCCESS;
1520}
1521
1522
1523/**
1524 * Implements exceptions and interrupts for protected mode.
1525 *
1526 * @returns VBox strict status code.
1527 * @param pIemCpu The IEM per CPU instance data.
1528 * @param pCtx The CPU context.
1529 * @param cbInstr The number of bytes to offset rIP by in the return
1530 * address.
1531 * @param u8Vector The interrupt / exception vector number.
1532 * @param fFlags The flags.
1533 * @param uErr The error value if IEM_XCPT_FLAGS_ERR is set.
1534 * @param uCr2 The CR2 value if IEM_XCPT_FLAGS_CR2 is set.
1535 */
1536static VBOXSTRICTRC
1537iemRaiseXcptOrIntInProtMode(PIEMCPU pIemCpu,
1538 PCPUMCTX pCtx,
1539 uint8_t cbInstr,
1540 uint8_t u8Vector,
1541 uint32_t fFlags,
1542 uint16_t uErr,
1543 uint64_t uCr2)
1544{
1545 /*
1546 * Read the IDT entry.
1547 */
1548 if (pCtx->idtr.cbIdt < UINT32_C(8) * u8Vector + 7)
1549 {
1550 Log(("RaiseXcptOrIntInProtMode: %#x is out of bounds (%#x)\n", u8Vector, pCtx->idtr.cbIdt));
1551 return iemRaiseGeneralProtectionFault(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Vector << X86_TRAP_ERR_SEL_SHIFT));
1552 }
1553 X86DESC Idte;
1554 VBOXSTRICTRC rcStrict = iemMemFetchDataU64(pIemCpu, &Idte.u, UINT8_MAX,
1555 pCtx->idtr.pIdt + UINT32_C(8) * u8Vector);
1556 if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
1557 return rcStrict;
1558
1559 /*
1560 * Check the descriptor type, DPL and such.
1561 * ASSUMES this is done in the same order as described for call-gate calls.
1562 */
1563 if (Idte.Gate.u1DescType)
1564 {
1565 Log(("RaiseXcptOrIntInProtMode %#x - not system selector (%#x) -> #GP\n", u8Vector, Idte.Gate.u4Type));
1566 return iemRaiseGeneralProtectionFault(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Vector << X86_TRAP_ERR_SEL_SHIFT));
1567 }
1568 uint32_t fEflToClear = X86_EFL_TF | X86_EFL_NT | X86_EFL_RF | X86_EFL_VM;
1569 switch (Idte.Gate.u4Type)
1570 {
1571 case X86_SEL_TYPE_SYS_UNDEFINED:
1572 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
1573 case X86_SEL_TYPE_SYS_LDT:
1574 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
1575 case X86_SEL_TYPE_SYS_286_CALL_GATE:
1576 case X86_SEL_TYPE_SYS_UNDEFINED2:
1577 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
1578 case X86_SEL_TYPE_SYS_UNDEFINED3:
1579 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
1580 case X86_SEL_TYPE_SYS_386_CALL_GATE:
1581 case X86_SEL_TYPE_SYS_UNDEFINED4:
1582 {
1583 /** @todo check what actually happens when the type is wrong...
1584 * esp. call gates. */
1585 Log(("RaiseXcptOrIntInProtMode %#x - invalid type (%#x) -> #GP\n", u8Vector, Idte.Gate.u4Type));
1586 return iemRaiseGeneralProtectionFault(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Vector << X86_TRAP_ERR_SEL_SHIFT));
1587 }
1588
1589 case X86_SEL_TYPE_SYS_286_INT_GATE:
1590 case X86_SEL_TYPE_SYS_386_INT_GATE:
1591 fEflToClear |= X86_EFL_IF;
1592 break;
1593
1594 case X86_SEL_TYPE_SYS_TASK_GATE:
1595 /** @todo task gates. */
1596 AssertFailedReturn(VERR_NOT_SUPPORTED);
1597
1598 case X86_SEL_TYPE_SYS_286_TRAP_GATE:
1599 case X86_SEL_TYPE_SYS_386_TRAP_GATE:
1600 break;
1601
1602 IEM_NOT_REACHED_DEFAULT_CASE_RET();
1603 }
1604
1605 /* Check DPL against CPL if applicable. */
1606 if (fFlags & IEM_XCPT_FLAGS_T_SOFT_INT)
1607 {
1608 if (pIemCpu->uCpl > Idte.Gate.u2Dpl)
1609 {
1610 Log(("RaiseXcptOrIntInProtMode %#x - CPL (%d) > DPL (%d) -> #GP\n", u8Vector, pIemCpu->uCpl, Idte.Gate.u2Dpl));
1611 return iemRaiseGeneralProtectionFault(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Vector << X86_TRAP_ERR_SEL_SHIFT));
1612 }
1613 }
1614
1615 /* Is it there? */
1616 if (!Idte.Gate.u1Present)
1617 {
1618 Log(("RaiseXcptOrIntInProtMode %#x - not present -> #NP\n", u8Vector));
1619 return iemRaiseSelectorNotPresentWithErr(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Vector << X86_TRAP_ERR_SEL_SHIFT));
1620 }
1621
1622 /* A null CS is bad. */
1623 RTSEL NewCS = Idte.Gate.u16Sel;
1624 if (!(NewCS & (X86_SEL_MASK | X86_SEL_LDT)))
1625 {
1626 Log(("RaiseXcptOrIntInProtMode %#x - CS=%#x -> #GP\n", u8Vector, NewCS));
1627 return iemRaiseGeneralProtectionFault0(pIemCpu);
1628 }
1629
1630 /* Fetch the descriptor for the new CS. */
1631 IEMSELDESC DescCS;
1632 rcStrict = iemMemFetchSelDesc(pIemCpu, &DescCS, NewCS);
1633 if (rcStrict != VINF_SUCCESS)
1634 return rcStrict;
1635
1636 /* Must be a code segment. */
1637 if (!DescCS.Legacy.Gen.u1DescType)
1638 {
1639 Log(("RaiseXcptOrIntInProtMode %#x - CS=%#x - system selector (%#x) -> #GP\n", u8Vector, NewCS, DescCS.Legacy.Gen.u4Type));
1640 return iemRaiseGeneralProtectionFault(pIemCpu, NewCS & (X86_SEL_MASK | X86_SEL_LDT));
1641 }
1642 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE))
1643 {
1644 Log(("RaiseXcptOrIntInProtMode %#x - CS=%#x - data selector (%#x) -> #GP\n", u8Vector, NewCS, DescCS.Legacy.Gen.u4Type));
1645 return iemRaiseGeneralProtectionFault(pIemCpu, NewCS & (X86_SEL_MASK | X86_SEL_LDT));
1646 }
1647
1648 /* Don't allow lowering the privilege level. */
1649 /** @todo Does the lowering of privileges apply to software interrupts
1650 * only? This has bearings on the more-privileged or
1651 * same-privilege stack behavior further down. A testcase would
1652 * be nice. */
1653 if (DescCS.Legacy.Gen.u2Dpl > pIemCpu->uCpl)
1654 {
1655 Log(("RaiseXcptOrIntInProtMode %#x - CS=%#x - DPL (%d) > CPL (%d) -> #GP\n",
1656 u8Vector, NewCS, DescCS.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
1657 return iemRaiseGeneralProtectionFault(pIemCpu, NewCS & (X86_SEL_MASK | X86_SEL_LDT));
1658 }
1659 /** @todo is the RPL of the interrupt/trap gate descriptor checked? */
1660
1661 /* Check the new EIP against the new CS limit. */
1662 uint32_t const uNewEip = Idte.Gate.u4Type == X86_SEL_TYPE_SYS_286_INT_GATE
1663 || Idte.Gate.u4Type == X86_SEL_TYPE_SYS_286_TRAP_GATE
1664 ? Idte.Gate.u16OffsetLow
1665 : Idte.Gate.u16OffsetLow | ((uint32_t)Idte.Gate.u16OffsetHigh << 16);
1666 uint32_t cbLimitCS = X86DESC_LIMIT(DescCS.Legacy);
1667 if (DescCS.Legacy.Gen.u1Granularity)
1668 cbLimitCS = (cbLimitCS << PAGE_SHIFT) | PAGE_OFFSET_MASK;
1669 if (uNewEip > cbLimitCS)
1670 {
1671 Log(("RaiseXcptOrIntInProtMode %#x - CS=%#x - DPL (%d) > CPL (%d) -> #GP\n",
1672 u8Vector, NewCS, DescCS.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
1673 return iemRaiseGeneralProtectionFault(pIemCpu, NewCS & (X86_SEL_MASK | X86_SEL_LDT));
1674 }
1675
1676 /* Make sure the selector is present. */
1677 if (!DescCS.Legacy.Gen.u1Present)
1678 {
1679 Log(("RaiseXcptOrIntInProtMode %#x - CS=%#x - segment not present -> #NP\n", u8Vector, NewCS));
1680 return iemRaiseSelectorNotPresentBySelector(pIemCpu, NewCS);
1681 }
1682
1683 /*
1684 * If the privilege level changes, we need to get a new stack from the TSS.
1685 * This in turns means validating the new SS and ESP...
1686 */
1687 uint8_t const uNewCpl = DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF
1688 ? pIemCpu->uCpl : DescCS.Legacy.Gen.u2Dpl;
1689 if (uNewCpl != pIemCpu->uCpl)
1690 {
1691 RTSEL NewSS;
1692 uint32_t uNewEsp;
1693 rcStrict = iemRaiseLoadStackFromTss32Or16(pIemCpu, pCtx, uNewCpl, &NewSS, &uNewEsp);
1694 if (rcStrict != VINF_SUCCESS)
1695 return rcStrict;
1696
1697 IEMSELDESC DescSS;
1698 rcStrict = iemMiscValidateNewSS(pIemCpu, pCtx, NewSS, uNewCpl, &DescSS);
1699 if (rcStrict != VINF_SUCCESS)
1700 return rcStrict;
1701
1702 /* Check that there is sufficient space for the stack frame. */
1703 uint32_t cbLimitSS = X86DESC_LIMIT(DescSS.Legacy);
1704 if (DescSS.Legacy.Gen.u1Granularity)
1705 cbLimitSS = (cbLimitSS << PAGE_SHIFT) | PAGE_OFFSET_MASK;
1706 AssertReturn(!(DescSS.Legacy.Gen.u4Type & X86_SEL_TYPE_DOWN), VERR_NOT_IMPLEMENTED);
1707
1708 uint8_t const cbStackFrame = fFlags & IEM_XCPT_FLAGS_ERR ? 24 : 20;
1709 if ( uNewEsp - 1 > cbLimitSS
1710 || uNewEsp < cbStackFrame)
1711 {
1712 Log(("RaiseXcptOrIntInProtMode: %#x - SS=%#x ESP=%#x cbStackFrame=%#x is out of bounds -> #GP\n",
1713 u8Vector, NewSS, uNewEsp, cbStackFrame));
1714 return iemRaiseSelectorBoundsBySelector(pIemCpu, NewSS);
1715 }
1716
1717 /*
1718 * Start making changes.
1719 */
1720
1721 /* Create the stack frame. */
1722 RTPTRUNION uStackFrame;
1723 rcStrict = iemMemMap(pIemCpu, &uStackFrame.pv, cbStackFrame, UINT8_MAX,
1724 uNewEsp - cbStackFrame + X86DESC_BASE(DescSS.Legacy), IEM_ACCESS_STACK_W);
1725 if (rcStrict != VINF_SUCCESS)
1726 return rcStrict;
1727 void * const pvStackFrame = uStackFrame.pv;
1728
1729 if (fFlags & IEM_XCPT_FLAGS_ERR)
1730 *uStackFrame.pu32++ = uErr;
1731 uStackFrame.pu32[0] = pCtx->eip;
1732 uStackFrame.pu32[1] = (pCtx->cs & ~X86_SEL_RPL) | pIemCpu->uCpl;
1733 uStackFrame.pu32[2] = pCtx->eflags.u;
1734 uStackFrame.pu32[3] = pCtx->esp;
1735 uStackFrame.pu32[4] = pCtx->ss;
1736 rcStrict = iemMemCommitAndUnmap(pIemCpu, pvStackFrame, IEM_ACCESS_STACK_W);
1737 if (rcStrict != VINF_SUCCESS)
1738 return rcStrict;
1739
1740 /* Mark the selectors 'accessed' (hope this is the correct time). */
1741 /** @todo testcase: excatly _when_ are the accessed bits set - before or
1742 * after pushing the stack frame? (Write protect the gdt + stack to
1743 * find out.) */
1744 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1745 {
1746 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, NewCS);
1747 if (rcStrict != VINF_SUCCESS)
1748 return rcStrict;
1749 DescCS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1750 }
1751
1752 if (!(DescSS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1753 {
1754 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, NewSS);
1755 if (rcStrict != VINF_SUCCESS)
1756 return rcStrict;
1757 DescSS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1758 }
1759
1760 /*
1761 * Start commint the register changes (joins with the DPL=CPL branch).
1762 */
1763 pCtx->ss = NewSS;
1764 pCtx->ssHid.u32Limit = cbLimitSS;
1765 pCtx->ssHid.u64Base = X86DESC_BASE(DescSS.Legacy);
1766 pCtx->ssHid.Attr.u = X86DESC_GET_HID_ATTR(DescSS.Legacy);
1767 pCtx->rsp = uNewEsp - cbStackFrame; /** @todo Is the high word cleared for 16-bit stacks and/or interrupt handlers? */
1768 pIemCpu->uCpl = uNewCpl;
1769 }
1770 /*
1771 * Same privilege, no stack change and smaller stack frame.
1772 */
1773 else
1774 {
1775 uint64_t uNewRsp;
1776 RTPTRUNION uStackFrame;
1777 uint8_t const cbStackFrame = fFlags & IEM_XCPT_FLAGS_ERR ? 16 : 12;
1778 rcStrict = iemMemStackPushBeginSpecial(pIemCpu, cbStackFrame, &uStackFrame.pv, &uNewRsp);
1779 if (rcStrict != VINF_SUCCESS)
1780 return rcStrict;
1781 void * const pvStackFrame = uStackFrame.pv;
1782
1783 if (fFlags & IEM_XCPT_FLAGS_ERR)
1784 *uStackFrame.pu32++ = uErr;
1785 uStackFrame.pu32[0] = pCtx->eip;
1786 uStackFrame.pu32[1] = (pCtx->cs & ~X86_SEL_RPL) | pIemCpu->uCpl;
1787 uStackFrame.pu32[2] = pCtx->eflags.u;
1788 rcStrict = iemMemCommitAndUnmap(pIemCpu, pvStackFrame, IEM_ACCESS_STACK_W); /* don't use the commit here */
1789 if (rcStrict != VINF_SUCCESS)
1790 return rcStrict;
1791
1792 /* Mark the CS selector as 'accessed'. */
1793 if (!(DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1794 {
1795 rcStrict = iemMemMarkSelDescAccessed(pIemCpu, NewCS);
1796 if (rcStrict != VINF_SUCCESS)
1797 return rcStrict;
1798 DescCS.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
1799 }
1800
1801 /*
1802 * Start committing the register changes (joins with the other branch).
1803 */
1804 pCtx->rsp = uNewRsp;
1805 }
1806
1807 /* ... register committing continues. */
1808 pCtx->cs = (NewCS & ~X86_SEL_RPL) | uNewCpl;
1809 pCtx->csHid.u32Limit = cbLimitCS;
1810 pCtx->csHid.u64Base = X86DESC_BASE(DescCS.Legacy);
1811 pCtx->csHid.Attr.u = X86DESC_GET_HID_ATTR(DescCS.Legacy);
1812
1813 pCtx->rip = uNewEip;
1814 pCtx->rflags.u &= ~fEflToClear;
1815
1816 if (fFlags & IEM_XCPT_FLAGS_T_CPU_XCPT)
1817 iemRaiseXcptAdjustState(pCtx, u8Vector);
1818
1819 return fFlags & IEM_XCPT_FLAGS_T_CPU_XCPT ? VINF_IEM_RAISED_XCPT : VINF_SUCCESS;
1820}
1821
1822
1823/**
1824 * Implements exceptions and interrupts for V8086 mode.
1825 *
1826 * @returns VBox strict status code.
1827 * @param pIemCpu The IEM per CPU instance data.
1828 * @param pCtx The CPU context.
1829 * @param cbInstr The number of bytes to offset rIP by in the return
1830 * address.
1831 * @param u8Vector The interrupt / exception vector number.
1832 * @param fFlags The flags.
1833 * @param uErr The error value if IEM_XCPT_FLAGS_ERR is set.
1834 * @param uCr2 The CR2 value if IEM_XCPT_FLAGS_CR2 is set.
1835 */
1836static VBOXSTRICTRC
1837iemRaiseXcptOrIntInV8086Mode(PIEMCPU pIemCpu,
1838 PCPUMCTX pCtx,
1839 uint8_t cbInstr,
1840 uint8_t u8Vector,
1841 uint32_t fFlags,
1842 uint16_t uErr,
1843 uint64_t uCr2)
1844{
1845 AssertMsgFailed(("V8086 exception / interrupt dispatching\n"));
1846 return VERR_NOT_IMPLEMENTED;
1847}
1848
1849
1850/**
1851 * Implements exceptions and interrupts for long mode.
1852 *
1853 * @returns VBox strict status code.
1854 * @param pIemCpu The IEM per CPU instance data.
1855 * @param pCtx The CPU context.
1856 * @param cbInstr The number of bytes to offset rIP by in the return
1857 * address.
1858 * @param u8Vector The interrupt / exception vector number.
1859 * @param fFlags The flags.
1860 * @param uErr The error value if IEM_XCPT_FLAGS_ERR is set.
1861 * @param uCr2 The CR2 value if IEM_XCPT_FLAGS_CR2 is set.
1862 */
1863static VBOXSTRICTRC
1864iemRaiseXcptOrIntInLongMode(PIEMCPU pIemCpu,
1865 PCPUMCTX pCtx,
1866 uint8_t cbInstr,
1867 uint8_t u8Vector,
1868 uint32_t fFlags,
1869 uint16_t uErr,
1870 uint64_t uCr2)
1871{
1872 AssertMsgFailed(("long mode exception / interrupt dispatching\n"));
1873 return VERR_NOT_IMPLEMENTED;
1874}
1875
1876
1877/**
1878 * Implements exceptions and interrupts.
1879 *
1880 * All exceptions and interrupts goes thru this function!
1881 *
1882 * @returns VBox strict status code.
1883 * @param pIemCpu The IEM per CPU instance data.
1884 * @param cbInstr The number of bytes to offset rIP by in the return
1885 * address.
1886 * @param u8Vector The interrupt / exception vector number.
1887 * @param fFlags The flags.
1888 * @param uErr The error value if IEM_XCPT_FLAGS_ERR is set.
1889 * @param uCr2 The CR2 value if IEM_XCPT_FLAGS_CR2 is set.
1890 */
1891DECL_NO_INLINE(static, VBOXSTRICTRC)
1892iemRaiseXcptOrInt(PIEMCPU pIemCpu,
1893 uint8_t cbInstr,
1894 uint8_t u8Vector,
1895 uint32_t fFlags,
1896 uint16_t uErr,
1897 uint64_t uCr2)
1898{
1899 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
1900
1901 /*
1902 * Do recursion accounting.
1903 */
1904 uint8_t const uPrevXcpt = pIemCpu->uCurXcpt;
1905 uint32_t const fPrevXcpt = pIemCpu->fCurXcpt;
1906 if (pIemCpu->cXcptRecursions == 0)
1907 Log(("iemRaiseXcptOrInt: %#x at %04x:%RGv cbInstr=%#x fFlags=%#x uErr=%#x uCr2=%llx\n",
1908 u8Vector, pCtx->cs, pCtx->rip, cbInstr, fFlags, uErr, uCr2));
1909 else
1910 {
1911 Log(("iemRaiseXcptOrInt: %#x at %04x:%RGv cbInstr=%#x fFlags=%#x uErr=%#x uCr2=%llx; prev=%#x depth=%d flags=%#x\n",
1912 u8Vector, pCtx->cs, pCtx->rip, cbInstr, fFlags, uErr, uCr2, pIemCpu->uCurXcpt, pIemCpu->cXcptRecursions + 1, fPrevXcpt));
1913
1914 /** @todo double and tripple faults. */
1915 AssertReturn(pIemCpu->cXcptRecursions < 3, VERR_NOT_IMPLEMENTED);
1916
1917 /** @todo set X86_TRAP_ERR_EXTERNAL when appropriate.
1918 if (fPrevXcpt & IEM_XCPT_FLAGS_T_EXT_INT)
1919 {
1920 ....
1921 } */
1922 }
1923 pIemCpu->cXcptRecursions++;
1924 pIemCpu->uCurXcpt = u8Vector;
1925 pIemCpu->fCurXcpt = fFlags;
1926
1927 /*
1928 * Extensive logging.
1929 */
1930#ifdef LOG_ENABLED
1931 if (LogIs3Enabled())
1932 {
1933 PVM pVM = IEMCPU_TO_VM(pIemCpu);
1934 PVMCPU pVCpu = IEMCPU_TO_VMCPU(pIemCpu);
1935 char szRegs[4096];
1936 DBGFR3RegPrintf(pVM, pVCpu->idCpu, &szRegs[0], sizeof(szRegs),
1937 "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n"
1938 "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n"
1939 "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n"
1940 "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n"
1941 "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n"
1942 "cs={%04VR{cs} base=%016VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} cr0=%016VR{cr0}\n"
1943 "ds={%04VR{ds} base=%016VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} cr2=%016VR{cr2}\n"
1944 "es={%04VR{es} base=%016VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} cr3=%016VR{cr3}\n"
1945 "fs={%04VR{fs} base=%016VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr4=%016VR{cr4}\n"
1946 "gs={%04VR{gs} base=%016VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr8=%016VR{cr8}\n"
1947 "ss={%04VR{ss} base=%016VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}}\n"
1948 "dr0=%016VR{dr0} dr1=%016VR{dr1} dr2=%016VR{dr2} dr3=%016VR{dr3}\n"
1949 "dr6=%016VR{dr6} dr7=%016VR{dr7}\n"
1950 "gdtr=%016VR{gdtr_base}:%04VR{gdtr_lim} idtr=%016VR{idtr_base}:%04VR{idtr_lim} rflags=%08VR{rflags}\n"
1951 "ldtr={%04VR{ldtr} base=%016VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%08VR{ldtr_attr}}\n"
1952 "tr ={%04VR{tr} base=%016VR{tr_base} limit=%08VR{tr_lim} flags=%08VR{tr_attr}}\n"
1953 " sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n"
1954 " efer=%016VR{efer}\n"
1955 " pat=%016VR{pat}\n"
1956 " sf_mask=%016VR{sf_mask}\n"
1957 "krnl_gs_base=%016VR{krnl_gs_base}\n"
1958 " lstar=%016VR{lstar}\n"
1959 " star=%016VR{star} cstar=%016VR{cstar}\n"
1960 "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n"
1961 );
1962
1963 char szInstr[256];
1964 DBGFR3DisasInstrEx(pVM, pVCpu->idCpu, 0, 0,
1965 DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_DEFAULT_MODE,
1966 szInstr, sizeof(szInstr), NULL);
1967 Log3(("%s%s\n", szRegs, szInstr));
1968 }
1969#endif /* LOG_ENABLED */
1970
1971 /*
1972 * Call the mode specific worker function.
1973 */
1974 VBOXSTRICTRC rcStrict;
1975 if (!(pCtx->cr0 & X86_CR0_PE))
1976 rcStrict = iemRaiseXcptOrIntInRealMode( pIemCpu, pCtx, cbInstr, u8Vector, fFlags, uErr, uCr2);
1977 else if (pCtx->msrEFER & MSR_K6_EFER_LMA)
1978 rcStrict = iemRaiseXcptOrIntInLongMode( pIemCpu, pCtx, cbInstr, u8Vector, fFlags, uErr, uCr2);
1979 else if (!pCtx->eflags.Bits.u1VM)
1980 rcStrict = iemRaiseXcptOrIntInProtMode( pIemCpu, pCtx, cbInstr, u8Vector, fFlags, uErr, uCr2);
1981 else
1982 rcStrict = iemRaiseXcptOrIntInV8086Mode(pIemCpu, pCtx, cbInstr, u8Vector, fFlags, uErr, uCr2);
1983
1984 /*
1985 * Unwind.
1986 */
1987 pIemCpu->cXcptRecursions--;
1988 pIemCpu->uCurXcpt = uPrevXcpt;
1989 pIemCpu->fCurXcpt = fPrevXcpt;
1990 Log(("iemRaiseXcptOrInt: returns %Rrc (vec=%#x); cs:rip=%04x:%RGv ss:rsp=%04x:%RGv\n",
1991 VBOXSTRICTRC_VAL(rcStrict), u8Vector, pCtx->cs, pCtx->rip, pCtx->ss, pCtx->esp));
1992 return rcStrict;
1993}
1994
1995
1996/** \#DE - 00. */
1997DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseDivideError(PIEMCPU pIemCpu)
1998{
1999 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_DE, IEM_XCPT_FLAGS_T_CPU_XCPT, 0, 0);
2000}
2001
2002
2003/** \#DB - 01. */
2004DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseDebugException(PIEMCPU pIemCpu)
2005{
2006 /** @todo set/clear RF. */
2007 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_DB, IEM_XCPT_FLAGS_T_CPU_XCPT, 0, 0);
2008}
2009
2010
2011/** \#UD - 06. */
2012DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseUndefinedOpcode(PIEMCPU pIemCpu)
2013{
2014 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_UD, IEM_XCPT_FLAGS_T_CPU_XCPT, 0, 0);
2015}
2016
2017
2018/** \#NM - 07. */
2019DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseDeviceNotAvailable(PIEMCPU pIemCpu)
2020{
2021 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_NM, IEM_XCPT_FLAGS_T_CPU_XCPT, 0, 0);
2022}
2023
2024
2025/** \#TS(err) - 0a. */
2026DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseTaskSwitchFaultWithErr(PIEMCPU pIemCpu, uint16_t uErr)
2027{
2028 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_TS, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR, uErr, 0);
2029}
2030
2031
2032/** \#TS(tr) - 0a. */
2033DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseTaskSwitchFaultCurrentTSS(PIEMCPU pIemCpu)
2034{
2035 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_TS, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR,
2036 pIemCpu->CTX_SUFF(pCtx)->tr, 0);
2037}
2038
2039
2040/** \#NP(err) - 0b. */
2041DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseSelectorNotPresentWithErr(PIEMCPU pIemCpu, uint16_t uErr)
2042{
2043 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_NP, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR, uErr, 0);
2044}
2045
2046
2047/** \#NP(seg) - 0b. */
2048DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseSelectorNotPresentBySegReg(PIEMCPU pIemCpu, uint32_t iSegReg)
2049{
2050 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_NP, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR,
2051 iemSRegFetchU16(pIemCpu, iSegReg) & ~X86_SEL_RPL, 0);
2052}
2053
2054
2055/** \#NP(sel) - 0b. */
2056DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseSelectorNotPresentBySelector(PIEMCPU pIemCpu, uint16_t uSel)
2057{
2058 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_NP, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR,
2059 uSel & ~X86_SEL_RPL, 0);
2060}
2061
2062
2063/** \#GP(n) - 0d. */
2064DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseGeneralProtectionFault(PIEMCPU pIemCpu, uint16_t uErr)
2065{
2066 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_GP, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR, uErr, 0);
2067}
2068
2069
2070/** \#GP(0) - 0d. */
2071DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseGeneralProtectionFault0(PIEMCPU pIemCpu)
2072{
2073 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_GP, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR, 0, 0);
2074}
2075
2076
2077/** \#GP(sel) - 0d. */
2078DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseGeneralProtectionFaultBySelector(PIEMCPU pIemCpu, RTSEL Sel)
2079{
2080 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_GP, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR,
2081 Sel & ~X86_SEL_RPL, 0);
2082}
2083
2084
2085/** \#GP(0) - 0d. */
2086DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseNotCanonical(PIEMCPU pIemCpu)
2087{
2088 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_GP, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR, 0, 0);
2089}
2090
2091
2092/** \#GP(sel) - 0d. */
2093DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseSelectorBounds(PIEMCPU pIemCpu, uint32_t iSegReg, uint32_t fAccess)
2094{
2095 NOREF(iSegReg); NOREF(fAccess);
2096 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_GP, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR, 0, 0);
2097}
2098
2099
2100/** \#GP(sel) - 0d. */
2101DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseSelectorBoundsBySelector(PIEMCPU pIemCpu, RTSEL Sel)
2102{
2103 NOREF(Sel);
2104 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_GP, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR, 0, 0);
2105}
2106
2107
2108/** \#GP(sel) - 0d. */
2109DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseSelectorInvalidAccess(PIEMCPU pIemCpu, uint32_t iSegReg, uint32_t fAccess)
2110{
2111 NOREF(iSegReg); NOREF(fAccess);
2112 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_GP, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR, 0, 0);
2113}
2114
2115
2116/** \#PF(n) - 0e. */
2117DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaisePageFault(PIEMCPU pIemCpu, RTGCPTR GCPtrWhere, uint32_t fAccess, int rc)
2118{
2119 uint16_t uErr;
2120 switch (rc)
2121 {
2122 case VERR_PAGE_NOT_PRESENT:
2123 case VERR_PAGE_TABLE_NOT_PRESENT:
2124 case VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT:
2125 case VERR_PAGE_MAP_LEVEL4_NOT_PRESENT:
2126 uErr = 0;
2127 break;
2128
2129 default:
2130 AssertMsgFailed(("%Rrc\n", rc));
2131 case VERR_ACCESS_DENIED:
2132 uErr = X86_TRAP_PF_P;
2133 break;
2134
2135 /** @todo reserved */
2136 }
2137
2138 if (pIemCpu->uCpl == 3)
2139 uErr |= X86_TRAP_PF_US;
2140
2141 if ( (fAccess & IEM_ACCESS_WHAT_MASK) == IEM_ACCESS_WHAT_CODE
2142 && ( (pIemCpu->CTX_SUFF(pCtx)->cr4 & X86_CR4_PAE)
2143 && (pIemCpu->CTX_SUFF(pCtx)->msrEFER & MSR_K6_EFER_NXE) ) )
2144 uErr |= X86_TRAP_PF_ID;
2145
2146 if (fAccess & IEM_ACCESS_TYPE_WRITE)
2147 uErr |= X86_TRAP_PF_RW;
2148
2149 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_PF, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR | IEM_XCPT_FLAGS_CR2,
2150 uErr, GCPtrWhere);
2151}
2152
2153
2154/** \#MF(n) - 10. */
2155DECL_NO_INLINE(static, VBOXSTRICTRC) iemRaiseMathFault(PIEMCPU pIemCpu)
2156{
2157 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_MF, IEM_XCPT_FLAGS_T_CPU_XCPT, 0, 0);
2158}
2159
2160
2161/**
2162 * Macro for calling iemCImplRaiseInvalidLockPrefix().
2163 *
2164 * This enables us to add/remove arguments and force different levels of
2165 * inlining as we wish.
2166 *
2167 * @return Strict VBox status code.
2168 */
2169#define IEMOP_RAISE_INVALID_LOCK_PREFIX() IEM_MC_DEFER_TO_CIMPL_0(iemCImplRaiseInvalidLockPrefix)
2170IEM_CIMPL_DEF_0(iemCImplRaiseInvalidLockPrefix)
2171{
2172 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_UD, IEM_XCPT_FLAGS_T_CPU_XCPT, 0, 0);
2173}
2174
2175
2176/**
2177 * Macro for calling iemCImplRaiseInvalidOpcode().
2178 *
2179 * This enables us to add/remove arguments and force different levels of
2180 * inlining as we wish.
2181 *
2182 * @return Strict VBox status code.
2183 */
2184#define IEMOP_RAISE_INVALID_OPCODE() IEM_MC_DEFER_TO_CIMPL_0(iemCImplRaiseInvalidOpcode)
2185IEM_CIMPL_DEF_0(iemCImplRaiseInvalidOpcode)
2186{
2187 return iemRaiseXcptOrInt(pIemCpu, 0, X86_XCPT_UD, IEM_XCPT_FLAGS_T_CPU_XCPT, 0, 0);
2188}
2189
2190
2191/** @} */
2192
2193
2194/*
2195 *
2196 * Helpers routines.
2197 * Helpers routines.
2198 * Helpers routines.
2199 *
2200 */
2201
2202/**
2203 * Recalculates the effective operand size.
2204 *
2205 * @param pIemCpu The IEM state.
2206 */
2207static void iemRecalEffOpSize(PIEMCPU pIemCpu)
2208{
2209 switch (pIemCpu->enmCpuMode)
2210 {
2211 case IEMMODE_16BIT:
2212 pIemCpu->enmEffOpSize = pIemCpu->fPrefixes & IEM_OP_PRF_SIZE_OP ? IEMMODE_32BIT : IEMMODE_16BIT;
2213 break;
2214 case IEMMODE_32BIT:
2215 pIemCpu->enmEffOpSize = pIemCpu->fPrefixes & IEM_OP_PRF_SIZE_OP ? IEMMODE_16BIT : IEMMODE_32BIT;
2216 break;
2217 case IEMMODE_64BIT:
2218 switch (pIemCpu->fPrefixes & (IEM_OP_PRF_SIZE_REX_W | IEM_OP_PRF_SIZE_OP))
2219 {
2220 case 0:
2221 pIemCpu->enmEffOpSize = pIemCpu->enmDefOpSize;
2222 break;
2223 case IEM_OP_PRF_SIZE_OP:
2224 pIemCpu->enmEffOpSize = IEMMODE_16BIT;
2225 break;
2226 case IEM_OP_PRF_SIZE_REX_W:
2227 case IEM_OP_PRF_SIZE_REX_W | IEM_OP_PRF_SIZE_OP:
2228 pIemCpu->enmEffOpSize = IEMMODE_64BIT;
2229 break;
2230 }
2231 break;
2232 default:
2233 AssertFailed();
2234 }
2235}
2236
2237
2238/**
2239 * Sets the default operand size to 64-bit and recalculates the effective
2240 * operand size.
2241 *
2242 * @param pIemCpu The IEM state.
2243 */
2244static void iemRecalEffOpSize64Default(PIEMCPU pIemCpu)
2245{
2246 Assert(pIemCpu->enmCpuMode == IEMMODE_64BIT);
2247 pIemCpu->enmDefOpSize = IEMMODE_64BIT;
2248 if ((pIemCpu->fPrefixes & (IEM_OP_PRF_SIZE_REX_W | IEM_OP_PRF_SIZE_OP)) != IEM_OP_PRF_SIZE_OP)
2249 pIemCpu->enmEffOpSize = IEMMODE_64BIT;
2250 else
2251 pIemCpu->enmEffOpSize = IEMMODE_16BIT;
2252}
2253
2254
2255/*
2256 *
2257 * Common opcode decoders.
2258 * Common opcode decoders.
2259 * Common opcode decoders.
2260 *
2261 */
2262#include <iprt/mem.h>
2263
2264/**
2265 * Used to add extra details about a stub case.
2266 * @param pIemCpu The IEM per CPU state.
2267 */
2268static void iemOpStubMsg2(PIEMCPU pIemCpu)
2269{
2270 PVM pVM = IEMCPU_TO_VM(pIemCpu);
2271 PVMCPU pVCpu = IEMCPU_TO_VMCPU(pIemCpu);
2272 char szRegs[4096];
2273 DBGFR3RegPrintf(pVM, pVCpu->idCpu, &szRegs[0], sizeof(szRegs),
2274 "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n"
2275 "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n"
2276 "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n"
2277 "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n"
2278 "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n"
2279 "cs={%04VR{cs} base=%016VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} cr0=%016VR{cr0}\n"
2280 "ds={%04VR{ds} base=%016VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} cr2=%016VR{cr2}\n"
2281 "es={%04VR{es} base=%016VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} cr3=%016VR{cr3}\n"
2282 "fs={%04VR{fs} base=%016VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr4=%016VR{cr4}\n"
2283 "gs={%04VR{gs} base=%016VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr8=%016VR{cr8}\n"
2284 "ss={%04VR{ss} base=%016VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}}\n"
2285 "dr0=%016VR{dr0} dr1=%016VR{dr1} dr2=%016VR{dr2} dr3=%016VR{dr3}\n"
2286 "dr6=%016VR{dr6} dr7=%016VR{dr7}\n"
2287 "gdtr=%016VR{gdtr_base}:%04VR{gdtr_lim} idtr=%016VR{idtr_base}:%04VR{idtr_lim} rflags=%08VR{rflags}\n"
2288 "ldtr={%04VR{ldtr} base=%016VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%08VR{ldtr_attr}}\n"
2289 "tr ={%04VR{tr} base=%016VR{tr_base} limit=%08VR{tr_lim} flags=%08VR{tr_attr}}\n"
2290 " sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n"
2291 " efer=%016VR{efer}\n"
2292 " pat=%016VR{pat}\n"
2293 " sf_mask=%016VR{sf_mask}\n"
2294 "krnl_gs_base=%016VR{krnl_gs_base}\n"
2295 " lstar=%016VR{lstar}\n"
2296 " star=%016VR{star} cstar=%016VR{cstar}\n"
2297 "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n"
2298 );
2299
2300 char szInstr[256];
2301 DBGFR3DisasInstrEx(pVM, pVCpu->idCpu, 0, 0,
2302 DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_DEFAULT_MODE,
2303 szInstr, sizeof(szInstr), NULL);
2304
2305 RTAssertMsg2Weak("%s%s\n", szRegs, szInstr);
2306}
2307
2308
2309/** Stubs an opcode. */
2310#define FNIEMOP_STUB(a_Name) \
2311 FNIEMOP_DEF(a_Name) \
2312 { \
2313 RTAssertMsg1(NULL, __LINE__, __FILE__, __FUNCTION__); \
2314 iemOpStubMsg2(pIemCpu); \
2315 RTAssertPanic(); \
2316 return VERR_NOT_IMPLEMENTED; \
2317 } \
2318 typedef int ignore_semicolon
2319
2320/** Stubs an opcode. */
2321#define FNIEMOP_STUB_1(a_Name, a_Type0, a_Name0) \
2322 FNIEMOP_DEF_1(a_Name, a_Type0, a_Name0) \
2323 { \
2324 RTAssertMsg1(NULL, __LINE__, __FILE__, __FUNCTION__); \
2325 iemOpStubMsg2(pIemCpu); \
2326 RTAssertPanic(); \
2327 return VERR_NOT_IMPLEMENTED; \
2328 } \
2329 typedef int ignore_semicolon
2330
2331
2332
2333/** @name Register Access.
2334 * @{
2335 */
2336
2337/**
2338 * Gets a reference (pointer) to the specified hidden segment register.
2339 *
2340 * @returns Hidden register reference.
2341 * @param pIemCpu The per CPU data.
2342 * @param iSegReg The segment register.
2343 */
2344static PCPUMSELREGHID iemSRegGetHid(PIEMCPU pIemCpu, uint8_t iSegReg)
2345{
2346 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2347 switch (iSegReg)
2348 {
2349 case X86_SREG_ES: return &pCtx->esHid;
2350 case X86_SREG_CS: return &pCtx->csHid;
2351 case X86_SREG_SS: return &pCtx->ssHid;
2352 case X86_SREG_DS: return &pCtx->dsHid;
2353 case X86_SREG_FS: return &pCtx->fsHid;
2354 case X86_SREG_GS: return &pCtx->gsHid;
2355 }
2356 AssertFailedReturn(NULL);
2357}
2358
2359
2360/**
2361 * Gets a reference (pointer) to the specified segment register (the selector
2362 * value).
2363 *
2364 * @returns Pointer to the selector variable.
2365 * @param pIemCpu The per CPU data.
2366 * @param iSegReg The segment register.
2367 */
2368static uint16_t *iemSRegRef(PIEMCPU pIemCpu, uint8_t iSegReg)
2369{
2370 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2371 switch (iSegReg)
2372 {
2373 case X86_SREG_ES: return &pCtx->es;
2374 case X86_SREG_CS: return &pCtx->cs;
2375 case X86_SREG_SS: return &pCtx->ss;
2376 case X86_SREG_DS: return &pCtx->ds;
2377 case X86_SREG_FS: return &pCtx->fs;
2378 case X86_SREG_GS: return &pCtx->gs;
2379 }
2380 AssertFailedReturn(NULL);
2381}
2382
2383
2384/**
2385 * Fetches the selector value of a segment register.
2386 *
2387 * @returns The selector value.
2388 * @param pIemCpu The per CPU data.
2389 * @param iSegReg The segment register.
2390 */
2391static uint16_t iemSRegFetchU16(PIEMCPU pIemCpu, uint8_t iSegReg)
2392{
2393 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2394 switch (iSegReg)
2395 {
2396 case X86_SREG_ES: return pCtx->es;
2397 case X86_SREG_CS: return pCtx->cs;
2398 case X86_SREG_SS: return pCtx->ss;
2399 case X86_SREG_DS: return pCtx->ds;
2400 case X86_SREG_FS: return pCtx->fs;
2401 case X86_SREG_GS: return pCtx->gs;
2402 }
2403 AssertFailedReturn(0xffff);
2404}
2405
2406
2407/**
2408 * Gets a reference (pointer) to the specified general register.
2409 *
2410 * @returns Register reference.
2411 * @param pIemCpu The per CPU data.
2412 * @param iReg The general register.
2413 */
2414static void *iemGRegRef(PIEMCPU pIemCpu, uint8_t iReg)
2415{
2416 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2417 switch (iReg)
2418 {
2419 case X86_GREG_xAX: return &pCtx->rax;
2420 case X86_GREG_xCX: return &pCtx->rcx;
2421 case X86_GREG_xDX: return &pCtx->rdx;
2422 case X86_GREG_xBX: return &pCtx->rbx;
2423 case X86_GREG_xSP: return &pCtx->rsp;
2424 case X86_GREG_xBP: return &pCtx->rbp;
2425 case X86_GREG_xSI: return &pCtx->rsi;
2426 case X86_GREG_xDI: return &pCtx->rdi;
2427 case X86_GREG_x8: return &pCtx->r8;
2428 case X86_GREG_x9: return &pCtx->r9;
2429 case X86_GREG_x10: return &pCtx->r10;
2430 case X86_GREG_x11: return &pCtx->r11;
2431 case X86_GREG_x12: return &pCtx->r12;
2432 case X86_GREG_x13: return &pCtx->r13;
2433 case X86_GREG_x14: return &pCtx->r14;
2434 case X86_GREG_x15: return &pCtx->r15;
2435 }
2436 AssertFailedReturn(NULL);
2437}
2438
2439
2440/**
2441 * Gets a reference (pointer) to the specified 8-bit general register.
2442 *
2443 * Because of AH, CH, DH and BH we cannot use iemGRegRef directly here.
2444 *
2445 * @returns Register reference.
2446 * @param pIemCpu The per CPU data.
2447 * @param iReg The register.
2448 */
2449static uint8_t *iemGRegRefU8(PIEMCPU pIemCpu, uint8_t iReg)
2450{
2451 if (pIemCpu->fPrefixes & IEM_OP_PRF_REX)
2452 return (uint8_t *)iemGRegRef(pIemCpu, iReg);
2453
2454 uint8_t *pu8Reg = (uint8_t *)iemGRegRef(pIemCpu, iReg & 3);
2455 if (iReg >= 4)
2456 pu8Reg++;
2457 return pu8Reg;
2458}
2459
2460
2461/**
2462 * Fetches the value of a 8-bit general register.
2463 *
2464 * @returns The register value.
2465 * @param pIemCpu The per CPU data.
2466 * @param iReg The register.
2467 */
2468static uint8_t iemGRegFetchU8(PIEMCPU pIemCpu, uint8_t iReg)
2469{
2470 uint8_t const *pbSrc = iemGRegRefU8(pIemCpu, iReg);
2471 return *pbSrc;
2472}
2473
2474
2475/**
2476 * Fetches the value of a 16-bit general register.
2477 *
2478 * @returns The register value.
2479 * @param pIemCpu The per CPU data.
2480 * @param iReg The register.
2481 */
2482static uint16_t iemGRegFetchU16(PIEMCPU pIemCpu, uint8_t iReg)
2483{
2484 return *(uint16_t *)iemGRegRef(pIemCpu, iReg);
2485}
2486
2487
2488/**
2489 * Fetches the value of a 32-bit general register.
2490 *
2491 * @returns The register value.
2492 * @param pIemCpu The per CPU data.
2493 * @param iReg The register.
2494 */
2495static uint32_t iemGRegFetchU32(PIEMCPU pIemCpu, uint8_t iReg)
2496{
2497 return *(uint32_t *)iemGRegRef(pIemCpu, iReg);
2498}
2499
2500
2501/**
2502 * Fetches the value of a 64-bit general register.
2503 *
2504 * @returns The register value.
2505 * @param pIemCpu The per CPU data.
2506 * @param iReg The register.
2507 */
2508static uint64_t iemGRegFetchU64(PIEMCPU pIemCpu, uint8_t iReg)
2509{
2510 return *(uint64_t *)iemGRegRef(pIemCpu, iReg);
2511}
2512
2513
2514/**
2515 * Is the FPU state in FXSAVE format or not.
2516 *
2517 * @returns true if it is, false if it's in FNSAVE.
2518 * @param pVCpu The virtual CPU handle.
2519 */
2520DECLINLINE(bool) iemFRegIsFxSaveFormat(PIEMCPU pIemCpu)
2521{
2522#ifdef RT_ARCH_AMD64
2523 return true;
2524#else
2525/// @todo return pVCpu->pVMR3->cpum.s.CPUFeatures.edx.u1FXSR;
2526 return true;
2527#endif
2528}
2529
2530
2531/**
2532 * Gets the FPU status word.
2533 *
2534 * @returns FPU status word
2535 * @param pIemCpu The per CPU data.
2536 */
2537static uint16_t iemFRegFetchFsw(PIEMCPU pIemCpu)
2538{
2539 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2540 uint16_t u16Fsw;
2541 if (iemFRegIsFxSaveFormat(pIemCpu))
2542 u16Fsw = pCtx->fpu.FSW;
2543 else
2544 {
2545 PX86FPUSTATE pFpu = (PX86FPUSTATE)&pCtx->fpu;
2546 u16Fsw = pFpu->FSW;
2547 }
2548 return u16Fsw;
2549}
2550
2551/**
2552 * Adds a 8-bit signed jump offset to RIP/EIP/IP.
2553 *
2554 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2555 * segment limit.
2556 *
2557 * @param pIemCpu The per CPU data.
2558 * @param offNextInstr The offset of the next instruction.
2559 */
2560static VBOXSTRICTRC iemRegRipRelativeJumpS8(PIEMCPU pIemCpu, int8_t offNextInstr)
2561{
2562 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2563 switch (pIemCpu->enmEffOpSize)
2564 {
2565 case IEMMODE_16BIT:
2566 {
2567 uint16_t uNewIp = pCtx->ip + offNextInstr + pIemCpu->offOpcode;
2568 if ( uNewIp > pCtx->csHid.u32Limit
2569 && pIemCpu->enmCpuMode != IEMMODE_64BIT) /* no need to check for non-canonical. */
2570 return iemRaiseGeneralProtectionFault0(pIemCpu);
2571 pCtx->rip = uNewIp;
2572 break;
2573 }
2574
2575 case IEMMODE_32BIT:
2576 {
2577 Assert(pCtx->rip <= UINT32_MAX);
2578 Assert(pIemCpu->enmCpuMode != IEMMODE_64BIT);
2579
2580 uint32_t uNewEip = pCtx->eip + offNextInstr + pIemCpu->offOpcode;
2581 if (uNewEip > pCtx->csHid.u32Limit)
2582 return iemRaiseGeneralProtectionFault0(pIemCpu);
2583 pCtx->rip = uNewEip;
2584 break;
2585 }
2586
2587 case IEMMODE_64BIT:
2588 {
2589 Assert(pIemCpu->enmCpuMode == IEMMODE_64BIT);
2590
2591 uint64_t uNewRip = pCtx->rip + offNextInstr + pIemCpu->offOpcode;
2592 if (!IEM_IS_CANONICAL(uNewRip))
2593 return iemRaiseGeneralProtectionFault0(pIemCpu);
2594 pCtx->rip = uNewRip;
2595 break;
2596 }
2597
2598 IEM_NOT_REACHED_DEFAULT_CASE_RET();
2599 }
2600
2601 return VINF_SUCCESS;
2602}
2603
2604
2605/**
2606 * Adds a 16-bit signed jump offset to RIP/EIP/IP.
2607 *
2608 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2609 * segment limit.
2610 *
2611 * @returns Strict VBox status code.
2612 * @param pIemCpu The per CPU data.
2613 * @param offNextInstr The offset of the next instruction.
2614 */
2615static VBOXSTRICTRC iemRegRipRelativeJumpS16(PIEMCPU pIemCpu, int16_t offNextInstr)
2616{
2617 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2618 Assert(pIemCpu->enmEffOpSize == IEMMODE_16BIT);
2619
2620 uint16_t uNewIp = pCtx->ip + offNextInstr + pIemCpu->offOpcode;
2621 if ( uNewIp > pCtx->csHid.u32Limit
2622 && pIemCpu->enmCpuMode != IEMMODE_64BIT) /* no need to check for non-canonical. */
2623 return iemRaiseGeneralProtectionFault0(pIemCpu);
2624 /** @todo Test 16-bit jump in 64-bit mode. */
2625 pCtx->rip = uNewIp;
2626
2627 return VINF_SUCCESS;
2628}
2629
2630
2631/**
2632 * Adds a 32-bit signed jump offset to RIP/EIP/IP.
2633 *
2634 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2635 * segment limit.
2636 *
2637 * @returns Strict VBox status code.
2638 * @param pIemCpu The per CPU data.
2639 * @param offNextInstr The offset of the next instruction.
2640 */
2641static VBOXSTRICTRC iemRegRipRelativeJumpS32(PIEMCPU pIemCpu, int32_t offNextInstr)
2642{
2643 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2644 Assert(pIemCpu->enmEffOpSize != IEMMODE_16BIT);
2645
2646 if (pIemCpu->enmEffOpSize == IEMMODE_32BIT)
2647 {
2648 Assert(pCtx->rip <= UINT32_MAX); Assert(pIemCpu->enmCpuMode != IEMMODE_64BIT);
2649
2650 uint32_t uNewEip = pCtx->eip + offNextInstr + pIemCpu->offOpcode;
2651 if (uNewEip > pCtx->csHid.u32Limit)
2652 return iemRaiseGeneralProtectionFault0(pIemCpu);
2653 pCtx->rip = uNewEip;
2654 }
2655 else
2656 {
2657 Assert(pIemCpu->enmCpuMode == IEMMODE_64BIT);
2658
2659 uint64_t uNewRip = pCtx->rip + offNextInstr + pIemCpu->offOpcode;
2660 if (!IEM_IS_CANONICAL(uNewRip))
2661 return iemRaiseGeneralProtectionFault0(pIemCpu);
2662 pCtx->rip = uNewRip;
2663 }
2664 return VINF_SUCCESS;
2665}
2666
2667
2668/**
2669 * Performs a near jump to the specified address.
2670 *
2671 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2672 * segment limit.
2673 *
2674 * @param pIemCpu The per CPU data.
2675 * @param uNewRip The new RIP value.
2676 */
2677static VBOXSTRICTRC iemRegRipJump(PIEMCPU pIemCpu, uint64_t uNewRip)
2678{
2679 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2680 switch (pIemCpu->enmEffOpSize)
2681 {
2682 case IEMMODE_16BIT:
2683 {
2684 Assert(uNewRip <= UINT16_MAX);
2685 if ( uNewRip > pCtx->csHid.u32Limit
2686 && pIemCpu->enmCpuMode != IEMMODE_64BIT) /* no need to check for non-canonical. */
2687 return iemRaiseGeneralProtectionFault0(pIemCpu);
2688 /** @todo Test 16-bit jump in 64-bit mode. */
2689 pCtx->rip = uNewRip;
2690 break;
2691 }
2692
2693 case IEMMODE_32BIT:
2694 {
2695 Assert(uNewRip <= UINT32_MAX);
2696 Assert(pCtx->rip <= UINT32_MAX);
2697 Assert(pIemCpu->enmCpuMode != IEMMODE_64BIT);
2698
2699 if (uNewRip > pCtx->csHid.u32Limit)
2700 return iemRaiseGeneralProtectionFault0(pIemCpu);
2701 pCtx->rip = uNewRip;
2702 break;
2703 }
2704
2705 case IEMMODE_64BIT:
2706 {
2707 Assert(pIemCpu->enmCpuMode == IEMMODE_64BIT);
2708
2709 if (!IEM_IS_CANONICAL(uNewRip))
2710 return iemRaiseGeneralProtectionFault0(pIemCpu);
2711 pCtx->rip = uNewRip;
2712 break;
2713 }
2714
2715 IEM_NOT_REACHED_DEFAULT_CASE_RET();
2716 }
2717
2718 return VINF_SUCCESS;
2719}
2720
2721
2722/**
2723 * Get the address of the top of the stack.
2724 *
2725 * @param pCtx The CPU context which SP/ESP/RSP should be
2726 * read.
2727 */
2728DECLINLINE(RTGCPTR) iemRegGetEffRsp(PCCPUMCTX pCtx)
2729{
2730 if (pCtx->ssHid.Attr.n.u1Long)
2731 return pCtx->rsp;
2732 if (pCtx->ssHid.Attr.n.u1DefBig)
2733 return pCtx->esp;
2734 return pCtx->sp;
2735}
2736
2737
2738/**
2739 * Updates the RIP/EIP/IP to point to the next instruction.
2740 *
2741 * @param pIemCpu The per CPU data.
2742 * @param cbInstr The number of bytes to add.
2743 */
2744static void iemRegAddToRip(PIEMCPU pIemCpu, uint8_t cbInstr)
2745{
2746 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
2747 switch (pIemCpu->enmCpuMode)
2748 {
2749 case IEMMODE_16BIT:
2750 Assert(pCtx->rip <= UINT16_MAX);
2751 pCtx->eip += cbInstr;
2752 pCtx->eip &= UINT32_C(0xffff);
2753 break;
2754
2755 case IEMMODE_32BIT:
2756 pCtx->eip += cbInstr;
2757 Assert(pCtx->rip <= UINT32_MAX);
2758 break;
2759
2760 case IEMMODE_64BIT:
2761 pCtx->rip += cbInstr;
2762 break;
2763 default: AssertFailed();
2764 }
2765}
2766
2767
2768/**
2769 * Updates the RIP/EIP/IP to point to the next instruction.
2770 *
2771 * @param pIemCpu The per CPU data.
2772 */
2773static void iemRegUpdateRip(PIEMCPU pIemCpu)
2774{
2775 return iemRegAddToRip(pIemCpu, pIemCpu->offOpcode);
2776}
2777
2778
2779/**
2780 * Adds to the stack pointer.
2781 *
2782 * @param pCtx The CPU context which SP/ESP/RSP should be
2783 * updated.
2784 * @param cbToAdd The number of bytes to add.
2785 */
2786DECLINLINE(void) iemRegAddToRsp(PCPUMCTX pCtx, uint8_t cbToAdd)
2787{
2788 if (pCtx->ssHid.Attr.n.u1Long)
2789 pCtx->rsp += cbToAdd;
2790 else if (pCtx->ssHid.Attr.n.u1DefBig)
2791 pCtx->esp += cbToAdd;
2792 else
2793 pCtx->sp += cbToAdd;
2794}
2795
2796
2797/**
2798 * Subtracts from the stack pointer.
2799 *
2800 * @param pCtx The CPU context which SP/ESP/RSP should be
2801 * updated.
2802 * @param cbToSub The number of bytes to subtract.
2803 */
2804DECLINLINE(void) iemRegSubFromRsp(PCPUMCTX pCtx, uint8_t cbToSub)
2805{
2806 if (pCtx->ssHid.Attr.n.u1Long)
2807 pCtx->rsp -= cbToSub;
2808 else if (pCtx->ssHid.Attr.n.u1DefBig)
2809 pCtx->esp -= cbToSub;
2810 else
2811 pCtx->sp -= cbToSub;
2812}
2813
2814
2815/**
2816 * Adds to the temporary stack pointer.
2817 *
2818 * @param pTmpRsp The temporary SP/ESP/RSP to update.
2819 * @param cbToAdd The number of bytes to add.
2820 * @param pCtx Where to get the current stack mode.
2821 */
2822DECLINLINE(void) iemRegAddToRspEx(PRTUINT64U pTmpRsp, uint8_t cbToAdd, PCCPUMCTX pCtx)
2823{
2824 if (pCtx->ssHid.Attr.n.u1Long)
2825 pTmpRsp->u += cbToAdd;
2826 else if (pCtx->ssHid.Attr.n.u1DefBig)
2827 pTmpRsp->DWords.dw0 += cbToAdd;
2828 else
2829 pTmpRsp->Words.w0 += cbToAdd;
2830}
2831
2832
2833/**
2834 * Subtracts from the temporary stack pointer.
2835 *
2836 * @param pTmpRsp The temporary SP/ESP/RSP to update.
2837 * @param cbToSub The number of bytes to subtract.
2838 * @param pCtx Where to get the current stack mode.
2839 */
2840DECLINLINE(void) iemRegSubFromRspEx(PRTUINT64U pTmpRsp, uint8_t cbToSub, PCCPUMCTX pCtx)
2841{
2842 if (pCtx->ssHid.Attr.n.u1Long)
2843 pTmpRsp->u -= cbToSub;
2844 else if (pCtx->ssHid.Attr.n.u1DefBig)
2845 pTmpRsp->DWords.dw0 -= cbToSub;
2846 else
2847 pTmpRsp->Words.w0 -= cbToSub;
2848}
2849
2850
2851/**
2852 * Calculates the effective stack address for a push of the specified size as
2853 * well as the new RSP value (upper bits may be masked).
2854 *
2855 * @returns Effective stack addressf for the push.
2856 * @param pCtx Where to get the current stack mode.
2857 * @param cbItem The size of the stack item to pop.
2858 * @param puNewRsp Where to return the new RSP value.
2859 */
2860DECLINLINE(RTGCPTR) iemRegGetRspForPush(PCCPUMCTX pCtx, uint8_t cbItem, uint64_t *puNewRsp)
2861{
2862 RTUINT64U uTmpRsp;
2863 RTGCPTR GCPtrTop;
2864 uTmpRsp.u = pCtx->rsp;
2865
2866 if (pCtx->ssHid.Attr.n.u1Long)
2867 GCPtrTop = uTmpRsp.u -= cbItem;
2868 else if (pCtx->ssHid.Attr.n.u1DefBig)
2869 GCPtrTop = uTmpRsp.DWords.dw0 -= cbItem;
2870 else
2871 GCPtrTop = uTmpRsp.Words.w0 -= cbItem;
2872 *puNewRsp = uTmpRsp.u;
2873 return GCPtrTop;
2874}
2875
2876
2877/**
2878 * Gets the current stack pointer and calculates the value after a pop of the
2879 * specified size.
2880 *
2881 * @returns Current stack pointer.
2882 * @param pCtx Where to get the current stack mode.
2883 * @param cbItem The size of the stack item to pop.
2884 * @param puNewRsp Where to return the new RSP value.
2885 */
2886DECLINLINE(RTGCPTR) iemRegGetRspForPop(PCCPUMCTX pCtx, uint8_t cbItem, uint64_t *puNewRsp)
2887{
2888 RTUINT64U uTmpRsp;
2889 RTGCPTR GCPtrTop;
2890 uTmpRsp.u = pCtx->rsp;
2891
2892 if (pCtx->ssHid.Attr.n.u1Long)
2893 {
2894 GCPtrTop = uTmpRsp.u;
2895 uTmpRsp.u += cbItem;
2896 }
2897 else if (pCtx->ssHid.Attr.n.u1DefBig)
2898 {
2899 GCPtrTop = uTmpRsp.DWords.dw0;
2900 uTmpRsp.DWords.dw0 += cbItem;
2901 }
2902 else
2903 {
2904 GCPtrTop = uTmpRsp.Words.w0;
2905 uTmpRsp.Words.w0 += cbItem;
2906 }
2907 *puNewRsp = uTmpRsp.u;
2908 return GCPtrTop;
2909}
2910
2911
2912/**
2913 * Calculates the effective stack address for a push of the specified size as
2914 * well as the new temporary RSP value (upper bits may be masked).
2915 *
2916 * @returns Effective stack addressf for the push.
2917 * @param pTmpRsp The temporary stack pointer. This is updated.
2918 * @param cbItem The size of the stack item to pop.
2919 * @param puNewRsp Where to return the new RSP value.
2920 */
2921DECLINLINE(RTGCPTR) iemRegGetRspForPushEx(PRTUINT64U pTmpRsp, uint8_t cbItem, PCCPUMCTX pCtx)
2922{
2923 RTGCPTR GCPtrTop;
2924
2925 if (pCtx->ssHid.Attr.n.u1Long)
2926 GCPtrTop = pTmpRsp->u -= cbItem;
2927 else if (pCtx->ssHid.Attr.n.u1DefBig)
2928 GCPtrTop = pTmpRsp->DWords.dw0 -= cbItem;
2929 else
2930 GCPtrTop = pTmpRsp->Words.w0 -= cbItem;
2931 return GCPtrTop;
2932}
2933
2934
2935/**
2936 * Gets the effective stack address for a pop of the specified size and
2937 * calculates and updates the temporary RSP.
2938 *
2939 * @returns Current stack pointer.
2940 * @param pTmpRsp The temporary stack pointer. This is updated.
2941 * @param pCtx Where to get the current stack mode.
2942 * @param cbItem The size of the stack item to pop.
2943 */
2944DECLINLINE(RTGCPTR) iemRegGetRspForPopEx(PRTUINT64U pTmpRsp, uint8_t cbItem, PCCPUMCTX pCtx)
2945{
2946 RTGCPTR GCPtrTop;
2947 if (pCtx->ssHid.Attr.n.u1Long)
2948 {
2949 GCPtrTop = pTmpRsp->u;
2950 pTmpRsp->u += cbItem;
2951 }
2952 else if (pCtx->ssHid.Attr.n.u1DefBig)
2953 {
2954 GCPtrTop = pTmpRsp->DWords.dw0;
2955 pTmpRsp->DWords.dw0 += cbItem;
2956 }
2957 else
2958 {
2959 GCPtrTop = pTmpRsp->Words.w0;
2960 pTmpRsp->Words.w0 += cbItem;
2961 }
2962 return GCPtrTop;
2963}
2964
2965
2966/**
2967 * Checks if an Intel CPUID feature bit is set.
2968 *
2969 * @returns true / false.
2970 *
2971 * @param pIemCpu The IEM per CPU data.
2972 * @param fEdx The EDX bit to test, or 0 if ECX.
2973 * @param fEcx The ECX bit to test, or 0 if EDX.
2974 * @remarks Used via IEM_IS_INTEL_CPUID_FEATURE_PRESENT_EDX,
2975 * IEM_IS_INTEL_CPUID_FEATURE_PRESENT_ECX and others.
2976 */
2977static bool iemRegIsIntelCpuIdFeaturePresent(PIEMCPU pIemCpu, uint32_t fEdx, uint32_t fEcx)
2978{
2979 uint32_t uEax, uEbx, uEcx, uEdx;
2980 CPUMGetGuestCpuId(IEMCPU_TO_VMCPU(pIemCpu), 0x00000001, &uEax, &uEbx, &uEcx, &uEdx);
2981 return (fEcx && (uEcx & fEcx))
2982 || (fEdx && (uEdx & fEdx));
2983}
2984
2985
2986/**
2987 * Checks if an AMD CPUID feature bit is set.
2988 *
2989 * @returns true / false.
2990 *
2991 * @param pIemCpu The IEM per CPU data.
2992 * @param fEdx The EDX bit to test, or 0 if ECX.
2993 * @param fEcx The ECX bit to test, or 0 if EDX.
2994 * @remarks Used via IEM_IS_AMD_CPUID_FEATURE_PRESENT_EDX,
2995 * IEM_IS_AMD_CPUID_FEATURE_PRESENT_ECX and others.
2996 */
2997static bool iemRegIsAmdCpuIdFeaturePresent(PIEMCPU pIemCpu, uint32_t fEdx, uint32_t fEcx)
2998{
2999 uint32_t uEax, uEbx, uEcx, uEdx;
3000 CPUMGetGuestCpuId(IEMCPU_TO_VMCPU(pIemCpu), 0x80000001, &uEax, &uEbx, &uEcx, &uEdx);
3001 return (fEcx && (uEcx & fEcx))
3002 || (fEdx && (uEdx & fEdx));
3003}
3004
3005/** @} */
3006
3007
3008/** @name Memory access.
3009 *
3010 * @{
3011 */
3012
3013
3014/**
3015 * Checks if the given segment can be written to, raise the appropriate
3016 * exception if not.
3017 *
3018 * @returns VBox strict status code.
3019 *
3020 * @param pIemCpu The IEM per CPU data.
3021 * @param pHid Pointer to the hidden register.
3022 * @param iSegReg The register number.
3023 */
3024static VBOXSTRICTRC iemMemSegCheckWriteAccessEx(PIEMCPU pIemCpu, PCCPUMSELREGHID pHid, uint8_t iSegReg)
3025{
3026 if (!pHid->Attr.n.u1Present)
3027 return iemRaiseSelectorNotPresentBySegReg(pIemCpu, iSegReg);
3028
3029 if ( ( (pHid->Attr.n.u4Type & X86_SEL_TYPE_CODE)
3030 || !(pHid->Attr.n.u4Type & X86_SEL_TYPE_WRITE) )
3031 && pIemCpu->enmCpuMode != IEMMODE_64BIT )
3032 return iemRaiseSelectorInvalidAccess(pIemCpu, iSegReg, IEM_ACCESS_DATA_W);
3033
3034 /** @todo DPL/RPL/CPL? */
3035
3036 return VINF_SUCCESS;
3037}
3038
3039
3040/**
3041 * Checks if the given segment can be read from, raise the appropriate
3042 * exception if not.
3043 *
3044 * @returns VBox strict status code.
3045 *
3046 * @param pIemCpu The IEM per CPU data.
3047 * @param pHid Pointer to the hidden register.
3048 * @param iSegReg The register number.
3049 */
3050static VBOXSTRICTRC iemMemSegCheckReadAccessEx(PIEMCPU pIemCpu, PCCPUMSELREGHID pHid, uint8_t iSegReg)
3051{
3052 if (!pHid->Attr.n.u1Present)
3053 return iemRaiseSelectorNotPresentBySegReg(pIemCpu, iSegReg);
3054
3055 if ( (pHid->Attr.n.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE
3056 && pIemCpu->enmCpuMode != IEMMODE_64BIT )
3057 return iemRaiseSelectorInvalidAccess(pIemCpu, iSegReg, IEM_ACCESS_DATA_R);
3058
3059 /** @todo DPL/RPL/CPL? */
3060
3061 return VINF_SUCCESS;
3062}
3063
3064
3065/**
3066 * Applies the segment limit, base and attributes.
3067 *
3068 * This may raise a \#GP or \#SS.
3069 *
3070 * @returns VBox strict status code.
3071 *
3072 * @param pIemCpu The IEM per CPU data.
3073 * @param fAccess The kind of access which is being performed.
3074 * @param iSegReg The index of the segment register to apply.
3075 * This is UINT8_MAX if none (for IDT, GDT, LDT,
3076 * TSS, ++).
3077 * @param pGCPtrMem Pointer to the guest memory address to apply
3078 * segmentation to. Input and output parameter.
3079 */
3080static VBOXSTRICTRC iemMemApplySegment(PIEMCPU pIemCpu, uint32_t fAccess, uint8_t iSegReg,
3081 size_t cbMem, PRTGCPTR pGCPtrMem)
3082{
3083 if (iSegReg == UINT8_MAX)
3084 return VINF_SUCCESS;
3085
3086 PCPUMSELREGHID pSel = iemSRegGetHid(pIemCpu, iSegReg);
3087 switch (pIemCpu->enmCpuMode)
3088 {
3089 case IEMMODE_16BIT:
3090 case IEMMODE_32BIT:
3091 {
3092 RTGCPTR32 GCPtrFirst32 = (RTGCPTR32)*pGCPtrMem;
3093 RTGCPTR32 GCPtrLast32 = GCPtrFirst32 + (uint32_t)cbMem - 1;
3094
3095 Assert(pSel->Attr.n.u1Present);
3096 Assert(pSel->Attr.n.u1DescType);
3097 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
3098 {
3099 if ( (fAccess & IEM_ACCESS_TYPE_WRITE)
3100 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE) )
3101 return iemRaiseSelectorInvalidAccess(pIemCpu, iSegReg, fAccess);
3102
3103 if (!IEM_IS_REAL_OR_V86_MODE(pIemCpu))
3104 {
3105 /** @todo CPL check. */
3106 }
3107
3108 /*
3109 * There are two kinds of data selectors, normal and expand down.
3110 */
3111 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
3112 {
3113 if ( GCPtrFirst32 > pSel->u32Limit
3114 || GCPtrLast32 > pSel->u32Limit) /* yes, in real mode too (since 80286). */
3115 return iemRaiseSelectorBounds(pIemCpu, iSegReg, fAccess);
3116
3117 *pGCPtrMem = GCPtrFirst32 += (uint32_t)pSel->u64Base;
3118 }
3119 else
3120 {
3121 /** @todo implement expand down segments. */
3122 AssertFailed(/** @todo implement this */);
3123 return VERR_NOT_IMPLEMENTED;
3124 }
3125 }
3126 else
3127 {
3128
3129 /*
3130 * Code selector and usually be used to read thru, writing is
3131 * only permitted in real and V8086 mode.
3132 */
3133 if ( ( (fAccess & IEM_ACCESS_TYPE_WRITE)
3134 || ( (fAccess & IEM_ACCESS_TYPE_READ)
3135 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)) )
3136 && !IEM_IS_REAL_OR_V86_MODE(pIemCpu) )
3137 return iemRaiseSelectorInvalidAccess(pIemCpu, iSegReg, fAccess);
3138
3139 if ( GCPtrFirst32 > pSel->u32Limit
3140 || GCPtrLast32 > pSel->u32Limit) /* yes, in real mode too (since 80286). */
3141 return iemRaiseSelectorBounds(pIemCpu, iSegReg, fAccess);
3142
3143 if (!IEM_IS_REAL_OR_V86_MODE(pIemCpu))
3144 {
3145 /** @todo CPL check. */
3146 }
3147
3148 *pGCPtrMem = GCPtrFirst32 += (uint32_t)pSel->u64Base;
3149 }
3150 return VINF_SUCCESS;
3151 }
3152
3153 case IEMMODE_64BIT:
3154 if (iSegReg == X86_SREG_GS || iSegReg == X86_SREG_FS)
3155 *pGCPtrMem += pSel->u64Base;
3156 return VINF_SUCCESS;
3157
3158 default:
3159 AssertFailedReturn(VERR_INTERNAL_ERROR_5);
3160 }
3161}
3162
3163
3164/**
3165 * Translates a virtual address to a physical physical address and checks if we
3166 * can access the page as specified.
3167 *
3168 * @param pIemCpu The IEM per CPU data.
3169 * @param GCPtrMem The virtual address.
3170 * @param fAccess The intended access.
3171 * @param pGCPhysMem Where to return the physical address.
3172 */
3173static VBOXSTRICTRC iemMemPageTranslateAndCheckAccess(PIEMCPU pIemCpu, RTGCPTR GCPtrMem, uint32_t fAccess,
3174 PRTGCPHYS pGCPhysMem)
3175{
3176 /** @todo Need a different PGM interface here. We're currently using
3177 * generic / REM interfaces. this won't cut it for R0 & RC. */
3178 RTGCPHYS GCPhys;
3179 uint64_t fFlags;
3180 int rc = PGMGstGetPage(IEMCPU_TO_VMCPU(pIemCpu), GCPtrMem, &fFlags, &GCPhys);
3181 if (RT_FAILURE(rc))
3182 {
3183 /** @todo Check unassigned memory in unpaged mode. */
3184 *pGCPhysMem = NIL_RTGCPHYS;
3185 return iemRaisePageFault(pIemCpu, GCPtrMem, fAccess, rc);
3186 }
3187
3188 if ( (fFlags & (X86_PTE_RW | X86_PTE_US | X86_PTE_PAE_NX)) != (X86_PTE_RW | X86_PTE_US)
3189 && ( ( (fAccess & IEM_ACCESS_TYPE_WRITE) /* Write to read only memory? */
3190 && !(fFlags & X86_PTE_RW)
3191 && ( pIemCpu->uCpl != 0
3192 || (pIemCpu->CTX_SUFF(pCtx)->cr0 & X86_CR0_WP)) )
3193 || ( !(fFlags & X86_PTE_US) /* Kernel memory */
3194 && pIemCpu->uCpl == 3)
3195 || ( (fAccess & IEM_ACCESS_TYPE_EXEC) /* Executing non-executable memory? */
3196 && (fFlags & X86_PTE_PAE_NX)
3197 && (pIemCpu->CTX_SUFF(pCtx)->msrEFER & MSR_K6_EFER_NXE) )
3198 )
3199 )
3200 {
3201 *pGCPhysMem = NIL_RTGCPHYS;
3202 return iemRaisePageFault(pIemCpu, GCPtrMem, fAccess, VERR_ACCESS_DENIED);
3203 }
3204
3205 GCPhys |= GCPtrMem & PAGE_OFFSET_MASK;
3206 *pGCPhysMem = GCPhys;
3207 return VINF_SUCCESS;
3208}
3209
3210
3211
3212/**
3213 * Maps a physical page.
3214 *
3215 * @returns VBox status code (see PGMR3PhysTlbGCPhys2Ptr).
3216 * @param pIemCpu The IEM per CPU data.
3217 * @param GCPhysMem The physical address.
3218 * @param fAccess The intended access.
3219 * @param ppvMem Where to return the mapping address.
3220 */
3221static int iemMemPageMap(PIEMCPU pIemCpu, RTGCPHYS GCPhysMem, uint32_t fAccess, void **ppvMem)
3222{
3223#ifdef IEM_VERIFICATION_MODE
3224 /* Force the alternative path so we can ignore writes. */
3225 if ((fAccess & IEM_ACCESS_TYPE_WRITE) && !pIemCpu->fNoRem)
3226 return VERR_PGM_PHYS_TLB_CATCH_ALL;
3227#endif
3228
3229 /*
3230 * If we can map the page without trouble, do a block processing
3231 * until the end of the current page.
3232 */
3233 /** @todo need some better API. */
3234 return PGMR3PhysTlbGCPhys2Ptr(IEMCPU_TO_VM(pIemCpu),
3235 GCPhysMem,
3236 RT_BOOL(fAccess & IEM_ACCESS_TYPE_WRITE),
3237 ppvMem);
3238}
3239
3240
3241/**
3242 * Looks up a memory mapping entry.
3243 *
3244 * @returns The mapping index (positive) or VERR_NOT_FOUND (negative).
3245 * @param pIemCpu The IEM per CPU data.
3246 * @param pvMem The memory address.
3247 * @param fAccess The access to.
3248 */
3249DECLINLINE(int) iemMapLookup(PIEMCPU pIemCpu, void *pvMem, uint32_t fAccess)
3250{
3251 fAccess &= IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK;
3252 if ( pIemCpu->aMemMappings[0].pv == pvMem
3253 && (pIemCpu->aMemMappings[0].fAccess & (IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK)) == fAccess)
3254 return 0;
3255 if ( pIemCpu->aMemMappings[1].pv == pvMem
3256 && (pIemCpu->aMemMappings[1].fAccess & (IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK)) == fAccess)
3257 return 1;
3258 if ( pIemCpu->aMemMappings[2].pv == pvMem
3259 && (pIemCpu->aMemMappings[2].fAccess & (IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK)) == fAccess)
3260 return 2;
3261 return VERR_NOT_FOUND;
3262}
3263
3264
3265/**
3266 * Finds a free memmap entry when using iNextMapping doesn't work.
3267 *
3268 * @returns Memory mapping index, 1024 on failure.
3269 * @param pIemCpu The IEM per CPU data.
3270 */
3271static unsigned iemMemMapFindFree(PIEMCPU pIemCpu)
3272{
3273 /*
3274 * The easy case.
3275 */
3276 if (pIemCpu->cActiveMappings == 0)
3277 {
3278 pIemCpu->iNextMapping = 1;
3279 return 0;
3280 }
3281
3282 /* There should be enough mappings for all instructions. */
3283 AssertReturn(pIemCpu->cActiveMappings < RT_ELEMENTS(pIemCpu->aMemMappings), 1024);
3284
3285 for (unsigned i = 0; i < RT_ELEMENTS(pIemCpu->aMemMappings); i++)
3286 if (pIemCpu->aMemMappings[i].fAccess == IEM_ACCESS_INVALID)
3287 return i;
3288
3289 AssertFailedReturn(1024);
3290}
3291
3292
3293/**
3294 * Commits a bounce buffer that needs writing back and unmaps it.
3295 *
3296 * @returns Strict VBox status code.
3297 * @param pIemCpu The IEM per CPU data.
3298 * @param iMemMap The index of the buffer to commit.
3299 */
3300static VBOXSTRICTRC iemMemBounceBufferCommitAndUnmap(PIEMCPU pIemCpu, unsigned iMemMap)
3301{
3302 Assert(pIemCpu->aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED);
3303 Assert(pIemCpu->aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE);
3304
3305 /*
3306 * Do the writing.
3307 */
3308 int rc;
3309 if ( !pIemCpu->aMemBbMappings[iMemMap].fUnassigned
3310 && !IEM_VERIFICATION_ENABLED(pIemCpu))
3311 {
3312 uint16_t const cbFirst = pIemCpu->aMemBbMappings[iMemMap].cbFirst;
3313 uint16_t const cbSecond = pIemCpu->aMemBbMappings[iMemMap].cbSecond;
3314 uint8_t const *pbBuf = &pIemCpu->aBounceBuffers[iMemMap].ab[0];
3315 if (!pIemCpu->fByPassHandlers)
3316 {
3317 rc = PGMPhysWrite(IEMCPU_TO_VM(pIemCpu),
3318 pIemCpu->aMemBbMappings[iMemMap].GCPhysFirst,
3319 pbBuf,
3320 cbFirst);
3321 if (cbSecond && rc == VINF_SUCCESS)
3322 rc = PGMPhysWrite(IEMCPU_TO_VM(pIemCpu),
3323 pIemCpu->aMemBbMappings[iMemMap].GCPhysSecond,
3324 pbBuf + cbFirst,
3325 cbSecond);
3326 }
3327 else
3328 {
3329 rc = PGMPhysSimpleWriteGCPhys(IEMCPU_TO_VM(pIemCpu),
3330 pIemCpu->aMemBbMappings[iMemMap].GCPhysFirst,
3331 pbBuf,
3332 cbFirst);
3333 if (cbSecond && rc == VINF_SUCCESS)
3334 rc = PGMPhysSimpleWriteGCPhys(IEMCPU_TO_VM(pIemCpu),
3335 pIemCpu->aMemBbMappings[iMemMap].GCPhysSecond,
3336 pbBuf + cbFirst,
3337 cbSecond);
3338 }
3339 }
3340 else
3341 rc = VINF_SUCCESS;
3342
3343#ifdef IEM_VERIFICATION_MODE
3344 /*
3345 * Record the write(s).
3346 */
3347 if (!pIemCpu->fNoRem)
3348 {
3349 PIEMVERIFYEVTREC pEvtRec = iemVerifyAllocRecord(pIemCpu);
3350 if (pEvtRec)
3351 {
3352 pEvtRec->enmEvent = IEMVERIFYEVENT_RAM_WRITE;
3353 pEvtRec->u.RamWrite.GCPhys = pIemCpu->aMemBbMappings[iMemMap].GCPhysFirst;
3354 pEvtRec->u.RamWrite.cb = pIemCpu->aMemBbMappings[iMemMap].cbFirst;
3355 memcpy(pEvtRec->u.RamWrite.ab, &pIemCpu->aBounceBuffers[iMemMap].ab[0], pIemCpu->aMemBbMappings[iMemMap].cbFirst);
3356 pEvtRec->pNext = *pIemCpu->ppIemEvtRecNext;
3357 *pIemCpu->ppIemEvtRecNext = pEvtRec;
3358 }
3359 if (pIemCpu->aMemBbMappings[iMemMap].cbSecond)
3360 {
3361 pEvtRec = iemVerifyAllocRecord(pIemCpu);
3362 if (pEvtRec)
3363 {
3364 pEvtRec->enmEvent = IEMVERIFYEVENT_RAM_WRITE;
3365 pEvtRec->u.RamWrite.GCPhys = pIemCpu->aMemBbMappings[iMemMap].GCPhysSecond;
3366 pEvtRec->u.RamWrite.cb = pIemCpu->aMemBbMappings[iMemMap].cbSecond;
3367 memcpy(pEvtRec->u.RamWrite.ab,
3368 &pIemCpu->aBounceBuffers[iMemMap].ab[pIemCpu->aMemBbMappings[iMemMap].cbFirst],
3369 pIemCpu->aMemBbMappings[iMemMap].cbSecond);
3370 pEvtRec->pNext = *pIemCpu->ppIemEvtRecNext;
3371 *pIemCpu->ppIemEvtRecNext = pEvtRec;
3372 }
3373 }
3374 }
3375#endif
3376
3377 /*
3378 * Free the mapping entry.
3379 */
3380 pIemCpu->aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
3381 Assert(pIemCpu->cActiveMappings != 0);
3382 pIemCpu->cActiveMappings--;
3383 return rc;
3384}
3385
3386
3387/**
3388 * iemMemMap worker that deals with a request crossing pages.
3389 */
3390static VBOXSTRICTRC iemMemBounceBufferMapCrossPage(PIEMCPU pIemCpu, int iMemMap, void **ppvMem,
3391 size_t cbMem, RTGCPTR GCPtrFirst, uint32_t fAccess)
3392{
3393 /*
3394 * Do the address translations.
3395 */
3396 RTGCPHYS GCPhysFirst;
3397 VBOXSTRICTRC rcStrict = iemMemPageTranslateAndCheckAccess(pIemCpu, GCPtrFirst, fAccess, &GCPhysFirst);
3398 if (rcStrict != VINF_SUCCESS)
3399 return rcStrict;
3400
3401 RTGCPHYS GCPhysSecond;
3402 rcStrict = iemMemPageTranslateAndCheckAccess(pIemCpu, GCPtrFirst + (cbMem - 1), fAccess, &GCPhysSecond);
3403 if (rcStrict != VINF_SUCCESS)
3404 return rcStrict;
3405 GCPhysSecond &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
3406
3407 /*
3408 * Read in the current memory content if it's a read of execute access.
3409 */
3410 uint8_t *pbBuf = &pIemCpu->aBounceBuffers[iMemMap].ab[0];
3411 uint32_t const cbFirstPage = PAGE_SIZE - (GCPhysFirst & PAGE_OFFSET_MASK);
3412 uint32_t const cbSecondPage = (uint32_t)(cbMem - cbFirstPage);
3413
3414 if (fAccess & (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_EXEC))
3415 {
3416 int rc;
3417 if (!pIemCpu->fByPassHandlers)
3418 {
3419 rc = PGMPhysRead(IEMCPU_TO_VM(pIemCpu), GCPhysFirst, pbBuf, cbFirstPage);
3420 if (rc != VINF_SUCCESS)
3421 return rc;
3422 rc = PGMPhysRead(IEMCPU_TO_VM(pIemCpu), GCPhysSecond, pbBuf + cbFirstPage, cbSecondPage);
3423 if (rc != VINF_SUCCESS)
3424 return rc;
3425 }
3426 else
3427 {
3428 rc = PGMPhysSimpleReadGCPhys(IEMCPU_TO_VM(pIemCpu), pbBuf, GCPhysFirst, cbFirstPage);
3429 if (rc != VINF_SUCCESS)
3430 return rc;
3431 rc = PGMPhysSimpleReadGCPhys(IEMCPU_TO_VM(pIemCpu), pbBuf + cbFirstPage, GCPhysSecond, cbSecondPage);
3432 if (rc != VINF_SUCCESS)
3433 return rc;
3434 }
3435
3436#ifdef IEM_VERIFICATION_MODE
3437 if (!pIemCpu->fNoRem)
3438 {
3439 /*
3440 * Record the reads.
3441 */
3442 PIEMVERIFYEVTREC pEvtRec = iemVerifyAllocRecord(pIemCpu);
3443 if (pEvtRec)
3444 {
3445 pEvtRec->enmEvent = IEMVERIFYEVENT_RAM_READ;
3446 pEvtRec->u.RamRead.GCPhys = GCPhysFirst;
3447 pEvtRec->u.RamRead.cb = cbFirstPage;
3448 pEvtRec->pNext = *pIemCpu->ppIemEvtRecNext;
3449 *pIemCpu->ppIemEvtRecNext = pEvtRec;
3450 }
3451 pEvtRec = iemVerifyAllocRecord(pIemCpu);
3452 if (pEvtRec)
3453 {
3454 pEvtRec->enmEvent = IEMVERIFYEVENT_RAM_READ;
3455 pEvtRec->u.RamRead.GCPhys = GCPhysSecond;
3456 pEvtRec->u.RamRead.cb = cbSecondPage;
3457 pEvtRec->pNext = *pIemCpu->ppIemEvtRecNext;
3458 *pIemCpu->ppIemEvtRecNext = pEvtRec;
3459 }
3460 }
3461#endif
3462 }
3463#ifdef VBOX_STRICT
3464 else
3465 memset(pbBuf, 0xcc, cbMem);
3466#endif
3467#ifdef VBOX_STRICT
3468 if (cbMem < sizeof(pIemCpu->aBounceBuffers[iMemMap].ab))
3469 memset(pbBuf + cbMem, 0xaa, sizeof(pIemCpu->aBounceBuffers[iMemMap].ab) - cbMem);
3470#endif
3471
3472 /*
3473 * Commit the bounce buffer entry.
3474 */
3475 pIemCpu->aMemBbMappings[iMemMap].GCPhysFirst = GCPhysFirst;
3476 pIemCpu->aMemBbMappings[iMemMap].GCPhysSecond = GCPhysSecond;
3477 pIemCpu->aMemBbMappings[iMemMap].cbFirst = (uint16_t)cbFirstPage;
3478 pIemCpu->aMemBbMappings[iMemMap].cbSecond = (uint16_t)cbSecondPage;
3479 pIemCpu->aMemBbMappings[iMemMap].fUnassigned = false;
3480 pIemCpu->aMemMappings[iMemMap].pv = pbBuf;
3481 pIemCpu->aMemMappings[iMemMap].fAccess = fAccess | IEM_ACCESS_BOUNCE_BUFFERED;
3482 pIemCpu->cActiveMappings++;
3483
3484 *ppvMem = pbBuf;
3485 return VINF_SUCCESS;
3486}
3487
3488
3489/**
3490 * iemMemMap woker that deals with iemMemPageMap failures.
3491 */
3492static VBOXSTRICTRC iemMemBounceBufferMapPhys(PIEMCPU pIemCpu, unsigned iMemMap, void **ppvMem, size_t cbMem,
3493 RTGCPHYS GCPhysFirst, uint32_t fAccess, VBOXSTRICTRC rcMap)
3494{
3495 /*
3496 * Filter out conditions we can handle and the ones which shouldn't happen.
3497 */
3498 if ( rcMap != VINF_PGM_PHYS_TLB_CATCH_WRITE
3499 && rcMap != VERR_PGM_PHYS_TLB_CATCH_ALL
3500 && rcMap != VERR_PGM_PHYS_TLB_UNASSIGNED)
3501 {
3502 AssertReturn(RT_FAILURE_NP(rcMap), VERR_INTERNAL_ERROR_3);
3503 return rcMap;
3504 }
3505 pIemCpu->cPotentialExits++;
3506
3507 /*
3508 * Read in the current memory content if it's a read of execute access.
3509 */
3510 uint8_t *pbBuf = &pIemCpu->aBounceBuffers[iMemMap].ab[0];
3511 if (fAccess & (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_EXEC))
3512 {
3513 if (rcMap == VERR_PGM_PHYS_TLB_UNASSIGNED)
3514 memset(pbBuf, 0xff, cbMem);
3515 else
3516 {
3517 int rc;
3518 if (!pIemCpu->fByPassHandlers)
3519 rc = PGMPhysRead(IEMCPU_TO_VM(pIemCpu), GCPhysFirst, pbBuf, cbMem);
3520 else
3521 rc = PGMPhysSimpleReadGCPhys(IEMCPU_TO_VM(pIemCpu), pbBuf, GCPhysFirst, cbMem);
3522 if (rc != VINF_SUCCESS)
3523 return rc;
3524 }
3525
3526#ifdef IEM_VERIFICATION_MODE
3527 if (!pIemCpu->fNoRem)
3528 {
3529 /*
3530 * Record the read.
3531 */
3532 PIEMVERIFYEVTREC pEvtRec = iemVerifyAllocRecord(pIemCpu);
3533 if (pEvtRec)
3534 {
3535 pEvtRec->enmEvent = IEMVERIFYEVENT_RAM_READ;
3536 pEvtRec->u.RamRead.GCPhys = GCPhysFirst;
3537 pEvtRec->u.RamRead.cb = cbMem;
3538 pEvtRec->pNext = *pIemCpu->ppIemEvtRecNext;
3539 *pIemCpu->ppIemEvtRecNext = pEvtRec;
3540 }
3541 }
3542#endif
3543 }
3544#ifdef VBOX_STRICT
3545 else
3546 memset(pbBuf, 0xcc, cbMem);
3547#endif
3548#ifdef VBOX_STRICT
3549 if (cbMem < sizeof(pIemCpu->aBounceBuffers[iMemMap].ab))
3550 memset(pbBuf + cbMem, 0xaa, sizeof(pIemCpu->aBounceBuffers[iMemMap].ab) - cbMem);
3551#endif
3552
3553 /*
3554 * Commit the bounce buffer entry.
3555 */
3556 pIemCpu->aMemBbMappings[iMemMap].GCPhysFirst = GCPhysFirst;
3557 pIemCpu->aMemBbMappings[iMemMap].GCPhysSecond = NIL_RTGCPHYS;
3558 pIemCpu->aMemBbMappings[iMemMap].cbFirst = (uint16_t)cbMem;
3559 pIemCpu->aMemBbMappings[iMemMap].cbSecond = 0;
3560 pIemCpu->aMemBbMappings[iMemMap].fUnassigned = rcMap == VERR_PGM_PHYS_TLB_UNASSIGNED;
3561 pIemCpu->aMemMappings[iMemMap].pv = pbBuf;
3562 pIemCpu->aMemMappings[iMemMap].fAccess = fAccess | IEM_ACCESS_BOUNCE_BUFFERED;
3563 pIemCpu->cActiveMappings++;
3564
3565 *ppvMem = pbBuf;
3566 return VINF_SUCCESS;
3567}
3568
3569
3570
3571/**
3572 * Maps the specified guest memory for the given kind of access.
3573 *
3574 * This may be using bounce buffering of the memory if it's crossing a page
3575 * boundary or if there is an access handler installed for any of it. Because
3576 * of lock prefix guarantees, we're in for some extra clutter when this
3577 * happens.
3578 *
3579 * This may raise a \#GP, \#SS, \#PF or \#AC.
3580 *
3581 * @returns VBox strict status code.
3582 *
3583 * @param pIemCpu The IEM per CPU data.
3584 * @param ppvMem Where to return the pointer to the mapped
3585 * memory.
3586 * @param cbMem The number of bytes to map. This is usually 1,
3587 * 2, 4, 6, 8, 12, 16 or 32. When used by string
3588 * operations it can be up to a page.
3589 * @param iSegReg The index of the segment register to use for
3590 * this access. The base and limits are checked.
3591 * Use UINT8_MAX to indicate that no segmentation
3592 * is required (for IDT, GDT and LDT accesses).
3593 * @param GCPtrMem The address of the guest memory.
3594 * @param a_fAccess How the memory is being accessed. The
3595 * IEM_ACCESS_TYPE_XXX bit is used to figure out
3596 * how to map the memory, while the
3597 * IEM_ACCESS_WHAT_XXX bit is used when raising
3598 * exceptions.
3599 */
3600static VBOXSTRICTRC iemMemMap(PIEMCPU pIemCpu, void **ppvMem, size_t cbMem, uint8_t iSegReg, RTGCPTR GCPtrMem, uint32_t fAccess)
3601{
3602 /*
3603 * Check the input and figure out which mapping entry to use.
3604 */
3605 Assert(cbMem <= 32);
3606 Assert(~(fAccess & ~(IEM_ACCESS_TYPE_MASK | IEM_ACCESS_WHAT_MASK)));
3607
3608 unsigned iMemMap = pIemCpu->iNextMapping;
3609 if (iMemMap >= RT_ELEMENTS(pIemCpu->aMemMappings))
3610 {
3611 iMemMap = iemMemMapFindFree(pIemCpu);
3612 AssertReturn(iMemMap < RT_ELEMENTS(pIemCpu->aMemMappings), VERR_INTERNAL_ERROR_3);
3613 }
3614
3615 /*
3616 * Map the memory, checking that we can actually access it. If something
3617 * slightly complicated happens, fall back on bounce buffering.
3618 */
3619 VBOXSTRICTRC rcStrict = iemMemApplySegment(pIemCpu, fAccess, iSegReg, cbMem, &GCPtrMem);
3620 if (rcStrict != VINF_SUCCESS)
3621 return rcStrict;
3622
3623 if ((GCPtrMem & PAGE_OFFSET_MASK) + cbMem > PAGE_SIZE) /* Crossing a page boundary? */
3624 return iemMemBounceBufferMapCrossPage(pIemCpu, iMemMap, ppvMem, cbMem, GCPtrMem, fAccess);
3625
3626 RTGCPHYS GCPhysFirst;
3627 rcStrict = iemMemPageTranslateAndCheckAccess(pIemCpu, GCPtrMem, fAccess, &GCPhysFirst);
3628 if (rcStrict != VINF_SUCCESS)
3629 return rcStrict;
3630
3631 void *pvMem;
3632 rcStrict = iemMemPageMap(pIemCpu, GCPhysFirst, fAccess, &pvMem);
3633 if (rcStrict != VINF_SUCCESS)
3634 return iemMemBounceBufferMapPhys(pIemCpu, iMemMap, ppvMem, cbMem, GCPhysFirst, fAccess, rcStrict);
3635
3636 /*
3637 * Fill in the mapping table entry.
3638 */
3639 pIemCpu->aMemMappings[iMemMap].pv = pvMem;
3640 pIemCpu->aMemMappings[iMemMap].fAccess = fAccess;
3641 pIemCpu->iNextMapping = iMemMap + 1;
3642 pIemCpu->cActiveMappings++;
3643
3644 *ppvMem = pvMem;
3645 return VINF_SUCCESS;
3646}
3647
3648
3649/**
3650 * Commits the guest memory if bounce buffered and unmaps it.
3651 *
3652 * @returns Strict VBox status code.
3653 * @param pIemCpu The IEM per CPU data.
3654 * @param pvMem The mapping.
3655 * @param fAccess The kind of access.
3656 */
3657static VBOXSTRICTRC iemMemCommitAndUnmap(PIEMCPU pIemCpu, void *pvMem, uint32_t fAccess)
3658{
3659 int iMemMap = iemMapLookup(pIemCpu, pvMem, fAccess);
3660 AssertReturn(iMemMap >= 0, iMemMap);
3661
3662 /*
3663 * If it's bounce buffered, we need to write back the buffer.
3664 */
3665 if ( (pIemCpu->aMemMappings[iMemMap].fAccess & (IEM_ACCESS_BOUNCE_BUFFERED | IEM_ACCESS_TYPE_WRITE))
3666 == (IEM_ACCESS_BOUNCE_BUFFERED | IEM_ACCESS_TYPE_WRITE))
3667 return iemMemBounceBufferCommitAndUnmap(pIemCpu, iMemMap);
3668
3669 /* Free the entry. */
3670 pIemCpu->aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
3671 Assert(pIemCpu->cActiveMappings != 0);
3672 pIemCpu->cActiveMappings--;
3673 return VINF_SUCCESS;
3674}
3675
3676
3677/**
3678 * Fetches a data byte.
3679 *
3680 * @returns Strict VBox status code.
3681 * @param pIemCpu The IEM per CPU data.
3682 * @param pu8Dst Where to return the byte.
3683 * @param iSegReg The index of the segment register to use for
3684 * this access. The base and limits are checked.
3685 * @param GCPtrMem The address of the guest memory.
3686 */
3687static VBOXSTRICTRC iemMemFetchDataU8(PIEMCPU pIemCpu, uint8_t *pu8Dst, uint8_t iSegReg, RTGCPTR GCPtrMem)
3688{
3689 /* The lazy approach for now... */
3690 uint8_t const *pu8Src;
3691 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu8Src, sizeof(*pu8Src), iSegReg, GCPtrMem, IEM_ACCESS_DATA_R);
3692 if (rc == VINF_SUCCESS)
3693 {
3694 *pu8Dst = *pu8Src;
3695 rc = iemMemCommitAndUnmap(pIemCpu, (void *)pu8Src, IEM_ACCESS_DATA_R);
3696 }
3697 return rc;
3698}
3699
3700
3701/**
3702 * Fetches a data word.
3703 *
3704 * @returns Strict VBox status code.
3705 * @param pIemCpu The IEM per CPU data.
3706 * @param pu16Dst Where to return the word.
3707 * @param iSegReg The index of the segment register to use for
3708 * this access. The base and limits are checked.
3709 * @param GCPtrMem The address of the guest memory.
3710 */
3711static VBOXSTRICTRC iemMemFetchDataU16(PIEMCPU pIemCpu, uint16_t *pu16Dst, uint8_t iSegReg, RTGCPTR GCPtrMem)
3712{
3713 /* The lazy approach for now... */
3714 uint16_t const *pu16Src;
3715 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu16Src, sizeof(*pu16Src), iSegReg, GCPtrMem, IEM_ACCESS_DATA_R);
3716 if (rc == VINF_SUCCESS)
3717 {
3718 *pu16Dst = *pu16Src;
3719 rc = iemMemCommitAndUnmap(pIemCpu, (void *)pu16Src, IEM_ACCESS_DATA_R);
3720 }
3721 return rc;
3722}
3723
3724
3725/**
3726 * Fetches a data dword.
3727 *
3728 * @returns Strict VBox status code.
3729 * @param pIemCpu The IEM per CPU data.
3730 * @param pu32Dst Where to return the dword.
3731 * @param iSegReg The index of the segment register to use for
3732 * this access. The base and limits are checked.
3733 * @param GCPtrMem The address of the guest memory.
3734 */
3735static VBOXSTRICTRC iemMemFetchDataU32(PIEMCPU pIemCpu, uint32_t *pu32Dst, uint8_t iSegReg, RTGCPTR GCPtrMem)
3736{
3737 /* The lazy approach for now... */
3738 uint32_t const *pu32Src;
3739 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu32Src, sizeof(*pu32Src), iSegReg, GCPtrMem, IEM_ACCESS_DATA_R);
3740 if (rc == VINF_SUCCESS)
3741 {
3742 *pu32Dst = *pu32Src;
3743 rc = iemMemCommitAndUnmap(pIemCpu, (void *)pu32Src, IEM_ACCESS_DATA_R);
3744 }
3745 return rc;
3746}
3747
3748
3749/**
3750 * Fetches a data dword and sign extends it to a qword.
3751 *
3752 * @returns Strict VBox status code.
3753 * @param pIemCpu The IEM per CPU data.
3754 * @param pu64Dst Where to return the sign extended value.
3755 * @param iSegReg The index of the segment register to use for
3756 * this access. The base and limits are checked.
3757 * @param GCPtrMem The address of the guest memory.
3758 */
3759static VBOXSTRICTRC iemMemFetchDataS32SxU64(PIEMCPU pIemCpu, uint64_t *pu64Dst, uint8_t iSegReg, RTGCPTR GCPtrMem)
3760{
3761 /* The lazy approach for now... */
3762 int32_t const *pi32Src;
3763 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pi32Src, sizeof(*pi32Src), iSegReg, GCPtrMem, IEM_ACCESS_DATA_R);
3764 if (rc == VINF_SUCCESS)
3765 {
3766 *pu64Dst = *pi32Src;
3767 rc = iemMemCommitAndUnmap(pIemCpu, (void *)pi32Src, IEM_ACCESS_DATA_R);
3768 }
3769#ifdef __GNUC__ /* warning: GCC may be a royal pain */
3770 else
3771 *pu64Dst = 0;
3772#endif
3773 return rc;
3774}
3775
3776
3777/**
3778 * Fetches a data qword.
3779 *
3780 * @returns Strict VBox status code.
3781 * @param pIemCpu The IEM per CPU data.
3782 * @param pu64Dst Where to return the qword.
3783 * @param iSegReg The index of the segment register to use for
3784 * this access. The base and limits are checked.
3785 * @param GCPtrMem The address of the guest memory.
3786 */
3787static VBOXSTRICTRC iemMemFetchDataU64(PIEMCPU pIemCpu, uint64_t *pu64Dst, uint8_t iSegReg, RTGCPTR GCPtrMem)
3788{
3789 /* The lazy approach for now... */
3790 uint64_t const *pu64Src;
3791 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu64Src, sizeof(*pu64Src), iSegReg, GCPtrMem, IEM_ACCESS_DATA_R);
3792 if (rc == VINF_SUCCESS)
3793 {
3794 *pu64Dst = *pu64Src;
3795 rc = iemMemCommitAndUnmap(pIemCpu, (void *)pu64Src, IEM_ACCESS_DATA_R);
3796 }
3797 return rc;
3798}
3799
3800
3801/**
3802 * Fetches a descriptor register (lgdt, lidt).
3803 *
3804 * @returns Strict VBox status code.
3805 * @param pIemCpu The IEM per CPU data.
3806 * @param pcbLimit Where to return the limit.
3807 * @param pGCPTrBase Where to return the base.
3808 * @param iSegReg The index of the segment register to use for
3809 * this access. The base and limits are checked.
3810 * @param GCPtrMem The address of the guest memory.
3811 * @param enmOpSize The effective operand size.
3812 */
3813static VBOXSTRICTRC iemMemFetchDataXdtr(PIEMCPU pIemCpu, uint16_t *pcbLimit, PRTGCPTR pGCPtrBase,
3814 uint8_t iSegReg, RTGCPTR GCPtrMem, IEMMODE enmOpSize)
3815{
3816 uint8_t const *pu8Src;
3817 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu,
3818 (void **)&pu8Src,
3819 enmOpSize == IEMMODE_64BIT
3820 ? 2 + 8
3821 : enmOpSize == IEMMODE_32BIT
3822 ? 2 + 4
3823 : 2 + 3,
3824 iSegReg,
3825 GCPtrMem,
3826 IEM_ACCESS_DATA_R);
3827 if (rcStrict == VINF_SUCCESS)
3828 {
3829 *pcbLimit = RT_MAKE_U16(pu8Src[0], pu8Src[1]);
3830 switch (enmOpSize)
3831 {
3832 case IEMMODE_16BIT:
3833 *pGCPtrBase = RT_MAKE_U32_FROM_U8(pu8Src[2], pu8Src[3], pu8Src[4], 0);
3834 break;
3835 case IEMMODE_32BIT:
3836 *pGCPtrBase = RT_MAKE_U32_FROM_U8(pu8Src[2], pu8Src[3], pu8Src[4], pu8Src[5]);
3837 break;
3838 case IEMMODE_64BIT:
3839 *pGCPtrBase = RT_MAKE_U64_FROM_U8(pu8Src[2], pu8Src[3], pu8Src[4], pu8Src[5],
3840 pu8Src[6], pu8Src[7], pu8Src[8], pu8Src[9]);
3841 break;
3842
3843 IEM_NOT_REACHED_DEFAULT_CASE_RET();
3844 }
3845 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)pu8Src, IEM_ACCESS_DATA_R);
3846 }
3847 return rcStrict;
3848}
3849
3850
3851
3852/**
3853 * Stores a data byte.
3854 *
3855 * @returns Strict VBox status code.
3856 * @param pIemCpu The IEM per CPU data.
3857 * @param iSegReg The index of the segment register to use for
3858 * this access. The base and limits are checked.
3859 * @param GCPtrMem The address of the guest memory.
3860 * @param u8Value The value to store.
3861 */
3862static VBOXSTRICTRC iemMemStoreDataU8(PIEMCPU pIemCpu, uint8_t iSegReg, RTGCPTR GCPtrMem, uint8_t u8Value)
3863{
3864 /* The lazy approach for now... */
3865 uint8_t *pu8Dst;
3866 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu8Dst, sizeof(*pu8Dst), iSegReg, GCPtrMem, IEM_ACCESS_DATA_W);
3867 if (rc == VINF_SUCCESS)
3868 {
3869 *pu8Dst = u8Value;
3870 rc = iemMemCommitAndUnmap(pIemCpu, pu8Dst, IEM_ACCESS_DATA_W);
3871 }
3872 return rc;
3873}
3874
3875
3876/**
3877 * Stores a data word.
3878 *
3879 * @returns Strict VBox status code.
3880 * @param pIemCpu The IEM per CPU data.
3881 * @param iSegReg The index of the segment register to use for
3882 * this access. The base and limits are checked.
3883 * @param GCPtrMem The address of the guest memory.
3884 * @param u16Value The value to store.
3885 */
3886static VBOXSTRICTRC iemMemStoreDataU16(PIEMCPU pIemCpu, uint8_t iSegReg, RTGCPTR GCPtrMem, uint16_t u16Value)
3887{
3888 /* The lazy approach for now... */
3889 uint16_t *pu16Dst;
3890 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu16Dst, sizeof(*pu16Dst), iSegReg, GCPtrMem, IEM_ACCESS_DATA_W);
3891 if (rc == VINF_SUCCESS)
3892 {
3893 *pu16Dst = u16Value;
3894 rc = iemMemCommitAndUnmap(pIemCpu, pu16Dst, IEM_ACCESS_DATA_W);
3895 }
3896 return rc;
3897}
3898
3899
3900/**
3901 * Stores a data dword.
3902 *
3903 * @returns Strict VBox status code.
3904 * @param pIemCpu The IEM per CPU data.
3905 * @param iSegReg The index of the segment register to use for
3906 * this access. The base and limits are checked.
3907 * @param GCPtrMem The address of the guest memory.
3908 * @param u32Value The value to store.
3909 */
3910static VBOXSTRICTRC iemMemStoreDataU32(PIEMCPU pIemCpu, uint8_t iSegReg, RTGCPTR GCPtrMem, uint32_t u32Value)
3911{
3912 /* The lazy approach for now... */
3913 uint32_t *pu32Dst;
3914 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu32Dst, sizeof(*pu32Dst), iSegReg, GCPtrMem, IEM_ACCESS_DATA_W);
3915 if (rc == VINF_SUCCESS)
3916 {
3917 *pu32Dst = u32Value;
3918 rc = iemMemCommitAndUnmap(pIemCpu, pu32Dst, IEM_ACCESS_DATA_W);
3919 }
3920 return rc;
3921}
3922
3923
3924/**
3925 * Stores a data qword.
3926 *
3927 * @returns Strict VBox status code.
3928 * @param pIemCpu The IEM per CPU data.
3929 * @param iSegReg The index of the segment register to use for
3930 * this access. The base and limits are checked.
3931 * @param GCPtrMem The address of the guest memory.
3932 * @param u64Value The value to store.
3933 */
3934static VBOXSTRICTRC iemMemStoreDataU64(PIEMCPU pIemCpu, uint8_t iSegReg, RTGCPTR GCPtrMem, uint64_t u64Value)
3935{
3936 /* The lazy approach for now... */
3937 uint64_t *pu64Dst;
3938 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu64Dst, sizeof(*pu64Dst), iSegReg, GCPtrMem, IEM_ACCESS_DATA_W);
3939 if (rc == VINF_SUCCESS)
3940 {
3941 *pu64Dst = u64Value;
3942 rc = iemMemCommitAndUnmap(pIemCpu, pu64Dst, IEM_ACCESS_DATA_W);
3943 }
3944 return rc;
3945}
3946
3947
3948/**
3949 * Pushes a word onto the stack.
3950 *
3951 * @returns Strict VBox status code.
3952 * @param pIemCpu The IEM per CPU data.
3953 * @param u16Value The value to push.
3954 */
3955static VBOXSTRICTRC iemMemStackPushU16(PIEMCPU pIemCpu, uint16_t u16Value)
3956{
3957 /* Increment the stack pointer. */
3958 uint64_t uNewRsp;
3959 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3960 RTGCPTR GCPtrTop = iemRegGetRspForPush(pCtx, 2, &uNewRsp);
3961
3962 /* Write the word the lazy way. */
3963 uint16_t *pu16Dst;
3964 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu16Dst, sizeof(*pu16Dst), X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_W);
3965 if (rc == VINF_SUCCESS)
3966 {
3967 *pu16Dst = u16Value;
3968 rc = iemMemCommitAndUnmap(pIemCpu, pu16Dst, IEM_ACCESS_STACK_W);
3969 }
3970
3971 /* Commit the new RSP value unless we an access handler made trouble. */
3972 if (rc == VINF_SUCCESS)
3973 pCtx->rsp = uNewRsp;
3974
3975 return rc;
3976}
3977
3978
3979/**
3980 * Pushes a dword onto the stack.
3981 *
3982 * @returns Strict VBox status code.
3983 * @param pIemCpu The IEM per CPU data.
3984 * @param u32Value The value to push.
3985 */
3986static VBOXSTRICTRC iemMemStackPushU32(PIEMCPU pIemCpu, uint32_t u32Value)
3987{
3988 /* Increment the stack pointer. */
3989 uint64_t uNewRsp;
3990 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
3991 RTGCPTR GCPtrTop = iemRegGetRspForPush(pCtx, 4, &uNewRsp);
3992
3993 /* Write the word the lazy way. */
3994 uint32_t *pu32Dst;
3995 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu32Dst, sizeof(*pu32Dst), X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_W);
3996 if (rc == VINF_SUCCESS)
3997 {
3998 *pu32Dst = u32Value;
3999 rc = iemMemCommitAndUnmap(pIemCpu, pu32Dst, IEM_ACCESS_STACK_W);
4000 }
4001
4002 /* Commit the new RSP value unless we an access handler made trouble. */
4003 if (rc == VINF_SUCCESS)
4004 pCtx->rsp = uNewRsp;
4005
4006 return rc;
4007}
4008
4009
4010/**
4011 * Pushes a qword onto the stack.
4012 *
4013 * @returns Strict VBox status code.
4014 * @param pIemCpu The IEM per CPU data.
4015 * @param u64Value The value to push.
4016 */
4017static VBOXSTRICTRC iemMemStackPushU64(PIEMCPU pIemCpu, uint64_t u64Value)
4018{
4019 /* Increment the stack pointer. */
4020 uint64_t uNewRsp;
4021 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4022 RTGCPTR GCPtrTop = iemRegGetRspForPush(pCtx, 8, &uNewRsp);
4023
4024 /* Write the word the lazy way. */
4025 uint64_t *pu64Dst;
4026 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu64Dst, sizeof(*pu64Dst), X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_W);
4027 if (rc == VINF_SUCCESS)
4028 {
4029 *pu64Dst = u64Value;
4030 rc = iemMemCommitAndUnmap(pIemCpu, pu64Dst, IEM_ACCESS_STACK_W);
4031 }
4032
4033 /* Commit the new RSP value unless we an access handler made trouble. */
4034 if (rc == VINF_SUCCESS)
4035 pCtx->rsp = uNewRsp;
4036
4037 return rc;
4038}
4039
4040
4041/**
4042 * Pops a word from the stack.
4043 *
4044 * @returns Strict VBox status code.
4045 * @param pIemCpu The IEM per CPU data.
4046 * @param pu16Value Where to store the popped value.
4047 */
4048static VBOXSTRICTRC iemMemStackPopU16(PIEMCPU pIemCpu, uint16_t *pu16Value)
4049{
4050 /* Increment the stack pointer. */
4051 uint64_t uNewRsp;
4052 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4053 RTGCPTR GCPtrTop = iemRegGetRspForPop(pCtx, 2, &uNewRsp);
4054
4055 /* Write the word the lazy way. */
4056 uint16_t const *pu16Src;
4057 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu16Src, sizeof(*pu16Src), X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_R);
4058 if (rc == VINF_SUCCESS)
4059 {
4060 *pu16Value = *pu16Src;
4061 rc = iemMemCommitAndUnmap(pIemCpu, (void *)pu16Src, IEM_ACCESS_STACK_R);
4062
4063 /* Commit the new RSP value. */
4064 if (rc == VINF_SUCCESS)
4065 pCtx->rsp = uNewRsp;
4066 }
4067
4068 return rc;
4069}
4070
4071
4072/**
4073 * Pops a dword from the stack.
4074 *
4075 * @returns Strict VBox status code.
4076 * @param pIemCpu The IEM per CPU data.
4077 * @param pu32Value Where to store the popped value.
4078 */
4079static VBOXSTRICTRC iemMemStackPopU32(PIEMCPU pIemCpu, uint32_t *pu32Value)
4080{
4081 /* Increment the stack pointer. */
4082 uint64_t uNewRsp;
4083 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4084 RTGCPTR GCPtrTop = iemRegGetRspForPop(pCtx, 4, &uNewRsp);
4085
4086 /* Write the word the lazy way. */
4087 uint32_t const *pu32Src;
4088 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu32Src, sizeof(*pu32Src), X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_R);
4089 if (rc == VINF_SUCCESS)
4090 {
4091 *pu32Value = *pu32Src;
4092 rc = iemMemCommitAndUnmap(pIemCpu, (void *)pu32Src, IEM_ACCESS_STACK_R);
4093
4094 /* Commit the new RSP value. */
4095 if (rc == VINF_SUCCESS)
4096 pCtx->rsp = uNewRsp;
4097 }
4098
4099 return rc;
4100}
4101
4102
4103/**
4104 * Pops a qword from the stack.
4105 *
4106 * @returns Strict VBox status code.
4107 * @param pIemCpu The IEM per CPU data.
4108 * @param pu64Value Where to store the popped value.
4109 */
4110static VBOXSTRICTRC iemMemStackPopU64(PIEMCPU pIemCpu, uint64_t *pu64Value)
4111{
4112 /* Increment the stack pointer. */
4113 uint64_t uNewRsp;
4114 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4115 RTGCPTR GCPtrTop = iemRegGetRspForPop(pCtx, 8, &uNewRsp);
4116
4117 /* Write the word the lazy way. */
4118 uint64_t const *pu64Src;
4119 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu64Src, sizeof(*pu64Src), X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_R);
4120 if (rc == VINF_SUCCESS)
4121 {
4122 *pu64Value = *pu64Src;
4123 rc = iemMemCommitAndUnmap(pIemCpu, (void *)pu64Src, IEM_ACCESS_STACK_R);
4124
4125 /* Commit the new RSP value. */
4126 if (rc == VINF_SUCCESS)
4127 pCtx->rsp = uNewRsp;
4128 }
4129
4130 return rc;
4131}
4132
4133
4134/**
4135 * Pushes a word onto the stack, using a temporary stack pointer.
4136 *
4137 * @returns Strict VBox status code.
4138 * @param pIemCpu The IEM per CPU data.
4139 * @param u16Value The value to push.
4140 * @param pTmpRsp Pointer to the temporary stack pointer.
4141 */
4142static VBOXSTRICTRC iemMemStackPushU16Ex(PIEMCPU pIemCpu, uint16_t u16Value, PRTUINT64U pTmpRsp)
4143{
4144 /* Increment the stack pointer. */
4145 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4146 RTUINT64U NewRsp = *pTmpRsp;
4147 RTGCPTR GCPtrTop = iemRegGetRspForPushEx(&NewRsp, 2, pCtx);
4148
4149 /* Write the word the lazy way. */
4150 uint16_t *pu16Dst;
4151 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu16Dst, sizeof(*pu16Dst), X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_W);
4152 if (rc == VINF_SUCCESS)
4153 {
4154 *pu16Dst = u16Value;
4155 rc = iemMemCommitAndUnmap(pIemCpu, pu16Dst, IEM_ACCESS_STACK_W);
4156 }
4157
4158 /* Commit the new RSP value unless we an access handler made trouble. */
4159 if (rc == VINF_SUCCESS)
4160 *pTmpRsp = NewRsp;
4161
4162 return rc;
4163}
4164
4165
4166/**
4167 * Pushes a dword onto the stack, using a temporary stack pointer.
4168 *
4169 * @returns Strict VBox status code.
4170 * @param pIemCpu The IEM per CPU data.
4171 * @param u32Value The value to push.
4172 * @param pTmpRsp Pointer to the temporary stack pointer.
4173 */
4174static VBOXSTRICTRC iemMemStackPushU32Ex(PIEMCPU pIemCpu, uint32_t u32Value, PRTUINT64U pTmpRsp)
4175{
4176 /* Increment the stack pointer. */
4177 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4178 RTUINT64U NewRsp = *pTmpRsp;
4179 RTGCPTR GCPtrTop = iemRegGetRspForPushEx(&NewRsp, 4, pCtx);
4180
4181 /* Write the word the lazy way. */
4182 uint32_t *pu32Dst;
4183 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu32Dst, sizeof(*pu32Dst), X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_W);
4184 if (rc == VINF_SUCCESS)
4185 {
4186 *pu32Dst = u32Value;
4187 rc = iemMemCommitAndUnmap(pIemCpu, pu32Dst, IEM_ACCESS_STACK_W);
4188 }
4189
4190 /* Commit the new RSP value unless we an access handler made trouble. */
4191 if (rc == VINF_SUCCESS)
4192 *pTmpRsp = NewRsp;
4193
4194 return rc;
4195}
4196
4197
4198/**
4199 * Pushes a dword onto the stack, using a temporary stack pointer.
4200 *
4201 * @returns Strict VBox status code.
4202 * @param pIemCpu The IEM per CPU data.
4203 * @param u64Value The value to push.
4204 * @param pTmpRsp Pointer to the temporary stack pointer.
4205 */
4206static VBOXSTRICTRC iemMemStackPushU64Ex(PIEMCPU pIemCpu, uint64_t u64Value, PRTUINT64U pTmpRsp)
4207{
4208 /* Increment the stack pointer. */
4209 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4210 RTUINT64U NewRsp = *pTmpRsp;
4211 RTGCPTR GCPtrTop = iemRegGetRspForPushEx(&NewRsp, 8, pCtx);
4212
4213 /* Write the word the lazy way. */
4214 uint64_t *pu64Dst;
4215 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu64Dst, sizeof(*pu64Dst), X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_W);
4216 if (rc == VINF_SUCCESS)
4217 {
4218 *pu64Dst = u64Value;
4219 rc = iemMemCommitAndUnmap(pIemCpu, pu64Dst, IEM_ACCESS_STACK_W);
4220 }
4221
4222 /* Commit the new RSP value unless we an access handler made trouble. */
4223 if (rc == VINF_SUCCESS)
4224 *pTmpRsp = NewRsp;
4225
4226 return rc;
4227}
4228
4229
4230/**
4231 * Pops a word from the stack, using a temporary stack pointer.
4232 *
4233 * @returns Strict VBox status code.
4234 * @param pIemCpu The IEM per CPU data.
4235 * @param pu16Value Where to store the popped value.
4236 * @param pTmpRsp Pointer to the temporary stack pointer.
4237 */
4238static VBOXSTRICTRC iemMemStackPopU16Ex(PIEMCPU pIemCpu, uint16_t *pu16Value, PRTUINT64U pTmpRsp)
4239{
4240 /* Increment the stack pointer. */
4241 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4242 RTUINT64U NewRsp = *pTmpRsp;
4243 RTGCPTR GCPtrTop = iemRegGetRspForPopEx(&NewRsp, 2, pCtx);
4244
4245 /* Write the word the lazy way. */
4246 uint16_t const *pu16Src;
4247 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu16Src, sizeof(*pu16Src), X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_R);
4248 if (rc == VINF_SUCCESS)
4249 {
4250 *pu16Value = *pu16Src;
4251 rc = iemMemCommitAndUnmap(pIemCpu, (void *)pu16Src, IEM_ACCESS_STACK_R);
4252
4253 /* Commit the new RSP value. */
4254 if (rc == VINF_SUCCESS)
4255 *pTmpRsp = NewRsp;
4256 }
4257
4258 return rc;
4259}
4260
4261
4262/**
4263 * Pops a dword from the stack, using a temporary stack pointer.
4264 *
4265 * @returns Strict VBox status code.
4266 * @param pIemCpu The IEM per CPU data.
4267 * @param pu32Value Where to store the popped value.
4268 * @param pTmpRsp Pointer to the temporary stack pointer.
4269 */
4270static VBOXSTRICTRC iemMemStackPopU32Ex(PIEMCPU pIemCpu, uint32_t *pu32Value, PRTUINT64U pTmpRsp)
4271{
4272 /* Increment the stack pointer. */
4273 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4274 RTUINT64U NewRsp = *pTmpRsp;
4275 RTGCPTR GCPtrTop = iemRegGetRspForPopEx(&NewRsp, 4, pCtx);
4276
4277 /* Write the word the lazy way. */
4278 uint32_t const *pu32Src;
4279 VBOXSTRICTRC rc = iemMemMap(pIemCpu, (void **)&pu32Src, sizeof(*pu32Src), X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_R);
4280 if (rc == VINF_SUCCESS)
4281 {
4282 *pu32Value = *pu32Src;
4283 rc = iemMemCommitAndUnmap(pIemCpu, (void *)pu32Src, IEM_ACCESS_STACK_R);
4284
4285 /* Commit the new RSP value. */
4286 if (rc == VINF_SUCCESS)
4287 *pTmpRsp = NewRsp;
4288 }
4289
4290 return rc;
4291}
4292
4293
4294/**
4295 * Pops a qword from the stack, using a temporary stack pointer.
4296 *
4297 * @returns Strict VBox status code.
4298 * @param pIemCpu The IEM per CPU data.
4299 * @param pu64Value Where to store the popped value.
4300 * @param pTmpRsp Pointer to the temporary stack pointer.
4301 */
4302static VBOXSTRICTRC iemMemStackPopU64Ex(PIEMCPU pIemCpu, uint64_t *pu64Value, PRTUINT64U pTmpRsp)
4303{
4304 /* Increment the stack pointer. */
4305 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4306 RTUINT64U NewRsp = *pTmpRsp;
4307 RTGCPTR GCPtrTop = iemRegGetRspForPopEx(&NewRsp, 8, pCtx);
4308
4309 /* Write the word the lazy way. */
4310 uint64_t const *pu64Src;
4311 VBOXSTRICTRC rcStrict = iemMemMap(pIemCpu, (void **)&pu64Src, sizeof(*pu64Src), X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_R);
4312 if (rcStrict == VINF_SUCCESS)
4313 {
4314 *pu64Value = *pu64Src;
4315 rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)pu64Src, IEM_ACCESS_STACK_R);
4316
4317 /* Commit the new RSP value. */
4318 if (rcStrict == VINF_SUCCESS)
4319 *pTmpRsp = NewRsp;
4320 }
4321
4322 return rcStrict;
4323}
4324
4325
4326/**
4327 * Begin a special stack push (used by interrupt, exceptions and such).
4328 *
4329 * This will raise #SS or #PF if appropriate.
4330 *
4331 * @returns Strict VBox status code.
4332 * @param pIemCpu The IEM per CPU data.
4333 * @param cbMem The number of bytes to push onto the stack.
4334 * @param ppvMem Where to return the pointer to the stack memory.
4335 * As with the other memory functions this could be
4336 * direct access or bounce buffered access, so
4337 * don't commit register until the commit call
4338 * succeeds.
4339 * @param puNewRsp Where to return the new RSP value. This must be
4340 * passed unchanged to
4341 * iemMemStackPushCommitSpecial().
4342 */
4343static VBOXSTRICTRC iemMemStackPushBeginSpecial(PIEMCPU pIemCpu, size_t cbMem, void **ppvMem, uint64_t *puNewRsp)
4344{
4345 Assert(cbMem < UINT8_MAX);
4346 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4347 RTGCPTR GCPtrTop = iemRegGetRspForPush(pCtx, (uint8_t)cbMem, puNewRsp);
4348 return iemMemMap(pIemCpu, ppvMem, cbMem, X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_W);
4349}
4350
4351
4352/**
4353 * Commits a special stack push (started by iemMemStackPushBeginSpecial).
4354 *
4355 * This will update the rSP.
4356 *
4357 * @returns Strict VBox status code.
4358 * @param pIemCpu The IEM per CPU data.
4359 * @param pvMem The pointer returned by
4360 * iemMemStackPushBeginSpecial().
4361 * @param uNewRsp The new RSP value returned by
4362 * iemMemStackPushBeginSpecial().
4363 */
4364static VBOXSTRICTRC iemMemStackPushCommitSpecial(PIEMCPU pIemCpu, void *pvMem, uint64_t uNewRsp)
4365{
4366 VBOXSTRICTRC rcStrict = iemMemCommitAndUnmap(pIemCpu, pvMem, IEM_ACCESS_STACK_W);
4367 if (rcStrict == VINF_SUCCESS)
4368 pIemCpu->CTX_SUFF(pCtx)->rsp = uNewRsp;
4369 return rcStrict;
4370}
4371
4372
4373/**
4374 * Begin a special stack pop (used by iret, retf and such).
4375 *
4376 * This will raise #SS or #PF if appropriate.
4377 *
4378 * @returns Strict VBox status code.
4379 * @param pIemCpu The IEM per CPU data.
4380 * @param cbMem The number of bytes to push onto the stack.
4381 * @param ppvMem Where to return the pointer to the stack memory.
4382 * @param puNewRsp Where to return the new RSP value. This must be
4383 * passed unchanged to
4384 * iemMemStackPopCommitSpecial().
4385 */
4386static VBOXSTRICTRC iemMemStackPopBeginSpecial(PIEMCPU pIemCpu, size_t cbMem, void const **ppvMem, uint64_t *puNewRsp)
4387{
4388 Assert(cbMem < UINT8_MAX);
4389 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4390 RTGCPTR GCPtrTop = iemRegGetRspForPop(pCtx, (uint8_t)cbMem, puNewRsp);
4391 return iemMemMap(pIemCpu, (void **)ppvMem, cbMem, X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_R);
4392}
4393
4394
4395/**
4396 * Commits a special stack pop (started by iemMemStackPopBeginSpecial).
4397 *
4398 * This will update the rSP.
4399 *
4400 * @returns Strict VBox status code.
4401 * @param pIemCpu The IEM per CPU data.
4402 * @param pvMem The pointer returned by
4403 * iemMemStackPopBeginSpecial().
4404 * @param uNewRsp The new RSP value returned by
4405 * iemMemStackPopBeginSpecial().
4406 */
4407static VBOXSTRICTRC iemMemStackPopCommitSpecial(PIEMCPU pIemCpu, void const *pvMem, uint64_t uNewRsp)
4408{
4409 VBOXSTRICTRC rcStrict = iemMemCommitAndUnmap(pIemCpu, (void *)pvMem, IEM_ACCESS_STACK_R);
4410 if (rcStrict == VINF_SUCCESS)
4411 pIemCpu->CTX_SUFF(pCtx)->rsp = uNewRsp;
4412 return rcStrict;
4413}
4414
4415
4416/**
4417 * Fetches a descriptor table entry.
4418 *
4419 * @returns Strict VBox status code.
4420 * @param pIemCpu The IEM per CPU.
4421 * @param pDesc Where to return the descriptor table entry.
4422 * @param uSel The selector which table entry to fetch.
4423 */
4424static VBOXSTRICTRC iemMemFetchSelDesc(PIEMCPU pIemCpu, PIEMSELDESC pDesc, uint16_t uSel)
4425{
4426 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4427
4428 /** @todo did the 286 require all 8 bytes to be accessible? */
4429 /*
4430 * Get the selector table base and check bounds.
4431 */
4432 RTGCPTR GCPtrBase;
4433 if (uSel & X86_SEL_LDT)
4434 {
4435 if ( !pCtx->ldtrHid.Attr.n.u1Present
4436 || (uSel | 0x7U) > pCtx->ldtrHid.u32Limit )
4437 {
4438 Log(("iemMemFetchSelDesc: LDT selector %#x is out of bounds (%3x) or ldtr is NP (%#x)\n",
4439 uSel, pCtx->ldtrHid.u32Limit, pCtx->ldtr));
4440 /** @todo is this the right exception? */
4441 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
4442 }
4443
4444 Assert(pCtx->ldtrHid.Attr.n.u1Present);
4445 GCPtrBase = pCtx->ldtrHid.u64Base;
4446 }
4447 else
4448 {
4449 if ((uSel | 0x7U) > pCtx->gdtr.cbGdt)
4450 {
4451 Log(("iemMemFetchSelDesc: GDT selector %#x is out of bounds (%3x)\n", uSel, pCtx->gdtr.cbGdt));
4452 /** @todo is this the right exception? */
4453 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
4454 }
4455 GCPtrBase = pCtx->gdtr.pGdt;
4456 }
4457
4458 /*
4459 * Read the legacy descriptor and maybe the long mode extensions if
4460 * required.
4461 */
4462 VBOXSTRICTRC rcStrict = iemMemFetchDataU64(pIemCpu, &pDesc->Legacy.u, UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK));
4463 if (rcStrict == VINF_SUCCESS)
4464 {
4465 if ( !IEM_IS_LONG_MODE(pIemCpu)
4466 || pDesc->Legacy.Gen.u1DescType)
4467 pDesc->Long.au64[1] = 0;
4468 else if ((uint32_t)(uSel & X86_SEL_MASK) + 15 < (uSel & X86_SEL_LDT ? pCtx->ldtrHid.u32Limit : pCtx->gdtr.cbGdt))
4469 rcStrict = iemMemFetchDataU64(pIemCpu, &pDesc->Legacy.u, UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK));
4470 else
4471 {
4472 Log(("iemMemFetchSelDesc: system selector %#x is out of bounds\n", uSel));
4473 /** @todo is this the right exception? */
4474 return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
4475 }
4476 }
4477 return rcStrict;
4478}
4479
4480
4481/**
4482 * Marks the selector descriptor as accessed (only non-system descriptors).
4483 *
4484 * This function ASSUMES that iemMemFetchSelDesc has be called previously and
4485 * will therefore skip the limit checks.
4486 *
4487 * @returns Strict VBox status code.
4488 * @param pIemCpu The IEM per CPU.
4489 * @param uSel The selector.
4490 */
4491static VBOXSTRICTRC iemMemMarkSelDescAccessed(PIEMCPU pIemCpu, uint16_t uSel)
4492{
4493 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
4494
4495 /*
4496 * Get the selector table base and calculate the entry address.
4497 */
4498 RTGCPTR GCPtr = uSel & X86_SEL_LDT
4499 ? pCtx->ldtrHid.u64Base
4500 : pCtx->gdtr.pGdt;
4501 GCPtr += uSel & X86_SEL_MASK;
4502
4503 /*
4504 * ASMAtomicBitSet will assert if the address is misaligned, so do some
4505 * ugly stuff to avoid this. This will make sure it's an atomic access
4506 * as well more or less remove any question about 8-bit or 32-bit accesss.
4507 */
4508 VBOXSTRICTRC rcStrict;
4509 uint32_t volatile *pu32;
4510 if ((GCPtr & 3) == 0)
4511 {
4512 /* The normal case, map the 32-bit bits around the accessed bit (40). */
4513 GCPtr += 2 + 2;
4514 rcStrict = iemMemMap(pIemCpu, (void **)&pu32, 4, UINT8_MAX, GCPtr, IEM_ACCESS_DATA_RW);
4515 if (rcStrict != VINF_SUCCESS)
4516 return rcStrict;
4517 ASMAtomicBitSet(pu32, 8); /* X86_SEL_TYPE_ACCESSED is 1, but it is preceeded by u8BaseHigh1. */
4518 }
4519 else
4520 {
4521 /* The misaligned GDT/LDT case, map the whole thing. */
4522 rcStrict = iemMemMap(pIemCpu, (void **)&pu32, 8, UINT8_MAX, GCPtr, IEM_ACCESS_DATA_RW);
4523 if (rcStrict != VINF_SUCCESS)
4524 return rcStrict;
4525 switch ((uintptr_t)pu32 & 3)
4526 {
4527 case 0: ASMAtomicBitSet(pu32, 40 + 0 - 0); break;
4528 case 1: ASMAtomicBitSet((uint8_t volatile *)pu32 + 3, 40 + 0 - 24); break;
4529 case 2: ASMAtomicBitSet((uint8_t volatile *)pu32 + 2, 40 + 0 - 16); break;
4530 case 3: ASMAtomicBitSet((uint8_t volatile *)pu32 + 1, 40 + 0 - 8); break;
4531 }
4532 }
4533
4534 return iemMemCommitAndUnmap(pIemCpu, (void *)pu32, IEM_ACCESS_DATA_RW);
4535}
4536
4537/** @} */
4538
4539
4540/*
4541 * Include the C/C++ implementation of instruction.
4542 */
4543#include "IEMAllCImpl.cpp.h"
4544
4545
4546
4547/** @name "Microcode" macros.
4548 *
4549 * The idea is that we should be able to use the same code to interpret
4550 * instructions as well as recompiler instructions. Thus this obfuscation.
4551 *
4552 * @{
4553 */
4554#define IEM_MC_BEGIN(a_cArgs, a_cLocals) {
4555#define IEM_MC_END() }
4556#define IEM_MC_PAUSE() do {} while (0)
4557#define IEM_MC_CONTINUE() do {} while (0)
4558
4559/** Internal macro. */
4560#define IEM_MC_RETURN_ON_FAILURE(a_Expr) \
4561 do \
4562 { \
4563 VBOXSTRICTRC rcStrict2 = a_Expr; \
4564 if (rcStrict2 != VINF_SUCCESS) \
4565 return rcStrict2; \
4566 } while (0)
4567
4568#define IEM_MC_ADVANCE_RIP() iemRegUpdateRip(pIemCpu)
4569#define IEM_MC_REL_JMP_S8(a_i8) IEM_MC_RETURN_ON_FAILURE(iemRegRipRelativeJumpS8(pIemCpu, a_i8))
4570#define IEM_MC_REL_JMP_S16(a_i16) IEM_MC_RETURN_ON_FAILURE(iemRegRipRelativeJumpS16(pIemCpu, a_i16))
4571#define IEM_MC_REL_JMP_S32(a_i32) IEM_MC_RETURN_ON_FAILURE(iemRegRipRelativeJumpS32(pIemCpu, a_i32))
4572#define IEM_MC_SET_RIP_U16(a_u16NewIP) IEM_MC_RETURN_ON_FAILURE(iemRegRipJump((pIemCpu), (a_u16NewIP)))
4573#define IEM_MC_SET_RIP_U32(a_u32NewIP) IEM_MC_RETURN_ON_FAILURE(iemRegRipJump((pIemCpu), (a_u32NewIP)))
4574#define IEM_MC_SET_RIP_U64(a_u64NewIP) IEM_MC_RETURN_ON_FAILURE(iemRegRipJump((pIemCpu), (a_u64NewIP)))
4575
4576#define IEM_MC_RAISE_DIVIDE_ERROR() return iemRaiseDivideError(pIemCpu)
4577#define IEM_MC_MAYBE_RAISE_DEVICE_NOT_AVAILABLE() \
4578 do { \
4579 if ((pIemCpu)->CTX_SUFF(pCtx)->cr0 & (X86_CR0_EM | X86_CR0_TS)) \
4580 return iemRaiseDeviceNotAvailable(pIemCpu); \
4581 } while (0)
4582#define IEM_MC_MAYBE_RAISE_FPU_XCPT() \
4583 do { \
4584 if (iemFRegFetchFsw(pIemCpu) & X86_FSW_ES) \
4585 return iemRaiseMathFault(pIemCpu); \
4586 } while (0)
4587#define IEM_MC_RAISE_GP0_IF_CPL_NOT_ZERO() \
4588 do { \
4589 if (pIemCpu->uCpl != 0) \
4590 return iemRaiseGeneralProtectionFault0(pIemCpu); \
4591 } while (0)
4592
4593
4594#define IEM_MC_LOCAL(a_Type, a_Name) a_Type a_Name
4595#define IEM_MC_LOCAL_CONST(a_Type, a_Name, a_Value) a_Type const a_Name = (a_Value)
4596#define IEM_MC_REF_LOCAL(a_pRefArg, a_Local) (a_pRefArg) = &(a_Local)
4597#define IEM_MC_ARG(a_Type, a_Name, a_iArg) a_Type a_Name
4598#define IEM_MC_ARG_CONST(a_Type, a_Name, a_Value, a_iArg) a_Type const a_Name = (a_Value)
4599#define IEM_MC_ARG_LOCAL_EFLAGS(a_pName, a_Name, a_iArg) \
4600 uint32_t a_Name; \
4601 uint32_t *a_pName = &a_Name
4602#define IEM_MC_COMMIT_EFLAGS(a_EFlags) \
4603 do { (pIemCpu)->CTX_SUFF(pCtx)->eflags.u = (a_EFlags); Assert((pIemCpu)->CTX_SUFF(pCtx)->eflags.u & X86_EFL_1); } while (0)
4604
4605#define IEM_MC_ASSIGN(a_VarOrArg, a_CVariableOrConst) (a_VarOrArg) = (a_CVariableOrConst)
4606#define IEM_MC_ASSIGN_TO_SMALLER IEM_MC_ASSIGN
4607
4608#define IEM_MC_FETCH_GREG_U8(a_u8Dst, a_iGReg) (a_u8Dst) = iemGRegFetchU8(pIemCpu, (a_iGReg))
4609#define IEM_MC_FETCH_GREG_U8_ZX_U16(a_u16Dst, a_iGReg) (a_u16Dst) = iemGRegFetchU8(pIemCpu, (a_iGReg))
4610#define IEM_MC_FETCH_GREG_U8_ZX_U32(a_u32Dst, a_iGReg) (a_u32Dst) = iemGRegFetchU8(pIemCpu, (a_iGReg))
4611#define IEM_MC_FETCH_GREG_U8_ZX_U64(a_u64Dst, a_iGReg) (a_u64Dst) = iemGRegFetchU8(pIemCpu, (a_iGReg))
4612#define IEM_MC_FETCH_GREG_U8_SX_U16(a_u16Dst, a_iGReg) (a_u16Dst) = (int8_t)iemGRegFetchU8(pIemCpu, (a_iGReg))
4613#define IEM_MC_FETCH_GREG_U8_SX_U32(a_u32Dst, a_iGReg) (a_u32Dst) = (int8_t)iemGRegFetchU8(pIemCpu, (a_iGReg))
4614#define IEM_MC_FETCH_GREG_U8_SX_U64(a_u64Dst, a_iGReg) (a_u64Dst) = (int8_t)iemGRegFetchU8(pIemCpu, (a_iGReg))
4615#define IEM_MC_FETCH_GREG_U16(a_u16Dst, a_iGReg) (a_u16Dst) = iemGRegFetchU16(pIemCpu, (a_iGReg))
4616#define IEM_MC_FETCH_GREG_U16_ZX_U32(a_u32Dst, a_iGReg) (a_u32Dst) = iemGRegFetchU16(pIemCpu, (a_iGReg))
4617#define IEM_MC_FETCH_GREG_U16_ZX_U64(a_u64Dst, a_iGReg) (a_u64Dst) = iemGRegFetchU16(pIemCpu, (a_iGReg))
4618#define IEM_MC_FETCH_GREG_U16_SX_U32(a_u32Dst, a_iGReg) (a_u32Dst) = (int16_t)iemGRegFetchU16(pIemCpu, (a_iGReg))
4619#define IEM_MC_FETCH_GREG_U16_SX_U64(a_u64Dst, a_iGReg) (a_u64Dst) = (int16_t)iemGRegFetchU16(pIemCpu, (a_iGReg))
4620#define IEM_MC_FETCH_GREG_U32(a_u32Dst, a_iGReg) (a_u32Dst) = iemGRegFetchU32(pIemCpu, (a_iGReg))
4621#define IEM_MC_FETCH_GREG_U32_ZX_U64(a_u64Dst, a_iGReg) (a_u64Dst) = iemGRegFetchU32(pIemCpu, (a_iGReg))
4622#define IEM_MC_FETCH_GREG_U32_SX_U64(a_u64Dst, a_iGReg) (a_u64Dst) = (int32_t)iemGRegFetchU32(pIemCpu, (a_iGReg))
4623#define IEM_MC_FETCH_GREG_U64(a_u64Dst, a_iGReg) (a_u64Dst) = iemGRegFetchU64(pIemCpu, (a_iGReg))
4624#define IEM_MC_FETCH_GREG_U64_ZX_U64 IEM_MC_FETCH_GREG_U64
4625#define IEM_MC_FETCH_SREG_U16(a_u16Dst, a_iSReg) (a_u16Dst) = iemSRegFetchU16(pIemCpu, (a_iSReg))
4626#define IEM_MC_FETCH_SREG_ZX_U32(a_u32Dst, a_iSReg) (a_u32Dst) = iemSRegFetchU16(pIemCpu, (a_iSReg))
4627#define IEM_MC_FETCH_SREG_ZX_U64(a_u64Dst, a_iSReg) (a_u64Dst) = iemSRegFetchU16(pIemCpu, (a_iSReg))
4628#define IEM_MC_FETCH_CR0_U16(a_u16Dst) (a_u16Dst) = (uint16_t)(pIemCpu)->CTX_SUFF(pCtx)->cr0
4629#define IEM_MC_FETCH_CR0_U32(a_u32Dst) (a_u32Dst) = (uint32_t)(pIemCpu)->CTX_SUFF(pCtx)->cr0
4630#define IEM_MC_FETCH_CR0_U64(a_u64Dst) (a_u64Dst) = (pIemCpu)->CTX_SUFF(pCtx)->cr0
4631#define IEM_MC_FETCH_EFLAGS(a_EFlags) (a_EFlags) = (pIemCpu)->CTX_SUFF(pCtx)->eflags.u
4632#define IEM_MC_FETCH_FSW(a_u16Fsw) (a_u16Fsw) = iemFRegFetchFsw(pIemCpu)
4633
4634#define IEM_MC_STORE_GREG_U8(a_iGReg, a_u8Value) *iemGRegRefU8(pIemCpu, (a_iGReg)) = (a_u8Value)
4635#define IEM_MC_STORE_GREG_U16(a_iGReg, a_u16Value) *(uint16_t *)iemGRegRef(pIemCpu, (a_iGReg)) = (a_u16Value)
4636#define IEM_MC_STORE_GREG_U32(a_iGReg, a_u32Value) *(uint64_t *)iemGRegRef(pIemCpu, (a_iGReg)) = (uint32_t)(a_u32Value) /* clear high bits. */
4637#define IEM_MC_STORE_GREG_U64(a_iGReg, a_u64Value) *(uint64_t *)iemGRegRef(pIemCpu, (a_iGReg)) = (a_u64Value)
4638#define IEM_MC_STORE_GREG_U8_CONST IEM_MC_STORE_GREG_U8
4639#define IEM_MC_STORE_GREG_U16_CONST IEM_MC_STORE_GREG_U16
4640#define IEM_MC_STORE_GREG_U32_CONST IEM_MC_STORE_GREG_U32
4641#define IEM_MC_STORE_GREG_U64_CONST IEM_MC_STORE_GREG_U64
4642#define IEM_MC_CLEAR_HIGH_GREG_U64(a_iGReg) *(uint64_t *)iemGRegRef(pIemCpu, (a_iGReg)) &= UINT32_MAX
4643
4644#define IEM_MC_REF_GREG_U8(a_pu8Dst, a_iGReg) (a_pu8Dst) = iemGRegRefU8(pIemCpu, (a_iGReg))
4645#define IEM_MC_REF_GREG_U16(a_pu16Dst, a_iGReg) (a_pu16Dst) = (uint16_t *)iemGRegRef(pIemCpu, (a_iGReg))
4646/** @todo User of IEM_MC_REF_GREG_U32 needs to clear the high bits on
4647 * commit. */
4648#define IEM_MC_REF_GREG_U32(a_pu32Dst, a_iGReg) (a_pu32Dst) = (uint32_t *)iemGRegRef(pIemCpu, (a_iGReg))
4649#define IEM_MC_REF_GREG_U64(a_pu64Dst, a_iGReg) (a_pu64Dst) = (uint64_t *)iemGRegRef(pIemCpu, (a_iGReg))
4650#define IEM_MC_REF_EFLAGS(a_pEFlags) (a_pEFlags) = &(pIemCpu)->CTX_SUFF(pCtx)->eflags.u
4651
4652#define IEM_MC_ADD_GREG_U8(a_iGReg, a_u8Value) *(uint8_t *)iemGRegRef(pIemCpu, (a_iGReg)) += (a_u8Value)
4653#define IEM_MC_ADD_GREG_U16(a_iGReg, a_u16Value) *(uint16_t *)iemGRegRef(pIemCpu, (a_iGReg)) += (a_u16Value)
4654#define IEM_MC_ADD_GREG_U32(a_iGReg, a_u32Value) \
4655 do { \
4656 uint32_t *pu32Reg = (uint32_t *)iemGRegRef(pIemCpu, (a_iGReg)); \
4657 *pu32Reg += (a_u32Value); \
4658 pu32Reg[1] = 0; /* implicitly clear the high bit. */ \
4659 } while (0)
4660#define IEM_MC_ADD_GREG_U64(a_iGReg, a_u64Value) *(uint64_t *)iemGRegRef(pIemCpu, (a_iGReg)) += (a_u64Value)
4661
4662#define IEM_MC_SUB_GREG_U8(a_iGReg, a_u8Value) *(uint8_t *)iemGRegRef(pIemCpu, (a_iGReg)) -= (a_u8Value)
4663#define IEM_MC_SUB_GREG_U16(a_iGReg, a_u16Value) *(uint16_t *)iemGRegRef(pIemCpu, (a_iGReg)) -= (a_u16Value)
4664#define IEM_MC_SUB_GREG_U32(a_iGReg, a_u32Value) \
4665 do { \
4666 uint32_t *pu32Reg = (uint32_t *)iemGRegRef(pIemCpu, (a_iGReg)); \
4667 *pu32Reg -= (a_u32Value); \
4668 pu32Reg[1] = 0; /* implicitly clear the high bit. */ \
4669 } while (0)
4670#define IEM_MC_SUB_GREG_U64(a_iGReg, a_u64Value) *(uint64_t *)iemGRegRef(pIemCpu, (a_iGReg)) -= (a_u64Value)
4671
4672#define IEM_MC_ADD_GREG_U8_TO_LOCAL(a_u8Value, a_iGReg) do { (a_u8Value) += iemGRegFetchU8( pIemCpu, (a_iGReg)); } while (0)
4673#define IEM_MC_ADD_GREG_U16_TO_LOCAL(a_u16Value, a_iGReg) do { (a_u16Value) += iemGRegFetchU16(pIemCpu, (a_iGReg)); } while (0)
4674#define IEM_MC_ADD_GREG_U32_TO_LOCAL(a_u32Value, a_iGReg) do { (a_u32Value) += iemGRegFetchU32(pIemCpu, (a_iGReg)); } while (0)
4675#define IEM_MC_ADD_GREG_U64_TO_LOCAL(a_u64Value, a_iGReg) do { (a_u64Value) += iemGRegFetchU64(pIemCpu, (a_iGReg)); } while (0)
4676#define IEM_MC_ADD_LOCAL_S16_TO_EFF_ADDR(a_EffAddr, a_i16) do { (a_EffAddr) += (a_i16); } while (0)
4677#define IEM_MC_ADD_LOCAL_S32_TO_EFF_ADDR(a_EffAddr, a_i32) do { (a_EffAddr) += (a_i32); } while (0)
4678#define IEM_MC_ADD_LOCAL_S64_TO_EFF_ADDR(a_EffAddr, a_i64) do { (a_EffAddr) += (a_i64); } while (0)
4679
4680#define IEM_MC_AND_LOCAL_U16(a_u16Local, a_u16Mask) do { (a_u16Local) &= (a_u16Mask); } while (0)
4681#define IEM_MC_AND_LOCAL_U32(a_u32Local, a_u32Mask) do { (a_u32Local) &= (a_u32Mask); } while (0)
4682#define IEM_MC_AND_LOCAL_U64(a_u64Local, a_u64Mask) do { (a_u64Local) &= (a_u64Mask); } while (0)
4683
4684#define IEM_MC_AND_ARG_U16(a_u16Arg, a_u16Mask) do { (a_u16Arg) &= (a_u16Mask); } while (0)
4685#define IEM_MC_AND_ARG_U32(a_u32Arg, a_u32Mask) do { (a_u32Arg) &= (a_u32Mask); } while (0)
4686#define IEM_MC_AND_ARG_U64(a_u64Arg, a_u64Mask) do { (a_u64Arg) &= (a_u64Mask); } while (0)
4687
4688#define IEM_MC_SAR_LOCAL_S16(a_i16Local, a_cShift) do { (a_i16Local) >>= (a_cShift); } while (0)
4689#define IEM_MC_SAR_LOCAL_S32(a_i32Local, a_cShift) do { (a_i32Local) >>= (a_cShift); } while (0)
4690#define IEM_MC_SAR_LOCAL_S64(a_i64Local, a_cShift) do { (a_i64Local) >>= (a_cShift); } while (0)
4691
4692#define IEM_MC_SHL_LOCAL_S16(a_i16Local, a_cShift) do { (a_i16Local) <<= (a_cShift); } while (0)
4693#define IEM_MC_SHL_LOCAL_S32(a_i32Local, a_cShift) do { (a_i32Local) <<= (a_cShift); } while (0)
4694#define IEM_MC_SHL_LOCAL_S64(a_i64Local, a_cShift) do { (a_i64Local) <<= (a_cShift); } while (0)
4695
4696
4697#define IEM_MC_SET_EFL_BIT(a_fBit) do { (pIemCpu)->CTX_SUFF(pCtx)->eflags.u |= (a_fBit); } while (0)
4698#define IEM_MC_CLEAR_EFL_BIT(a_fBit) do { (pIemCpu)->CTX_SUFF(pCtx)->eflags.u &= ~(a_fBit); } while (0)
4699
4700
4701
4702#define IEM_MC_FETCH_MEM_U8(a_u8Dst, a_iSeg, a_GCPtrMem) \
4703 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU8(pIemCpu, &(a_u8Dst), (a_iSeg), (a_GCPtrMem)))
4704#define IEM_MC_FETCH_MEM16_U8(a_u8Dst, a_iSeg, a_GCPtrMem16) \
4705 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU8(pIemCpu, &(a_u8Dst), (a_iSeg), (a_GCPtrMem16)))
4706#define IEM_MC_FETCH_MEM32_U8(a_u8Dst, a_iSeg, a_GCPtrMem32) \
4707 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU8(pIemCpu, &(a_u8Dst), (a_iSeg), (a_GCPtrMem32)))
4708
4709#define IEM_MC_FETCH_MEM_U16(a_u16Dst, a_iSeg, a_GCPtrMem) \
4710 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU16(pIemCpu, &(a_u16Dst), (a_iSeg), (a_GCPtrMem)))
4711#define IEM_MC_FETCH_MEM_U16_DISP(a_u16Dst, a_iSeg, a_GCPtrMem, a_offDisp) \
4712 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU16(pIemCpu, &(a_u16Dst), (a_iSeg), (a_GCPtrMem) + (a_offDisp)))
4713
4714#define IEM_MC_FETCH_MEM_U32(a_u32Dst, a_iSeg, a_GCPtrMem) \
4715 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU32(pIemCpu, &(a_u32Dst), (a_iSeg), (a_GCPtrMem)))
4716#define IEM_MC_FETCH_MEM_U32_DISP(a_u32Dst, a_iSeg, a_GCPtrMem, a_offDisp) \
4717 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU32(pIemCpu, &(a_u32Dst), (a_iSeg), (a_GCPtrMem) + (a_offDisp)))
4718
4719#define IEM_MC_FETCH_MEM_S32_SX_U64(a_u64Dst, a_iSeg, a_GCPtrMem) \
4720 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataS32SxU64(pIemCpu, &(a_u64Dst), (a_iSeg), (a_GCPtrMem)))
4721
4722#define IEM_MC_FETCH_MEM_U64(a_u64Dst, a_iSeg, a_GCPtrMem) \
4723 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU64(pIemCpu, &(a_u64Dst), (a_iSeg), (a_GCPtrMem)))
4724#define IEM_MC_FETCH_MEM_U64_DISP(a_u64Dst, a_iSeg, a_GCPtrMem, a_offDisp) \
4725 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU64(pIemCpu, &(a_u64Dst), (a_iSeg), (a_GCPtrMem) + (a_offDisp)))
4726
4727#define IEM_MC_FETCH_MEM_U8_ZX_U16(a_u16Dst, a_iSeg, a_GCPtrMem) \
4728 do { \
4729 uint8_t u8Tmp; \
4730 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU8(pIemCpu, &u8Tmp, (a_iSeg), (a_GCPtrMem))); \
4731 (a_u16Dst) = u8Tmp; \
4732 } while (0)
4733#define IEM_MC_FETCH_MEM_U8_ZX_U32(a_u32Dst, a_iSeg, a_GCPtrMem) \
4734 do { \
4735 uint8_t u8Tmp; \
4736 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU8(pIemCpu, &u8Tmp, (a_iSeg), (a_GCPtrMem))); \
4737 (a_u32Dst) = u8Tmp; \
4738 } while (0)
4739#define IEM_MC_FETCH_MEM_U8_ZX_U64(a_u64Dst, a_iSeg, a_GCPtrMem) \
4740 do { \
4741 uint8_t u8Tmp; \
4742 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU8(pIemCpu, &u8Tmp, (a_iSeg), (a_GCPtrMem))); \
4743 (a_u64Dst) = u8Tmp; \
4744 } while (0)
4745#define IEM_MC_FETCH_MEM_U16_ZX_U32(a_u32Dst, a_iSeg, a_GCPtrMem) \
4746 do { \
4747 uint16_t u16Tmp; \
4748 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU16(pIemCpu, &u16Tmp, (a_iSeg), (a_GCPtrMem))); \
4749 (a_u32Dst) = u16Tmp; \
4750 } while (0)
4751#define IEM_MC_FETCH_MEM_U16_ZX_U64(a_u64Dst, a_iSeg, a_GCPtrMem) \
4752 do { \
4753 uint16_t u16Tmp; \
4754 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU16(pIemCpu, &u16Tmp, (a_iSeg), (a_GCPtrMem))); \
4755 (a_u64Dst) = u16Tmp; \
4756 } while (0)
4757#define IEM_MC_FETCH_MEM_U32_ZX_U64(a_u64Dst, a_iSeg, a_GCPtrMem) \
4758 do { \
4759 uint32_t u32Tmp; \
4760 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU32(pIemCpu, &u32Tmp, (a_iSeg), (a_GCPtrMem))); \
4761 (a_u64Dst) = u32Tmp; \
4762 } while (0)
4763
4764#define IEM_MC_FETCH_MEM_U8_SX_U16(a_u16Dst, a_iSeg, a_GCPtrMem) \
4765 do { \
4766 uint8_t u8Tmp; \
4767 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU8(pIemCpu, &u8Tmp, (a_iSeg), (a_GCPtrMem))); \
4768 (a_u16Dst) = (int8_t)u8Tmp; \
4769 } while (0)
4770#define IEM_MC_FETCH_MEM_U8_SX_U32(a_u32Dst, a_iSeg, a_GCPtrMem) \
4771 do { \
4772 uint8_t u8Tmp; \
4773 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU8(pIemCpu, &u8Tmp, (a_iSeg), (a_GCPtrMem))); \
4774 (a_u32Dst) = (int8_t)u8Tmp; \
4775 } while (0)
4776#define IEM_MC_FETCH_MEM_U8_SX_U64(a_u64Dst, a_iSeg, a_GCPtrMem) \
4777 do { \
4778 uint8_t u8Tmp; \
4779 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU8(pIemCpu, &u8Tmp, (a_iSeg), (a_GCPtrMem))); \
4780 (a_u64Dst) = (int8_t)u8Tmp; \
4781 } while (0)
4782#define IEM_MC_FETCH_MEM_U16_SX_U32(a_u32Dst, a_iSeg, a_GCPtrMem) \
4783 do { \
4784 uint16_t u16Tmp; \
4785 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU16(pIemCpu, &u16Tmp, (a_iSeg), (a_GCPtrMem))); \
4786 (a_u32Dst) = (int16_t)u16Tmp; \
4787 } while (0)
4788#define IEM_MC_FETCH_MEM_U16_SX_U64(a_u64Dst, a_iSeg, a_GCPtrMem) \
4789 do { \
4790 uint16_t u16Tmp; \
4791 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU16(pIemCpu, &u16Tmp, (a_iSeg), (a_GCPtrMem))); \
4792 (a_u64Dst) = (int16_t)u16Tmp; \
4793 } while (0)
4794#define IEM_MC_FETCH_MEM_U32_SX_U64(a_u64Dst, a_iSeg, a_GCPtrMem) \
4795 do { \
4796 uint32_t u32Tmp; \
4797 IEM_MC_RETURN_ON_FAILURE(iemMemFetchDataU32(pIemCpu, &u32Tmp, (a_iSeg), (a_GCPtrMem))); \
4798 (a_u64Dst) = (int32_t)u32Tmp; \
4799 } while (0)
4800
4801#define IEM_MC_STORE_MEM_U8(a_iSeg, a_GCPtrMem, a_u8Value) \
4802 IEM_MC_RETURN_ON_FAILURE(iemMemStoreDataU8(pIemCpu, (a_iSeg), (a_GCPtrMem), (a_u8Value)))
4803#define IEM_MC_STORE_MEM_U16(a_iSeg, a_GCPtrMem, a_u16Value) \
4804 IEM_MC_RETURN_ON_FAILURE(iemMemStoreDataU16(pIemCpu, (a_iSeg), (a_GCPtrMem), (a_u16Value)))
4805#define IEM_MC_STORE_MEM_U32(a_iSeg, a_GCPtrMem, a_u32Value) \
4806 IEM_MC_RETURN_ON_FAILURE(iemMemStoreDataU32(pIemCpu, (a_iSeg), (a_GCPtrMem), (a_u32Value)))
4807#define IEM_MC_STORE_MEM_U64(a_iSeg, a_GCPtrMem, a_u64Value) \
4808 IEM_MC_RETURN_ON_FAILURE(iemMemStoreDataU64(pIemCpu, (a_iSeg), (a_GCPtrMem), (a_u64Value)))
4809
4810#define IEM_MC_STORE_MEM_U8_CONST(a_iSeg, a_GCPtrMem, a_u8C) \
4811 IEM_MC_RETURN_ON_FAILURE(iemMemStoreDataU8(pIemCpu, (a_iSeg), (a_GCPtrMem), (a_u8C)))
4812
4813#define IEM_MC_PUSH_U16(a_u16Value) \
4814 IEM_MC_RETURN_ON_FAILURE(iemMemStackPushU16(pIemCpu, (a_u16Value)))
4815#define IEM_MC_PUSH_U32(a_u32Value) \
4816 IEM_MC_RETURN_ON_FAILURE(iemMemStackPushU32(pIemCpu, (a_u32Value)))
4817#define IEM_MC_PUSH_U64(a_u64Value) \
4818 IEM_MC_RETURN_ON_FAILURE(iemMemStackPushU64(pIemCpu, (a_u64Value)))
4819
4820#define IEM_MC_POP_U16(a_pu16Value) \
4821 IEM_MC_RETURN_ON_FAILURE(iemMemStackPopU16(pIemCpu, (a_pu16Value)))
4822#define IEM_MC_POP_U32(a_pu32Value) \
4823 IEM_MC_RETURN_ON_FAILURE(iemMemStackPopU32(pIemCpu, (a_pu32Value)))
4824#define IEM_MC_POP_U64(a_pu64Value) \
4825 IEM_MC_RETURN_ON_FAILURE(iemMemStackPopU64(pIemCpu, (a_pu64Value)))
4826
4827/** Maps guest memory for direct or bounce buffered access.
4828 * The purpose is to pass it to an operand implementation, thus the a_iArg.
4829 * @remarks May return.
4830 */
4831#define IEM_MC_MEM_MAP(a_pMem, a_fAccess, a_iSeg, a_GCPtrMem, a_iArg) \
4832 IEM_MC_RETURN_ON_FAILURE(iemMemMap(pIemCpu, (void **)&(a_pMem), sizeof(*(a_pMem)), (a_iSeg), (a_GCPtrMem), (a_fAccess)))
4833
4834/** Maps guest memory for direct or bounce buffered access.
4835 * The purpose is to pass it to an operand implementation, thus the a_iArg.
4836 * @remarks May return.
4837 */
4838#define IEM_MC_MEM_MAP_EX(a_pvMem, a_fAccess, a_cbMem, a_iSeg, a_GCPtrMem, a_iArg) \
4839 IEM_MC_RETURN_ON_FAILURE(iemMemMap(pIemCpu, (void **)&(a_pvMem), (a_cbMem), (a_iSeg), (a_GCPtrMem), (a_fAccess)))
4840
4841/** Commits the memory and unmaps the guest memory.
4842 * @remarks May return.
4843 */
4844#define IEM_MC_MEM_COMMIT_AND_UNMAP(a_pvMem, a_fAccess) \
4845 IEM_MC_RETURN_ON_FAILURE(iemMemCommitAndUnmap(pIemCpu, (a_pvMem), (a_fAccess)))
4846
4847/** Calculate efficient address from R/M. */
4848#define IEM_MC_CALC_RM_EFF_ADDR(a_GCPtrEff, bRm) \
4849 IEM_MC_RETURN_ON_FAILURE(iemOpHlpCalcRmEffAddr(pIemCpu, (bRm), &(a_GCPtrEff)))
4850
4851#define IEM_MC_CALL_VOID_AIMPL_2(a_pfn, a0, a1) (a_pfn)((a0), (a1))
4852#define IEM_MC_CALL_VOID_AIMPL_3(a_pfn, a0, a1, a2) (a_pfn)((a0), (a1), (a2))
4853#define IEM_MC_CALL_VOID_AIMPL_4(a_pfn, a0, a1, a2, a3) (a_pfn)((a0), (a1), (a2), (a3))
4854#define IEM_MC_CALL_AIMPL_4(a_rc, a_pfn, a0, a1, a2, a3) (a_rc) = (a_pfn)((a0), (a1), (a2), (a3))
4855
4856/**
4857 * Defers the rest of the instruction emulation to a C implementation routine
4858 * and returns, only taking the standard parameters.
4859 *
4860 * @param a_pfnCImpl The pointer to the C routine.
4861 * @sa IEM_DECL_IMPL_C_TYPE_0 and IEM_CIMPL_DEF_0.
4862 */
4863#define IEM_MC_CALL_CIMPL_0(a_pfnCImpl) return (a_pfnCImpl)(pIemCpu, pIemCpu->offOpcode)
4864
4865/**
4866 * Defers the rest of instruction emulation to a C implementation routine and
4867 * returns, taking one argument in addition to the standard ones.
4868 *
4869 * @param a_pfnCImpl The pointer to the C routine.
4870 * @param a0 The argument.
4871 */
4872#define IEM_MC_CALL_CIMPL_1(a_pfnCImpl, a0) return (a_pfnCImpl)(pIemCpu, pIemCpu->offOpcode, a0)
4873
4874/**
4875 * Defers the rest of the instruction emulation to a C implementation routine
4876 * and returns, taking two arguments in addition to the standard ones.
4877 *
4878 * @param a_pfnCImpl The pointer to the C routine.
4879 * @param a0 The first extra argument.
4880 * @param a1 The second extra argument.
4881 */
4882#define IEM_MC_CALL_CIMPL_2(a_pfnCImpl, a0, a1) return (a_pfnCImpl)(pIemCpu, pIemCpu->offOpcode, a0, a1)
4883
4884/**
4885 * Defers the rest of the instruction emulation to a C implementation routine
4886 * and returns, taking two arguments in addition to the standard ones.
4887 *
4888 * @param a_pfnCImpl The pointer to the C routine.
4889 * @param a0 The first extra argument.
4890 * @param a1 The second extra argument.
4891 * @param a2 The third extra argument.
4892 */
4893#define IEM_MC_CALL_CIMPL_3(a_pfnCImpl, a0, a1, a2) return (a_pfnCImpl)(pIemCpu, pIemCpu->offOpcode, a0, a1, a2)
4894
4895/**
4896 * Defers the rest of the instruction emulation to a C implementation routine
4897 * and returns, taking two arguments in addition to the standard ones.
4898 *
4899 * @param a_pfnCImpl The pointer to the C routine.
4900 * @param a0 The first extra argument.
4901 * @param a1 The second extra argument.
4902 * @param a2 The third extra argument.
4903 * @param a3 The fourth extra argument.
4904 * @param a4 The fifth extra argument.
4905 */
4906#define IEM_MC_CALL_CIMPL_5(a_pfnCImpl, a0, a1, a2, a3, a4) return (a_pfnCImpl)(pIemCpu, pIemCpu->offOpcode, a0, a1, a2, a3, a4)
4907
4908/**
4909 * Defers the entire instruction emulation to a C implementation routine and
4910 * returns, only taking the standard parameters.
4911 *
4912 * This shall be used without any IEM_MC_BEGIN or IEM_END macro surrounding it.
4913 *
4914 * @param a_pfnCImpl The pointer to the C routine.
4915 * @sa IEM_DECL_IMPL_C_TYPE_0 and IEM_CIMPL_DEF_0.
4916 */
4917#define IEM_MC_DEFER_TO_CIMPL_0(a_pfnCImpl) (a_pfnCImpl)(pIemCpu, pIemCpu->offOpcode)
4918
4919/**
4920 * Defers the entire instruction emulation to a C implementation routine and
4921 * returns, taking one argument in addition to the standard ones.
4922 *
4923 * This shall be used without any IEM_MC_BEGIN or IEM_END macro surrounding it.
4924 *
4925 * @param a_pfnCImpl The pointer to the C routine.
4926 * @param a0 The argument.
4927 */
4928#define IEM_MC_DEFER_TO_CIMPL_1(a_pfnCImpl, a0) (a_pfnCImpl)(pIemCpu, pIemCpu->offOpcode, a0)
4929
4930/**
4931 * Defers the entire instruction emulation to a C implementation routine and
4932 * returns, taking two arguments in addition to the standard ones.
4933 *
4934 * This shall be used without any IEM_MC_BEGIN or IEM_END macro surrounding it.
4935 *
4936 * @param a_pfnCImpl The pointer to the C routine.
4937 * @param a0 The first extra argument.
4938 * @param a1 The second extra argument.
4939 */
4940#define IEM_MC_DEFER_TO_CIMPL_2(a_pfnCImpl, a0, a1) (a_pfnCImpl)(pIemCpu, pIemCpu->offOpcode, a0, a1)
4941
4942/**
4943 * Defers the entire instruction emulation to a C implementation routine and
4944 * returns, taking three arguments in addition to the standard ones.
4945 *
4946 * This shall be used without any IEM_MC_BEGIN or IEM_END macro surrounding it.
4947 *
4948 * @param a_pfnCImpl The pointer to the C routine.
4949 * @param a0 The first extra argument.
4950 * @param a1 The second extra argument.
4951 * @param a2 The third extra argument.
4952 */
4953#define IEM_MC_DEFER_TO_CIMPL_3(a_pfnCImpl, a0, a1, a2) (a_pfnCImpl)(pIemCpu, pIemCpu->offOpcode, a0, a1, a2)
4954
4955#define IEM_MC_IF_EFL_BIT_SET(a_fBit) if (pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBit)) {
4956#define IEM_MC_IF_EFL_BIT_NOT_SET(a_fBit) if (!(pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBit))) {
4957#define IEM_MC_IF_EFL_ANY_BITS_SET(a_fBits) if (pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBits)) {
4958#define IEM_MC_IF_EFL_NO_BITS_SET(a_fBits) if (!(pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBits))) {
4959#define IEM_MC_IF_EFL_BITS_NE(a_fBit1, a_fBit2) \
4960 if ( !!(pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBit1)) \
4961 != !!(pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBit2)) ) {
4962#define IEM_MC_IF_EFL_BITS_EQ(a_fBit1, a_fBit2) \
4963 if ( !!(pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBit1)) \
4964 == !!(pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBit2)) ) {
4965#define IEM_MC_IF_EFL_BIT_SET_OR_BITS_NE(a_fBit, a_fBit1, a_fBit2) \
4966 if ( (pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBit)) \
4967 || !!(pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBit1)) \
4968 != !!(pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBit2)) ) {
4969#define IEM_MC_IF_EFL_BIT_NOT_SET_AND_BITS_EQ(a_fBit, a_fBit1, a_fBit2) \
4970 if ( !(pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBit)) \
4971 && !!(pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBit1)) \
4972 == !!(pIemCpu->CTX_SUFF(pCtx)->eflags.u & (a_fBit2)) ) {
4973#define IEM_MC_IF_CX_IS_NZ() if (pIemCpu->CTX_SUFF(pCtx)->cx != 0) {
4974#define IEM_MC_IF_ECX_IS_NZ() if (pIemCpu->CTX_SUFF(pCtx)->ecx != 0) {
4975#define IEM_MC_IF_RCX_IS_NZ() if (pIemCpu->CTX_SUFF(pCtx)->rcx != 0) {
4976#define IEM_MC_IF_CX_IS_NZ_AND_EFL_BIT_SET(a_fBit) \
4977 if ( pIemCpu->CTX_SUFF(pCtx)->cx != 0 \
4978 && (pIemCpu->CTX_SUFF(pCtx)->eflags.u & a_fBit)) {
4979#define IEM_MC_IF_ECX_IS_NZ_AND_EFL_BIT_SET(a_fBit) \
4980 if ( pIemCpu->CTX_SUFF(pCtx)->ecx != 0 \
4981 && (pIemCpu->CTX_SUFF(pCtx)->eflags.u & a_fBit)) {
4982#define IEM_MC_IF_RCX_IS_NZ_AND_EFL_BIT_SET(a_fBit) \
4983 if ( pIemCpu->CTX_SUFF(pCtx)->rcx != 0 \
4984 && (pIemCpu->CTX_SUFF(pCtx)->eflags.u & a_fBit)) {
4985#define IEM_MC_IF_CX_IS_NZ_AND_EFL_BIT_NOT_SET(a_fBit) \
4986 if ( pIemCpu->CTX_SUFF(pCtx)->cx != 0 \
4987 && !(pIemCpu->CTX_SUFF(pCtx)->eflags.u & a_fBit)) {
4988#define IEM_MC_IF_ECX_IS_NZ_AND_EFL_BIT_NOT_SET(a_fBit) \
4989 if ( pIemCpu->CTX_SUFF(pCtx)->ecx != 0 \
4990 && !(pIemCpu->CTX_SUFF(pCtx)->eflags.u & a_fBit)) {
4991#define IEM_MC_IF_RCX_IS_NZ_AND_EFL_BIT_NOT_SET(a_fBit) \
4992 if ( pIemCpu->CTX_SUFF(pCtx)->rcx != 0 \
4993 && !(pIemCpu->CTX_SUFF(pCtx)->eflags.u & a_fBit)) {
4994#define IEM_MC_IF_LOCAL_IS_Z(a_Local) if ((a_Local) == 0) {
4995#define IEM_MC_IF_GREG_BIT_SET(a_iGReg, a_iBitNo) if (*(uint64_t *)iemGRegRef(pIemCpu, (a_iGReg)) & RT_BIT_64(a_iBitNo)) {
4996#define IEM_MC_ELSE() } else {
4997#define IEM_MC_ENDIF() } do {} while (0)
4998
4999/** @} */
5000
5001
5002/** @name Opcode Debug Helpers.
5003 * @{
5004 */
5005#ifdef DEBUG
5006# define IEMOP_MNEMONIC(a_szMnemonic) \
5007 Log2(("decode - %04x:%RGv %s%s [#%u]\n", pIemCpu->CTX_SUFF(pCtx)->cs, pIemCpu->CTX_SUFF(pCtx)->rip, \
5008 pIemCpu->fPrefixes & IEM_OP_PRF_LOCK ? "lock " : "", a_szMnemonic, pIemCpu->cInstructions))
5009# define IEMOP_MNEMONIC2(a_szMnemonic, a_szOps) \
5010 Log2(("decode - %04x:%RGv %s%s %s [#%u]\n", pIemCpu->CTX_SUFF(pCtx)->cs, pIemCpu->CTX_SUFF(pCtx)->rip, \
5011 pIemCpu->fPrefixes & IEM_OP_PRF_LOCK ? "lock " : "", a_szMnemonic, a_szOps, pIemCpu->cInstructions))
5012#else
5013# define IEMOP_MNEMONIC(a_szMnemonic) do { } while (0)
5014# define IEMOP_MNEMONIC2(a_szMnemonic, a_szOps) do { } while (0)
5015#endif
5016
5017/** @} */
5018
5019
5020/** @name Opcode Helpers.
5021 * @{
5022 */
5023
5024/** The instruction allows no lock prefixing (in this encoding), throw #UD if
5025 * lock prefixed. */
5026#define IEMOP_HLP_NO_LOCK_PREFIX() \
5027 do \
5028 { \
5029 if (pIemCpu->fPrefixes & IEM_OP_PRF_LOCK) \
5030 return IEMOP_RAISE_INVALID_LOCK_PREFIX(); \
5031 } while (0)
5032
5033/** The instruction is not available in 64-bit mode, throw #UD if we're in
5034 * 64-bit mode. */
5035#define IEMOP_HLP_NO_64BIT() \
5036 do \
5037 { \
5038 if (pIemCpu->enmCpuMode == IEMMODE_64BIT) \
5039 return IEMOP_RAISE_INVALID_OPCODE(); \
5040 } while (0)
5041
5042/** The instruction defaults to 64-bit operand size if 64-bit mode. */
5043#define IEMOP_HLP_DEFAULT_64BIT_OP_SIZE() \
5044 do \
5045 { \
5046 if (pIemCpu->enmCpuMode == IEMMODE_64BIT) \
5047 iemRecalEffOpSize64Default(pIemCpu); \
5048 } while (0)
5049
5050
5051
5052/**
5053 * Calculates the effective address of a ModR/M memory operand.
5054 *
5055 * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR.
5056 *
5057 * @return Strict VBox status code.
5058 * @param pIemCpu The IEM per CPU data.
5059 * @param bRm The ModRM byte.
5060 * @param pGCPtrEff Where to return the effective address.
5061 */
5062static VBOXSTRICTRC iemOpHlpCalcRmEffAddr(PIEMCPU pIemCpu, uint8_t bRm, PRTGCPTR pGCPtrEff)
5063{
5064 LogFlow(("iemOpHlpCalcRmEffAddr: bRm=%#x\n", bRm));
5065 PCCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5066#define SET_SS_DEF() \
5067 do \
5068 { \
5069 if (!(pIemCpu->fPrefixes & IEM_OP_PRF_SEG_MASK)) \
5070 pIemCpu->iEffSeg = X86_SREG_SS; \
5071 } while (0)
5072
5073/** @todo Check the effective address size crap! */
5074 switch (pIemCpu->enmEffAddrMode)
5075 {
5076 case IEMMODE_16BIT:
5077 {
5078 uint16_t u16EffAddr;
5079
5080 /* Handle the disp16 form with no registers first. */
5081 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)
5082 IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);
5083 else
5084 {
5085 /* Get the displacment. */
5086 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
5087 {
5088 case 0: u16EffAddr = 0; break;
5089 case 1: IEM_OPCODE_GET_NEXT_S8_SX_U16(&u16EffAddr); break;
5090 case 2: IEM_OPCODE_GET_NEXT_U16(&u16EffAddr); break;
5091 default: AssertFailedReturn(VERR_INTERNAL_ERROR_2); /* (caller checked for these) */
5092 }
5093
5094 /* Add the base and index registers to the disp. */
5095 switch (bRm & X86_MODRM_RM_MASK)
5096 {
5097 case 0: u16EffAddr += pCtx->bx + pCtx->si; break;
5098 case 1: u16EffAddr += pCtx->bx + pCtx->di; break;
5099 case 2: u16EffAddr += pCtx->bp + pCtx->si; SET_SS_DEF(); break;
5100 case 3: u16EffAddr += pCtx->bp + pCtx->di; SET_SS_DEF(); break;
5101 case 4: u16EffAddr += pCtx->si; break;
5102 case 5: u16EffAddr += pCtx->di; break;
5103 case 6: u16EffAddr += pCtx->bp; SET_SS_DEF(); break;
5104 case 7: u16EffAddr += pCtx->bx; break;
5105 }
5106 }
5107
5108 *pGCPtrEff = u16EffAddr;
5109 LogFlow(("iemOpHlpCalcRmEffAddr: EffAddr=%#06RGv\n", *pGCPtrEff));
5110 return VINF_SUCCESS;
5111 }
5112
5113 case IEMMODE_32BIT:
5114 {
5115 uint32_t u32EffAddr;
5116
5117 /* Handle the disp32 form with no registers first. */
5118 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
5119 IEM_OPCODE_GET_NEXT_U32(&u32EffAddr);
5120 else
5121 {
5122 /* Get the register (or SIB) value. */
5123 switch ((bRm & X86_MODRM_RM_MASK))
5124 {
5125 case 0: u32EffAddr = pCtx->eax; break;
5126 case 1: u32EffAddr = pCtx->ecx; break;
5127 case 2: u32EffAddr = pCtx->edx; break;
5128 case 3: u32EffAddr = pCtx->ebx; break;
5129 case 4: /* SIB */
5130 {
5131 uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
5132
5133 /* Get the index and scale it. */
5134 switch ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)
5135 {
5136 case 0: u32EffAddr = pCtx->eax; break;
5137 case 1: u32EffAddr = pCtx->ecx; break;
5138 case 2: u32EffAddr = pCtx->edx; break;
5139 case 3: u32EffAddr = pCtx->ebx; break;
5140 case 4: u32EffAddr = 0; /*none */ break;
5141 case 5: u32EffAddr = pCtx->ebp; break;
5142 case 6: u32EffAddr = pCtx->esi; break;
5143 case 7: u32EffAddr = pCtx->edi; break;
5144 IEM_NOT_REACHED_DEFAULT_CASE_RET();
5145 }
5146 u32EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
5147
5148 /* add base */
5149 switch (bSib & X86_SIB_BASE_MASK)
5150 {
5151 case 0: u32EffAddr += pCtx->eax; break;
5152 case 1: u32EffAddr += pCtx->ecx; break;
5153 case 2: u32EffAddr += pCtx->edx; break;
5154 case 3: u32EffAddr += pCtx->ebx; break;
5155 case 4: u32EffAddr += pCtx->esp; SET_SS_DEF(); break;
5156 case 5:
5157 if ((bRm & X86_MODRM_MOD_MASK) != 0)
5158 {
5159 u32EffAddr += pCtx->ebp;
5160 SET_SS_DEF();
5161 }
5162 else
5163 {
5164 uint32_t u32Disp;
5165 IEM_OPCODE_GET_NEXT_U32(&u32Disp);
5166 u32EffAddr += u32Disp;
5167 }
5168 break;
5169 case 6: u32EffAddr += pCtx->esi; break;
5170 case 7: u32EffAddr += pCtx->edi; break;
5171 IEM_NOT_REACHED_DEFAULT_CASE_RET();
5172 }
5173 break;
5174 }
5175 case 5: u32EffAddr = pCtx->ebp; SET_SS_DEF(); break;
5176 case 6: u32EffAddr = pCtx->esi; break;
5177 case 7: u32EffAddr = pCtx->edi; break;
5178 IEM_NOT_REACHED_DEFAULT_CASE_RET();
5179 }
5180
5181 /* Get and add the displacement. */
5182 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
5183 {
5184 case 0:
5185 break;
5186 case 1:
5187 {
5188 int8_t i8Disp; IEM_OPCODE_GET_NEXT_S8(&i8Disp);
5189 u32EffAddr += i8Disp;
5190 break;
5191 }
5192 case 2:
5193 {
5194 uint32_t u32Disp; IEM_OPCODE_GET_NEXT_U32(&u32Disp);
5195 u32EffAddr += u32Disp;
5196 break;
5197 }
5198 default:
5199 AssertFailedReturn(VERR_INTERNAL_ERROR_2); /* (caller checked for these) */
5200 }
5201
5202 }
5203 if (pIemCpu->enmEffAddrMode == IEMMODE_32BIT)
5204 *pGCPtrEff = u32EffAddr;
5205 else
5206 {
5207 Assert(pIemCpu->enmEffAddrMode == IEMMODE_16BIT);
5208 *pGCPtrEff = u32EffAddr & UINT16_MAX;
5209 }
5210 LogFlow(("iemOpHlpCalcRmEffAddr: EffAddr=%#010RGv\n", *pGCPtrEff));
5211 return VINF_SUCCESS;
5212 }
5213
5214 case IEMMODE_64BIT:
5215 {
5216 uint64_t u64EffAddr;
5217
5218 /* Handle the rip+disp32 form with no registers first. */
5219 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
5220 {
5221 IEM_OPCODE_GET_NEXT_S32_SX_U64(&u64EffAddr);
5222 u64EffAddr += pCtx->rip + pIemCpu->offOpcode;
5223 }
5224 else
5225 {
5226 /* Get the register (or SIB) value. */
5227 switch ((bRm & X86_MODRM_RM_MASK) | pIemCpu->uRexB)
5228 {
5229 case 0: u64EffAddr = pCtx->rax; break;
5230 case 1: u64EffAddr = pCtx->rcx; break;
5231 case 2: u64EffAddr = pCtx->rdx; break;
5232 case 3: u64EffAddr = pCtx->rbx; break;
5233 case 5: u64EffAddr = pCtx->rbp; SET_SS_DEF(); break;
5234 case 6: u64EffAddr = pCtx->rsi; break;
5235 case 7: u64EffAddr = pCtx->rdi; break;
5236 case 8: u64EffAddr = pCtx->r8; break;
5237 case 9: u64EffAddr = pCtx->r9; break;
5238 case 10: u64EffAddr = pCtx->r10; break;
5239 case 11: u64EffAddr = pCtx->r11; break;
5240 case 13: u64EffAddr = pCtx->r13; break;
5241 case 14: u64EffAddr = pCtx->r14; break;
5242 case 15: u64EffAddr = pCtx->r15; break;
5243 /* SIB */
5244 case 4:
5245 case 12:
5246 {
5247 uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
5248
5249 /* Get the index and scale it. */
5250 switch (((bSib & X86_SIB_INDEX_SHIFT) >> X86_SIB_INDEX_SMASK) | pIemCpu->uRexIndex)
5251 {
5252 case 0: u64EffAddr = pCtx->rax; break;
5253 case 1: u64EffAddr = pCtx->rcx; break;
5254 case 2: u64EffAddr = pCtx->rdx; break;
5255 case 3: u64EffAddr = pCtx->rbx; break;
5256 case 4: u64EffAddr = 0; /*none */ break;
5257 case 5: u64EffAddr = pCtx->rbp; break;
5258 case 6: u64EffAddr = pCtx->rsi; break;
5259 case 7: u64EffAddr = pCtx->rdi; break;
5260 case 8: u64EffAddr = pCtx->r8; break;
5261 case 9: u64EffAddr = pCtx->r9; break;
5262 case 10: u64EffAddr = pCtx->r10; break;
5263 case 11: u64EffAddr = pCtx->r11; break;
5264 case 12: u64EffAddr = pCtx->r12; break;
5265 case 13: u64EffAddr = pCtx->r13; break;
5266 case 14: u64EffAddr = pCtx->r14; break;
5267 case 15: u64EffAddr = pCtx->r15; break;
5268 IEM_NOT_REACHED_DEFAULT_CASE_RET();
5269 }
5270 u64EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
5271
5272 /* add base */
5273 switch ((bSib & X86_SIB_BASE_MASK) | pIemCpu->uRexB)
5274 {
5275 case 0: u64EffAddr += pCtx->rax; break;
5276 case 1: u64EffAddr += pCtx->rcx; break;
5277 case 2: u64EffAddr += pCtx->rdx; break;
5278 case 3: u64EffAddr += pCtx->rbx; break;
5279 case 4: u64EffAddr += pCtx->rsp; SET_SS_DEF(); break;
5280 case 6: u64EffAddr += pCtx->rsi; break;
5281 case 7: u64EffAddr += pCtx->rdi; break;
5282 case 8: u64EffAddr += pCtx->r8; break;
5283 case 9: u64EffAddr += pCtx->r9; break;
5284 case 10: u64EffAddr += pCtx->r10; break;
5285 case 11: u64EffAddr += pCtx->r11; break;
5286 case 14: u64EffAddr += pCtx->r14; break;
5287 case 15: u64EffAddr += pCtx->r15; break;
5288 /* complicated encodings */
5289 case 5:
5290 case 13:
5291 if ((bRm & X86_MODRM_MOD_MASK) != 0)
5292 {
5293 if (!pIemCpu->uRexB)
5294 {
5295 u64EffAddr += pCtx->rbp;
5296 SET_SS_DEF();
5297 }
5298 else
5299 u64EffAddr += pCtx->r13;
5300 }
5301 else
5302 {
5303 uint32_t u32Disp;
5304 IEM_OPCODE_GET_NEXT_U32(&u32Disp);
5305 u64EffAddr += (int32_t)u32Disp;
5306 }
5307 break;
5308 }
5309 break;
5310 }
5311 IEM_NOT_REACHED_DEFAULT_CASE_RET();
5312 }
5313
5314 /* Get and add the displacement. */
5315 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
5316 {
5317 case 0:
5318 break;
5319 case 1:
5320 {
5321 int8_t i8Disp;
5322 IEM_OPCODE_GET_NEXT_S8(&i8Disp);
5323 u64EffAddr += i8Disp;
5324 break;
5325 }
5326 case 2:
5327 {
5328 uint32_t u32Disp;
5329 IEM_OPCODE_GET_NEXT_U32(&u32Disp);
5330 u64EffAddr += (int32_t)u32Disp;
5331 break;
5332 }
5333 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* (caller checked for these) */
5334 }
5335
5336 }
5337 if (pIemCpu->enmEffAddrMode == IEMMODE_64BIT)
5338 *pGCPtrEff = u64EffAddr;
5339 else
5340 *pGCPtrEff = u64EffAddr & UINT16_MAX;
5341 LogFlow(("iemOpHlpCalcRmEffAddr: EffAddr=%#010RGv\n", *pGCPtrEff));
5342 return VINF_SUCCESS;
5343 }
5344 }
5345
5346 AssertFailedReturn(VERR_INTERNAL_ERROR_3);
5347}
5348
5349/** @} */
5350
5351
5352
5353/*
5354 * Include the instructions
5355 */
5356#include "IEMAllInstructions.cpp.h"
5357
5358
5359
5360
5361#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
5362
5363/**
5364 * Sets up execution verification mode.
5365 */
5366static void iemExecVerificationModeSetup(PIEMCPU pIemCpu)
5367{
5368 PVMCPU pVCpu = IEMCPU_TO_VMCPU(pIemCpu);
5369 PCPUMCTX pOrgCtx = pIemCpu->CTX_SUFF(pCtx);
5370
5371 /*
5372 * Enable verification and/or logging.
5373 */
5374 pIemCpu->fNoRem = !LogIs6Enabled(); /* logging triggers the no-rem/rem verification stuff */
5375 if ( pIemCpu->fNoRem
5376#if 0 /* auto enable on first paged protected mode interrupt */
5377 && pOrgCtx->eflags.Bits.u1IF
5378 && (pOrgCtx->cr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG)
5379 && TRPMHasTrap(pVCpu)
5380 && EMGetInhibitInterruptsPC(pVCpu) != pOrgCtx->rip)
5381#endif
5382#if 0
5383 && pOrgCtx->cs == 0x10
5384 && ( pOrgCtx->rip == 0x90119e3e
5385 || pOrgCtx->rip == 0x901d9810
5386 )
5387#endif
5388#if 0 /* Auto enable; DSL. */
5389 && pOrgCtx->cs == 0x10
5390 && ( pOrgCtx->rip == 0x00100fc7
5391 || pOrgCtx->rip == 0x00100ffc
5392 || pOrgCtx->rip == 0x00100ffe
5393 )
5394#endif
5395#if 0
5396 && 0
5397#endif
5398 )
5399 {
5400 RTLogGroupSettings(NULL, "iem.eo.l6.l2");
5401 RTLogFlags(NULL, "enabled");
5402 pIemCpu->fNoRem = false;
5403 }
5404
5405 /*
5406 * Switch state.
5407 */
5408 if (IEM_VERIFICATION_ENABLED(pIemCpu))
5409 {
5410 static CPUMCTX s_DebugCtx; /* Ugly! */
5411
5412 s_DebugCtx = *pOrgCtx;
5413 pIemCpu->CTX_SUFF(pCtx) = &s_DebugCtx;
5414 }
5415
5416 /*
5417 * See if there is an interrupt pending in TRPM and inject it if we can.
5418 */
5419 if ( pOrgCtx->eflags.Bits.u1IF
5420 && TRPMHasTrap(pVCpu)
5421 && EMGetInhibitInterruptsPC(pVCpu) != pOrgCtx->rip)
5422 {
5423 uint8_t u8TrapNo;
5424 TRPMEVENT enmType;
5425 RTGCUINT uErrCode;
5426 RTGCPTR uCr2;
5427 int rc2 = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrCode, &uCr2); AssertRC(rc2);
5428 IEMInjectTrap(pVCpu, u8TrapNo, enmType, (uint16_t)uErrCode, uCr2);
5429 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
5430 TRPMResetTrap(pVCpu);
5431 }
5432
5433 /*
5434 * Reset the counters.
5435 */
5436 pIemCpu->cIOReads = 0;
5437 pIemCpu->cIOWrites = 0;
5438 pIemCpu->fUndefinedEFlags = 0;
5439
5440 if (IEM_VERIFICATION_ENABLED(pIemCpu))
5441 {
5442 /*
5443 * Free all verification records.
5444 */
5445 PIEMVERIFYEVTREC pEvtRec = pIemCpu->pIemEvtRecHead;
5446 pIemCpu->pIemEvtRecHead = NULL;
5447 pIemCpu->ppIemEvtRecNext = &pIemCpu->pIemEvtRecHead;
5448 do
5449 {
5450 while (pEvtRec)
5451 {
5452 PIEMVERIFYEVTREC pNext = pEvtRec->pNext;
5453 pEvtRec->pNext = pIemCpu->pFreeEvtRec;
5454 pIemCpu->pFreeEvtRec = pEvtRec;
5455 pEvtRec = pNext;
5456 }
5457 pEvtRec = pIemCpu->pOtherEvtRecHead;
5458 pIemCpu->pOtherEvtRecHead = NULL;
5459 pIemCpu->ppOtherEvtRecNext = &pIemCpu->pOtherEvtRecHead;
5460 } while (pEvtRec);
5461 }
5462}
5463
5464
5465/**
5466 * Allocate an event record.
5467 * @returns Poitner to a record.
5468 */
5469static PIEMVERIFYEVTREC iemVerifyAllocRecord(PIEMCPU pIemCpu)
5470{
5471 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
5472 return NULL;
5473
5474 PIEMVERIFYEVTREC pEvtRec = pIemCpu->pFreeEvtRec;
5475 if (pEvtRec)
5476 pIemCpu->pFreeEvtRec = pEvtRec->pNext;
5477 else
5478 {
5479 if (!pIemCpu->ppIemEvtRecNext)
5480 return NULL; /* Too early (fake PCIBIOS), ignore notification. */
5481
5482 pEvtRec = (PIEMVERIFYEVTREC)MMR3HeapAlloc(IEMCPU_TO_VM(pIemCpu), MM_TAG_EM /* lazy bird*/, sizeof(*pEvtRec));
5483 if (!pEvtRec)
5484 return NULL;
5485 }
5486 pEvtRec->enmEvent = IEMVERIFYEVENT_INVALID;
5487 pEvtRec->pNext = NULL;
5488 return pEvtRec;
5489}
5490
5491
5492/**
5493 * IOMMMIORead notification.
5494 */
5495VMM_INT_DECL(void) IEMNotifyMMIORead(PVM pVM, RTGCPHYS GCPhys, size_t cbValue)
5496{
5497 PVMCPU pVCpu = VMMGetCpu(pVM);
5498 if (!pVCpu)
5499 return;
5500 PIEMCPU pIemCpu = &pVCpu->iem.s;
5501 PIEMVERIFYEVTREC pEvtRec = iemVerifyAllocRecord(pIemCpu);
5502 if (!pEvtRec)
5503 return;
5504 pEvtRec->enmEvent = IEMVERIFYEVENT_RAM_READ;
5505 pEvtRec->u.RamRead.GCPhys = GCPhys;
5506 pEvtRec->u.RamRead.cb = cbValue;
5507 pEvtRec->pNext = *pIemCpu->ppOtherEvtRecNext;
5508 *pIemCpu->ppOtherEvtRecNext = pEvtRec;
5509}
5510
5511
5512/**
5513 * IOMMMIOWrite notification.
5514 */
5515VMM_INT_DECL(void) IEMNotifyMMIOWrite(PVM pVM, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue)
5516{
5517 PVMCPU pVCpu = VMMGetCpu(pVM);
5518 if (!pVCpu)
5519 return;
5520 PIEMCPU pIemCpu = &pVCpu->iem.s;
5521 PIEMVERIFYEVTREC pEvtRec = iemVerifyAllocRecord(pIemCpu);
5522 if (!pEvtRec)
5523 return;
5524 pEvtRec->enmEvent = IEMVERIFYEVENT_RAM_WRITE;
5525 pEvtRec->u.RamWrite.GCPhys = GCPhys;
5526 pEvtRec->u.RamWrite.cb = cbValue;
5527 pEvtRec->u.RamWrite.ab[0] = RT_BYTE1(u32Value);
5528 pEvtRec->u.RamWrite.ab[1] = RT_BYTE2(u32Value);
5529 pEvtRec->u.RamWrite.ab[2] = RT_BYTE3(u32Value);
5530 pEvtRec->u.RamWrite.ab[3] = RT_BYTE4(u32Value);
5531 pEvtRec->pNext = *pIemCpu->ppOtherEvtRecNext;
5532 *pIemCpu->ppOtherEvtRecNext = pEvtRec;
5533}
5534
5535
5536/**
5537 * IOMIOPortRead notification.
5538 */
5539VMM_INT_DECL(void) IEMNotifyIOPortRead(PVM pVM, RTIOPORT Port, size_t cbValue)
5540{
5541 PVMCPU pVCpu = VMMGetCpu(pVM);
5542 if (!pVCpu)
5543 return;
5544 PIEMCPU pIemCpu = &pVCpu->iem.s;
5545 PIEMVERIFYEVTREC pEvtRec = iemVerifyAllocRecord(pIemCpu);
5546 if (!pEvtRec)
5547 return;
5548 pEvtRec->enmEvent = IEMVERIFYEVENT_IOPORT_READ;
5549 pEvtRec->u.IOPortRead.Port = Port;
5550 pEvtRec->u.IOPortRead.cbValue = cbValue;
5551 pEvtRec->pNext = *pIemCpu->ppOtherEvtRecNext;
5552 *pIemCpu->ppOtherEvtRecNext = pEvtRec;
5553}
5554
5555/**
5556 * IOMIOPortWrite notification.
5557 */
5558VMM_INT_DECL(void) IEMNotifyIOPortWrite(PVM pVM, RTIOPORT Port, uint32_t u32Value, size_t cbValue)
5559{
5560 PVMCPU pVCpu = VMMGetCpu(pVM);
5561 if (!pVCpu)
5562 return;
5563 PIEMCPU pIemCpu = &pVCpu->iem.s;
5564 PIEMVERIFYEVTREC pEvtRec = iemVerifyAllocRecord(pIemCpu);
5565 if (!pEvtRec)
5566 return;
5567 pEvtRec->enmEvent = IEMVERIFYEVENT_IOPORT_WRITE;
5568 pEvtRec->u.IOPortWrite.Port = Port;
5569 pEvtRec->u.IOPortWrite.cbValue = cbValue;
5570 pEvtRec->u.IOPortWrite.u32Value = u32Value;
5571 pEvtRec->pNext = *pIemCpu->ppOtherEvtRecNext;
5572 *pIemCpu->ppOtherEvtRecNext = pEvtRec;
5573}
5574
5575
5576VMM_INT_DECL(void) IEMNotifyIOPortReadString(PVM pVM, RTIOPORT Port, RTGCPTR GCPtrDst, RTGCUINTREG cTransfers, size_t cbValue)
5577{
5578 AssertFailed();
5579}
5580
5581
5582VMM_INT_DECL(void) IEMNotifyIOPortWriteString(PVM pVM, RTIOPORT Port, RTGCPTR GCPtrSrc, RTGCUINTREG cTransfers, size_t cbValue)
5583{
5584 AssertFailed();
5585}
5586
5587
5588/**
5589 * Fakes and records an I/O port read.
5590 *
5591 * @returns VINF_SUCCESS.
5592 * @param pIemCpu The IEM per CPU data.
5593 * @param Port The I/O port.
5594 * @param pu32Value Where to store the fake value.
5595 * @param cbValue The size of the access.
5596 */
5597static VBOXSTRICTRC iemVerifyFakeIOPortRead(PIEMCPU pIemCpu, RTIOPORT Port, uint32_t *pu32Value, size_t cbValue)
5598{
5599 PIEMVERIFYEVTREC pEvtRec = iemVerifyAllocRecord(pIemCpu);
5600 if (pEvtRec)
5601 {
5602 pEvtRec->enmEvent = IEMVERIFYEVENT_IOPORT_READ;
5603 pEvtRec->u.IOPortRead.Port = Port;
5604 pEvtRec->u.IOPortRead.cbValue = cbValue;
5605 pEvtRec->pNext = *pIemCpu->ppIemEvtRecNext;
5606 *pIemCpu->ppIemEvtRecNext = pEvtRec;
5607 }
5608 pIemCpu->cIOReads++;
5609 *pu32Value = 0xffffffff;
5610 return VINF_SUCCESS;
5611}
5612
5613
5614/**
5615 * Fakes and records an I/O port write.
5616 *
5617 * @returns VINF_SUCCESS.
5618 * @param pIemCpu The IEM per CPU data.
5619 * @param Port The I/O port.
5620 * @param u32Value The value being written.
5621 * @param cbValue The size of the access.
5622 */
5623static VBOXSTRICTRC iemVerifyFakeIOPortWrite(PIEMCPU pIemCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue)
5624{
5625 PIEMVERIFYEVTREC pEvtRec = iemVerifyAllocRecord(pIemCpu);
5626 if (pEvtRec)
5627 {
5628 pEvtRec->enmEvent = IEMVERIFYEVENT_IOPORT_WRITE;
5629 pEvtRec->u.IOPortWrite.Port = Port;
5630 pEvtRec->u.IOPortWrite.cbValue = cbValue;
5631 pEvtRec->u.IOPortWrite.u32Value = u32Value;
5632 pEvtRec->pNext = *pIemCpu->ppIemEvtRecNext;
5633 *pIemCpu->ppIemEvtRecNext = pEvtRec;
5634 }
5635 pIemCpu->cIOWrites++;
5636 return VINF_SUCCESS;
5637}
5638
5639
5640/**
5641 * Used to add extra details about a stub case.
5642 * @param pIemCpu The IEM per CPU state.
5643 */
5644static void iemVerifyAssertMsg2(PIEMCPU pIemCpu)
5645{
5646 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
5647 PVM pVM = IEMCPU_TO_VM(pIemCpu);
5648 PVMCPU pVCpu = IEMCPU_TO_VMCPU(pIemCpu);
5649 char szRegs[4096];
5650 DBGFR3RegPrintf(pVM, pVCpu->idCpu, &szRegs[0], sizeof(szRegs),
5651 "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n"
5652 "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n"
5653 "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n"
5654 "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n"
5655 "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n"
5656 "cs={%04VR{cs} base=%016VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} cr0=%016VR{cr0}\n"
5657 "ds={%04VR{ds} base=%016VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} cr2=%016VR{cr2}\n"
5658 "es={%04VR{es} base=%016VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} cr3=%016VR{cr3}\n"
5659 "fs={%04VR{fs} base=%016VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr4=%016VR{cr4}\n"
5660 "gs={%04VR{gs} base=%016VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr8=%016VR{cr8}\n"
5661 "ss={%04VR{ss} base=%016VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}}\n"
5662 "dr0=%016VR{dr0} dr1=%016VR{dr1} dr2=%016VR{dr2} dr3=%016VR{dr3}\n"
5663 "dr6=%016VR{dr6} dr7=%016VR{dr7}\n"
5664 "gdtr=%016VR{gdtr_base}:%04VR{gdtr_lim} idtr=%016VR{idtr_base}:%04VR{idtr_lim} rflags=%08VR{rflags}\n"
5665 "ldtr={%04VR{ldtr} base=%016VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%08VR{ldtr_attr}}\n"
5666 "tr ={%04VR{tr} base=%016VR{tr_base} limit=%08VR{tr_lim} flags=%08VR{tr_attr}}\n"
5667 " sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n"
5668 " efer=%016VR{efer}\n"
5669 " pat=%016VR{pat}\n"
5670 " sf_mask=%016VR{sf_mask}\n"
5671 "krnl_gs_base=%016VR{krnl_gs_base}\n"
5672 " lstar=%016VR{lstar}\n"
5673 " star=%016VR{star} cstar=%016VR{cstar}\n"
5674 "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n"
5675 );
5676
5677 char szInstr1[256];
5678 DBGFR3DisasInstrEx(pVM, pVCpu->idCpu, pCtx->cs, pCtx->rip - pIemCpu->offOpcode,
5679 DBGF_DISAS_FLAGS_DEFAULT_MODE,
5680 szInstr1, sizeof(szInstr1), NULL);
5681 char szInstr2[256];
5682 DBGFR3DisasInstrEx(pVM, pVCpu->idCpu, 0, 0,
5683 DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_DEFAULT_MODE,
5684 szInstr2, sizeof(szInstr2), NULL);
5685
5686 RTAssertMsg2Weak("%s%s\n%s\n", szRegs, szInstr1, szInstr2);
5687}
5688
5689
5690/**
5691 * Used by iemVerifyAssertRecord and iemVerifyAssertRecords to add a record
5692 * dump to the assertion info.
5693 *
5694 * @param pEvtRec The record to dump.
5695 */
5696static void iemVerifyAssertAddRecordDump(PIEMVERIFYEVTREC pEvtRec)
5697{
5698 switch (pEvtRec->enmEvent)
5699 {
5700 case IEMVERIFYEVENT_IOPORT_READ:
5701 RTAssertMsg2Add("I/O PORT READ from %#6x, %d bytes\n",
5702 pEvtRec->u.IOPortWrite.Port,
5703 pEvtRec->u.IOPortWrite.cbValue);
5704 break;
5705 case IEMVERIFYEVENT_IOPORT_WRITE:
5706 RTAssertMsg2Add("I/O PORT WRITE to %#6x, %d bytes, value %#x\n",
5707 pEvtRec->u.IOPortWrite.Port,
5708 pEvtRec->u.IOPortWrite.cbValue,
5709 pEvtRec->u.IOPortWrite.u32Value);
5710 break;
5711 case IEMVERIFYEVENT_RAM_READ:
5712 RTAssertMsg2Add("RAM READ at %RGp, %#4zx bytes\n",
5713 pEvtRec->u.RamRead.GCPhys,
5714 pEvtRec->u.RamRead.cb);
5715 break;
5716 case IEMVERIFYEVENT_RAM_WRITE:
5717 RTAssertMsg2Add("RAM WRITE at %RGp, %#4zx bytes: %.*RHxs\n",
5718 pEvtRec->u.RamWrite.GCPhys,
5719 pEvtRec->u.RamWrite.cb,
5720 (int)pEvtRec->u.RamWrite.cb,
5721 pEvtRec->u.RamWrite.ab);
5722 break;
5723 default:
5724 AssertMsgFailed(("Invalid event type %d\n", pEvtRec->enmEvent));
5725 break;
5726 }
5727}
5728
5729
5730/**
5731 * Raises an assertion on the specified record, showing the given message with
5732 * a record dump attached.
5733 *
5734 * @param pIemCpu The IEM per CPU data.
5735 * @param pEvtRec1 The first record.
5736 * @param pEvtRec2 The second record.
5737 * @param pszMsg The message explaining why we're asserting.
5738 */
5739static void iemVerifyAssertRecords(PIEMCPU pIemCpu, PIEMVERIFYEVTREC pEvtRec1, PIEMVERIFYEVTREC pEvtRec2, const char *pszMsg)
5740{
5741 RTAssertMsg1(pszMsg, __LINE__, __FILE__, __PRETTY_FUNCTION__);
5742 iemVerifyAssertAddRecordDump(pEvtRec1);
5743 iemVerifyAssertAddRecordDump(pEvtRec2);
5744 iemVerifyAssertMsg2(pIemCpu);
5745 RTAssertPanic();
5746}
5747
5748
5749/**
5750 * Raises an assertion on the specified record, showing the given message with
5751 * a record dump attached.
5752 *
5753 * @param pIemCpu The IEM per CPU data.
5754 * @param pEvtRec1 The first record.
5755 * @param pszMsg The message explaining why we're asserting.
5756 */
5757static void iemVerifyAssertRecord(PIEMCPU pIemCpu, PIEMVERIFYEVTREC pEvtRec, const char *pszMsg)
5758{
5759 RTAssertMsg1(pszMsg, __LINE__, __FILE__, __PRETTY_FUNCTION__);
5760 iemVerifyAssertAddRecordDump(pEvtRec);
5761 iemVerifyAssertMsg2(pIemCpu);
5762 RTAssertPanic();
5763}
5764
5765
5766/**
5767 * Verifies a write record.
5768 *
5769 * @param pIemCpu The IEM per CPU data.
5770 * @param pEvtRec The write record.
5771 */
5772static void iemVerifyWriteRecord(PIEMCPU pIemCpu, PIEMVERIFYEVTREC pEvtRec)
5773{
5774 uint8_t abBuf[sizeof(pEvtRec->u.RamWrite.ab)]; RT_ZERO(abBuf);
5775 int rc = PGMPhysSimpleReadGCPhys(IEMCPU_TO_VM(pIemCpu), abBuf, pEvtRec->u.RamWrite.GCPhys, pEvtRec->u.RamWrite.cb);
5776 if ( RT_FAILURE(rc)
5777 || memcmp(abBuf, pEvtRec->u.RamWrite.ab, pEvtRec->u.RamWrite.cb) )
5778 {
5779 /* fend off ins */
5780 if ( !pIemCpu->cIOReads
5781 || pEvtRec->u.RamWrite.ab[0] != 0xcc
5782 || ( pEvtRec->u.RamWrite.cb != 1
5783 && pEvtRec->u.RamWrite.cb != 2
5784 && pEvtRec->u.RamWrite.cb != 4) )
5785 {
5786 /* fend off ROMs */
5787 if ( pEvtRec->u.RamWrite.GCPhys - UINT32_C(0x000c0000) > UINT32_C(0x8000)
5788 && pEvtRec->u.RamWrite.GCPhys - UINT32_C(0x000e0000) > UINT32_C(0x20000)
5789 && pEvtRec->u.RamWrite.GCPhys - UINT32_C(0xfffc0000) > UINT32_C(0x40000) )
5790 {
5791 RTAssertMsg1(NULL, __LINE__, __FILE__, __PRETTY_FUNCTION__);
5792 RTAssertMsg2Weak("Memory at %RGv differs\n", pEvtRec->u.RamWrite.GCPhys);
5793 RTAssertMsg2Add("REM: %.*Rhxs\n"
5794 "IEM: %.*Rhxs\n",
5795 pEvtRec->u.RamWrite.cb, abBuf,
5796 pEvtRec->u.RamWrite.cb, pEvtRec->u.RamWrite.ab);
5797 iemVerifyAssertAddRecordDump(pEvtRec);
5798 iemVerifyAssertMsg2(pIemCpu);
5799 RTAssertPanic();
5800 }
5801 }
5802 }
5803
5804}
5805
5806/**
5807 * Performs the post-execution verfication checks.
5808 */
5809static void iemExecVerificationModeCheck(PIEMCPU pIemCpu)
5810{
5811 if (!IEM_VERIFICATION_ENABLED(pIemCpu))
5812 return;
5813
5814 /*
5815 * Switch back the state.
5816 */
5817 PCPUMCTX pOrgCtx = CPUMQueryGuestCtxPtr(IEMCPU_TO_VMCPU(pIemCpu));
5818 PCPUMCTX pDebugCtx = pIemCpu->CTX_SUFF(pCtx);
5819 Assert(pOrgCtx != pDebugCtx);
5820 pIemCpu->CTX_SUFF(pCtx) = pOrgCtx;
5821
5822 /*
5823 * Execute the instruction in REM.
5824 */
5825 PVM pVM = IEMCPU_TO_VM(pIemCpu);
5826 EMRemLock(pVM);
5827 int rc = REMR3EmulateInstruction(pVM, IEMCPU_TO_VMCPU(pIemCpu));
5828 AssertRC(rc);
5829 EMRemUnlock(pVM);
5830
5831 /*
5832 * Compare the register states.
5833 */
5834 unsigned cDiffs = 0;
5835 if (memcmp(pOrgCtx, pDebugCtx, sizeof(*pDebugCtx)))
5836 {
5837 Log(("REM and IEM ends up with different registers!\n"));
5838
5839# define CHECK_FIELD(a_Field) \
5840 do \
5841 { \
5842 if (pOrgCtx->a_Field != pDebugCtx->a_Field) \
5843 { \
5844 switch (sizeof(pOrgCtx->a_Field)) \
5845 { \
5846 case 1: RTAssertMsg2Weak(" %8s differs - iem=%02x - rem=%02x\n", #a_Field, pDebugCtx->a_Field, pOrgCtx->a_Field); break; \
5847 case 2: RTAssertMsg2Weak(" %8s differs - iem=%04x - rem=%04x\n", #a_Field, pDebugCtx->a_Field, pOrgCtx->a_Field); break; \
5848 case 4: RTAssertMsg2Weak(" %8s differs - iem=%08x - rem=%08x\n", #a_Field, pDebugCtx->a_Field, pOrgCtx->a_Field); break; \
5849 case 8: RTAssertMsg2Weak(" %8s differs - iem=%016llx - rem=%016llx\n", #a_Field, pDebugCtx->a_Field, pOrgCtx->a_Field); break; \
5850 default: RTAssertMsg2Weak(" %8s differs\n", #a_Field); break; \
5851 } \
5852 cDiffs++; \
5853 } \
5854 } while (0)
5855
5856# define CHECK_BIT_FIELD(a_Field) \
5857 do \
5858 { \
5859 if (pOrgCtx->a_Field != pDebugCtx->a_Field) \
5860 { \
5861 RTAssertMsg2Weak(" %8s differs - iem=%02x - rem=%02x\n", #a_Field, pDebugCtx->a_Field, pOrgCtx->a_Field); \
5862 cDiffs++; \
5863 } \
5864 } while (0)
5865
5866# define CHECK_SEL(a_Sel) \
5867 do \
5868 { \
5869 CHECK_FIELD(a_Sel); \
5870 if ( pOrgCtx->a_Sel##Hid.Attr.u != pDebugCtx->a_Sel##Hid.Attr.u \
5871 && (pOrgCtx->a_Sel##Hid.Attr.u | X86_SEL_TYPE_ACCESSED) != pDebugCtx->a_Sel##Hid.Attr.u) \
5872 { \
5873 RTAssertMsg2Weak(" %8sHid.Attr differs - iem=%02x - rem=%02x\n", #a_Sel, pDebugCtx->a_Sel##Hid.Attr.u, pOrgCtx->a_Sel##Hid.Attr.u); \
5874 cDiffs++; \
5875 } \
5876 CHECK_FIELD(a_Sel##Hid.u64Base); \
5877 CHECK_FIELD(a_Sel##Hid.u32Limit); \
5878 } while (0)
5879
5880 if (memcmp(&pOrgCtx->fpu, &pDebugCtx->fpu, sizeof(pDebugCtx->fpu)))
5881 {
5882 RTAssertMsg2Weak(" the FPU state differs\n");
5883 cDiffs++;
5884 CHECK_FIELD(fpu.FCW);
5885 CHECK_FIELD(fpu.FSW);
5886 CHECK_FIELD(fpu.FTW);
5887 CHECK_FIELD(fpu.FOP);
5888 CHECK_FIELD(fpu.FPUIP);
5889 CHECK_FIELD(fpu.CS);
5890 CHECK_FIELD(fpu.Rsrvd1);
5891 CHECK_FIELD(fpu.FPUDP);
5892 CHECK_FIELD(fpu.DS);
5893 CHECK_FIELD(fpu.Rsrvd2);
5894 CHECK_FIELD(fpu.MXCSR);
5895 CHECK_FIELD(fpu.MXCSR_MASK);
5896 CHECK_FIELD(fpu.aRegs[0].au64[0]); CHECK_FIELD(fpu.aRegs[0].au64[1]);
5897 CHECK_FIELD(fpu.aRegs[1].au64[0]); CHECK_FIELD(fpu.aRegs[1].au64[1]);
5898 CHECK_FIELD(fpu.aRegs[2].au64[0]); CHECK_FIELD(fpu.aRegs[2].au64[1]);
5899 CHECK_FIELD(fpu.aRegs[3].au64[0]); CHECK_FIELD(fpu.aRegs[3].au64[1]);
5900 CHECK_FIELD(fpu.aRegs[4].au64[0]); CHECK_FIELD(fpu.aRegs[4].au64[1]);
5901 CHECK_FIELD(fpu.aRegs[5].au64[0]); CHECK_FIELD(fpu.aRegs[5].au64[1]);
5902 CHECK_FIELD(fpu.aRegs[6].au64[0]); CHECK_FIELD(fpu.aRegs[6].au64[1]);
5903 CHECK_FIELD(fpu.aRegs[7].au64[0]); CHECK_FIELD(fpu.aRegs[7].au64[1]);
5904 CHECK_FIELD(fpu.aXMM[ 0].au64[0]); CHECK_FIELD(fpu.aXMM[ 0].au64[1]);
5905 CHECK_FIELD(fpu.aXMM[ 1].au64[0]); CHECK_FIELD(fpu.aXMM[ 1].au64[1]);
5906 CHECK_FIELD(fpu.aXMM[ 2].au64[0]); CHECK_FIELD(fpu.aXMM[ 2].au64[1]);
5907 CHECK_FIELD(fpu.aXMM[ 3].au64[0]); CHECK_FIELD(fpu.aXMM[ 3].au64[1]);
5908 CHECK_FIELD(fpu.aXMM[ 4].au64[0]); CHECK_FIELD(fpu.aXMM[ 4].au64[1]);
5909 CHECK_FIELD(fpu.aXMM[ 5].au64[0]); CHECK_FIELD(fpu.aXMM[ 5].au64[1]);
5910 CHECK_FIELD(fpu.aXMM[ 6].au64[0]); CHECK_FIELD(fpu.aXMM[ 6].au64[1]);
5911 CHECK_FIELD(fpu.aXMM[ 7].au64[0]); CHECK_FIELD(fpu.aXMM[ 7].au64[1]);
5912 CHECK_FIELD(fpu.aXMM[ 8].au64[0]); CHECK_FIELD(fpu.aXMM[ 8].au64[1]);
5913 CHECK_FIELD(fpu.aXMM[ 9].au64[0]); CHECK_FIELD(fpu.aXMM[ 9].au64[1]);
5914 CHECK_FIELD(fpu.aXMM[10].au64[0]); CHECK_FIELD(fpu.aXMM[10].au64[1]);
5915 CHECK_FIELD(fpu.aXMM[11].au64[0]); CHECK_FIELD(fpu.aXMM[11].au64[1]);
5916 CHECK_FIELD(fpu.aXMM[12].au64[0]); CHECK_FIELD(fpu.aXMM[12].au64[1]);
5917 CHECK_FIELD(fpu.aXMM[13].au64[0]); CHECK_FIELD(fpu.aXMM[13].au64[1]);
5918 CHECK_FIELD(fpu.aXMM[14].au64[0]); CHECK_FIELD(fpu.aXMM[14].au64[1]);
5919 CHECK_FIELD(fpu.aXMM[15].au64[0]); CHECK_FIELD(fpu.aXMM[15].au64[1]);
5920 for (unsigned i = 0; i < RT_ELEMENTS(pOrgCtx->fpu.au32RsrvdRest); i++)
5921 CHECK_FIELD(fpu.au32RsrvdRest[i]);
5922 }
5923 CHECK_FIELD(rip);
5924 uint32_t fFlagsMask = UINT32_MAX & ~pIemCpu->fUndefinedEFlags;
5925 if ((pOrgCtx->rflags.u & fFlagsMask) != (pDebugCtx->rflags.u & fFlagsMask))
5926 {
5927 RTAssertMsg2Weak(" rflags differs - iem=%08llx rem=%08llx\n", pDebugCtx->rflags.u, pOrgCtx->rflags.u);
5928 CHECK_BIT_FIELD(rflags.Bits.u1CF);
5929 CHECK_BIT_FIELD(rflags.Bits.u1Reserved0);
5930 CHECK_BIT_FIELD(rflags.Bits.u1PF);
5931 CHECK_BIT_FIELD(rflags.Bits.u1Reserved1);
5932 CHECK_BIT_FIELD(rflags.Bits.u1AF);
5933 CHECK_BIT_FIELD(rflags.Bits.u1Reserved2);
5934 CHECK_BIT_FIELD(rflags.Bits.u1ZF);
5935 CHECK_BIT_FIELD(rflags.Bits.u1SF);
5936 CHECK_BIT_FIELD(rflags.Bits.u1TF);
5937 CHECK_BIT_FIELD(rflags.Bits.u1IF);
5938 CHECK_BIT_FIELD(rflags.Bits.u1DF);
5939 CHECK_BIT_FIELD(rflags.Bits.u1OF);
5940 CHECK_BIT_FIELD(rflags.Bits.u2IOPL);
5941 CHECK_BIT_FIELD(rflags.Bits.u1NT);
5942 CHECK_BIT_FIELD(rflags.Bits.u1Reserved3);
5943 CHECK_BIT_FIELD(rflags.Bits.u1RF);
5944 CHECK_BIT_FIELD(rflags.Bits.u1VM);
5945 CHECK_BIT_FIELD(rflags.Bits.u1AC);
5946 CHECK_BIT_FIELD(rflags.Bits.u1VIF);
5947 CHECK_BIT_FIELD(rflags.Bits.u1VIP);
5948 CHECK_BIT_FIELD(rflags.Bits.u1ID);
5949 }
5950
5951 if (pIemCpu->cIOReads != 1 && !pIemCpu->fIgnoreRaxRdx)
5952 CHECK_FIELD(rax);
5953 CHECK_FIELD(rcx);
5954 if (!pIemCpu->fIgnoreRaxRdx)
5955 CHECK_FIELD(rdx);
5956 CHECK_FIELD(rbx);
5957 CHECK_FIELD(rsp);
5958 CHECK_FIELD(rbp);
5959 CHECK_FIELD(rsi);
5960 CHECK_FIELD(rdi);
5961 CHECK_FIELD(r8);
5962 CHECK_FIELD(r9);
5963 CHECK_FIELD(r10);
5964 CHECK_FIELD(r11);
5965 CHECK_FIELD(r12);
5966 CHECK_FIELD(r13);
5967 CHECK_SEL(cs);
5968 CHECK_SEL(ss);
5969 CHECK_SEL(ds);
5970 CHECK_SEL(es);
5971 CHECK_SEL(fs);
5972 CHECK_SEL(gs);
5973 CHECK_FIELD(cr0);
5974 CHECK_FIELD(cr2);
5975 CHECK_FIELD(cr3);
5976 CHECK_FIELD(cr4);
5977 CHECK_FIELD(dr[0]);
5978 CHECK_FIELD(dr[1]);
5979 CHECK_FIELD(dr[2]);
5980 CHECK_FIELD(dr[3]);
5981 CHECK_FIELD(dr[6]);
5982 CHECK_FIELD(dr[7]);
5983 CHECK_FIELD(gdtr.cbGdt);
5984 CHECK_FIELD(gdtr.pGdt);
5985 CHECK_FIELD(idtr.cbIdt);
5986 CHECK_FIELD(idtr.pIdt);
5987 CHECK_FIELD(ldtr);
5988 CHECK_FIELD(ldtrHid.u64Base);
5989 CHECK_FIELD(ldtrHid.u32Limit);
5990 CHECK_FIELD(ldtrHid.Attr.u);
5991 CHECK_FIELD(tr);
5992 CHECK_FIELD(trHid.u64Base);
5993 CHECK_FIELD(trHid.u32Limit);
5994 CHECK_FIELD(trHid.Attr.u);
5995 CHECK_FIELD(SysEnter.cs);
5996 CHECK_FIELD(SysEnter.eip);
5997 CHECK_FIELD(SysEnter.esp);
5998 CHECK_FIELD(msrEFER);
5999 CHECK_FIELD(msrSTAR);
6000 CHECK_FIELD(msrPAT);
6001 CHECK_FIELD(msrLSTAR);
6002 CHECK_FIELD(msrCSTAR);
6003 CHECK_FIELD(msrSFMASK);
6004 CHECK_FIELD(msrKERNELGSBASE);
6005
6006 if (cDiffs != 0)
6007 {
6008 RTAssertMsg1(NULL, __LINE__, __FILE__, __FUNCTION__);
6009 iemVerifyAssertMsg2(pIemCpu);
6010 RTAssertPanic();
6011 }
6012# undef CHECK_FIELD
6013# undef CHECK_BIT_FIELD
6014 }
6015
6016 /*
6017 * If the register state compared fine, check the verification event
6018 * records.
6019 */
6020 if (cDiffs == 0)
6021 {
6022 /*
6023 * Compare verficiation event records.
6024 * - I/O port accesses should be a 1:1 match.
6025 */
6026 PIEMVERIFYEVTREC pIemRec = pIemCpu->pIemEvtRecHead;
6027 PIEMVERIFYEVTREC pOtherRec = pIemCpu->pOtherEvtRecHead;
6028 while (pIemRec && pOtherRec)
6029 {
6030 /* Since we might miss RAM writes and reads, ignore reads and check
6031 that any written memory is the same extra ones. */
6032 while ( IEMVERIFYEVENT_IS_RAM(pIemRec->enmEvent)
6033 && !IEMVERIFYEVENT_IS_RAM(pOtherRec->enmEvent)
6034 && pIemRec->pNext)
6035 {
6036 if (pIemRec->enmEvent == IEMVERIFYEVENT_RAM_WRITE)
6037 iemVerifyWriteRecord(pIemCpu, pIemRec);
6038 pIemRec = pIemRec->pNext;
6039 }
6040
6041 /* Do the compare. */
6042 if (pIemRec->enmEvent != pOtherRec->enmEvent)
6043 {
6044 iemVerifyAssertRecords(pIemCpu, pIemRec, pOtherRec, "Type mismatches");
6045 break;
6046 }
6047 bool fEquals;
6048 switch (pIemRec->enmEvent)
6049 {
6050 case IEMVERIFYEVENT_IOPORT_READ:
6051 fEquals = pIemRec->u.IOPortRead.Port == pOtherRec->u.IOPortRead.Port
6052 && pIemRec->u.IOPortRead.cbValue == pOtherRec->u.IOPortRead.cbValue;
6053 break;
6054 case IEMVERIFYEVENT_IOPORT_WRITE:
6055 fEquals = pIemRec->u.IOPortWrite.Port == pOtherRec->u.IOPortWrite.Port
6056 && pIemRec->u.IOPortWrite.cbValue == pOtherRec->u.IOPortWrite.cbValue
6057 && pIemRec->u.IOPortWrite.u32Value == pOtherRec->u.IOPortWrite.u32Value;
6058 break;
6059 case IEMVERIFYEVENT_RAM_READ:
6060 fEquals = pIemRec->u.RamRead.GCPhys == pOtherRec->u.RamRead.GCPhys
6061 && pIemRec->u.RamRead.cb == pOtherRec->u.RamRead.cb;
6062 break;
6063 case IEMVERIFYEVENT_RAM_WRITE:
6064 fEquals = pIemRec->u.RamWrite.GCPhys == pOtherRec->u.RamWrite.GCPhys
6065 && pIemRec->u.RamWrite.cb == pOtherRec->u.RamWrite.cb
6066 && !memcmp(pIemRec->u.RamWrite.ab, pOtherRec->u.RamWrite.ab, pIemRec->u.RamWrite.cb);
6067 break;
6068 default:
6069 fEquals = false;
6070 break;
6071 }
6072 if (!fEquals)
6073 {
6074 iemVerifyAssertRecords(pIemCpu, pIemRec, pOtherRec, "Mismatch");
6075 break;
6076 }
6077
6078 /* advance */
6079 pIemRec = pIemRec->pNext;
6080 pOtherRec = pOtherRec->pNext;
6081 }
6082
6083 /* Ignore extra writes and reads. */
6084 while (pIemRec && IEMVERIFYEVENT_IS_RAM(pIemRec->enmEvent))
6085 {
6086 if (pIemRec->enmEvent == IEMVERIFYEVENT_RAM_WRITE)
6087 iemVerifyWriteRecord(pIemCpu, pIemRec);
6088 pIemRec = pIemRec->pNext;
6089 }
6090 if (pIemRec != NULL)
6091 iemVerifyAssertRecord(pIemCpu, pIemRec, "Extra IEM record!");
6092 else if (pOtherRec != NULL)
6093 iemVerifyAssertRecord(pIemCpu, pIemRec, "Extra Other record!");
6094 }
6095 pIemCpu->CTX_SUFF(pCtx) = pOrgCtx;
6096
6097#if 0
6098 /*
6099 * HACK ALERT! You don't normally want to verify a whole boot sequence.
6100 */
6101 if (pIemCpu->cInstructions == 1)
6102 RTLogFlags(NULL, "disabled");
6103#endif
6104}
6105
6106#else /* !IEM_VERIFICATION_MODE || !IN_RING3 */
6107
6108/* stubs */
6109static VBOXSTRICTRC iemVerifyFakeIOPortRead(PIEMCPU pIemCpu, RTIOPORT Port, uint32_t *pu32Value, size_t cbValue)
6110{
6111 return VERR_INTERNAL_ERROR;
6112}
6113
6114static VBOXSTRICTRC iemVerifyFakeIOPortWrite(PIEMCPU pIemCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue)
6115{
6116 return VERR_INTERNAL_ERROR;
6117}
6118
6119#endif /* !IEM_VERIFICATION_MODE || !IN_RING3 */
6120
6121
6122/**
6123 * Execute one instruction.
6124 *
6125 * @return Strict VBox status code.
6126 * @param pVCpu The current virtual CPU.
6127 */
6128VMMDECL(VBOXSTRICTRC) IEMExecOne(PVMCPU pVCpu)
6129{
6130 PIEMCPU pIemCpu = &pVCpu->iem.s;
6131
6132#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
6133 iemExecVerificationModeSetup(pIemCpu);
6134#endif
6135#ifdef LOG_ENABLED
6136 PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
6137 if (LogIs2Enabled())
6138 {
6139 char szInstr[256];
6140 uint32_t cbInstr = 0;
6141 DBGFR3DisasInstrEx(pVCpu->pVMR3, pVCpu->idCpu, 0, 0,
6142 DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_DEFAULT_MODE,
6143 szInstr, sizeof(szInstr), &cbInstr);
6144
6145 Log2(("**** "
6146 " eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n"
6147 " eip=%08x esp=%08x ebp=%08x iopl=%d\n"
6148 " cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x efl=%08x\n"
6149 " %s\n"
6150 ,
6151 pCtx->eax, pCtx->ebx, pCtx->ecx, pCtx->edx, pCtx->esi, pCtx->edi,
6152 pCtx->eip, pCtx->esp, pCtx->ebp, pCtx->eflags.Bits.u2IOPL,
6153 (RTSEL)pCtx->cs, (RTSEL)pCtx->ss, (RTSEL)pCtx->ds, (RTSEL)pCtx->es,
6154 (RTSEL)pCtx->fs, (RTSEL)pCtx->gs, pCtx->eflags.u,
6155 szInstr));
6156 }
6157#endif
6158
6159 /*
6160 * Do the decoding and emulation.
6161 */
6162 VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pIemCpu);
6163 if (rcStrict != VINF_SUCCESS)
6164 return rcStrict;
6165
6166 uint8_t b; IEM_OPCODE_GET_NEXT_U8(&b);
6167 rcStrict = FNIEMOP_CALL(g_apfnOneByteMap[b]);
6168 if (rcStrict == VINF_SUCCESS)
6169 pIemCpu->cInstructions++;
6170//#ifdef DEBUG
6171// AssertMsg(pIemCpu->offOpcode == cbInstr || rcStrict != VINF_SUCCESS, ("%u %u\n", pIemCpu->offOpcode, cbInstr));
6172//#endif
6173
6174 /* Execute the next instruction as well if a cli, pop ss or
6175 mov ss, Gr has just completed successfully. */
6176 if ( rcStrict == VINF_SUCCESS
6177 && VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
6178 && EMGetInhibitInterruptsPC(pVCpu) == pIemCpu->CTX_SUFF(pCtx)->rip )
6179 {
6180 rcStrict = iemInitDecoderAndPrefetchOpcodes(pIemCpu);
6181 if (rcStrict == VINF_SUCCESS)
6182 {
6183 b; IEM_OPCODE_GET_NEXT_U8(&b);
6184 rcStrict = FNIEMOP_CALL(g_apfnOneByteMap[b]);
6185 if (rcStrict == VINF_SUCCESS)
6186 pIemCpu->cInstructions++;
6187 }
6188 EMSetInhibitInterruptsPC(pVCpu, UINT64_C(0x7777555533331111));
6189 }
6190
6191 /*
6192 * Assert some sanity.
6193 */
6194#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
6195 iemExecVerificationModeCheck(pIemCpu);
6196#endif
6197 return rcStrict;
6198}
6199
6200
6201/**
6202 * Injects a trap, fault, abort, software interrupt or external interrupt.
6203 *
6204 * The parameter list matches TRPMQueryTrapAll pretty closely.
6205 *
6206 * @returns Strict VBox status code.
6207 * @param pVCpu The current virtual CPU.
6208 * @param u8TrapNo The trap number.
6209 * @param enmType What type is it (trap/fault/abort), software
6210 * interrupt or hardware interrupt.
6211 * @param uErrCode The error code if applicable.
6212 * @param uCr2 The CR2 value if applicable.
6213 */
6214VMM_INT_DECL(VBOXSTRICTRC) IEMInjectTrap(PVMCPU pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType, uint16_t uErrCode, RTGCPTR uCr2)
6215{
6216 uint32_t fFlags;
6217 switch (enmType)
6218 {
6219 case TRPM_HARDWARE_INT:
6220 Log(("IEMInjectTrap: %#4x ext\n", u8TrapNo));
6221 fFlags = IEM_XCPT_FLAGS_T_EXT_INT;
6222 uErrCode = uCr2 = 0;
6223 break;
6224
6225 case TRPM_SOFTWARE_INT:
6226 Log(("IEMInjectTrap: %#4x soft\n", u8TrapNo));
6227 fFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
6228 uErrCode = uCr2 = 0;
6229 break;
6230
6231 case TRPM_TRAP:
6232 Log(("IEMInjectTrap: %#4x trap err=%#x cr2=%#RGv\n", u8TrapNo, uErrCode, uCr2));
6233 fFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
6234 if (u8TrapNo == X86_XCPT_PF)
6235 fFlags |= IEM_XCPT_FLAGS_CR2;
6236 switch (u8TrapNo)
6237 {
6238 case X86_XCPT_DF:
6239 case X86_XCPT_TS:
6240 case X86_XCPT_NP:
6241 case X86_XCPT_SS:
6242 case X86_XCPT_PF:
6243 case X86_XCPT_AC:
6244 fFlags |= IEM_XCPT_FLAGS_ERR;
6245 break;
6246 }
6247 break;
6248
6249 IEM_NOT_REACHED_DEFAULT_CASE_RET();
6250 }
6251
6252 return iemRaiseXcptOrInt(&pVCpu->iem.s, 0, u8TrapNo, fFlags, uErrCode, uCr2);
6253}
6254
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