VirtualBox

Changeset 108226 in vbox


Ignore:
Timestamp:
Feb 14, 2025 3:54:48 PM (4 weeks ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
167546
Message:

VMM/IEM: Splitting up IEMAll.cpp. jiraref:VBP-1531

Location:
trunk/src/VBox/VMM
Files:
4 edited
2 copied
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/Makefile.kmk

    r108220 r108226  
    196196        VMMAll/IEMAll.cpp \
    197197        VMMAll/target-x86/IEMAllExec-x86.cpp \
     198        VMMAll/target-x86/IEMAllMem-x86.cpp \
    198199        VMMAll/target-x86/IEMAllXcpt-x86.cpp \
    199200        VMMAll/target-x86/IEMAllHlpFpu-x86.cpp \
     
    941942        VMMAll/IEMAll.cpp \
    942943        VMMAll/target-x86/IEMAllExec-x86.cpp \
     944        VMMAll/target-x86/IEMAllMem-x86.cpp \
    943945        VMMAll/target-x86/IEMAllXcpt-x86.cpp \
    944946        VMMAll/target-x86/IEMAllHlpFpu-x86.cpp \
     
    11581160  VMMAll/IEMAll.cpp_CXXFLAGS                                       += -noover -O2xy
    11591161  VMMAll/target-x86/IEMAllExec-x86.cpp_CXXFLAGS                    += -noover -O2xy
     1162  VMMAll/target-x86/IEMAllMem-x86.cpp_CXXFLAGS                     += -noover -O2xy
    11601163  VMMAll/target-x86/IEMAllXcpt-x86.cpp_CXXFLAGS                    += -noover -O2xy
    11611164  VMMAll/target-x86/IEMAllHlpFpu-x86.cpp_CXXFLAGS                  += -noover -O2xy
     
    11721175  VMMAll/IEMAll.cpp_CXXFLAGS                                       += -O2 -fomit-frame-pointer
    11731176  VMMAll/target-x86/IEMAllExec-x86.cpp_CXXFLAGS                    += -O2 -fomit-frame-pointer
     1177  VMMAll/target-x86/IEMAllMem-x86.cpp_CXXFLAGS                     += -O2 -fomit-frame-pointer
    11741178  VMMAll/target-x86/IEMAllXcpt-x86.cpp_CXXFLAGS                    += -O2 -fomit-frame-pointer
    11751179  VMMAll/target-x86/IEMAllHlpFpu-x86.cpp_CXXFLAGS                  += -O2 -fomit-frame-pointer
  • trunk/src/VBox/VMM/VMMAll/IEMAll.cpp

    r108220 r108226  
    163163
    164164#include "IEMInline.h"
    165 
    166 
    167 /*********************************************************************************************************************************
    168 *   Structures and Typedefs                                                                                                      *
    169 *********************************************************************************************************************************/
    170 /**
    171  * CPU exception classes.
    172  */
    173 typedef enum IEMXCPTCLASS
    174 {
    175     IEMXCPTCLASS_BENIGN,
    176     IEMXCPTCLASS_CONTRIBUTORY,
    177     IEMXCPTCLASS_PAGE_FAULT,
    178     IEMXCPTCLASS_DOUBLE_FAULT
    179 } IEMXCPTCLASS;
     165#ifdef VBOX_VMM_TARGET_X86
     166# include "target-x86/IEMAllTlbInline-x86.h"
     167#endif
    180168
    181169
     
    635623#if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    636624/**
    637  * Helper for doing large page accounting at TLB load time.
    638  */
    639 template<bool const a_fGlobal>
    640 DECL_FORCE_INLINE(void) iemTlbLoadedLargePage(PVMCPUCC pVCpu, IEMTLB *pTlb, RTGCPTR uTagNoRev, bool f2MbLargePages)
    641 {
    642     if (a_fGlobal)
    643         pTlb->cTlbGlobalLargePageCurLoads++;
    644     else
    645         pTlb->cTlbNonGlobalLargePageCurLoads++;
    646 
    647 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    648     RTGCPTR const idxBit = IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + a_fGlobal;
    649     ASMBitSet(pTlb->bmLargePage, idxBit);
    650 # endif
    651 
    652     AssertCompile(IEMTLB_CALC_TAG_NO_REV((RTGCPTR)0x8731U << GUEST_PAGE_SHIFT) == 0x8731U);
    653     uint32_t const                 fMask = (f2MbLargePages ? _2M - 1U : _4M - 1U) >> GUEST_PAGE_SHIFT;
    654     IEMTLB::LARGEPAGERANGE * const pRange = a_fGlobal
    655                                           ? &pTlb->GlobalLargePageRange
    656                                           : &pTlb->NonGlobalLargePageRange;
    657     uTagNoRev &= ~(RTGCPTR)fMask;
    658     if (uTagNoRev < pRange->uFirstTag)
    659         pRange->uFirstTag = uTagNoRev;
    660 
    661     uTagNoRev |= fMask;
    662     if (uTagNoRev > pRange->uLastTag)
    663         pRange->uLastTag = uTagNoRev;
    664 
    665     RT_NOREF_PV(pVCpu);
    666 }
    667 #endif
    668 
    669 
    670 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    671 /**
    672625 * Worker for iemTlbInvalidateAll.
    673626 */
     
    777730
    778731
    779 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    780 
    781 /** @todo graduate this to cdefs.h or asm-mem.h.   */
    782 # ifdef RT_ARCH_ARM64              /** @todo RT_CACHELINE_SIZE is wrong for M1 */
    783 #  undef RT_CACHELINE_SIZE
    784 #  define RT_CACHELINE_SIZE 128
    785 # endif
    786 
    787 # if defined(_MM_HINT_T0) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
    788 #  define MY_PREFETCH(a_pvAddr)     _mm_prefetch((const char *)(a_pvAddr), _MM_HINT_T0)
    789 # elif defined(_MSC_VER) && (defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32))
    790 #  define MY_PREFETCH(a_pvAddr)     __prefetch((a_pvAddr))
    791 # elif defined(__GNUC__) || RT_CLANG_HAS_FEATURE(__builtin_prefetch)
    792 #  define MY_PREFETCH(a_pvAddr)     __builtin_prefetch((a_pvAddr), 0 /*rw*/, 3 /*locality*/)
    793 # else
    794 #  define MY_PREFETCH(a_pvAddr)     ((void)0)
    795 # endif
    796 # if 0
    797 #  undef  MY_PREFETCH
    798 #  define MY_PREFETCH(a_pvAddr)     ((void)0)
    799 # endif
    800 
    801 /** @def MY_PREFETCH_64
    802  * 64 byte prefetch hint, could be more depending on cache line size. */
    803 /** @def MY_PREFETCH_128
    804  * 128 byte prefetch hint. */
    805 /** @def MY_PREFETCH_256
    806  * 256 byte prefetch hint. */
    807 # if RT_CACHELINE_SIZE >= 128
    808     /* 128 byte cache lines */
    809 #  define MY_PREFETCH_64(a_pvAddr)  MY_PREFETCH(a_pvAddr)
    810 #  define MY_PREFETCH_128(a_pvAddr) MY_PREFETCH(a_pvAddr)
    811 #  define MY_PREFETCH_256(a_pvAddr) do { \
    812         MY_PREFETCH(a_pvAddr); \
    813         MY_PREFETCH((uint8_t const *)a_pvAddr + 128); \
    814     } while (0)
    815 # else
    816     /* 64 byte cache lines */
    817 #  define MY_PREFETCH_64(a_pvAddr)  MY_PREFETCH(a_pvAddr)
    818 #  define MY_PREFETCH_128(a_pvAddr) do { \
    819         MY_PREFETCH(a_pvAddr); \
    820         MY_PREFETCH((uint8_t const *)a_pvAddr + 64); \
    821     } while (0)
    822 #  define MY_PREFETCH_256(a_pvAddr) do { \
    823         MY_PREFETCH(a_pvAddr); \
    824         MY_PREFETCH((uint8_t const *)a_pvAddr + 64); \
    825         MY_PREFETCH((uint8_t const *)a_pvAddr + 128); \
    826         MY_PREFETCH((uint8_t const *)a_pvAddr + 192); \
    827     } while (0)
    828 # endif
    829 
    830 template<bool const a_fDataTlb, bool const a_f2MbLargePage, bool const a_fGlobal, bool const a_fNonGlobal>
    831 DECLINLINE(void) iemTlbInvalidateLargePageWorkerInner(PVMCPUCC pVCpu, IEMTLB *pTlb, RTGCPTR GCPtrTag,
    832                                                       RTGCPTR GCPtrInstrBufPcTag) RT_NOEXCEPT
    833 {
    834     IEMTLBTRACE_LARGE_SCAN(pVCpu, a_fGlobal, a_fNonGlobal, a_fDataTlb);
    835     AssertCompile(IEMTLB_ENTRY_COUNT >= 16); /* prefetching + unroll assumption */
    836 
    837     if (a_fGlobal)
    838         pTlb->cTlbInvlPgLargeGlobal += 1;
    839     if (a_fNonGlobal)
    840         pTlb->cTlbInvlPgLargeNonGlobal += 1;
    841 
    842     /*
    843      * Set up the scan.
    844      *
    845      * GCPtrTagMask: A 2MB page consists of 512 4K pages, so a 256 TLB will map
    846      * offset zero and offset 1MB to the same slot pair.  Our GCPtrTag[Globl]
    847      * values are for the range 0-1MB, or slots 0-256.  So, we construct a mask
    848      * that fold large page offsets 1MB-2MB into the 0-1MB range.
    849      *
    850      * For our example with 2MB pages and a 256 entry TLB: 0xfffffffffffffeff
    851      *
    852      * MY_PREFETCH: Hope that prefetching 256 bytes at the time is okay for
    853      * relevant host architectures.
    854      */
    855     /** @todo benchmark this code from the guest side. */
    856     bool const      fPartialScan = IEMTLB_ENTRY_COUNT > (a_f2MbLargePage ? 512 : 1024);
    857 #ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    858     uintptr_t       idxBitmap    = fPartialScan ? IEMTLB_TAG_TO_EVEN_INDEX(GCPtrTag) / 64 : 0;
    859     uintptr_t const idxBitmapEnd = fPartialScan ? idxBitmap + ((a_f2MbLargePage ? 512 : 1024) * 2) / 64
    860                                                 : IEMTLB_ENTRY_COUNT * 2 / 64;
    861 #else
    862     uintptr_t       idxEven      = fPartialScan ? IEMTLB_TAG_TO_EVEN_INDEX(GCPtrTag) : 0;
    863     MY_PREFETCH_256(&pTlb->aEntries[idxEven + !a_fNonGlobal]);
    864     uintptr_t const idxEvenEnd   = fPartialScan ? idxEven + ((a_f2MbLargePage ? 512 : 1024) * 2) : IEMTLB_ENTRY_COUNT * 2;
    865 #endif
    866     RTGCPTR const   GCPtrTagMask = fPartialScan ? ~(RTGCPTR)0
    867                                  : ~(RTGCPTR)(  (RT_BIT_32(a_f2MbLargePage ? 9 : 10) - 1U)
    868                                               & ~(uint32_t)(RT_BIT_32(IEMTLB_ENTRY_COUNT_AS_POWER_OF_TWO) - 1U));
    869 
    870     /*
    871      * Set cbInstrBufTotal to zero if GCPtrInstrBufPcTag is within any of the tag ranges.
    872      * We make ASSUMPTIONS about IEMTLB_CALC_TAG_NO_REV here.
    873      */
    874     AssertCompile(IEMTLB_CALC_TAG_NO_REV((RTGCPTR)0x8731U << GUEST_PAGE_SHIFT) == 0x8731U);
    875     if (   !a_fDataTlb
    876         && GCPtrInstrBufPcTag - GCPtrTag < (a_f2MbLargePage ? 512U : 1024U))
    877         pVCpu->iem.s.cbInstrBufTotal = 0;
    878 
    879     /*
    880      * Combine TAG values with the TLB revisions.
    881      */
    882     RTGCPTR GCPtrTagGlob = a_fGlobal ? GCPtrTag | pTlb->uTlbRevisionGlobal : 0;
    883     if (a_fNonGlobal)
    884         GCPtrTag |= pTlb->uTlbRevision;
    885 
    886     /*
    887      * Do the scanning.
    888      */
    889 #ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    890     uint64_t const bmMask  = a_fGlobal && a_fNonGlobal ? UINT64_MAX
    891                            : a_fGlobal ? UINT64_C(0xaaaaaaaaaaaaaaaa) : UINT64_C(0x5555555555555555);
    892     /* Scan bitmap entries (64 bits at the time): */
    893     for (;;)
    894     {
    895 # if 1
    896         uint64_t bmEntry = pTlb->bmLargePage[idxBitmap] & bmMask;
    897         if (bmEntry)
    898         {
    899             /* Scan the non-zero 64-bit value in groups of 8 bits: */
    900             uint64_t  bmToClear = 0;
    901             uintptr_t idxEven   = idxBitmap * 64;
    902             uint32_t  idxTag    = 0;
    903             for (;;)
    904             {
    905                 if (bmEntry & 0xff)
    906                 {
    907 #  define ONE_PAIR(a_idxTagIter, a_idxEvenIter, a_bmNonGlobal, a_bmGlobal) \
    908                         if (a_fNonGlobal) \
    909                         { \
    910                             if (bmEntry & a_bmNonGlobal) \
    911                             { \
    912                                 Assert(pTlb->aEntries[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE); \
    913                                 if ((pTlb->aEntries[a_idxEvenIter].uTag & GCPtrTagMask) == (GCPtrTag + a_idxTagIter)) \
    914                                 { \
    915                                     IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTag + a_idxTagIter, \
    916                                                                  pTlb->aEntries[a_idxEvenIter].GCPhys, \
    917                                                                  a_idxEvenIter, a_fDataTlb); \
    918                                     pTlb->aEntries[a_idxEvenIter].uTag = 0; \
    919                                     bmToClearSub8 |= a_bmNonGlobal; \
    920                                 } \
    921                             } \
    922                             else \
    923                                 Assert(   !(pTlb->aEntries[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE)\
    924                                        ||    (pTlb->aEntries[a_idxEvenIter].uTag & IEMTLB_REVISION_MASK) \
    925                                           != (GCPtrTag & IEMTLB_REVISION_MASK)); \
    926                         } \
    927                         if (a_fGlobal) \
    928                         { \
    929                             if (bmEntry & a_bmGlobal) \
    930                             {  \
    931                                 Assert(pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE); \
    932                                 if ((pTlb->aEntries[a_idxEvenIter + 1].uTag & GCPtrTagMask) == (GCPtrTagGlob + a_idxTagIter)) \
    933                                 { \
    934                                     IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTagGlob + a_idxTagIter, \
    935                                                                  pTlb->aEntries[a_idxEvenIter + 1].GCPhys, \
    936                                                                  a_idxEvenIter + 1, a_fDataTlb); \
    937                                     pTlb->aEntries[a_idxEvenIter + 1].uTag = 0; \
    938                                     bmToClearSub8 |= a_bmGlobal; \
    939                                 } \
    940                             } \
    941                             else \
    942                                 Assert(   !(pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE)\
    943                                        ||    (pTlb->aEntries[a_idxEvenIter + 1].uTag & IEMTLB_REVISION_MASK) \
    944                                           != (GCPtrTagGlob & IEMTLB_REVISION_MASK)); \
    945                         }
    946                     uint64_t bmToClearSub8 = 0;
    947                     ONE_PAIR(idxTag + 0, idxEven + 0, 0x01, 0x02)
    948                     ONE_PAIR(idxTag + 1, idxEven + 2, 0x04, 0x08)
    949                     ONE_PAIR(idxTag + 2, idxEven + 4, 0x10, 0x20)
    950                     ONE_PAIR(idxTag + 3, idxEven + 6, 0x40, 0x80)
    951                     bmToClear |= bmToClearSub8 << (idxTag * 2);
    952 #  undef ONE_PAIR
    953                 }
    954 
    955                 /* advance to the next 8 bits. */
    956                 bmEntry >>= 8;
    957                 if (!bmEntry)
    958                     break;
    959                 idxEven  += 8;
    960                 idxTag   += 4;
    961             }
    962 
    963             /* Clear the large page flags we covered. */
    964             pTlb->bmLargePage[idxBitmap] &= ~bmToClear;
    965         }
    966 # else
    967         uint64_t const bmEntry = pTlb->bmLargePage[idxBitmap] & bmMask;
    968         if (bmEntry)
    969         {
    970             /* Scan the non-zero 64-bit value completely unrolled: */
    971             uintptr_t const idxEven   = idxBitmap * 64;
    972             uint64_t        bmToClear = 0;
    973 #  define ONE_PAIR(a_idxTagIter, a_idxEvenIter, a_bmNonGlobal, a_bmGlobal) \
    974                 if (a_fNonGlobal) \
    975                 { \
    976                     if (bmEntry & a_bmNonGlobal) \
    977                     { \
    978                         Assert(pTlb->aEntries[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE); \
    979                         if ((pTlb->aEntries[a_idxEvenIter].uTag & GCPtrTagMask) == (GCPtrTag + a_idxTagIter)) \
    980                         { \
    981                             IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTag + a_idxTagIter, \
    982                                                          pTlb->aEntries[a_idxEvenIter].GCPhys, \
    983                                                          a_idxEvenIter, a_fDataTlb); \
    984                             pTlb->aEntries[a_idxEvenIter].uTag = 0; \
    985                             bmToClear |= a_bmNonGlobal; \
    986                         } \
    987                     } \
    988                     else \
    989                         Assert(   !(pTlb->aEntriqes[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE)\
    990                                ||    (pTlb->aEntries[a_idxEvenIter].uTag & IEMTLB_REVISION_MASK) \
    991                                   != (GCPtrTag & IEMTLB_REVISION_MASK)); \
    992                 } \
    993                 if (a_fGlobal) \
    994                 { \
    995                     if (bmEntry & a_bmGlobal) \
    996                     {  \
    997                         Assert(pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE); \
    998                         if ((pTlb->aEntries[a_idxEvenIter + 1].uTag & GCPtrTagMask) == (GCPtrTagGlob + a_idxTagIter)) \
    999                         { \
    1000                             IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTagGlob + a_idxTagIter, \
    1001                                                          pTlb->aEntries[a_idxEvenIter + 1].GCPhys, \
    1002                                                          a_idxEvenIter + 1, a_fDataTlb); \
    1003                             pTlb->aEntries[a_idxEvenIter + 1].uTag = 0; \
    1004                             bmToClear |= a_bmGlobal; \
    1005                         } \
    1006                     } \
    1007                     else \
    1008                         Assert(   !(pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE)\
    1009                                ||    (pTlb->aEntries[a_idxEvenIter + 1].uTag & IEMTLB_REVISION_MASK) \
    1010                                   != (GCPtrTagGlob & IEMTLB_REVISION_MASK)); \
    1011                 } ((void)0)
    1012 #  define FOUR_PAIRS(a_iByte, a_cShift) \
    1013                 ONE_PAIR(0 + a_iByte * 4, idxEven + 0 + a_iByte * 8, UINT64_C(0x01) << a_cShift, UINT64_C(0x02) << a_cShift); \
    1014                 ONE_PAIR(1 + a_iByte * 4, idxEven + 2 + a_iByte * 8, UINT64_C(0x04) << a_cShift, UINT64_C(0x08) << a_cShift); \
    1015                 ONE_PAIR(2 + a_iByte * 4, idxEven + 4 + a_iByte * 8, UINT64_C(0x10) << a_cShift, UINT64_C(0x20) << a_cShift); \
    1016                 ONE_PAIR(3 + a_iByte * 4, idxEven + 6 + a_iByte * 8, UINT64_C(0x40) << a_cShift, UINT64_C(0x80) << a_cShift)
    1017             if (bmEntry & (uint32_t)UINT16_MAX)
    1018             {
    1019                 FOUR_PAIRS(0,  0);
    1020                 FOUR_PAIRS(1,  8);
    1021             }
    1022             if (bmEntry & ((uint32_t)UINT16_MAX << 16))
    1023             {
    1024                 FOUR_PAIRS(2, 16);
    1025                 FOUR_PAIRS(3, 24);
    1026             }
    1027             if (bmEntry & ((uint64_t)UINT16_MAX << 32))
    1028             {
    1029                 FOUR_PAIRS(4, 32);
    1030                 FOUR_PAIRS(5, 40);
    1031             }
    1032             if (bmEntry & ((uint64_t)UINT16_MAX << 16))
    1033             {
    1034                 FOUR_PAIRS(6, 48);
    1035                 FOUR_PAIRS(7, 56);
    1036             }
    1037 #  undef FOUR_PAIRS
    1038 
    1039             /* Clear the large page flags we covered. */
    1040             pTlb->bmLargePage[idxBitmap] &= ~bmToClear;
    1041         }
    1042 # endif
    1043 
    1044         /* advance */
    1045         idxBitmap++;
    1046         if (idxBitmap >= idxBitmapEnd)
    1047             break;
    1048         if (a_fNonGlobal)
    1049             GCPtrTag     += 32;
    1050         if (a_fGlobal)
    1051             GCPtrTagGlob += 32;
    1052     }
    1053 
    1054 #else  /* !IEMTLB_WITH_LARGE_PAGE_BITMAP */
    1055 
    1056     for (; idxEven < idxEvenEnd; idxEven += 8)
    1057     {
    1058 # define ONE_ITERATION(a_idxEvenIter) \
    1059             if (a_fNonGlobal)  \
    1060             { \
    1061                 if ((pTlb->aEntries[a_idxEvenIter].uTag & GCPtrTagMask) == GCPtrTag) \
    1062                 { \
    1063                     if (pTlb->aEntries[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE) \
    1064                     { \
    1065                         IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTag, pTlb->aEntries[a_idxEvenIter].GCPhys, \
    1066                                                      a_idxEvenIter, a_fDataTlb); \
    1067                         pTlb->aEntries[a_idxEvenIter].uTag = 0; \
    1068                     } \
    1069                 } \
    1070                 GCPtrTag++; \
    1071             } \
    1072             \
    1073             if (a_fGlobal) \
    1074             { \
    1075                 if ((pTlb->aEntries[a_idxEvenIter + 1].uTag & GCPtrTagMask) == GCPtrTagGlob) \
    1076                 { \
    1077                     if (pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE) \
    1078                     { \
    1079                         IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTag, pTlb->aEntries[a_idxEvenIter + 1].GCPhys, \
    1080                                                      a_idxEvenIter + 1, a_fDataTlb); \
    1081                         pTlb->aEntries[a_idxEvenIter + 1].uTag = 0; \
    1082                     } \
    1083                 } \
    1084                 GCPtrTagGlob++; \
    1085             }
    1086         if (idxEven < idxEvenEnd - 4)
    1087             MY_PREFETCH_256(&pTlb->aEntries[idxEven +  8 + !a_fNonGlobal]);
    1088         ONE_ITERATION(idxEven)
    1089         ONE_ITERATION(idxEven + 2)
    1090         ONE_ITERATION(idxEven + 4)
    1091         ONE_ITERATION(idxEven + 6)
    1092 # undef ONE_ITERATION
    1093     }
    1094 #endif /* !IEMTLB_WITH_LARGE_PAGE_BITMAP */
    1095 }
    1096 
    1097 template<bool const a_fDataTlb, bool const a_f2MbLargePage>
    1098 DECLINLINE(void) iemTlbInvalidateLargePageWorker(PVMCPUCC pVCpu, IEMTLB *pTlb, RTGCPTR GCPtrTag,
    1099                                                  RTGCPTR GCPtrInstrBufPcTag) RT_NOEXCEPT
    1100 {
    1101     AssertCompile(IEMTLB_CALC_TAG_NO_REV((RTGCPTR)0x8731U << GUEST_PAGE_SHIFT) == 0x8731U);
    1102 
    1103     GCPtrTag &= ~(RTGCPTR)(RT_BIT_64((a_f2MbLargePage ? 21 : 22) - GUEST_PAGE_SHIFT) - 1U);
    1104     if (   GCPtrTag >= pTlb->GlobalLargePageRange.uFirstTag
    1105         && GCPtrTag <= pTlb->GlobalLargePageRange.uLastTag)
    1106     {
    1107         if (   GCPtrTag < pTlb->NonGlobalLargePageRange.uFirstTag
    1108             || GCPtrTag > pTlb->NonGlobalLargePageRange.uLastTag)
    1109             iemTlbInvalidateLargePageWorkerInner<a_fDataTlb, a_f2MbLargePage, true, false>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag);
    1110         else
    1111             iemTlbInvalidateLargePageWorkerInner<a_fDataTlb, a_f2MbLargePage, true, true>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag);
    1112     }
    1113     else if (   GCPtrTag < pTlb->NonGlobalLargePageRange.uFirstTag
    1114              || GCPtrTag > pTlb->NonGlobalLargePageRange.uLastTag)
    1115     {
    1116         /* Large pages aren't as likely in the non-global TLB half. */
    1117         IEMTLBTRACE_LARGE_SCAN(pVCpu, false, false, a_fDataTlb);
    1118     }
    1119     else
    1120         iemTlbInvalidateLargePageWorkerInner<a_fDataTlb, a_f2MbLargePage, false, true>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag);
    1121 }
    1122 
    1123 template<bool const a_fDataTlb>
    1124 DECLINLINE(void) iemTlbInvalidatePageWorker(PVMCPUCC pVCpu, IEMTLB *pTlb, RTGCPTR GCPtrTag, uintptr_t idxEven) RT_NOEXCEPT
    1125 {
    1126     pTlb->cTlbInvlPg += 1;
    1127 
    1128     /*
    1129      * Flush the entry pair.
    1130      */
    1131     if (pTlb->aEntries[idxEven].uTag == (GCPtrTag | pTlb->uTlbRevision))
    1132     {
    1133         IEMTLBTRACE_EVICT_SLOT(pVCpu, GCPtrTag, pTlb->aEntries[idxEven].GCPhys, idxEven, a_fDataTlb);
    1134         pTlb->aEntries[idxEven].uTag = 0;
    1135         if (!a_fDataTlb && GCPtrTag == IEMTLB_CALC_TAG_NO_REV(pVCpu->iem.s.uInstrBufPc))
    1136             pVCpu->iem.s.cbInstrBufTotal = 0;
    1137     }
    1138     if (pTlb->aEntries[idxEven + 1].uTag == (GCPtrTag | pTlb->uTlbRevisionGlobal))
    1139     {
    1140         IEMTLBTRACE_EVICT_SLOT(pVCpu, GCPtrTag, pTlb->aEntries[idxEven + 1].GCPhys, idxEven + 1, a_fDataTlb);
    1141         pTlb->aEntries[idxEven + 1].uTag = 0;
    1142         if (!a_fDataTlb && GCPtrTag == IEMTLB_CALC_TAG_NO_REV(pVCpu->iem.s.uInstrBufPc))
    1143             pVCpu->iem.s.cbInstrBufTotal = 0;
    1144     }
    1145 
    1146     /*
    1147      * If there are (or has been) large pages in the TLB, we must check if the
    1148      * address being flushed may involve one of those, as then we'd have to
    1149      * scan for entries relating to the same page and flush those as well.
    1150      */
    1151 # if 0 /** @todo do accurate counts or currently loaded large stuff and we can use those  */
    1152     if (pTlb->cTlbGlobalLargePageCurLoads || pTlb->cTlbNonGlobalLargePageCurLoads)
    1153 # else
    1154     if (pTlb->GlobalLargePageRange.uLastTag || pTlb->NonGlobalLargePageRange.uLastTag)
    1155 # endif
    1156     {
    1157         RTGCPTR const GCPtrInstrBufPcTag = a_fDataTlb ? 0 : IEMTLB_CALC_TAG_NO_REV(pVCpu->iem.s.uInstrBufPc);
    1158         if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE)
    1159             iemTlbInvalidateLargePageWorker<a_fDataTlb, true>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag);
    1160         else
    1161             iemTlbInvalidateLargePageWorker<a_fDataTlb, false>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag);
    1162     }
    1163 }
    1164 
    1165 #endif /* defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) */
    1166 
    1167732/**
    1168733 * Invalidates a page in the TLBs.
     
    1204769 * @thread EMT(pVCpu)
    1205770 */
    1206 static void IEMTlbInvalidateAllPhysicalSlow(PVMCPUCC pVCpu)
    1207 {
    1208     Log10(("IEMTlbInvalidateAllPhysicalSlow\n"));
     771void iemTlbInvalidateAllPhysicalSlow(PVMCPUCC pVCpu) RT_NOEXCEPT
     772{
     773    Log10(("iemTlbInvalidateAllPhysicalSlow\n"));
    1209774    ASMAtomicWriteU64(&pVCpu->iem.s.CodeTlb.uTlbPhysRev, IEMTLB_PHYS_REV_INCR * 2);
    1210775    ASMAtomicWriteU64(&pVCpu->iem.s.DataTlb.uTlbPhysRev, IEMTLB_PHYS_REV_INCR * 2);
     
    1265830    }
    1266831    else
    1267         IEMTlbInvalidateAllPhysicalSlow(pVCpu);
     832        iemTlbInvalidateAllPhysicalSlow(pVCpu);
    1268833#else
    1269834    NOREF(pVCpu);
     
    1307872        else
    1308873        {
    1309             IEMTlbInvalidateAllPhysicalSlow(pVCpu);
     874            iemTlbInvalidateAllPhysicalSlow(pVCpu);
    1310875            continue;
    1311876        }
     
    14831048                { /* likely */ }
    14841049                else
    1485                     IEMTlbInvalidateAllPhysicalSlow(pVCpu);
     1050                    iemTlbInvalidateAllPhysicalSlow(pVCpu);
    14861051                pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK;
    14871052                int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.CodeTlb.uTlbPhysRev,
     
    15561121            { /* likely */ }
    15571122            else
    1558                 IEMTlbInvalidateAllPhysicalSlow(pVCpu);
     1123                iemTlbInvalidateAllPhysicalSlow(pVCpu);
    15591124            Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_GCPHYS2PTR_MASK));
    15601125            rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhysPg, &pVCpu->iem.s.CodeTlb.uTlbPhysRev,
     
    24271992#undef  LOG_GROUP
    24281993#define LOG_GROUP LOG_GROUP_IEM_MEM
    2429 
    2430 /**
    2431  * Applies the segment limit, base and attributes.
    2432  *
    2433  * This may raise a \#GP or \#SS.
    2434  *
    2435  * @returns VBox strict status code.
    2436  *
    2437  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2438  * @param   fAccess             The kind of access which is being performed.
    2439  * @param   iSegReg             The index of the segment register to apply.
    2440  *                              This is UINT8_MAX if none (for IDT, GDT, LDT,
    2441  *                              TSS, ++).
    2442  * @param   cbMem               The access size.
    2443  * @param   pGCPtrMem           Pointer to the guest memory address to apply
    2444  *                              segmentation to.  Input and output parameter.
    2445  */
    2446 VBOXSTRICTRC iemMemApplySegment(PVMCPUCC pVCpu, uint32_t fAccess, uint8_t iSegReg, size_t cbMem, PRTGCPTR pGCPtrMem) RT_NOEXCEPT
    2447 {
    2448     if (iSegReg == UINT8_MAX)
    2449         return VINF_SUCCESS;
    2450 
    2451     IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
    2452     PCPUMSELREGHID pSel = iemSRegGetHid(pVCpu, iSegReg);
    2453     switch (IEM_GET_CPU_MODE(pVCpu))
    2454     {
    2455         case IEMMODE_16BIT:
    2456         case IEMMODE_32BIT:
    2457         {
    2458             RTGCPTR32 GCPtrFirst32 = (RTGCPTR32)*pGCPtrMem;
    2459             RTGCPTR32 GCPtrLast32  = GCPtrFirst32 + (uint32_t)cbMem - 1;
    2460 
    2461             if (   pSel->Attr.n.u1Present
    2462                 && !pSel->Attr.n.u1Unusable)
    2463             {
    2464                 Assert(pSel->Attr.n.u1DescType);
    2465                 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
    2466                 {
    2467                     if (   (fAccess & IEM_ACCESS_TYPE_WRITE)
    2468                         && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE) )
    2469                         return iemRaiseSelectorInvalidAccess(pVCpu, iSegReg, fAccess);
    2470 
    2471                     if (!IEM_IS_REAL_OR_V86_MODE(pVCpu))
    2472                     {
    2473                         /** @todo CPL check. */
    2474                     }
    2475 
    2476                     /*
    2477                      * There are two kinds of data selectors, normal and expand down.
    2478                      */
    2479                     if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
    2480                     {
    2481                         if (   GCPtrFirst32 > pSel->u32Limit
    2482                             || GCPtrLast32  > pSel->u32Limit) /* yes, in real mode too (since 80286). */
    2483                             return iemRaiseSelectorBounds(pVCpu, iSegReg, fAccess);
    2484                     }
    2485                     else
    2486                     {
    2487                        /*
    2488                         * The upper boundary is defined by the B bit, not the G bit!
    2489                         */
    2490                        if (   GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
    2491                            || GCPtrLast32  > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
    2492                           return iemRaiseSelectorBounds(pVCpu, iSegReg, fAccess);
    2493                     }
    2494                     *pGCPtrMem = GCPtrFirst32 += (uint32_t)pSel->u64Base;
    2495                 }
    2496                 else
    2497                 {
    2498                     /*
    2499                      * Code selector and usually be used to read thru, writing is
    2500                      * only permitted in real and V8086 mode.
    2501                      */
    2502                     if (   (   (fAccess & IEM_ACCESS_TYPE_WRITE)
    2503                             || (   (fAccess & IEM_ACCESS_TYPE_READ)
    2504                                && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)) )
    2505                         && !IEM_IS_REAL_OR_V86_MODE(pVCpu) )
    2506                         return iemRaiseSelectorInvalidAccess(pVCpu, iSegReg, fAccess);
    2507 
    2508                     if (   GCPtrFirst32 > pSel->u32Limit
    2509                         || GCPtrLast32  > pSel->u32Limit) /* yes, in real mode too (since 80286). */
    2510                         return iemRaiseSelectorBounds(pVCpu, iSegReg, fAccess);
    2511 
    2512                     if (!IEM_IS_REAL_OR_V86_MODE(pVCpu))
    2513                     {
    2514                         /** @todo CPL check. */
    2515                     }
    2516 
    2517                     *pGCPtrMem  = GCPtrFirst32 += (uint32_t)pSel->u64Base;
    2518                 }
    2519             }
    2520             else
    2521                 return iemRaiseGeneralProtectionFault0(pVCpu);
    2522             return VINF_SUCCESS;
    2523         }
    2524 
    2525         case IEMMODE_64BIT:
    2526         {
    2527             RTGCPTR GCPtrMem = *pGCPtrMem;
    2528             if (iSegReg == X86_SREG_GS || iSegReg == X86_SREG_FS)
    2529                 *pGCPtrMem = GCPtrMem + pSel->u64Base;
    2530 
    2531             Assert(cbMem >= 1);
    2532             if (RT_LIKELY(X86_IS_CANONICAL(GCPtrMem) && X86_IS_CANONICAL(GCPtrMem + cbMem - 1)))
    2533                 return VINF_SUCCESS;
    2534             /** @todo We should probably raise \#SS(0) here if segment is SS; see AMD spec.
    2535              *        4.12.2 "Data Limit Checks in 64-bit Mode". */
    2536             return iemRaiseGeneralProtectionFault0(pVCpu);
    2537         }
    2538 
    2539         default:
    2540             AssertFailedReturn(VERR_IEM_IPE_7);
    2541     }
    2542 }
    2543 
    2544 
    2545 /**
    2546  * Translates a virtual address to a physical physical address and checks if we
    2547  * can access the page as specified.
    2548  *
    2549  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2550  * @param   GCPtrMem            The virtual address.
    2551  * @param   cbAccess            The access size, for raising \#PF correctly for
    2552  *                              FXSAVE and such.
    2553  * @param   fAccess             The intended access.
    2554  * @param   pGCPhysMem          Where to return the physical address.
    2555  */
    2556 VBOXSTRICTRC iemMemPageTranslateAndCheckAccess(PVMCPUCC pVCpu, RTGCPTR GCPtrMem, uint32_t cbAccess,
    2557                                                uint32_t fAccess, PRTGCPHYS pGCPhysMem) RT_NOEXCEPT
    2558 {
    2559     /** @todo Need a different PGM interface here.  We're currently using
    2560      *        generic / REM interfaces. this won't cut it for R0. */
    2561     /** @todo If/when PGM handles paged real-mode, we can remove the hack in
    2562      *        iemSvmWorldSwitch/iemVmxWorldSwitch to work around raising a page-fault
    2563      *        here. */
    2564     Assert(!(fAccess & IEM_ACCESS_TYPE_EXEC));
    2565     PGMPTWALKFAST WalkFast;
    2566     AssertCompile(IEM_ACCESS_TYPE_READ  == PGMQPAGE_F_READ);
    2567     AssertCompile(IEM_ACCESS_TYPE_WRITE == PGMQPAGE_F_WRITE);
    2568     AssertCompile(IEM_ACCESS_TYPE_EXEC  == PGMQPAGE_F_EXECUTE);
    2569     AssertCompile(X86_CR0_WP            == PGMQPAGE_F_CR0_WP0);
    2570     uint32_t fQPage = (fAccess & (PGMQPAGE_F_READ | IEM_ACCESS_TYPE_WRITE | PGMQPAGE_F_EXECUTE))
    2571                     | (((uint32_t)pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP) ^ X86_CR0_WP);
    2572     if (IEM_GET_CPL(pVCpu) == 3 && !(fAccess & IEM_ACCESS_WHAT_SYS))
    2573         fQPage |= PGMQPAGE_F_USER_MODE;
    2574     int rc = PGMGstQueryPageFast(pVCpu, GCPtrMem, fQPage, &WalkFast);
    2575     if (RT_SUCCESS(rc))
    2576     {
    2577         Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
    2578 
    2579         /* If the page is writable and does not have the no-exec bit set, all
    2580            access is allowed.  Otherwise we'll have to check more carefully... */
    2581         Assert(   (WalkFast.fEffective & (X86_PTE_RW | X86_PTE_US | X86_PTE_PAE_NX)) == (X86_PTE_RW | X86_PTE_US)
    2582                || (   (   !(fAccess & IEM_ACCESS_TYPE_WRITE)
    2583                        || (WalkFast.fEffective & X86_PTE_RW)
    2584                        || (   (    IEM_GET_CPL(pVCpu) != 3
    2585                                || (fAccess & IEM_ACCESS_WHAT_SYS))
    2586                            && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)) )
    2587                     && (   (WalkFast.fEffective & X86_PTE_US)
    2588                         || IEM_GET_CPL(pVCpu) != 3
    2589                         || (fAccess & IEM_ACCESS_WHAT_SYS) )
    2590                     && (   !(fAccess & IEM_ACCESS_TYPE_EXEC)
    2591                         || !(WalkFast.fEffective & X86_PTE_PAE_NX)
    2592                         || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE) )
    2593                   )
    2594               );
    2595 
    2596         /* PGMGstQueryPageFast sets the A & D bits. */
    2597         /** @todo testcase: check when A and D bits are actually set by the CPU.  */
    2598         Assert(!(~WalkFast.fEffective & (fAccess & IEM_ACCESS_TYPE_WRITE ? X86_PTE_D | X86_PTE_A : X86_PTE_A)));
    2599 
    2600         *pGCPhysMem = WalkFast.GCPhys;
    2601         return VINF_SUCCESS;
    2602     }
    2603 
    2604     LogEx(LOG_GROUP_IEM,("iemMemPageTranslateAndCheckAccess: GCPtrMem=%RGv - failed to fetch page -> #PF\n", GCPtrMem));
    2605     /** @todo Check unassigned memory in unpaged mode. */
    2606 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    2607     if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    2608         IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
    2609 #endif
    2610     *pGCPhysMem = NIL_RTGCPHYS;
    2611     return iemRaisePageFault(pVCpu, GCPtrMem, cbAccess, fAccess, rc);
    2612 }
    26131994
    26141995#if 0 /*unused*/
     
    28832264/**
    28842265 * Helper for iemMemMap, iemMemMapJmp and iemMemBounceBufferMapCrossPage.
     2266 * @todo duplicated
    28852267 */
    28862268DECL_FORCE_INLINE(uint32_t)
     
    28972279 * iemMemMap worker that deals with a request crossing pages.
    28982280 */
    2899 static VBOXSTRICTRC
    2900 iemMemBounceBufferMapCrossPage(PVMCPUCC pVCpu, int iMemMap, void **ppvMem, uint8_t *pbUnmapInfo,
    2901                                size_t cbMem, RTGCPTR GCPtrFirst, uint32_t fAccess)
     2281VBOXSTRICTRC iemMemBounceBufferMapCrossPage(PVMCPUCC pVCpu, int iMemMap, void **ppvMem, uint8_t *pbUnmapInfo,
     2282                                            size_t cbMem, RTGCPTR GCPtrFirst, uint32_t fAccess) RT_NOEXCEPT
    29022283{
    29032284    STAM_COUNTER_INC(&pVCpu->iem.s.StatMemBounceBufferCrossPage);
     
    30502431 * iemMemMap woker that deals with iemMemPageMap failures.
    30512432 */
    3052 static VBOXSTRICTRC iemMemBounceBufferMapPhys(PVMCPUCC pVCpu, unsigned iMemMap, void **ppvMem, uint8_t *pbUnmapInfo, size_t cbMem,
    3053                                               RTGCPHYS GCPhysFirst, uint32_t fAccess, VBOXSTRICTRC rcMap)
     2433VBOXSTRICTRC iemMemBounceBufferMapPhys(PVMCPUCC pVCpu, unsigned iMemMap, void **ppvMem, uint8_t *pbUnmapInfo, size_t cbMem,
     2434                                       RTGCPHYS GCPhysFirst, uint32_t fAccess, VBOXSTRICTRC rcMap) RT_NOEXCEPT
    30542435{
    30552436    STAM_COUNTER_INC(&pVCpu->iem.s.StatMemBounceBufferMapPhys);
     
    31372518
    31382519/**
    3139  * Maps the specified guest memory for the given kind of access.
    3140  *
    3141  * This may be using bounce buffering of the memory if it's crossing a page
    3142  * boundary or if there is an access handler installed for any of it.  Because
    3143  * of lock prefix guarantees, we're in for some extra clutter when this
    3144  * happens.
    3145  *
    3146  * This may raise a \#GP, \#SS, \#PF or \#AC.
    3147  *
    3148  * @returns VBox strict status code.
    3149  *
    3150  * @param   pVCpu       The cross context virtual CPU structure of the calling thread.
    3151  * @param   ppvMem      Where to return the pointer to the mapped memory.
    3152  * @param   pbUnmapInfo Where to return unmap info to be passed to
    3153  *                      iemMemCommitAndUnmap or iemMemRollbackAndUnmap when
    3154  *                      done.
    3155  * @param   cbMem       The number of bytes to map.  This is usually 1, 2, 4, 6,
    3156  *                      8, 12, 16, 32 or 512.  When used by string operations
    3157  *                      it can be up to a page.
    3158  * @param   iSegReg     The index of the segment register to use for this
    3159  *                      access.  The base and limits are checked. Use UINT8_MAX
    3160  *                      to indicate that no segmentation is required (for IDT,
    3161  *                      GDT and LDT accesses).
    3162  * @param   GCPtrMem    The address of the guest memory.
    3163  * @param   fAccess     How the memory is being accessed.  The
    3164  *                      IEM_ACCESS_TYPE_XXX part is used to figure out how to
    3165  *                      map the memory, while the IEM_ACCESS_WHAT_XXX part is
    3166  *                      used when raising exceptions.  The IEM_ACCESS_ATOMIC and
    3167  *                      IEM_ACCESS_PARTIAL_WRITE bits are also allowed to be
    3168  *                      set.
    3169  * @param   uAlignCtl   Alignment control:
    3170  *                          - Bits 15:0 is the alignment mask.
    3171  *                          - Bits 31:16 for flags like IEM_MEMMAP_F_ALIGN_GP,
    3172  *                            IEM_MEMMAP_F_ALIGN_SSE, and
    3173  *                            IEM_MEMMAP_F_ALIGN_GP_OR_AC.
    3174  *                      Pass zero to skip alignment.
    3175  */
    3176 VBOXSTRICTRC iemMemMap(PVMCPUCC pVCpu, void **ppvMem, uint8_t *pbUnmapInfo, size_t cbMem, uint8_t iSegReg, RTGCPTR GCPtrMem,
    3177                        uint32_t fAccess, uint32_t uAlignCtl) RT_NOEXCEPT
    3178 {
    3179     STAM_COUNTER_INC(&pVCpu->iem.s.StatMemMapNoJmp);
    3180 
    3181     /*
    3182      * Check the input and figure out which mapping entry to use.
    3183      */
    3184     Assert(cbMem <= sizeof(pVCpu->iem.s.aBounceBuffers[0]));
    3185     Assert(   cbMem <= 64 || cbMem == 512 || cbMem == 256 || cbMem == 108 || cbMem == 104 || cbMem == 102 || cbMem == 94
    3186            || (iSegReg == UINT8_MAX && uAlignCtl == 0 && fAccess == IEM_ACCESS_DATA_R /* for the CPUID logging interface */) );
    3187     Assert(!(fAccess & ~(IEM_ACCESS_TYPE_MASK | IEM_ACCESS_WHAT_MASK | IEM_ACCESS_ATOMIC | IEM_ACCESS_PARTIAL_WRITE)));
    3188     Assert(pVCpu->iem.s.cActiveMappings < RT_ELEMENTS(pVCpu->iem.s.aMemMappings));
    3189 
    3190     unsigned iMemMap = pVCpu->iem.s.iNextMapping;
    3191     if (   iMemMap >= RT_ELEMENTS(pVCpu->iem.s.aMemMappings)
    3192         || pVCpu->iem.s.aMemMappings[iMemMap].fAccess != IEM_ACCESS_INVALID)
    3193     {
    3194         iMemMap = iemMemMapFindFree(pVCpu);
    3195         AssertLogRelMsgReturn(iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings),
    3196                               ("active=%d fAccess[0] = {%#x, %#x, %#x}\n", pVCpu->iem.s.cActiveMappings,
    3197                                pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemMappings[1].fAccess,
    3198                                pVCpu->iem.s.aMemMappings[2].fAccess),
    3199                               VERR_IEM_IPE_9);
    3200     }
    3201 
    3202     /*
    3203      * Map the memory, checking that we can actually access it.  If something
    3204      * slightly complicated happens, fall back on bounce buffering.
    3205      */
    3206     VBOXSTRICTRC rcStrict = iemMemApplySegment(pVCpu, fAccess, iSegReg, cbMem, &GCPtrMem);
    3207     if (rcStrict == VINF_SUCCESS)
    3208     { /* likely */ }
    3209     else
    3210         return rcStrict;
    3211 
    3212     if ((GCPtrMem & GUEST_PAGE_OFFSET_MASK) + cbMem <= GUEST_PAGE_SIZE) /* Crossing a page boundary? */
    3213     { /* likely */ }
    3214     else
    3215         return iemMemBounceBufferMapCrossPage(pVCpu, iMemMap, ppvMem, pbUnmapInfo, cbMem, GCPtrMem, fAccess);
    3216 
    3217     /*
    3218      * Alignment check.
    3219      */
    3220     if ( (GCPtrMem & (uAlignCtl & UINT16_MAX)) == 0 )
    3221     { /* likelyish */ }
    3222     else
    3223     {
    3224         /* Misaligned access. */
    3225         if ((fAccess & IEM_ACCESS_WHAT_MASK) != IEM_ACCESS_WHAT_SYS)
    3226         {
    3227             if (   !(uAlignCtl & IEM_MEMMAP_F_ALIGN_GP)
    3228                 || (   (uAlignCtl & IEM_MEMMAP_F_ALIGN_SSE)
    3229                     && (pVCpu->cpum.GstCtx.XState.x87.MXCSR & X86_MXCSR_MM)) )
    3230             {
    3231                 AssertCompile(X86_CR0_AM == X86_EFL_AC);
    3232 
    3233                 if (!iemMemAreAlignmentChecksEnabled(pVCpu))
    3234                 { /* likely */ }
    3235                 else
    3236                     return iemRaiseAlignmentCheckException(pVCpu);
    3237             }
    3238             else if (   (uAlignCtl & IEM_MEMMAP_F_ALIGN_GP_OR_AC)
    3239                      && (GCPtrMem & 3) /* The value 4 matches 10980xe's FXSAVE and helps make bs3-cpu-basic2 work. */
    3240                     /** @todo may only apply to 2, 4 or 8 byte misalignments depending on the CPU
    3241                      * implementation. See FXSAVE/FRSTOR/XSAVE/XRSTOR/++.  Using 4 for now as
    3242                      * that's what FXSAVE does on a 10980xe. */
    3243                      && iemMemAreAlignmentChecksEnabled(pVCpu))
    3244                 return iemRaiseAlignmentCheckException(pVCpu);
    3245             else
    3246                 return iemRaiseGeneralProtectionFault0(pVCpu);
    3247         }
    3248 
    3249 #if (defined(RT_ARCH_AMD64) && defined(RT_OS_LINUX)) || defined(RT_ARCH_ARM64)
    3250         /* If the access is atomic there are host platform alignmnet restrictions
    3251            we need to conform with. */
    3252         if (   !(fAccess & IEM_ACCESS_ATOMIC)
    3253 # if defined(RT_ARCH_AMD64)
    3254             || (64U - (GCPtrMem & 63U) >= cbMem) /* split-lock detection. ASSUMES 64 byte cache line. */
    3255 # elif defined(RT_ARCH_ARM64)
    3256             || (16U - (GCPtrMem & 15U) >= cbMem) /* LSE2 allows atomics anywhere within a 16 byte sized & aligned block. */
    3257 # else
    3258 #  error port me
    3259 # endif
    3260            )
    3261         { /* okay */ }
    3262         else
    3263         {
    3264             LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv LB %u - misaligned atomic fallback.\n", GCPtrMem, cbMem));
    3265             pVCpu->iem.s.cMisalignedAtomics += 1;
    3266             return VINF_EM_EMULATE_SPLIT_LOCK;
    3267         }
    3268 #endif
    3269     }
    3270 
    3271 #ifdef IEM_WITH_DATA_TLB
    3272     Assert(!(fAccess & IEM_ACCESS_TYPE_EXEC));
    3273 
    3274     /*
    3275      * Get the TLB entry for this page and check PT flags.
    3276      *
    3277      * We reload the TLB entry if we need to set the dirty bit (accessed
    3278      * should in theory always be set).
    3279      */
    3280     uint8_t           *pbMem     = NULL;
    3281     uint64_t const     uTagNoRev = IEMTLB_CALC_TAG_NO_REV(GCPtrMem);
    3282     PIEMTLBENTRY       pTlbe     = IEMTLB_TAG_TO_EVEN_ENTRY(&pVCpu->iem.s.DataTlb, uTagNoRev);
    3283     uint64_t const     fTlbeAD   = IEMTLBE_F_PT_NO_ACCESSED | (fAccess & IEM_ACCESS_TYPE_WRITE ? IEMTLBE_F_PT_NO_DIRTY : 0);
    3284     if (   (   pTlbe->uTag               == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevision)
    3285             && !(pTlbe->fFlagsAndPhysRev & fTlbeAD) )
    3286         || (   (pTlbe = pTlbe + 1)->uTag == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevisionGlobal)
    3287             && !(pTlbe->fFlagsAndPhysRev & fTlbeAD) ) )
    3288     {
    3289 # ifdef IEM_WITH_TLB_STATISTICS
    3290         pVCpu->iem.s.DataTlb.cTlbCoreHits++;
    3291 # endif
    3292 
    3293         /* If the page is either supervisor only or non-writable, we need to do
    3294            more careful access checks. */
    3295         if (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_USER | IEMTLBE_F_PT_NO_WRITE))
    3296         {
    3297             /* Write to read only memory? */
    3298             if (   (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_WRITE)
    3299                 && (fAccess & IEM_ACCESS_TYPE_WRITE)
    3300                 && (   (    IEM_GET_CPL(pVCpu) == 3
    3301                         && !(fAccess & IEM_ACCESS_WHAT_SYS))
    3302                     || (pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)))
    3303             {
    3304                 LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - read-only page -> #PF\n", GCPtrMem));
    3305                 return iemRaisePageFault(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess & ~IEM_ACCESS_TYPE_READ, VERR_ACCESS_DENIED);
    3306             }
    3307 
    3308             /* Kernel memory accessed by userland? */
    3309             if (   (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER)
    3310                 && IEM_GET_CPL(pVCpu) == 3
    3311                 && !(fAccess & IEM_ACCESS_WHAT_SYS))
    3312             {
    3313                 LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - user access to kernel page -> #PF\n", GCPtrMem));
    3314                 return iemRaisePageFault(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, VERR_ACCESS_DENIED);
    3315             }
    3316         }
    3317 
    3318         /* Look up the physical page info if necessary. */
    3319         if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pVCpu->iem.s.DataTlb.uTlbPhysRev)
    3320 # ifdef IN_RING3
    3321             pbMem = pTlbe->pbMappingR3;
    3322 # else
    3323             pbMem = NULL;
    3324 # endif
    3325         else
    3326         {
    3327             if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR))
    3328             { /* likely */ }
    3329             else
    3330                 IEMTlbInvalidateAllPhysicalSlow(pVCpu);
    3331             pTlbe->pbMappingR3       = NULL;
    3332             pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK;
    3333             int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
    3334                                                 &pbMem, &pTlbe->fFlagsAndPhysRev);
    3335             AssertRCReturn(rc, rc);
    3336 # ifdef IN_RING3
    3337             pTlbe->pbMappingR3 = pbMem;
    3338 # endif
    3339         }
    3340     }
    3341     else
    3342     {
    3343         pVCpu->iem.s.DataTlb.cTlbCoreMisses++;
    3344 
    3345         /* This page table walking will set A bits as required by the access while performing the walk.
    3346            ASSUMES these are set when the address is translated rather than on commit... */
    3347         /** @todo testcase: check when A bits are actually set by the CPU for code.  */
    3348         PGMPTWALKFAST WalkFast;
    3349         AssertCompile(IEM_ACCESS_TYPE_READ  == PGMQPAGE_F_READ);
    3350         AssertCompile(IEM_ACCESS_TYPE_WRITE == PGMQPAGE_F_WRITE);
    3351         AssertCompile(IEM_ACCESS_TYPE_EXEC  == PGMQPAGE_F_EXECUTE);
    3352         AssertCompile(X86_CR0_WP            == PGMQPAGE_F_CR0_WP0);
    3353         uint32_t fQPage = (fAccess & (PGMQPAGE_F_READ | IEM_ACCESS_TYPE_WRITE | PGMQPAGE_F_EXECUTE))
    3354                         | (((uint32_t)pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP) ^ X86_CR0_WP);
    3355         if (IEM_GET_CPL(pVCpu) == 3 && !(fAccess & IEM_ACCESS_WHAT_SYS))
    3356             fQPage |= PGMQPAGE_F_USER_MODE;
    3357         int rc = PGMGstQueryPageFast(pVCpu, GCPtrMem, fQPage, &WalkFast);
    3358         if (RT_SUCCESS(rc))
    3359             Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
    3360         else
    3361         {
    3362             LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - failed to fetch page -> #PF\n", GCPtrMem));
    3363 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    3364             if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    3365                 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
    3366 # endif
    3367             return iemRaisePageFault(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, rc);
    3368         }
    3369 
    3370         uint32_t fDataBps;
    3371         if (   RT_LIKELY(!(pVCpu->iem.s.fExec & IEM_F_PENDING_BRK_DATA))
    3372             || RT_LIKELY(!(fDataBps = iemMemCheckDataBreakpoint(pVCpu->CTX_SUFF(pVM), pVCpu, GCPtrMem, cbMem, fAccess))))
    3373         {
    3374             if (   !(WalkFast.fEffective & PGM_PTATTRS_G_MASK)
    3375                 || IEM_GET_CPL(pVCpu) != 0) /* optimization: Only use the PTE.G=1 entries in ring-0. */
    3376             {
    3377                 pTlbe--;
    3378                 pTlbe->uTag         = uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevision;
    3379                 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE)
    3380                     iemTlbLoadedLargePage<false>(pVCpu, &pVCpu->iem.s.DataTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE));
    3381 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    3382                 else
    3383                     ASMBitClear(pVCpu->iem.s.DataTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev));
    3384 # endif
    3385             }
    3386             else
    3387             {
    3388                 pVCpu->iem.s.DataTlb.cTlbCoreGlobalLoads++;
    3389                 pTlbe->uTag         = uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevisionGlobal;
    3390                 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE)
    3391                     iemTlbLoadedLargePage<true>(pVCpu, &pVCpu->iem.s.DataTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE));
    3392 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    3393                 else
    3394                     ASMBitClear(pVCpu->iem.s.DataTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + 1);
    3395 # endif
    3396             }
    3397         }
    3398         else
    3399         {
    3400             /* If we hit a data breakpoint, we use a dummy TLBE to force all accesses
    3401                to the page with the data access breakpoint armed on it to pass thru here. */
    3402             if (fDataBps > 1)
    3403                 LogEx(LOG_GROUP_IEM, ("iemMemMap: Data breakpoint: fDataBps=%#x for %RGv LB %zx; fAccess=%#x cs:rip=%04x:%08RX64\n",
    3404                                       fDataBps, GCPtrMem, cbMem, fAccess, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    3405             pVCpu->cpum.GstCtx.eflags.uBoth |= fDataBps & (CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK);
    3406             pTlbe = &pVCpu->iem.s.DataBreakpointTlbe;
    3407             pTlbe->uTag = uTagNoRev;
    3408         }
    3409         pTlbe->fFlagsAndPhysRev = (~WalkFast.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A) /* skipping NX */)
    3410                                 | (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE);
    3411         RTGCPHYS const GCPhysPg = WalkFast.GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
    3412         pTlbe->GCPhys           = GCPhysPg;
    3413         pTlbe->pbMappingR3      = NULL;
    3414         Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED));
    3415         Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_DIRTY) || !(fAccess & IEM_ACCESS_TYPE_WRITE));
    3416         Assert(   !(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_WRITE)
    3417                || !(fAccess & IEM_ACCESS_TYPE_WRITE)
    3418                || (fQPage & (PGMQPAGE_F_CR0_WP0 | PGMQPAGE_F_USER_MODE)) == PGMQPAGE_F_CR0_WP0);
    3419         Assert(   !(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER)
    3420                || IEM_GET_CPL(pVCpu) != 3
    3421                || (fAccess & IEM_ACCESS_WHAT_SYS));
    3422 
    3423         if (pTlbe != &pVCpu->iem.s.DataBreakpointTlbe)
    3424         {
    3425             if (!((uintptr_t)pTlbe & (sizeof(*pTlbe) * 2 - 1)))
    3426                 IEMTLBTRACE_LOAD(       pVCpu, GCPtrMem, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, true);
    3427             else
    3428                 IEMTLBTRACE_LOAD_GLOBAL(pVCpu, GCPtrMem, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, true);
    3429         }
    3430 
    3431         /* Resolve the physical address. */
    3432         Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_GCPHYS2PTR_MASK));
    3433         rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhysPg, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
    3434                                         &pbMem, &pTlbe->fFlagsAndPhysRev);
    3435         AssertRCReturn(rc, rc);
    3436 # ifdef IN_RING3
    3437         pTlbe->pbMappingR3 = pbMem;
    3438 # endif
    3439     }
    3440 
    3441     /*
    3442      * Check the physical page level access and mapping.
    3443      */
    3444     if (   !(pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PG_NO_WRITE | IEMTLBE_F_PG_NO_READ))
    3445         || !(pTlbe->fFlagsAndPhysRev & (  (fAccess & IEM_ACCESS_TYPE_WRITE ? IEMTLBE_F_PG_NO_WRITE : 0)
    3446                                         | (fAccess & IEM_ACCESS_TYPE_READ  ? IEMTLBE_F_PG_NO_READ  : 0))) )
    3447     { /* probably likely */ }
    3448     else
    3449         return iemMemBounceBufferMapPhys(pVCpu, iMemMap, ppvMem, pbUnmapInfo, cbMem,
    3450                                          pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK), fAccess,
    3451                                            pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_UNASSIGNED ? VERR_PGM_PHYS_TLB_UNASSIGNED
    3452                                          : pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_NO_READ    ? VERR_PGM_PHYS_TLB_CATCH_ALL
    3453                                                                                              : VERR_PGM_PHYS_TLB_CATCH_WRITE);
    3454     Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_NO_MAPPINGR3)); /* ASSUMPTIONS about PGMPhysIemGCPhys2PtrNoLock behaviour. */
    3455 
    3456     if (pbMem)
    3457     {
    3458         Assert(!((uintptr_t)pbMem & GUEST_PAGE_OFFSET_MASK));
    3459         pbMem    = pbMem + (GCPtrMem & GUEST_PAGE_OFFSET_MASK);
    3460         fAccess |= IEM_ACCESS_NOT_LOCKED;
    3461     }
    3462     else
    3463     {
    3464         Assert(!(fAccess & IEM_ACCESS_NOT_LOCKED));
    3465         RTGCPHYS const GCPhysFirst = pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK);
    3466         rcStrict = iemMemPageMap(pVCpu, GCPhysFirst, fAccess, (void **)&pbMem, &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    3467         if (rcStrict != VINF_SUCCESS)
    3468             return iemMemBounceBufferMapPhys(pVCpu, iMemMap, ppvMem, pbUnmapInfo, cbMem, GCPhysFirst, fAccess, rcStrict);
    3469     }
    3470 
    3471     void * const pvMem = pbMem;
    3472 
    3473     if (fAccess & IEM_ACCESS_TYPE_WRITE)
    3474         Log6(("IEM WR %RGv (%RGp) LB %#zx\n", GCPtrMem, pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK), cbMem));
    3475     if (fAccess & IEM_ACCESS_TYPE_READ)
    3476         Log2(("IEM RD %RGv (%RGp) LB %#zx\n", GCPtrMem, pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK), cbMem));
    3477 
    3478 #else  /* !IEM_WITH_DATA_TLB */
    3479 
    3480     RTGCPHYS GCPhysFirst;
    3481     rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, &GCPhysFirst);
    3482     if (rcStrict != VINF_SUCCESS)
    3483         return rcStrict;
    3484 
    3485     if (fAccess & IEM_ACCESS_TYPE_WRITE)
    3486         Log6(("IEM WR %RGv (%RGp) LB %#zx\n", GCPtrMem, GCPhysFirst, cbMem));
    3487     if (fAccess & IEM_ACCESS_TYPE_READ)
    3488         Log2(("IEM RD %RGv (%RGp) LB %#zx\n", GCPtrMem, GCPhysFirst, cbMem));
    3489 
    3490     void *pvMem;
    3491     rcStrict = iemMemPageMap(pVCpu, GCPhysFirst, fAccess, &pvMem, &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    3492     if (rcStrict != VINF_SUCCESS)
    3493         return iemMemBounceBufferMapPhys(pVCpu, iMemMap, ppvMem, pbUnmapInfo, cbMem, GCPhysFirst, fAccess, rcStrict);
    3494 
    3495 #endif /* !IEM_WITH_DATA_TLB */
    3496 
    3497     /*
    3498      * Fill in the mapping table entry.
    3499      */
    3500     pVCpu->iem.s.aMemMappings[iMemMap].pv      = pvMem;
    3501     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = fAccess;
    3502     pVCpu->iem.s.iNextMapping     = iMemMap + 1;
    3503     pVCpu->iem.s.cActiveMappings += 1;
    3504 
    3505     *ppvMem = pvMem;
    3506     *pbUnmapInfo = iMemMap | 0x08 | ((fAccess & IEM_ACCESS_TYPE_MASK) << 4);
    3507     AssertCompile(IEM_ACCESS_TYPE_MASK <= 0xf);
    3508     AssertCompile(RT_ELEMENTS(pVCpu->iem.s.aMemMappings) < 8);
    3509 
    3510     return VINF_SUCCESS;
    3511 }
    3512 
    3513 
    3514 /**
    35152520 * Commits the guest memory if bounce buffered and unmaps it.
    35162521 *
     
    35722577
    35732578#ifdef IEM_WITH_SETJMP
    3574 
    3575 /**
    3576  * Maps the specified guest memory for the given kind of access, longjmp on
    3577  * error.
    3578  *
    3579  * This may be using bounce buffering of the memory if it's crossing a page
    3580  * boundary or if there is an access handler installed for any of it.  Because
    3581  * of lock prefix guarantees, we're in for some extra clutter when this
    3582  * happens.
    3583  *
    3584  * This may raise a \#GP, \#SS, \#PF or \#AC.
    3585  *
    3586  * @returns Pointer to the mapped memory.
    3587  *
    3588  * @param   pVCpu       The cross context virtual CPU structure of the calling thread.
    3589  * @param   bUnmapInfo  Where to return unmap info to be passed to
    3590  *                      iemMemCommitAndUnmapJmp, iemMemCommitAndUnmapRwSafeJmp,
    3591  *                      iemMemCommitAndUnmapWoSafeJmp,
    3592  *                      iemMemCommitAndUnmapRoSafeJmp,
    3593  *                      iemMemRollbackAndUnmapWoSafe or iemMemRollbackAndUnmap
    3594  *                      when done.
    3595  * @param   cbMem       The number of bytes to map.  This is usually 1,
    3596  *                      2, 4, 6, 8, 12, 16, 32 or 512.  When used by
    3597  *                      string operations it can be up to a page.
    3598  * @param   iSegReg     The index of the segment register to use for
    3599  *                      this access.  The base and limits are checked.
    3600  *                      Use UINT8_MAX to indicate that no segmentation
    3601  *                      is required (for IDT, GDT and LDT accesses).
    3602  * @param   GCPtrMem    The address of the guest memory.
    3603  * @param   fAccess     How the memory is being accessed. The
    3604  *                      IEM_ACCESS_TYPE_XXX part is used to figure out how to
    3605  *                      map the memory, while the IEM_ACCESS_WHAT_XXX part is
    3606  *                      used when raising exceptions. The IEM_ACCESS_ATOMIC and
    3607  *                      IEM_ACCESS_PARTIAL_WRITE bits are also allowed to be
    3608  *                      set.
    3609  * @param   uAlignCtl   Alignment control:
    3610  *                          - Bits 15:0 is the alignment mask.
    3611  *                          - Bits 31:16 for flags like IEM_MEMMAP_F_ALIGN_GP,
    3612  *                            IEM_MEMMAP_F_ALIGN_SSE, and
    3613  *                            IEM_MEMMAP_F_ALIGN_GP_OR_AC.
    3614  *                      Pass zero to skip alignment.
    3615  * @tparam  a_fSafe     Whether this is a call from "safe" fallback function in
    3616  *                      IEMAllMemRWTmpl.cpp.h (@c true) or a generic one that
    3617  *                      needs counting as such in the statistics.
    3618  */
    3619 template<bool a_fSafeCall = false>
    3620 static void *iemMemMapJmp(PVMCPUCC pVCpu, uint8_t *pbUnmapInfo, size_t cbMem, uint8_t iSegReg, RTGCPTR GCPtrMem,
    3621                           uint32_t fAccess, uint32_t uAlignCtl) IEM_NOEXCEPT_MAY_LONGJMP
    3622 {
    3623     STAM_COUNTER_INC(&pVCpu->iem.s.StatMemMapJmp);
    3624 
    3625     /*
    3626      * Check the input, check segment access and adjust address
    3627      * with segment base.
    3628      */
    3629     Assert(cbMem <= 64 || cbMem == 512 || cbMem == 108 || cbMem == 104 || cbMem == 94); /* 512 is the max! */
    3630     Assert(!(fAccess & ~(IEM_ACCESS_TYPE_MASK | IEM_ACCESS_WHAT_MASK | IEM_ACCESS_ATOMIC | IEM_ACCESS_PARTIAL_WRITE)));
    3631     Assert(pVCpu->iem.s.cActiveMappings < RT_ELEMENTS(pVCpu->iem.s.aMemMappings));
    3632 
    3633     VBOXSTRICTRC rcStrict = iemMemApplySegment(pVCpu, fAccess, iSegReg, cbMem, &GCPtrMem);
    3634     if (rcStrict == VINF_SUCCESS) { /*likely*/ }
    3635     else IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    3636 
    3637     /*
    3638      * Alignment check.
    3639      */
    3640     if ( (GCPtrMem & (uAlignCtl & UINT16_MAX)) == 0 )
    3641     { /* likelyish */ }
    3642     else
    3643     {
    3644         /* Misaligned access. */
    3645         if ((fAccess & IEM_ACCESS_WHAT_MASK) != IEM_ACCESS_WHAT_SYS)
    3646         {
    3647             if (   !(uAlignCtl & IEM_MEMMAP_F_ALIGN_GP)
    3648                 || (   (uAlignCtl & IEM_MEMMAP_F_ALIGN_SSE)
    3649                     && (pVCpu->cpum.GstCtx.XState.x87.MXCSR & X86_MXCSR_MM)) )
    3650             {
    3651                 AssertCompile(X86_CR0_AM == X86_EFL_AC);
    3652 
    3653                 if (iemMemAreAlignmentChecksEnabled(pVCpu))
    3654                     iemRaiseAlignmentCheckExceptionJmp(pVCpu);
    3655             }
    3656             else if (   (uAlignCtl & IEM_MEMMAP_F_ALIGN_GP_OR_AC)
    3657                      && (GCPtrMem & 3) /* The value 4 matches 10980xe's FXSAVE and helps make bs3-cpu-basic2 work. */
    3658                     /** @todo may only apply to 2, 4 or 8 byte misalignments depending on the CPU
    3659                      * implementation. See FXSAVE/FRSTOR/XSAVE/XRSTOR/++.  Using 4 for now as
    3660                      * that's what FXSAVE does on a 10980xe. */
    3661                      && iemMemAreAlignmentChecksEnabled(pVCpu))
    3662                 iemRaiseAlignmentCheckExceptionJmp(pVCpu);
    3663             else
    3664                 iemRaiseGeneralProtectionFault0Jmp(pVCpu);
    3665         }
    3666 
    3667 #if (defined(RT_ARCH_AMD64) && defined(RT_OS_LINUX)) || defined(RT_ARCH_ARM64)
    3668         /* If the access is atomic there are host platform alignmnet restrictions
    3669            we need to conform with. */
    3670         if (   !(fAccess & IEM_ACCESS_ATOMIC)
    3671 # if defined(RT_ARCH_AMD64)
    3672             || (64U - (GCPtrMem & 63U) >= cbMem) /* split-lock detection. ASSUMES 64 byte cache line. */
    3673 # elif defined(RT_ARCH_ARM64)
    3674             || (16U - (GCPtrMem & 15U) >= cbMem) /* LSE2 allows atomics anywhere within a 16 byte sized & aligned block. */
    3675 # else
    3676 #  error port me
    3677 # endif
    3678            )
    3679         { /* okay */ }
    3680         else
    3681         {
    3682             LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv LB %u - misaligned atomic fallback.\n", GCPtrMem, cbMem));
    3683             pVCpu->iem.s.cMisalignedAtomics += 1;
    3684             IEM_DO_LONGJMP(pVCpu, VINF_EM_EMULATE_SPLIT_LOCK);
    3685         }
    3686 #endif
    3687     }
    3688 
    3689     /*
    3690      * Figure out which mapping entry to use.
    3691      */
    3692     unsigned iMemMap = pVCpu->iem.s.iNextMapping;
    3693     if (   iMemMap >= RT_ELEMENTS(pVCpu->iem.s.aMemMappings)
    3694         || pVCpu->iem.s.aMemMappings[iMemMap].fAccess != IEM_ACCESS_INVALID)
    3695     {
    3696         iMemMap = iemMemMapFindFree(pVCpu);
    3697         AssertLogRelMsgStmt(iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings),
    3698                             ("active=%d fAccess[0] = {%#x, %#x, %#x}\n", pVCpu->iem.s.cActiveMappings,
    3699                              pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemMappings[1].fAccess,
    3700                              pVCpu->iem.s.aMemMappings[2].fAccess),
    3701                             IEM_DO_LONGJMP(pVCpu, VERR_IEM_IPE_9));
    3702     }
    3703 
    3704     /*
    3705      * Crossing a page boundary?
    3706      */
    3707     if ((GCPtrMem & GUEST_PAGE_OFFSET_MASK) + cbMem <= GUEST_PAGE_SIZE)
    3708     { /* No (likely). */ }
    3709     else
    3710     {
    3711         void *pvMem;
    3712         rcStrict = iemMemBounceBufferMapCrossPage(pVCpu, iMemMap, &pvMem, pbUnmapInfo, cbMem, GCPtrMem, fAccess);
    3713         if (rcStrict == VINF_SUCCESS)
    3714             return pvMem;
    3715         IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    3716     }
    3717 
    3718 #ifdef IEM_WITH_DATA_TLB
    3719     Assert(!(fAccess & IEM_ACCESS_TYPE_EXEC));
    3720 
    3721     /*
    3722      * Get the TLB entry for this page checking that it has the A & D bits
    3723      * set as per fAccess flags.
    3724      */
    3725     /** @todo make the caller pass these in with fAccess. */
    3726     uint64_t const     fNoUser          = (fAccess & IEM_ACCESS_WHAT_MASK) != IEM_ACCESS_WHAT_SYS && IEM_GET_CPL(pVCpu) == 3
    3727                                         ? IEMTLBE_F_PT_NO_USER : 0;
    3728     uint64_t const     fNoWriteNoDirty  = fAccess & IEM_ACCESS_TYPE_WRITE
    3729                                         ? IEMTLBE_F_PG_NO_WRITE | IEMTLBE_F_PT_NO_DIRTY
    3730                                           | (   (pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)
    3731                                              || (IEM_GET_CPL(pVCpu) == 3 && (fAccess & IEM_ACCESS_WHAT_MASK) != IEM_ACCESS_WHAT_SYS)
    3732                                              ? IEMTLBE_F_PT_NO_WRITE : 0)
    3733                                         : 0;
    3734     uint64_t const     fNoRead          = fAccess & IEM_ACCESS_TYPE_READ ? IEMTLBE_F_PG_NO_READ : 0;
    3735     uint64_t const     uTagNoRev        = IEMTLB_CALC_TAG_NO_REV(GCPtrMem);
    3736     PIEMTLBENTRY       pTlbe            = IEMTLB_TAG_TO_EVEN_ENTRY(&pVCpu->iem.s.DataTlb, uTagNoRev);
    3737     uint64_t const     fTlbeAD          = IEMTLBE_F_PT_NO_ACCESSED | (fNoWriteNoDirty & IEMTLBE_F_PT_NO_DIRTY);
    3738     if (   (   pTlbe->uTag               == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevision)
    3739             && !(pTlbe->fFlagsAndPhysRev & fTlbeAD) )
    3740         || (   (pTlbe = pTlbe + 1)->uTag == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevisionGlobal)
    3741             && !(pTlbe->fFlagsAndPhysRev & fTlbeAD) ) )
    3742     {
    3743 # ifdef IEM_WITH_TLB_STATISTICS
    3744         if (a_fSafeCall)
    3745             pVCpu->iem.s.DataTlb.cTlbSafeHits++;
    3746         else
    3747             pVCpu->iem.s.DataTlb.cTlbCoreHits++;
    3748 # endif
    3749     }
    3750     else
    3751     {
    3752         if (a_fSafeCall)
    3753             pVCpu->iem.s.DataTlb.cTlbSafeMisses++;
    3754         else
    3755             pVCpu->iem.s.DataTlb.cTlbCoreMisses++;
    3756 
    3757         /* This page table walking will set A and D bits as required by the
    3758            access while performing the walk.
    3759            ASSUMES these are set when the address is translated rather than on commit... */
    3760         /** @todo testcase: check when A and D bits are actually set by the CPU.  */
    3761         PGMPTWALKFAST WalkFast;
    3762         AssertCompile(IEM_ACCESS_TYPE_READ  == PGMQPAGE_F_READ);
    3763         AssertCompile(IEM_ACCESS_TYPE_WRITE == PGMQPAGE_F_WRITE);
    3764         AssertCompile(IEM_ACCESS_TYPE_EXEC  == PGMQPAGE_F_EXECUTE);
    3765         AssertCompile(X86_CR0_WP            == PGMQPAGE_F_CR0_WP0);
    3766         uint32_t fQPage = (fAccess & (PGMQPAGE_F_READ | IEM_ACCESS_TYPE_WRITE | PGMQPAGE_F_EXECUTE))
    3767                         | (((uint32_t)pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP) ^ X86_CR0_WP);
    3768         if (IEM_GET_CPL(pVCpu) == 3 && !(fAccess & IEM_ACCESS_WHAT_SYS))
    3769             fQPage |= PGMQPAGE_F_USER_MODE;
    3770         int rc = PGMGstQueryPageFast(pVCpu, GCPtrMem, fQPage, &WalkFast);
    3771         if (RT_SUCCESS(rc))
    3772             Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
    3773         else
    3774         {
    3775             LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - failed to fetch page -> #PF\n", GCPtrMem));
    3776 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    3777             if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    3778                 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
    3779 # endif
    3780             iemRaisePageFaultJmp(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, rc);
    3781         }
    3782 
    3783         uint32_t fDataBps;
    3784         if (   RT_LIKELY(!(pVCpu->iem.s.fExec & IEM_F_PENDING_BRK_DATA))
    3785             || RT_LIKELY(!(fDataBps = iemMemCheckDataBreakpoint(pVCpu->CTX_SUFF(pVM), pVCpu, GCPtrMem, cbMem, fAccess))))
    3786         {
    3787             if (   !(WalkFast.fEffective & PGM_PTATTRS_G_MASK)
    3788                 || IEM_GET_CPL(pVCpu) != 0) /* optimization: Only use the PTE.G=1 entries in ring-0. */
    3789             {
    3790                 pTlbe--;
    3791                 pTlbe->uTag         = uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevision;
    3792                 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE)
    3793                     iemTlbLoadedLargePage<false>(pVCpu, &pVCpu->iem.s.DataTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE));
    3794 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    3795                 else
    3796                     ASMBitClear(pVCpu->iem.s.DataTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev));
    3797 # endif
    3798             }
    3799             else
    3800             {
    3801                 if (a_fSafeCall)
    3802                     pVCpu->iem.s.DataTlb.cTlbSafeGlobalLoads++;
    3803                 else
    3804                     pVCpu->iem.s.DataTlb.cTlbCoreGlobalLoads++;
    3805                 pTlbe->uTag         = uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevisionGlobal;
    3806                 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE)
    3807                     iemTlbLoadedLargePage<true>(pVCpu, &pVCpu->iem.s.DataTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE));
    3808 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    3809                 else
    3810                     ASMBitClear(pVCpu->iem.s.DataTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + 1);
    3811 # endif
    3812             }
    3813         }
    3814         else
    3815         {
    3816             /* If we hit a data breakpoint, we use a dummy TLBE to force all accesses
    3817                to the page with the data access breakpoint armed on it to pass thru here. */
    3818             if (fDataBps > 1)
    3819                 LogEx(LOG_GROUP_IEM, ("iemMemMapJmp<%d>: Data breakpoint: fDataBps=%#x for %RGv LB %zx; fAccess=%#x cs:rip=%04x:%08RX64\n",
    3820                                       a_fSafeCall, fDataBps, GCPtrMem, cbMem, fAccess, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    3821             pVCpu->cpum.GstCtx.eflags.uBoth |= fDataBps & (CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK);
    3822             pTlbe = &pVCpu->iem.s.DataBreakpointTlbe;
    3823             pTlbe->uTag = uTagNoRev;
    3824         }
    3825         pTlbe->fFlagsAndPhysRev = (~WalkFast.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A) /* skipping NX */)
    3826                                 | (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE);
    3827         RTGCPHYS const GCPhysPg = WalkFast.GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
    3828         pTlbe->GCPhys           = GCPhysPg;
    3829         pTlbe->pbMappingR3      = NULL;
    3830         Assert(!(pTlbe->fFlagsAndPhysRev & ((fNoWriteNoDirty & IEMTLBE_F_PT_NO_DIRTY) | IEMTLBE_F_PT_NO_ACCESSED)));
    3831         Assert(   !(pTlbe->fFlagsAndPhysRev & fNoWriteNoDirty & IEMTLBE_F_PT_NO_WRITE)
    3832                || (fQPage & (PGMQPAGE_F_CR0_WP0 | PGMQPAGE_F_USER_MODE)) == PGMQPAGE_F_CR0_WP0);
    3833         Assert(!(pTlbe->fFlagsAndPhysRev & fNoUser & IEMTLBE_F_PT_NO_USER));
    3834 
    3835         if (pTlbe != &pVCpu->iem.s.DataBreakpointTlbe)
    3836         {
    3837             if (!((uintptr_t)pTlbe & (sizeof(*pTlbe) * 2 - 1)))
    3838                 IEMTLBTRACE_LOAD(       pVCpu, GCPtrMem, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, true);
    3839             else
    3840                 IEMTLBTRACE_LOAD_GLOBAL(pVCpu, GCPtrMem, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, true);
    3841         }
    3842 
    3843         /* Resolve the physical address. */
    3844         Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_GCPHYS2PTR_MASK));
    3845         uint8_t *pbMemFullLoad = NULL;
    3846         rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhysPg, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
    3847                                         &pbMemFullLoad, &pTlbe->fFlagsAndPhysRev);
    3848         AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc));
    3849 # ifdef IN_RING3
    3850         pTlbe->pbMappingR3 = pbMemFullLoad;
    3851 # endif
    3852     }
    3853 
    3854     /*
    3855      * Check the flags and physical revision.
    3856      * Note! This will revalidate the uTlbPhysRev after a full load.  This is
    3857      *       just to keep the code structure simple (i.e. avoid gotos or similar).
    3858      */
    3859     uint8_t *pbMem;
    3860     if (   (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PHYS_REV | IEMTLBE_F_PT_NO_ACCESSED | fNoRead | fNoWriteNoDirty | fNoUser))
    3861         == pVCpu->iem.s.DataTlb.uTlbPhysRev)
    3862 # ifdef IN_RING3
    3863         pbMem = pTlbe->pbMappingR3;
    3864 # else
    3865         pbMem = NULL;
    3866 # endif
    3867     else
    3868     {
    3869         Assert(!(pTlbe->fFlagsAndPhysRev & ((fNoWriteNoDirty & IEMTLBE_F_PT_NO_DIRTY) | IEMTLBE_F_PT_NO_ACCESSED)));
    3870 
    3871         /*
    3872          * Okay, something isn't quite right or needs refreshing.
    3873          */
    3874         /* Write to read only memory? */
    3875         if (pTlbe->fFlagsAndPhysRev & fNoWriteNoDirty & IEMTLBE_F_PT_NO_WRITE)
    3876         {
    3877             LogEx(LOG_GROUP_IEM, ("iemMemMapJmp: GCPtrMem=%RGv - read-only page -> #PF\n", GCPtrMem));
    3878 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    3879 /** @todo TLB: EPT isn't integrated into the TLB stuff, so we don't know whether
    3880  *        to trigger an \#PG or a VM nested paging exit here yet! */
    3881             if (Walk.fFailed & PGM_WALKFAIL_EPT)
    3882                 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
    3883 # endif
    3884             iemRaisePageFaultJmp(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess & ~IEM_ACCESS_TYPE_READ, VERR_ACCESS_DENIED);
    3885         }
    3886 
    3887         /* Kernel memory accessed by userland? */
    3888         if (pTlbe->fFlagsAndPhysRev & fNoUser & IEMTLBE_F_PT_NO_USER)
    3889         {
    3890             LogEx(LOG_GROUP_IEM, ("iemMemMapJmp: GCPtrMem=%RGv - user access to kernel page -> #PF\n", GCPtrMem));
    3891 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    3892 /** @todo TLB: See above. */
    3893             if (Walk.fFailed & PGM_WALKFAIL_EPT)
    3894                 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
    3895 # endif
    3896             iemRaisePageFaultJmp(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, VERR_ACCESS_DENIED);
    3897         }
    3898 
    3899         /*
    3900          * Check if the physical page info needs updating.
    3901          */
    3902         if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pVCpu->iem.s.DataTlb.uTlbPhysRev)
    3903 # ifdef IN_RING3
    3904             pbMem = pTlbe->pbMappingR3;
    3905 # else
    3906             pbMem = NULL;
    3907 # endif
    3908         else
    3909         {
    3910             pTlbe->pbMappingR3       = NULL;
    3911             pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK;
    3912             pbMem = NULL;
    3913             int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
    3914                                                 &pbMem, &pTlbe->fFlagsAndPhysRev);
    3915             AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc));
    3916 # ifdef IN_RING3
    3917             pTlbe->pbMappingR3 = pbMem;
    3918 # endif
    3919         }
    3920 
    3921         /*
    3922          * Check the physical page level access and mapping.
    3923          */
    3924         if (!(pTlbe->fFlagsAndPhysRev & ((fNoWriteNoDirty | fNoRead) & (IEMTLBE_F_PG_NO_WRITE | IEMTLBE_F_PG_NO_READ))))
    3925         { /* probably likely */ }
    3926         else
    3927         {
    3928             rcStrict = iemMemBounceBufferMapPhys(pVCpu, iMemMap, (void **)&pbMem, pbUnmapInfo, cbMem,
    3929                                                  pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK), fAccess,
    3930                                                    pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_UNASSIGNED ? VERR_PGM_PHYS_TLB_UNASSIGNED
    3931                                                  : pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_NO_READ    ? VERR_PGM_PHYS_TLB_CATCH_ALL
    3932                                                                                                      : VERR_PGM_PHYS_TLB_CATCH_WRITE);
    3933             if (rcStrict == VINF_SUCCESS)
    3934                 return pbMem;
    3935             IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    3936         }
    3937     }
    3938     Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_NO_MAPPINGR3)); /* ASSUMPTIONS about PGMPhysIemGCPhys2PtrNoLock behaviour. */
    3939 
    3940     if (pbMem)
    3941     {
    3942         Assert(!((uintptr_t)pbMem & GUEST_PAGE_OFFSET_MASK));
    3943         pbMem    = pbMem + (GCPtrMem & GUEST_PAGE_OFFSET_MASK);
    3944         fAccess |= IEM_ACCESS_NOT_LOCKED;
    3945     }
    3946     else
    3947     {
    3948         Assert(!(fAccess & IEM_ACCESS_NOT_LOCKED));
    3949         RTGCPHYS const GCPhysFirst = pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK);
    3950         rcStrict = iemMemPageMap(pVCpu, GCPhysFirst, fAccess, (void **)&pbMem, &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    3951         if (rcStrict == VINF_SUCCESS)
    3952         {
    3953             *pbUnmapInfo = iMemMap | 0x08 | ((fAccess & IEM_ACCESS_TYPE_MASK) << 4);
    3954             return pbMem;
    3955         }
    3956         IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    3957     }
    3958 
    3959     void * const pvMem = pbMem;
    3960 
    3961     if (fAccess & IEM_ACCESS_TYPE_WRITE)
    3962         Log6(("IEM WR %RGv (%RGp) LB %#zx\n", GCPtrMem, pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK), cbMem));
    3963     if (fAccess & IEM_ACCESS_TYPE_READ)
    3964         Log2(("IEM RD %RGv (%RGp) LB %#zx\n", GCPtrMem, pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK), cbMem));
    3965 
    3966 #else  /* !IEM_WITH_DATA_TLB */
    3967 
    3968 
    3969     RTGCPHYS GCPhysFirst;
    3970     rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, &GCPhysFirst);
    3971     if (rcStrict == VINF_SUCCESS) { /*likely*/ }
    3972     else IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    3973 
    3974     if (fAccess & IEM_ACCESS_TYPE_WRITE)
    3975         Log6(("IEM WR %RGv (%RGp) LB %#zx\n", GCPtrMem, GCPhysFirst, cbMem));
    3976     if (fAccess & IEM_ACCESS_TYPE_READ)
    3977         Log2(("IEM RD %RGv (%RGp) LB %#zx\n", GCPtrMem, GCPhysFirst, cbMem));
    3978 
    3979     void *pvMem;
    3980     rcStrict = iemMemPageMap(pVCpu, GCPhysFirst, fAccess, &pvMem, &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    3981     if (rcStrict == VINF_SUCCESS)
    3982     { /* likely */ }
    3983     else
    3984     {
    3985         rcStrict = iemMemBounceBufferMapPhys(pVCpu, iMemMap, &pvMem, pbUnmapInfo, cbMem, GCPhysFirst, fAccess, rcStrict);
    3986         if (rcStrict == VINF_SUCCESS)
    3987             return pvMem;
    3988         IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    3989     }
    3990 
    3991 #endif /* !IEM_WITH_DATA_TLB */
    3992 
    3993     /*
    3994      * Fill in the mapping table entry.
    3995      */
    3996     pVCpu->iem.s.aMemMappings[iMemMap].pv      = pvMem;
    3997     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = fAccess;
    3998     pVCpu->iem.s.iNextMapping = iMemMap + 1;
    3999     pVCpu->iem.s.cActiveMappings++;
    4000 
    4001     *pbUnmapInfo = iMemMap | 0x08 | ((fAccess & IEM_ACCESS_TYPE_MASK) << 4);
    4002     return pvMem;
    4003 }
    4004 
    4005 
    4006 /** @see iemMemMapJmp */
    4007 static void *iemMemMapSafeJmp(PVMCPUCC pVCpu, uint8_t *pbUnmapInfo, size_t cbMem, uint8_t iSegReg, RTGCPTR GCPtrMem,
    4008                               uint32_t fAccess, uint32_t uAlignCtl) IEM_NOEXCEPT_MAY_LONGJMP
    4009 {
    4010     return iemMemMapJmp<true /*a_fSafeCall*/>(pVCpu, pbUnmapInfo, cbMem, iSegReg, GCPtrMem, fAccess, uAlignCtl);
    4011 }
    4012 
    40132579
    40142580/**
     
    41632729    }
    41642730}
    4165 
    4166 
    4167 /*
    4168  * Instantiate R/W templates.
    4169  */
    4170 #define TMPL_MEM_WITH_STACK
    4171 
    4172 #define TMPL_MEM_TYPE       uint8_t
    4173 #define TMPL_MEM_FN_SUFF    U8
    4174 #define TMPL_MEM_FMT_TYPE   "%#04x"
    4175 #define TMPL_MEM_FMT_DESC   "byte"
    4176 #include "IEMAllMemRWTmpl.cpp.h"
    4177 
    4178 #define TMPL_MEM_TYPE       uint16_t
    4179 #define TMPL_MEM_FN_SUFF    U16
    4180 #define TMPL_MEM_FMT_TYPE   "%#06x"
    4181 #define TMPL_MEM_FMT_DESC   "word"
    4182 #include "IEMAllMemRWTmpl.cpp.h"
    4183 
    4184 #define TMPL_WITH_PUSH_SREG
    4185 #define TMPL_MEM_TYPE       uint32_t
    4186 #define TMPL_MEM_FN_SUFF    U32
    4187 #define TMPL_MEM_FMT_TYPE   "%#010x"
    4188 #define TMPL_MEM_FMT_DESC   "dword"
    4189 #include "IEMAllMemRWTmpl.cpp.h"
    4190 #undef TMPL_WITH_PUSH_SREG
    4191 
    4192 #define TMPL_MEM_TYPE       uint64_t
    4193 #define TMPL_MEM_FN_SUFF    U64
    4194 #define TMPL_MEM_FMT_TYPE   "%#018RX64"
    4195 #define TMPL_MEM_FMT_DESC   "qword"
    4196 #include "IEMAllMemRWTmpl.cpp.h"
    4197 
    4198 #undef TMPL_MEM_WITH_STACK
    4199 
    4200 #define TMPL_MEM_TYPE       uint32_t
    4201 #define TMPL_MEM_TYPE_ALIGN 0
    4202 #define TMPL_MEM_FN_SUFF    U32NoAc
    4203 #define TMPL_MEM_FMT_TYPE   "%#010x"
    4204 #define TMPL_MEM_FMT_DESC   "dword"
    4205 #include "IEMAllMemRWTmpl.cpp.h"
    4206 #undef TMPL_WITH_PUSH_SREG
    4207 
    4208 #define TMPL_MEM_TYPE       uint64_t
    4209 #define TMPL_MEM_TYPE_ALIGN 0
    4210 #define TMPL_MEM_FN_SUFF    U64NoAc
    4211 #define TMPL_MEM_FMT_TYPE   "%#018RX64"
    4212 #define TMPL_MEM_FMT_DESC   "qword"
    4213 #include "IEMAllMemRWTmpl.cpp.h"
    4214 
    4215 #define TMPL_MEM_TYPE       uint64_t
    4216 #define TMPL_MEM_TYPE_ALIGN (sizeof(uint64_t) * 2 - 1)
    4217 #define TMPL_MEM_FN_SUFF    U64AlignedU128
    4218 #define TMPL_MEM_FMT_TYPE   "%#018RX64"
    4219 #define TMPL_MEM_FMT_DESC   "qword"
    4220 #include "IEMAllMemRWTmpl.cpp.h"
    4221 
    4222 /* See IEMAllMemRWTmplInline.cpp.h */
    4223 #define TMPL_MEM_BY_REF
    4224 
    4225 #define TMPL_MEM_TYPE       RTFLOAT80U
    4226 #define TMPL_MEM_TYPE_ALIGN (sizeof(uint64_t) - 1)
    4227 #define TMPL_MEM_FN_SUFF    R80
    4228 #define TMPL_MEM_FMT_TYPE   "%.10Rhxs"
    4229 #define TMPL_MEM_FMT_DESC   "tword"
    4230 #include "IEMAllMemRWTmpl.cpp.h"
    4231 
    4232 #define TMPL_MEM_TYPE       RTPBCD80U
    4233 #define TMPL_MEM_TYPE_ALIGN (sizeof(uint64_t) - 1) /** @todo testcase: 80-bit BCD alignment */
    4234 #define TMPL_MEM_FN_SUFF    D80
    4235 #define TMPL_MEM_FMT_TYPE   "%.10Rhxs"
    4236 #define TMPL_MEM_FMT_DESC   "tword"
    4237 #include "IEMAllMemRWTmpl.cpp.h"
    4238 
    4239 #define TMPL_MEM_TYPE       RTUINT128U
    4240 #define TMPL_MEM_TYPE_ALIGN (sizeof(RTUINT128U) - 1)
    4241 #define TMPL_MEM_FN_SUFF    U128
    4242 #define TMPL_MEM_FMT_TYPE   "%.16Rhxs"
    4243 #define TMPL_MEM_FMT_DESC   "dqword"
    4244 #include "IEMAllMemRWTmpl.cpp.h"
    4245 
    4246 #define TMPL_MEM_TYPE           RTUINT128U
    4247 #define TMPL_MEM_TYPE_ALIGN     (sizeof(RTUINT128U) - 1)
    4248 #define TMPL_MEM_MAP_FLAGS_ADD  (IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_SSE)
    4249 #define TMPL_MEM_FN_SUFF        U128AlignedSse
    4250 #define TMPL_MEM_FMT_TYPE       "%.16Rhxs"
    4251 #define TMPL_MEM_FMT_DESC       "dqword"
    4252 #include "IEMAllMemRWTmpl.cpp.h"
    4253 
    4254 #define TMPL_MEM_TYPE       RTUINT128U
    4255 #define TMPL_MEM_TYPE_ALIGN 0
    4256 #define TMPL_MEM_FN_SUFF    U128NoAc
    4257 #define TMPL_MEM_FMT_TYPE   "%.16Rhxs"
    4258 #define TMPL_MEM_FMT_DESC   "dqword"
    4259 #include "IEMAllMemRWTmpl.cpp.h"
    4260 
    4261 #define TMPL_MEM_TYPE       RTUINT256U
    4262 #define TMPL_MEM_TYPE_ALIGN 0
    4263 #define TMPL_MEM_FN_SUFF    U256NoAc
    4264 #define TMPL_MEM_FMT_TYPE   "%.32Rhxs"
    4265 #define TMPL_MEM_FMT_DESC   "qqword"
    4266 #include "IEMAllMemRWTmpl.cpp.h"
    4267 
    4268 #define TMPL_MEM_TYPE           RTUINT256U
    4269 #define TMPL_MEM_TYPE_ALIGN     (sizeof(RTUINT256U) - 1)
    4270 #define TMPL_MEM_MAP_FLAGS_ADD  IEM_MEMMAP_F_ALIGN_GP
    4271 #define TMPL_MEM_FN_SUFF        U256AlignedAvx
    4272 #define TMPL_MEM_FMT_TYPE       "%.32Rhxs"
    4273 #define TMPL_MEM_FMT_DESC       "qqword"
    4274 #include "IEMAllMemRWTmpl.cpp.h"
    4275 
    4276 /**
    4277  * Fetches a data dword and zero extends it to a qword.
    4278  *
    4279  * @returns Strict VBox status code.
    4280  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4281  * @param   pu64Dst             Where to return the qword.
    4282  * @param   iSegReg             The index of the segment register to use for
    4283  *                              this access.  The base and limits are checked.
    4284  * @param   GCPtrMem            The address of the guest memory.
    4285  */
    4286 VBOXSTRICTRC iemMemFetchDataU32_ZX_U64(PVMCPUCC pVCpu, uint64_t *pu64Dst, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4287 {
    4288     /* The lazy approach for now... */
    4289     uint8_t         bUnmapInfo;
    4290     uint32_t const *pu32Src;
    4291     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pu32Src, &bUnmapInfo, sizeof(*pu32Src), iSegReg, GCPtrMem,
    4292                                 IEM_ACCESS_DATA_R, sizeof(*pu32Src) - 1);
    4293     if (rc == VINF_SUCCESS)
    4294     {
    4295         *pu64Dst = *pu32Src;
    4296         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4297         Log(("IEM RD dword %d|%RGv: %#010RX64\n", iSegReg, GCPtrMem, *pu64Dst));
    4298     }
    4299     return rc;
    4300 }
    4301 
    4302 
    4303 #ifdef SOME_UNUSED_FUNCTION
    4304 /**
    4305  * Fetches a data dword and sign extends it to a qword.
    4306  *
    4307  * @returns Strict VBox status code.
    4308  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4309  * @param   pu64Dst             Where to return the sign extended value.
    4310  * @param   iSegReg             The index of the segment register to use for
    4311  *                              this access.  The base and limits are checked.
    4312  * @param   GCPtrMem            The address of the guest memory.
    4313  */
    4314 VBOXSTRICTRC iemMemFetchDataS32SxU64(PVMCPUCC pVCpu, uint64_t *pu64Dst, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4315 {
    4316     /* The lazy approach for now... */
    4317     uint8_t        bUnmapInfo;
    4318     int32_t const *pi32Src;
    4319     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pi32Src, &bUnmapInfo, sizeof(*pi32Src), iSegReg, GCPtrMem,
    4320                                 IEM_ACCESS_DATA_R, sizeof(*pi32Src) - 1);
    4321     if (rc == VINF_SUCCESS)
    4322     {
    4323         *pu64Dst = *pi32Src;
    4324         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4325         Log(("IEM RD dword %d|%RGv: %#010x\n", iSegReg, GCPtrMem, (uint32_t)*pu64Dst));
    4326     }
    4327 #ifdef __GNUC__ /* warning: GCC may be a royal pain */
    4328     else
    4329         *pu64Dst = 0;
    4330 #endif
    4331     return rc;
    4332 }
    4333 #endif
    4334 
    4335 
    4336 /**
    4337  * Fetches a descriptor register (lgdt, lidt).
    4338  *
    4339  * @returns Strict VBox status code.
    4340  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4341  * @param   pcbLimit            Where to return the limit.
    4342  * @param   pGCPtrBase          Where to return the base.
    4343  * @param   iSegReg             The index of the segment register to use for
    4344  *                              this access.  The base and limits are checked.
    4345  * @param   GCPtrMem            The address of the guest memory.
    4346  * @param   enmOpSize           The effective operand size.
    4347  */
    4348 VBOXSTRICTRC iemMemFetchDataXdtr(PVMCPUCC pVCpu, uint16_t *pcbLimit, PRTGCPTR pGCPtrBase, uint8_t iSegReg,
    4349                                  RTGCPTR GCPtrMem, IEMMODE enmOpSize) RT_NOEXCEPT
    4350 {
    4351     /*
    4352      * Just like SIDT and SGDT, the LIDT and LGDT instructions are a
    4353      * little special:
    4354      *      - The two reads are done separately.
    4355      *      - Operand size override works in 16-bit and 32-bit code, but 64-bit.
    4356      *      - We suspect the 386 to actually commit the limit before the base in
    4357      *        some cases (search for 386 in  bs3CpuBasic2_lidt_lgdt_One).  We
    4358      *        don't try emulate this eccentric behavior, because it's not well
    4359      *        enough understood and rather hard to trigger.
    4360      *      - The 486 seems to do a dword limit read when the operand size is 32-bit.
    4361      */
    4362     VBOXSTRICTRC rcStrict;
    4363     if (IEM_IS_64BIT_CODE(pVCpu))
    4364     {
    4365         rcStrict = iemMemFetchDataU16(pVCpu, pcbLimit, iSegReg, GCPtrMem);
    4366         if (rcStrict == VINF_SUCCESS)
    4367             rcStrict = iemMemFetchDataU64(pVCpu, pGCPtrBase, iSegReg, GCPtrMem + 2);
    4368     }
    4369     else
    4370     {
    4371         uint32_t uTmp = 0; /* (Visual C++ maybe used uninitialized) */
    4372         if (enmOpSize == IEMMODE_32BIT)
    4373         {
    4374             if (IEM_GET_TARGET_CPU(pVCpu) != IEMTARGETCPU_486)
    4375             {
    4376                 rcStrict = iemMemFetchDataU16(pVCpu, pcbLimit, iSegReg, GCPtrMem);
    4377                 if (rcStrict == VINF_SUCCESS)
    4378                     rcStrict = iemMemFetchDataU32(pVCpu, &uTmp, iSegReg, GCPtrMem + 2);
    4379             }
    4380             else
    4381             {
    4382                 rcStrict = iemMemFetchDataU32(pVCpu, &uTmp, iSegReg, GCPtrMem);
    4383                 if (rcStrict == VINF_SUCCESS)
    4384                 {
    4385                     *pcbLimit = (uint16_t)uTmp;
    4386                     rcStrict = iemMemFetchDataU32(pVCpu, &uTmp, iSegReg, GCPtrMem + 2);
    4387                 }
    4388             }
    4389             if (rcStrict == VINF_SUCCESS)
    4390                 *pGCPtrBase = uTmp;
    4391         }
    4392         else
    4393         {
    4394             rcStrict = iemMemFetchDataU16(pVCpu, pcbLimit, iSegReg, GCPtrMem);
    4395             if (rcStrict == VINF_SUCCESS)
    4396             {
    4397                 rcStrict = iemMemFetchDataU32(pVCpu, &uTmp, iSegReg, GCPtrMem + 2);
    4398                 if (rcStrict == VINF_SUCCESS)
    4399                     *pGCPtrBase = uTmp & UINT32_C(0x00ffffff);
    4400             }
    4401         }
    4402     }
    4403     return rcStrict;
    4404 }
    4405 
    4406 
    4407 /**
    4408  * Stores a data dqword, SSE aligned.
    4409  *
    4410  * @returns Strict VBox status code.
    4411  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4412  * @param   iSegReg             The index of the segment register to use for
    4413  *                              this access.  The base and limits are checked.
    4414  * @param   GCPtrMem            The address of the guest memory.
    4415  * @param   u128Value           The value to store.
    4416  */
    4417 VBOXSTRICTRC iemMemStoreDataU128AlignedSse(PVMCPUCC pVCpu, uint8_t iSegReg, RTGCPTR GCPtrMem, RTUINT128U u128Value) RT_NOEXCEPT
    4418 {
    4419     /* The lazy approach for now... */
    4420     uint8_t      bUnmapInfo;
    4421     PRTUINT128U  pu128Dst;
    4422     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pu128Dst, &bUnmapInfo, sizeof(*pu128Dst), iSegReg, GCPtrMem, IEM_ACCESS_DATA_W,
    4423                                 (sizeof(*pu128Dst) - 1) | IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_SSE);
    4424     if (rc == VINF_SUCCESS)
    4425     {
    4426         pu128Dst->au64[0] = u128Value.au64[0];
    4427         pu128Dst->au64[1] = u128Value.au64[1];
    4428         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4429         Log5(("IEM WR dqword %d|%RGv: %.16Rhxs\n", iSegReg, GCPtrMem, pu128Dst));
    4430     }
    4431     return rc;
    4432 }
    4433 
    4434 
    4435 #ifdef IEM_WITH_SETJMP
    4436 /**
    4437  * Stores a data dqword, SSE aligned.
    4438  *
    4439  * @returns Strict VBox status code.
    4440  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4441  * @param   iSegReg             The index of the segment register to use for
    4442  *                              this access.  The base and limits are checked.
    4443  * @param   GCPtrMem            The address of the guest memory.
    4444  * @param   u128Value           The value to store.
    4445  */
    4446 void iemMemStoreDataU128AlignedSseJmp(PVMCPUCC pVCpu, uint8_t iSegReg, RTGCPTR GCPtrMem,
    4447                                       RTUINT128U u128Value) IEM_NOEXCEPT_MAY_LONGJMP
    4448 {
    4449     /* The lazy approach for now... */
    4450     uint8_t     bUnmapInfo;
    4451     PRTUINT128U pu128Dst = (PRTUINT128U)iemMemMapJmp(pVCpu, &bUnmapInfo, sizeof(*pu128Dst), iSegReg, GCPtrMem, IEM_ACCESS_DATA_W,
    4452                                                      (sizeof(*pu128Dst) - 1) | IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_SSE);
    4453     pu128Dst->au64[0] = u128Value.au64[0];
    4454     pu128Dst->au64[1] = u128Value.au64[1];
    4455     iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);
    4456     Log5(("IEM WR dqword %d|%RGv: %.16Rhxs\n", iSegReg, GCPtrMem, pu128Dst));
    4457 }
    4458 #endif
    4459 
    4460 
    4461 /**
    4462  * Stores a data dqword.
    4463  *
    4464  * @returns Strict VBox status code.
    4465  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4466  * @param   iSegReg             The index of the segment register to use for
    4467  *                              this access.  The base and limits are checked.
    4468  * @param   GCPtrMem            The address of the guest memory.
    4469  * @param   pu256Value          Pointer to the value to store.
    4470  */
    4471 VBOXSTRICTRC iemMemStoreDataU256(PVMCPUCC pVCpu, uint8_t iSegReg, RTGCPTR GCPtrMem, PCRTUINT256U pu256Value) RT_NOEXCEPT
    4472 {
    4473     /* The lazy approach for now... */
    4474     uint8_t      bUnmapInfo;
    4475     PRTUINT256U  pu256Dst;
    4476     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pu256Dst, &bUnmapInfo, sizeof(*pu256Dst), iSegReg, GCPtrMem,
    4477                                 IEM_ACCESS_DATA_W, 0 /* NO_AC variant */);
    4478     if (rc == VINF_SUCCESS)
    4479     {
    4480         pu256Dst->au64[0] = pu256Value->au64[0];
    4481         pu256Dst->au64[1] = pu256Value->au64[1];
    4482         pu256Dst->au64[2] = pu256Value->au64[2];
    4483         pu256Dst->au64[3] = pu256Value->au64[3];
    4484         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4485         Log5(("IEM WR qqword %d|%RGv: %.32Rhxs\n", iSegReg, GCPtrMem, pu256Dst));
    4486     }
    4487     return rc;
    4488 }
    4489 
    4490 
    4491 #ifdef IEM_WITH_SETJMP
    4492 /**
    4493  * Stores a data dqword, longjmp on error.
    4494  *
    4495  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4496  * @param   iSegReg             The index of the segment register to use for
    4497  *                              this access.  The base and limits are checked.
    4498  * @param   GCPtrMem            The address of the guest memory.
    4499  * @param   pu256Value          Pointer to the value to store.
    4500  */
    4501 void iemMemStoreDataU256Jmp(PVMCPUCC pVCpu, uint8_t iSegReg, RTGCPTR GCPtrMem, PCRTUINT256U pu256Value) IEM_NOEXCEPT_MAY_LONGJMP
    4502 {
    4503     /* The lazy approach for now... */
    4504     uint8_t     bUnmapInfo;
    4505     PRTUINT256U pu256Dst = (PRTUINT256U)iemMemMapJmp(pVCpu, &bUnmapInfo, sizeof(*pu256Dst), iSegReg, GCPtrMem,
    4506                                                      IEM_ACCESS_DATA_W, 0 /* NO_AC variant */);
    4507     pu256Dst->au64[0] = pu256Value->au64[0];
    4508     pu256Dst->au64[1] = pu256Value->au64[1];
    4509     pu256Dst->au64[2] = pu256Value->au64[2];
    4510     pu256Dst->au64[3] = pu256Value->au64[3];
    4511     iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);
    4512     Log5(("IEM WR qqword %d|%RGv: %.32Rhxs\n", iSegReg, GCPtrMem, pu256Dst));
    4513 }
    4514 #endif
    4515 
    4516 
    4517 /**
    4518  * Stores a descriptor register (sgdt, sidt).
    4519  *
    4520  * @returns Strict VBox status code.
    4521  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4522  * @param   cbLimit             The limit.
    4523  * @param   GCPtrBase           The base address.
    4524  * @param   iSegReg             The index of the segment register to use for
    4525  *                              this access.  The base and limits are checked.
    4526  * @param   GCPtrMem            The address of the guest memory.
    4527  */
    4528 VBOXSTRICTRC iemMemStoreDataXdtr(PVMCPUCC pVCpu, uint16_t cbLimit, RTGCPTR GCPtrBase, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4529 {
    4530     /*
    4531      * The SIDT and SGDT instructions actually stores the data using two
    4532      * independent writes (see bs3CpuBasic2_sidt_sgdt_One).  The instructions
    4533      * does not respond to opsize prefixes.
    4534      */
    4535     VBOXSTRICTRC rcStrict = iemMemStoreDataU16(pVCpu, iSegReg, GCPtrMem, cbLimit);
    4536     if (rcStrict == VINF_SUCCESS)
    4537     {
    4538         if (IEM_IS_16BIT_CODE(pVCpu))
    4539             rcStrict = iemMemStoreDataU32(pVCpu, iSegReg, GCPtrMem + 2,
    4540                                           IEM_GET_TARGET_CPU(pVCpu) <= IEMTARGETCPU_286
    4541                                           ? (uint32_t)GCPtrBase | UINT32_C(0xff000000) : (uint32_t)GCPtrBase);
    4542         else if (IEM_IS_32BIT_CODE(pVCpu))
    4543             rcStrict = iemMemStoreDataU32(pVCpu, iSegReg, GCPtrMem + 2, (uint32_t)GCPtrBase);
    4544         else
    4545             rcStrict = iemMemStoreDataU64(pVCpu, iSegReg, GCPtrMem + 2, GCPtrBase);
    4546     }
    4547     return rcStrict;
    4548 }
    4549 
    4550 
    4551 /**
    4552  * Begin a special stack push (used by interrupt, exceptions and such).
    4553  *
    4554  * This will raise \#SS or \#PF if appropriate.
    4555  *
    4556  * @returns Strict VBox status code.
    4557  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4558  * @param   cbMem               The number of bytes to push onto the stack.
    4559  * @param   cbAlign             The alignment mask (7, 3, 1).
    4560  * @param   ppvMem              Where to return the pointer to the stack memory.
    4561  *                              As with the other memory functions this could be
    4562  *                              direct access or bounce buffered access, so
    4563  *                              don't commit register until the commit call
    4564  *                              succeeds.
    4565  * @param   pbUnmapInfo         Where to store unmap info for
    4566  *                              iemMemStackPushCommitSpecial.
    4567  * @param   puNewRsp            Where to return the new RSP value.  This must be
    4568  *                              passed unchanged to
    4569  *                              iemMemStackPushCommitSpecial().
    4570  */
    4571 VBOXSTRICTRC iemMemStackPushBeginSpecial(PVMCPUCC pVCpu, size_t cbMem, uint32_t cbAlign,
    4572                                          void **ppvMem, uint8_t *pbUnmapInfo, uint64_t *puNewRsp) RT_NOEXCEPT
    4573 {
    4574     Assert(cbMem < UINT8_MAX);
    4575     RTGCPTR GCPtrTop = iemRegGetRspForPush(pVCpu, (uint8_t)cbMem, puNewRsp);
    4576     return iemMemMap(pVCpu, ppvMem, pbUnmapInfo, cbMem, X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_W, cbAlign);
    4577 }
    4578 
    4579 
    4580 /**
    4581  * Commits a special stack push (started by iemMemStackPushBeginSpecial).
    4582  *
    4583  * This will update the rSP.
    4584  *
    4585  * @returns Strict VBox status code.
    4586  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4587  * @param   bUnmapInfo          Unmap info set by iemMemStackPushBeginSpecial.
    4588  * @param   uNewRsp             The new RSP value returned by
    4589  *                              iemMemStackPushBeginSpecial().
    4590  */
    4591 VBOXSTRICTRC iemMemStackPushCommitSpecial(PVMCPUCC pVCpu, uint8_t bUnmapInfo, uint64_t uNewRsp) RT_NOEXCEPT
    4592 {
    4593     VBOXSTRICTRC rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4594     if (rcStrict == VINF_SUCCESS)
    4595         pVCpu->cpum.GstCtx.rsp = uNewRsp;
    4596     return rcStrict;
    4597 }
    4598 
    4599 
    4600 /**
    4601  * Begin a special stack pop (used by iret, retf and such).
    4602  *
    4603  * This will raise \#SS or \#PF if appropriate.
    4604  *
    4605  * @returns Strict VBox status code.
    4606  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4607  * @param   cbMem               The number of bytes to pop from the stack.
    4608  * @param   cbAlign             The alignment mask (7, 3, 1).
    4609  * @param   ppvMem              Where to return the pointer to the stack memory.
    4610  * @param   pbUnmapInfo         Where to store unmap info for
    4611  *                              iemMemStackPopDoneSpecial.
    4612  * @param   puNewRsp            Where to return the new RSP value.  This must be
    4613  *                              assigned to CPUMCTX::rsp manually some time
    4614  *                              after iemMemStackPopDoneSpecial() has been
    4615  *                              called.
    4616  */
    4617 VBOXSTRICTRC iemMemStackPopBeginSpecial(PVMCPUCC pVCpu, size_t cbMem, uint32_t cbAlign,
    4618                                         void const **ppvMem, uint8_t *pbUnmapInfo, uint64_t *puNewRsp) RT_NOEXCEPT
    4619 {
    4620     Assert(cbMem < UINT8_MAX);
    4621     RTGCPTR     GCPtrTop = iemRegGetRspForPop(pVCpu, (uint8_t)cbMem, puNewRsp);
    4622     return iemMemMap(pVCpu, (void **)ppvMem, pbUnmapInfo, cbMem, X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_R, cbAlign);
    4623 }
    4624 
    4625 
    4626 /**
    4627  * Continue a special stack pop (used by iret and retf), for the purpose of
    4628  * retrieving a new stack pointer.
    4629  *
    4630  * This will raise \#SS or \#PF if appropriate.
    4631  *
    4632  * @returns Strict VBox status code.
    4633  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4634  * @param   off                 Offset from the top of the stack. This is zero
    4635  *                              except in the retf case.
    4636  * @param   cbMem               The number of bytes to pop from the stack.
    4637  * @param   ppvMem              Where to return the pointer to the stack memory.
    4638  * @param   pbUnmapInfo         Where to store unmap info for
    4639  *                              iemMemStackPopDoneSpecial.
    4640  * @param   uCurNewRsp          The current uncommitted RSP value.  (No need to
    4641  *                              return this because all use of this function is
    4642  *                              to retrieve a new value and anything we return
    4643  *                              here would be discarded.)
    4644  */
    4645 VBOXSTRICTRC iemMemStackPopContinueSpecial(PVMCPUCC pVCpu, size_t off, size_t cbMem,
    4646                                            void const **ppvMem, uint8_t *pbUnmapInfo, uint64_t uCurNewRsp) RT_NOEXCEPT
    4647 {
    4648     Assert(cbMem < UINT8_MAX);
    4649 
    4650     /* The essense of iemRegGetRspForPopEx and friends: */ /** @todo put this into a inlined function? */
    4651     RTGCPTR GCPtrTop;
    4652     if (IEM_IS_64BIT_CODE(pVCpu))
    4653         GCPtrTop = uCurNewRsp;
    4654     else if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
    4655         GCPtrTop = (uint32_t)uCurNewRsp;
    4656     else
    4657         GCPtrTop = (uint16_t)uCurNewRsp;
    4658 
    4659     return iemMemMap(pVCpu, (void **)ppvMem, pbUnmapInfo, cbMem, X86_SREG_SS, GCPtrTop + off, IEM_ACCESS_STACK_R,
    4660                      0 /* checked in iemMemStackPopBeginSpecial */);
    4661 }
    4662 
    4663 
    4664 /**
    4665  * Done with a special stack pop (started by iemMemStackPopBeginSpecial or
    4666  * iemMemStackPopContinueSpecial).
    4667  *
    4668  * The caller will manually commit the rSP.
    4669  *
    4670  * @returns Strict VBox status code.
    4671  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4672  * @param   bUnmapInfo          Unmap information returned by
    4673  *                              iemMemStackPopBeginSpecial() or
    4674  *                              iemMemStackPopContinueSpecial().
    4675  */
    4676 VBOXSTRICTRC iemMemStackPopDoneSpecial(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT
    4677 {
    4678     return iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4679 }
    4680 
    4681 
    4682 /**
    4683  * Fetches a system table byte.
    4684  *
    4685  * @returns Strict VBox status code.
    4686  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4687  * @param   pbDst               Where to return the byte.
    4688  * @param   iSegReg             The index of the segment register to use for
    4689  *                              this access.  The base and limits are checked.
    4690  * @param   GCPtrMem            The address of the guest memory.
    4691  */
    4692 VBOXSTRICTRC iemMemFetchSysU8(PVMCPUCC pVCpu, uint8_t *pbDst, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4693 {
    4694     /* The lazy approach for now... */
    4695     uint8_t        bUnmapInfo;
    4696     uint8_t const *pbSrc;
    4697     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pbSrc, &bUnmapInfo, sizeof(*pbSrc), iSegReg, GCPtrMem, IEM_ACCESS_SYS_R, 0);
    4698     if (rc == VINF_SUCCESS)
    4699     {
    4700         *pbDst = *pbSrc;
    4701         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4702     }
    4703     return rc;
    4704 }
    4705 
    4706 
    4707 /**
    4708  * Fetches a system table word.
    4709  *
    4710  * @returns Strict VBox status code.
    4711  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4712  * @param   pu16Dst             Where to return the word.
    4713  * @param   iSegReg             The index of the segment register to use for
    4714  *                              this access.  The base and limits are checked.
    4715  * @param   GCPtrMem            The address of the guest memory.
    4716  */
    4717 VBOXSTRICTRC iemMemFetchSysU16(PVMCPUCC pVCpu, uint16_t *pu16Dst, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4718 {
    4719     /* The lazy approach for now... */
    4720     uint8_t         bUnmapInfo;
    4721     uint16_t const *pu16Src;
    4722     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pu16Src, &bUnmapInfo, sizeof(*pu16Src), iSegReg, GCPtrMem, IEM_ACCESS_SYS_R, 0);
    4723     if (rc == VINF_SUCCESS)
    4724     {
    4725         *pu16Dst = *pu16Src;
    4726         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4727     }
    4728     return rc;
    4729 }
    4730 
    4731 
    4732 /**
    4733  * Fetches a system table dword.
    4734  *
    4735  * @returns Strict VBox status code.
    4736  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4737  * @param   pu32Dst             Where to return the dword.
    4738  * @param   iSegReg             The index of the segment register to use for
    4739  *                              this access.  The base and limits are checked.
    4740  * @param   GCPtrMem            The address of the guest memory.
    4741  */
    4742 VBOXSTRICTRC iemMemFetchSysU32(PVMCPUCC pVCpu, uint32_t *pu32Dst, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4743 {
    4744     /* The lazy approach for now... */
    4745     uint8_t         bUnmapInfo;
    4746     uint32_t const *pu32Src;
    4747     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pu32Src, &bUnmapInfo, sizeof(*pu32Src), iSegReg, GCPtrMem, IEM_ACCESS_SYS_R, 0);
    4748     if (rc == VINF_SUCCESS)
    4749     {
    4750         *pu32Dst = *pu32Src;
    4751         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4752     }
    4753     return rc;
    4754 }
    4755 
    4756 
    4757 /**
    4758  * Fetches a system table qword.
    4759  *
    4760  * @returns Strict VBox status code.
    4761  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4762  * @param   pu64Dst             Where to return the qword.
    4763  * @param   iSegReg             The index of the segment register to use for
    4764  *                              this access.  The base and limits are checked.
    4765  * @param   GCPtrMem            The address of the guest memory.
    4766  */
    4767 VBOXSTRICTRC iemMemFetchSysU64(PVMCPUCC pVCpu, uint64_t *pu64Dst, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4768 {
    4769     /* The lazy approach for now... */
    4770     uint8_t         bUnmapInfo;
    4771     uint64_t const *pu64Src;
    4772     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pu64Src, &bUnmapInfo, sizeof(*pu64Src), iSegReg, GCPtrMem, IEM_ACCESS_SYS_R, 0);
    4773     if (rc == VINF_SUCCESS)
    4774     {
    4775         *pu64Dst = *pu64Src;
    4776         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4777     }
    4778     return rc;
    4779 }
    4780 
    4781 
    4782 /**
    4783  * Fetches a descriptor table entry with caller specified error code.
    4784  *
    4785  * @returns Strict VBox status code.
    4786  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4787  * @param   pDesc               Where to return the descriptor table entry.
    4788  * @param   uSel                The selector which table entry to fetch.
    4789  * @param   uXcpt               The exception to raise on table lookup error.
    4790  * @param   uErrorCode          The error code associated with the exception.
    4791  */
    4792 VBOXSTRICTRC iemMemFetchSelDescWithErr(PVMCPUCC pVCpu, PIEMSELDESC pDesc, uint16_t uSel,
    4793                                        uint8_t uXcpt, uint16_t uErrorCode)  RT_NOEXCEPT
    4794 {
    4795     AssertPtr(pDesc);
    4796     IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_GDTR | CPUMCTX_EXTRN_LDTR);
    4797 
    4798     /** @todo did the 286 require all 8 bytes to be accessible? */
    4799     /*
    4800      * Get the selector table base and check bounds.
    4801      */
    4802     RTGCPTR GCPtrBase;
    4803     if (uSel & X86_SEL_LDT)
    4804     {
    4805         if (   !pVCpu->cpum.GstCtx.ldtr.Attr.n.u1Present
    4806             || (uSel | X86_SEL_RPL_LDT) > pVCpu->cpum.GstCtx.ldtr.u32Limit )
    4807         {
    4808             LogEx(LOG_GROUP_IEM, ("iemMemFetchSelDesc: LDT selector %#x is out of bounds (%3x) or ldtr is NP (%#x)\n",
    4809                    uSel, pVCpu->cpum.GstCtx.ldtr.u32Limit, pVCpu->cpum.GstCtx.ldtr.Sel));
    4810             return iemRaiseXcptOrInt(pVCpu, 0, uXcpt, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR,
    4811                                      uErrorCode, 0);
    4812         }
    4813 
    4814         Assert(pVCpu->cpum.GstCtx.ldtr.Attr.n.u1Present);
    4815         GCPtrBase = pVCpu->cpum.GstCtx.ldtr.u64Base;
    4816     }
    4817     else
    4818     {
    4819         if ((uSel | X86_SEL_RPL_LDT) > pVCpu->cpum.GstCtx.gdtr.cbGdt)
    4820         {
    4821             LogEx(LOG_GROUP_IEM, ("iemMemFetchSelDesc: GDT selector %#x is out of bounds (%3x)\n", uSel, pVCpu->cpum.GstCtx.gdtr.cbGdt));
    4822             return iemRaiseXcptOrInt(pVCpu, 0, uXcpt, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR,
    4823                                      uErrorCode, 0);
    4824         }
    4825         GCPtrBase = pVCpu->cpum.GstCtx.gdtr.pGdt;
    4826     }
    4827 
    4828     /*
    4829      * Read the legacy descriptor and maybe the long mode extensions if
    4830      * required.
    4831      */
    4832     VBOXSTRICTRC rcStrict;
    4833     if (IEM_GET_TARGET_CPU(pVCpu) > IEMTARGETCPU_286)
    4834         rcStrict = iemMemFetchSysU64(pVCpu, &pDesc->Legacy.u, UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK));
    4835     else
    4836     {
    4837         rcStrict     = iemMemFetchSysU16(pVCpu, &pDesc->Legacy.au16[0], UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK) + 0);
    4838         if (rcStrict == VINF_SUCCESS)
    4839             rcStrict = iemMemFetchSysU16(pVCpu, &pDesc->Legacy.au16[1], UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK) + 2);
    4840         if (rcStrict == VINF_SUCCESS)
    4841             rcStrict = iemMemFetchSysU16(pVCpu, &pDesc->Legacy.au16[2], UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK) + 4);
    4842         if (rcStrict == VINF_SUCCESS)
    4843             pDesc->Legacy.au16[3] = 0;
    4844         else
    4845             return rcStrict;
    4846     }
    4847 
    4848     if (rcStrict == VINF_SUCCESS)
    4849     {
    4850         if (   !IEM_IS_LONG_MODE(pVCpu)
    4851             || pDesc->Legacy.Gen.u1DescType)
    4852             pDesc->Long.au64[1] = 0;
    4853         else if (   (uint32_t)(uSel | X86_SEL_RPL_LDT) + 8
    4854                  <= (uSel & X86_SEL_LDT ? pVCpu->cpum.GstCtx.ldtr.u32Limit : pVCpu->cpum.GstCtx.gdtr.cbGdt))
    4855             rcStrict = iemMemFetchSysU64(pVCpu, &pDesc->Long.au64[1], UINT8_MAX, GCPtrBase + (uSel | X86_SEL_RPL_LDT) + 1);
    4856         else
    4857         {
    4858             LogEx(LOG_GROUP_IEM,("iemMemFetchSelDesc: system selector %#x is out of bounds\n", uSel));
    4859             /** @todo is this the right exception? */
    4860             return iemRaiseXcptOrInt(pVCpu, 0, uXcpt, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR, uErrorCode, 0);
    4861         }
    4862     }
    4863     return rcStrict;
    4864 }
    4865 
    4866 
    4867 /**
    4868  * Fetches a descriptor table entry.
    4869  *
    4870  * @returns Strict VBox status code.
    4871  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4872  * @param   pDesc               Where to return the descriptor table entry.
    4873  * @param   uSel                The selector which table entry to fetch.
    4874  * @param   uXcpt               The exception to raise on table lookup error.
    4875  */
    4876 VBOXSTRICTRC iemMemFetchSelDesc(PVMCPUCC pVCpu, PIEMSELDESC pDesc, uint16_t uSel, uint8_t uXcpt) RT_NOEXCEPT
    4877 {
    4878     return iemMemFetchSelDescWithErr(pVCpu, pDesc, uSel, uXcpt, uSel & X86_SEL_MASK_OFF_RPL);
    4879 }
    4880 
    4881 
    4882 /**
    4883  * Marks the selector descriptor as accessed (only non-system descriptors).
    4884  *
    4885  * This function ASSUMES that iemMemFetchSelDesc has be called previously and
    4886  * will therefore skip the limit checks.
    4887  *
    4888  * @returns Strict VBox status code.
    4889  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4890  * @param   uSel                The selector.
    4891  */
    4892 VBOXSTRICTRC iemMemMarkSelDescAccessed(PVMCPUCC pVCpu, uint16_t uSel) RT_NOEXCEPT
    4893 {
    4894     /*
    4895      * Get the selector table base and calculate the entry address.
    4896      */
    4897     RTGCPTR GCPtr = uSel & X86_SEL_LDT
    4898                   ? pVCpu->cpum.GstCtx.ldtr.u64Base
    4899                   : pVCpu->cpum.GstCtx.gdtr.pGdt;
    4900     GCPtr += uSel & X86_SEL_MASK;
    4901 
    4902     /*
    4903      * ASMAtomicBitSet will assert if the address is misaligned, so do some
    4904      * ugly stuff to avoid this.  This will make sure it's an atomic access
    4905      * as well more or less remove any question about 8-bit or 32-bit accesss.
    4906      */
    4907     VBOXSTRICTRC        rcStrict;
    4908     uint8_t             bUnmapInfo;
    4909     uint32_t volatile  *pu32;
    4910     if ((GCPtr & 3) == 0)
    4911     {
    4912         /* The normal case, map the 32-bit bits around the accessed bit (40). */
    4913         GCPtr += 2 + 2;
    4914         rcStrict = iemMemMap(pVCpu, (void **)&pu32, &bUnmapInfo, 4, UINT8_MAX, GCPtr, IEM_ACCESS_SYS_RW, 0);
    4915         if (rcStrict != VINF_SUCCESS)
    4916             return rcStrict;
    4917         ASMAtomicBitSet(pu32, 8); /* X86_SEL_TYPE_ACCESSED is 1, but it is preceeded by u8BaseHigh1. */
    4918     }
    4919     else
    4920     {
    4921         /* The misaligned GDT/LDT case, map the whole thing. */
    4922         rcStrict = iemMemMap(pVCpu, (void **)&pu32, &bUnmapInfo, 8, UINT8_MAX, GCPtr, IEM_ACCESS_SYS_RW, 0);
    4923         if (rcStrict != VINF_SUCCESS)
    4924             return rcStrict;
    4925         switch ((uintptr_t)pu32 & 3)
    4926         {
    4927             case 0: ASMAtomicBitSet(pu32,                         40 + 0 -  0); break;
    4928             case 1: ASMAtomicBitSet((uint8_t volatile *)pu32 + 3, 40 + 0 - 24); break;
    4929             case 2: ASMAtomicBitSet((uint8_t volatile *)pu32 + 2, 40 + 0 - 16); break;
    4930             case 3: ASMAtomicBitSet((uint8_t volatile *)pu32 + 1, 40 + 0 -  8); break;
    4931         }
    4932     }
    4933 
    4934     return iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4935 }
    4936 
    49372731
    49382732#undef  LOG_GROUP
  • trunk/src/VBox/VMM/VMMAll/target-x86/IEMAllHlpFpu-x86.cpp

    r108220 r108226  
    4545#include <VBox/vmm/vmcc.h>
    4646#include <VBox/log.h>
    47 #include <VBox/err.h>
     47#include <iprt/errcore.h>
    4848#include <iprt/assert.h>
    4949#include <iprt/string.h>
  • trunk/src/VBox/VMM/VMMAll/target-x86/IEMAllMem-x86.cpp

    r108220 r108226  
    11/* $Id$ */
    22/** @file
    3  * IEM - Interpreted Execution Manager - All Contexts.
     3 * IEM - Interpreted Execution Manager - x86 target, memory.
    44 */
    55
     
    2727
    2828
    29 /** @page pg_iem    IEM - Interpreted Execution Manager
    30  *
    31  * The interpreted exeuction manager (IEM) is for executing short guest code
    32  * sequences that are causing too many exits / virtualization traps.  It will
    33  * also be used to interpret single instructions, thus replacing the selective
    34  * interpreters in EM and IOM.
    35  *
    36  * Design goals:
    37  *      - Relatively small footprint, although we favour speed and correctness
    38  *        over size.
    39  *      - Reasonably fast.
    40  *      - Correctly handle lock prefixed instructions.
    41  *      - Complete instruction set - eventually.
    42  *      - Refactorable into a recompiler, maybe.
    43  *      - Replace EMInterpret*.
    44  *
    45  * Using the existing disassembler has been considered, however this is thought
    46  * to conflict with speed as the disassembler chews things a bit too much while
    47  * leaving us with a somewhat complicated state to interpret afterwards.
    48  *
    49  *
    50  * The current code is very much work in progress. You've been warned!
    51  *
    52  *
    53  * @section sec_iem_fpu_instr   FPU Instructions
    54  *
    55  * On x86 and AMD64 hosts, the FPU instructions are implemented by executing the
    56  * same or equivalent instructions on the host FPU.  To make life easy, we also
    57  * let the FPU prioritize the unmasked exceptions for us.  This however, only
    58  * works reliably when CR0.NE is set, i.e. when using \#MF instead the IRQ 13
    59  * for FPU exception delivery, because with CR0.NE=0 there is a window where we
    60  * can trigger spurious FPU exceptions.
    61  *
    62  * The guest FPU state is not loaded into the host CPU and kept there till we
    63  * leave IEM because the calling conventions have declared an all year open
    64  * season on much of the FPU state.  For instance an innocent looking call to
    65  * memcpy might end up using a whole bunch of XMM or MM registers if the
    66  * particular implementation finds it worthwhile.
    67  *
    68  *
    69  * @section sec_iem_logging     Logging
    70  *
    71  * The IEM code uses the \"IEM\" log group for the main logging. The different
    72  * logging levels/flags are generally used for the following purposes:
    73  *      - Level 1  (Log)  : Errors, exceptions, interrupts and such major events.
    74  *      - Flow  (LogFlow) : Basic enter/exit IEM state info.
    75  *      - Level 2  (Log2) : ?
    76  *      - Level 3  (Log3) : More detailed enter/exit IEM state info.
    77  *      - Level 4  (Log4) : Decoding mnemonics w/ EIP.
    78  *      - Level 5  (Log5) : Decoding details.
    79  *      - Level 6  (Log6) : Enables/disables the lockstep comparison with REM.
    80  *      - Level 7  (Log7) : iret++ execution logging.
    81  *      - Level 8  (Log8) :
    82  *      - Level 9  (Log9) :
    83  *      - Level 10 (Log10): TLBs.
    84  *      - Level 11 (Log11): Unmasked FPU exceptions.
    85  *
    86  * The \"IEM_MEM\" log group covers most of memory related details logging,
    87  * except for errors and exceptions:
    88  *      - Level 1  (Log)  : Reads.
    89  *      - Level 2  (Log2) : Read fallbacks.
    90  *      - Level 3  (Log3) : MemMap read.
    91  *      - Level 4  (Log4) : MemMap read fallbacks.
    92  *      - Level 5  (Log5) : Writes
    93  *      - Level 6  (Log6) : Write fallbacks.
    94  *      - Level 7  (Log7) : MemMap writes and read-writes.
    95  *      - Level 8  (Log8) : MemMap write and read-write fallbacks.
    96  *      - Level 9  (Log9) : Stack reads.
    97  *      - Level 10 (Log10): Stack read fallbacks.
    98  *      - Level 11 (Log11): Stack writes.
    99  *      - Level 12 (Log12): Stack write fallbacks.
    100  *      - Flow  (LogFlow) :
    101  *
    102  * The SVM (AMD-V) and VMX (VT-x) code has the following assignments:
    103  *      - Level 1  (Log)  : Errors and other major events.
    104  *      - Flow (LogFlow)  : Misc flow stuff (cleanup?)
    105  *      - Level 2  (Log2) : VM exits.
    106  *
    107  * The syscall logging level assignments:
    108  *      - Level 1: DOS and BIOS.
    109  *      - Level 2: Windows 3.x
    110  *      - Level 3: Linux.
    111  */
    112 
    113 /* Disabled warning C4505: 'iemRaisePageFaultJmp' : unreferenced local function has been removed */
    114 #ifdef _MSC_VER
    115 # pragma warning(disable:4505)
    116 #endif
    117 
    118 
    11929/*********************************************************************************************************************************
    12030*   Header Files                                                                                                                 *
    12131*********************************************************************************************************************************/
    122 #define LOG_GROUP   LOG_GROUP_IEM
     32#define LOG_GROUP LOG_GROUP_IEM_MEM
    12333#define VMCPU_INCL_CPUM_GST_CTX
    12434#ifdef IN_RING0
     
    12737#include <VBox/vmm/iem.h>
    12838#include <VBox/vmm/cpum.h>
    129 #include <VBox/vmm/pdmapic.h>
    130 #include <VBox/vmm/pdm.h>
    13139#include <VBox/vmm/pgm.h>
    132 #include <VBox/vmm/iom.h>
    133 #include <VBox/vmm/em.h>
    134 #include <VBox/vmm/hm.h>
    135 #include <VBox/vmm/nem.h>
    136 #include <VBox/vmm/gcm.h>
    137 #include <VBox/vmm/gim.h>
    138 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM
    139 # include <VBox/vmm/em.h>
    140 # include <VBox/vmm/hm_svm.h>
    141 #endif
    142 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    143 # include <VBox/vmm/hmvmxinline.h>
    144 #endif
    145 #include <VBox/vmm/tm.h>
    14640#include <VBox/vmm/dbgf.h>
    147 #include <VBox/vmm/dbgftrace.h>
    14841#include "IEMInternal.h"
    14942#include <VBox/vmm/vmcc.h>
    15043#include <VBox/log.h>
    15144#include <VBox/err.h>
    152 #include <VBox/param.h>
    153 #include <VBox/dis.h>
    154 #include <iprt/asm-math.h>
    155 #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
    156 # include <iprt/asm-amd64-x86.h>
    157 #elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
    158 # include <iprt/asm-arm.h>
    159 #endif
    16045#include <iprt/assert.h>
    16146#include <iprt/string.h>
     
    16348
    16449#include "IEMInline.h"
    165 
    166 
    167 /*********************************************************************************************************************************
    168 *   Structures and Typedefs                                                                                                      *
    169 *********************************************************************************************************************************/
    170 /**
    171  * CPU exception classes.
    172  */
    173 typedef enum IEMXCPTCLASS
    174 {
    175     IEMXCPTCLASS_BENIGN,
    176     IEMXCPTCLASS_CONTRIBUTORY,
    177     IEMXCPTCLASS_PAGE_FAULT,
    178     IEMXCPTCLASS_DOUBLE_FAULT
    179 } IEMXCPTCLASS;
    180 
    181 
    182 /*********************************************************************************************************************************
    183 *   Global Variables                                                                                                             *
    184 *********************************************************************************************************************************/
    185 #if defined(IEM_LOG_MEMORY_WRITES)
    186 /** What IEM just wrote. */
    187 uint8_t g_abIemWrote[256];
    188 /** How much IEM just wrote. */
    189 size_t g_cbIemWrote;
    190 #endif
    191 
    192 
    193 /**
    194  * Calculates IEM_F_BRK_PENDING_XXX (IEM_F_PENDING_BRK_MASK) flags, slow code
    195  * path.
    196  *
    197  * This will also invalidate TLB entries for any pages with active data
    198  * breakpoints on them.
    199  *
    200  * @returns IEM_F_BRK_PENDING_XXX or zero.
    201  * @param   pVCpu               The cross context virtual CPU structure of the
    202  *                              calling thread.
    203  *
    204  * @note    Don't call directly, use iemCalcExecDbgFlags instead.
    205  */
    206 uint32_t iemCalcExecDbgFlagsSlow(PVMCPUCC pVCpu)
    207 {
    208     uint32_t fExec = 0;
    209 
    210     /*
    211      * Helper for invalidate the data TLB for breakpoint addresses.
    212      *
    213      * This is to make sure any access to the page will always trigger a TLB
    214      * load for as long as the breakpoint is enabled.
    215      */
    216 #ifdef IEM_WITH_DATA_TLB
    217 # define INVALID_TLB_ENTRY_FOR_BP(a_uValue) do { \
    218         RTGCPTR uTagNoRev = (a_uValue); \
    219         uTagNoRev = IEMTLB_CALC_TAG_NO_REV(uTagNoRev); \
    220         /** @todo do large page accounting */ \
    221         uintptr_t const idxEven = IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev); \
    222         if (pVCpu->iem.s.DataTlb.aEntries[idxEven].uTag == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevision)) \
    223             pVCpu->iem.s.DataTlb.aEntries[idxEven].uTag = 0; \
    224         if (pVCpu->iem.s.DataTlb.aEntries[idxEven + 1].uTag == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevisionGlobal)) \
    225             pVCpu->iem.s.DataTlb.aEntries[idxEven + 1].uTag = 0; \
    226     } while (0)
    227 #else
    228 # define INVALID_TLB_ENTRY_FOR_BP(a_uValue) do { } while (0)
    229 #endif
    230 
    231     /*
    232      * Process guest breakpoints.
    233      */
    234 #define PROCESS_ONE_BP(a_fDr7, a_iBp, a_uValue) do { \
    235         if (a_fDr7 & X86_DR7_L_G(a_iBp)) \
    236         { \
    237             switch (X86_DR7_GET_RW(a_fDr7, a_iBp)) \
    238             { \
    239                 case X86_DR7_RW_EO: \
    240                     fExec |= IEM_F_PENDING_BRK_INSTR; \
    241                     break; \
    242                 case X86_DR7_RW_WO: \
    243                 case X86_DR7_RW_RW: \
    244                     fExec |= IEM_F_PENDING_BRK_DATA; \
    245                     INVALID_TLB_ENTRY_FOR_BP(a_uValue); \
    246                     break; \
    247                 case X86_DR7_RW_IO: \
    248                     fExec |= IEM_F_PENDING_BRK_X86_IO; \
    249                     break; \
    250             } \
    251         } \
    252     } while (0)
    253 
    254     uint32_t const fGstDr7 = (uint32_t)pVCpu->cpum.GstCtx.dr[7];
    255     if (fGstDr7 & X86_DR7_ENABLED_MASK)
    256     {
    257 /** @todo extract more details here to simplify matching later. */
    258 #ifdef IEM_WITH_DATA_TLB
    259         IEM_CTX_IMPORT_NORET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
    260 #endif
    261         PROCESS_ONE_BP(fGstDr7, 0, pVCpu->cpum.GstCtx.dr[0]);
    262         PROCESS_ONE_BP(fGstDr7, 1, pVCpu->cpum.GstCtx.dr[1]);
    263         PROCESS_ONE_BP(fGstDr7, 2, pVCpu->cpum.GstCtx.dr[2]);
    264         PROCESS_ONE_BP(fGstDr7, 3, pVCpu->cpum.GstCtx.dr[3]);
    265     }
    266 
    267     /*
    268      * Process hypervisor breakpoints.
    269      */
    270     PVMCC const    pVM       = pVCpu->CTX_SUFF(pVM);
    271     uint32_t const fHyperDr7 = DBGFBpGetDR7(pVM);
    272     if (fHyperDr7 & X86_DR7_ENABLED_MASK)
    273     {
    274 /** @todo extract more details here to simplify matching later. */
    275         PROCESS_ONE_BP(fHyperDr7, 0, DBGFBpGetDR0(pVM));
    276         PROCESS_ONE_BP(fHyperDr7, 1, DBGFBpGetDR1(pVM));
    277         PROCESS_ONE_BP(fHyperDr7, 2, DBGFBpGetDR2(pVM));
    278         PROCESS_ONE_BP(fHyperDr7, 3, DBGFBpGetDR3(pVM));
    279     }
    280 
    281     return fExec;
    282 }
    283 
    284 
    285 /**
    286  * Initializes the decoder state.
    287  *
    288  * iemReInitDecoder is mostly a copy of this function.
    289  *
    290  * @param   pVCpu               The cross context virtual CPU structure of the
    291  *                              calling thread.
    292  * @param   fExecOpts           Optional execution flags:
    293  *                                  - IEM_F_BYPASS_HANDLERS
    294  *                                  - IEM_F_X86_DISREGARD_LOCK
    295  */
    296 DECLINLINE(void) iemInitDecoder(PVMCPUCC pVCpu, uint32_t fExecOpts)
    297 {
    298     IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_MUST_MASK);
    299     Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_IEM));
    300     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));
    301     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
    302     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.es));
    303     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ds));
    304     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.fs));
    305     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.gs));
    306     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ldtr));
    307     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.tr));
    308 
    309     /* Execution state: */
    310     uint32_t fExec;
    311     pVCpu->iem.s.fExec = fExec = iemCalcExecFlags(pVCpu) | fExecOpts;
    312 
    313     /* Decoder state: */
    314     pVCpu->iem.s.enmDefAddrMode     = fExec & IEM_F_MODE_CPUMODE_MASK;  /** @todo check if this is correct... */
    315     pVCpu->iem.s.enmEffAddrMode     = fExec & IEM_F_MODE_CPUMODE_MASK;
    316     if ((fExec & IEM_F_MODE_CPUMODE_MASK) != IEMMODE_64BIT)
    317     {
    318         pVCpu->iem.s.enmDefOpSize   = fExec & IEM_F_MODE_CPUMODE_MASK;  /** @todo check if this is correct... */
    319         pVCpu->iem.s.enmEffOpSize   = fExec & IEM_F_MODE_CPUMODE_MASK;
    320     }
    321     else
    322     {
    323         pVCpu->iem.s.enmDefOpSize   = IEMMODE_32BIT;
    324         pVCpu->iem.s.enmEffOpSize   = IEMMODE_32BIT;
    325     }
    326     pVCpu->iem.s.fPrefixes          = 0;
    327     pVCpu->iem.s.uRexReg            = 0;
    328     pVCpu->iem.s.uRexB              = 0;
    329     pVCpu->iem.s.uRexIndex          = 0;
    330     pVCpu->iem.s.idxPrefix          = 0;
    331     pVCpu->iem.s.uVex3rdReg         = 0;
    332     pVCpu->iem.s.uVexLength         = 0;
    333     pVCpu->iem.s.fEvexStuff         = 0;
    334     pVCpu->iem.s.iEffSeg            = X86_SREG_DS;
    335 #ifdef IEM_WITH_CODE_TLB
    336     pVCpu->iem.s.pbInstrBuf         = NULL;
    337     pVCpu->iem.s.offInstrNextByte   = 0;
    338     pVCpu->iem.s.offCurInstrStart   = 0;
    339 # ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
    340     pVCpu->iem.s.offOpcode          = 0;
    341 # endif
    342 # ifdef VBOX_STRICT
    343     pVCpu->iem.s.GCPhysInstrBuf     = NIL_RTGCPHYS;
    344     pVCpu->iem.s.cbInstrBuf         = UINT16_MAX;
    345     pVCpu->iem.s.cbInstrBufTotal    = UINT16_MAX;
    346     pVCpu->iem.s.uInstrBufPc        = UINT64_C(0xc0ffc0ffcff0c0ff);
    347 # endif
    348 #else
    349     pVCpu->iem.s.offOpcode          = 0;
    350     pVCpu->iem.s.cbOpcode           = 0;
    351 #endif
    352     pVCpu->iem.s.offModRm           = 0;
    353     pVCpu->iem.s.cActiveMappings    = 0;
    354     pVCpu->iem.s.iNextMapping       = 0;
    355     pVCpu->iem.s.rcPassUp           = VINF_SUCCESS;
    356 
    357 #ifdef DBGFTRACE_ENABLED
    358     switch (IEM_GET_CPU_MODE(pVCpu))
    359     {
    360         case IEMMODE_64BIT:
    361             RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I64/%u %08llx", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.rip);
    362             break;
    363         case IEMMODE_32BIT:
    364             RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I32/%u %04x:%08x", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip);
    365             break;
    366         case IEMMODE_16BIT:
    367             RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I16/%u %04x:%04x", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip);
    368             break;
    369     }
    370 #endif
    371 }
    372 
    373 
    374 /**
    375  * Reinitializes the decoder state 2nd+ loop of IEMExecLots.
    376  *
    377  * This is mostly a copy of iemInitDecoder.
    378  *
    379  * @param   pVCpu               The cross context virtual CPU structure of the calling EMT.
    380  */
    381 DECLINLINE(void) iemReInitDecoder(PVMCPUCC pVCpu)
    382 {
    383     Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_IEM));
    384     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));
    385     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
    386     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.es));
    387     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ds));
    388     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.fs));
    389     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.gs));
    390     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ldtr));
    391     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.tr));
    392 
    393     /* ASSUMES: Anyone changing CPU state affecting the fExec bits will update them! */
    394     AssertMsg((pVCpu->iem.s.fExec & ~IEM_F_USER_OPTS) == iemCalcExecFlags(pVCpu),
    395               ("fExec=%#x iemCalcExecModeFlags=%#x\n", pVCpu->iem.s.fExec, iemCalcExecFlags(pVCpu)));
    396 
    397     IEMMODE const enmMode = IEM_GET_CPU_MODE(pVCpu);
    398     pVCpu->iem.s.enmDefAddrMode     = enmMode;  /** @todo check if this is correct... */
    399     pVCpu->iem.s.enmEffAddrMode     = enmMode;
    400     if (enmMode != IEMMODE_64BIT)
    401     {
    402         pVCpu->iem.s.enmDefOpSize   = enmMode;  /** @todo check if this is correct... */
    403         pVCpu->iem.s.enmEffOpSize   = enmMode;
    404     }
    405     else
    406     {
    407         pVCpu->iem.s.enmDefOpSize   = IEMMODE_32BIT;
    408         pVCpu->iem.s.enmEffOpSize   = IEMMODE_32BIT;
    409     }
    410     pVCpu->iem.s.fPrefixes          = 0;
    411     pVCpu->iem.s.uRexReg            = 0;
    412     pVCpu->iem.s.uRexB              = 0;
    413     pVCpu->iem.s.uRexIndex          = 0;
    414     pVCpu->iem.s.idxPrefix          = 0;
    415     pVCpu->iem.s.uVex3rdReg         = 0;
    416     pVCpu->iem.s.uVexLength         = 0;
    417     pVCpu->iem.s.fEvexStuff         = 0;
    418     pVCpu->iem.s.iEffSeg            = X86_SREG_DS;
    419 #ifdef IEM_WITH_CODE_TLB
    420     if (pVCpu->iem.s.pbInstrBuf)
    421     {
    422         uint64_t off = (enmMode == IEMMODE_64BIT
    423                         ? pVCpu->cpum.GstCtx.rip
    424                         : pVCpu->cpum.GstCtx.eip + (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base)
    425                      - pVCpu->iem.s.uInstrBufPc;
    426         if (off < pVCpu->iem.s.cbInstrBufTotal)
    427         {
    428             pVCpu->iem.s.offInstrNextByte = (uint32_t)off;
    429             pVCpu->iem.s.offCurInstrStart = (uint16_t)off;
    430             if ((uint16_t)off + 15 <= pVCpu->iem.s.cbInstrBufTotal)
    431                 pVCpu->iem.s.cbInstrBuf = (uint16_t)off + 15;
    432             else
    433                 pVCpu->iem.s.cbInstrBuf = pVCpu->iem.s.cbInstrBufTotal;
    434         }
    435         else
    436         {
    437             pVCpu->iem.s.pbInstrBuf       = NULL;
    438             pVCpu->iem.s.offInstrNextByte = 0;
    439             pVCpu->iem.s.offCurInstrStart = 0;
    440             pVCpu->iem.s.cbInstrBuf       = 0;
    441             pVCpu->iem.s.cbInstrBufTotal  = 0;
    442             pVCpu->iem.s.GCPhysInstrBuf   = NIL_RTGCPHYS;
    443         }
    444     }
    445     else
    446     {
    447         pVCpu->iem.s.offInstrNextByte = 0;
    448         pVCpu->iem.s.offCurInstrStart = 0;
    449         pVCpu->iem.s.cbInstrBuf       = 0;
    450         pVCpu->iem.s.cbInstrBufTotal  = 0;
    451 # ifdef VBOX_STRICT
    452         pVCpu->iem.s.GCPhysInstrBuf   = NIL_RTGCPHYS;
    453 # endif
    454     }
    455 # ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
    456     pVCpu->iem.s.offOpcode          = 0;
    457 # endif
    458 #else  /* !IEM_WITH_CODE_TLB */
    459     pVCpu->iem.s.cbOpcode           = 0;
    460     pVCpu->iem.s.offOpcode          = 0;
    461 #endif /* !IEM_WITH_CODE_TLB */
    462     pVCpu->iem.s.offModRm           = 0;
    463     Assert(pVCpu->iem.s.cActiveMappings == 0);
    464     pVCpu->iem.s.iNextMapping       = 0;
    465     Assert(pVCpu->iem.s.rcPassUp   == VINF_SUCCESS);
    466     Assert(!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS));
    467 
    468 #ifdef DBGFTRACE_ENABLED
    469     switch (enmMode)
    470     {
    471         case IEMMODE_64BIT:
    472             RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I64/%u %08llx", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.rip);
    473             break;
    474         case IEMMODE_32BIT:
    475             RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I32/%u %04x:%08x", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip);
    476             break;
    477         case IEMMODE_16BIT:
    478             RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I16/%u %04x:%04x", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip);
    479             break;
    480     }
    481 #endif
    482 }
    483 
    484 
    485 
    486 /**
    487  * Prefetch opcodes the first time when starting executing.
    488  *
    489  * @returns Strict VBox status code.
    490  * @param   pVCpu               The cross context virtual CPU structure of the
    491  *                              calling thread.
    492  * @param   fExecOpts           Optional execution flags:
    493  *                                  - IEM_F_BYPASS_HANDLERS
    494  *                                  - IEM_F_X86_DISREGARD_LOCK
    495  */
    496 static VBOXSTRICTRC iemInitDecoderAndPrefetchOpcodes(PVMCPUCC pVCpu, uint32_t fExecOpts) RT_NOEXCEPT
    497 {
    498     iemInitDecoder(pVCpu, fExecOpts);
    499 
    500 #ifndef IEM_WITH_CODE_TLB
    501     /*
    502      * What we're doing here is very similar to iemMemMap/iemMemBounceBufferMap.
    503      *
    504      * First translate CS:rIP to a physical address.
    505      *
    506      * Note! The iemOpcodeFetchMoreBytes code depends on this here code to fetch
    507      *       all relevant bytes from the first page, as it ASSUMES it's only ever
    508      *       called for dealing with CS.LIM, page crossing and instructions that
    509      *       are too long.
    510      */
    511     uint32_t    cbToTryRead;
    512     RTGCPTR     GCPtrPC;
    513     if (IEM_IS_64BIT_CODE(pVCpu))
    514     {
    515         cbToTryRead = GUEST_PAGE_SIZE;
    516         GCPtrPC     = pVCpu->cpum.GstCtx.rip;
    517         if (IEM_IS_CANONICAL(GCPtrPC))
    518             cbToTryRead = GUEST_PAGE_SIZE - (GCPtrPC & GUEST_PAGE_OFFSET_MASK);
    519         else
    520             return iemRaiseGeneralProtectionFault0(pVCpu);
    521     }
    522     else
    523     {
    524         uint32_t GCPtrPC32 = pVCpu->cpum.GstCtx.eip;
    525         AssertMsg(!(GCPtrPC32 & ~(uint32_t)UINT16_MAX) || IEM_IS_32BIT_CODE(pVCpu), ("%04x:%RX64\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    526         if (GCPtrPC32 <= pVCpu->cpum.GstCtx.cs.u32Limit)
    527             cbToTryRead = pVCpu->cpum.GstCtx.cs.u32Limit - GCPtrPC32 + 1;
    528         else
    529             return iemRaiseSelectorBounds(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
    530         if (cbToTryRead) { /* likely */ }
    531         else /* overflowed */
    532         {
    533             Assert(GCPtrPC32 == 0); Assert(pVCpu->cpum.GstCtx.cs.u32Limit == UINT32_MAX);
    534             cbToTryRead = UINT32_MAX;
    535         }
    536         GCPtrPC = (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base + GCPtrPC32;
    537         Assert(GCPtrPC <= UINT32_MAX);
    538     }
    539 
    540     PGMPTWALKFAST WalkFast;
    541     int rc = PGMGstQueryPageFast(pVCpu, GCPtrPC,
    542                                  IEM_GET_CPL(pVCpu) == 3 ? PGMQPAGE_F_EXECUTE | PGMQPAGE_F_USER_MODE : PGMQPAGE_F_EXECUTE,
    543                                  &WalkFast);
    544     if (RT_SUCCESS(rc))
    545         Assert(WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED);
    546     else
    547     {
    548         Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - rc=%Rrc\n", GCPtrPC, rc));
    549 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    550 /** @todo This isn't quite right yet, as PGM_GST_SLAT_NAME_EPT(Walk) doesn't
    551  * know about what kind of access we're making! See PGM_GST_NAME(WalkFast). */
    552         if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    553             IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
    554 # endif
    555         return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, rc);
    556     }
    557 #if 0
    558     if ((WalkFast.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3) { /* likely */ }
    559     else
    560     {
    561         Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - supervisor page\n", GCPtrPC));
    562 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    563 /** @todo this is completely wrong for EPT. WalkFast.fFailed is always zero here!*/
    564 #  error completely wrong
    565         if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    566             IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
    567 # endif
    568         return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
    569     }
    570     if (!(WalkFast.fEffective & X86_PTE_PAE_NX) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE)) { /* likely */ }
    571     else
    572     {
    573         Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - NX\n", GCPtrPC));
    574 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    575 /** @todo this is completely wrong for EPT. WalkFast.fFailed is always zero here!*/
    576 #  error completely wrong.
    577         if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    578             IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
    579 # endif
    580         return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
    581     }
    582 #else
    583     Assert((WalkFast.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3);
    584     Assert(!(WalkFast.fEffective & X86_PTE_PAE_NX) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE));
    585 #endif
    586     RTGCPHYS const GCPhys = WalkFast.GCPhys;
    587 
    588     /*
    589      * Read the bytes at this address.
    590      */
    591     uint32_t cbLeftOnPage = GUEST_PAGE_SIZE - (GCPtrPC & GUEST_PAGE_OFFSET_MASK);
    592     if (cbToTryRead > cbLeftOnPage)
    593         cbToTryRead = cbLeftOnPage;
    594     if (cbToTryRead > sizeof(pVCpu->iem.s.abOpcode))
    595         cbToTryRead = sizeof(pVCpu->iem.s.abOpcode);
    596 
    597     if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))
    598     {
    599         VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), GCPhys, pVCpu->iem.s.abOpcode, cbToTryRead, PGMACCESSORIGIN_IEM);
    600         if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    601         { /* likely */ }
    602         else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    603         {
    604             Log(("iemInitDecoderAndPrefetchOpcodes: %RGv/%RGp LB %#x - read status -  rcStrict=%Rrc\n",
    605                  GCPtrPC, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead));
    606             rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    607         }
    608         else
    609         {
    610             Log((RT_SUCCESS(rcStrict)
    611                  ? "iemInitDecoderAndPrefetchOpcodes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n"
    612                  : "iemInitDecoderAndPrefetchOpcodes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n",
    613                  GCPtrPC, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead));
    614             return rcStrict;
    615         }
    616     }
    617     else
    618     {
    619         rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), pVCpu->iem.s.abOpcode, GCPhys, cbToTryRead);
    620         if (RT_SUCCESS(rc))
    621         { /* likely */ }
    622         else
    623         {
    624             Log(("iemInitDecoderAndPrefetchOpcodes: %RGv/%RGp LB %#x - read error - rc=%Rrc (!!)\n",
    625                  GCPtrPC, GCPhys, rc, cbToTryRead));
    626             return rc;
    627         }
    628     }
    629     pVCpu->iem.s.cbOpcode = cbToTryRead;
    630 #endif /* !IEM_WITH_CODE_TLB */
    631     return VINF_SUCCESS;
    632 }
    633 
    634 
    635 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    636 /**
    637  * Helper for doing large page accounting at TLB load time.
    638  */
    639 template<bool const a_fGlobal>
    640 DECL_FORCE_INLINE(void) iemTlbLoadedLargePage(PVMCPUCC pVCpu, IEMTLB *pTlb, RTGCPTR uTagNoRev, bool f2MbLargePages)
    641 {
    642     if (a_fGlobal)
    643         pTlb->cTlbGlobalLargePageCurLoads++;
    644     else
    645         pTlb->cTlbNonGlobalLargePageCurLoads++;
    646 
    647 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    648     RTGCPTR const idxBit = IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + a_fGlobal;
    649     ASMBitSet(pTlb->bmLargePage, idxBit);
    650 # endif
    651 
    652     AssertCompile(IEMTLB_CALC_TAG_NO_REV((RTGCPTR)0x8731U << GUEST_PAGE_SHIFT) == 0x8731U);
    653     uint32_t const                 fMask = (f2MbLargePages ? _2M - 1U : _4M - 1U) >> GUEST_PAGE_SHIFT;
    654     IEMTLB::LARGEPAGERANGE * const pRange = a_fGlobal
    655                                           ? &pTlb->GlobalLargePageRange
    656                                           : &pTlb->NonGlobalLargePageRange;
    657     uTagNoRev &= ~(RTGCPTR)fMask;
    658     if (uTagNoRev < pRange->uFirstTag)
    659         pRange->uFirstTag = uTagNoRev;
    660 
    661     uTagNoRev |= fMask;
    662     if (uTagNoRev > pRange->uLastTag)
    663         pRange->uLastTag = uTagNoRev;
    664 
    665     RT_NOREF_PV(pVCpu);
    666 }
    667 #endif
    668 
    669 
    670 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    671 /**
    672  * Worker for iemTlbInvalidateAll.
    673  */
    674 template<bool a_fGlobal>
    675 DECL_FORCE_INLINE(void) iemTlbInvalidateOne(IEMTLB *pTlb)
    676 {
    677     if (!a_fGlobal)
    678         pTlb->cTlsFlushes++;
    679     else
    680         pTlb->cTlsGlobalFlushes++;
    681 
    682     pTlb->uTlbRevision += IEMTLB_REVISION_INCR;
    683     if (RT_LIKELY(pTlb->uTlbRevision != 0))
    684     { /* very likely */ }
    685     else
    686     {
    687         pTlb->uTlbRevision = IEMTLB_REVISION_INCR;
    688         pTlb->cTlbRevisionRollovers++;
    689         unsigned i = RT_ELEMENTS(pTlb->aEntries) / 2;
    690         while (i-- > 0)
    691             pTlb->aEntries[i * 2].uTag = 0;
    692     }
    693 
    694     pTlb->cTlbNonGlobalLargePageCurLoads    = 0;
    695     pTlb->NonGlobalLargePageRange.uLastTag  = 0;
    696     pTlb->NonGlobalLargePageRange.uFirstTag = UINT64_MAX;
    697 
    698     if (a_fGlobal)
    699     {
    700         pTlb->uTlbRevisionGlobal += IEMTLB_REVISION_INCR;
    701         if (RT_LIKELY(pTlb->uTlbRevisionGlobal != 0))
    702         { /* very likely */ }
    703         else
    704         {
    705             pTlb->uTlbRevisionGlobal = IEMTLB_REVISION_INCR;
    706             pTlb->cTlbRevisionRollovers++;
    707             unsigned i = RT_ELEMENTS(pTlb->aEntries) / 2;
    708             while (i-- > 0)
    709                 pTlb->aEntries[i * 2 + 1].uTag = 0;
    710         }
    711 
    712         pTlb->cTlbGlobalLargePageCurLoads    = 0;
    713         pTlb->GlobalLargePageRange.uLastTag  = 0;
    714         pTlb->GlobalLargePageRange.uFirstTag = UINT64_MAX;
    715     }
    716 }
    717 #endif
    718 
    719 
    720 /**
    721  * Worker for IEMTlbInvalidateAll and IEMTlbInvalidateAllGlobal.
    722  */
    723 template<bool a_fGlobal>
    724 DECL_FORCE_INLINE(void) iemTlbInvalidateAll(PVMCPUCC pVCpu)
    725 {
    726 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    727     Log10(("IEMTlbInvalidateAll\n"));
    728 
    729 # ifdef IEM_WITH_CODE_TLB
    730     pVCpu->iem.s.cbInstrBufTotal = 0;
    731     iemTlbInvalidateOne<a_fGlobal>(&pVCpu->iem.s.CodeTlb);
    732     if (a_fGlobal)
    733         IEMTLBTRACE_FLUSH_GLOBAL(pVCpu, pVCpu->iem.s.CodeTlb.uTlbRevision, pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal, false);
    734     else
    735         IEMTLBTRACE_FLUSH(pVCpu, pVCpu->iem.s.CodeTlb.uTlbRevision, false);
    736 # endif
    737 
    738 # ifdef IEM_WITH_DATA_TLB
    739     iemTlbInvalidateOne<a_fGlobal>(&pVCpu->iem.s.DataTlb);
    740     if (a_fGlobal)
    741         IEMTLBTRACE_FLUSH_GLOBAL(pVCpu, pVCpu->iem.s.DataTlb.uTlbRevision, pVCpu->iem.s.DataTlb.uTlbRevisionGlobal, true);
    742     else
    743         IEMTLBTRACE_FLUSH(pVCpu, pVCpu->iem.s.DataTlb.uTlbRevision, true);
    744 # endif
    745 #else
    746     RT_NOREF(pVCpu);
    747 #endif
    748 }
    749 
    750 
    751 /**
    752  * Invalidates non-global the IEM TLB entries.
    753  *
    754  * This is called internally as well as by PGM when moving GC mappings.
    755  *
    756  * @param   pVCpu       The cross context virtual CPU structure of the calling
    757  *                      thread.
    758  */
    759 VMM_INT_DECL(void) IEMTlbInvalidateAll(PVMCPUCC pVCpu)
    760 {
    761     iemTlbInvalidateAll<false>(pVCpu);
    762 }
    763 
    764 
    765 /**
    766  * Invalidates all the IEM TLB entries.
    767  *
    768  * This is called internally as well as by PGM when moving GC mappings.
    769  *
    770  * @param   pVCpu       The cross context virtual CPU structure of the calling
    771  *                      thread.
    772  */
    773 VMM_INT_DECL(void) IEMTlbInvalidateAllGlobal(PVMCPUCC pVCpu)
    774 {
    775     iemTlbInvalidateAll<true>(pVCpu);
    776 }
    777 
    778 
    779 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    780 
    781 /** @todo graduate this to cdefs.h or asm-mem.h.   */
    782 # ifdef RT_ARCH_ARM64              /** @todo RT_CACHELINE_SIZE is wrong for M1 */
    783 #  undef RT_CACHELINE_SIZE
    784 #  define RT_CACHELINE_SIZE 128
    785 # endif
    786 
    787 # if defined(_MM_HINT_T0) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
    788 #  define MY_PREFETCH(a_pvAddr)     _mm_prefetch((const char *)(a_pvAddr), _MM_HINT_T0)
    789 # elif defined(_MSC_VER) && (defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32))
    790 #  define MY_PREFETCH(a_pvAddr)     __prefetch((a_pvAddr))
    791 # elif defined(__GNUC__) || RT_CLANG_HAS_FEATURE(__builtin_prefetch)
    792 #  define MY_PREFETCH(a_pvAddr)     __builtin_prefetch((a_pvAddr), 0 /*rw*/, 3 /*locality*/)
    793 # else
    794 #  define MY_PREFETCH(a_pvAddr)     ((void)0)
    795 # endif
    796 # if 0
    797 #  undef  MY_PREFETCH
    798 #  define MY_PREFETCH(a_pvAddr)     ((void)0)
    799 # endif
    800 
    801 /** @def MY_PREFETCH_64
    802  * 64 byte prefetch hint, could be more depending on cache line size. */
    803 /** @def MY_PREFETCH_128
    804  * 128 byte prefetch hint. */
    805 /** @def MY_PREFETCH_256
    806  * 256 byte prefetch hint. */
    807 # if RT_CACHELINE_SIZE >= 128
    808     /* 128 byte cache lines */
    809 #  define MY_PREFETCH_64(a_pvAddr)  MY_PREFETCH(a_pvAddr)
    810 #  define MY_PREFETCH_128(a_pvAddr) MY_PREFETCH(a_pvAddr)
    811 #  define MY_PREFETCH_256(a_pvAddr) do { \
    812         MY_PREFETCH(a_pvAddr); \
    813         MY_PREFETCH((uint8_t const *)a_pvAddr + 128); \
    814     } while (0)
    815 # else
    816     /* 64 byte cache lines */
    817 #  define MY_PREFETCH_64(a_pvAddr)  MY_PREFETCH(a_pvAddr)
    818 #  define MY_PREFETCH_128(a_pvAddr) do { \
    819         MY_PREFETCH(a_pvAddr); \
    820         MY_PREFETCH((uint8_t const *)a_pvAddr + 64); \
    821     } while (0)
    822 #  define MY_PREFETCH_256(a_pvAddr) do { \
    823         MY_PREFETCH(a_pvAddr); \
    824         MY_PREFETCH((uint8_t const *)a_pvAddr + 64); \
    825         MY_PREFETCH((uint8_t const *)a_pvAddr + 128); \
    826         MY_PREFETCH((uint8_t const *)a_pvAddr + 192); \
    827     } while (0)
    828 # endif
    829 
    830 template<bool const a_fDataTlb, bool const a_f2MbLargePage, bool const a_fGlobal, bool const a_fNonGlobal>
    831 DECLINLINE(void) iemTlbInvalidateLargePageWorkerInner(PVMCPUCC pVCpu, IEMTLB *pTlb, RTGCPTR GCPtrTag,
    832                                                       RTGCPTR GCPtrInstrBufPcTag) RT_NOEXCEPT
    833 {
    834     IEMTLBTRACE_LARGE_SCAN(pVCpu, a_fGlobal, a_fNonGlobal, a_fDataTlb);
    835     AssertCompile(IEMTLB_ENTRY_COUNT >= 16); /* prefetching + unroll assumption */
    836 
    837     if (a_fGlobal)
    838         pTlb->cTlbInvlPgLargeGlobal += 1;
    839     if (a_fNonGlobal)
    840         pTlb->cTlbInvlPgLargeNonGlobal += 1;
    841 
    842     /*
    843      * Set up the scan.
    844      *
    845      * GCPtrTagMask: A 2MB page consists of 512 4K pages, so a 256 TLB will map
    846      * offset zero and offset 1MB to the same slot pair.  Our GCPtrTag[Globl]
    847      * values are for the range 0-1MB, or slots 0-256.  So, we construct a mask
    848      * that fold large page offsets 1MB-2MB into the 0-1MB range.
    849      *
    850      * For our example with 2MB pages and a 256 entry TLB: 0xfffffffffffffeff
    851      *
    852      * MY_PREFETCH: Hope that prefetching 256 bytes at the time is okay for
    853      * relevant host architectures.
    854      */
    855     /** @todo benchmark this code from the guest side. */
    856     bool const      fPartialScan = IEMTLB_ENTRY_COUNT > (a_f2MbLargePage ? 512 : 1024);
    857 #ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    858     uintptr_t       idxBitmap    = fPartialScan ? IEMTLB_TAG_TO_EVEN_INDEX(GCPtrTag) / 64 : 0;
    859     uintptr_t const idxBitmapEnd = fPartialScan ? idxBitmap + ((a_f2MbLargePage ? 512 : 1024) * 2) / 64
    860                                                 : IEMTLB_ENTRY_COUNT * 2 / 64;
    861 #else
    862     uintptr_t       idxEven      = fPartialScan ? IEMTLB_TAG_TO_EVEN_INDEX(GCPtrTag) : 0;
    863     MY_PREFETCH_256(&pTlb->aEntries[idxEven + !a_fNonGlobal]);
    864     uintptr_t const idxEvenEnd   = fPartialScan ? idxEven + ((a_f2MbLargePage ? 512 : 1024) * 2) : IEMTLB_ENTRY_COUNT * 2;
    865 #endif
    866     RTGCPTR const   GCPtrTagMask = fPartialScan ? ~(RTGCPTR)0
    867                                  : ~(RTGCPTR)(  (RT_BIT_32(a_f2MbLargePage ? 9 : 10) - 1U)
    868                                               & ~(uint32_t)(RT_BIT_32(IEMTLB_ENTRY_COUNT_AS_POWER_OF_TWO) - 1U));
    869 
    870     /*
    871      * Set cbInstrBufTotal to zero if GCPtrInstrBufPcTag is within any of the tag ranges.
    872      * We make ASSUMPTIONS about IEMTLB_CALC_TAG_NO_REV here.
    873      */
    874     AssertCompile(IEMTLB_CALC_TAG_NO_REV((RTGCPTR)0x8731U << GUEST_PAGE_SHIFT) == 0x8731U);
    875     if (   !a_fDataTlb
    876         && GCPtrInstrBufPcTag - GCPtrTag < (a_f2MbLargePage ? 512U : 1024U))
    877         pVCpu->iem.s.cbInstrBufTotal = 0;
    878 
    879     /*
    880      * Combine TAG values with the TLB revisions.
    881      */
    882     RTGCPTR GCPtrTagGlob = a_fGlobal ? GCPtrTag | pTlb->uTlbRevisionGlobal : 0;
    883     if (a_fNonGlobal)
    884         GCPtrTag |= pTlb->uTlbRevision;
    885 
    886     /*
    887      * Do the scanning.
    888      */
    889 #ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    890     uint64_t const bmMask  = a_fGlobal && a_fNonGlobal ? UINT64_MAX
    891                            : a_fGlobal ? UINT64_C(0xaaaaaaaaaaaaaaaa) : UINT64_C(0x5555555555555555);
    892     /* Scan bitmap entries (64 bits at the time): */
    893     for (;;)
    894     {
    895 # if 1
    896         uint64_t bmEntry = pTlb->bmLargePage[idxBitmap] & bmMask;
    897         if (bmEntry)
    898         {
    899             /* Scan the non-zero 64-bit value in groups of 8 bits: */
    900             uint64_t  bmToClear = 0;
    901             uintptr_t idxEven   = idxBitmap * 64;
    902             uint32_t  idxTag    = 0;
    903             for (;;)
    904             {
    905                 if (bmEntry & 0xff)
    906                 {
    907 #  define ONE_PAIR(a_idxTagIter, a_idxEvenIter, a_bmNonGlobal, a_bmGlobal) \
    908                         if (a_fNonGlobal) \
    909                         { \
    910                             if (bmEntry & a_bmNonGlobal) \
    911                             { \
    912                                 Assert(pTlb->aEntries[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE); \
    913                                 if ((pTlb->aEntries[a_idxEvenIter].uTag & GCPtrTagMask) == (GCPtrTag + a_idxTagIter)) \
    914                                 { \
    915                                     IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTag + a_idxTagIter, \
    916                                                                  pTlb->aEntries[a_idxEvenIter].GCPhys, \
    917                                                                  a_idxEvenIter, a_fDataTlb); \
    918                                     pTlb->aEntries[a_idxEvenIter].uTag = 0; \
    919                                     bmToClearSub8 |= a_bmNonGlobal; \
    920                                 } \
    921                             } \
    922                             else \
    923                                 Assert(   !(pTlb->aEntries[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE)\
    924                                        ||    (pTlb->aEntries[a_idxEvenIter].uTag & IEMTLB_REVISION_MASK) \
    925                                           != (GCPtrTag & IEMTLB_REVISION_MASK)); \
    926                         } \
    927                         if (a_fGlobal) \
    928                         { \
    929                             if (bmEntry & a_bmGlobal) \
    930                             {  \
    931                                 Assert(pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE); \
    932                                 if ((pTlb->aEntries[a_idxEvenIter + 1].uTag & GCPtrTagMask) == (GCPtrTagGlob + a_idxTagIter)) \
    933                                 { \
    934                                     IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTagGlob + a_idxTagIter, \
    935                                                                  pTlb->aEntries[a_idxEvenIter + 1].GCPhys, \
    936                                                                  a_idxEvenIter + 1, a_fDataTlb); \
    937                                     pTlb->aEntries[a_idxEvenIter + 1].uTag = 0; \
    938                                     bmToClearSub8 |= a_bmGlobal; \
    939                                 } \
    940                             } \
    941                             else \
    942                                 Assert(   !(pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE)\
    943                                        ||    (pTlb->aEntries[a_idxEvenIter + 1].uTag & IEMTLB_REVISION_MASK) \
    944                                           != (GCPtrTagGlob & IEMTLB_REVISION_MASK)); \
    945                         }
    946                     uint64_t bmToClearSub8 = 0;
    947                     ONE_PAIR(idxTag + 0, idxEven + 0, 0x01, 0x02)
    948                     ONE_PAIR(idxTag + 1, idxEven + 2, 0x04, 0x08)
    949                     ONE_PAIR(idxTag + 2, idxEven + 4, 0x10, 0x20)
    950                     ONE_PAIR(idxTag + 3, idxEven + 6, 0x40, 0x80)
    951                     bmToClear |= bmToClearSub8 << (idxTag * 2);
    952 #  undef ONE_PAIR
    953                 }
    954 
    955                 /* advance to the next 8 bits. */
    956                 bmEntry >>= 8;
    957                 if (!bmEntry)
    958                     break;
    959                 idxEven  += 8;
    960                 idxTag   += 4;
    961             }
    962 
    963             /* Clear the large page flags we covered. */
    964             pTlb->bmLargePage[idxBitmap] &= ~bmToClear;
    965         }
    966 # else
    967         uint64_t const bmEntry = pTlb->bmLargePage[idxBitmap] & bmMask;
    968         if (bmEntry)
    969         {
    970             /* Scan the non-zero 64-bit value completely unrolled: */
    971             uintptr_t const idxEven   = idxBitmap * 64;
    972             uint64_t        bmToClear = 0;
    973 #  define ONE_PAIR(a_idxTagIter, a_idxEvenIter, a_bmNonGlobal, a_bmGlobal) \
    974                 if (a_fNonGlobal) \
    975                 { \
    976                     if (bmEntry & a_bmNonGlobal) \
    977                     { \
    978                         Assert(pTlb->aEntries[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE); \
    979                         if ((pTlb->aEntries[a_idxEvenIter].uTag & GCPtrTagMask) == (GCPtrTag + a_idxTagIter)) \
    980                         { \
    981                             IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTag + a_idxTagIter, \
    982                                                          pTlb->aEntries[a_idxEvenIter].GCPhys, \
    983                                                          a_idxEvenIter, a_fDataTlb); \
    984                             pTlb->aEntries[a_idxEvenIter].uTag = 0; \
    985                             bmToClear |= a_bmNonGlobal; \
    986                         } \
    987                     } \
    988                     else \
    989                         Assert(   !(pTlb->aEntriqes[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE)\
    990                                ||    (pTlb->aEntries[a_idxEvenIter].uTag & IEMTLB_REVISION_MASK) \
    991                                   != (GCPtrTag & IEMTLB_REVISION_MASK)); \
    992                 } \
    993                 if (a_fGlobal) \
    994                 { \
    995                     if (bmEntry & a_bmGlobal) \
    996                     {  \
    997                         Assert(pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE); \
    998                         if ((pTlb->aEntries[a_idxEvenIter + 1].uTag & GCPtrTagMask) == (GCPtrTagGlob + a_idxTagIter)) \
    999                         { \
    1000                             IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTagGlob + a_idxTagIter, \
    1001                                                          pTlb->aEntries[a_idxEvenIter + 1].GCPhys, \
    1002                                                          a_idxEvenIter + 1, a_fDataTlb); \
    1003                             pTlb->aEntries[a_idxEvenIter + 1].uTag = 0; \
    1004                             bmToClear |= a_bmGlobal; \
    1005                         } \
    1006                     } \
    1007                     else \
    1008                         Assert(   !(pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE)\
    1009                                ||    (pTlb->aEntries[a_idxEvenIter + 1].uTag & IEMTLB_REVISION_MASK) \
    1010                                   != (GCPtrTagGlob & IEMTLB_REVISION_MASK)); \
    1011                 } ((void)0)
    1012 #  define FOUR_PAIRS(a_iByte, a_cShift) \
    1013                 ONE_PAIR(0 + a_iByte * 4, idxEven + 0 + a_iByte * 8, UINT64_C(0x01) << a_cShift, UINT64_C(0x02) << a_cShift); \
    1014                 ONE_PAIR(1 + a_iByte * 4, idxEven + 2 + a_iByte * 8, UINT64_C(0x04) << a_cShift, UINT64_C(0x08) << a_cShift); \
    1015                 ONE_PAIR(2 + a_iByte * 4, idxEven + 4 + a_iByte * 8, UINT64_C(0x10) << a_cShift, UINT64_C(0x20) << a_cShift); \
    1016                 ONE_PAIR(3 + a_iByte * 4, idxEven + 6 + a_iByte * 8, UINT64_C(0x40) << a_cShift, UINT64_C(0x80) << a_cShift)
    1017             if (bmEntry & (uint32_t)UINT16_MAX)
    1018             {
    1019                 FOUR_PAIRS(0,  0);
    1020                 FOUR_PAIRS(1,  8);
    1021             }
    1022             if (bmEntry & ((uint32_t)UINT16_MAX << 16))
    1023             {
    1024                 FOUR_PAIRS(2, 16);
    1025                 FOUR_PAIRS(3, 24);
    1026             }
    1027             if (bmEntry & ((uint64_t)UINT16_MAX << 32))
    1028             {
    1029                 FOUR_PAIRS(4, 32);
    1030                 FOUR_PAIRS(5, 40);
    1031             }
    1032             if (bmEntry & ((uint64_t)UINT16_MAX << 16))
    1033             {
    1034                 FOUR_PAIRS(6, 48);
    1035                 FOUR_PAIRS(7, 56);
    1036             }
    1037 #  undef FOUR_PAIRS
    1038 
    1039             /* Clear the large page flags we covered. */
    1040             pTlb->bmLargePage[idxBitmap] &= ~bmToClear;
    1041         }
    1042 # endif
    1043 
    1044         /* advance */
    1045         idxBitmap++;
    1046         if (idxBitmap >= idxBitmapEnd)
    1047             break;
    1048         if (a_fNonGlobal)
    1049             GCPtrTag     += 32;
    1050         if (a_fGlobal)
    1051             GCPtrTagGlob += 32;
    1052     }
    1053 
    1054 #else  /* !IEMTLB_WITH_LARGE_PAGE_BITMAP */
    1055 
    1056     for (; idxEven < idxEvenEnd; idxEven += 8)
    1057     {
    1058 # define ONE_ITERATION(a_idxEvenIter) \
    1059             if (a_fNonGlobal)  \
    1060             { \
    1061                 if ((pTlb->aEntries[a_idxEvenIter].uTag & GCPtrTagMask) == GCPtrTag) \
    1062                 { \
    1063                     if (pTlb->aEntries[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE) \
    1064                     { \
    1065                         IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTag, pTlb->aEntries[a_idxEvenIter].GCPhys, \
    1066                                                      a_idxEvenIter, a_fDataTlb); \
    1067                         pTlb->aEntries[a_idxEvenIter].uTag = 0; \
    1068                     } \
    1069                 } \
    1070                 GCPtrTag++; \
    1071             } \
    1072             \
    1073             if (a_fGlobal) \
    1074             { \
    1075                 if ((pTlb->aEntries[a_idxEvenIter + 1].uTag & GCPtrTagMask) == GCPtrTagGlob) \
    1076                 { \
    1077                     if (pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE) \
    1078                     { \
    1079                         IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTag, pTlb->aEntries[a_idxEvenIter + 1].GCPhys, \
    1080                                                      a_idxEvenIter + 1, a_fDataTlb); \
    1081                         pTlb->aEntries[a_idxEvenIter + 1].uTag = 0; \
    1082                     } \
    1083                 } \
    1084                 GCPtrTagGlob++; \
    1085             }
    1086         if (idxEven < idxEvenEnd - 4)
    1087             MY_PREFETCH_256(&pTlb->aEntries[idxEven +  8 + !a_fNonGlobal]);
    1088         ONE_ITERATION(idxEven)
    1089         ONE_ITERATION(idxEven + 2)
    1090         ONE_ITERATION(idxEven + 4)
    1091         ONE_ITERATION(idxEven + 6)
    1092 # undef ONE_ITERATION
    1093     }
    1094 #endif /* !IEMTLB_WITH_LARGE_PAGE_BITMAP */
    1095 }
    1096 
    1097 template<bool const a_fDataTlb, bool const a_f2MbLargePage>
    1098 DECLINLINE(void) iemTlbInvalidateLargePageWorker(PVMCPUCC pVCpu, IEMTLB *pTlb, RTGCPTR GCPtrTag,
    1099                                                  RTGCPTR GCPtrInstrBufPcTag) RT_NOEXCEPT
    1100 {
    1101     AssertCompile(IEMTLB_CALC_TAG_NO_REV((RTGCPTR)0x8731U << GUEST_PAGE_SHIFT) == 0x8731U);
    1102 
    1103     GCPtrTag &= ~(RTGCPTR)(RT_BIT_64((a_f2MbLargePage ? 21 : 22) - GUEST_PAGE_SHIFT) - 1U);
    1104     if (   GCPtrTag >= pTlb->GlobalLargePageRange.uFirstTag
    1105         && GCPtrTag <= pTlb->GlobalLargePageRange.uLastTag)
    1106     {
    1107         if (   GCPtrTag < pTlb->NonGlobalLargePageRange.uFirstTag
    1108             || GCPtrTag > pTlb->NonGlobalLargePageRange.uLastTag)
    1109             iemTlbInvalidateLargePageWorkerInner<a_fDataTlb, a_f2MbLargePage, true, false>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag);
    1110         else
    1111             iemTlbInvalidateLargePageWorkerInner<a_fDataTlb, a_f2MbLargePage, true, true>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag);
    1112     }
    1113     else if (   GCPtrTag < pTlb->NonGlobalLargePageRange.uFirstTag
    1114              || GCPtrTag > pTlb->NonGlobalLargePageRange.uLastTag)
    1115     {
    1116         /* Large pages aren't as likely in the non-global TLB half. */
    1117         IEMTLBTRACE_LARGE_SCAN(pVCpu, false, false, a_fDataTlb);
    1118     }
    1119     else
    1120         iemTlbInvalidateLargePageWorkerInner<a_fDataTlb, a_f2MbLargePage, false, true>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag);
    1121 }
    1122 
    1123 template<bool const a_fDataTlb>
    1124 DECLINLINE(void) iemTlbInvalidatePageWorker(PVMCPUCC pVCpu, IEMTLB *pTlb, RTGCPTR GCPtrTag, uintptr_t idxEven) RT_NOEXCEPT
    1125 {
    1126     pTlb->cTlbInvlPg += 1;
    1127 
    1128     /*
    1129      * Flush the entry pair.
    1130      */
    1131     if (pTlb->aEntries[idxEven].uTag == (GCPtrTag | pTlb->uTlbRevision))
    1132     {
    1133         IEMTLBTRACE_EVICT_SLOT(pVCpu, GCPtrTag, pTlb->aEntries[idxEven].GCPhys, idxEven, a_fDataTlb);
    1134         pTlb->aEntries[idxEven].uTag = 0;
    1135         if (!a_fDataTlb && GCPtrTag == IEMTLB_CALC_TAG_NO_REV(pVCpu->iem.s.uInstrBufPc))
    1136             pVCpu->iem.s.cbInstrBufTotal = 0;
    1137     }
    1138     if (pTlb->aEntries[idxEven + 1].uTag == (GCPtrTag | pTlb->uTlbRevisionGlobal))
    1139     {
    1140         IEMTLBTRACE_EVICT_SLOT(pVCpu, GCPtrTag, pTlb->aEntries[idxEven + 1].GCPhys, idxEven + 1, a_fDataTlb);
    1141         pTlb->aEntries[idxEven + 1].uTag = 0;
    1142         if (!a_fDataTlb && GCPtrTag == IEMTLB_CALC_TAG_NO_REV(pVCpu->iem.s.uInstrBufPc))
    1143             pVCpu->iem.s.cbInstrBufTotal = 0;
    1144     }
    1145 
    1146     /*
    1147      * If there are (or has been) large pages in the TLB, we must check if the
    1148      * address being flushed may involve one of those, as then we'd have to
    1149      * scan for entries relating to the same page and flush those as well.
    1150      */
    1151 # if 0 /** @todo do accurate counts or currently loaded large stuff and we can use those  */
    1152     if (pTlb->cTlbGlobalLargePageCurLoads || pTlb->cTlbNonGlobalLargePageCurLoads)
    1153 # else
    1154     if (pTlb->GlobalLargePageRange.uLastTag || pTlb->NonGlobalLargePageRange.uLastTag)
    1155 # endif
    1156     {
    1157         RTGCPTR const GCPtrInstrBufPcTag = a_fDataTlb ? 0 : IEMTLB_CALC_TAG_NO_REV(pVCpu->iem.s.uInstrBufPc);
    1158         if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE)
    1159             iemTlbInvalidateLargePageWorker<a_fDataTlb, true>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag);
    1160         else
    1161             iemTlbInvalidateLargePageWorker<a_fDataTlb, false>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag);
    1162     }
    1163 }
    1164 
    1165 #endif /* defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) */
    1166 
    1167 /**
    1168  * Invalidates a page in the TLBs.
    1169  *
    1170  * @param   pVCpu       The cross context virtual CPU structure of the calling
    1171  *                      thread.
    1172  * @param   GCPtr       The address of the page to invalidate
    1173  * @thread EMT(pVCpu)
    1174  */
    1175 VMM_INT_DECL(void) IEMTlbInvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCPtr)
    1176 {
    1177     IEMTLBTRACE_INVLPG(pVCpu, GCPtr);
    1178 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    1179     Log10(("IEMTlbInvalidatePage: GCPtr=%RGv\n", GCPtr));
    1180     GCPtr = IEMTLB_CALC_TAG_NO_REV(GCPtr);
    1181     Assert(!(GCPtr >> (48 - X86_PAGE_SHIFT)));
    1182     uintptr_t const idxEven = IEMTLB_TAG_TO_EVEN_INDEX(GCPtr);
    1183 
    1184 # ifdef IEM_WITH_CODE_TLB
    1185     iemTlbInvalidatePageWorker<false>(pVCpu, &pVCpu->iem.s.CodeTlb, GCPtr, idxEven);
    1186 # endif
    1187 # ifdef IEM_WITH_DATA_TLB
    1188     iemTlbInvalidatePageWorker<true>(pVCpu, &pVCpu->iem.s.DataTlb, GCPtr, idxEven);
    1189 # endif
    1190 #else
    1191     NOREF(pVCpu); NOREF(GCPtr);
    1192 #endif
    1193 }
    1194 
    1195 
    1196 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    1197 /**
    1198  * Invalid both TLBs slow fashion following a rollover.
    1199  *
    1200  * Worker for IEMTlbInvalidateAllPhysical,
    1201  * IEMTlbInvalidateAllPhysicalAllCpus, iemOpcodeFetchBytesJmp, iemMemMap,
    1202  * iemMemMapJmp and others.
    1203  *
    1204  * @thread EMT(pVCpu)
    1205  */
    1206 static void IEMTlbInvalidateAllPhysicalSlow(PVMCPUCC pVCpu)
    1207 {
    1208     Log10(("IEMTlbInvalidateAllPhysicalSlow\n"));
    1209     ASMAtomicWriteU64(&pVCpu->iem.s.CodeTlb.uTlbPhysRev, IEMTLB_PHYS_REV_INCR * 2);
    1210     ASMAtomicWriteU64(&pVCpu->iem.s.DataTlb.uTlbPhysRev, IEMTLB_PHYS_REV_INCR * 2);
    1211 
    1212     unsigned i;
    1213 # ifdef IEM_WITH_CODE_TLB
    1214     i = RT_ELEMENTS(pVCpu->iem.s.CodeTlb.aEntries);
    1215     while (i-- > 0)
    1216     {
    1217         pVCpu->iem.s.CodeTlb.aEntries[i].pbMappingR3       = NULL;
    1218         pVCpu->iem.s.CodeTlb.aEntries[i].fFlagsAndPhysRev &= ~(  IEMTLBE_F_PG_NO_WRITE   | IEMTLBE_F_PG_NO_READ
    1219                                                                | IEMTLBE_F_PG_UNASSIGNED | IEMTLBE_F_PHYS_REV);
    1220     }
    1221     pVCpu->iem.s.CodeTlb.cTlbPhysRevRollovers++;
    1222     pVCpu->iem.s.CodeTlb.cTlbPhysRevFlushes++;
    1223 # endif
    1224 # ifdef IEM_WITH_DATA_TLB
    1225     i = RT_ELEMENTS(pVCpu->iem.s.DataTlb.aEntries);
    1226     while (i-- > 0)
    1227     {
    1228         pVCpu->iem.s.DataTlb.aEntries[i].pbMappingR3       = NULL;
    1229         pVCpu->iem.s.DataTlb.aEntries[i].fFlagsAndPhysRev &= ~(  IEMTLBE_F_PG_NO_WRITE   | IEMTLBE_F_PG_NO_READ
    1230                                                                | IEMTLBE_F_PG_UNASSIGNED | IEMTLBE_F_PHYS_REV);
    1231     }
    1232     pVCpu->iem.s.DataTlb.cTlbPhysRevRollovers++;
    1233     pVCpu->iem.s.DataTlb.cTlbPhysRevFlushes++;
    1234 # endif
    1235 
    1236 }
    1237 #endif
    1238 
    1239 
    1240 /**
    1241  * Invalidates the host physical aspects of the IEM TLBs.
    1242  *
    1243  * This is called internally as well as by PGM when moving GC mappings.
    1244  *
    1245  * @param   pVCpu       The cross context virtual CPU structure of the calling
    1246  *                      thread.
    1247  * @note    Currently not used.
    1248  */
    1249 VMM_INT_DECL(void) IEMTlbInvalidateAllPhysical(PVMCPUCC pVCpu)
    1250 {
    1251 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    1252     /* Note! This probably won't end up looking exactly like this, but it give an idea... */
    1253     Log10(("IEMTlbInvalidateAllPhysical\n"));
    1254 
    1255 # ifdef IEM_WITH_CODE_TLB
    1256     pVCpu->iem.s.cbInstrBufTotal = 0;
    1257 # endif
    1258     uint64_t uTlbPhysRev = pVCpu->iem.s.CodeTlb.uTlbPhysRev + IEMTLB_PHYS_REV_INCR;
    1259     if (RT_LIKELY(uTlbPhysRev > IEMTLB_PHYS_REV_INCR * 2))
    1260     {
    1261         pVCpu->iem.s.CodeTlb.uTlbPhysRev = uTlbPhysRev;
    1262         pVCpu->iem.s.CodeTlb.cTlbPhysRevFlushes++;
    1263         pVCpu->iem.s.DataTlb.uTlbPhysRev = uTlbPhysRev;
    1264         pVCpu->iem.s.DataTlb.cTlbPhysRevFlushes++;
    1265     }
    1266     else
    1267         IEMTlbInvalidateAllPhysicalSlow(pVCpu);
    1268 #else
    1269     NOREF(pVCpu);
    1270 #endif
    1271 }
    1272 
    1273 
    1274 /**
    1275  * Invalidates the host physical aspects of the IEM TLBs.
    1276  *
    1277  * This is called internally as well as by PGM when moving GC mappings.
    1278  *
    1279  * @param   pVM         The cross context VM structure.
    1280  * @param   idCpuCaller The ID of the calling EMT if available to the caller,
    1281  *                      otherwise NIL_VMCPUID.
    1282  * @param   enmReason   The reason we're called.
    1283  *
    1284  * @remarks Caller holds the PGM lock.
    1285  */
    1286 VMM_INT_DECL(void) IEMTlbInvalidateAllPhysicalAllCpus(PVMCC pVM, VMCPUID idCpuCaller, IEMTLBPHYSFLUSHREASON enmReason)
    1287 {
    1288 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    1289     PVMCPUCC const pVCpuCaller = idCpuCaller >= pVM->cCpus ? VMMGetCpu(pVM) : VMMGetCpuById(pVM, idCpuCaller);
    1290     if (pVCpuCaller)
    1291         VMCPU_ASSERT_EMT(pVCpuCaller);
    1292     Log10(("IEMTlbInvalidateAllPhysicalAllCpus: %d\n", enmReason)); RT_NOREF(enmReason);
    1293 
    1294     VMCC_FOR_EACH_VMCPU(pVM)
    1295     {
    1296 # ifdef IEM_WITH_CODE_TLB
    1297         if (pVCpuCaller == pVCpu)
    1298             pVCpu->iem.s.cbInstrBufTotal = 0;
    1299 # endif
    1300 
    1301         uint64_t const uTlbPhysRevPrev = ASMAtomicUoReadU64(&pVCpu->iem.s.CodeTlb.uTlbPhysRev);
    1302         uint64_t       uTlbPhysRevNew  = uTlbPhysRevPrev + IEMTLB_PHYS_REV_INCR;
    1303         if (RT_LIKELY(uTlbPhysRevNew > IEMTLB_PHYS_REV_INCR * 2))
    1304         { /* likely */}
    1305         else if (pVCpuCaller != pVCpu)
    1306             uTlbPhysRevNew = IEMTLB_PHYS_REV_INCR;
    1307         else
    1308         {
    1309             IEMTlbInvalidateAllPhysicalSlow(pVCpu);
    1310             continue;
    1311         }
    1312         if (ASMAtomicCmpXchgU64(&pVCpu->iem.s.CodeTlb.uTlbPhysRev, uTlbPhysRevNew, uTlbPhysRevPrev))
    1313             pVCpu->iem.s.CodeTlb.cTlbPhysRevFlushes++;
    1314 
    1315         if (ASMAtomicCmpXchgU64(&pVCpu->iem.s.DataTlb.uTlbPhysRev, uTlbPhysRevNew, uTlbPhysRevPrev))
    1316             pVCpu->iem.s.DataTlb.cTlbPhysRevFlushes++;
    1317     }
    1318     VMCC_FOR_EACH_VMCPU_END(pVM);
    1319 
    1320 #else
    1321     RT_NOREF(pVM, idCpuCaller, enmReason);
    1322 #endif
    1323 }
    1324 
    1325 
    1326 /**
    1327  * Flushes the prefetch buffer, light version.
    1328  */
    1329 void iemOpcodeFlushLight(PVMCPUCC pVCpu, uint8_t cbInstr)
    1330 {
    1331 #ifndef IEM_WITH_CODE_TLB
    1332     pVCpu->iem.s.cbOpcode = cbInstr;
    1333 #else
    1334     RT_NOREF(pVCpu, cbInstr);
    1335 #endif
    1336 }
    1337 
    1338 
    1339 /**
    1340  * Flushes the prefetch buffer, heavy version.
    1341  */
    1342 void iemOpcodeFlushHeavy(PVMCPUCC pVCpu, uint8_t cbInstr)
    1343 {
    1344 #ifndef IEM_WITH_CODE_TLB
    1345     pVCpu->iem.s.cbOpcode = cbInstr; /* Note! SVM and VT-x may set this to zero on exit, rather than the instruction length. */
    1346 #elif 1
    1347     pVCpu->iem.s.cbInstrBufTotal = 0;
    1348     RT_NOREF(cbInstr);
    1349 #else
    1350     RT_NOREF(pVCpu, cbInstr);
    1351 #endif
    1352 }
    1353 
    1354 
    1355 
    1356 #ifdef IEM_WITH_CODE_TLB
    1357 
    1358 /**
    1359  * Tries to fetches @a cbDst opcode bytes, raise the appropriate exception on
    1360  * failure and jumps.
    1361  *
    1362  * We end up here for a number of reasons:
    1363  *      - pbInstrBuf isn't yet initialized.
    1364  *      - Advancing beyond the buffer boundrary (e.g. cross page).
    1365  *      - Advancing beyond the CS segment limit.
    1366  *      - Fetching from non-mappable page (e.g. MMIO).
    1367  *      - TLB loading in the recompiler (@a pvDst = NULL, @a cbDst = 0).
    1368  *
    1369  * @param   pVCpu               The cross context virtual CPU structure of the
    1370  *                              calling thread.
    1371  * @param   pvDst               Where to return the bytes.
    1372  * @param   cbDst               Number of bytes to read.  A value of zero is
    1373  *                              allowed for initializing pbInstrBuf (the
    1374  *                              recompiler does this).  In this case it is best
    1375  *                              to set pbInstrBuf to NULL prior to the call.
    1376  */
    1377 void iemOpcodeFetchBytesJmp(PVMCPUCC pVCpu, size_t cbDst, void *pvDst) IEM_NOEXCEPT_MAY_LONGJMP
    1378 {
    1379 # ifdef IN_RING3
    1380     for (;;)
    1381     {
    1382         Assert(cbDst <= 8);
    1383         uint32_t offBuf = pVCpu->iem.s.offInstrNextByte;
    1384 
    1385         /*
    1386          * We might have a partial buffer match, deal with that first to make the
    1387          * rest simpler.  This is the first part of the cross page/buffer case.
    1388          */
    1389         uint8_t const * const pbInstrBuf = pVCpu->iem.s.pbInstrBuf;
    1390         if (pbInstrBuf != NULL)
    1391         {
    1392             Assert(cbDst != 0); /* pbInstrBuf shall be NULL in case of a TLB load */
    1393             uint32_t const cbInstrBuf = pVCpu->iem.s.cbInstrBuf;
    1394             if (offBuf < cbInstrBuf)
    1395             {
    1396                 Assert(offBuf + cbDst > cbInstrBuf);
    1397                 uint32_t const cbCopy = cbInstrBuf - offBuf;
    1398                 memcpy(pvDst, &pbInstrBuf[offBuf], cbCopy);
    1399 
    1400                 cbDst  -= cbCopy;
    1401                 pvDst   = (uint8_t *)pvDst + cbCopy;
    1402                 offBuf += cbCopy;
    1403             }
    1404         }
    1405 
    1406         /*
    1407          * Check segment limit, figuring how much we're allowed to access at this point.
    1408          *
    1409          * We will fault immediately if RIP is past the segment limit / in non-canonical
    1410          * territory.  If we do continue, there are one or more bytes to read before we
    1411          * end up in trouble and we need to do that first before faulting.
    1412          */
    1413         RTGCPTR  GCPtrFirst;
    1414         uint32_t cbMaxRead;
    1415         if (IEM_IS_64BIT_CODE(pVCpu))
    1416         {
    1417             GCPtrFirst = pVCpu->cpum.GstCtx.rip + (offBuf - (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart);
    1418             if (RT_LIKELY(IEM_IS_CANONICAL(GCPtrFirst)))
    1419             { /* likely */ }
    1420             else
    1421                 iemRaiseGeneralProtectionFault0Jmp(pVCpu);
    1422             cbMaxRead = X86_PAGE_SIZE - ((uint32_t)GCPtrFirst & X86_PAGE_OFFSET_MASK);
    1423         }
    1424         else
    1425         {
    1426             GCPtrFirst = pVCpu->cpum.GstCtx.eip + (offBuf - (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart);
    1427             /* Assert(!(GCPtrFirst & ~(uint32_t)UINT16_MAX) || IEM_IS_32BIT_CODE(pVCpu)); - this is allowed */
    1428             if (RT_LIKELY((uint32_t)GCPtrFirst <= pVCpu->cpum.GstCtx.cs.u32Limit))
    1429             { /* likely */ }
    1430             else /** @todo For CPUs older than the 386, we should not necessarily generate \#GP here but wrap around! */
    1431                 iemRaiseSelectorBoundsJmp(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
    1432             cbMaxRead = pVCpu->cpum.GstCtx.cs.u32Limit - (uint32_t)GCPtrFirst + 1;
    1433             if (cbMaxRead != 0)
    1434             { /* likely */ }
    1435             else
    1436             {
    1437                 /* Overflowed because address is 0 and limit is max. */
    1438                 Assert(GCPtrFirst == 0); Assert(pVCpu->cpum.GstCtx.cs.u32Limit == UINT32_MAX);
    1439                 cbMaxRead = X86_PAGE_SIZE;
    1440             }
    1441             GCPtrFirst = (uint32_t)GCPtrFirst + (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base;
    1442             uint32_t cbMaxRead2 = X86_PAGE_SIZE - ((uint32_t)GCPtrFirst & X86_PAGE_OFFSET_MASK);
    1443             if (cbMaxRead2 < cbMaxRead)
    1444                 cbMaxRead = cbMaxRead2;
    1445             /** @todo testcase: unreal modes, both huge 16-bit and 32-bit. */
    1446         }
    1447 
    1448         /*
    1449          * Get the TLB entry for this piece of code.
    1450          */
    1451         uint64_t const uTagNoRev = IEMTLB_CALC_TAG_NO_REV(GCPtrFirst);
    1452         PIEMTLBENTRY   pTlbe     = IEMTLB_TAG_TO_EVEN_ENTRY(&pVCpu->iem.s.CodeTlb, uTagNoRev);
    1453         if (   pTlbe->uTag               == (uTagNoRev | pVCpu->iem.s.CodeTlb.uTlbRevision)
    1454             || (pTlbe = pTlbe + 1)->uTag == (uTagNoRev | pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal))
    1455         {
    1456             /* likely when executing lots of code, otherwise unlikely */
    1457 #  ifdef IEM_WITH_TLB_STATISTICS
    1458             pVCpu->iem.s.CodeTlb.cTlbCoreHits++;
    1459 #  endif
    1460             Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED));
    1461 
    1462             /* Check TLB page table level access flags. */
    1463             if (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_USER | IEMTLBE_F_PT_NO_EXEC))
    1464             {
    1465                 if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER) && IEM_GET_CPL(pVCpu) == 3)
    1466                 {
    1467                     Log(("iemOpcodeFetchBytesJmp: %RGv - supervisor page\n", GCPtrFirst));
    1468                     iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
    1469                 }
    1470                 if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_EXEC) && (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE))
    1471                 {
    1472                     Log(("iemOpcodeFetchMoreBytes: %RGv - NX\n", GCPtrFirst));
    1473                     iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
    1474                 }
    1475             }
    1476 
    1477             /* Look up the physical page info if necessary. */
    1478             if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pVCpu->iem.s.CodeTlb.uTlbPhysRev)
    1479             { /* not necessary */ }
    1480             else
    1481             {
    1482                 if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR))
    1483                 { /* likely */ }
    1484                 else
    1485                     IEMTlbInvalidateAllPhysicalSlow(pVCpu);
    1486                 pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK;
    1487                 int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.CodeTlb.uTlbPhysRev,
    1488                                                     &pTlbe->pbMappingR3, &pTlbe->fFlagsAndPhysRev);
    1489                 AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc));
    1490             }
    1491         }
    1492         else
    1493         {
    1494             pVCpu->iem.s.CodeTlb.cTlbCoreMisses++;
    1495 
    1496             /* This page table walking will set A bits as required by the access while performing the walk.
    1497                ASSUMES these are set when the address is translated rather than on commit... */
    1498             /** @todo testcase: check when A bits are actually set by the CPU for code.  */
    1499             PGMPTWALKFAST WalkFast;
    1500             int rc = PGMGstQueryPageFast(pVCpu, GCPtrFirst,
    1501                                          IEM_GET_CPL(pVCpu) == 3 ? PGMQPAGE_F_EXECUTE | PGMQPAGE_F_USER_MODE : PGMQPAGE_F_EXECUTE,
    1502                                          &WalkFast);
    1503             if (RT_SUCCESS(rc))
    1504                 Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
    1505             else
    1506             {
    1507 #  ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    1508                 /** @todo Nested VMX: Need to handle EPT violation/misconfig here?  OF COURSE! */
    1509                 Assert(!(Walk.fFailed & PGM_WALKFAIL_EPT));
    1510 #  endif
    1511                 Log(("iemOpcodeFetchMoreBytes: %RGv - rc=%Rrc\n", GCPtrFirst, rc));
    1512                 iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, rc);
    1513             }
    1514 
    1515             AssertCompile(IEMTLBE_F_PT_NO_EXEC == 1);
    1516             if (   !(WalkFast.fEffective & PGM_PTATTRS_G_MASK)
    1517                 || IEM_GET_CPL(pVCpu) != 0) /* optimization: Only use the PTE.G=1 entries in ring-0. */
    1518             {
    1519                 pTlbe--;
    1520                 pTlbe->uTag         = uTagNoRev | pVCpu->iem.s.CodeTlb.uTlbRevision;
    1521                 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE)
    1522                     iemTlbLoadedLargePage<false>(pVCpu, &pVCpu->iem.s.CodeTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE));
    1523 #  ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    1524                 else
    1525                     ASMBitClear(pVCpu->iem.s.CodeTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev));
    1526 #  endif
    1527             }
    1528             else
    1529             {
    1530                 pVCpu->iem.s.CodeTlb.cTlbCoreGlobalLoads++;
    1531                 pTlbe->uTag         = uTagNoRev | pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal;
    1532                 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE)
    1533                     iemTlbLoadedLargePage<true>(pVCpu, &pVCpu->iem.s.CodeTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE));
    1534 #  ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    1535                 else
    1536                     ASMBitClear(pVCpu->iem.s.CodeTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + 1);
    1537 #  endif
    1538             }
    1539             pTlbe->fFlagsAndPhysRev = (~WalkFast.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A))
    1540                                     | (WalkFast.fEffective >> X86_PTE_PAE_BIT_NX) /*IEMTLBE_F_PT_NO_EXEC*/
    1541                                     | (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE);
    1542             RTGCPHYS const GCPhysPg = WalkFast.GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
    1543             pTlbe->GCPhys           = GCPhysPg;
    1544             pTlbe->pbMappingR3      = NULL;
    1545             Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_EXEC) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE));
    1546             Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER) || IEM_GET_CPL(pVCpu) != 3);
    1547             Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED));
    1548 
    1549             if (!((uintptr_t)pTlbe & (sizeof(*pTlbe) * 2 - 1)))
    1550                 IEMTLBTRACE_LOAD(       pVCpu, GCPtrFirst, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, false);
    1551             else
    1552                 IEMTLBTRACE_LOAD_GLOBAL(pVCpu, GCPtrFirst, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, false);
    1553 
    1554             /* Resolve the physical address. */
    1555             if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR))
    1556             { /* likely */ }
    1557             else
    1558                 IEMTlbInvalidateAllPhysicalSlow(pVCpu);
    1559             Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_GCPHYS2PTR_MASK));
    1560             rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhysPg, &pVCpu->iem.s.CodeTlb.uTlbPhysRev,
    1561                                             &pTlbe->pbMappingR3, &pTlbe->fFlagsAndPhysRev);
    1562             AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc));
    1563         }
    1564 
    1565 # if defined(IN_RING3) || defined(IN_RING0) /** @todo fixme */
    1566         /*
    1567          * Try do a direct read using the pbMappingR3 pointer.
    1568          * Note! Do not recheck the physical TLB revision number here as we have the
    1569          *       wrong response to changes in the else case.  If someone is updating
    1570          *       pVCpu->iem.s.CodeTlb.uTlbPhysRev in parallel to us, we should be fine
    1571          *       pretending we always won the race.
    1572          */
    1573         if (    (pTlbe->fFlagsAndPhysRev & (/*IEMTLBE_F_PHYS_REV |*/ IEMTLBE_F_NO_MAPPINGR3 | IEMTLBE_F_PG_NO_READ))
    1574              == /*pVCpu->iem.s.CodeTlb.uTlbPhysRev*/ 0U)
    1575         {
    1576             uint32_t const offPg = (GCPtrFirst & X86_PAGE_OFFSET_MASK);
    1577             pVCpu->iem.s.cbInstrBufTotal = offPg + cbMaxRead;
    1578             if (offBuf == (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart)
    1579             {
    1580                 pVCpu->iem.s.cbInstrBuf       = offPg + RT_MIN(15, cbMaxRead);
    1581                 pVCpu->iem.s.offCurInstrStart = (int16_t)offPg;
    1582             }
    1583             else
    1584             {
    1585                 uint32_t const cbInstr = offBuf - (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart;
    1586                 if (cbInstr + (uint32_t)cbDst <= 15)
    1587                 {
    1588                     pVCpu->iem.s.cbInstrBuf       = offPg + RT_MIN(cbMaxRead + cbInstr, 15) - cbInstr;
    1589                     pVCpu->iem.s.offCurInstrStart = (int16_t)(offPg - cbInstr);
    1590                 }
    1591                 else
    1592                 {
    1593                     Log(("iemOpcodeFetchMoreBytes: %04x:%08RX64 LB %#x + %#zx -> #GP(0)\n",
    1594                          pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, cbInstr, cbDst));
    1595                     iemRaiseGeneralProtectionFault0Jmp(pVCpu);
    1596                 }
    1597             }
    1598             if (cbDst <= cbMaxRead)
    1599             {
    1600                 pVCpu->iem.s.fTbCrossedPage     |= offPg == 0 || pVCpu->iem.s.fTbBranched != 0; /** @todo Spurious load effect on branch handling? */
    1601 #  if 0 /* unused */
    1602                 pVCpu->iem.s.GCPhysInstrBufPrev  = pVCpu->iem.s.GCPhysInstrBuf;
    1603 #  endif
    1604                 pVCpu->iem.s.offInstrNextByte = offPg + (uint32_t)cbDst;
    1605                 pVCpu->iem.s.uInstrBufPc      = GCPtrFirst & ~(RTGCPTR)X86_PAGE_OFFSET_MASK;
    1606                 pVCpu->iem.s.GCPhysInstrBuf   = pTlbe->GCPhys;
    1607                 pVCpu->iem.s.pbInstrBuf       = pTlbe->pbMappingR3;
    1608                 if (cbDst > 0) /* To make ASAN happy in the TLB load case. */
    1609                     memcpy(pvDst, &pTlbe->pbMappingR3[offPg], cbDst);
    1610                 else
    1611                     Assert(!pvDst);
    1612                 return;
    1613             }
    1614             pVCpu->iem.s.pbInstrBuf = NULL;
    1615 
    1616             memcpy(pvDst, &pTlbe->pbMappingR3[offPg], cbMaxRead);
    1617             pVCpu->iem.s.offInstrNextByte = offPg + cbMaxRead;
    1618         }
    1619 # else
    1620 #  error "refactor as needed"
    1621         /*
    1622          * If there is no special read handling, so we can read a bit more and
    1623          * put it in the prefetch buffer.
    1624          */
    1625         if (   cbDst < cbMaxRead
    1626             && (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PHYS_REV | IEMTLBE_F_PG_NO_READ)) == pVCpu->iem.s.CodeTlb.uTlbPhysRev)
    1627         {
    1628             VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), pTlbe->GCPhys,
    1629                                                 &pVCpu->iem.s.abOpcode[0], cbToTryRead, PGMACCESSORIGIN_IEM);
    1630             if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    1631             { /* likely */ }
    1632             else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    1633             {
    1634                 Log(("iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status -  rcStrict=%Rrc\n",
    1635                      GCPtrNext, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead));
    1636                 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    1637                 AssertStmt(rcStrict == VINF_SUCCESS, IEM_DO_LONGJMP(pVCpu, VBOXSTRICRC_VAL(rcStrict)));
    1638             }
    1639             else
    1640             {
    1641                 Log((RT_SUCCESS(rcStrict)
    1642                      ? "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n"
    1643                      : "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n",
    1644                      GCPtrNext, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead));
    1645                 IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    1646             }
    1647         }
    1648 # endif
    1649         /*
    1650          * Special read handling, so only read exactly what's needed.
    1651          * This is a highly unlikely scenario.
    1652          */
    1653         else
    1654         {
    1655             pVCpu->iem.s.CodeTlb.cTlbSlowCodeReadPath++;
    1656 
    1657             /* Check instruction length. */
    1658             uint32_t const cbInstr = offBuf - (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart;
    1659             if (RT_LIKELY(cbInstr + cbDst <= 15))
    1660             { /* likely */ }
    1661             else
    1662             {
    1663                 Log(("iemOpcodeFetchMoreBytes: %04x:%08RX64 LB %#x + %#zx -> #GP(0) [slow]\n",
    1664                      pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, cbInstr, cbDst));
    1665                 iemRaiseGeneralProtectionFault0Jmp(pVCpu);
    1666             }
    1667 
    1668             /* Do the reading. */
    1669             uint32_t const cbToRead = RT_MIN((uint32_t)cbDst, cbMaxRead);
    1670             if (cbToRead > 0)
    1671             {
    1672                 VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK),
    1673                                                     pvDst, cbToRead, PGMACCESSORIGIN_IEM);
    1674                 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    1675                 { /* likely */ }
    1676                 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    1677                 {
    1678                     Log(("iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status -  rcStrict=%Rrc\n",
    1679                          GCPtrFirst, pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK), VBOXSTRICTRC_VAL(rcStrict), cbToRead));
    1680                     rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    1681                     AssertStmt(rcStrict == VINF_SUCCESS, IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict)));
    1682                 }
    1683                 else
    1684                 {
    1685                     Log((RT_SUCCESS(rcStrict)
    1686                          ? "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n"
    1687                          : "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n",
    1688                          GCPtrFirst, pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK), VBOXSTRICTRC_VAL(rcStrict), cbToRead));
    1689                     IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    1690                 }
    1691             }
    1692 
    1693             /* Update the state and probably return. */
    1694             uint32_t const offPg = (GCPtrFirst & X86_PAGE_OFFSET_MASK);
    1695             pVCpu->iem.s.fTbCrossedPage     |= offPg == 0 || pVCpu->iem.s.fTbBranched != 0;
    1696 #  if 0 /* unused */
    1697             pVCpu->iem.s.GCPhysInstrBufPrev  = pVCpu->iem.s.GCPhysInstrBuf;
    1698 #  endif
    1699             pVCpu->iem.s.offCurInstrStart = (int16_t)(offPg - cbInstr);
    1700             pVCpu->iem.s.offInstrNextByte = offPg + cbInstr + cbToRead;
    1701             pVCpu->iem.s.cbInstrBuf       = offPg + RT_MIN(15, cbMaxRead + cbInstr) - cbToRead - cbInstr;
    1702             pVCpu->iem.s.cbInstrBufTotal  = X86_PAGE_SIZE; /** @todo ??? */
    1703             pVCpu->iem.s.GCPhysInstrBuf   = pTlbe->GCPhys;
    1704             pVCpu->iem.s.uInstrBufPc      = GCPtrFirst & ~(RTGCPTR)X86_PAGE_OFFSET_MASK;
    1705             pVCpu->iem.s.pbInstrBuf       = NULL;
    1706             if (cbToRead == cbDst)
    1707                 return;
    1708             Assert(cbToRead == cbMaxRead);
    1709         }
    1710 
    1711         /*
    1712          * More to read, loop.
    1713          */
    1714         cbDst -= cbMaxRead;
    1715         pvDst  = (uint8_t *)pvDst + cbMaxRead;
    1716     }
    1717 # else  /* !IN_RING3 */
    1718     RT_NOREF(pvDst, cbDst);
    1719     if (pvDst || cbDst)
    1720         IEM_DO_LONGJMP(pVCpu, VERR_INTERNAL_ERROR);
    1721 # endif /* !IN_RING3 */
    1722 }
    1723 
    1724 #else /* !IEM_WITH_CODE_TLB */
    1725 
    1726 /**
    1727  * Try fetch at least @a cbMin bytes more opcodes, raise the appropriate
    1728  * exception if it fails.
    1729  *
    1730  * @returns Strict VBox status code.
    1731  * @param   pVCpu               The cross context virtual CPU structure of the
    1732  *                              calling thread.
    1733  * @param   cbMin               The minimum number of bytes relative offOpcode
    1734  *                              that must be read.
    1735  */
    1736 VBOXSTRICTRC iemOpcodeFetchMoreBytes(PVMCPUCC pVCpu, size_t cbMin) RT_NOEXCEPT
    1737 {
    1738     /*
    1739      * What we're doing here is very similar to iemMemMap/iemMemBounceBufferMap.
    1740      *
    1741      * First translate CS:rIP to a physical address.
    1742      */
    1743     uint8_t const   cbOpcode  = pVCpu->iem.s.cbOpcode;
    1744     uint8_t const   offOpcode = pVCpu->iem.s.offOpcode;
    1745     uint8_t const   cbLeft    = cbOpcode - offOpcode;
    1746     Assert(cbLeft < cbMin);
    1747     Assert(cbOpcode <= sizeof(pVCpu->iem.s.abOpcode));
    1748 
    1749     uint32_t        cbToTryRead;
    1750     RTGCPTR         GCPtrNext;
    1751     if (IEM_IS_64BIT_CODE(pVCpu))
    1752     {
    1753         GCPtrNext   = pVCpu->cpum.GstCtx.rip + cbOpcode;
    1754         if (!IEM_IS_CANONICAL(GCPtrNext))
    1755             return iemRaiseGeneralProtectionFault0(pVCpu);
    1756         cbToTryRead = GUEST_PAGE_SIZE - (GCPtrNext & GUEST_PAGE_OFFSET_MASK);
    1757     }
    1758     else
    1759     {
    1760         uint32_t GCPtrNext32 = pVCpu->cpum.GstCtx.eip;
    1761         /* Assert(!(GCPtrNext32 & ~(uint32_t)UINT16_MAX) || IEM_IS_32BIT_CODE(pVCpu)); - this is allowed */
    1762         GCPtrNext32 += cbOpcode;
    1763         if (GCPtrNext32 > pVCpu->cpum.GstCtx.cs.u32Limit)
    1764             /** @todo For CPUs older than the 386, we should not generate \#GP here but wrap around! */
    1765             return iemRaiseSelectorBounds(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
    1766         cbToTryRead = pVCpu->cpum.GstCtx.cs.u32Limit - GCPtrNext32 + 1;
    1767         if (!cbToTryRead) /* overflowed */
    1768         {
    1769             Assert(GCPtrNext32 == 0); Assert(pVCpu->cpum.GstCtx.cs.u32Limit == UINT32_MAX);
    1770             cbToTryRead = UINT32_MAX;
    1771             /** @todo check out wrapping around the code segment.  */
    1772         }
    1773         if (cbToTryRead < cbMin - cbLeft)
    1774             return iemRaiseSelectorBounds(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
    1775         GCPtrNext = (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base + GCPtrNext32;
    1776 
    1777         uint32_t cbLeftOnPage = GUEST_PAGE_SIZE - (GCPtrNext & GUEST_PAGE_OFFSET_MASK);
    1778         if (cbToTryRead > cbLeftOnPage)
    1779             cbToTryRead = cbLeftOnPage;
    1780     }
    1781 
    1782     /* Restrict to opcode buffer space.
    1783 
    1784        We're making ASSUMPTIONS here based on work done previously in
    1785        iemInitDecoderAndPrefetchOpcodes, where bytes from the first page will
    1786        be fetched in case of an instruction crossing two pages. */
    1787     if (cbToTryRead > sizeof(pVCpu->iem.s.abOpcode) - cbOpcode)
    1788         cbToTryRead = sizeof(pVCpu->iem.s.abOpcode) - cbOpcode;
    1789     if (RT_LIKELY(cbToTryRead + cbLeft >= cbMin))
    1790     { /* likely */ }
    1791     else
    1792     {
    1793         Log(("iemOpcodeFetchMoreBytes: %04x:%08RX64 LB %#x + %#zx -> #GP(0)\n",
    1794              pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, offOpcode, cbMin));
    1795         return iemRaiseGeneralProtectionFault0(pVCpu);
    1796     }
    1797 
    1798     PGMPTWALKFAST WalkFast;
    1799     int rc = PGMGstQueryPageFast(pVCpu, GCPtrNext,
    1800                                  IEM_GET_CPL(pVCpu) == 3 ? PGMQPAGE_F_EXECUTE | PGMQPAGE_F_USER_MODE : PGMQPAGE_F_EXECUTE,
    1801                                  &WalkFast);
    1802     if (RT_SUCCESS(rc))
    1803         Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
    1804     else
    1805     {
    1806         Log(("iemOpcodeFetchMoreBytes: %RGv - rc=%Rrc\n", GCPtrNext, rc));
    1807 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    1808         if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    1809             IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
    1810 #endif
    1811         return iemRaisePageFault(pVCpu, GCPtrNext, 1, IEM_ACCESS_INSTRUCTION, rc);
    1812     }
    1813     Assert((WalkFast.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3);
    1814     Assert(!(WalkFast.fEffective & X86_PTE_PAE_NX) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE));
    1815 
    1816     RTGCPHYS const GCPhys = WalkFast.GCPhys;
    1817     Log5(("GCPtrNext=%RGv GCPhys=%RGp cbOpcodes=%#x\n",  GCPtrNext,  GCPhys, cbOpcode));
    1818 
    1819     /*
    1820      * Read the bytes at this address.
    1821      *
    1822      * We read all unpatched bytes in iemInitDecoderAndPrefetchOpcodes already,
    1823      * and since PATM should only patch the start of an instruction there
    1824      * should be no need to check again here.
    1825      */
    1826     if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))
    1827     {
    1828         VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), GCPhys, &pVCpu->iem.s.abOpcode[cbOpcode],
    1829                                             cbToTryRead, PGMACCESSORIGIN_IEM);
    1830         if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    1831         { /* likely */ }
    1832         else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    1833         {
    1834             Log(("iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status -  rcStrict=%Rrc\n",
    1835                  GCPtrNext, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead));
    1836             rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    1837         }
    1838         else
    1839         {
    1840             Log((RT_SUCCESS(rcStrict)
    1841                  ? "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n"
    1842                  : "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n",
    1843                  GCPtrNext, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead));
    1844             return rcStrict;
    1845         }
    1846     }
    1847     else
    1848     {
    1849         rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.abOpcode[cbOpcode], GCPhys, cbToTryRead);
    1850         if (RT_SUCCESS(rc))
    1851         { /* likely */ }
    1852         else
    1853         {
    1854             Log(("iemOpcodeFetchMoreBytes: %RGv - read error - rc=%Rrc (!!)\n", GCPtrNext, rc));
    1855             return rc;
    1856         }
    1857     }
    1858     pVCpu->iem.s.cbOpcode = cbOpcode + cbToTryRead;
    1859     Log5(("%.*Rhxs\n", pVCpu->iem.s.cbOpcode, pVCpu->iem.s.abOpcode));
    1860 
    1861     return VINF_SUCCESS;
    1862 }
    1863 
    1864 #endif /* !IEM_WITH_CODE_TLB */
    1865 #ifndef IEM_WITH_SETJMP
    1866 
    1867 /**
    1868  * Deals with the problematic cases that iemOpcodeGetNextU8 doesn't like.
    1869  *
    1870  * @returns Strict VBox status code.
    1871  * @param   pVCpu               The cross context virtual CPU structure of the
    1872  *                              calling thread.
    1873  * @param   pb                  Where to return the opcode byte.
    1874  */
    1875 VBOXSTRICTRC iemOpcodeGetNextU8Slow(PVMCPUCC pVCpu, uint8_t *pb) RT_NOEXCEPT
    1876 {
    1877     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 1);
    1878     if (rcStrict == VINF_SUCCESS)
    1879     {
    1880         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    1881         *pb = pVCpu->iem.s.abOpcode[offOpcode];
    1882         pVCpu->iem.s.offOpcode = offOpcode + 1;
    1883     }
    1884     else
    1885         *pb = 0;
    1886     return rcStrict;
    1887 }
    1888 
    1889 #else  /* IEM_WITH_SETJMP */
    1890 
    1891 /**
    1892  * Deals with the problematic cases that iemOpcodeGetNextU8Jmp doesn't like, longjmp on error.
    1893  *
    1894  * @returns The opcode byte.
    1895  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    1896  */
    1897 uint8_t iemOpcodeGetNextU8SlowJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
    1898 {
    1899 # ifdef IEM_WITH_CODE_TLB
    1900     uint8_t u8;
    1901     iemOpcodeFetchBytesJmp(pVCpu, sizeof(u8), &u8);
    1902     return u8;
    1903 # else
    1904     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 1);
    1905     if (rcStrict == VINF_SUCCESS)
    1906         return pVCpu->iem.s.abOpcode[pVCpu->iem.s.offOpcode++];
    1907     IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    1908 # endif
    1909 }
    1910 
    1911 #endif /* IEM_WITH_SETJMP */
    1912 
    1913 #ifndef IEM_WITH_SETJMP
    1914 
    1915 /**
    1916  * Deals with the problematic cases that iemOpcodeGetNextS8SxU16 doesn't like.
    1917  *
    1918  * @returns Strict VBox status code.
    1919  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    1920  * @param   pu16                Where to return the opcode dword.
    1921  */
    1922 VBOXSTRICTRC iemOpcodeGetNextS8SxU16Slow(PVMCPUCC pVCpu, uint16_t *pu16) RT_NOEXCEPT
    1923 {
    1924     uint8_t      u8;
    1925     VBOXSTRICTRC rcStrict = iemOpcodeGetNextU8Slow(pVCpu, &u8);
    1926     if (rcStrict == VINF_SUCCESS)
    1927         *pu16 = (int8_t)u8;
    1928     return rcStrict;
    1929 }
    1930 
    1931 
    1932 /**
    1933  * Deals with the problematic cases that iemOpcodeGetNextS8SxU32 doesn't like.
    1934  *
    1935  * @returns Strict VBox status code.
    1936  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    1937  * @param   pu32                Where to return the opcode dword.
    1938  */
    1939 VBOXSTRICTRC iemOpcodeGetNextS8SxU32Slow(PVMCPUCC pVCpu, uint32_t *pu32) RT_NOEXCEPT
    1940 {
    1941     uint8_t      u8;
    1942     VBOXSTRICTRC rcStrict = iemOpcodeGetNextU8Slow(pVCpu, &u8);
    1943     if (rcStrict == VINF_SUCCESS)
    1944         *pu32 = (int8_t)u8;
    1945     return rcStrict;
    1946 }
    1947 
    1948 
    1949 /**
    1950  * Deals with the problematic cases that iemOpcodeGetNextS8SxU64 doesn't like.
    1951  *
    1952  * @returns Strict VBox status code.
    1953  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    1954  * @param   pu64                Where to return the opcode qword.
    1955  */
    1956 VBOXSTRICTRC iemOpcodeGetNextS8SxU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
    1957 {
    1958     uint8_t      u8;
    1959     VBOXSTRICTRC rcStrict = iemOpcodeGetNextU8Slow(pVCpu, &u8);
    1960     if (rcStrict == VINF_SUCCESS)
    1961         *pu64 = (int8_t)u8;
    1962     return rcStrict;
    1963 }
    1964 
    1965 #endif /* !IEM_WITH_SETJMP */
    1966 
    1967 
    1968 #ifndef IEM_WITH_SETJMP
    1969 
    1970 /**
    1971  * Deals with the problematic cases that iemOpcodeGetNextU16 doesn't like.
    1972  *
    1973  * @returns Strict VBox status code.
    1974  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    1975  * @param   pu16                Where to return the opcode word.
    1976  */
    1977 VBOXSTRICTRC iemOpcodeGetNextU16Slow(PVMCPUCC pVCpu, uint16_t *pu16) RT_NOEXCEPT
    1978 {
    1979     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 2);
    1980     if (rcStrict == VINF_SUCCESS)
    1981     {
    1982         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    1983 # ifdef IEM_USE_UNALIGNED_DATA_ACCESS
    1984         *pu16 = *(uint16_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
    1985 # else
    1986         *pu16 = RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]);
    1987 # endif
    1988         pVCpu->iem.s.offOpcode = offOpcode + 2;
    1989     }
    1990     else
    1991         *pu16 = 0;
    1992     return rcStrict;
    1993 }
    1994 
    1995 #else  /* IEM_WITH_SETJMP */
    1996 
    1997 /**
    1998  * Deals with the problematic cases that iemOpcodeGetNextU16Jmp doesn't like, longjmp on error
    1999  *
    2000  * @returns The opcode word.
    2001  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2002  */
    2003 uint16_t iemOpcodeGetNextU16SlowJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
    2004 {
    2005 # ifdef IEM_WITH_CODE_TLB
    2006     uint16_t u16;
    2007     iemOpcodeFetchBytesJmp(pVCpu, sizeof(u16), &u16);
    2008     return u16;
    2009 # else
    2010     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 2);
    2011     if (rcStrict == VINF_SUCCESS)
    2012     {
    2013         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2014         pVCpu->iem.s.offOpcode += 2;
    2015 #  ifdef IEM_USE_UNALIGNED_DATA_ACCESS
    2016         return *(uint16_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
    2017 #  else
    2018         return RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]);
    2019 #  endif
    2020     }
    2021     IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    2022 # endif
    2023 }
    2024 
    2025 #endif /* IEM_WITH_SETJMP */
    2026 
    2027 #ifndef IEM_WITH_SETJMP
    2028 
    2029 /**
    2030  * Deals with the problematic cases that iemOpcodeGetNextU16ZxU32 doesn't like.
    2031  *
    2032  * @returns Strict VBox status code.
    2033  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2034  * @param   pu32                Where to return the opcode double word.
    2035  */
    2036 VBOXSTRICTRC iemOpcodeGetNextU16ZxU32Slow(PVMCPUCC pVCpu, uint32_t *pu32) RT_NOEXCEPT
    2037 {
    2038     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 2);
    2039     if (rcStrict == VINF_SUCCESS)
    2040     {
    2041         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2042         *pu32 = RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]);
    2043         pVCpu->iem.s.offOpcode = offOpcode + 2;
    2044     }
    2045     else
    2046         *pu32 = 0;
    2047     return rcStrict;
    2048 }
    2049 
    2050 
    2051 /**
    2052  * Deals with the problematic cases that iemOpcodeGetNextU16ZxU64 doesn't like.
    2053  *
    2054  * @returns Strict VBox status code.
    2055  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2056  * @param   pu64                Where to return the opcode quad word.
    2057  */
    2058 VBOXSTRICTRC iemOpcodeGetNextU16ZxU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
    2059 {
    2060     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 2);
    2061     if (rcStrict == VINF_SUCCESS)
    2062     {
    2063         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2064         *pu64 = RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]);
    2065         pVCpu->iem.s.offOpcode = offOpcode + 2;
    2066     }
    2067     else
    2068         *pu64 = 0;
    2069     return rcStrict;
    2070 }
    2071 
    2072 #endif /* !IEM_WITH_SETJMP */
    2073 
    2074 #ifndef IEM_WITH_SETJMP
    2075 
    2076 /**
    2077  * Deals with the problematic cases that iemOpcodeGetNextU32 doesn't like.
    2078  *
    2079  * @returns Strict VBox status code.
    2080  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2081  * @param   pu32                Where to return the opcode dword.
    2082  */
    2083 VBOXSTRICTRC iemOpcodeGetNextU32Slow(PVMCPUCC pVCpu, uint32_t *pu32) RT_NOEXCEPT
    2084 {
    2085     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 4);
    2086     if (rcStrict == VINF_SUCCESS)
    2087     {
    2088         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2089 # ifdef IEM_USE_UNALIGNED_DATA_ACCESS
    2090         *pu32 = *(uint32_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
    2091 # else
    2092         *pu32 = RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
    2093                                     pVCpu->iem.s.abOpcode[offOpcode + 1],
    2094                                     pVCpu->iem.s.abOpcode[offOpcode + 2],
    2095                                     pVCpu->iem.s.abOpcode[offOpcode + 3]);
    2096 # endif
    2097         pVCpu->iem.s.offOpcode = offOpcode + 4;
    2098     }
    2099     else
    2100         *pu32 = 0;
    2101     return rcStrict;
    2102 }
    2103 
    2104 #else  /* IEM_WITH_SETJMP */
    2105 
    2106 /**
    2107  * Deals with the problematic cases that iemOpcodeGetNextU32Jmp doesn't like, longjmp on error.
    2108  *
    2109  * @returns The opcode dword.
    2110  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2111  */
    2112 uint32_t iemOpcodeGetNextU32SlowJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
    2113 {
    2114 # ifdef IEM_WITH_CODE_TLB
    2115     uint32_t u32;
    2116     iemOpcodeFetchBytesJmp(pVCpu, sizeof(u32), &u32);
    2117     return u32;
    2118 # else
    2119     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 4);
    2120     if (rcStrict == VINF_SUCCESS)
    2121     {
    2122         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2123         pVCpu->iem.s.offOpcode = offOpcode + 4;
    2124 #  ifdef IEM_USE_UNALIGNED_DATA_ACCESS
    2125         return *(uint32_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
    2126 #  else
    2127         return RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
    2128                                    pVCpu->iem.s.abOpcode[offOpcode + 1],
    2129                                    pVCpu->iem.s.abOpcode[offOpcode + 2],
    2130                                    pVCpu->iem.s.abOpcode[offOpcode + 3]);
    2131 #  endif
    2132     }
    2133     IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    2134 # endif
    2135 }
    2136 
    2137 #endif /* IEM_WITH_SETJMP */
    2138 
    2139 #ifndef IEM_WITH_SETJMP
    2140 
    2141 /**
    2142  * Deals with the problematic cases that iemOpcodeGetNextU32ZxU64 doesn't like.
    2143  *
    2144  * @returns Strict VBox status code.
    2145  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2146  * @param   pu64                Where to return the opcode dword.
    2147  */
    2148 VBOXSTRICTRC iemOpcodeGetNextU32ZxU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
    2149 {
    2150     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 4);
    2151     if (rcStrict == VINF_SUCCESS)
    2152     {
    2153         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2154         *pu64 = RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
    2155                                     pVCpu->iem.s.abOpcode[offOpcode + 1],
    2156                                     pVCpu->iem.s.abOpcode[offOpcode + 2],
    2157                                     pVCpu->iem.s.abOpcode[offOpcode + 3]);
    2158         pVCpu->iem.s.offOpcode = offOpcode + 4;
    2159     }
    2160     else
    2161         *pu64 = 0;
    2162     return rcStrict;
    2163 }
    2164 
    2165 
    2166 /**
    2167  * Deals with the problematic cases that iemOpcodeGetNextS32SxU64 doesn't like.
    2168  *
    2169  * @returns Strict VBox status code.
    2170  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2171  * @param   pu64                Where to return the opcode qword.
    2172  */
    2173 VBOXSTRICTRC iemOpcodeGetNextS32SxU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
    2174 {
    2175     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 4);
    2176     if (rcStrict == VINF_SUCCESS)
    2177     {
    2178         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2179         *pu64 = (int32_t)RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
    2180                                              pVCpu->iem.s.abOpcode[offOpcode + 1],
    2181                                              pVCpu->iem.s.abOpcode[offOpcode + 2],
    2182                                              pVCpu->iem.s.abOpcode[offOpcode + 3]);
    2183         pVCpu->iem.s.offOpcode = offOpcode + 4;
    2184     }
    2185     else
    2186         *pu64 = 0;
    2187     return rcStrict;
    2188 }
    2189 
    2190 #endif /* !IEM_WITH_SETJMP */
    2191 
    2192 #ifndef IEM_WITH_SETJMP
    2193 
    2194 /**
    2195  * Deals with the problematic cases that iemOpcodeGetNextU64 doesn't like.
    2196  *
    2197  * @returns Strict VBox status code.
    2198  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2199  * @param   pu64                Where to return the opcode qword.
    2200  */
    2201 VBOXSTRICTRC iemOpcodeGetNextU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
    2202 {
    2203     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 8);
    2204     if (rcStrict == VINF_SUCCESS)
    2205     {
    2206         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2207 # ifdef IEM_USE_UNALIGNED_DATA_ACCESS
    2208         *pu64 = *(uint64_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
    2209 # else
    2210         *pu64 = RT_MAKE_U64_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
    2211                                     pVCpu->iem.s.abOpcode[offOpcode + 1],
    2212                                     pVCpu->iem.s.abOpcode[offOpcode + 2],
    2213                                     pVCpu->iem.s.abOpcode[offOpcode + 3],
    2214                                     pVCpu->iem.s.abOpcode[offOpcode + 4],
    2215                                     pVCpu->iem.s.abOpcode[offOpcode + 5],
    2216                                     pVCpu->iem.s.abOpcode[offOpcode + 6],
    2217                                     pVCpu->iem.s.abOpcode[offOpcode + 7]);
    2218 # endif
    2219         pVCpu->iem.s.offOpcode = offOpcode + 8;
    2220     }
    2221     else
    2222         *pu64 = 0;
    2223     return rcStrict;
    2224 }
    2225 
    2226 #else  /* IEM_WITH_SETJMP */
    2227 
    2228 /**
    2229  * Deals with the problematic cases that iemOpcodeGetNextU64Jmp doesn't like, longjmp on error.
    2230  *
    2231  * @returns The opcode qword.
    2232  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2233  */
    2234 uint64_t iemOpcodeGetNextU64SlowJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
    2235 {
    2236 # ifdef IEM_WITH_CODE_TLB
    2237     uint64_t u64;
    2238     iemOpcodeFetchBytesJmp(pVCpu, sizeof(u64), &u64);
    2239     return u64;
    2240 # else
    2241     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 8);
    2242     if (rcStrict == VINF_SUCCESS)
    2243     {
    2244         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2245         pVCpu->iem.s.offOpcode = offOpcode + 8;
    2246 #  ifdef IEM_USE_UNALIGNED_DATA_ACCESS
    2247         return *(uint64_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
    2248 #  else
    2249         return RT_MAKE_U64_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
    2250                                    pVCpu->iem.s.abOpcode[offOpcode + 1],
    2251                                    pVCpu->iem.s.abOpcode[offOpcode + 2],
    2252                                    pVCpu->iem.s.abOpcode[offOpcode + 3],
    2253                                    pVCpu->iem.s.abOpcode[offOpcode + 4],
    2254                                    pVCpu->iem.s.abOpcode[offOpcode + 5],
    2255                                    pVCpu->iem.s.abOpcode[offOpcode + 6],
    2256                                    pVCpu->iem.s.abOpcode[offOpcode + 7]);
    2257 #  endif
    2258     }
    2259     IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    2260 # endif
    2261 }
    2262 
    2263 #endif /* IEM_WITH_SETJMP */
    2264 
    2265 
    2266 
    2267 /** @name   Register Access.
     50#include "IEMAllTlbInline-x86.h"
     51
     52
     53/** @name   Memory access.
     54 *
    226855 * @{
    226956 */
    2270 
    2271 /**
    2272  * Adds a 8-bit signed jump offset to RIP/EIP/IP.
    2273  *
    2274  * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
    2275  * segment limit.
    2276  *
    2277  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2278  * @param   cbInstr             Instruction size.
    2279  * @param   offNextInstr        The offset of the next instruction.
    2280  * @param   enmEffOpSize        Effective operand size.
    2281  */
    2282 VBOXSTRICTRC iemRegRipRelativeJumpS8AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int8_t offNextInstr,
    2283                                                         IEMMODE enmEffOpSize) RT_NOEXCEPT
    2284 {
    2285     switch (enmEffOpSize)
    2286     {
    2287         case IEMMODE_16BIT:
    2288         {
    2289             uint16_t const uNewIp = pVCpu->cpum.GstCtx.ip + cbInstr + (int16_t)offNextInstr;
    2290             if (RT_LIKELY(   uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit
    2291                           || IEM_IS_64BIT_CODE(pVCpu) /* no CS limit checks in 64-bit mode */))
    2292                 pVCpu->cpum.GstCtx.rip = uNewIp;
    2293             else
    2294                 return iemRaiseGeneralProtectionFault0(pVCpu);
    2295             break;
    2296         }
    2297 
    2298         case IEMMODE_32BIT:
    2299         {
    2300             Assert(!IEM_IS_64BIT_CODE(pVCpu));
    2301             Assert(pVCpu->cpum.GstCtx.rip <= UINT32_MAX);
    2302 
    2303             uint32_t const uNewEip = pVCpu->cpum.GstCtx.eip + cbInstr + (int32_t)offNextInstr;
    2304             if (RT_LIKELY(uNewEip <= pVCpu->cpum.GstCtx.cs.u32Limit))
    2305                 pVCpu->cpum.GstCtx.rip = uNewEip;
    2306             else
    2307                 return iemRaiseGeneralProtectionFault0(pVCpu);
    2308             break;
    2309         }
    2310 
    2311         case IEMMODE_64BIT:
    2312         {
    2313             Assert(IEM_IS_64BIT_CODE(pVCpu));
    2314 
    2315             uint64_t const uNewRip = pVCpu->cpum.GstCtx.rip + cbInstr + (int64_t)offNextInstr;
    2316             if (RT_LIKELY(IEM_IS_CANONICAL(uNewRip)))
    2317                 pVCpu->cpum.GstCtx.rip = uNewRip;
    2318             else
    2319                 return iemRaiseGeneralProtectionFault0(pVCpu);
    2320             break;
    2321         }
    2322 
    2323         IEM_NOT_REACHED_DEFAULT_CASE_RET();
    2324     }
    2325 
    2326 #ifndef IEM_WITH_CODE_TLB
    2327     /* Flush the prefetch buffer. */
    2328     pVCpu->iem.s.cbOpcode = cbInstr;
    2329 #endif
    2330 
    2331     /*
    2332      * Clear RF and finish the instruction (maybe raise #DB).
    2333      */
    2334     return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
    2335 }
    2336 
    2337 
    2338 /**
    2339  * Adds a 16-bit signed jump offset to RIP/EIP/IP.
    2340  *
    2341  * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
    2342  * segment limit.
    2343  *
    2344  * @returns Strict VBox status code.
    2345  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2346  * @param   cbInstr             Instruction size.
    2347  * @param   offNextInstr        The offset of the next instruction.
    2348  */
    2349 VBOXSTRICTRC iemRegRipRelativeJumpS16AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int16_t offNextInstr) RT_NOEXCEPT
    2350 {
    2351     Assert(pVCpu->iem.s.enmEffOpSize == IEMMODE_16BIT);
    2352 
    2353     uint16_t const uNewIp = pVCpu->cpum.GstCtx.ip + cbInstr + offNextInstr;
    2354     if (RT_LIKELY(   uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit
    2355                   || IEM_IS_64BIT_CODE(pVCpu) /* no limit checking in 64-bit mode */))
    2356         pVCpu->cpum.GstCtx.rip = uNewIp;
    2357     else
    2358         return iemRaiseGeneralProtectionFault0(pVCpu);
    2359 
    2360 #ifndef IEM_WITH_CODE_TLB
    2361     /* Flush the prefetch buffer. */
    2362     pVCpu->iem.s.cbOpcode = IEM_GET_INSTR_LEN(pVCpu);
    2363 #endif
    2364 
    2365     /*
    2366      * Clear RF and finish the instruction (maybe raise #DB).
    2367      */
    2368     return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
    2369 }
    2370 
    2371 
    2372 /**
    2373  * Adds a 32-bit signed jump offset to RIP/EIP/IP.
    2374  *
    2375  * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
    2376  * segment limit.
    2377  *
    2378  * @returns Strict VBox status code.
    2379  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2380  * @param   cbInstr             Instruction size.
    2381  * @param   offNextInstr        The offset of the next instruction.
    2382  * @param   enmEffOpSize        Effective operand size.
    2383  */
    2384 VBOXSTRICTRC iemRegRipRelativeJumpS32AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int32_t offNextInstr,
    2385                                                          IEMMODE enmEffOpSize) RT_NOEXCEPT
    2386 {
    2387     if (enmEffOpSize == IEMMODE_32BIT)
    2388     {
    2389         Assert(pVCpu->cpum.GstCtx.rip <= UINT32_MAX); Assert(!IEM_IS_64BIT_CODE(pVCpu));
    2390 
    2391         uint32_t const uNewEip = pVCpu->cpum.GstCtx.eip + cbInstr + offNextInstr;
    2392         if (RT_LIKELY(uNewEip <= pVCpu->cpum.GstCtx.cs.u32Limit))
    2393             pVCpu->cpum.GstCtx.rip = uNewEip;
    2394         else
    2395             return iemRaiseGeneralProtectionFault0(pVCpu);
    2396     }
    2397     else
    2398     {
    2399         Assert(enmEffOpSize == IEMMODE_64BIT);
    2400 
    2401         uint64_t const uNewRip = pVCpu->cpum.GstCtx.rip + cbInstr + (int64_t)offNextInstr;
    2402         if (RT_LIKELY(IEM_IS_CANONICAL(uNewRip)))
    2403             pVCpu->cpum.GstCtx.rip = uNewRip;
    2404         else
    2405             return iemRaiseGeneralProtectionFault0(pVCpu);
    2406     }
    2407 
    2408 #ifndef IEM_WITH_CODE_TLB
    2409     /* Flush the prefetch buffer. */
    2410     pVCpu->iem.s.cbOpcode = IEM_GET_INSTR_LEN(pVCpu);
    2411 #endif
    2412 
    2413     /*
    2414      * Clear RF and finish the instruction (maybe raise #DB).
    2415      */
    2416     return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
    2417 }
    2418 
    2419 /** @}  */
    2420 
    2421 
    2422 /** @name   Memory access.
    2423  *
    2424  * @{
    2425  */
    2426 
    2427 #undef  LOG_GROUP
    2428 #define LOG_GROUP LOG_GROUP_IEM_MEM
    242957
    243058/**
     
    2612240}
    2613241
    2614 #if 0 /*unused*/
    2615 /**
    2616  * Looks up a memory mapping entry.
    2617  *
    2618  * @returns The mapping index (positive) or VERR_NOT_FOUND (negative).
    2619  * @param   pVCpu           The cross context virtual CPU structure of the calling thread.
    2620  * @param   pvMem           The memory address.
    2621  * @param   fAccess         The access to.
    2622  */
    2623 DECLINLINE(int) iemMapLookup(PVMCPUCC pVCpu, void *pvMem, uint32_t fAccess)
    2624 {
    2625     Assert(pVCpu->iem.s.cActiveMappings <= RT_ELEMENTS(pVCpu->iem.s.aMemMappings));
    2626     fAccess &= IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK;
    2627     if (   pVCpu->iem.s.aMemMappings[0].pv == pvMem
    2628         && (pVCpu->iem.s.aMemMappings[0].fAccess & (IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK)) == fAccess)
    2629         return 0;
    2630     if (   pVCpu->iem.s.aMemMappings[1].pv == pvMem
    2631         && (pVCpu->iem.s.aMemMappings[1].fAccess & (IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK)) == fAccess)
    2632         return 1;
    2633     if (   pVCpu->iem.s.aMemMappings[2].pv == pvMem
    2634         && (pVCpu->iem.s.aMemMappings[2].fAccess & (IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK)) == fAccess)
    2635         return 2;
    2636     return VERR_NOT_FOUND;
    2637 }
    2638 #endif
    2639242
    2640243/**
     
    2667270
    2668271/**
    2669  * Commits a bounce buffer that needs writing back and unmaps it.
    2670  *
    2671  * @returns Strict VBox status code.
    2672  * @param   pVCpu           The cross context virtual CPU structure of the calling thread.
    2673  * @param   iMemMap         The index of the buffer to commit.
    2674  * @param   fPostponeFail   Whether we can postpone writer failures to ring-3.
    2675  *                          Always false in ring-3, obviously.
    2676  */
    2677 static VBOXSTRICTRC iemMemBounceBufferCommitAndUnmap(PVMCPUCC pVCpu, unsigned iMemMap, bool fPostponeFail)
    2678 {
    2679     Assert(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED);
    2680     Assert(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE);
    2681 #ifdef IN_RING3
    2682     Assert(!fPostponeFail);
    2683     RT_NOREF_PV(fPostponeFail);
    2684 #endif
    2685 
    2686     /*
    2687      * Do the writing.
    2688      */
    2689     PVMCC pVM = pVCpu->CTX_SUFF(pVM);
    2690     if (!pVCpu->iem.s.aMemBbMappings[iMemMap].fUnassigned)
    2691     {
    2692         uint16_t const  cbFirst  = pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst;
    2693         uint16_t const  cbSecond = pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond;
    2694         uint8_t const  *pbBuf    = &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0];
    2695         if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))
    2696         {
    2697             /*
    2698              * Carefully and efficiently dealing with access handler return
    2699              * codes make this a little bloated.
    2700              */
    2701             VBOXSTRICTRC rcStrict = PGMPhysWrite(pVM,
    2702                                                  pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst,
    2703                                                  pbBuf,
    2704                                                  cbFirst,
    2705                                                  PGMACCESSORIGIN_IEM);
    2706             if (rcStrict == VINF_SUCCESS)
    2707             {
    2708                 if (cbSecond)
    2709                 {
    2710                     rcStrict = PGMPhysWrite(pVM,
    2711                                             pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond,
    2712                                             pbBuf + cbFirst,
    2713                                             cbSecond,
    2714                                             PGMACCESSORIGIN_IEM);
    2715                     if (rcStrict == VINF_SUCCESS)
    2716                     { /* nothing */ }
    2717                     else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    2718                     {
    2719                         LogEx(LOG_GROUP_IEM,
    2720                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc\n",
    2721                               pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    2722                               pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));
    2723                         rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    2724                     }
    2725 #ifndef IN_RING3
    2726                     else if (fPostponeFail)
    2727                     {
    2728                         LogEx(LOG_GROUP_IEM,
    2729                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (postponed)\n",
    2730                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    2731                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));
    2732                         pVCpu->iem.s.aMemMappings[iMemMap].fAccess |= IEM_ACCESS_PENDING_R3_WRITE_2ND;
    2733                         VMCPU_FF_SET(pVCpu, VMCPU_FF_IEM);
    2734                         return iemSetPassUpStatus(pVCpu, rcStrict);
    2735                     }
    2736 #endif
    2737                     else
    2738                     {
    2739                         LogEx(LOG_GROUP_IEM,
    2740                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (!!)\n",
    2741                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    2742                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));
    2743                         return rcStrict;
    2744                     }
    2745                 }
    2746             }
    2747             else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    2748             {
    2749                 if (!cbSecond)
    2750                 {
    2751                     LogEx(LOG_GROUP_IEM,
    2752                           ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc\n",
    2753                            pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict) ));
    2754                     rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    2755                 }
    2756                 else
    2757                 {
    2758                     VBOXSTRICTRC rcStrict2 = PGMPhysWrite(pVM,
    2759                                                           pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond,
    2760                                                           pbBuf + cbFirst,
    2761                                                           cbSecond,
    2762                                                           PGMACCESSORIGIN_IEM);
    2763                     if (rcStrict2 == VINF_SUCCESS)
    2764                     {
    2765                         LogEx(LOG_GROUP_IEM,
    2766                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc GCPhysSecond=%RGp/%#x\n",
    2767                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict),
    2768                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond));
    2769                         rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    2770                     }
    2771                     else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict2))
    2772                     {
    2773                         LogEx(LOG_GROUP_IEM,
    2774                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc GCPhysSecond=%RGp/%#x %Rrc\n",
    2775                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict),
    2776                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict2) ));
    2777                         PGM_PHYS_RW_DO_UPDATE_STRICT_RC(rcStrict, rcStrict2);
    2778                         rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    2779                     }
    2780 #ifndef IN_RING3
    2781                     else if (fPostponeFail)
    2782                     {
    2783                         LogEx(LOG_GROUP_IEM,
    2784                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (postponed)\n",
    2785                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    2786                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));
    2787                         pVCpu->iem.s.aMemMappings[iMemMap].fAccess |= IEM_ACCESS_PENDING_R3_WRITE_2ND;
    2788                         VMCPU_FF_SET(pVCpu, VMCPU_FF_IEM);
    2789                         return iemSetPassUpStatus(pVCpu, rcStrict);
    2790                     }
    2791 #endif
    2792                     else
    2793                     {
    2794                         LogEx(LOG_GROUP_IEM,
    2795                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc GCPhysSecond=%RGp/%#x %Rrc (!!)\n",
    2796                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict),
    2797                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict2) ));
    2798                         return rcStrict2;
    2799                     }
    2800                 }
    2801             }
    2802 #ifndef IN_RING3
    2803             else if (fPostponeFail)
    2804             {
    2805                 LogEx(LOG_GROUP_IEM,
    2806                       ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (postponed)\n",
    2807                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    2808                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));
    2809                 if (!cbSecond)
    2810                     pVCpu->iem.s.aMemMappings[iMemMap].fAccess |= IEM_ACCESS_PENDING_R3_WRITE_1ST;
    2811                 else
    2812                     pVCpu->iem.s.aMemMappings[iMemMap].fAccess |= IEM_ACCESS_PENDING_R3_WRITE_1ST | IEM_ACCESS_PENDING_R3_WRITE_2ND;
    2813                 VMCPU_FF_SET(pVCpu, VMCPU_FF_IEM);
    2814                 return iemSetPassUpStatus(pVCpu, rcStrict);
    2815             }
    2816 #endif
    2817             else
    2818             {
    2819                 LogEx(LOG_GROUP_IEM,
    2820                       ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc [GCPhysSecond=%RGp/%#x] (!!)\n",
    2821                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict),
    2822                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond));
    2823                 return rcStrict;
    2824             }
    2825         }
    2826         else
    2827         {
    2828             /*
    2829              * No access handlers, much simpler.
    2830              */
    2831             int rc = PGMPhysSimpleWriteGCPhys(pVM, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, pbBuf, cbFirst);
    2832             if (RT_SUCCESS(rc))
    2833             {
    2834                 if (cbSecond)
    2835                 {
    2836                     rc = PGMPhysSimpleWriteGCPhys(pVM, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, pbBuf + cbFirst, cbSecond);
    2837                     if (RT_SUCCESS(rc))
    2838                     { /* likely */ }
    2839                     else
    2840                     {
    2841                         LogEx(LOG_GROUP_IEM,
    2842                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysSimpleWriteGCPhys GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (!!)\n",
    2843                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    2844                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, rc));
    2845                         return rc;
    2846                     }
    2847                 }
    2848             }
    2849             else
    2850             {
    2851                 LogEx(LOG_GROUP_IEM,
    2852                       ("iemMemBounceBufferCommitAndUnmap: PGMPhysSimpleWriteGCPhys GCPhysFirst=%RGp/%#x %Rrc [GCPhysSecond=%RGp/%#x] (!!)\n",
    2853                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, rc,
    2854                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond));
    2855                 return rc;
    2856             }
    2857         }
    2858     }
    2859 
    2860 #if defined(IEM_LOG_MEMORY_WRITES)
    2861     Log5(("IEM Wrote %RGp: %.*Rhxs\n", pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst,
    2862           RT_MAX(RT_MIN(pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst, 64), 1), &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0]));
    2863     if (pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond)
    2864         Log5(("IEM Wrote %RGp: %.*Rhxs [2nd page]\n", pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond,
    2865               RT_MIN(pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond, 64),
    2866               &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst]));
    2867 
    2868     size_t cbWrote = pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst + pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond;
    2869     g_cbIemWrote = cbWrote;
    2870     memcpy(g_abIemWrote, &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0], RT_MIN(cbWrote, sizeof(g_abIemWrote)));
    2871 #endif
    2872 
    2873     /*
    2874      * Free the mapping entry.
    2875      */
    2876     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    2877     Assert(pVCpu->iem.s.cActiveMappings != 0);
    2878     pVCpu->iem.s.cActiveMappings--;
    2879     return VINF_SUCCESS;
    2880 }
    2881 
    2882 
    2883 /**
    2884272 * Helper for iemMemMap, iemMemMapJmp and iemMemBounceBufferMapCrossPage.
     273 * @todo duplicated
    2885274 */
    2886275DECL_FORCE_INLINE(uint32_t)
     
    2892281    return DBGFBpCheckDataRead(pVM, pVCpu, GCPtrMem, (uint32_t)cbMem, fSysAccess);
    2893282}
    2894 
    2895 
    2896 /**
    2897  * iemMemMap worker that deals with a request crossing pages.
    2898  */
    2899 static VBOXSTRICTRC
    2900 iemMemBounceBufferMapCrossPage(PVMCPUCC pVCpu, int iMemMap, void **ppvMem, uint8_t *pbUnmapInfo,
    2901                                size_t cbMem, RTGCPTR GCPtrFirst, uint32_t fAccess)
    2902 {
    2903     STAM_COUNTER_INC(&pVCpu->iem.s.StatMemBounceBufferCrossPage);
    2904     Assert(cbMem <= GUEST_PAGE_SIZE);
    2905 
    2906     /*
    2907      * Do the address translations.
    2908      */
    2909     uint32_t const cbFirstPage  = GUEST_PAGE_SIZE - (uint32_t)(GCPtrFirst & GUEST_PAGE_OFFSET_MASK);
    2910     RTGCPHYS GCPhysFirst;
    2911     VBOXSTRICTRC rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, GCPtrFirst, cbFirstPage, fAccess, &GCPhysFirst);
    2912     if (rcStrict != VINF_SUCCESS)
    2913         return rcStrict;
    2914     Assert((GCPhysFirst & GUEST_PAGE_OFFSET_MASK) == (GCPtrFirst & GUEST_PAGE_OFFSET_MASK));
    2915 
    2916     uint32_t const cbSecondPage = (uint32_t)cbMem - cbFirstPage;
    2917     RTGCPHYS GCPhysSecond;
    2918     rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, (GCPtrFirst + (cbMem - 1)) & ~(RTGCPTR)GUEST_PAGE_OFFSET_MASK,
    2919                                                  cbSecondPage, fAccess, &GCPhysSecond);
    2920     if (rcStrict != VINF_SUCCESS)
    2921         return rcStrict;
    2922     Assert((GCPhysSecond & GUEST_PAGE_OFFSET_MASK) == 0);
    2923     GCPhysSecond &= ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK; /** @todo why? */
    2924 
    2925     PVMCC pVM = pVCpu->CTX_SUFF(pVM);
    2926 
    2927     /*
    2928      * Check for data breakpoints.
    2929      */
    2930     if (RT_LIKELY(!(pVCpu->iem.s.fExec & IEM_F_PENDING_BRK_DATA)))
    2931     { /* likely */ }
    2932     else
    2933     {
    2934         uint32_t fDataBps = iemMemCheckDataBreakpoint(pVM, pVCpu, GCPtrFirst, cbFirstPage, fAccess);
    2935         fDataBps         |= iemMemCheckDataBreakpoint(pVM, pVCpu, (GCPtrFirst + (cbMem - 1)) & ~(RTGCPTR)GUEST_PAGE_OFFSET_MASK,
    2936                                                       cbSecondPage, fAccess);
    2937         pVCpu->cpum.GstCtx.eflags.uBoth |= fDataBps & (CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK);
    2938         if (fDataBps > 1)
    2939             LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapCrossPage: Data breakpoint: fDataBps=%#x for %RGv LB %zx; fAccess=%#x cs:rip=%04x:%08RX64\n",
    2940                                   fDataBps, GCPtrFirst, cbMem, fAccess, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    2941     }
    2942 
    2943     /*
    2944      * Read in the current memory content if it's a read, execute or partial
    2945      * write access.
    2946      */
    2947     uint8_t * const pbBuf = &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0];
    2948 
    2949     if (fAccess & (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_EXEC | IEM_ACCESS_PARTIAL_WRITE))
    2950     {
    2951         if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))
    2952         {
    2953             /*
    2954              * Must carefully deal with access handler status codes here,
    2955              * makes the code a bit bloated.
    2956              */
    2957             rcStrict = PGMPhysRead(pVM, GCPhysFirst, pbBuf, cbFirstPage, PGMACCESSORIGIN_IEM);
    2958             if (rcStrict == VINF_SUCCESS)
    2959             {
    2960                 rcStrict = PGMPhysRead(pVM, GCPhysSecond, pbBuf + cbFirstPage, cbSecondPage, PGMACCESSORIGIN_IEM);
    2961                 if (rcStrict == VINF_SUCCESS)
    2962                 { /*likely */ }
    2963                 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    2964                     rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    2965                 else
    2966                 {
    2967                     LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysSecond=%RGp rcStrict2=%Rrc (!!)\n",
    2968                                           GCPhysSecond, VBOXSTRICTRC_VAL(rcStrict) ));
    2969                     return rcStrict;
    2970                 }
    2971             }
    2972             else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    2973             {
    2974                 VBOXSTRICTRC rcStrict2 = PGMPhysRead(pVM, GCPhysSecond, pbBuf + cbFirstPage, cbSecondPage, PGMACCESSORIGIN_IEM);
    2975                 if (PGM_PHYS_RW_IS_SUCCESS(rcStrict2))
    2976                 {
    2977                     PGM_PHYS_RW_DO_UPDATE_STRICT_RC(rcStrict, rcStrict2);
    2978                     rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    2979                 }
    2980                 else
    2981                 {
    2982                     LogEx(LOG_GROUP_IEM,
    2983                           ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysSecond=%RGp rcStrict2=%Rrc (rcStrict=%Rrc) (!!)\n",
    2984                            GCPhysSecond, VBOXSTRICTRC_VAL(rcStrict2), VBOXSTRICTRC_VAL(rcStrict2) ));
    2985                     return rcStrict2;
    2986                 }
    2987             }
    2988             else
    2989             {
    2990                 LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysFirst=%RGp rcStrict=%Rrc (!!)\n",
    2991                                       GCPhysFirst, VBOXSTRICTRC_VAL(rcStrict) ));
    2992                 return rcStrict;
    2993             }
    2994         }
    2995         else
    2996         {
    2997             /*
    2998              * No informational status codes here, much more straight forward.
    2999              */
    3000             int rc = PGMPhysSimpleReadGCPhys(pVM, pbBuf, GCPhysFirst, cbFirstPage);
    3001             if (RT_SUCCESS(rc))
    3002             {
    3003                 Assert(rc == VINF_SUCCESS);
    3004                 rc = PGMPhysSimpleReadGCPhys(pVM, pbBuf + cbFirstPage, GCPhysSecond, cbSecondPage);
    3005                 if (RT_SUCCESS(rc))
    3006                     Assert(rc == VINF_SUCCESS);
    3007                 else
    3008                 {
    3009                     LogEx(LOG_GROUP_IEM,
    3010                           ("iemMemBounceBufferMapPhys: PGMPhysSimpleReadGCPhys GCPhysSecond=%RGp rc=%Rrc (!!)\n", GCPhysSecond, rc));
    3011                     return rc;
    3012                 }
    3013             }
    3014             else
    3015             {
    3016                 LogEx(LOG_GROUP_IEM,
    3017                       ("iemMemBounceBufferMapPhys: PGMPhysSimpleReadGCPhys GCPhysFirst=%RGp rc=%Rrc (!!)\n", GCPhysFirst, rc));
    3018                 return rc;
    3019             }
    3020         }
    3021     }
    3022 #ifdef VBOX_STRICT
    3023     else
    3024         memset(pbBuf, 0xcc, cbMem);
    3025     if (cbMem < sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab))
    3026         memset(pbBuf + cbMem, 0xaa, sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab) - cbMem);
    3027 #endif
    3028     AssertCompileMemberAlignment(VMCPU, iem.s.aBounceBuffers, 64);
    3029 
    3030     /*
    3031      * Commit the bounce buffer entry.
    3032      */
    3033     pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst    = GCPhysFirst;
    3034     pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond   = GCPhysSecond;
    3035     pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst        = (uint16_t)cbFirstPage;
    3036     pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond       = (uint16_t)cbSecondPage;
    3037     pVCpu->iem.s.aMemBbMappings[iMemMap].fUnassigned    = false;
    3038     pVCpu->iem.s.aMemMappings[iMemMap].pv               = pbBuf;
    3039     pVCpu->iem.s.aMemMappings[iMemMap].fAccess          = fAccess | IEM_ACCESS_BOUNCE_BUFFERED;
    3040     pVCpu->iem.s.iNextMapping = iMemMap + 1;
    3041     pVCpu->iem.s.cActiveMappings++;
    3042 
    3043     *ppvMem = pbBuf;
    3044     *pbUnmapInfo = iMemMap | 0x08 | ((fAccess & IEM_ACCESS_TYPE_MASK) << 4);
    3045     return VINF_SUCCESS;
    3046 }
    3047 
    3048 
    3049 /**
    3050  * iemMemMap woker that deals with iemMemPageMap failures.
    3051  */
    3052 static VBOXSTRICTRC iemMemBounceBufferMapPhys(PVMCPUCC pVCpu, unsigned iMemMap, void **ppvMem, uint8_t *pbUnmapInfo, size_t cbMem,
    3053                                               RTGCPHYS GCPhysFirst, uint32_t fAccess, VBOXSTRICTRC rcMap)
    3054 {
    3055     STAM_COUNTER_INC(&pVCpu->iem.s.StatMemBounceBufferMapPhys);
    3056 
    3057     /*
    3058      * Filter out conditions we can handle and the ones which shouldn't happen.
    3059      */
    3060     if (   rcMap != VERR_PGM_PHYS_TLB_CATCH_WRITE
    3061         && rcMap != VERR_PGM_PHYS_TLB_CATCH_ALL
    3062         && rcMap != VERR_PGM_PHYS_TLB_UNASSIGNED)
    3063     {
    3064         AssertReturn(RT_FAILURE_NP(rcMap), VERR_IEM_IPE_8);
    3065         return rcMap;
    3066     }
    3067     pVCpu->iem.s.cPotentialExits++;
    3068 
    3069     /*
    3070      * Read in the current memory content if it's a read, execute or partial
    3071      * write access.
    3072      */
    3073     uint8_t *pbBuf = &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0];
    3074     if (fAccess & (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_EXEC | IEM_ACCESS_PARTIAL_WRITE))
    3075     {
    3076         if (rcMap == VERR_PGM_PHYS_TLB_UNASSIGNED)
    3077             memset(pbBuf, 0xff, cbMem);
    3078         else
    3079         {
    3080             int rc;
    3081             if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))
    3082             {
    3083                 VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), GCPhysFirst, pbBuf, cbMem, PGMACCESSORIGIN_IEM);
    3084                 if (rcStrict == VINF_SUCCESS)
    3085                 { /* nothing */ }
    3086                 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    3087                     rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    3088                 else
    3089                 {
    3090                     LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysFirst=%RGp rcStrict=%Rrc (!!)\n",
    3091                                           GCPhysFirst, VBOXSTRICTRC_VAL(rcStrict) ));
    3092                     return rcStrict;
    3093                 }
    3094             }
    3095             else
    3096             {
    3097                 rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), pbBuf, GCPhysFirst, cbMem);
    3098                 if (RT_SUCCESS(rc))
    3099                 { /* likely */ }
    3100                 else
    3101                 {
    3102                     LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysSimpleReadGCPhys GCPhysFirst=%RGp rcStrict=%Rrc (!!)\n",
    3103                                           GCPhysFirst, rc));
    3104                     return rc;
    3105                 }
    3106             }
    3107         }
    3108     }
    3109 #ifdef VBOX_STRICT
    3110     else
    3111         memset(pbBuf, 0xcc, cbMem);
    3112 #endif
    3113 #ifdef VBOX_STRICT
    3114     if (cbMem < sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab))
    3115         memset(pbBuf + cbMem, 0xaa, sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab) - cbMem);
    3116 #endif
    3117 
    3118     /*
    3119      * Commit the bounce buffer entry.
    3120      */
    3121     pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst    = GCPhysFirst;
    3122     pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond   = NIL_RTGCPHYS;
    3123     pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst        = (uint16_t)cbMem;
    3124     pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond       = 0;
    3125     pVCpu->iem.s.aMemBbMappings[iMemMap].fUnassigned    = rcMap == VERR_PGM_PHYS_TLB_UNASSIGNED;
    3126     pVCpu->iem.s.aMemMappings[iMemMap].pv               = pbBuf;
    3127     pVCpu->iem.s.aMemMappings[iMemMap].fAccess          = fAccess | IEM_ACCESS_BOUNCE_BUFFERED;
    3128     pVCpu->iem.s.iNextMapping = iMemMap + 1;
    3129     pVCpu->iem.s.cActiveMappings++;
    3130 
    3131     *ppvMem = pbBuf;
    3132     *pbUnmapInfo = iMemMap | 0x08 | ((fAccess & IEM_ACCESS_TYPE_MASK) << 4);
    3133     return VINF_SUCCESS;
    3134 }
    3135 
    3136283
    3137284
     
    3328475            { /* likely */ }
    3329476            else
    3330                 IEMTlbInvalidateAllPhysicalSlow(pVCpu);
     477                iemTlbInvalidateAllPhysicalSlow(pVCpu);
    3331478            pTlbe->pbMappingR3       = NULL;
    3332479            pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK;
     
    3509656
    3510657    return VINF_SUCCESS;
    3511 }
    3512 
    3513 
    3514 /**
    3515  * Commits the guest memory if bounce buffered and unmaps it.
    3516  *
    3517  * @returns Strict VBox status code.
    3518  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    3519  * @param   bUnmapInfo          Unmap info set by iemMemMap.
    3520  */
    3521 VBOXSTRICTRC iemMemCommitAndUnmap(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT
    3522 {
    3523     uintptr_t const iMemMap = bUnmapInfo & 0x7;
    3524     AssertMsgReturn(   (bUnmapInfo & 0x08)
    3525                     && iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings)
    3526                     && (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_TYPE_MASK | 0xf)) == ((unsigned)bUnmapInfo >> 4),
    3527                     ("%#x fAccess=%#x\n", bUnmapInfo, pVCpu->iem.s.aMemMappings[iMemMap].fAccess),
    3528                     VERR_NOT_FOUND);
    3529 
    3530     /* If it's bounce buffered, we may need to write back the buffer. */
    3531     if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED)
    3532     {
    3533         if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE)
    3534             return iemMemBounceBufferCommitAndUnmap(pVCpu, iMemMap, false /*fPostponeFail*/);
    3535     }
    3536     /* Otherwise unlock it. */
    3537     else if (!(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_NOT_LOCKED))
    3538         PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    3539 
    3540     /* Free the entry. */
    3541     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    3542     Assert(pVCpu->iem.s.cActiveMappings != 0);
    3543     pVCpu->iem.s.cActiveMappings--;
    3544     return VINF_SUCCESS;
    3545 }
    3546 
    3547 
    3548 /**
    3549  * Rolls back the guest memory (conceptually only) and unmaps it.
    3550  *
    3551  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    3552  * @param   bUnmapInfo          Unmap info set by iemMemMap.
    3553  */
    3554 void iemMemRollbackAndUnmap(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT
    3555 {
    3556     uintptr_t const iMemMap = bUnmapInfo & 0x7;
    3557     AssertMsgReturnVoid(   (bUnmapInfo & 0x08)
    3558                         && iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings)
    3559                         &&    (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_TYPE_MASK | 0xf))
    3560                            == ((unsigned)bUnmapInfo >> 4),
    3561                         ("%#x fAccess=%#x\n", bUnmapInfo, pVCpu->iem.s.aMemMappings[iMemMap].fAccess));
    3562 
    3563     /* Unlock it if necessary. */
    3564     if (!(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_NOT_LOCKED))
    3565         PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    3566 
    3567     /* Free the entry. */
    3568     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    3569     Assert(pVCpu->iem.s.cActiveMappings != 0);
    3570     pVCpu->iem.s.cActiveMappings--;
    3571658}
    3572659
     
    40111098}
    40121099
    4013 
    4014 /**
    4015  * Commits the guest memory if bounce buffered and unmaps it, longjmp on error.
    4016  *
    4017  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4018  * @param   pvMem               The mapping.
    4019  * @param   fAccess             The kind of access.
    4020  */
    4021 void iemMemCommitAndUnmapJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP
    4022 {
    4023     uintptr_t const iMemMap = bUnmapInfo & 0x7;
    4024     AssertMsgReturnVoid(   (bUnmapInfo & 0x08)
    4025                         && iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings)
    4026                         &&    (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_TYPE_MASK | 0xf))
    4027                            == ((unsigned)bUnmapInfo >> 4),
    4028                         ("%#x fAccess=%#x\n", bUnmapInfo, pVCpu->iem.s.aMemMappings[iMemMap].fAccess));
    4029 
    4030     /* If it's bounce buffered, we may need to write back the buffer. */
    4031     if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED)
    4032     {
    4033         if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE)
    4034         {
    4035             VBOXSTRICTRC rcStrict = iemMemBounceBufferCommitAndUnmap(pVCpu, iMemMap, false /*fPostponeFail*/);
    4036             if (rcStrict == VINF_SUCCESS)
    4037                 return;
    4038             IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    4039         }
    4040     }
    4041     /* Otherwise unlock it. */
    4042     else if (!(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_NOT_LOCKED))
    4043         PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    4044 
    4045     /* Free the entry. */
    4046     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    4047     Assert(pVCpu->iem.s.cActiveMappings != 0);
    4048     pVCpu->iem.s.cActiveMappings--;
    4049 }
    4050 
    4051 
    4052 /** Fallback for iemMemCommitAndUnmapRwJmp.  */
    4053 void iemMemCommitAndUnmapRwSafeJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP
    4054 {
    4055     Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_WRITE));
    4056     iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);
    4057 }
    4058 
    4059 
    4060 /** Fallback for iemMemCommitAndUnmapAtJmp.  */
    4061 void iemMemCommitAndUnmapAtSafeJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP
    4062 {
    4063     Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_WRITE));
    4064     iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);
    4065 }
    4066 
    4067 
    4068 /** Fallback for iemMemCommitAndUnmapWoJmp.  */
    4069 void iemMemCommitAndUnmapWoSafeJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP
    4070 {
    4071     Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == IEM_ACCESS_TYPE_WRITE);
    4072     iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);
    4073 }
    4074 
    4075 
    4076 /** Fallback for iemMemCommitAndUnmapRoJmp.  */
    4077 void iemMemCommitAndUnmapRoSafeJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP
    4078 {
    4079     Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == IEM_ACCESS_TYPE_READ);
    4080     iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);
    4081 }
    4082 
    4083 
    4084 /** Fallback for iemMemRollbackAndUnmapWo.  */
    4085 void iemMemRollbackAndUnmapWoSafe(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT
    4086 {
    4087     Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == IEM_ACCESS_TYPE_WRITE);
    4088     iemMemRollbackAndUnmap(pVCpu, bUnmapInfo);
    4089 }
    4090 
    40911100#endif /* IEM_WITH_SETJMP */
    4092 
    4093 #ifndef IN_RING3
    4094 /**
    4095  * Commits the guest memory if bounce buffered and unmaps it, if any bounce
    4096  * buffer part shows trouble it will be postponed to ring-3 (sets FF and stuff).
    4097  *
    4098  * Allows the instruction to be completed and retired, while the IEM user will
    4099  * return to ring-3 immediately afterwards and do the postponed writes there.
    4100  *
    4101  * @returns VBox status code (no strict statuses).  Caller must check
    4102  *          VMCPU_FF_IEM before repeating string instructions and similar stuff.
    4103  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4104  * @param   pvMem               The mapping.
    4105  * @param   fAccess             The kind of access.
    4106  */
    4107 VBOXSTRICTRC iemMemCommitAndUnmapPostponeTroubleToR3(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT
    4108 {
    4109     uintptr_t const iMemMap = bUnmapInfo & 0x7;
    4110     AssertMsgReturn(   (bUnmapInfo & 0x08)
    4111                     && iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings)
    4112                     &&    (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_TYPE_MASK | 0xf))
    4113                        == ((unsigned)bUnmapInfo >> 4),
    4114                     ("%#x fAccess=%#x\n", bUnmapInfo, pVCpu->iem.s.aMemMappings[iMemMap].fAccess),
    4115                     VERR_NOT_FOUND);
    4116 
    4117     /* If it's bounce buffered, we may need to write back the buffer. */
    4118     if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED)
    4119     {
    4120         if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE)
    4121             return iemMemBounceBufferCommitAndUnmap(pVCpu, iMemMap, true /*fPostponeFail*/);
    4122     }
    4123     /* Otherwise unlock it. */
    4124     else if (!(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_NOT_LOCKED))
    4125         PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    4126 
    4127     /* Free the entry. */
    4128     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    4129     Assert(pVCpu->iem.s.cActiveMappings != 0);
    4130     pVCpu->iem.s.cActiveMappings--;
    4131     return VINF_SUCCESS;
    4132 }
    4133 #endif
    4134 
    4135 
    4136 /**
    4137  * Rollbacks mappings, releasing page locks and such.
    4138  *
    4139  * The caller shall only call this after checking cActiveMappings.
    4140  *
    4141  * @param   pVCpu       The cross context virtual CPU structure of the calling thread.
    4142  */
    4143 void iemMemRollback(PVMCPUCC pVCpu) RT_NOEXCEPT
    4144 {
    4145     Assert(pVCpu->iem.s.cActiveMappings > 0);
    4146 
    4147     uint32_t iMemMap = RT_ELEMENTS(pVCpu->iem.s.aMemMappings);
    4148     while (iMemMap-- > 0)
    4149     {
    4150         uint32_t const fAccess = pVCpu->iem.s.aMemMappings[iMemMap].fAccess;
    4151         if (fAccess != IEM_ACCESS_INVALID)
    4152         {
    4153             AssertMsg(!(fAccess & ~IEM_ACCESS_VALID_MASK) && fAccess != 0, ("%#x\n", fAccess));
    4154             pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    4155             if (!(fAccess & (IEM_ACCESS_BOUNCE_BUFFERED | IEM_ACCESS_NOT_LOCKED)))
    4156                 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    4157             AssertMsg(pVCpu->iem.s.cActiveMappings > 0,
    4158                       ("iMemMap=%u fAccess=%#x pv=%p GCPhysFirst=%RGp GCPhysSecond=%RGp\n",
    4159                        iMemMap, fAccess, pVCpu->iem.s.aMemMappings[iMemMap].pv,
    4160                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond));
    4161             pVCpu->iem.s.cActiveMappings--;
    4162         }
    4163     }
    4164 }
    41651101
    41661102
     
    41741110#define TMPL_MEM_FMT_TYPE   "%#04x"
    41751111#define TMPL_MEM_FMT_DESC   "byte"
    4176 #include "IEMAllMemRWTmpl.cpp.h"
     1112#include "IEMAllMemRWTmpl-x86.cpp.h"
    41771113
    41781114#define TMPL_MEM_TYPE       uint16_t
     
    41801116#define TMPL_MEM_FMT_TYPE   "%#06x"
    41811117#define TMPL_MEM_FMT_DESC   "word"
    4182 #include "IEMAllMemRWTmpl.cpp.h"
     1118#include "IEMAllMemRWTmpl-x86.cpp.h"
    41831119
    41841120#define TMPL_WITH_PUSH_SREG
     
    41871123#define TMPL_MEM_FMT_TYPE   "%#010x"
    41881124#define TMPL_MEM_FMT_DESC   "dword"
    4189 #include "IEMAllMemRWTmpl.cpp.h"
     1125#include "IEMAllMemRWTmpl-x86.cpp.h"
    41901126#undef TMPL_WITH_PUSH_SREG
    41911127
     
    41941130#define TMPL_MEM_FMT_TYPE   "%#018RX64"
    41951131#define TMPL_MEM_FMT_DESC   "qword"
    4196 #include "IEMAllMemRWTmpl.cpp.h"
     1132#include "IEMAllMemRWTmpl-x86.cpp.h"
    41971133
    41981134#undef TMPL_MEM_WITH_STACK
     
    42031139#define TMPL_MEM_FMT_TYPE   "%#010x"
    42041140#define TMPL_MEM_FMT_DESC   "dword"
    4205 #include "IEMAllMemRWTmpl.cpp.h"
     1141#include "IEMAllMemRWTmpl-x86.cpp.h"
    42061142#undef TMPL_WITH_PUSH_SREG
    42071143
     
    42111147#define TMPL_MEM_FMT_TYPE   "%#018RX64"
    42121148#define TMPL_MEM_FMT_DESC   "qword"
    4213 #include "IEMAllMemRWTmpl.cpp.h"
     1149#include "IEMAllMemRWTmpl-x86.cpp.h"
    42141150
    42151151#define TMPL_MEM_TYPE       uint64_t
     
    42181154#define TMPL_MEM_FMT_TYPE   "%#018RX64"
    42191155#define TMPL_MEM_FMT_DESC   "qword"
    4220 #include "IEMAllMemRWTmpl.cpp.h"
     1156#include "IEMAllMemRWTmpl-x86.cpp.h"
    42211157
    42221158/* See IEMAllMemRWTmplInline.cpp.h */
     
    42281164#define TMPL_MEM_FMT_TYPE   "%.10Rhxs"
    42291165#define TMPL_MEM_FMT_DESC   "tword"
    4230 #include "IEMAllMemRWTmpl.cpp.h"
     1166#include "IEMAllMemRWTmpl-x86.cpp.h"
    42311167
    42321168#define TMPL_MEM_TYPE       RTPBCD80U
     
    42351171#define TMPL_MEM_FMT_TYPE   "%.10Rhxs"
    42361172#define TMPL_MEM_FMT_DESC   "tword"
    4237 #include "IEMAllMemRWTmpl.cpp.h"
     1173#include "IEMAllMemRWTmpl-x86.cpp.h"
    42381174
    42391175#define TMPL_MEM_TYPE       RTUINT128U
     
    42421178#define TMPL_MEM_FMT_TYPE   "%.16Rhxs"
    42431179#define TMPL_MEM_FMT_DESC   "dqword"
    4244 #include "IEMAllMemRWTmpl.cpp.h"
     1180#include "IEMAllMemRWTmpl-x86.cpp.h"
    42451181
    42461182#define TMPL_MEM_TYPE           RTUINT128U
     
    42501186#define TMPL_MEM_FMT_TYPE       "%.16Rhxs"
    42511187#define TMPL_MEM_FMT_DESC       "dqword"
    4252 #include "IEMAllMemRWTmpl.cpp.h"
     1188#include "IEMAllMemRWTmpl-x86.cpp.h"
    42531189
    42541190#define TMPL_MEM_TYPE       RTUINT128U
     
    42571193#define TMPL_MEM_FMT_TYPE   "%.16Rhxs"
    42581194#define TMPL_MEM_FMT_DESC   "dqword"
    4259 #include "IEMAllMemRWTmpl.cpp.h"
     1195#include "IEMAllMemRWTmpl-x86.cpp.h"
    42601196
    42611197#define TMPL_MEM_TYPE       RTUINT256U
     
    42641200#define TMPL_MEM_FMT_TYPE   "%.32Rhxs"
    42651201#define TMPL_MEM_FMT_DESC   "qqword"
    4266 #include "IEMAllMemRWTmpl.cpp.h"
     1202#include "IEMAllMemRWTmpl-x86.cpp.h"
    42671203
    42681204#define TMPL_MEM_TYPE           RTUINT256U
     
    42721208#define TMPL_MEM_FMT_TYPE       "%.32Rhxs"
    42731209#define TMPL_MEM_FMT_DESC       "qqword"
    4274 #include "IEMAllMemRWTmpl.cpp.h"
     1210#include "IEMAllMemRWTmpl-x86.cpp.h"
     1211
    42751212
    42761213/**
     
    49351872}
    49361873
    4937 
    4938 #undef  LOG_GROUP
    4939 #define LOG_GROUP LOG_GROUP_IEM
    4940 
    49411874/** @} */
    49421875
    4943 /** @name   Opcode Helpers.
    4944  * @{
    4945  */
    4946 
    4947 /**
    4948  * Calculates the effective address of a ModR/M memory operand.
    4949  *
    4950  * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR.
    4951  *
    4952  * @return  Strict VBox status code.
    4953  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4954  * @param   bRm                 The ModRM byte.
    4955  * @param   cbImmAndRspOffset   - First byte: The size of any immediate
    4956  *                                following the effective address opcode bytes
    4957  *                                (only for RIP relative addressing).
    4958  *                              - Second byte: RSP displacement (for POP [ESP]).
    4959  * @param   pGCPtrEff           Where to return the effective address.
    4960  */
    4961 VBOXSTRICTRC iemOpHlpCalcRmEffAddr(PVMCPUCC pVCpu, uint8_t bRm, uint32_t cbImmAndRspOffset, PRTGCPTR pGCPtrEff) RT_NOEXCEPT
    4962 {
    4963     Log5(("iemOpHlpCalcRmEffAddr: bRm=%#x\n", bRm));
    4964 # define SET_SS_DEF() \
    4965     do \
    4966     { \
    4967         if (!(pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SEG_MASK)) \
    4968             pVCpu->iem.s.iEffSeg = X86_SREG_SS; \
    4969     } while (0)
    4970 
    4971     if (!IEM_IS_64BIT_CODE(pVCpu))
    4972     {
    4973 /** @todo Check the effective address size crap! */
    4974         if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_16BIT)
    4975         {
    4976             uint16_t u16EffAddr;
    4977 
    4978             /* Handle the disp16 form with no registers first. */
    4979             if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)
    4980                 IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);
    4981             else
    4982             {
    4983                 /* Get the displacment. */
    4984                 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    4985                 {
    4986                     case 0:  u16EffAddr = 0;                             break;
    4987                     case 1:  IEM_OPCODE_GET_NEXT_S8_SX_U16(&u16EffAddr); break;
    4988                     case 2:  IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);       break;
    4989                     default: AssertFailedReturn(VERR_IEM_IPE_1); /* (caller checked for these) */
    4990                 }
    4991 
    4992                 /* Add the base and index registers to the disp. */
    4993                 switch (bRm & X86_MODRM_RM_MASK)
    4994                 {
    4995                     case 0: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.si; break;
    4996                     case 1: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.di; break;
    4997                     case 2: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.si; SET_SS_DEF(); break;
    4998                     case 3: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.di; SET_SS_DEF(); break;
    4999                     case 4: u16EffAddr += pVCpu->cpum.GstCtx.si;            break;
    5000                     case 5: u16EffAddr += pVCpu->cpum.GstCtx.di;            break;
    5001                     case 6: u16EffAddr += pVCpu->cpum.GstCtx.bp;            SET_SS_DEF(); break;
    5002                     case 7: u16EffAddr += pVCpu->cpum.GstCtx.bx;            break;
    5003                 }
    5004             }
    5005 
    5006             *pGCPtrEff = u16EffAddr;
    5007         }
    5008         else
    5009         {
    5010             Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5011             uint32_t u32EffAddr;
    5012 
    5013             /* Handle the disp32 form with no registers first. */
    5014             if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    5015                 IEM_OPCODE_GET_NEXT_U32(&u32EffAddr);
    5016             else
    5017             {
    5018                 /* Get the register (or SIB) value. */
    5019                 switch ((bRm & X86_MODRM_RM_MASK))
    5020                 {
    5021                     case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    5022                     case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    5023                     case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    5024                     case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    5025                     case 4: /* SIB */
    5026                     {
    5027                         uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
    5028 
    5029                         /* Get the index and scale it. */
    5030                         switch ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)
    5031                         {
    5032                             case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    5033                             case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    5034                             case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    5035                             case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    5036                             case 4: u32EffAddr = 0; /*none */ break;
    5037                             case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;
    5038                             case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    5039                             case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    5040                             IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5041                         }
    5042                         u32EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    5043 
    5044                         /* add base */
    5045                         switch (bSib & X86_SIB_BASE_MASK)
    5046                         {
    5047                             case 0: u32EffAddr += pVCpu->cpum.GstCtx.eax; break;
    5048                             case 1: u32EffAddr += pVCpu->cpum.GstCtx.ecx; break;
    5049                             case 2: u32EffAddr += pVCpu->cpum.GstCtx.edx; break;
    5050                             case 3: u32EffAddr += pVCpu->cpum.GstCtx.ebx; break;
    5051                             case 4: u32EffAddr += pVCpu->cpum.GstCtx.esp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
    5052                             case 5:
    5053                                 if ((bRm & X86_MODRM_MOD_MASK) != 0)
    5054                                 {
    5055                                     u32EffAddr += pVCpu->cpum.GstCtx.ebp;
    5056                                     SET_SS_DEF();
    5057                                 }
    5058                                 else
    5059                                 {
    5060                                     uint32_t u32Disp;
    5061                                     IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5062                                     u32EffAddr += u32Disp;
    5063                                 }
    5064                                 break;
    5065                             case 6: u32EffAddr += pVCpu->cpum.GstCtx.esi; break;
    5066                             case 7: u32EffAddr += pVCpu->cpum.GstCtx.edi; break;
    5067                             IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5068                         }
    5069                         break;
    5070                     }
    5071                     case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; SET_SS_DEF(); break;
    5072                     case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    5073                     case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    5074                     IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5075                 }
    5076 
    5077                 /* Get and add the displacement. */
    5078                 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5079                 {
    5080                     case 0:
    5081                         break;
    5082                     case 1:
    5083                     {
    5084                         int8_t i8Disp; IEM_OPCODE_GET_NEXT_S8(&i8Disp);
    5085                         u32EffAddr += i8Disp;
    5086                         break;
    5087                     }
    5088                     case 2:
    5089                     {
    5090                         uint32_t u32Disp; IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5091                         u32EffAddr += u32Disp;
    5092                         break;
    5093                     }
    5094                     default:
    5095                         AssertFailedReturn(VERR_IEM_IPE_2); /* (caller checked for these) */
    5096                 }
    5097 
    5098             }
    5099             Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5100             *pGCPtrEff = u32EffAddr;
    5101         }
    5102     }
    5103     else
    5104     {
    5105         uint64_t u64EffAddr;
    5106 
    5107         /* Handle the rip+disp32 form with no registers first. */
    5108         if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    5109         {
    5110             IEM_OPCODE_GET_NEXT_S32_SX_U64(&u64EffAddr);
    5111             u64EffAddr += pVCpu->cpum.GstCtx.rip + IEM_GET_INSTR_LEN(pVCpu) + (cbImmAndRspOffset & UINT32_C(0xff));
    5112         }
    5113         else
    5114         {
    5115             /* Get the register (or SIB) value. */
    5116             switch ((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB)
    5117             {
    5118                 case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    5119                 case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    5120                 case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    5121                 case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    5122                 case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; SET_SS_DEF(); break;
    5123                 case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    5124                 case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    5125                 case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    5126                 case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    5127                 case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    5128                 case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    5129                 case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    5130                 case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    5131                 case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    5132                 /* SIB */
    5133                 case 4:
    5134                 case 12:
    5135                 {
    5136                     uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
    5137 
    5138                     /* Get the index and scale it. */
    5139                     switch (((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) | pVCpu->iem.s.uRexIndex)
    5140                     {
    5141                         case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    5142                         case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    5143                         case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    5144                         case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    5145                         case  4: u64EffAddr = 0; /*none */ break;
    5146                         case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;
    5147                         case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    5148                         case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    5149                         case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    5150                         case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    5151                         case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    5152                         case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    5153                         case 12: u64EffAddr = pVCpu->cpum.GstCtx.r12; break;
    5154                         case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    5155                         case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    5156                         case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    5157                         IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5158                     }
    5159                     u64EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    5160 
    5161                     /* add base */
    5162                     switch ((bSib & X86_SIB_BASE_MASK) | pVCpu->iem.s.uRexB)
    5163                     {
    5164                         case  0: u64EffAddr += pVCpu->cpum.GstCtx.rax; break;
    5165                         case  1: u64EffAddr += pVCpu->cpum.GstCtx.rcx; break;
    5166                         case  2: u64EffAddr += pVCpu->cpum.GstCtx.rdx; break;
    5167                         case  3: u64EffAddr += pVCpu->cpum.GstCtx.rbx; break;
    5168                         case  4: u64EffAddr += pVCpu->cpum.GstCtx.rsp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
    5169                         case  6: u64EffAddr += pVCpu->cpum.GstCtx.rsi; break;
    5170                         case  7: u64EffAddr += pVCpu->cpum.GstCtx.rdi; break;
    5171                         case  8: u64EffAddr += pVCpu->cpum.GstCtx.r8;  break;
    5172                         case  9: u64EffAddr += pVCpu->cpum.GstCtx.r9;  break;
    5173                         case 10: u64EffAddr += pVCpu->cpum.GstCtx.r10; break;
    5174                         case 11: u64EffAddr += pVCpu->cpum.GstCtx.r11; break;
    5175                         case 12: u64EffAddr += pVCpu->cpum.GstCtx.r12; break;
    5176                         case 14: u64EffAddr += pVCpu->cpum.GstCtx.r14; break;
    5177                         case 15: u64EffAddr += pVCpu->cpum.GstCtx.r15; break;
    5178                         /* complicated encodings */
    5179                         case 5:
    5180                         case 13:
    5181                             if ((bRm & X86_MODRM_MOD_MASK) != 0)
    5182                             {
    5183                                 if (!pVCpu->iem.s.uRexB)
    5184                                 {
    5185                                     u64EffAddr += pVCpu->cpum.GstCtx.rbp;
    5186                                     SET_SS_DEF();
    5187                                 }
    5188                                 else
    5189                                     u64EffAddr += pVCpu->cpum.GstCtx.r13;
    5190                             }
    5191                             else
    5192                             {
    5193                                 uint32_t u32Disp;
    5194                                 IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5195                                 u64EffAddr += (int32_t)u32Disp;
    5196                             }
    5197                             break;
    5198                         IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5199                     }
    5200                     break;
    5201                 }
    5202                 IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5203             }
    5204 
    5205             /* Get and add the displacement. */
    5206             switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5207             {
    5208                 case 0:
    5209                     break;
    5210                 case 1:
    5211                 {
    5212                     int8_t i8Disp;
    5213                     IEM_OPCODE_GET_NEXT_S8(&i8Disp);
    5214                     u64EffAddr += i8Disp;
    5215                     break;
    5216                 }
    5217                 case 2:
    5218                 {
    5219                     uint32_t u32Disp;
    5220                     IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5221                     u64EffAddr += (int32_t)u32Disp;
    5222                     break;
    5223                 }
    5224                 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* (caller checked for these) */
    5225             }
    5226 
    5227         }
    5228 
    5229         if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)
    5230             *pGCPtrEff = u64EffAddr;
    5231         else
    5232         {
    5233             Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5234             *pGCPtrEff = u64EffAddr & UINT32_MAX;
    5235         }
    5236     }
    5237 
    5238     Log5(("iemOpHlpCalcRmEffAddr: EffAddr=%#010RGv\n", *pGCPtrEff));
    5239     return VINF_SUCCESS;
    5240 }
    5241 
    5242 
    5243 #ifdef IEM_WITH_SETJMP
    5244 /**
    5245  * Calculates the effective address of a ModR/M memory operand.
    5246  *
    5247  * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR.
    5248  *
    5249  * May longjmp on internal error.
    5250  *
    5251  * @return  The effective address.
    5252  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    5253  * @param   bRm                 The ModRM byte.
    5254  * @param   cbImmAndRspOffset   - First byte: The size of any immediate
    5255  *                                following the effective address opcode bytes
    5256  *                                (only for RIP relative addressing).
    5257  *                              - Second byte: RSP displacement (for POP [ESP]).
    5258  */
    5259 RTGCPTR iemOpHlpCalcRmEffAddrJmp(PVMCPUCC pVCpu, uint8_t bRm, uint32_t cbImmAndRspOffset) IEM_NOEXCEPT_MAY_LONGJMP
    5260 {
    5261     Log5(("iemOpHlpCalcRmEffAddrJmp: bRm=%#x\n", bRm));
    5262 # define SET_SS_DEF() \
    5263     do \
    5264     { \
    5265         if (!(pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SEG_MASK)) \
    5266             pVCpu->iem.s.iEffSeg = X86_SREG_SS; \
    5267     } while (0)
    5268 
    5269     if (!IEM_IS_64BIT_CODE(pVCpu))
    5270     {
    5271 /** @todo Check the effective address size crap! */
    5272         if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_16BIT)
    5273         {
    5274             uint16_t u16EffAddr;
    5275 
    5276             /* Handle the disp16 form with no registers first. */
    5277             if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)
    5278                 IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);
    5279             else
    5280             {
    5281                 /* Get the displacment. */
    5282                 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5283                 {
    5284                     case 0:  u16EffAddr = 0;                             break;
    5285                     case 1:  IEM_OPCODE_GET_NEXT_S8_SX_U16(&u16EffAddr); break;
    5286                     case 2:  IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);       break;
    5287                     default: AssertFailedStmt(IEM_DO_LONGJMP(pVCpu, VERR_IEM_IPE_1)); /* (caller checked for these) */
    5288                 }
    5289 
    5290                 /* Add the base and index registers to the disp. */
    5291                 switch (bRm & X86_MODRM_RM_MASK)
    5292                 {
    5293                     case 0: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.si; break;
    5294                     case 1: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.di; break;
    5295                     case 2: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.si; SET_SS_DEF(); break;
    5296                     case 3: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.di; SET_SS_DEF(); break;
    5297                     case 4: u16EffAddr += pVCpu->cpum.GstCtx.si;            break;
    5298                     case 5: u16EffAddr += pVCpu->cpum.GstCtx.di;            break;
    5299                     case 6: u16EffAddr += pVCpu->cpum.GstCtx.bp;            SET_SS_DEF(); break;
    5300                     case 7: u16EffAddr += pVCpu->cpum.GstCtx.bx;            break;
    5301                 }
    5302             }
    5303 
    5304             Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#06RX16\n", u16EffAddr));
    5305             return u16EffAddr;
    5306         }
    5307 
    5308         Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5309         uint32_t u32EffAddr;
    5310 
    5311         /* Handle the disp32 form with no registers first. */
    5312         if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    5313             IEM_OPCODE_GET_NEXT_U32(&u32EffAddr);
    5314         else
    5315         {
    5316             /* Get the register (or SIB) value. */
    5317             switch ((bRm & X86_MODRM_RM_MASK))
    5318             {
    5319                 case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    5320                 case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    5321                 case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    5322                 case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    5323                 case 4: /* SIB */
    5324                 {
    5325                     uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
    5326 
    5327                     /* Get the index and scale it. */
    5328                     switch ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)
    5329                     {
    5330                         case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    5331                         case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    5332                         case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    5333                         case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    5334                         case 4: u32EffAddr = 0; /*none */ break;
    5335                         case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;
    5336                         case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    5337                         case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    5338                         IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
    5339                     }
    5340                     u32EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    5341 
    5342                     /* add base */
    5343                     switch (bSib & X86_SIB_BASE_MASK)
    5344                     {
    5345                         case 0: u32EffAddr += pVCpu->cpum.GstCtx.eax; break;
    5346                         case 1: u32EffAddr += pVCpu->cpum.GstCtx.ecx; break;
    5347                         case 2: u32EffAddr += pVCpu->cpum.GstCtx.edx; break;
    5348                         case 3: u32EffAddr += pVCpu->cpum.GstCtx.ebx; break;
    5349                         case 4: u32EffAddr += pVCpu->cpum.GstCtx.esp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
    5350                         case 5:
    5351                             if ((bRm & X86_MODRM_MOD_MASK) != 0)
    5352                             {
    5353                                 u32EffAddr += pVCpu->cpum.GstCtx.ebp;
    5354                                 SET_SS_DEF();
    5355                             }
    5356                             else
    5357                             {
    5358                                 uint32_t u32Disp;
    5359                                 IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5360                                 u32EffAddr += u32Disp;
    5361                             }
    5362                             break;
    5363                         case 6: u32EffAddr += pVCpu->cpum.GstCtx.esi; break;
    5364                         case 7: u32EffAddr += pVCpu->cpum.GstCtx.edi; break;
    5365                         IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
    5366                     }
    5367                     break;
    5368                 }
    5369                 case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; SET_SS_DEF(); break;
    5370                 case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    5371                 case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    5372                 IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
    5373             }
    5374 
    5375             /* Get and add the displacement. */
    5376             switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5377             {
    5378                 case 0:
    5379                     break;
    5380                 case 1:
    5381                 {
    5382                     int8_t i8Disp; IEM_OPCODE_GET_NEXT_S8(&i8Disp);
    5383                     u32EffAddr += i8Disp;
    5384                     break;
    5385                 }
    5386                 case 2:
    5387                 {
    5388                     uint32_t u32Disp; IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5389                     u32EffAddr += u32Disp;
    5390                     break;
    5391                 }
    5392                 default:
    5393                     AssertFailedStmt(IEM_DO_LONGJMP(pVCpu, VERR_IEM_IPE_2)); /* (caller checked for these) */
    5394             }
    5395         }
    5396 
    5397         Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5398         Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RX32\n", u32EffAddr));
    5399         return u32EffAddr;
    5400     }
    5401 
    5402     uint64_t u64EffAddr;
    5403 
    5404     /* Handle the rip+disp32 form with no registers first. */
    5405     if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    5406     {
    5407         IEM_OPCODE_GET_NEXT_S32_SX_U64(&u64EffAddr);
    5408         u64EffAddr += pVCpu->cpum.GstCtx.rip + IEM_GET_INSTR_LEN(pVCpu) + (cbImmAndRspOffset & UINT32_C(0xff));
    5409     }
    5410     else
    5411     {
    5412         /* Get the register (or SIB) value. */
    5413         switch ((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB)
    5414         {
    5415             case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    5416             case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    5417             case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    5418             case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    5419             case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; SET_SS_DEF(); break;
    5420             case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    5421             case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    5422             case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    5423             case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    5424             case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    5425             case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    5426             case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    5427             case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    5428             case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    5429             /* SIB */
    5430             case 4:
    5431             case 12:
    5432             {
    5433                 uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
    5434 
    5435                 /* Get the index and scale it. */
    5436                 switch (((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) | pVCpu->iem.s.uRexIndex)
    5437                 {
    5438                     case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    5439                     case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    5440                     case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    5441                     case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    5442                     case  4: u64EffAddr = 0; /*none */ break;
    5443                     case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;
    5444                     case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    5445                     case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    5446                     case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    5447                     case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    5448                     case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    5449                     case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    5450                     case 12: u64EffAddr = pVCpu->cpum.GstCtx.r12; break;
    5451                     case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    5452                     case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    5453                     case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    5454                     IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
    5455                 }
    5456                 u64EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    5457 
    5458                 /* add base */
    5459                 switch ((bSib & X86_SIB_BASE_MASK) | pVCpu->iem.s.uRexB)
    5460                 {
    5461                     case  0: u64EffAddr += pVCpu->cpum.GstCtx.rax; break;
    5462                     case  1: u64EffAddr += pVCpu->cpum.GstCtx.rcx; break;
    5463                     case  2: u64EffAddr += pVCpu->cpum.GstCtx.rdx; break;
    5464                     case  3: u64EffAddr += pVCpu->cpum.GstCtx.rbx; break;
    5465                     case  4: u64EffAddr += pVCpu->cpum.GstCtx.rsp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
    5466                     case  6: u64EffAddr += pVCpu->cpum.GstCtx.rsi; break;
    5467                     case  7: u64EffAddr += pVCpu->cpum.GstCtx.rdi; break;
    5468                     case  8: u64EffAddr += pVCpu->cpum.GstCtx.r8;  break;
    5469                     case  9: u64EffAddr += pVCpu->cpum.GstCtx.r9;  break;
    5470                     case 10: u64EffAddr += pVCpu->cpum.GstCtx.r10; break;
    5471                     case 11: u64EffAddr += pVCpu->cpum.GstCtx.r11; break;
    5472                     case 12: u64EffAddr += pVCpu->cpum.GstCtx.r12; break;
    5473                     case 14: u64EffAddr += pVCpu->cpum.GstCtx.r14; break;
    5474                     case 15: u64EffAddr += pVCpu->cpum.GstCtx.r15; break;
    5475                     /* complicated encodings */
    5476                     case 5:
    5477                     case 13:
    5478                         if ((bRm & X86_MODRM_MOD_MASK) != 0)
    5479                         {
    5480                             if (!pVCpu->iem.s.uRexB)
    5481                             {
    5482                                 u64EffAddr += pVCpu->cpum.GstCtx.rbp;
    5483                                 SET_SS_DEF();
    5484                             }
    5485                             else
    5486                                 u64EffAddr += pVCpu->cpum.GstCtx.r13;
    5487                         }
    5488                         else
    5489                         {
    5490                             uint32_t u32Disp;
    5491                             IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5492                             u64EffAddr += (int32_t)u32Disp;
    5493                         }
    5494                         break;
    5495                     IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
    5496                 }
    5497                 break;
    5498             }
    5499             IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
    5500         }
    5501 
    5502         /* Get and add the displacement. */
    5503         switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5504         {
    5505             case 0:
    5506                 break;
    5507             case 1:
    5508             {
    5509                 int8_t i8Disp;
    5510                 IEM_OPCODE_GET_NEXT_S8(&i8Disp);
    5511                 u64EffAddr += i8Disp;
    5512                 break;
    5513             }
    5514             case 2:
    5515             {
    5516                 uint32_t u32Disp;
    5517                 IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5518                 u64EffAddr += (int32_t)u32Disp;
    5519                 break;
    5520             }
    5521             IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX); /* (caller checked for these) */
    5522         }
    5523 
    5524     }
    5525 
    5526     if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)
    5527     {
    5528         Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RGv\n", u64EffAddr));
    5529         return u64EffAddr;
    5530     }
    5531     Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5532     Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RGv\n", u64EffAddr & UINT32_MAX));
    5533     return u64EffAddr & UINT32_MAX;
    5534 }
    5535 #endif /* IEM_WITH_SETJMP */
    5536 
    5537 
    5538 /**
    5539  * Calculates the effective address of a ModR/M memory operand, extended version
    5540  * for use in the recompilers.
    5541  *
    5542  * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR.
    5543  *
    5544  * @return  Strict VBox status code.
    5545  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    5546  * @param   bRm                 The ModRM byte.
    5547  * @param   cbImmAndRspOffset   - First byte: The size of any immediate
    5548  *                                following the effective address opcode bytes
    5549  *                                (only for RIP relative addressing).
    5550  *                              - Second byte: RSP displacement (for POP [ESP]).
    5551  * @param   pGCPtrEff           Where to return the effective address.
    5552  * @param   puInfo              Extra info: 32-bit displacement (bits 31:0) and
    5553  *                              SIB byte (bits 39:32).
    5554  */
    5555 VBOXSTRICTRC iemOpHlpCalcRmEffAddrEx(PVMCPUCC pVCpu, uint8_t bRm, uint32_t cbImmAndRspOffset, PRTGCPTR pGCPtrEff, uint64_t *puInfo) RT_NOEXCEPT
    5556 {
    5557     Log5(("iemOpHlpCalcRmEffAddr: bRm=%#x\n", bRm));
    5558 # define SET_SS_DEF() \
    5559     do \
    5560     { \
    5561         if (!(pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SEG_MASK)) \
    5562             pVCpu->iem.s.iEffSeg = X86_SREG_SS; \
    5563     } while (0)
    5564 
    5565     uint64_t uInfo;
    5566     if (!IEM_IS_64BIT_CODE(pVCpu))
    5567     {
    5568 /** @todo Check the effective address size crap! */
    5569         if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_16BIT)
    5570         {
    5571             uint16_t u16EffAddr;
    5572 
    5573             /* Handle the disp16 form with no registers first. */
    5574             if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)
    5575             {
    5576                 IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);
    5577                 uInfo = u16EffAddr;
    5578             }
    5579             else
    5580             {
    5581                 /* Get the displacment. */
    5582                 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5583                 {
    5584                     case 0:  u16EffAddr = 0;                             break;
    5585                     case 1:  IEM_OPCODE_GET_NEXT_S8_SX_U16(&u16EffAddr); break;
    5586                     case 2:  IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);       break;
    5587                     default: AssertFailedReturn(VERR_IEM_IPE_1); /* (caller checked for these) */
    5588                 }
    5589                 uInfo = u16EffAddr;
    5590 
    5591                 /* Add the base and index registers to the disp. */
    5592                 switch (bRm & X86_MODRM_RM_MASK)
    5593                 {
    5594                     case 0: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.si; break;
    5595                     case 1: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.di; break;
    5596                     case 2: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.si; SET_SS_DEF(); break;
    5597                     case 3: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.di; SET_SS_DEF(); break;
    5598                     case 4: u16EffAddr += pVCpu->cpum.GstCtx.si;            break;
    5599                     case 5: u16EffAddr += pVCpu->cpum.GstCtx.di;            break;
    5600                     case 6: u16EffAddr += pVCpu->cpum.GstCtx.bp;            SET_SS_DEF(); break;
    5601                     case 7: u16EffAddr += pVCpu->cpum.GstCtx.bx;            break;
    5602                 }
    5603             }
    5604 
    5605             *pGCPtrEff = u16EffAddr;
    5606         }
    5607         else
    5608         {
    5609             Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5610             uint32_t u32EffAddr;
    5611 
    5612             /* Handle the disp32 form with no registers first. */
    5613             if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    5614             {
    5615                 IEM_OPCODE_GET_NEXT_U32(&u32EffAddr);
    5616                 uInfo = u32EffAddr;
    5617             }
    5618             else
    5619             {
    5620                 /* Get the register (or SIB) value. */
    5621                 uInfo = 0;
    5622                 switch ((bRm & X86_MODRM_RM_MASK))
    5623                 {
    5624                     case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    5625                     case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    5626                     case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    5627                     case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    5628                     case 4: /* SIB */
    5629                     {
    5630                         uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
    5631                         uInfo = (uint64_t)bSib << 32;
    5632 
    5633                         /* Get the index and scale it. */
    5634                         switch ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)
    5635                         {
    5636                             case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    5637                             case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    5638                             case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    5639                             case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    5640                             case 4: u32EffAddr = 0; /*none */ break;
    5641                             case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;
    5642                             case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    5643                             case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    5644                             IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5645                         }
    5646                         u32EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    5647 
    5648                         /* add base */
    5649                         switch (bSib & X86_SIB_BASE_MASK)
    5650                         {
    5651                             case 0: u32EffAddr += pVCpu->cpum.GstCtx.eax; break;
    5652                             case 1: u32EffAddr += pVCpu->cpum.GstCtx.ecx; break;
    5653                             case 2: u32EffAddr += pVCpu->cpum.GstCtx.edx; break;
    5654                             case 3: u32EffAddr += pVCpu->cpum.GstCtx.ebx; break;
    5655                             case 4: u32EffAddr += pVCpu->cpum.GstCtx.esp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
    5656                             case 5:
    5657                                 if ((bRm & X86_MODRM_MOD_MASK) != 0)
    5658                                 {
    5659                                     u32EffAddr += pVCpu->cpum.GstCtx.ebp;
    5660                                     SET_SS_DEF();
    5661                                 }
    5662                                 else
    5663                                 {
    5664                                     uint32_t u32Disp;
    5665                                     IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5666                                     u32EffAddr += u32Disp;
    5667                                     uInfo      |= u32Disp;
    5668                                 }
    5669                                 break;
    5670                             case 6: u32EffAddr += pVCpu->cpum.GstCtx.esi; break;
    5671                             case 7: u32EffAddr += pVCpu->cpum.GstCtx.edi; break;
    5672                             IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5673                         }
    5674                         break;
    5675                     }
    5676                     case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; SET_SS_DEF(); break;
    5677                     case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    5678                     case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    5679                     IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5680                 }
    5681 
    5682                 /* Get and add the displacement. */
    5683                 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5684                 {
    5685                     case 0:
    5686                         break;
    5687                     case 1:
    5688                     {
    5689                         int8_t i8Disp; IEM_OPCODE_GET_NEXT_S8(&i8Disp);
    5690                         u32EffAddr += i8Disp;
    5691                         uInfo |= (uint32_t)(int32_t)i8Disp;
    5692                         break;
    5693                     }
    5694                     case 2:
    5695                     {
    5696                         uint32_t u32Disp; IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5697                         u32EffAddr += u32Disp;
    5698                         uInfo      |= (uint32_t)u32Disp;
    5699                         break;
    5700                     }
    5701                     default:
    5702                         AssertFailedReturn(VERR_IEM_IPE_2); /* (caller checked for these) */
    5703                 }
    5704 
    5705             }
    5706             Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5707             *pGCPtrEff = u32EffAddr;
    5708         }
    5709     }
    5710     else
    5711     {
    5712         uint64_t u64EffAddr;
    5713 
    5714         /* Handle the rip+disp32 form with no registers first. */
    5715         if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    5716         {
    5717             IEM_OPCODE_GET_NEXT_S32_SX_U64(&u64EffAddr);
    5718             uInfo = (uint32_t)u64EffAddr;
    5719             u64EffAddr += pVCpu->cpum.GstCtx.rip + IEM_GET_INSTR_LEN(pVCpu) + (cbImmAndRspOffset & UINT32_C(0xff));
    5720         }
    5721         else
    5722         {
    5723             /* Get the register (or SIB) value. */
    5724             uInfo = 0;
    5725             switch ((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB)
    5726             {
    5727                 case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    5728                 case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    5729                 case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    5730                 case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    5731                 case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; SET_SS_DEF(); break;
    5732                 case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    5733                 case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    5734                 case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    5735                 case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    5736                 case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    5737                 case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    5738                 case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    5739                 case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    5740                 case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    5741                 /* SIB */
    5742                 case 4:
    5743                 case 12:
    5744                 {
    5745                     uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
    5746                     uInfo = (uint64_t)bSib << 32;
    5747 
    5748                     /* Get the index and scale it. */
    5749                     switch (((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) | pVCpu->iem.s.uRexIndex)
    5750                     {
    5751                         case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    5752                         case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    5753                         case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    5754                         case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    5755                         case  4: u64EffAddr = 0; /*none */ break;
    5756                         case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;
    5757                         case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    5758                         case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    5759                         case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    5760                         case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    5761                         case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    5762                         case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    5763                         case 12: u64EffAddr = pVCpu->cpum.GstCtx.r12; break;
    5764                         case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    5765                         case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    5766                         case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    5767                         IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5768                     }
    5769                     u64EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    5770 
    5771                     /* add base */
    5772                     switch ((bSib & X86_SIB_BASE_MASK) | pVCpu->iem.s.uRexB)
    5773                     {
    5774                         case  0: u64EffAddr += pVCpu->cpum.GstCtx.rax; break;
    5775                         case  1: u64EffAddr += pVCpu->cpum.GstCtx.rcx; break;
    5776                         case  2: u64EffAddr += pVCpu->cpum.GstCtx.rdx; break;
    5777                         case  3: u64EffAddr += pVCpu->cpum.GstCtx.rbx; break;
    5778                         case  4: u64EffAddr += pVCpu->cpum.GstCtx.rsp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
    5779                         case  6: u64EffAddr += pVCpu->cpum.GstCtx.rsi; break;
    5780                         case  7: u64EffAddr += pVCpu->cpum.GstCtx.rdi; break;
    5781                         case  8: u64EffAddr += pVCpu->cpum.GstCtx.r8;  break;
    5782                         case  9: u64EffAddr += pVCpu->cpum.GstCtx.r9;  break;
    5783                         case 10: u64EffAddr += pVCpu->cpum.GstCtx.r10; break;
    5784                         case 11: u64EffAddr += pVCpu->cpum.GstCtx.r11; break;
    5785                         case 12: u64EffAddr += pVCpu->cpum.GstCtx.r12; break;
    5786                         case 14: u64EffAddr += pVCpu->cpum.GstCtx.r14; break;
    5787                         case 15: u64EffAddr += pVCpu->cpum.GstCtx.r15; break;
    5788                         /* complicated encodings */
    5789                         case 5:
    5790                         case 13:
    5791                             if ((bRm & X86_MODRM_MOD_MASK) != 0)
    5792                             {
    5793                                 if (!pVCpu->iem.s.uRexB)
    5794                                 {
    5795                                     u64EffAddr += pVCpu->cpum.GstCtx.rbp;
    5796                                     SET_SS_DEF();
    5797                                 }
    5798                                 else
    5799                                     u64EffAddr += pVCpu->cpum.GstCtx.r13;
    5800                             }
    5801                             else
    5802                             {
    5803                                 uint32_t u32Disp;
    5804                                 IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5805                                 u64EffAddr += (int32_t)u32Disp;
    5806                                 uInfo      |= u32Disp;
    5807                             }
    5808                             break;
    5809                         IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5810                     }
    5811                     break;
    5812                 }
    5813                 IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5814             }
    5815 
    5816             /* Get and add the displacement. */
    5817             switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5818             {
    5819                 case 0:
    5820                     break;
    5821                 case 1:
    5822                 {
    5823                     int8_t i8Disp;
    5824                     IEM_OPCODE_GET_NEXT_S8(&i8Disp);
    5825                     u64EffAddr += i8Disp;
    5826                     uInfo      |= (uint32_t)(int32_t)i8Disp;
    5827                     break;
    5828                 }
    5829                 case 2:
    5830                 {
    5831                     uint32_t u32Disp;
    5832                     IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5833                     u64EffAddr += (int32_t)u32Disp;
    5834                     uInfo      |= u32Disp;
    5835                     break;
    5836                 }
    5837                 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* (caller checked for these) */
    5838             }
    5839 
    5840         }
    5841 
    5842         if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)
    5843             *pGCPtrEff = u64EffAddr;
    5844         else
    5845         {
    5846             Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5847             *pGCPtrEff = u64EffAddr & UINT32_MAX;
    5848         }
    5849     }
    5850     *puInfo = uInfo;
    5851 
    5852     Log5(("iemOpHlpCalcRmEffAddrEx: EffAddr=%#010RGv uInfo=%RX64\n", *pGCPtrEff, uInfo));
    5853     return VINF_SUCCESS;
    5854 }
    5855 
    5856 /** @}  */
    5857 
    5858 
    5859 #ifdef LOG_ENABLED
    5860 /**
    5861  * Logs the current instruction.
    5862  * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
    5863  * @param   fSameCtx    Set if we have the same context information as the VMM,
    5864  *                      clear if we may have already executed an instruction in
    5865  *                      our debug context. When clear, we assume IEMCPU holds
    5866  *                      valid CPU mode info.
    5867  *
    5868  *                      The @a fSameCtx parameter is now misleading and obsolete.
    5869  * @param   pszFunction The IEM function doing the execution.
    5870  */
    5871 static void iemLogCurInstr(PVMCPUCC pVCpu, bool fSameCtx, const char *pszFunction) RT_NOEXCEPT
    5872 {
    5873 # ifdef IN_RING3
    5874     if (LogIs2Enabled())
    5875     {
    5876         char     szInstr[256];
    5877         uint32_t cbInstr = 0;
    5878         if (fSameCtx)
    5879             DBGFR3DisasInstrEx(pVCpu->pVMR3->pUVM, pVCpu->idCpu, 0, 0,
    5880                                DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_DEFAULT_MODE,
    5881                                szInstr, sizeof(szInstr), &cbInstr);
    5882         else
    5883         {
    5884             uint32_t fFlags = 0;
    5885             switch (IEM_GET_CPU_MODE(pVCpu))
    5886             {
    5887                 case IEMMODE_64BIT: fFlags |= DBGF_DISAS_FLAGS_64BIT_MODE; break;
    5888                 case IEMMODE_32BIT: fFlags |= DBGF_DISAS_FLAGS_32BIT_MODE; break;
    5889                 case IEMMODE_16BIT:
    5890                     if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE) || pVCpu->cpum.GstCtx.eflags.Bits.u1VM)
    5891                         fFlags |= DBGF_DISAS_FLAGS_16BIT_REAL_MODE;
    5892                     else
    5893                         fFlags |= DBGF_DISAS_FLAGS_16BIT_MODE;
    5894                     break;
    5895             }
    5896             DBGFR3DisasInstrEx(pVCpu->pVMR3->pUVM, pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, fFlags,
    5897                                szInstr, sizeof(szInstr), &cbInstr);
    5898         }
    5899 
    5900         PCX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
    5901         Log2(("**** %s fExec=%x\n"
    5902               " eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n"
    5903               " eip=%08x esp=%08x ebp=%08x iopl=%d tr=%04x\n"
    5904               " cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x efl=%08x\n"
    5905               " fsw=%04x fcw=%04x ftw=%02x mxcsr=%04x/%04x\n"
    5906               " %s\n"
    5907               , pszFunction, pVCpu->iem.s.fExec,
    5908               pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ebx, pVCpu->cpum.GstCtx.ecx, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.esi, pVCpu->cpum.GstCtx.edi,
    5909               pVCpu->cpum.GstCtx.eip, pVCpu->cpum.GstCtx.esp, pVCpu->cpum.GstCtx.ebp, pVCpu->cpum.GstCtx.eflags.Bits.u2IOPL, pVCpu->cpum.GstCtx.tr.Sel,
    5910               pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.ds.Sel, pVCpu->cpum.GstCtx.es.Sel,
    5911               pVCpu->cpum.GstCtx.fs.Sel, pVCpu->cpum.GstCtx.gs.Sel, pVCpu->cpum.GstCtx.eflags.u,
    5912               pFpuCtx->FSW, pFpuCtx->FCW, pFpuCtx->FTW, pFpuCtx->MXCSR, pFpuCtx->MXCSR_MASK,
    5913               szInstr));
    5914 
    5915         /* This stuff sucks atm. as it fills the log with MSRs. */
    5916         //if (LogIs3Enabled())
    5917         //    DBGFR3InfoEx(pVCpu->pVMR3->pUVM, pVCpu->idCpu, "cpumguest", "verbose", NULL);
    5918     }
    5919     else
    5920 # endif
    5921         LogFlow(("%s: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x\n", pszFunction, pVCpu->cpum.GstCtx.cs.Sel,
    5922                  pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u));
    5923     RT_NOREF_PV(pVCpu); RT_NOREF_PV(fSameCtx);
    5924 }
    5925 #endif /* LOG_ENABLED */
    5926 
    5927 
    5928 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    5929 /**
    5930  * Deals with VMCPU_FF_VMX_APIC_WRITE, VMCPU_FF_VMX_MTF, VMCPU_FF_VMX_NMI_WINDOW,
    5931  * VMCPU_FF_VMX_PREEMPT_TIMER and VMCPU_FF_VMX_INT_WINDOW.
    5932  *
    5933  * @returns Modified rcStrict.
    5934  * @param   pVCpu       The cross context virtual CPU structure of the calling thread.
    5935  * @param   rcStrict    The instruction execution status.
    5936  */
    5937 static VBOXSTRICTRC iemHandleNestedInstructionBoundaryFFs(PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict) RT_NOEXCEPT
    5938 {
    5939     Assert(CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu)));
    5940     if (!VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF))
    5941     {
    5942         /* VMX preemption timer takes priority over NMI-window exits. */
    5943         if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER))
    5944         {
    5945             rcStrict = iemVmxVmexitPreemptTimer(pVCpu);
    5946             Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER));
    5947         }
    5948         /*
    5949          * Check remaining intercepts.
    5950          *
    5951          * NMI-window and Interrupt-window VM-exits.
    5952          * Interrupt shadow (block-by-STI and Mov SS) inhibits interrupts and may also block NMIs.
    5953          * Event injection during VM-entry takes priority over NMI-window and interrupt-window VM-exits.
    5954          *
    5955          * See Intel spec. 26.7.6 "NMI-Window Exiting".
    5956          * See Intel spec. 26.7.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
    5957          */
    5958         else if (   VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW | VMCPU_FF_VMX_INT_WINDOW)
    5959                  && !CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)
    5960                  && !TRPMHasTrap(pVCpu))
    5961         {
    5962             Assert(CPUMIsGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx));
    5963             if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW)
    5964                 && CPUMIsGuestVmxVirtNmiBlocking(&pVCpu->cpum.GstCtx))
    5965             {
    5966                 rcStrict = iemVmxVmexit(pVCpu, VMX_EXIT_NMI_WINDOW, 0 /* u64ExitQual */);
    5967                 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW));
    5968             }
    5969             else if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW)
    5970                      && CPUMIsGuestVmxVirtIntrEnabled(&pVCpu->cpum.GstCtx))
    5971             {
    5972                 rcStrict = iemVmxVmexit(pVCpu, VMX_EXIT_INT_WINDOW, 0 /* u64ExitQual */);
    5973                 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW));
    5974             }
    5975         }
    5976     }
    5977     /* TPR-below threshold/APIC write has the highest priority. */
    5978     else  if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
    5979     {
    5980         rcStrict = iemVmxApicWriteEmulation(pVCpu);
    5981         Assert(!CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx));
    5982         Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE));
    5983     }
    5984     /* MTF takes priority over VMX-preemption timer. */
    5985     else
    5986     {
    5987         rcStrict = iemVmxVmexit(pVCpu, VMX_EXIT_MTF, 0 /* u64ExitQual */);
    5988         Assert(!CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx));
    5989         Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF));
    5990     }
    5991     return rcStrict;
    5992 }
    5993 #endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
    5994 
    5995 
    5996 /**
    5997  * The actual code execution bits of IEMExecOne, IEMExecOneWithPrefetchedByPC,
    5998  * IEMExecOneBypass and friends.
    5999  *
    6000  * Similar code is found in IEMExecLots.
    6001  *
    6002  * @return  Strict VBox status code.
    6003  * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
    6004  * @param   fExecuteInhibit     If set, execute the instruction following CLI,
    6005  *                      POP SS and MOV SS,GR.
    6006  * @param   pszFunction The calling function name.
    6007  */
    6008 DECLINLINE(VBOXSTRICTRC) iemExecOneInner(PVMCPUCC pVCpu, bool fExecuteInhibit, const char *pszFunction)
    6009 {
    6010     AssertMsg(pVCpu->iem.s.aMemMappings[0].fAccess == IEM_ACCESS_INVALID, ("0: %#x %RGp\n", pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemBbMappings[0].GCPhysFirst));
    6011     AssertMsg(pVCpu->iem.s.aMemMappings[1].fAccess == IEM_ACCESS_INVALID, ("1: %#x %RGp\n", pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemBbMappings[1].GCPhysFirst));
    6012     AssertMsg(pVCpu->iem.s.aMemMappings[2].fAccess == IEM_ACCESS_INVALID, ("2: %#x %RGp\n", pVCpu->iem.s.aMemMappings[2].fAccess, pVCpu->iem.s.aMemBbMappings[2].GCPhysFirst));
    6013     RT_NOREF_PV(pszFunction);
    6014 
    6015 #ifdef IEM_WITH_SETJMP
    6016     VBOXSTRICTRC rcStrict;
    6017     IEM_TRY_SETJMP(pVCpu, rcStrict)
    6018     {
    6019         uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);
    6020         rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);
    6021     }
    6022     IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);
    6023     {
    6024         pVCpu->iem.s.cLongJumps++;
    6025     }
    6026     IEM_CATCH_LONGJMP_END(pVCpu);
    6027 #else
    6028     uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);
    6029     VBOXSTRICTRC rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);
    6030 #endif
    6031     if (rcStrict == VINF_SUCCESS)
    6032         pVCpu->iem.s.cInstructions++;
    6033     if (pVCpu->iem.s.cActiveMappings > 0)
    6034     {
    6035         Assert(rcStrict != VINF_SUCCESS);
    6036         iemMemRollback(pVCpu);
    6037     }
    6038     AssertMsg(pVCpu->iem.s.aMemMappings[0].fAccess == IEM_ACCESS_INVALID, ("0: %#x %RGp\n", pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemBbMappings[0].GCPhysFirst));
    6039     AssertMsg(pVCpu->iem.s.aMemMappings[1].fAccess == IEM_ACCESS_INVALID, ("1: %#x %RGp\n", pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemBbMappings[1].GCPhysFirst));
    6040     AssertMsg(pVCpu->iem.s.aMemMappings[2].fAccess == IEM_ACCESS_INVALID, ("2: %#x %RGp\n", pVCpu->iem.s.aMemMappings[2].fAccess, pVCpu->iem.s.aMemBbMappings[2].GCPhysFirst));
    6041 
    6042 //#ifdef DEBUG
    6043 //    AssertMsg(IEM_GET_INSTR_LEN(pVCpu) == cbInstr || rcStrict != VINF_SUCCESS, ("%u %u\n", IEM_GET_INSTR_LEN(pVCpu), cbInstr));
    6044 //#endif
    6045 
    6046 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    6047     /*
    6048      * Perform any VMX nested-guest instruction boundary actions.
    6049      *
    6050      * If any of these causes a VM-exit, we must skip executing the next
    6051      * instruction (would run into stale page tables). A VM-exit makes sure
    6052      * there is no interrupt-inhibition, so that should ensure we don't go
    6053      * to try execute the next instruction. Clearing fExecuteInhibit is
    6054      * problematic because of the setjmp/longjmp clobbering above.
    6055      */
    6056     if (   !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER
    6057                                      | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW)
    6058         || rcStrict != VINF_SUCCESS)
    6059     { /* likely */ }
    6060     else
    6061         rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);
    6062 #endif
    6063 
    6064     /* Execute the next instruction as well if a cli, pop ss or
    6065        mov ss, Gr has just completed successfully. */
    6066     if (   fExecuteInhibit
    6067         && rcStrict == VINF_SUCCESS
    6068         && CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx))
    6069     {
    6070         rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, pVCpu->iem.s.fExec & (IEM_F_BYPASS_HANDLERS | IEM_F_X86_DISREGARD_LOCK));
    6071         if (rcStrict == VINF_SUCCESS)
    6072         {
    6073 #ifdef LOG_ENABLED
    6074             iemLogCurInstr(pVCpu, false, pszFunction);
    6075 #endif
    6076 #ifdef IEM_WITH_SETJMP
    6077             IEM_TRY_SETJMP_AGAIN(pVCpu, rcStrict)
    6078             {
    6079                 uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);
    6080                 rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);
    6081             }
    6082             IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);
    6083             {
    6084                 pVCpu->iem.s.cLongJumps++;
    6085             }
    6086             IEM_CATCH_LONGJMP_END(pVCpu);
    6087 #else
    6088             IEM_OPCODE_GET_FIRST_U8(&b);
    6089             rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);
    6090 #endif
    6091             if (rcStrict == VINF_SUCCESS)
    6092             {
    6093                 pVCpu->iem.s.cInstructions++;
    6094 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    6095                 if (!VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER
    6096                                               | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW))
    6097                 { /* likely */ }
    6098                 else
    6099                     rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);
    6100 #endif
    6101             }
    6102             if (pVCpu->iem.s.cActiveMappings > 0)
    6103             {
    6104                 Assert(rcStrict != VINF_SUCCESS);
    6105                 iemMemRollback(pVCpu);
    6106             }
    6107             AssertMsg(pVCpu->iem.s.aMemMappings[0].fAccess == IEM_ACCESS_INVALID, ("0: %#x %RGp\n", pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemBbMappings[0].GCPhysFirst));
    6108             AssertMsg(pVCpu->iem.s.aMemMappings[1].fAccess == IEM_ACCESS_INVALID, ("1: %#x %RGp\n", pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemBbMappings[1].GCPhysFirst));
    6109             AssertMsg(pVCpu->iem.s.aMemMappings[2].fAccess == IEM_ACCESS_INVALID, ("2: %#x %RGp\n", pVCpu->iem.s.aMemMappings[2].fAccess, pVCpu->iem.s.aMemBbMappings[2].GCPhysFirst));
    6110         }
    6111         else if (pVCpu->iem.s.cActiveMappings > 0)
    6112             iemMemRollback(pVCpu);
    6113         /** @todo drop this after we bake this change into RIP advancing. */
    6114         CPUMClearInterruptShadow(&pVCpu->cpum.GstCtx); /* hope this is correct for all exceptional cases... */
    6115     }
    6116 
    6117     /*
    6118      * Return value fiddling, statistics and sanity assertions.
    6119      */
    6120     rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6121 
    6122     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));
    6123     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
    6124     return rcStrict;
    6125 }
    6126 
    6127 
    6128 /**
    6129  * Execute one instruction.
    6130  *
    6131  * @return  Strict VBox status code.
    6132  * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
    6133  */
    6134 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOne(PVMCPUCC pVCpu)
    6135 {
    6136     AssertCompile(sizeof(pVCpu->iem.s) <= sizeof(pVCpu->iem.padding)); /* (tstVMStruct can't do it's job w/o instruction stats) */
    6137 #ifdef LOG_ENABLED
    6138     iemLogCurInstr(pVCpu, true, "IEMExecOne");
    6139 #endif
    6140 
    6141     /*
    6142      * Do the decoding and emulation.
    6143      */
    6144     VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, 0 /*fExecOpts*/);
    6145     if (rcStrict == VINF_SUCCESS)
    6146         rcStrict = iemExecOneInner(pVCpu, true, "IEMExecOne");
    6147     else if (pVCpu->iem.s.cActiveMappings > 0)
    6148         iemMemRollback(pVCpu);
    6149 
    6150     if (rcStrict != VINF_SUCCESS)
    6151         LogFlow(("IEMExecOne: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc\n",
    6152                  pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict)));
    6153     return rcStrict;
    6154 }
    6155 
    6156 
    6157 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOneWithPrefetchedByPC(PVMCPUCC pVCpu, uint64_t OpcodeBytesPC,
    6158                                                         const void *pvOpcodeBytes, size_t cbOpcodeBytes)
    6159 {
    6160     VBOXSTRICTRC rcStrict;
    6161     if (   cbOpcodeBytes
    6162         && pVCpu->cpum.GstCtx.rip == OpcodeBytesPC)
    6163     {
    6164         iemInitDecoder(pVCpu, 0 /*fExecOpts*/);
    6165 #ifdef IEM_WITH_CODE_TLB
    6166         pVCpu->iem.s.uInstrBufPc      = OpcodeBytesPC;
    6167         pVCpu->iem.s.pbInstrBuf       = (uint8_t const *)pvOpcodeBytes;
    6168         pVCpu->iem.s.cbInstrBufTotal  = (uint16_t)RT_MIN(X86_PAGE_SIZE, cbOpcodeBytes);
    6169         pVCpu->iem.s.offCurInstrStart = 0;
    6170         pVCpu->iem.s.offInstrNextByte = 0;
    6171         pVCpu->iem.s.GCPhysInstrBuf   = NIL_RTGCPHYS;
    6172 #else
    6173         pVCpu->iem.s.cbOpcode = (uint8_t)RT_MIN(cbOpcodeBytes, sizeof(pVCpu->iem.s.abOpcode));
    6174         memcpy(pVCpu->iem.s.abOpcode, pvOpcodeBytes, pVCpu->iem.s.cbOpcode);
    6175 #endif
    6176         rcStrict = VINF_SUCCESS;
    6177     }
    6178     else
    6179         rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, 0 /*fExecOpts*/);
    6180     if (rcStrict == VINF_SUCCESS)
    6181         rcStrict = iemExecOneInner(pVCpu, true, "IEMExecOneWithPrefetchedByPC");
    6182     else if (pVCpu->iem.s.cActiveMappings > 0)
    6183         iemMemRollback(pVCpu);
    6184 
    6185     return rcStrict;
    6186 }
    6187 
    6188 
    6189 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOneBypass(PVMCPUCC pVCpu)
    6190 {
    6191     VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, IEM_F_BYPASS_HANDLERS);
    6192     if (rcStrict == VINF_SUCCESS)
    6193         rcStrict = iemExecOneInner(pVCpu, false, "IEMExecOneBypass");
    6194     else if (pVCpu->iem.s.cActiveMappings > 0)
    6195         iemMemRollback(pVCpu);
    6196 
    6197     return rcStrict;
    6198 }
    6199 
    6200 
    6201 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOneBypassWithPrefetchedByPC(PVMCPUCC pVCpu, uint64_t OpcodeBytesPC,
    6202                                                               const void *pvOpcodeBytes, size_t cbOpcodeBytes)
    6203 {
    6204     VBOXSTRICTRC rcStrict;
    6205     if (   cbOpcodeBytes
    6206         && pVCpu->cpum.GstCtx.rip == OpcodeBytesPC)
    6207     {
    6208         iemInitDecoder(pVCpu, IEM_F_BYPASS_HANDLERS);
    6209 #ifdef IEM_WITH_CODE_TLB
    6210         pVCpu->iem.s.uInstrBufPc      = OpcodeBytesPC;
    6211         pVCpu->iem.s.pbInstrBuf       = (uint8_t const *)pvOpcodeBytes;
    6212         pVCpu->iem.s.cbInstrBufTotal  = (uint16_t)RT_MIN(X86_PAGE_SIZE, cbOpcodeBytes);
    6213         pVCpu->iem.s.offCurInstrStart = 0;
    6214         pVCpu->iem.s.offInstrNextByte = 0;
    6215         pVCpu->iem.s.GCPhysInstrBuf   = NIL_RTGCPHYS;
    6216 #else
    6217         pVCpu->iem.s.cbOpcode = (uint8_t)RT_MIN(cbOpcodeBytes, sizeof(pVCpu->iem.s.abOpcode));
    6218         memcpy(pVCpu->iem.s.abOpcode, pvOpcodeBytes, pVCpu->iem.s.cbOpcode);
    6219 #endif
    6220         rcStrict = VINF_SUCCESS;
    6221     }
    6222     else
    6223         rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, IEM_F_BYPASS_HANDLERS);
    6224     if (rcStrict == VINF_SUCCESS)
    6225         rcStrict = iemExecOneInner(pVCpu, false, "IEMExecOneBypassWithPrefetchedByPC");
    6226     else if (pVCpu->iem.s.cActiveMappings > 0)
    6227         iemMemRollback(pVCpu);
    6228 
    6229     return rcStrict;
    6230 }
    6231 
    6232 
    6233 /**
    6234  * For handling split cacheline lock operations when the host has split-lock
    6235  * detection enabled.
    6236  *
    6237  * This will cause the interpreter to disregard the lock prefix and implicit
    6238  * locking (xchg).
    6239  *
    6240  * @returns Strict VBox status code.
    6241  * @param   pVCpu   The cross context virtual CPU structure of the calling EMT.
    6242  */
    6243 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOneIgnoreLock(PVMCPUCC pVCpu)
    6244 {
    6245     /*
    6246      * Do the decoding and emulation.
    6247      */
    6248     VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, IEM_F_X86_DISREGARD_LOCK);
    6249     if (rcStrict == VINF_SUCCESS)
    6250         rcStrict = iemExecOneInner(pVCpu, true, "IEMExecOneIgnoreLock");
    6251     else if (pVCpu->iem.s.cActiveMappings > 0)
    6252         iemMemRollback(pVCpu);
    6253 
    6254     if (rcStrict != VINF_SUCCESS)
    6255         LogFlow(("IEMExecOneIgnoreLock: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc\n",
    6256                  pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict)));
    6257     return rcStrict;
    6258 }
    6259 
    6260 
    6261 /**
    6262  * Code common to IEMExecLots and IEMExecRecompilerThreaded that attempts to
    6263  * inject a pending TRPM trap.
    6264  */
    6265 VBOXSTRICTRC iemExecInjectPendingTrap(PVMCPUCC pVCpu)
    6266 {
    6267     Assert(TRPMHasTrap(pVCpu));
    6268 
    6269     if (   !CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)
    6270         && !CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx))
    6271     {
    6272         /** @todo Can we centralize this under CPUMCanInjectInterrupt()? */
    6273 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
    6274         bool fIntrEnabled = CPUMGetGuestGif(&pVCpu->cpum.GstCtx);
    6275         if (fIntrEnabled)
    6276         {
    6277             if (!CPUMIsGuestInNestedHwvirtMode(IEM_GET_CTX(pVCpu)))
    6278                 fIntrEnabled = pVCpu->cpum.GstCtx.eflags.Bits.u1IF;
    6279             else if (CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu)))
    6280                 fIntrEnabled = CPUMIsGuestVmxPhysIntrEnabled(IEM_GET_CTX(pVCpu));
    6281             else
    6282             {
    6283                 Assert(CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)));
    6284                 fIntrEnabled = CPUMIsGuestSvmPhysIntrEnabled(pVCpu, IEM_GET_CTX(pVCpu));
    6285             }
    6286         }
    6287 #else
    6288         bool fIntrEnabled = pVCpu->cpum.GstCtx.eflags.Bits.u1IF;
    6289 #endif
    6290         if (fIntrEnabled)
    6291         {
    6292             uint8_t     u8TrapNo;
    6293             TRPMEVENT   enmType;
    6294             uint32_t    uErrCode;
    6295             RTGCPTR     uCr2;
    6296             int rc2 = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrCode, &uCr2, NULL /*pu8InstLen*/, NULL /*fIcebp*/);
    6297             AssertRC(rc2);
    6298             Assert(enmType == TRPM_HARDWARE_INT);
    6299             VBOXSTRICTRC rcStrict = IEMInjectTrap(pVCpu, u8TrapNo, enmType, (uint16_t)uErrCode, uCr2, 0 /*cbInstr*/);
    6300 
    6301             TRPMResetTrap(pVCpu);
    6302 
    6303 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
    6304             /* Injecting an event may cause a VM-exit. */
    6305             if (   rcStrict != VINF_SUCCESS
    6306                 && rcStrict != VINF_IEM_RAISED_XCPT)
    6307                 return iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6308 #else
    6309             NOREF(rcStrict);
    6310 #endif
    6311         }
    6312     }
    6313 
    6314     return VINF_SUCCESS;
    6315 }
    6316 
    6317 
    6318 VMM_INT_DECL(VBOXSTRICTRC) IEMExecLots(PVMCPUCC pVCpu, uint32_t cMaxInstructions, uint32_t cPollRate, uint32_t *pcInstructions)
    6319 {
    6320     uint32_t const cInstructionsAtStart = pVCpu->iem.s.cInstructions;
    6321     AssertMsg(RT_IS_POWER_OF_TWO(cPollRate + 1), ("%#x\n", cPollRate));
    6322     Assert(cMaxInstructions > 0);
    6323 
    6324     /*
    6325      * See if there is an interrupt pending in TRPM, inject it if we can.
    6326      */
    6327     /** @todo What if we are injecting an exception and not an interrupt? Is that
    6328      *        possible here? For now we assert it is indeed only an interrupt. */
    6329     if (!TRPMHasTrap(pVCpu))
    6330     { /* likely */ }
    6331     else
    6332     {
    6333         VBOXSTRICTRC rcStrict = iemExecInjectPendingTrap(pVCpu);
    6334         if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    6335         { /*likely */ }
    6336         else
    6337             return rcStrict;
    6338     }
    6339 
    6340     /*
    6341      * Initial decoder init w/ prefetch, then setup setjmp.
    6342      */
    6343     VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, 0 /*fExecOpts*/);
    6344     if (rcStrict == VINF_SUCCESS)
    6345     {
    6346 #ifdef IEM_WITH_SETJMP
    6347         pVCpu->iem.s.cActiveMappings = 0; /** @todo wtf? */
    6348         IEM_TRY_SETJMP(pVCpu, rcStrict)
    6349 #endif
    6350         {
    6351             /*
    6352              * The run loop.  We limit ourselves to 4096 instructions right now.
    6353              */
    6354             uint32_t cMaxInstructionsGccStupidity = cMaxInstructions;
    6355             PVMCC pVM = pVCpu->CTX_SUFF(pVM);
    6356             for (;;)
    6357             {
    6358                 /*
    6359                  * Log the state.
    6360                  */
    6361 #ifdef LOG_ENABLED
    6362                 iemLogCurInstr(pVCpu, true, "IEMExecLots");
    6363 #endif
    6364 
    6365                 /*
    6366                  * Do the decoding and emulation.
    6367                  */
    6368                 uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);
    6369                 rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);
    6370 #ifdef VBOX_STRICT
    6371                 CPUMAssertGuestRFlagsCookie(pVM, pVCpu);
    6372 #endif
    6373                 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    6374                 {
    6375                     Assert(pVCpu->iem.s.cActiveMappings == 0);
    6376                     pVCpu->iem.s.cInstructions++;
    6377 
    6378 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    6379                     /* Perform any VMX nested-guest instruction boundary actions. */
    6380                     uint64_t fCpu = pVCpu->fLocalForcedActions;
    6381                     if (!(fCpu & (  VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER
    6382                                   | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW)))
    6383                     { /* likely */ }
    6384                     else
    6385                     {
    6386                         rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);
    6387                         if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    6388                             fCpu = pVCpu->fLocalForcedActions;
    6389                         else
    6390                         {
    6391                             rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6392                             break;
    6393                         }
    6394                     }
    6395 #endif
    6396                     if (RT_LIKELY(pVCpu->iem.s.rcPassUp == VINF_SUCCESS))
    6397                     {
    6398 #ifndef VBOX_WITH_NESTED_HWVIRT_VMX
    6399                         uint64_t fCpu = pVCpu->fLocalForcedActions;
    6400 #endif
    6401                         fCpu &= VMCPU_FF_ALL_MASK & ~(  VMCPU_FF_PGM_SYNC_CR3
    6402                                                       | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
    6403                                                       | VMCPU_FF_TLB_FLUSH
    6404                                                       | VMCPU_FF_UNHALT );
    6405 
    6406                         if (RT_LIKELY(   (   !fCpu
    6407                                           || (   !(fCpu & ~(VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
    6408                                               && !pVCpu->cpum.GstCtx.rflags.Bits.u1IF) )
    6409                                       && !VM_FF_IS_ANY_SET(pVM, VM_FF_ALL_MASK) ))
    6410                         {
    6411                             if (--cMaxInstructionsGccStupidity > 0)
    6412                             {
    6413                                 /* Poll timers every now an then according to the caller's specs. */
    6414                                 if (   (cMaxInstructionsGccStupidity & cPollRate) != 0
    6415                                     || !TMTimerPollBool(pVM, pVCpu))
    6416                                 {
    6417                                     Assert(pVCpu->iem.s.cActiveMappings == 0);
    6418                                     iemReInitDecoder(pVCpu);
    6419                                     continue;
    6420                                 }
    6421                             }
    6422                         }
    6423                     }
    6424                     Assert(pVCpu->iem.s.cActiveMappings == 0);
    6425                 }
    6426                 else if (pVCpu->iem.s.cActiveMappings > 0)
    6427                     iemMemRollback(pVCpu);
    6428                 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6429                 break;
    6430             }
    6431         }
    6432 #ifdef IEM_WITH_SETJMP
    6433         IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);
    6434         {
    6435             if (pVCpu->iem.s.cActiveMappings > 0)
    6436                 iemMemRollback(pVCpu);
    6437 # if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
    6438             rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6439 # endif
    6440             pVCpu->iem.s.cLongJumps++;
    6441         }
    6442         IEM_CATCH_LONGJMP_END(pVCpu);
    6443 #endif
    6444 
    6445         /*
    6446          * Assert hidden register sanity (also done in iemInitDecoder and iemReInitDecoder).
    6447          */
    6448         Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));
    6449         Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
    6450     }
    6451     else
    6452     {
    6453         if (pVCpu->iem.s.cActiveMappings > 0)
    6454             iemMemRollback(pVCpu);
    6455 
    6456 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
    6457         /*
    6458          * When a nested-guest causes an exception intercept (e.g. #PF) when fetching
    6459          * code as part of instruction execution, we need this to fix-up VINF_SVM_VMEXIT.
    6460          */
    6461         rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6462 #endif
    6463     }
    6464 
    6465     /*
    6466      * Maybe re-enter raw-mode and log.
    6467      */
    6468     if (rcStrict != VINF_SUCCESS)
    6469         LogFlow(("IEMExecLots: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc\n",
    6470                  pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict)));
    6471     if (pcInstructions)
    6472         *pcInstructions = pVCpu->iem.s.cInstructions - cInstructionsAtStart;
    6473     return rcStrict;
    6474 }
    6475 
    6476 
    6477 /**
    6478  * Interface used by EMExecuteExec, does exit statistics and limits.
    6479  *
    6480  * @returns Strict VBox status code.
    6481  * @param   pVCpu               The cross context virtual CPU structure.
    6482  * @param   fWillExit           To be defined.
    6483  * @param   cMinInstructions    Minimum number of instructions to execute before checking for FFs.
    6484  * @param   cMaxInstructions    Maximum number of instructions to execute.
    6485  * @param   cMaxInstructionsWithoutExits
    6486  *                              The max number of instructions without exits.
    6487  * @param   pStats              Where to return statistics.
    6488  */
    6489 VMM_INT_DECL(VBOXSTRICTRC)
    6490 IEMExecForExits(PVMCPUCC pVCpu, uint32_t fWillExit, uint32_t cMinInstructions, uint32_t cMaxInstructions,
    6491                 uint32_t cMaxInstructionsWithoutExits, PIEMEXECFOREXITSTATS pStats)
    6492 {
    6493     NOREF(fWillExit); /** @todo define flexible exit crits */
    6494 
    6495     /*
    6496      * Initialize return stats.
    6497      */
    6498     pStats->cInstructions    = 0;
    6499     pStats->cExits           = 0;
    6500     pStats->cMaxExitDistance = 0;
    6501     pStats->cReserved        = 0;
    6502 
    6503     /*
    6504      * Initial decoder init w/ prefetch, then setup setjmp.
    6505      */
    6506     VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, 0 /*fExecOpts*/);
    6507     if (rcStrict == VINF_SUCCESS)
    6508     {
    6509 #ifdef IEM_WITH_SETJMP
    6510         pVCpu->iem.s.cActiveMappings     = 0; /** @todo wtf?!? */
    6511         IEM_TRY_SETJMP(pVCpu, rcStrict)
    6512 #endif
    6513         {
    6514 #ifdef IN_RING0
    6515             bool const fCheckPreemptionPending   = !RTThreadPreemptIsPossible() || !RTThreadPreemptIsEnabled(NIL_RTTHREAD);
    6516 #endif
    6517             uint32_t   cInstructionSinceLastExit = 0;
    6518 
    6519             /*
    6520              * The run loop.  We limit ourselves to 4096 instructions right now.
    6521              */
    6522             PVM pVM = pVCpu->CTX_SUFF(pVM);
    6523             for (;;)
    6524             {
    6525                 /*
    6526                  * Log the state.
    6527                  */
    6528 #ifdef LOG_ENABLED
    6529                 iemLogCurInstr(pVCpu, true, "IEMExecForExits");
    6530 #endif
    6531 
    6532                 /*
    6533                  * Do the decoding and emulation.
    6534                  */
    6535                 uint32_t const cPotentialExits = pVCpu->iem.s.cPotentialExits;
    6536 
    6537                 uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);
    6538                 rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);
    6539 
    6540                 if (   cPotentialExits != pVCpu->iem.s.cPotentialExits
    6541                     && cInstructionSinceLastExit > 0 /* don't count the first */ )
    6542                 {
    6543                     pStats->cExits += 1;
    6544                     if (cInstructionSinceLastExit > pStats->cMaxExitDistance)
    6545                         pStats->cMaxExitDistance = cInstructionSinceLastExit;
    6546                     cInstructionSinceLastExit = 0;
    6547                 }
    6548 
    6549                 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    6550                 {
    6551                     Assert(pVCpu->iem.s.cActiveMappings == 0);
    6552                     pVCpu->iem.s.cInstructions++;
    6553                     pStats->cInstructions++;
    6554                     cInstructionSinceLastExit++;
    6555 
    6556 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    6557                     /* Perform any VMX nested-guest instruction boundary actions. */
    6558                     uint64_t fCpu = pVCpu->fLocalForcedActions;
    6559                     if (!(fCpu & (  VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER
    6560                                   | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW)))
    6561                     { /* likely */ }
    6562                     else
    6563                     {
    6564                         rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);
    6565                         if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    6566                             fCpu = pVCpu->fLocalForcedActions;
    6567                         else
    6568                         {
    6569                             rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6570                             break;
    6571                         }
    6572                     }
    6573 #endif
    6574                     if (RT_LIKELY(pVCpu->iem.s.rcPassUp == VINF_SUCCESS))
    6575                     {
    6576 #ifndef VBOX_WITH_NESTED_HWVIRT_VMX
    6577                         uint64_t fCpu = pVCpu->fLocalForcedActions;
    6578 #endif
    6579                         fCpu &= VMCPU_FF_ALL_MASK & ~(  VMCPU_FF_PGM_SYNC_CR3
    6580                                                       | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
    6581                                                       | VMCPU_FF_TLB_FLUSH
    6582                                                       | VMCPU_FF_UNHALT );
    6583                         if (RT_LIKELY(   (   (   !fCpu
    6584                                               || (   !(fCpu & ~(VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
    6585                                                   && !pVCpu->cpum.GstCtx.rflags.Bits.u1IF))
    6586                                           && !VM_FF_IS_ANY_SET(pVM, VM_FF_ALL_MASK) )
    6587                                       || pStats->cInstructions < cMinInstructions))
    6588                         {
    6589                             if (pStats->cInstructions < cMaxInstructions)
    6590                             {
    6591                                 if (cInstructionSinceLastExit <= cMaxInstructionsWithoutExits)
    6592                                 {
    6593 #ifdef IN_RING0
    6594                                     if (   !fCheckPreemptionPending
    6595                                         || !RTThreadPreemptIsPending(NIL_RTTHREAD))
    6596 #endif
    6597                                     {
    6598                                         Assert(pVCpu->iem.s.cActiveMappings == 0);
    6599                                         iemReInitDecoder(pVCpu);
    6600                                         continue;
    6601                                     }
    6602 #ifdef IN_RING0
    6603                                     rcStrict = VINF_EM_RAW_INTERRUPT;
    6604                                     break;
    6605 #endif
    6606                                 }
    6607                             }
    6608                         }
    6609                         Assert(!(fCpu & VMCPU_FF_IEM));
    6610                     }
    6611                     Assert(pVCpu->iem.s.cActiveMappings == 0);
    6612                 }
    6613                 else if (pVCpu->iem.s.cActiveMappings > 0)
    6614                         iemMemRollback(pVCpu);
    6615                 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6616                 break;
    6617             }
    6618         }
    6619 #ifdef IEM_WITH_SETJMP
    6620         IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);
    6621         {
    6622             if (pVCpu->iem.s.cActiveMappings > 0)
    6623                 iemMemRollback(pVCpu);
    6624             pVCpu->iem.s.cLongJumps++;
    6625         }
    6626         IEM_CATCH_LONGJMP_END(pVCpu);
    6627 #endif
    6628 
    6629         /*
    6630          * Assert hidden register sanity (also done in iemInitDecoder and iemReInitDecoder).
    6631          */
    6632         Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));
    6633         Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
    6634     }
    6635     else
    6636     {
    6637         if (pVCpu->iem.s.cActiveMappings > 0)
    6638             iemMemRollback(pVCpu);
    6639 
    6640 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
    6641         /*
    6642          * When a nested-guest causes an exception intercept (e.g. #PF) when fetching
    6643          * code as part of instruction execution, we need this to fix-up VINF_SVM_VMEXIT.
    6644          */
    6645         rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6646 #endif
    6647     }
    6648 
    6649     /*
    6650      * Maybe re-enter raw-mode and log.
    6651      */
    6652     if (rcStrict != VINF_SUCCESS)
    6653         LogFlow(("IEMExecForExits: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc; ins=%u exits=%u maxdist=%u\n",
    6654                  pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp,
    6655                  pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict), pStats->cInstructions, pStats->cExits, pStats->cMaxExitDistance));
    6656     return rcStrict;
    6657 }
    6658 
    6659 
    6660 /**
    6661  * Injects a trap, fault, abort, software interrupt or external interrupt.
    6662  *
    6663  * The parameter list matches TRPMQueryTrapAll pretty closely.
    6664  *
    6665  * @returns Strict VBox status code.
    6666  * @param   pVCpu               The cross context virtual CPU structure of the calling EMT.
    6667  * @param   u8TrapNo            The trap number.
    6668  * @param   enmType             What type is it (trap/fault/abort), software
    6669  *                              interrupt or hardware interrupt.
    6670  * @param   uErrCode            The error code if applicable.
    6671  * @param   uCr2                The CR2 value if applicable.
    6672  * @param   cbInstr             The instruction length (only relevant for
    6673  *                              software interrupts).
    6674  * @note    x86 specific, but difficult to move due to iemInitDecoder dep.
    6675  */
    6676 VMM_INT_DECL(VBOXSTRICTRC) IEMInjectTrap(PVMCPUCC pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType, uint16_t uErrCode, RTGCPTR uCr2,
    6677                                          uint8_t cbInstr)
    6678 {
    6679     iemInitDecoder(pVCpu, 0 /*fExecOpts*/); /** @todo wrong init function! */
    6680 #ifdef DBGFTRACE_ENABLED
    6681     RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "IEMInjectTrap: %x %d %x %llx",
    6682                       u8TrapNo, enmType, uErrCode, uCr2);
    6683 #endif
    6684 
    6685     uint32_t fFlags;
    6686     switch (enmType)
    6687     {
    6688         case TRPM_HARDWARE_INT:
    6689             Log(("IEMInjectTrap: %#4x ext\n", u8TrapNo));
    6690             fFlags = IEM_XCPT_FLAGS_T_EXT_INT;
    6691             uErrCode = uCr2 = 0;
    6692             break;
    6693 
    6694         case TRPM_SOFTWARE_INT:
    6695             Log(("IEMInjectTrap: %#4x soft\n", u8TrapNo));
    6696             fFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
    6697             uErrCode = uCr2 = 0;
    6698             break;
    6699 
    6700         case TRPM_TRAP:
    6701         case TRPM_NMI: /** @todo Distinguish NMI from exception 2. */
    6702             Log(("IEMInjectTrap: %#4x trap err=%#x cr2=%#RGv\n", u8TrapNo, uErrCode, uCr2));
    6703             fFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
    6704             if (u8TrapNo == X86_XCPT_PF)
    6705                 fFlags |= IEM_XCPT_FLAGS_CR2;
    6706             switch (u8TrapNo)
    6707             {
    6708                 case X86_XCPT_DF:
    6709                 case X86_XCPT_TS:
    6710                 case X86_XCPT_NP:
    6711                 case X86_XCPT_SS:
    6712                 case X86_XCPT_PF:
    6713                 case X86_XCPT_AC:
    6714                 case X86_XCPT_GP:
    6715                     fFlags |= IEM_XCPT_FLAGS_ERR;
    6716                     break;
    6717             }
    6718             break;
    6719 
    6720         IEM_NOT_REACHED_DEFAULT_CASE_RET();
    6721     }
    6722 
    6723     VBOXSTRICTRC rcStrict = iemRaiseXcptOrInt(pVCpu, cbInstr, u8TrapNo, fFlags, uErrCode, uCr2);
    6724 
    6725     if (pVCpu->iem.s.cActiveMappings > 0)
    6726         iemMemRollback(pVCpu);
    6727 
    6728     return rcStrict;
    6729 }
    6730 
    6731 
    6732 /**
    6733  * Injects the active TRPM event.
    6734  *
    6735  * @returns Strict VBox status code.
    6736  * @param   pVCpu               The cross context virtual CPU structure.
    6737  */
    6738 VMM_INT_DECL(VBOXSTRICTRC) IEMInjectTrpmEvent(PVMCPUCC pVCpu)
    6739 {
    6740 #ifndef IEM_IMPLEMENTS_TASKSWITCH
    6741     IEM_RETURN_ASPECT_NOT_IMPLEMENTED_LOG(("Event injection\n"));
    6742 #else
    6743     uint8_t     u8TrapNo;
    6744     TRPMEVENT   enmType;
    6745     uint32_t    uErrCode;
    6746     RTGCUINTPTR uCr2;
    6747     uint8_t     cbInstr;
    6748     int rc = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrCode, &uCr2, &cbInstr, NULL /* fIcebp */);
    6749     if (RT_FAILURE(rc))
    6750         return rc;
    6751 
    6752     /** @todo r=ramshankar: Pass ICEBP info. to IEMInjectTrap() below and handle
    6753      *        ICEBP \#DB injection as a special case. */
    6754     VBOXSTRICTRC rcStrict = IEMInjectTrap(pVCpu, u8TrapNo, enmType, uErrCode, uCr2, cbInstr);
    6755 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM
    6756     if (rcStrict == VINF_SVM_VMEXIT)
    6757         rcStrict = VINF_SUCCESS;
    6758 #endif
    6759 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    6760     if (rcStrict == VINF_VMX_VMEXIT)
    6761         rcStrict = VINF_SUCCESS;
    6762 #endif
    6763     /** @todo Are there any other codes that imply the event was successfully
    6764      *        delivered to the guest? See @bugref{6607}.  */
    6765     if (   rcStrict == VINF_SUCCESS
    6766         || rcStrict == VINF_IEM_RAISED_XCPT)
    6767         TRPMResetTrap(pVCpu);
    6768 
    6769     return rcStrict;
    6770 #endif
    6771 }
    6772 
    6773 
    6774 VMM_INT_DECL(int) IEMBreakpointSet(PVM pVM, RTGCPTR GCPtrBp)
    6775 {
    6776     RT_NOREF_PV(pVM); RT_NOREF_PV(GCPtrBp);
    6777     return VERR_NOT_IMPLEMENTED;
    6778 }
    6779 
    6780 
    6781 VMM_INT_DECL(int) IEMBreakpointClear(PVM pVM, RTGCPTR GCPtrBp)
    6782 {
    6783     RT_NOREF_PV(pVM); RT_NOREF_PV(GCPtrBp);
    6784     return VERR_NOT_IMPLEMENTED;
    6785 }
    6786 
    6787 #ifdef IN_RING3
    6788 
    6789 /**
    6790  * Handles the unlikely and probably fatal merge cases.
    6791  *
    6792  * @returns Merged status code.
    6793  * @param   rcStrict        Current EM status code.
    6794  * @param   rcStrictCommit  The IOM I/O or MMIO write commit status to merge
    6795  *                          with @a rcStrict.
    6796  * @param   iMemMap         The memory mapping index. For error reporting only.
    6797  * @param   pVCpu           The cross context virtual CPU structure of the calling
    6798  *                          thread, for error reporting only.
    6799  */
    6800 DECL_NO_INLINE(static, VBOXSTRICTRC) iemR3MergeStatusSlow(VBOXSTRICTRC rcStrict, VBOXSTRICTRC rcStrictCommit,
    6801                                                           unsigned iMemMap, PVMCPUCC pVCpu)
    6802 {
    6803     if (RT_FAILURE_NP(rcStrict))
    6804         return rcStrict;
    6805 
    6806     if (RT_FAILURE_NP(rcStrictCommit))
    6807         return rcStrictCommit;
    6808 
    6809     if (rcStrict == rcStrictCommit)
    6810         return rcStrictCommit;
    6811 
    6812     AssertLogRelMsgFailed(("rcStrictCommit=%Rrc rcStrict=%Rrc iMemMap=%u fAccess=%#x FirstPg=%RGp LB %u SecondPg=%RGp LB %u\n",
    6813                            VBOXSTRICTRC_VAL(rcStrictCommit), VBOXSTRICTRC_VAL(rcStrict), iMemMap,
    6814                            pVCpu->iem.s.aMemMappings[iMemMap].fAccess,
    6815                            pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst,
    6816                            pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond));
    6817     return VERR_IOM_FF_STATUS_IPE;
    6818 }
    6819 
    6820 
    6821 /**
    6822  * Helper for IOMR3ProcessForceFlag.
    6823  *
    6824  * @returns Merged status code.
    6825  * @param   rcStrict        Current EM status code.
    6826  * @param   rcStrictCommit  The IOM I/O or MMIO write commit status to merge
    6827  *                          with @a rcStrict.
    6828  * @param   iMemMap         The memory mapping index. For error reporting only.
    6829  * @param   pVCpu           The cross context virtual CPU structure of the calling
    6830  *                          thread, for error reporting only.
    6831  */
    6832 DECLINLINE(VBOXSTRICTRC) iemR3MergeStatus(VBOXSTRICTRC rcStrict, VBOXSTRICTRC rcStrictCommit, unsigned iMemMap, PVMCPUCC pVCpu)
    6833 {
    6834     /* Simple. */
    6835     if (RT_LIKELY(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RAW_TO_R3))
    6836         return rcStrictCommit;
    6837 
    6838     if (RT_LIKELY(rcStrictCommit == VINF_SUCCESS))
    6839         return rcStrict;
    6840 
    6841     /* EM scheduling status codes. */
    6842     if (RT_LIKELY(   rcStrict >= VINF_EM_FIRST
    6843                   && rcStrict <= VINF_EM_LAST))
    6844     {
    6845         if (RT_LIKELY(   rcStrictCommit >= VINF_EM_FIRST
    6846                       && rcStrictCommit <= VINF_EM_LAST))
    6847             return rcStrict < rcStrictCommit ? rcStrict : rcStrictCommit;
    6848     }
    6849 
    6850     /* Unlikely */
    6851     return iemR3MergeStatusSlow(rcStrict, rcStrictCommit, iMemMap, pVCpu);
    6852 }
    6853 
    6854 
    6855 /**
    6856  * Called by force-flag handling code when VMCPU_FF_IEM is set.
    6857  *
    6858  * @returns Merge between @a rcStrict and what the commit operation returned.
    6859  * @param   pVM         The cross context VM structure.
    6860  * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
    6861  * @param   rcStrict    The status code returned by ring-0 or raw-mode.
    6862  */
    6863 VMMR3_INT_DECL(VBOXSTRICTRC) IEMR3ProcessForceFlag(PVM pVM, PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict)
    6864 {
    6865     /*
    6866      * Reset the pending commit.
    6867      */
    6868     AssertMsg(  (pVCpu->iem.s.aMemMappings[0].fAccess | pVCpu->iem.s.aMemMappings[1].fAccess | pVCpu->iem.s.aMemMappings[2].fAccess)
    6869               & (IEM_ACCESS_PENDING_R3_WRITE_1ST | IEM_ACCESS_PENDING_R3_WRITE_2ND),
    6870               ("%#x %#x %#x\n",
    6871                pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemMappings[2].fAccess));
    6872     VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_IEM);
    6873 
    6874     /*
    6875      * Commit the pending bounce buffers (usually just one).
    6876      */
    6877     unsigned cBufs = 0;
    6878     unsigned iMemMap = RT_ELEMENTS(pVCpu->iem.s.aMemMappings);
    6879     while (iMemMap-- > 0)
    6880         if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_PENDING_R3_WRITE_1ST | IEM_ACCESS_PENDING_R3_WRITE_2ND))
    6881         {
    6882             Assert(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE);
    6883             Assert(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED);
    6884             Assert(!pVCpu->iem.s.aMemBbMappings[iMemMap].fUnassigned);
    6885 
    6886             uint16_t const  cbFirst  = pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst;
    6887             uint16_t const  cbSecond = pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond;
    6888             uint8_t const  *pbBuf    = &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0];
    6889 
    6890             if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_PENDING_R3_WRITE_1ST)
    6891             {
    6892                 VBOXSTRICTRC rcStrictCommit1 = PGMPhysWrite(pVM,
    6893                                                             pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst,
    6894                                                             pbBuf,
    6895                                                             cbFirst,
    6896                                                             PGMACCESSORIGIN_IEM);
    6897                 rcStrict = iemR3MergeStatus(rcStrict, rcStrictCommit1, iMemMap, pVCpu);
    6898                 Log(("IEMR3ProcessForceFlag: iMemMap=%u GCPhysFirst=%RGp LB %#x %Rrc => %Rrc\n",
    6899                      iMemMap, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    6900                      VBOXSTRICTRC_VAL(rcStrictCommit1), VBOXSTRICTRC_VAL(rcStrict)));
    6901             }
    6902 
    6903             if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_PENDING_R3_WRITE_2ND)
    6904             {
    6905                 VBOXSTRICTRC rcStrictCommit2 = PGMPhysWrite(pVM,
    6906                                                             pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond,
    6907                                                             pbBuf + cbFirst,
    6908                                                             cbSecond,
    6909                                                             PGMACCESSORIGIN_IEM);
    6910                 rcStrict = iemR3MergeStatus(rcStrict, rcStrictCommit2, iMemMap, pVCpu);
    6911                 Log(("IEMR3ProcessForceFlag: iMemMap=%u GCPhysSecond=%RGp LB %#x %Rrc => %Rrc\n",
    6912                      iMemMap, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond,
    6913                      VBOXSTRICTRC_VAL(rcStrictCommit2), VBOXSTRICTRC_VAL(rcStrict)));
    6914             }
    6915             cBufs++;
    6916             pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    6917         }
    6918 
    6919     AssertMsg(cBufs > 0 && cBufs == pVCpu->iem.s.cActiveMappings,
    6920               ("cBufs=%u cActiveMappings=%u - %#x %#x %#x\n", cBufs, pVCpu->iem.s.cActiveMappings,
    6921                pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemMappings[2].fAccess));
    6922     pVCpu->iem.s.cActiveMappings = 0;
    6923     return rcStrict;
    6924 }
    6925 
    6926 #endif /* IN_RING3 */
    6927 
  • trunk/src/VBox/VMM/VMMAll/target-x86/IEMAllTlbInline-x86.h

    r108220 r108226  
    2727
    2828
    29 /** @page pg_iem    IEM - Interpreted Execution Manager
    30  *
    31  * The interpreted exeuction manager (IEM) is for executing short guest code
    32  * sequences that are causing too many exits / virtualization traps.  It will
    33  * also be used to interpret single instructions, thus replacing the selective
    34  * interpreters in EM and IOM.
    35  *
    36  * Design goals:
    37  *      - Relatively small footprint, although we favour speed and correctness
    38  *        over size.
    39  *      - Reasonably fast.
    40  *      - Correctly handle lock prefixed instructions.
    41  *      - Complete instruction set - eventually.
    42  *      - Refactorable into a recompiler, maybe.
    43  *      - Replace EMInterpret*.
    44  *
    45  * Using the existing disassembler has been considered, however this is thought
    46  * to conflict with speed as the disassembler chews things a bit too much while
    47  * leaving us with a somewhat complicated state to interpret afterwards.
    48  *
    49  *
    50  * The current code is very much work in progress. You've been warned!
    51  *
    52  *
    53  * @section sec_iem_fpu_instr   FPU Instructions
    54  *
    55  * On x86 and AMD64 hosts, the FPU instructions are implemented by executing the
    56  * same or equivalent instructions on the host FPU.  To make life easy, we also
    57  * let the FPU prioritize the unmasked exceptions for us.  This however, only
    58  * works reliably when CR0.NE is set, i.e. when using \#MF instead the IRQ 13
    59  * for FPU exception delivery, because with CR0.NE=0 there is a window where we
    60  * can trigger spurious FPU exceptions.
    61  *
    62  * The guest FPU state is not loaded into the host CPU and kept there till we
    63  * leave IEM because the calling conventions have declared an all year open
    64  * season on much of the FPU state.  For instance an innocent looking call to
    65  * memcpy might end up using a whole bunch of XMM or MM registers if the
    66  * particular implementation finds it worthwhile.
    67  *
    68  *
    69  * @section sec_iem_logging     Logging
    70  *
    71  * The IEM code uses the \"IEM\" log group for the main logging. The different
    72  * logging levels/flags are generally used for the following purposes:
    73  *      - Level 1  (Log)  : Errors, exceptions, interrupts and such major events.
    74  *      - Flow  (LogFlow) : Basic enter/exit IEM state info.
    75  *      - Level 2  (Log2) : ?
    76  *      - Level 3  (Log3) : More detailed enter/exit IEM state info.
    77  *      - Level 4  (Log4) : Decoding mnemonics w/ EIP.
    78  *      - Level 5  (Log5) : Decoding details.
    79  *      - Level 6  (Log6) : Enables/disables the lockstep comparison with REM.
    80  *      - Level 7  (Log7) : iret++ execution logging.
    81  *      - Level 8  (Log8) :
    82  *      - Level 9  (Log9) :
    83  *      - Level 10 (Log10): TLBs.
    84  *      - Level 11 (Log11): Unmasked FPU exceptions.
    85  *
    86  * The \"IEM_MEM\" log group covers most of memory related details logging,
    87  * except for errors and exceptions:
    88  *      - Level 1  (Log)  : Reads.
    89  *      - Level 2  (Log2) : Read fallbacks.
    90  *      - Level 3  (Log3) : MemMap read.
    91  *      - Level 4  (Log4) : MemMap read fallbacks.
    92  *      - Level 5  (Log5) : Writes
    93  *      - Level 6  (Log6) : Write fallbacks.
    94  *      - Level 7  (Log7) : MemMap writes and read-writes.
    95  *      - Level 8  (Log8) : MemMap write and read-write fallbacks.
    96  *      - Level 9  (Log9) : Stack reads.
    97  *      - Level 10 (Log10): Stack read fallbacks.
    98  *      - Level 11 (Log11): Stack writes.
    99  *      - Level 12 (Log12): Stack write fallbacks.
    100  *      - Flow  (LogFlow) :
    101  *
    102  * The SVM (AMD-V) and VMX (VT-x) code has the following assignments:
    103  *      - Level 1  (Log)  : Errors and other major events.
    104  *      - Flow (LogFlow)  : Misc flow stuff (cleanup?)
    105  *      - Level 2  (Log2) : VM exits.
    106  *
    107  * The syscall logging level assignments:
    108  *      - Level 1: DOS and BIOS.
    109  *      - Level 2: Windows 3.x
    110  *      - Level 3: Linux.
    111  */
    112 
    113 /* Disabled warning C4505: 'iemRaisePageFaultJmp' : unreferenced local function has been removed */
    114 #ifdef _MSC_VER
    115 # pragma warning(disable:4505)
     29#ifndef VMM_INCLUDED_SRC_VMMAll_target_x86_IEMAllTlbInline_x86_h
     30#define VMM_INCLUDED_SRC_VMMAll_target_x86_IEMAllTlbInline_x86_h
     31#ifndef RT_WITHOUT_PRAGMA_ONCE
     32# pragma once
    11633#endif
    11734
    118 
    119 /*********************************************************************************************************************************
    120 *   Header Files                                                                                                                 *
    121 *********************************************************************************************************************************/
    122 #define LOG_GROUP   LOG_GROUP_IEM
    123 #define VMCPU_INCL_CPUM_GST_CTX
    124 #ifdef IN_RING0
    125 # define VBOX_VMM_TARGET_X86
    126 #endif
    127 #include <VBox/vmm/iem.h>
    128 #include <VBox/vmm/cpum.h>
    129 #include <VBox/vmm/pdmapic.h>
    130 #include <VBox/vmm/pdm.h>
    131 #include <VBox/vmm/pgm.h>
    132 #include <VBox/vmm/iom.h>
    133 #include <VBox/vmm/em.h>
    134 #include <VBox/vmm/hm.h>
    135 #include <VBox/vmm/nem.h>
    136 #include <VBox/vmm/gcm.h>
    137 #include <VBox/vmm/gim.h>
    138 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM
    139 # include <VBox/vmm/em.h>
    140 # include <VBox/vmm/hm_svm.h>
    141 #endif
    142 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    143 # include <VBox/vmm/hmvmxinline.h>
    144 #endif
    145 #include <VBox/vmm/tm.h>
    146 #include <VBox/vmm/dbgf.h>
    147 #include <VBox/vmm/dbgftrace.h>
    148 #include "IEMInternal.h"
    149 #include <VBox/vmm/vmcc.h>
    150 #include <VBox/log.h>
    151 #include <VBox/err.h>
    152 #include <VBox/param.h>
    153 #include <VBox/dis.h>
    154 #include <iprt/asm-math.h>
    155 #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
    156 # include <iprt/asm-amd64-x86.h>
    157 #elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
    158 # include <iprt/asm-arm.h>
    159 #endif
    160 #include <iprt/assert.h>
    161 #include <iprt/string.h>
    162 #include <iprt/x86.h>
    163 
    164 #include "IEMInline.h"
    165 
    166 
    167 /*********************************************************************************************************************************
    168 *   Structures and Typedefs                                                                                                      *
    169 *********************************************************************************************************************************/
    170 /**
    171  * CPU exception classes.
    172  */
    173 typedef enum IEMXCPTCLASS
    174 {
    175     IEMXCPTCLASS_BENIGN,
    176     IEMXCPTCLASS_CONTRIBUTORY,
    177     IEMXCPTCLASS_PAGE_FAULT,
    178     IEMXCPTCLASS_DOUBLE_FAULT
    179 } IEMXCPTCLASS;
    180 
    181 
    182 /*********************************************************************************************************************************
    183 *   Global Variables                                                                                                             *
    184 *********************************************************************************************************************************/
    185 #if defined(IEM_LOG_MEMORY_WRITES)
    186 /** What IEM just wrote. */
    187 uint8_t g_abIemWrote[256];
    188 /** How much IEM just wrote. */
    189 size_t g_cbIemWrote;
    190 #endif
    191 
    192 
    193 /**
    194  * Calculates IEM_F_BRK_PENDING_XXX (IEM_F_PENDING_BRK_MASK) flags, slow code
    195  * path.
    196  *
    197  * This will also invalidate TLB entries for any pages with active data
    198  * breakpoints on them.
    199  *
    200  * @returns IEM_F_BRK_PENDING_XXX or zero.
    201  * @param   pVCpu               The cross context virtual CPU structure of the
    202  *                              calling thread.
    203  *
    204  * @note    Don't call directly, use iemCalcExecDbgFlags instead.
    205  */
    206 uint32_t iemCalcExecDbgFlagsSlow(PVMCPUCC pVCpu)
    207 {
    208     uint32_t fExec = 0;
    209 
    210     /*
    211      * Helper for invalidate the data TLB for breakpoint addresses.
    212      *
    213      * This is to make sure any access to the page will always trigger a TLB
    214      * load for as long as the breakpoint is enabled.
    215      */
    216 #ifdef IEM_WITH_DATA_TLB
    217 # define INVALID_TLB_ENTRY_FOR_BP(a_uValue) do { \
    218         RTGCPTR uTagNoRev = (a_uValue); \
    219         uTagNoRev = IEMTLB_CALC_TAG_NO_REV(uTagNoRev); \
    220         /** @todo do large page accounting */ \
    221         uintptr_t const idxEven = IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev); \
    222         if (pVCpu->iem.s.DataTlb.aEntries[idxEven].uTag == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevision)) \
    223             pVCpu->iem.s.DataTlb.aEntries[idxEven].uTag = 0; \
    224         if (pVCpu->iem.s.DataTlb.aEntries[idxEven + 1].uTag == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevisionGlobal)) \
    225             pVCpu->iem.s.DataTlb.aEntries[idxEven + 1].uTag = 0; \
    226     } while (0)
    227 #else
    228 # define INVALID_TLB_ENTRY_FOR_BP(a_uValue) do { } while (0)
    229 #endif
    230 
    231     /*
    232      * Process guest breakpoints.
    233      */
    234 #define PROCESS_ONE_BP(a_fDr7, a_iBp, a_uValue) do { \
    235         if (a_fDr7 & X86_DR7_L_G(a_iBp)) \
    236         { \
    237             switch (X86_DR7_GET_RW(a_fDr7, a_iBp)) \
    238             { \
    239                 case X86_DR7_RW_EO: \
    240                     fExec |= IEM_F_PENDING_BRK_INSTR; \
    241                     break; \
    242                 case X86_DR7_RW_WO: \
    243                 case X86_DR7_RW_RW: \
    244                     fExec |= IEM_F_PENDING_BRK_DATA; \
    245                     INVALID_TLB_ENTRY_FOR_BP(a_uValue); \
    246                     break; \
    247                 case X86_DR7_RW_IO: \
    248                     fExec |= IEM_F_PENDING_BRK_X86_IO; \
    249                     break; \
    250             } \
    251         } \
    252     } while (0)
    253 
    254     uint32_t const fGstDr7 = (uint32_t)pVCpu->cpum.GstCtx.dr[7];
    255     if (fGstDr7 & X86_DR7_ENABLED_MASK)
    256     {
    257 /** @todo extract more details here to simplify matching later. */
    258 #ifdef IEM_WITH_DATA_TLB
    259         IEM_CTX_IMPORT_NORET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
    260 #endif
    261         PROCESS_ONE_BP(fGstDr7, 0, pVCpu->cpum.GstCtx.dr[0]);
    262         PROCESS_ONE_BP(fGstDr7, 1, pVCpu->cpum.GstCtx.dr[1]);
    263         PROCESS_ONE_BP(fGstDr7, 2, pVCpu->cpum.GstCtx.dr[2]);
    264         PROCESS_ONE_BP(fGstDr7, 3, pVCpu->cpum.GstCtx.dr[3]);
    265     }
    266 
    267     /*
    268      * Process hypervisor breakpoints.
    269      */
    270     PVMCC const    pVM       = pVCpu->CTX_SUFF(pVM);
    271     uint32_t const fHyperDr7 = DBGFBpGetDR7(pVM);
    272     if (fHyperDr7 & X86_DR7_ENABLED_MASK)
    273     {
    274 /** @todo extract more details here to simplify matching later. */
    275         PROCESS_ONE_BP(fHyperDr7, 0, DBGFBpGetDR0(pVM));
    276         PROCESS_ONE_BP(fHyperDr7, 1, DBGFBpGetDR1(pVM));
    277         PROCESS_ONE_BP(fHyperDr7, 2, DBGFBpGetDR2(pVM));
    278         PROCESS_ONE_BP(fHyperDr7, 3, DBGFBpGetDR3(pVM));
    279     }
    280 
    281     return fExec;
    282 }
    283 
    284 
    285 /**
    286  * Initializes the decoder state.
    287  *
    288  * iemReInitDecoder is mostly a copy of this function.
    289  *
    290  * @param   pVCpu               The cross context virtual CPU structure of the
    291  *                              calling thread.
    292  * @param   fExecOpts           Optional execution flags:
    293  *                                  - IEM_F_BYPASS_HANDLERS
    294  *                                  - IEM_F_X86_DISREGARD_LOCK
    295  */
    296 DECLINLINE(void) iemInitDecoder(PVMCPUCC pVCpu, uint32_t fExecOpts)
    297 {
    298     IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_MUST_MASK);
    299     Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_IEM));
    300     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));
    301     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
    302     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.es));
    303     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ds));
    304     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.fs));
    305     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.gs));
    306     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ldtr));
    307     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.tr));
    308 
    309     /* Execution state: */
    310     uint32_t fExec;
    311     pVCpu->iem.s.fExec = fExec = iemCalcExecFlags(pVCpu) | fExecOpts;
    312 
    313     /* Decoder state: */
    314     pVCpu->iem.s.enmDefAddrMode     = fExec & IEM_F_MODE_CPUMODE_MASK;  /** @todo check if this is correct... */
    315     pVCpu->iem.s.enmEffAddrMode     = fExec & IEM_F_MODE_CPUMODE_MASK;
    316     if ((fExec & IEM_F_MODE_CPUMODE_MASK) != IEMMODE_64BIT)
    317     {
    318         pVCpu->iem.s.enmDefOpSize   = fExec & IEM_F_MODE_CPUMODE_MASK;  /** @todo check if this is correct... */
    319         pVCpu->iem.s.enmEffOpSize   = fExec & IEM_F_MODE_CPUMODE_MASK;
    320     }
    321     else
    322     {
    323         pVCpu->iem.s.enmDefOpSize   = IEMMODE_32BIT;
    324         pVCpu->iem.s.enmEffOpSize   = IEMMODE_32BIT;
    325     }
    326     pVCpu->iem.s.fPrefixes          = 0;
    327     pVCpu->iem.s.uRexReg            = 0;
    328     pVCpu->iem.s.uRexB              = 0;
    329     pVCpu->iem.s.uRexIndex          = 0;
    330     pVCpu->iem.s.idxPrefix          = 0;
    331     pVCpu->iem.s.uVex3rdReg         = 0;
    332     pVCpu->iem.s.uVexLength         = 0;
    333     pVCpu->iem.s.fEvexStuff         = 0;
    334     pVCpu->iem.s.iEffSeg            = X86_SREG_DS;
    335 #ifdef IEM_WITH_CODE_TLB
    336     pVCpu->iem.s.pbInstrBuf         = NULL;
    337     pVCpu->iem.s.offInstrNextByte   = 0;
    338     pVCpu->iem.s.offCurInstrStart   = 0;
    339 # ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
    340     pVCpu->iem.s.offOpcode          = 0;
    341 # endif
    342 # ifdef VBOX_STRICT
    343     pVCpu->iem.s.GCPhysInstrBuf     = NIL_RTGCPHYS;
    344     pVCpu->iem.s.cbInstrBuf         = UINT16_MAX;
    345     pVCpu->iem.s.cbInstrBufTotal    = UINT16_MAX;
    346     pVCpu->iem.s.uInstrBufPc        = UINT64_C(0xc0ffc0ffcff0c0ff);
    347 # endif
    348 #else
    349     pVCpu->iem.s.offOpcode          = 0;
    350     pVCpu->iem.s.cbOpcode           = 0;
    351 #endif
    352     pVCpu->iem.s.offModRm           = 0;
    353     pVCpu->iem.s.cActiveMappings    = 0;
    354     pVCpu->iem.s.iNextMapping       = 0;
    355     pVCpu->iem.s.rcPassUp           = VINF_SUCCESS;
    356 
    357 #ifdef DBGFTRACE_ENABLED
    358     switch (IEM_GET_CPU_MODE(pVCpu))
    359     {
    360         case IEMMODE_64BIT:
    361             RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I64/%u %08llx", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.rip);
    362             break;
    363         case IEMMODE_32BIT:
    364             RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I32/%u %04x:%08x", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip);
    365             break;
    366         case IEMMODE_16BIT:
    367             RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I16/%u %04x:%04x", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip);
    368             break;
    369     }
    370 #endif
    371 }
    372 
    373 
    374 /**
    375  * Reinitializes the decoder state 2nd+ loop of IEMExecLots.
    376  *
    377  * This is mostly a copy of iemInitDecoder.
    378  *
    379  * @param   pVCpu               The cross context virtual CPU structure of the calling EMT.
    380  */
    381 DECLINLINE(void) iemReInitDecoder(PVMCPUCC pVCpu)
    382 {
    383     Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_IEM));
    384     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));
    385     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
    386     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.es));
    387     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ds));
    388     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.fs));
    389     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.gs));
    390     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ldtr));
    391     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.tr));
    392 
    393     /* ASSUMES: Anyone changing CPU state affecting the fExec bits will update them! */
    394     AssertMsg((pVCpu->iem.s.fExec & ~IEM_F_USER_OPTS) == iemCalcExecFlags(pVCpu),
    395               ("fExec=%#x iemCalcExecModeFlags=%#x\n", pVCpu->iem.s.fExec, iemCalcExecFlags(pVCpu)));
    396 
    397     IEMMODE const enmMode = IEM_GET_CPU_MODE(pVCpu);
    398     pVCpu->iem.s.enmDefAddrMode     = enmMode;  /** @todo check if this is correct... */
    399     pVCpu->iem.s.enmEffAddrMode     = enmMode;
    400     if (enmMode != IEMMODE_64BIT)
    401     {
    402         pVCpu->iem.s.enmDefOpSize   = enmMode;  /** @todo check if this is correct... */
    403         pVCpu->iem.s.enmEffOpSize   = enmMode;
    404     }
    405     else
    406     {
    407         pVCpu->iem.s.enmDefOpSize   = IEMMODE_32BIT;
    408         pVCpu->iem.s.enmEffOpSize   = IEMMODE_32BIT;
    409     }
    410     pVCpu->iem.s.fPrefixes          = 0;
    411     pVCpu->iem.s.uRexReg            = 0;
    412     pVCpu->iem.s.uRexB              = 0;
    413     pVCpu->iem.s.uRexIndex          = 0;
    414     pVCpu->iem.s.idxPrefix          = 0;
    415     pVCpu->iem.s.uVex3rdReg         = 0;
    416     pVCpu->iem.s.uVexLength         = 0;
    417     pVCpu->iem.s.fEvexStuff         = 0;
    418     pVCpu->iem.s.iEffSeg            = X86_SREG_DS;
    419 #ifdef IEM_WITH_CODE_TLB
    420     if (pVCpu->iem.s.pbInstrBuf)
    421     {
    422         uint64_t off = (enmMode == IEMMODE_64BIT
    423                         ? pVCpu->cpum.GstCtx.rip
    424                         : pVCpu->cpum.GstCtx.eip + (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base)
    425                      - pVCpu->iem.s.uInstrBufPc;
    426         if (off < pVCpu->iem.s.cbInstrBufTotal)
    427         {
    428             pVCpu->iem.s.offInstrNextByte = (uint32_t)off;
    429             pVCpu->iem.s.offCurInstrStart = (uint16_t)off;
    430             if ((uint16_t)off + 15 <= pVCpu->iem.s.cbInstrBufTotal)
    431                 pVCpu->iem.s.cbInstrBuf = (uint16_t)off + 15;
    432             else
    433                 pVCpu->iem.s.cbInstrBuf = pVCpu->iem.s.cbInstrBufTotal;
    434         }
    435         else
    436         {
    437             pVCpu->iem.s.pbInstrBuf       = NULL;
    438             pVCpu->iem.s.offInstrNextByte = 0;
    439             pVCpu->iem.s.offCurInstrStart = 0;
    440             pVCpu->iem.s.cbInstrBuf       = 0;
    441             pVCpu->iem.s.cbInstrBufTotal  = 0;
    442             pVCpu->iem.s.GCPhysInstrBuf   = NIL_RTGCPHYS;
    443         }
    444     }
    445     else
    446     {
    447         pVCpu->iem.s.offInstrNextByte = 0;
    448         pVCpu->iem.s.offCurInstrStart = 0;
    449         pVCpu->iem.s.cbInstrBuf       = 0;
    450         pVCpu->iem.s.cbInstrBufTotal  = 0;
    451 # ifdef VBOX_STRICT
    452         pVCpu->iem.s.GCPhysInstrBuf   = NIL_RTGCPHYS;
    453 # endif
    454     }
    455 # ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
    456     pVCpu->iem.s.offOpcode          = 0;
    457 # endif
    458 #else  /* !IEM_WITH_CODE_TLB */
    459     pVCpu->iem.s.cbOpcode           = 0;
    460     pVCpu->iem.s.offOpcode          = 0;
    461 #endif /* !IEM_WITH_CODE_TLB */
    462     pVCpu->iem.s.offModRm           = 0;
    463     Assert(pVCpu->iem.s.cActiveMappings == 0);
    464     pVCpu->iem.s.iNextMapping       = 0;
    465     Assert(pVCpu->iem.s.rcPassUp   == VINF_SUCCESS);
    466     Assert(!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS));
    467 
    468 #ifdef DBGFTRACE_ENABLED
    469     switch (enmMode)
    470     {
    471         case IEMMODE_64BIT:
    472             RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I64/%u %08llx", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.rip);
    473             break;
    474         case IEMMODE_32BIT:
    475             RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I32/%u %04x:%08x", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip);
    476             break;
    477         case IEMMODE_16BIT:
    478             RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I16/%u %04x:%04x", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip);
    479             break;
    480     }
    481 #endif
    482 }
    483 
    484 
    485 
    486 /**
    487  * Prefetch opcodes the first time when starting executing.
    488  *
    489  * @returns Strict VBox status code.
    490  * @param   pVCpu               The cross context virtual CPU structure of the
    491  *                              calling thread.
    492  * @param   fExecOpts           Optional execution flags:
    493  *                                  - IEM_F_BYPASS_HANDLERS
    494  *                                  - IEM_F_X86_DISREGARD_LOCK
    495  */
    496 static VBOXSTRICTRC iemInitDecoderAndPrefetchOpcodes(PVMCPUCC pVCpu, uint32_t fExecOpts) RT_NOEXCEPT
    497 {
    498     iemInitDecoder(pVCpu, fExecOpts);
    499 
    500 #ifndef IEM_WITH_CODE_TLB
    501     /*
    502      * What we're doing here is very similar to iemMemMap/iemMemBounceBufferMap.
    503      *
    504      * First translate CS:rIP to a physical address.
    505      *
    506      * Note! The iemOpcodeFetchMoreBytes code depends on this here code to fetch
    507      *       all relevant bytes from the first page, as it ASSUMES it's only ever
    508      *       called for dealing with CS.LIM, page crossing and instructions that
    509      *       are too long.
    510      */
    511     uint32_t    cbToTryRead;
    512     RTGCPTR     GCPtrPC;
    513     if (IEM_IS_64BIT_CODE(pVCpu))
    514     {
    515         cbToTryRead = GUEST_PAGE_SIZE;
    516         GCPtrPC     = pVCpu->cpum.GstCtx.rip;
    517         if (IEM_IS_CANONICAL(GCPtrPC))
    518             cbToTryRead = GUEST_PAGE_SIZE - (GCPtrPC & GUEST_PAGE_OFFSET_MASK);
    519         else
    520             return iemRaiseGeneralProtectionFault0(pVCpu);
    521     }
    522     else
    523     {
    524         uint32_t GCPtrPC32 = pVCpu->cpum.GstCtx.eip;
    525         AssertMsg(!(GCPtrPC32 & ~(uint32_t)UINT16_MAX) || IEM_IS_32BIT_CODE(pVCpu), ("%04x:%RX64\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    526         if (GCPtrPC32 <= pVCpu->cpum.GstCtx.cs.u32Limit)
    527             cbToTryRead = pVCpu->cpum.GstCtx.cs.u32Limit - GCPtrPC32 + 1;
    528         else
    529             return iemRaiseSelectorBounds(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
    530         if (cbToTryRead) { /* likely */ }
    531         else /* overflowed */
    532         {
    533             Assert(GCPtrPC32 == 0); Assert(pVCpu->cpum.GstCtx.cs.u32Limit == UINT32_MAX);
    534             cbToTryRead = UINT32_MAX;
    535         }
    536         GCPtrPC = (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base + GCPtrPC32;
    537         Assert(GCPtrPC <= UINT32_MAX);
    538     }
    539 
    540     PGMPTWALKFAST WalkFast;
    541     int rc = PGMGstQueryPageFast(pVCpu, GCPtrPC,
    542                                  IEM_GET_CPL(pVCpu) == 3 ? PGMQPAGE_F_EXECUTE | PGMQPAGE_F_USER_MODE : PGMQPAGE_F_EXECUTE,
    543                                  &WalkFast);
    544     if (RT_SUCCESS(rc))
    545         Assert(WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED);
    546     else
    547     {
    548         Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - rc=%Rrc\n", GCPtrPC, rc));
    549 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    550 /** @todo This isn't quite right yet, as PGM_GST_SLAT_NAME_EPT(Walk) doesn't
    551  * know about what kind of access we're making! See PGM_GST_NAME(WalkFast). */
    552         if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    553             IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
    554 # endif
    555         return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, rc);
    556     }
    557 #if 0
    558     if ((WalkFast.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3) { /* likely */ }
    559     else
    560     {
    561         Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - supervisor page\n", GCPtrPC));
    562 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    563 /** @todo this is completely wrong for EPT. WalkFast.fFailed is always zero here!*/
    564 #  error completely wrong
    565         if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    566             IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
    567 # endif
    568         return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
    569     }
    570     if (!(WalkFast.fEffective & X86_PTE_PAE_NX) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE)) { /* likely */ }
    571     else
    572     {
    573         Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - NX\n", GCPtrPC));
    574 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    575 /** @todo this is completely wrong for EPT. WalkFast.fFailed is always zero here!*/
    576 #  error completely wrong.
    577         if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    578             IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
    579 # endif
    580         return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
    581     }
    582 #else
    583     Assert((WalkFast.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3);
    584     Assert(!(WalkFast.fEffective & X86_PTE_PAE_NX) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE));
    585 #endif
    586     RTGCPHYS const GCPhys = WalkFast.GCPhys;
    587 
    588     /*
    589      * Read the bytes at this address.
    590      */
    591     uint32_t cbLeftOnPage = GUEST_PAGE_SIZE - (GCPtrPC & GUEST_PAGE_OFFSET_MASK);
    592     if (cbToTryRead > cbLeftOnPage)
    593         cbToTryRead = cbLeftOnPage;
    594     if (cbToTryRead > sizeof(pVCpu->iem.s.abOpcode))
    595         cbToTryRead = sizeof(pVCpu->iem.s.abOpcode);
    596 
    597     if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))
    598     {
    599         VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), GCPhys, pVCpu->iem.s.abOpcode, cbToTryRead, PGMACCESSORIGIN_IEM);
    600         if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    601         { /* likely */ }
    602         else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    603         {
    604             Log(("iemInitDecoderAndPrefetchOpcodes: %RGv/%RGp LB %#x - read status -  rcStrict=%Rrc\n",
    605                  GCPtrPC, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead));
    606             rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    607         }
    608         else
    609         {
    610             Log((RT_SUCCESS(rcStrict)
    611                  ? "iemInitDecoderAndPrefetchOpcodes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n"
    612                  : "iemInitDecoderAndPrefetchOpcodes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n",
    613                  GCPtrPC, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead));
    614             return rcStrict;
    615         }
    616     }
    617     else
    618     {
    619         rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), pVCpu->iem.s.abOpcode, GCPhys, cbToTryRead);
    620         if (RT_SUCCESS(rc))
    621         { /* likely */ }
    622         else
    623         {
    624             Log(("iemInitDecoderAndPrefetchOpcodes: %RGv/%RGp LB %#x - read error - rc=%Rrc (!!)\n",
    625                  GCPtrPC, GCPhys, rc, cbToTryRead));
    626             return rc;
    627         }
    628     }
    629     pVCpu->iem.s.cbOpcode = cbToTryRead;
    630 #endif /* !IEM_WITH_CODE_TLB */
    631     return VINF_SUCCESS;
    632 }
    633 
    634 
    63535#if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
     36
    63637/**
    63738 * Helper for doing large page accounting at TLB load time.
     
    66566    RT_NOREF_PV(pVCpu);
    66667}
    667 #endif
    668 
    669 
    670 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    671 /**
    672  * Worker for iemTlbInvalidateAll.
    673  */
    674 template<bool a_fGlobal>
    675 DECL_FORCE_INLINE(void) iemTlbInvalidateOne(IEMTLB *pTlb)
    676 {
    677     if (!a_fGlobal)
    678         pTlb->cTlsFlushes++;
    679     else
    680         pTlb->cTlsGlobalFlushes++;
    681 
    682     pTlb->uTlbRevision += IEMTLB_REVISION_INCR;
    683     if (RT_LIKELY(pTlb->uTlbRevision != 0))
    684     { /* very likely */ }
    685     else
    686     {
    687         pTlb->uTlbRevision = IEMTLB_REVISION_INCR;
    688         pTlb->cTlbRevisionRollovers++;
    689         unsigned i = RT_ELEMENTS(pTlb->aEntries) / 2;
    690         while (i-- > 0)
    691             pTlb->aEntries[i * 2].uTag = 0;
    692     }
    693 
    694     pTlb->cTlbNonGlobalLargePageCurLoads    = 0;
    695     pTlb->NonGlobalLargePageRange.uLastTag  = 0;
    696     pTlb->NonGlobalLargePageRange.uFirstTag = UINT64_MAX;
    697 
    698     if (a_fGlobal)
    699     {
    700         pTlb->uTlbRevisionGlobal += IEMTLB_REVISION_INCR;
    701         if (RT_LIKELY(pTlb->uTlbRevisionGlobal != 0))
    702         { /* very likely */ }
    703         else
    704         {
    705             pTlb->uTlbRevisionGlobal = IEMTLB_REVISION_INCR;
    706             pTlb->cTlbRevisionRollovers++;
    707             unsigned i = RT_ELEMENTS(pTlb->aEntries) / 2;
    708             while (i-- > 0)
    709                 pTlb->aEntries[i * 2 + 1].uTag = 0;
    710         }
    711 
    712         pTlb->cTlbGlobalLargePageCurLoads    = 0;
    713         pTlb->GlobalLargePageRange.uLastTag  = 0;
    714         pTlb->GlobalLargePageRange.uFirstTag = UINT64_MAX;
    715     }
    716 }
    717 #endif
    718 
    719 
    720 /**
    721  * Worker for IEMTlbInvalidateAll and IEMTlbInvalidateAllGlobal.
    722  */
    723 template<bool a_fGlobal>
    724 DECL_FORCE_INLINE(void) iemTlbInvalidateAll(PVMCPUCC pVCpu)
    725 {
    726 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    727     Log10(("IEMTlbInvalidateAll\n"));
    728 
    729 # ifdef IEM_WITH_CODE_TLB
    730     pVCpu->iem.s.cbInstrBufTotal = 0;
    731     iemTlbInvalidateOne<a_fGlobal>(&pVCpu->iem.s.CodeTlb);
    732     if (a_fGlobal)
    733         IEMTLBTRACE_FLUSH_GLOBAL(pVCpu, pVCpu->iem.s.CodeTlb.uTlbRevision, pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal, false);
    734     else
    735         IEMTLBTRACE_FLUSH(pVCpu, pVCpu->iem.s.CodeTlb.uTlbRevision, false);
    736 # endif
    737 
    738 # ifdef IEM_WITH_DATA_TLB
    739     iemTlbInvalidateOne<a_fGlobal>(&pVCpu->iem.s.DataTlb);
    740     if (a_fGlobal)
    741         IEMTLBTRACE_FLUSH_GLOBAL(pVCpu, pVCpu->iem.s.DataTlb.uTlbRevision, pVCpu->iem.s.DataTlb.uTlbRevisionGlobal, true);
    742     else
    743         IEMTLBTRACE_FLUSH(pVCpu, pVCpu->iem.s.DataTlb.uTlbRevision, true);
    744 # endif
    745 #else
    746     RT_NOREF(pVCpu);
    747 #endif
    748 }
    749 
    750 
    751 /**
    752  * Invalidates non-global the IEM TLB entries.
    753  *
    754  * This is called internally as well as by PGM when moving GC mappings.
    755  *
    756  * @param   pVCpu       The cross context virtual CPU structure of the calling
    757  *                      thread.
    758  */
    759 VMM_INT_DECL(void) IEMTlbInvalidateAll(PVMCPUCC pVCpu)
    760 {
    761     iemTlbInvalidateAll<false>(pVCpu);
    762 }
    763 
    764 
    765 /**
    766  * Invalidates all the IEM TLB entries.
    767  *
    768  * This is called internally as well as by PGM when moving GC mappings.
    769  *
    770  * @param   pVCpu       The cross context virtual CPU structure of the calling
    771  *                      thread.
    772  */
    773 VMM_INT_DECL(void) IEMTlbInvalidateAllGlobal(PVMCPUCC pVCpu)
    774 {
    775     iemTlbInvalidateAll<true>(pVCpu);
    776 }
    777 
    778 
    779 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
     68
    78069
    78170/** @todo graduate this to cdefs.h or asm-mem.h.   */
     
    1165454#endif /* defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) */
    1166455
    1167 /**
    1168  * Invalidates a page in the TLBs.
    1169  *
    1170  * @param   pVCpu       The cross context virtual CPU structure of the calling
    1171  *                      thread.
    1172  * @param   GCPtr       The address of the page to invalidate
    1173  * @thread EMT(pVCpu)
    1174  */
    1175 VMM_INT_DECL(void) IEMTlbInvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCPtr)
    1176 {
    1177     IEMTLBTRACE_INVLPG(pVCpu, GCPtr);
    1178 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    1179     Log10(("IEMTlbInvalidatePage: GCPtr=%RGv\n", GCPtr));
    1180     GCPtr = IEMTLB_CALC_TAG_NO_REV(GCPtr);
    1181     Assert(!(GCPtr >> (48 - X86_PAGE_SHIFT)));
    1182     uintptr_t const idxEven = IEMTLB_TAG_TO_EVEN_INDEX(GCPtr);
    1183 
    1184 # ifdef IEM_WITH_CODE_TLB
    1185     iemTlbInvalidatePageWorker<false>(pVCpu, &pVCpu->iem.s.CodeTlb, GCPtr, idxEven);
    1186 # endif
    1187 # ifdef IEM_WITH_DATA_TLB
    1188     iemTlbInvalidatePageWorker<true>(pVCpu, &pVCpu->iem.s.DataTlb, GCPtr, idxEven);
    1189 # endif
    1190 #else
    1191     NOREF(pVCpu); NOREF(GCPtr);
    1192 #endif
    1193 }
    1194 
    1195 
    1196 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    1197 /**
    1198  * Invalid both TLBs slow fashion following a rollover.
    1199  *
    1200  * Worker for IEMTlbInvalidateAllPhysical,
    1201  * IEMTlbInvalidateAllPhysicalAllCpus, iemOpcodeFetchBytesJmp, iemMemMap,
    1202  * iemMemMapJmp and others.
    1203  *
    1204  * @thread EMT(pVCpu)
    1205  */
    1206 static void IEMTlbInvalidateAllPhysicalSlow(PVMCPUCC pVCpu)
    1207 {
    1208     Log10(("IEMTlbInvalidateAllPhysicalSlow\n"));
    1209     ASMAtomicWriteU64(&pVCpu->iem.s.CodeTlb.uTlbPhysRev, IEMTLB_PHYS_REV_INCR * 2);
    1210     ASMAtomicWriteU64(&pVCpu->iem.s.DataTlb.uTlbPhysRev, IEMTLB_PHYS_REV_INCR * 2);
    1211 
    1212     unsigned i;
    1213 # ifdef IEM_WITH_CODE_TLB
    1214     i = RT_ELEMENTS(pVCpu->iem.s.CodeTlb.aEntries);
    1215     while (i-- > 0)
    1216     {
    1217         pVCpu->iem.s.CodeTlb.aEntries[i].pbMappingR3       = NULL;
    1218         pVCpu->iem.s.CodeTlb.aEntries[i].fFlagsAndPhysRev &= ~(  IEMTLBE_F_PG_NO_WRITE   | IEMTLBE_F_PG_NO_READ
    1219                                                                | IEMTLBE_F_PG_UNASSIGNED | IEMTLBE_F_PHYS_REV);
    1220     }
    1221     pVCpu->iem.s.CodeTlb.cTlbPhysRevRollovers++;
    1222     pVCpu->iem.s.CodeTlb.cTlbPhysRevFlushes++;
    1223 # endif
    1224 # ifdef IEM_WITH_DATA_TLB
    1225     i = RT_ELEMENTS(pVCpu->iem.s.DataTlb.aEntries);
    1226     while (i-- > 0)
    1227     {
    1228         pVCpu->iem.s.DataTlb.aEntries[i].pbMappingR3       = NULL;
    1229         pVCpu->iem.s.DataTlb.aEntries[i].fFlagsAndPhysRev &= ~(  IEMTLBE_F_PG_NO_WRITE   | IEMTLBE_F_PG_NO_READ
    1230                                                                | IEMTLBE_F_PG_UNASSIGNED | IEMTLBE_F_PHYS_REV);
    1231     }
    1232     pVCpu->iem.s.DataTlb.cTlbPhysRevRollovers++;
    1233     pVCpu->iem.s.DataTlb.cTlbPhysRevFlushes++;
    1234 # endif
    1235 
    1236 }
    1237 #endif
    1238 
    1239 
    1240 /**
    1241  * Invalidates the host physical aspects of the IEM TLBs.
    1242  *
    1243  * This is called internally as well as by PGM when moving GC mappings.
    1244  *
    1245  * @param   pVCpu       The cross context virtual CPU structure of the calling
    1246  *                      thread.
    1247  * @note    Currently not used.
    1248  */
    1249 VMM_INT_DECL(void) IEMTlbInvalidateAllPhysical(PVMCPUCC pVCpu)
    1250 {
    1251 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    1252     /* Note! This probably won't end up looking exactly like this, but it give an idea... */
    1253     Log10(("IEMTlbInvalidateAllPhysical\n"));
    1254 
    1255 # ifdef IEM_WITH_CODE_TLB
    1256     pVCpu->iem.s.cbInstrBufTotal = 0;
    1257 # endif
    1258     uint64_t uTlbPhysRev = pVCpu->iem.s.CodeTlb.uTlbPhysRev + IEMTLB_PHYS_REV_INCR;
    1259     if (RT_LIKELY(uTlbPhysRev > IEMTLB_PHYS_REV_INCR * 2))
    1260     {
    1261         pVCpu->iem.s.CodeTlb.uTlbPhysRev = uTlbPhysRev;
    1262         pVCpu->iem.s.CodeTlb.cTlbPhysRevFlushes++;
    1263         pVCpu->iem.s.DataTlb.uTlbPhysRev = uTlbPhysRev;
    1264         pVCpu->iem.s.DataTlb.cTlbPhysRevFlushes++;
    1265     }
    1266     else
    1267         IEMTlbInvalidateAllPhysicalSlow(pVCpu);
    1268 #else
    1269     NOREF(pVCpu);
    1270 #endif
    1271 }
    1272 
    1273 
    1274 /**
    1275  * Invalidates the host physical aspects of the IEM TLBs.
    1276  *
    1277  * This is called internally as well as by PGM when moving GC mappings.
    1278  *
    1279  * @param   pVM         The cross context VM structure.
    1280  * @param   idCpuCaller The ID of the calling EMT if available to the caller,
    1281  *                      otherwise NIL_VMCPUID.
    1282  * @param   enmReason   The reason we're called.
    1283  *
    1284  * @remarks Caller holds the PGM lock.
    1285  */
    1286 VMM_INT_DECL(void) IEMTlbInvalidateAllPhysicalAllCpus(PVMCC pVM, VMCPUID idCpuCaller, IEMTLBPHYSFLUSHREASON enmReason)
    1287 {
    1288 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)
    1289     PVMCPUCC const pVCpuCaller = idCpuCaller >= pVM->cCpus ? VMMGetCpu(pVM) : VMMGetCpuById(pVM, idCpuCaller);
    1290     if (pVCpuCaller)
    1291         VMCPU_ASSERT_EMT(pVCpuCaller);
    1292     Log10(("IEMTlbInvalidateAllPhysicalAllCpus: %d\n", enmReason)); RT_NOREF(enmReason);
    1293 
    1294     VMCC_FOR_EACH_VMCPU(pVM)
    1295     {
    1296 # ifdef IEM_WITH_CODE_TLB
    1297         if (pVCpuCaller == pVCpu)
    1298             pVCpu->iem.s.cbInstrBufTotal = 0;
    1299 # endif
    1300 
    1301         uint64_t const uTlbPhysRevPrev = ASMAtomicUoReadU64(&pVCpu->iem.s.CodeTlb.uTlbPhysRev);
    1302         uint64_t       uTlbPhysRevNew  = uTlbPhysRevPrev + IEMTLB_PHYS_REV_INCR;
    1303         if (RT_LIKELY(uTlbPhysRevNew > IEMTLB_PHYS_REV_INCR * 2))
    1304         { /* likely */}
    1305         else if (pVCpuCaller != pVCpu)
    1306             uTlbPhysRevNew = IEMTLB_PHYS_REV_INCR;
    1307         else
    1308         {
    1309             IEMTlbInvalidateAllPhysicalSlow(pVCpu);
    1310             continue;
    1311         }
    1312         if (ASMAtomicCmpXchgU64(&pVCpu->iem.s.CodeTlb.uTlbPhysRev, uTlbPhysRevNew, uTlbPhysRevPrev))
    1313             pVCpu->iem.s.CodeTlb.cTlbPhysRevFlushes++;
    1314 
    1315         if (ASMAtomicCmpXchgU64(&pVCpu->iem.s.DataTlb.uTlbPhysRev, uTlbPhysRevNew, uTlbPhysRevPrev))
    1316             pVCpu->iem.s.DataTlb.cTlbPhysRevFlushes++;
    1317     }
    1318     VMCC_FOR_EACH_VMCPU_END(pVM);
    1319 
    1320 #else
    1321     RT_NOREF(pVM, idCpuCaller, enmReason);
    1322 #endif
    1323 }
    1324 
    1325 
    1326 /**
    1327  * Flushes the prefetch buffer, light version.
    1328  */
    1329 void iemOpcodeFlushLight(PVMCPUCC pVCpu, uint8_t cbInstr)
    1330 {
    1331 #ifndef IEM_WITH_CODE_TLB
    1332     pVCpu->iem.s.cbOpcode = cbInstr;
    1333 #else
    1334     RT_NOREF(pVCpu, cbInstr);
    1335 #endif
    1336 }
    1337 
    1338 
    1339 /**
    1340  * Flushes the prefetch buffer, heavy version.
    1341  */
    1342 void iemOpcodeFlushHeavy(PVMCPUCC pVCpu, uint8_t cbInstr)
    1343 {
    1344 #ifndef IEM_WITH_CODE_TLB
    1345     pVCpu->iem.s.cbOpcode = cbInstr; /* Note! SVM and VT-x may set this to zero on exit, rather than the instruction length. */
    1346 #elif 1
    1347     pVCpu->iem.s.cbInstrBufTotal = 0;
    1348     RT_NOREF(cbInstr);
    1349 #else
    1350     RT_NOREF(pVCpu, cbInstr);
    1351 #endif
    1352 }
    1353 
    1354 
    1355 
    1356 #ifdef IEM_WITH_CODE_TLB
    1357 
    1358 /**
    1359  * Tries to fetches @a cbDst opcode bytes, raise the appropriate exception on
    1360  * failure and jumps.
    1361  *
    1362  * We end up here for a number of reasons:
    1363  *      - pbInstrBuf isn't yet initialized.
    1364  *      - Advancing beyond the buffer boundrary (e.g. cross page).
    1365  *      - Advancing beyond the CS segment limit.
    1366  *      - Fetching from non-mappable page (e.g. MMIO).
    1367  *      - TLB loading in the recompiler (@a pvDst = NULL, @a cbDst = 0).
    1368  *
    1369  * @param   pVCpu               The cross context virtual CPU structure of the
    1370  *                              calling thread.
    1371  * @param   pvDst               Where to return the bytes.
    1372  * @param   cbDst               Number of bytes to read.  A value of zero is
    1373  *                              allowed for initializing pbInstrBuf (the
    1374  *                              recompiler does this).  In this case it is best
    1375  *                              to set pbInstrBuf to NULL prior to the call.
    1376  */
    1377 void iemOpcodeFetchBytesJmp(PVMCPUCC pVCpu, size_t cbDst, void *pvDst) IEM_NOEXCEPT_MAY_LONGJMP
    1378 {
    1379 # ifdef IN_RING3
    1380     for (;;)
    1381     {
    1382         Assert(cbDst <= 8);
    1383         uint32_t offBuf = pVCpu->iem.s.offInstrNextByte;
    1384 
    1385         /*
    1386          * We might have a partial buffer match, deal with that first to make the
    1387          * rest simpler.  This is the first part of the cross page/buffer case.
    1388          */
    1389         uint8_t const * const pbInstrBuf = pVCpu->iem.s.pbInstrBuf;
    1390         if (pbInstrBuf != NULL)
    1391         {
    1392             Assert(cbDst != 0); /* pbInstrBuf shall be NULL in case of a TLB load */
    1393             uint32_t const cbInstrBuf = pVCpu->iem.s.cbInstrBuf;
    1394             if (offBuf < cbInstrBuf)
    1395             {
    1396                 Assert(offBuf + cbDst > cbInstrBuf);
    1397                 uint32_t const cbCopy = cbInstrBuf - offBuf;
    1398                 memcpy(pvDst, &pbInstrBuf[offBuf], cbCopy);
    1399 
    1400                 cbDst  -= cbCopy;
    1401                 pvDst   = (uint8_t *)pvDst + cbCopy;
    1402                 offBuf += cbCopy;
    1403             }
    1404         }
    1405 
    1406         /*
    1407          * Check segment limit, figuring how much we're allowed to access at this point.
    1408          *
    1409          * We will fault immediately if RIP is past the segment limit / in non-canonical
    1410          * territory.  If we do continue, there are one or more bytes to read before we
    1411          * end up in trouble and we need to do that first before faulting.
    1412          */
    1413         RTGCPTR  GCPtrFirst;
    1414         uint32_t cbMaxRead;
    1415         if (IEM_IS_64BIT_CODE(pVCpu))
    1416         {
    1417             GCPtrFirst = pVCpu->cpum.GstCtx.rip + (offBuf - (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart);
    1418             if (RT_LIKELY(IEM_IS_CANONICAL(GCPtrFirst)))
    1419             { /* likely */ }
    1420             else
    1421                 iemRaiseGeneralProtectionFault0Jmp(pVCpu);
    1422             cbMaxRead = X86_PAGE_SIZE - ((uint32_t)GCPtrFirst & X86_PAGE_OFFSET_MASK);
    1423         }
    1424         else
    1425         {
    1426             GCPtrFirst = pVCpu->cpum.GstCtx.eip + (offBuf - (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart);
    1427             /* Assert(!(GCPtrFirst & ~(uint32_t)UINT16_MAX) || IEM_IS_32BIT_CODE(pVCpu)); - this is allowed */
    1428             if (RT_LIKELY((uint32_t)GCPtrFirst <= pVCpu->cpum.GstCtx.cs.u32Limit))
    1429             { /* likely */ }
    1430             else /** @todo For CPUs older than the 386, we should not necessarily generate \#GP here but wrap around! */
    1431                 iemRaiseSelectorBoundsJmp(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
    1432             cbMaxRead = pVCpu->cpum.GstCtx.cs.u32Limit - (uint32_t)GCPtrFirst + 1;
    1433             if (cbMaxRead != 0)
    1434             { /* likely */ }
    1435             else
    1436             {
    1437                 /* Overflowed because address is 0 and limit is max. */
    1438                 Assert(GCPtrFirst == 0); Assert(pVCpu->cpum.GstCtx.cs.u32Limit == UINT32_MAX);
    1439                 cbMaxRead = X86_PAGE_SIZE;
    1440             }
    1441             GCPtrFirst = (uint32_t)GCPtrFirst + (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base;
    1442             uint32_t cbMaxRead2 = X86_PAGE_SIZE - ((uint32_t)GCPtrFirst & X86_PAGE_OFFSET_MASK);
    1443             if (cbMaxRead2 < cbMaxRead)
    1444                 cbMaxRead = cbMaxRead2;
    1445             /** @todo testcase: unreal modes, both huge 16-bit and 32-bit. */
    1446         }
    1447 
    1448         /*
    1449          * Get the TLB entry for this piece of code.
    1450          */
    1451         uint64_t const uTagNoRev = IEMTLB_CALC_TAG_NO_REV(GCPtrFirst);
    1452         PIEMTLBENTRY   pTlbe     = IEMTLB_TAG_TO_EVEN_ENTRY(&pVCpu->iem.s.CodeTlb, uTagNoRev);
    1453         if (   pTlbe->uTag               == (uTagNoRev | pVCpu->iem.s.CodeTlb.uTlbRevision)
    1454             || (pTlbe = pTlbe + 1)->uTag == (uTagNoRev | pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal))
    1455         {
    1456             /* likely when executing lots of code, otherwise unlikely */
    1457 #  ifdef IEM_WITH_TLB_STATISTICS
    1458             pVCpu->iem.s.CodeTlb.cTlbCoreHits++;
    1459 #  endif
    1460             Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED));
    1461 
    1462             /* Check TLB page table level access flags. */
    1463             if (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_USER | IEMTLBE_F_PT_NO_EXEC))
    1464             {
    1465                 if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER) && IEM_GET_CPL(pVCpu) == 3)
    1466                 {
    1467                     Log(("iemOpcodeFetchBytesJmp: %RGv - supervisor page\n", GCPtrFirst));
    1468                     iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
    1469                 }
    1470                 if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_EXEC) && (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE))
    1471                 {
    1472                     Log(("iemOpcodeFetchMoreBytes: %RGv - NX\n", GCPtrFirst));
    1473                     iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
    1474                 }
    1475             }
    1476 
    1477             /* Look up the physical page info if necessary. */
    1478             if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pVCpu->iem.s.CodeTlb.uTlbPhysRev)
    1479             { /* not necessary */ }
    1480             else
    1481             {
    1482                 if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR))
    1483                 { /* likely */ }
    1484                 else
    1485                     IEMTlbInvalidateAllPhysicalSlow(pVCpu);
    1486                 pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK;
    1487                 int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.CodeTlb.uTlbPhysRev,
    1488                                                     &pTlbe->pbMappingR3, &pTlbe->fFlagsAndPhysRev);
    1489                 AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc));
    1490             }
    1491         }
    1492         else
    1493         {
    1494             pVCpu->iem.s.CodeTlb.cTlbCoreMisses++;
    1495 
    1496             /* This page table walking will set A bits as required by the access while performing the walk.
    1497                ASSUMES these are set when the address is translated rather than on commit... */
    1498             /** @todo testcase: check when A bits are actually set by the CPU for code.  */
    1499             PGMPTWALKFAST WalkFast;
    1500             int rc = PGMGstQueryPageFast(pVCpu, GCPtrFirst,
    1501                                          IEM_GET_CPL(pVCpu) == 3 ? PGMQPAGE_F_EXECUTE | PGMQPAGE_F_USER_MODE : PGMQPAGE_F_EXECUTE,
    1502                                          &WalkFast);
    1503             if (RT_SUCCESS(rc))
    1504                 Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
    1505             else
    1506             {
    1507 #  ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    1508                 /** @todo Nested VMX: Need to handle EPT violation/misconfig here?  OF COURSE! */
    1509                 Assert(!(Walk.fFailed & PGM_WALKFAIL_EPT));
    1510 #  endif
    1511                 Log(("iemOpcodeFetchMoreBytes: %RGv - rc=%Rrc\n", GCPtrFirst, rc));
    1512                 iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, rc);
    1513             }
    1514 
    1515             AssertCompile(IEMTLBE_F_PT_NO_EXEC == 1);
    1516             if (   !(WalkFast.fEffective & PGM_PTATTRS_G_MASK)
    1517                 || IEM_GET_CPL(pVCpu) != 0) /* optimization: Only use the PTE.G=1 entries in ring-0. */
    1518             {
    1519                 pTlbe--;
    1520                 pTlbe->uTag         = uTagNoRev | pVCpu->iem.s.CodeTlb.uTlbRevision;
    1521                 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE)
    1522                     iemTlbLoadedLargePage<false>(pVCpu, &pVCpu->iem.s.CodeTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE));
    1523 #  ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    1524                 else
    1525                     ASMBitClear(pVCpu->iem.s.CodeTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev));
    1526 #  endif
    1527             }
    1528             else
    1529             {
    1530                 pVCpu->iem.s.CodeTlb.cTlbCoreGlobalLoads++;
    1531                 pTlbe->uTag         = uTagNoRev | pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal;
    1532                 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE)
    1533                     iemTlbLoadedLargePage<true>(pVCpu, &pVCpu->iem.s.CodeTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE));
    1534 #  ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    1535                 else
    1536                     ASMBitClear(pVCpu->iem.s.CodeTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + 1);
    1537 #  endif
    1538             }
    1539             pTlbe->fFlagsAndPhysRev = (~WalkFast.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A))
    1540                                     | (WalkFast.fEffective >> X86_PTE_PAE_BIT_NX) /*IEMTLBE_F_PT_NO_EXEC*/
    1541                                     | (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE);
    1542             RTGCPHYS const GCPhysPg = WalkFast.GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
    1543             pTlbe->GCPhys           = GCPhysPg;
    1544             pTlbe->pbMappingR3      = NULL;
    1545             Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_EXEC) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE));
    1546             Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER) || IEM_GET_CPL(pVCpu) != 3);
    1547             Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED));
    1548 
    1549             if (!((uintptr_t)pTlbe & (sizeof(*pTlbe) * 2 - 1)))
    1550                 IEMTLBTRACE_LOAD(       pVCpu, GCPtrFirst, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, false);
    1551             else
    1552                 IEMTLBTRACE_LOAD_GLOBAL(pVCpu, GCPtrFirst, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, false);
    1553 
    1554             /* Resolve the physical address. */
    1555             if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR))
    1556             { /* likely */ }
    1557             else
    1558                 IEMTlbInvalidateAllPhysicalSlow(pVCpu);
    1559             Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_GCPHYS2PTR_MASK));
    1560             rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhysPg, &pVCpu->iem.s.CodeTlb.uTlbPhysRev,
    1561                                             &pTlbe->pbMappingR3, &pTlbe->fFlagsAndPhysRev);
    1562             AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc));
    1563         }
    1564 
    1565 # if defined(IN_RING3) || defined(IN_RING0) /** @todo fixme */
    1566         /*
    1567          * Try do a direct read using the pbMappingR3 pointer.
    1568          * Note! Do not recheck the physical TLB revision number here as we have the
    1569          *       wrong response to changes in the else case.  If someone is updating
    1570          *       pVCpu->iem.s.CodeTlb.uTlbPhysRev in parallel to us, we should be fine
    1571          *       pretending we always won the race.
    1572          */
    1573         if (    (pTlbe->fFlagsAndPhysRev & (/*IEMTLBE_F_PHYS_REV |*/ IEMTLBE_F_NO_MAPPINGR3 | IEMTLBE_F_PG_NO_READ))
    1574              == /*pVCpu->iem.s.CodeTlb.uTlbPhysRev*/ 0U)
    1575         {
    1576             uint32_t const offPg = (GCPtrFirst & X86_PAGE_OFFSET_MASK);
    1577             pVCpu->iem.s.cbInstrBufTotal = offPg + cbMaxRead;
    1578             if (offBuf == (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart)
    1579             {
    1580                 pVCpu->iem.s.cbInstrBuf       = offPg + RT_MIN(15, cbMaxRead);
    1581                 pVCpu->iem.s.offCurInstrStart = (int16_t)offPg;
    1582             }
    1583             else
    1584             {
    1585                 uint32_t const cbInstr = offBuf - (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart;
    1586                 if (cbInstr + (uint32_t)cbDst <= 15)
    1587                 {
    1588                     pVCpu->iem.s.cbInstrBuf       = offPg + RT_MIN(cbMaxRead + cbInstr, 15) - cbInstr;
    1589                     pVCpu->iem.s.offCurInstrStart = (int16_t)(offPg - cbInstr);
    1590                 }
    1591                 else
    1592                 {
    1593                     Log(("iemOpcodeFetchMoreBytes: %04x:%08RX64 LB %#x + %#zx -> #GP(0)\n",
    1594                          pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, cbInstr, cbDst));
    1595                     iemRaiseGeneralProtectionFault0Jmp(pVCpu);
    1596                 }
    1597             }
    1598             if (cbDst <= cbMaxRead)
    1599             {
    1600                 pVCpu->iem.s.fTbCrossedPage     |= offPg == 0 || pVCpu->iem.s.fTbBranched != 0; /** @todo Spurious load effect on branch handling? */
    1601 #  if 0 /* unused */
    1602                 pVCpu->iem.s.GCPhysInstrBufPrev  = pVCpu->iem.s.GCPhysInstrBuf;
    1603 #  endif
    1604                 pVCpu->iem.s.offInstrNextByte = offPg + (uint32_t)cbDst;
    1605                 pVCpu->iem.s.uInstrBufPc      = GCPtrFirst & ~(RTGCPTR)X86_PAGE_OFFSET_MASK;
    1606                 pVCpu->iem.s.GCPhysInstrBuf   = pTlbe->GCPhys;
    1607                 pVCpu->iem.s.pbInstrBuf       = pTlbe->pbMappingR3;
    1608                 if (cbDst > 0) /* To make ASAN happy in the TLB load case. */
    1609                     memcpy(pvDst, &pTlbe->pbMappingR3[offPg], cbDst);
    1610                 else
    1611                     Assert(!pvDst);
    1612                 return;
    1613             }
    1614             pVCpu->iem.s.pbInstrBuf = NULL;
    1615 
    1616             memcpy(pvDst, &pTlbe->pbMappingR3[offPg], cbMaxRead);
    1617             pVCpu->iem.s.offInstrNextByte = offPg + cbMaxRead;
    1618         }
    1619 # else
    1620 #  error "refactor as needed"
    1621         /*
    1622          * If there is no special read handling, so we can read a bit more and
    1623          * put it in the prefetch buffer.
    1624          */
    1625         if (   cbDst < cbMaxRead
    1626             && (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PHYS_REV | IEMTLBE_F_PG_NO_READ)) == pVCpu->iem.s.CodeTlb.uTlbPhysRev)
    1627         {
    1628             VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), pTlbe->GCPhys,
    1629                                                 &pVCpu->iem.s.abOpcode[0], cbToTryRead, PGMACCESSORIGIN_IEM);
    1630             if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    1631             { /* likely */ }
    1632             else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    1633             {
    1634                 Log(("iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status -  rcStrict=%Rrc\n",
    1635                      GCPtrNext, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead));
    1636                 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    1637                 AssertStmt(rcStrict == VINF_SUCCESS, IEM_DO_LONGJMP(pVCpu, VBOXSTRICRC_VAL(rcStrict)));
    1638             }
    1639             else
    1640             {
    1641                 Log((RT_SUCCESS(rcStrict)
    1642                      ? "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n"
    1643                      : "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n",
    1644                      GCPtrNext, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead));
    1645                 IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    1646             }
    1647         }
    1648 # endif
    1649         /*
    1650          * Special read handling, so only read exactly what's needed.
    1651          * This is a highly unlikely scenario.
    1652          */
    1653         else
    1654         {
    1655             pVCpu->iem.s.CodeTlb.cTlbSlowCodeReadPath++;
    1656 
    1657             /* Check instruction length. */
    1658             uint32_t const cbInstr = offBuf - (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart;
    1659             if (RT_LIKELY(cbInstr + cbDst <= 15))
    1660             { /* likely */ }
    1661             else
    1662             {
    1663                 Log(("iemOpcodeFetchMoreBytes: %04x:%08RX64 LB %#x + %#zx -> #GP(0) [slow]\n",
    1664                      pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, cbInstr, cbDst));
    1665                 iemRaiseGeneralProtectionFault0Jmp(pVCpu);
    1666             }
    1667 
    1668             /* Do the reading. */
    1669             uint32_t const cbToRead = RT_MIN((uint32_t)cbDst, cbMaxRead);
    1670             if (cbToRead > 0)
    1671             {
    1672                 VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK),
    1673                                                     pvDst, cbToRead, PGMACCESSORIGIN_IEM);
    1674                 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    1675                 { /* likely */ }
    1676                 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    1677                 {
    1678                     Log(("iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status -  rcStrict=%Rrc\n",
    1679                          GCPtrFirst, pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK), VBOXSTRICTRC_VAL(rcStrict), cbToRead));
    1680                     rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    1681                     AssertStmt(rcStrict == VINF_SUCCESS, IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict)));
    1682                 }
    1683                 else
    1684                 {
    1685                     Log((RT_SUCCESS(rcStrict)
    1686                          ? "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n"
    1687                          : "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n",
    1688                          GCPtrFirst, pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK), VBOXSTRICTRC_VAL(rcStrict), cbToRead));
    1689                     IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    1690                 }
    1691             }
    1692 
    1693             /* Update the state and probably return. */
    1694             uint32_t const offPg = (GCPtrFirst & X86_PAGE_OFFSET_MASK);
    1695             pVCpu->iem.s.fTbCrossedPage     |= offPg == 0 || pVCpu->iem.s.fTbBranched != 0;
    1696 #  if 0 /* unused */
    1697             pVCpu->iem.s.GCPhysInstrBufPrev  = pVCpu->iem.s.GCPhysInstrBuf;
    1698 #  endif
    1699             pVCpu->iem.s.offCurInstrStart = (int16_t)(offPg - cbInstr);
    1700             pVCpu->iem.s.offInstrNextByte = offPg + cbInstr + cbToRead;
    1701             pVCpu->iem.s.cbInstrBuf       = offPg + RT_MIN(15, cbMaxRead + cbInstr) - cbToRead - cbInstr;
    1702             pVCpu->iem.s.cbInstrBufTotal  = X86_PAGE_SIZE; /** @todo ??? */
    1703             pVCpu->iem.s.GCPhysInstrBuf   = pTlbe->GCPhys;
    1704             pVCpu->iem.s.uInstrBufPc      = GCPtrFirst & ~(RTGCPTR)X86_PAGE_OFFSET_MASK;
    1705             pVCpu->iem.s.pbInstrBuf       = NULL;
    1706             if (cbToRead == cbDst)
    1707                 return;
    1708             Assert(cbToRead == cbMaxRead);
    1709         }
    1710 
    1711         /*
    1712          * More to read, loop.
    1713          */
    1714         cbDst -= cbMaxRead;
    1715         pvDst  = (uint8_t *)pvDst + cbMaxRead;
    1716     }
    1717 # else  /* !IN_RING3 */
    1718     RT_NOREF(pvDst, cbDst);
    1719     if (pvDst || cbDst)
    1720         IEM_DO_LONGJMP(pVCpu, VERR_INTERNAL_ERROR);
    1721 # endif /* !IN_RING3 */
    1722 }
    1723 
    1724 #else /* !IEM_WITH_CODE_TLB */
    1725 
    1726 /**
    1727  * Try fetch at least @a cbMin bytes more opcodes, raise the appropriate
    1728  * exception if it fails.
    1729  *
    1730  * @returns Strict VBox status code.
    1731  * @param   pVCpu               The cross context virtual CPU structure of the
    1732  *                              calling thread.
    1733  * @param   cbMin               The minimum number of bytes relative offOpcode
    1734  *                              that must be read.
    1735  */
    1736 VBOXSTRICTRC iemOpcodeFetchMoreBytes(PVMCPUCC pVCpu, size_t cbMin) RT_NOEXCEPT
    1737 {
    1738     /*
    1739      * What we're doing here is very similar to iemMemMap/iemMemBounceBufferMap.
    1740      *
    1741      * First translate CS:rIP to a physical address.
    1742      */
    1743     uint8_t const   cbOpcode  = pVCpu->iem.s.cbOpcode;
    1744     uint8_t const   offOpcode = pVCpu->iem.s.offOpcode;
    1745     uint8_t const   cbLeft    = cbOpcode - offOpcode;
    1746     Assert(cbLeft < cbMin);
    1747     Assert(cbOpcode <= sizeof(pVCpu->iem.s.abOpcode));
    1748 
    1749     uint32_t        cbToTryRead;
    1750     RTGCPTR         GCPtrNext;
    1751     if (IEM_IS_64BIT_CODE(pVCpu))
    1752     {
    1753         GCPtrNext   = pVCpu->cpum.GstCtx.rip + cbOpcode;
    1754         if (!IEM_IS_CANONICAL(GCPtrNext))
    1755             return iemRaiseGeneralProtectionFault0(pVCpu);
    1756         cbToTryRead = GUEST_PAGE_SIZE - (GCPtrNext & GUEST_PAGE_OFFSET_MASK);
    1757     }
    1758     else
    1759     {
    1760         uint32_t GCPtrNext32 = pVCpu->cpum.GstCtx.eip;
    1761         /* Assert(!(GCPtrNext32 & ~(uint32_t)UINT16_MAX) || IEM_IS_32BIT_CODE(pVCpu)); - this is allowed */
    1762         GCPtrNext32 += cbOpcode;
    1763         if (GCPtrNext32 > pVCpu->cpum.GstCtx.cs.u32Limit)
    1764             /** @todo For CPUs older than the 386, we should not generate \#GP here but wrap around! */
    1765             return iemRaiseSelectorBounds(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
    1766         cbToTryRead = pVCpu->cpum.GstCtx.cs.u32Limit - GCPtrNext32 + 1;
    1767         if (!cbToTryRead) /* overflowed */
    1768         {
    1769             Assert(GCPtrNext32 == 0); Assert(pVCpu->cpum.GstCtx.cs.u32Limit == UINT32_MAX);
    1770             cbToTryRead = UINT32_MAX;
    1771             /** @todo check out wrapping around the code segment.  */
    1772         }
    1773         if (cbToTryRead < cbMin - cbLeft)
    1774             return iemRaiseSelectorBounds(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
    1775         GCPtrNext = (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base + GCPtrNext32;
    1776 
    1777         uint32_t cbLeftOnPage = GUEST_PAGE_SIZE - (GCPtrNext & GUEST_PAGE_OFFSET_MASK);
    1778         if (cbToTryRead > cbLeftOnPage)
    1779             cbToTryRead = cbLeftOnPage;
    1780     }
    1781 
    1782     /* Restrict to opcode buffer space.
    1783 
    1784        We're making ASSUMPTIONS here based on work done previously in
    1785        iemInitDecoderAndPrefetchOpcodes, where bytes from the first page will
    1786        be fetched in case of an instruction crossing two pages. */
    1787     if (cbToTryRead > sizeof(pVCpu->iem.s.abOpcode) - cbOpcode)
    1788         cbToTryRead = sizeof(pVCpu->iem.s.abOpcode) - cbOpcode;
    1789     if (RT_LIKELY(cbToTryRead + cbLeft >= cbMin))
    1790     { /* likely */ }
    1791     else
    1792     {
    1793         Log(("iemOpcodeFetchMoreBytes: %04x:%08RX64 LB %#x + %#zx -> #GP(0)\n",
    1794              pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, offOpcode, cbMin));
    1795         return iemRaiseGeneralProtectionFault0(pVCpu);
    1796     }
    1797 
    1798     PGMPTWALKFAST WalkFast;
    1799     int rc = PGMGstQueryPageFast(pVCpu, GCPtrNext,
    1800                                  IEM_GET_CPL(pVCpu) == 3 ? PGMQPAGE_F_EXECUTE | PGMQPAGE_F_USER_MODE : PGMQPAGE_F_EXECUTE,
    1801                                  &WalkFast);
    1802     if (RT_SUCCESS(rc))
    1803         Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
    1804     else
    1805     {
    1806         Log(("iemOpcodeFetchMoreBytes: %RGv - rc=%Rrc\n", GCPtrNext, rc));
    1807 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    1808         if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    1809             IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
    1810 #endif
    1811         return iemRaisePageFault(pVCpu, GCPtrNext, 1, IEM_ACCESS_INSTRUCTION, rc);
    1812     }
    1813     Assert((WalkFast.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3);
    1814     Assert(!(WalkFast.fEffective & X86_PTE_PAE_NX) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE));
    1815 
    1816     RTGCPHYS const GCPhys = WalkFast.GCPhys;
    1817     Log5(("GCPtrNext=%RGv GCPhys=%RGp cbOpcodes=%#x\n",  GCPtrNext,  GCPhys, cbOpcode));
    1818 
    1819     /*
    1820      * Read the bytes at this address.
    1821      *
    1822      * We read all unpatched bytes in iemInitDecoderAndPrefetchOpcodes already,
    1823      * and since PATM should only patch the start of an instruction there
    1824      * should be no need to check again here.
    1825      */
    1826     if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))
    1827     {
    1828         VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), GCPhys, &pVCpu->iem.s.abOpcode[cbOpcode],
    1829                                             cbToTryRead, PGMACCESSORIGIN_IEM);
    1830         if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    1831         { /* likely */ }
    1832         else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    1833         {
    1834             Log(("iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status -  rcStrict=%Rrc\n",
    1835                  GCPtrNext, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead));
    1836             rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    1837         }
    1838         else
    1839         {
    1840             Log((RT_SUCCESS(rcStrict)
    1841                  ? "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n"
    1842                  : "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n",
    1843                  GCPtrNext, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead));
    1844             return rcStrict;
    1845         }
    1846     }
    1847     else
    1848     {
    1849         rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.abOpcode[cbOpcode], GCPhys, cbToTryRead);
    1850         if (RT_SUCCESS(rc))
    1851         { /* likely */ }
    1852         else
    1853         {
    1854             Log(("iemOpcodeFetchMoreBytes: %RGv - read error - rc=%Rrc (!!)\n", GCPtrNext, rc));
    1855             return rc;
    1856         }
    1857     }
    1858     pVCpu->iem.s.cbOpcode = cbOpcode + cbToTryRead;
    1859     Log5(("%.*Rhxs\n", pVCpu->iem.s.cbOpcode, pVCpu->iem.s.abOpcode));
    1860 
    1861     return VINF_SUCCESS;
    1862 }
    1863 
    1864 #endif /* !IEM_WITH_CODE_TLB */
    1865 #ifndef IEM_WITH_SETJMP
    1866 
    1867 /**
    1868  * Deals with the problematic cases that iemOpcodeGetNextU8 doesn't like.
    1869  *
    1870  * @returns Strict VBox status code.
    1871  * @param   pVCpu               The cross context virtual CPU structure of the
    1872  *                              calling thread.
    1873  * @param   pb                  Where to return the opcode byte.
    1874  */
    1875 VBOXSTRICTRC iemOpcodeGetNextU8Slow(PVMCPUCC pVCpu, uint8_t *pb) RT_NOEXCEPT
    1876 {
    1877     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 1);
    1878     if (rcStrict == VINF_SUCCESS)
    1879     {
    1880         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    1881         *pb = pVCpu->iem.s.abOpcode[offOpcode];
    1882         pVCpu->iem.s.offOpcode = offOpcode + 1;
    1883     }
    1884     else
    1885         *pb = 0;
    1886     return rcStrict;
    1887 }
    1888 
    1889 #else  /* IEM_WITH_SETJMP */
    1890 
    1891 /**
    1892  * Deals with the problematic cases that iemOpcodeGetNextU8Jmp doesn't like, longjmp on error.
    1893  *
    1894  * @returns The opcode byte.
    1895  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    1896  */
    1897 uint8_t iemOpcodeGetNextU8SlowJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
    1898 {
    1899 # ifdef IEM_WITH_CODE_TLB
    1900     uint8_t u8;
    1901     iemOpcodeFetchBytesJmp(pVCpu, sizeof(u8), &u8);
    1902     return u8;
    1903 # else
    1904     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 1);
    1905     if (rcStrict == VINF_SUCCESS)
    1906         return pVCpu->iem.s.abOpcode[pVCpu->iem.s.offOpcode++];
    1907     IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    1908 # endif
    1909 }
    1910 
    1911 #endif /* IEM_WITH_SETJMP */
    1912 
    1913 #ifndef IEM_WITH_SETJMP
    1914 
    1915 /**
    1916  * Deals with the problematic cases that iemOpcodeGetNextS8SxU16 doesn't like.
    1917  *
    1918  * @returns Strict VBox status code.
    1919  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    1920  * @param   pu16                Where to return the opcode dword.
    1921  */
    1922 VBOXSTRICTRC iemOpcodeGetNextS8SxU16Slow(PVMCPUCC pVCpu, uint16_t *pu16) RT_NOEXCEPT
    1923 {
    1924     uint8_t      u8;
    1925     VBOXSTRICTRC rcStrict = iemOpcodeGetNextU8Slow(pVCpu, &u8);
    1926     if (rcStrict == VINF_SUCCESS)
    1927         *pu16 = (int8_t)u8;
    1928     return rcStrict;
    1929 }
    1930 
    1931 
    1932 /**
    1933  * Deals with the problematic cases that iemOpcodeGetNextS8SxU32 doesn't like.
    1934  *
    1935  * @returns Strict VBox status code.
    1936  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    1937  * @param   pu32                Where to return the opcode dword.
    1938  */
    1939 VBOXSTRICTRC iemOpcodeGetNextS8SxU32Slow(PVMCPUCC pVCpu, uint32_t *pu32) RT_NOEXCEPT
    1940 {
    1941     uint8_t      u8;
    1942     VBOXSTRICTRC rcStrict = iemOpcodeGetNextU8Slow(pVCpu, &u8);
    1943     if (rcStrict == VINF_SUCCESS)
    1944         *pu32 = (int8_t)u8;
    1945     return rcStrict;
    1946 }
    1947 
    1948 
    1949 /**
    1950  * Deals with the problematic cases that iemOpcodeGetNextS8SxU64 doesn't like.
    1951  *
    1952  * @returns Strict VBox status code.
    1953  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    1954  * @param   pu64                Where to return the opcode qword.
    1955  */
    1956 VBOXSTRICTRC iemOpcodeGetNextS8SxU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
    1957 {
    1958     uint8_t      u8;
    1959     VBOXSTRICTRC rcStrict = iemOpcodeGetNextU8Slow(pVCpu, &u8);
    1960     if (rcStrict == VINF_SUCCESS)
    1961         *pu64 = (int8_t)u8;
    1962     return rcStrict;
    1963 }
    1964 
    1965 #endif /* !IEM_WITH_SETJMP */
    1966 
    1967 
    1968 #ifndef IEM_WITH_SETJMP
    1969 
    1970 /**
    1971  * Deals with the problematic cases that iemOpcodeGetNextU16 doesn't like.
    1972  *
    1973  * @returns Strict VBox status code.
    1974  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    1975  * @param   pu16                Where to return the opcode word.
    1976  */
    1977 VBOXSTRICTRC iemOpcodeGetNextU16Slow(PVMCPUCC pVCpu, uint16_t *pu16) RT_NOEXCEPT
    1978 {
    1979     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 2);
    1980     if (rcStrict == VINF_SUCCESS)
    1981     {
    1982         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    1983 # ifdef IEM_USE_UNALIGNED_DATA_ACCESS
    1984         *pu16 = *(uint16_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
    1985 # else
    1986         *pu16 = RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]);
    1987 # endif
    1988         pVCpu->iem.s.offOpcode = offOpcode + 2;
    1989     }
    1990     else
    1991         *pu16 = 0;
    1992     return rcStrict;
    1993 }
    1994 
    1995 #else  /* IEM_WITH_SETJMP */
    1996 
    1997 /**
    1998  * Deals with the problematic cases that iemOpcodeGetNextU16Jmp doesn't like, longjmp on error
    1999  *
    2000  * @returns The opcode word.
    2001  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2002  */
    2003 uint16_t iemOpcodeGetNextU16SlowJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
    2004 {
    2005 # ifdef IEM_WITH_CODE_TLB
    2006     uint16_t u16;
    2007     iemOpcodeFetchBytesJmp(pVCpu, sizeof(u16), &u16);
    2008     return u16;
    2009 # else
    2010     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 2);
    2011     if (rcStrict == VINF_SUCCESS)
    2012     {
    2013         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2014         pVCpu->iem.s.offOpcode += 2;
    2015 #  ifdef IEM_USE_UNALIGNED_DATA_ACCESS
    2016         return *(uint16_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
    2017 #  else
    2018         return RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]);
    2019 #  endif
    2020     }
    2021     IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    2022 # endif
    2023 }
    2024 
    2025 #endif /* IEM_WITH_SETJMP */
    2026 
    2027 #ifndef IEM_WITH_SETJMP
    2028 
    2029 /**
    2030  * Deals with the problematic cases that iemOpcodeGetNextU16ZxU32 doesn't like.
    2031  *
    2032  * @returns Strict VBox status code.
    2033  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2034  * @param   pu32                Where to return the opcode double word.
    2035  */
    2036 VBOXSTRICTRC iemOpcodeGetNextU16ZxU32Slow(PVMCPUCC pVCpu, uint32_t *pu32) RT_NOEXCEPT
    2037 {
    2038     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 2);
    2039     if (rcStrict == VINF_SUCCESS)
    2040     {
    2041         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2042         *pu32 = RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]);
    2043         pVCpu->iem.s.offOpcode = offOpcode + 2;
    2044     }
    2045     else
    2046         *pu32 = 0;
    2047     return rcStrict;
    2048 }
    2049 
    2050 
    2051 /**
    2052  * Deals with the problematic cases that iemOpcodeGetNextU16ZxU64 doesn't like.
    2053  *
    2054  * @returns Strict VBox status code.
    2055  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2056  * @param   pu64                Where to return the opcode quad word.
    2057  */
    2058 VBOXSTRICTRC iemOpcodeGetNextU16ZxU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
    2059 {
    2060     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 2);
    2061     if (rcStrict == VINF_SUCCESS)
    2062     {
    2063         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2064         *pu64 = RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]);
    2065         pVCpu->iem.s.offOpcode = offOpcode + 2;
    2066     }
    2067     else
    2068         *pu64 = 0;
    2069     return rcStrict;
    2070 }
    2071 
    2072 #endif /* !IEM_WITH_SETJMP */
    2073 
    2074 #ifndef IEM_WITH_SETJMP
    2075 
    2076 /**
    2077  * Deals with the problematic cases that iemOpcodeGetNextU32 doesn't like.
    2078  *
    2079  * @returns Strict VBox status code.
    2080  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2081  * @param   pu32                Where to return the opcode dword.
    2082  */
    2083 VBOXSTRICTRC iemOpcodeGetNextU32Slow(PVMCPUCC pVCpu, uint32_t *pu32) RT_NOEXCEPT
    2084 {
    2085     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 4);
    2086     if (rcStrict == VINF_SUCCESS)
    2087     {
    2088         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2089 # ifdef IEM_USE_UNALIGNED_DATA_ACCESS
    2090         *pu32 = *(uint32_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
    2091 # else
    2092         *pu32 = RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
    2093                                     pVCpu->iem.s.abOpcode[offOpcode + 1],
    2094                                     pVCpu->iem.s.abOpcode[offOpcode + 2],
    2095                                     pVCpu->iem.s.abOpcode[offOpcode + 3]);
    2096 # endif
    2097         pVCpu->iem.s.offOpcode = offOpcode + 4;
    2098     }
    2099     else
    2100         *pu32 = 0;
    2101     return rcStrict;
    2102 }
    2103 
    2104 #else  /* IEM_WITH_SETJMP */
    2105 
    2106 /**
    2107  * Deals with the problematic cases that iemOpcodeGetNextU32Jmp doesn't like, longjmp on error.
    2108  *
    2109  * @returns The opcode dword.
    2110  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2111  */
    2112 uint32_t iemOpcodeGetNextU32SlowJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
    2113 {
    2114 # ifdef IEM_WITH_CODE_TLB
    2115     uint32_t u32;
    2116     iemOpcodeFetchBytesJmp(pVCpu, sizeof(u32), &u32);
    2117     return u32;
    2118 # else
    2119     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 4);
    2120     if (rcStrict == VINF_SUCCESS)
    2121     {
    2122         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2123         pVCpu->iem.s.offOpcode = offOpcode + 4;
    2124 #  ifdef IEM_USE_UNALIGNED_DATA_ACCESS
    2125         return *(uint32_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
    2126 #  else
    2127         return RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
    2128                                    pVCpu->iem.s.abOpcode[offOpcode + 1],
    2129                                    pVCpu->iem.s.abOpcode[offOpcode + 2],
    2130                                    pVCpu->iem.s.abOpcode[offOpcode + 3]);
    2131 #  endif
    2132     }
    2133     IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    2134 # endif
    2135 }
    2136 
    2137 #endif /* IEM_WITH_SETJMP */
    2138 
    2139 #ifndef IEM_WITH_SETJMP
    2140 
    2141 /**
    2142  * Deals with the problematic cases that iemOpcodeGetNextU32ZxU64 doesn't like.
    2143  *
    2144  * @returns Strict VBox status code.
    2145  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2146  * @param   pu64                Where to return the opcode dword.
    2147  */
    2148 VBOXSTRICTRC iemOpcodeGetNextU32ZxU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
    2149 {
    2150     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 4);
    2151     if (rcStrict == VINF_SUCCESS)
    2152     {
    2153         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2154         *pu64 = RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
    2155                                     pVCpu->iem.s.abOpcode[offOpcode + 1],
    2156                                     pVCpu->iem.s.abOpcode[offOpcode + 2],
    2157                                     pVCpu->iem.s.abOpcode[offOpcode + 3]);
    2158         pVCpu->iem.s.offOpcode = offOpcode + 4;
    2159     }
    2160     else
    2161         *pu64 = 0;
    2162     return rcStrict;
    2163 }
    2164 
    2165 
    2166 /**
    2167  * Deals with the problematic cases that iemOpcodeGetNextS32SxU64 doesn't like.
    2168  *
    2169  * @returns Strict VBox status code.
    2170  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2171  * @param   pu64                Where to return the opcode qword.
    2172  */
    2173 VBOXSTRICTRC iemOpcodeGetNextS32SxU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
    2174 {
    2175     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 4);
    2176     if (rcStrict == VINF_SUCCESS)
    2177     {
    2178         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2179         *pu64 = (int32_t)RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
    2180                                              pVCpu->iem.s.abOpcode[offOpcode + 1],
    2181                                              pVCpu->iem.s.abOpcode[offOpcode + 2],
    2182                                              pVCpu->iem.s.abOpcode[offOpcode + 3]);
    2183         pVCpu->iem.s.offOpcode = offOpcode + 4;
    2184     }
    2185     else
    2186         *pu64 = 0;
    2187     return rcStrict;
    2188 }
    2189 
    2190 #endif /* !IEM_WITH_SETJMP */
    2191 
    2192 #ifndef IEM_WITH_SETJMP
    2193 
    2194 /**
    2195  * Deals with the problematic cases that iemOpcodeGetNextU64 doesn't like.
    2196  *
    2197  * @returns Strict VBox status code.
    2198  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2199  * @param   pu64                Where to return the opcode qword.
    2200  */
    2201 VBOXSTRICTRC iemOpcodeGetNextU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
    2202 {
    2203     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 8);
    2204     if (rcStrict == VINF_SUCCESS)
    2205     {
    2206         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2207 # ifdef IEM_USE_UNALIGNED_DATA_ACCESS
    2208         *pu64 = *(uint64_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
    2209 # else
    2210         *pu64 = RT_MAKE_U64_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
    2211                                     pVCpu->iem.s.abOpcode[offOpcode + 1],
    2212                                     pVCpu->iem.s.abOpcode[offOpcode + 2],
    2213                                     pVCpu->iem.s.abOpcode[offOpcode + 3],
    2214                                     pVCpu->iem.s.abOpcode[offOpcode + 4],
    2215                                     pVCpu->iem.s.abOpcode[offOpcode + 5],
    2216                                     pVCpu->iem.s.abOpcode[offOpcode + 6],
    2217                                     pVCpu->iem.s.abOpcode[offOpcode + 7]);
    2218 # endif
    2219         pVCpu->iem.s.offOpcode = offOpcode + 8;
    2220     }
    2221     else
    2222         *pu64 = 0;
    2223     return rcStrict;
    2224 }
    2225 
    2226 #else  /* IEM_WITH_SETJMP */
    2227 
    2228 /**
    2229  * Deals with the problematic cases that iemOpcodeGetNextU64Jmp doesn't like, longjmp on error.
    2230  *
    2231  * @returns The opcode qword.
    2232  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2233  */
    2234 uint64_t iemOpcodeGetNextU64SlowJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
    2235 {
    2236 # ifdef IEM_WITH_CODE_TLB
    2237     uint64_t u64;
    2238     iemOpcodeFetchBytesJmp(pVCpu, sizeof(u64), &u64);
    2239     return u64;
    2240 # else
    2241     VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 8);
    2242     if (rcStrict == VINF_SUCCESS)
    2243     {
    2244         uint8_t offOpcode = pVCpu->iem.s.offOpcode;
    2245         pVCpu->iem.s.offOpcode = offOpcode + 8;
    2246 #  ifdef IEM_USE_UNALIGNED_DATA_ACCESS
    2247         return *(uint64_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
    2248 #  else
    2249         return RT_MAKE_U64_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
    2250                                    pVCpu->iem.s.abOpcode[offOpcode + 1],
    2251                                    pVCpu->iem.s.abOpcode[offOpcode + 2],
    2252                                    pVCpu->iem.s.abOpcode[offOpcode + 3],
    2253                                    pVCpu->iem.s.abOpcode[offOpcode + 4],
    2254                                    pVCpu->iem.s.abOpcode[offOpcode + 5],
    2255                                    pVCpu->iem.s.abOpcode[offOpcode + 6],
    2256                                    pVCpu->iem.s.abOpcode[offOpcode + 7]);
    2257 #  endif
    2258     }
    2259     IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    2260 # endif
    2261 }
    2262 
    2263 #endif /* IEM_WITH_SETJMP */
    2264 
    2265 
    2266 
    2267 /** @name   Register Access.
    2268  * @{
    2269  */
    2270 
    2271 /**
    2272  * Adds a 8-bit signed jump offset to RIP/EIP/IP.
    2273  *
    2274  * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
    2275  * segment limit.
    2276  *
    2277  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2278  * @param   cbInstr             Instruction size.
    2279  * @param   offNextInstr        The offset of the next instruction.
    2280  * @param   enmEffOpSize        Effective operand size.
    2281  */
    2282 VBOXSTRICTRC iemRegRipRelativeJumpS8AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int8_t offNextInstr,
    2283                                                         IEMMODE enmEffOpSize) RT_NOEXCEPT
    2284 {
    2285     switch (enmEffOpSize)
    2286     {
    2287         case IEMMODE_16BIT:
    2288         {
    2289             uint16_t const uNewIp = pVCpu->cpum.GstCtx.ip + cbInstr + (int16_t)offNextInstr;
    2290             if (RT_LIKELY(   uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit
    2291                           || IEM_IS_64BIT_CODE(pVCpu) /* no CS limit checks in 64-bit mode */))
    2292                 pVCpu->cpum.GstCtx.rip = uNewIp;
    2293             else
    2294                 return iemRaiseGeneralProtectionFault0(pVCpu);
    2295             break;
    2296         }
    2297 
    2298         case IEMMODE_32BIT:
    2299         {
    2300             Assert(!IEM_IS_64BIT_CODE(pVCpu));
    2301             Assert(pVCpu->cpum.GstCtx.rip <= UINT32_MAX);
    2302 
    2303             uint32_t const uNewEip = pVCpu->cpum.GstCtx.eip + cbInstr + (int32_t)offNextInstr;
    2304             if (RT_LIKELY(uNewEip <= pVCpu->cpum.GstCtx.cs.u32Limit))
    2305                 pVCpu->cpum.GstCtx.rip = uNewEip;
    2306             else
    2307                 return iemRaiseGeneralProtectionFault0(pVCpu);
    2308             break;
    2309         }
    2310 
    2311         case IEMMODE_64BIT:
    2312         {
    2313             Assert(IEM_IS_64BIT_CODE(pVCpu));
    2314 
    2315             uint64_t const uNewRip = pVCpu->cpum.GstCtx.rip + cbInstr + (int64_t)offNextInstr;
    2316             if (RT_LIKELY(IEM_IS_CANONICAL(uNewRip)))
    2317                 pVCpu->cpum.GstCtx.rip = uNewRip;
    2318             else
    2319                 return iemRaiseGeneralProtectionFault0(pVCpu);
    2320             break;
    2321         }
    2322 
    2323         IEM_NOT_REACHED_DEFAULT_CASE_RET();
    2324     }
    2325 
    2326 #ifndef IEM_WITH_CODE_TLB
    2327     /* Flush the prefetch buffer. */
    2328     pVCpu->iem.s.cbOpcode = cbInstr;
    2329 #endif
    2330 
    2331     /*
    2332      * Clear RF and finish the instruction (maybe raise #DB).
    2333      */
    2334     return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
    2335 }
    2336 
    2337 
    2338 /**
    2339  * Adds a 16-bit signed jump offset to RIP/EIP/IP.
    2340  *
    2341  * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
    2342  * segment limit.
    2343  *
    2344  * @returns Strict VBox status code.
    2345  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2346  * @param   cbInstr             Instruction size.
    2347  * @param   offNextInstr        The offset of the next instruction.
    2348  */
    2349 VBOXSTRICTRC iemRegRipRelativeJumpS16AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int16_t offNextInstr) RT_NOEXCEPT
    2350 {
    2351     Assert(pVCpu->iem.s.enmEffOpSize == IEMMODE_16BIT);
    2352 
    2353     uint16_t const uNewIp = pVCpu->cpum.GstCtx.ip + cbInstr + offNextInstr;
    2354     if (RT_LIKELY(   uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit
    2355                   || IEM_IS_64BIT_CODE(pVCpu) /* no limit checking in 64-bit mode */))
    2356         pVCpu->cpum.GstCtx.rip = uNewIp;
    2357     else
    2358         return iemRaiseGeneralProtectionFault0(pVCpu);
    2359 
    2360 #ifndef IEM_WITH_CODE_TLB
    2361     /* Flush the prefetch buffer. */
    2362     pVCpu->iem.s.cbOpcode = IEM_GET_INSTR_LEN(pVCpu);
    2363 #endif
    2364 
    2365     /*
    2366      * Clear RF and finish the instruction (maybe raise #DB).
    2367      */
    2368     return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
    2369 }
    2370 
    2371 
    2372 /**
    2373  * Adds a 32-bit signed jump offset to RIP/EIP/IP.
    2374  *
    2375  * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
    2376  * segment limit.
    2377  *
    2378  * @returns Strict VBox status code.
    2379  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2380  * @param   cbInstr             Instruction size.
    2381  * @param   offNextInstr        The offset of the next instruction.
    2382  * @param   enmEffOpSize        Effective operand size.
    2383  */
    2384 VBOXSTRICTRC iemRegRipRelativeJumpS32AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int32_t offNextInstr,
    2385                                                          IEMMODE enmEffOpSize) RT_NOEXCEPT
    2386 {
    2387     if (enmEffOpSize == IEMMODE_32BIT)
    2388     {
    2389         Assert(pVCpu->cpum.GstCtx.rip <= UINT32_MAX); Assert(!IEM_IS_64BIT_CODE(pVCpu));
    2390 
    2391         uint32_t const uNewEip = pVCpu->cpum.GstCtx.eip + cbInstr + offNextInstr;
    2392         if (RT_LIKELY(uNewEip <= pVCpu->cpum.GstCtx.cs.u32Limit))
    2393             pVCpu->cpum.GstCtx.rip = uNewEip;
    2394         else
    2395             return iemRaiseGeneralProtectionFault0(pVCpu);
    2396     }
    2397     else
    2398     {
    2399         Assert(enmEffOpSize == IEMMODE_64BIT);
    2400 
    2401         uint64_t const uNewRip = pVCpu->cpum.GstCtx.rip + cbInstr + (int64_t)offNextInstr;
    2402         if (RT_LIKELY(IEM_IS_CANONICAL(uNewRip)))
    2403             pVCpu->cpum.GstCtx.rip = uNewRip;
    2404         else
    2405             return iemRaiseGeneralProtectionFault0(pVCpu);
    2406     }
    2407 
    2408 #ifndef IEM_WITH_CODE_TLB
    2409     /* Flush the prefetch buffer. */
    2410     pVCpu->iem.s.cbOpcode = IEM_GET_INSTR_LEN(pVCpu);
    2411 #endif
    2412 
    2413     /*
    2414      * Clear RF and finish the instruction (maybe raise #DB).
    2415      */
    2416     return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
    2417 }
    2418 
    2419 /** @}  */
    2420 
    2421 
    2422 /** @name   Memory access.
    2423  *
    2424  * @{
    2425  */
    2426 
    2427 #undef  LOG_GROUP
    2428 #define LOG_GROUP LOG_GROUP_IEM_MEM
    2429 
    2430 /**
    2431  * Applies the segment limit, base and attributes.
    2432  *
    2433  * This may raise a \#GP or \#SS.
    2434  *
    2435  * @returns VBox strict status code.
    2436  *
    2437  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2438  * @param   fAccess             The kind of access which is being performed.
    2439  * @param   iSegReg             The index of the segment register to apply.
    2440  *                              This is UINT8_MAX if none (for IDT, GDT, LDT,
    2441  *                              TSS, ++).
    2442  * @param   cbMem               The access size.
    2443  * @param   pGCPtrMem           Pointer to the guest memory address to apply
    2444  *                              segmentation to.  Input and output parameter.
    2445  */
    2446 VBOXSTRICTRC iemMemApplySegment(PVMCPUCC pVCpu, uint32_t fAccess, uint8_t iSegReg, size_t cbMem, PRTGCPTR pGCPtrMem) RT_NOEXCEPT
    2447 {
    2448     if (iSegReg == UINT8_MAX)
    2449         return VINF_SUCCESS;
    2450 
    2451     IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
    2452     PCPUMSELREGHID pSel = iemSRegGetHid(pVCpu, iSegReg);
    2453     switch (IEM_GET_CPU_MODE(pVCpu))
    2454     {
    2455         case IEMMODE_16BIT:
    2456         case IEMMODE_32BIT:
    2457         {
    2458             RTGCPTR32 GCPtrFirst32 = (RTGCPTR32)*pGCPtrMem;
    2459             RTGCPTR32 GCPtrLast32  = GCPtrFirst32 + (uint32_t)cbMem - 1;
    2460 
    2461             if (   pSel->Attr.n.u1Present
    2462                 && !pSel->Attr.n.u1Unusable)
    2463             {
    2464                 Assert(pSel->Attr.n.u1DescType);
    2465                 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
    2466                 {
    2467                     if (   (fAccess & IEM_ACCESS_TYPE_WRITE)
    2468                         && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE) )
    2469                         return iemRaiseSelectorInvalidAccess(pVCpu, iSegReg, fAccess);
    2470 
    2471                     if (!IEM_IS_REAL_OR_V86_MODE(pVCpu))
    2472                     {
    2473                         /** @todo CPL check. */
    2474                     }
    2475 
    2476                     /*
    2477                      * There are two kinds of data selectors, normal and expand down.
    2478                      */
    2479                     if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
    2480                     {
    2481                         if (   GCPtrFirst32 > pSel->u32Limit
    2482                             || GCPtrLast32  > pSel->u32Limit) /* yes, in real mode too (since 80286). */
    2483                             return iemRaiseSelectorBounds(pVCpu, iSegReg, fAccess);
    2484                     }
    2485                     else
    2486                     {
    2487                        /*
    2488                         * The upper boundary is defined by the B bit, not the G bit!
    2489                         */
    2490                        if (   GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
    2491                            || GCPtrLast32  > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
    2492                           return iemRaiseSelectorBounds(pVCpu, iSegReg, fAccess);
    2493                     }
    2494                     *pGCPtrMem = GCPtrFirst32 += (uint32_t)pSel->u64Base;
    2495                 }
    2496                 else
    2497                 {
    2498                     /*
    2499                      * Code selector and usually be used to read thru, writing is
    2500                      * only permitted in real and V8086 mode.
    2501                      */
    2502                     if (   (   (fAccess & IEM_ACCESS_TYPE_WRITE)
    2503                             || (   (fAccess & IEM_ACCESS_TYPE_READ)
    2504                                && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)) )
    2505                         && !IEM_IS_REAL_OR_V86_MODE(pVCpu) )
    2506                         return iemRaiseSelectorInvalidAccess(pVCpu, iSegReg, fAccess);
    2507 
    2508                     if (   GCPtrFirst32 > pSel->u32Limit
    2509                         || GCPtrLast32  > pSel->u32Limit) /* yes, in real mode too (since 80286). */
    2510                         return iemRaiseSelectorBounds(pVCpu, iSegReg, fAccess);
    2511 
    2512                     if (!IEM_IS_REAL_OR_V86_MODE(pVCpu))
    2513                     {
    2514                         /** @todo CPL check. */
    2515                     }
    2516 
    2517                     *pGCPtrMem  = GCPtrFirst32 += (uint32_t)pSel->u64Base;
    2518                 }
    2519             }
    2520             else
    2521                 return iemRaiseGeneralProtectionFault0(pVCpu);
    2522             return VINF_SUCCESS;
    2523         }
    2524 
    2525         case IEMMODE_64BIT:
    2526         {
    2527             RTGCPTR GCPtrMem = *pGCPtrMem;
    2528             if (iSegReg == X86_SREG_GS || iSegReg == X86_SREG_FS)
    2529                 *pGCPtrMem = GCPtrMem + pSel->u64Base;
    2530 
    2531             Assert(cbMem >= 1);
    2532             if (RT_LIKELY(X86_IS_CANONICAL(GCPtrMem) && X86_IS_CANONICAL(GCPtrMem + cbMem - 1)))
    2533                 return VINF_SUCCESS;
    2534             /** @todo We should probably raise \#SS(0) here if segment is SS; see AMD spec.
    2535              *        4.12.2 "Data Limit Checks in 64-bit Mode". */
    2536             return iemRaiseGeneralProtectionFault0(pVCpu);
    2537         }
    2538 
    2539         default:
    2540             AssertFailedReturn(VERR_IEM_IPE_7);
    2541     }
    2542 }
    2543 
    2544 
    2545 /**
    2546  * Translates a virtual address to a physical physical address and checks if we
    2547  * can access the page as specified.
    2548  *
    2549  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2550  * @param   GCPtrMem            The virtual address.
    2551  * @param   cbAccess            The access size, for raising \#PF correctly for
    2552  *                              FXSAVE and such.
    2553  * @param   fAccess             The intended access.
    2554  * @param   pGCPhysMem          Where to return the physical address.
    2555  */
    2556 VBOXSTRICTRC iemMemPageTranslateAndCheckAccess(PVMCPUCC pVCpu, RTGCPTR GCPtrMem, uint32_t cbAccess,
    2557                                                uint32_t fAccess, PRTGCPHYS pGCPhysMem) RT_NOEXCEPT
    2558 {
    2559     /** @todo Need a different PGM interface here.  We're currently using
    2560      *        generic / REM interfaces. this won't cut it for R0. */
    2561     /** @todo If/when PGM handles paged real-mode, we can remove the hack in
    2562      *        iemSvmWorldSwitch/iemVmxWorldSwitch to work around raising a page-fault
    2563      *        here. */
    2564     Assert(!(fAccess & IEM_ACCESS_TYPE_EXEC));
    2565     PGMPTWALKFAST WalkFast;
    2566     AssertCompile(IEM_ACCESS_TYPE_READ  == PGMQPAGE_F_READ);
    2567     AssertCompile(IEM_ACCESS_TYPE_WRITE == PGMQPAGE_F_WRITE);
    2568     AssertCompile(IEM_ACCESS_TYPE_EXEC  == PGMQPAGE_F_EXECUTE);
    2569     AssertCompile(X86_CR0_WP            == PGMQPAGE_F_CR0_WP0);
    2570     uint32_t fQPage = (fAccess & (PGMQPAGE_F_READ | IEM_ACCESS_TYPE_WRITE | PGMQPAGE_F_EXECUTE))
    2571                     | (((uint32_t)pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP) ^ X86_CR0_WP);
    2572     if (IEM_GET_CPL(pVCpu) == 3 && !(fAccess & IEM_ACCESS_WHAT_SYS))
    2573         fQPage |= PGMQPAGE_F_USER_MODE;
    2574     int rc = PGMGstQueryPageFast(pVCpu, GCPtrMem, fQPage, &WalkFast);
    2575     if (RT_SUCCESS(rc))
    2576     {
    2577         Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
    2578 
    2579         /* If the page is writable and does not have the no-exec bit set, all
    2580            access is allowed.  Otherwise we'll have to check more carefully... */
    2581         Assert(   (WalkFast.fEffective & (X86_PTE_RW | X86_PTE_US | X86_PTE_PAE_NX)) == (X86_PTE_RW | X86_PTE_US)
    2582                || (   (   !(fAccess & IEM_ACCESS_TYPE_WRITE)
    2583                        || (WalkFast.fEffective & X86_PTE_RW)
    2584                        || (   (    IEM_GET_CPL(pVCpu) != 3
    2585                                || (fAccess & IEM_ACCESS_WHAT_SYS))
    2586                            && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)) )
    2587                     && (   (WalkFast.fEffective & X86_PTE_US)
    2588                         || IEM_GET_CPL(pVCpu) != 3
    2589                         || (fAccess & IEM_ACCESS_WHAT_SYS) )
    2590                     && (   !(fAccess & IEM_ACCESS_TYPE_EXEC)
    2591                         || !(WalkFast.fEffective & X86_PTE_PAE_NX)
    2592                         || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE) )
    2593                   )
    2594               );
    2595 
    2596         /* PGMGstQueryPageFast sets the A & D bits. */
    2597         /** @todo testcase: check when A and D bits are actually set by the CPU.  */
    2598         Assert(!(~WalkFast.fEffective & (fAccess & IEM_ACCESS_TYPE_WRITE ? X86_PTE_D | X86_PTE_A : X86_PTE_A)));
    2599 
    2600         *pGCPhysMem = WalkFast.GCPhys;
    2601         return VINF_SUCCESS;
    2602     }
    2603 
    2604     LogEx(LOG_GROUP_IEM,("iemMemPageTranslateAndCheckAccess: GCPtrMem=%RGv - failed to fetch page -> #PF\n", GCPtrMem));
    2605     /** @todo Check unassigned memory in unpaged mode. */
    2606 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    2607     if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    2608         IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
    2609 #endif
    2610     *pGCPhysMem = NIL_RTGCPHYS;
    2611     return iemRaisePageFault(pVCpu, GCPtrMem, cbAccess, fAccess, rc);
    2612 }
    2613 
    2614 #if 0 /*unused*/
    2615 /**
    2616  * Looks up a memory mapping entry.
    2617  *
    2618  * @returns The mapping index (positive) or VERR_NOT_FOUND (negative).
    2619  * @param   pVCpu           The cross context virtual CPU structure of the calling thread.
    2620  * @param   pvMem           The memory address.
    2621  * @param   fAccess         The access to.
    2622  */
    2623 DECLINLINE(int) iemMapLookup(PVMCPUCC pVCpu, void *pvMem, uint32_t fAccess)
    2624 {
    2625     Assert(pVCpu->iem.s.cActiveMappings <= RT_ELEMENTS(pVCpu->iem.s.aMemMappings));
    2626     fAccess &= IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK;
    2627     if (   pVCpu->iem.s.aMemMappings[0].pv == pvMem
    2628         && (pVCpu->iem.s.aMemMappings[0].fAccess & (IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK)) == fAccess)
    2629         return 0;
    2630     if (   pVCpu->iem.s.aMemMappings[1].pv == pvMem
    2631         && (pVCpu->iem.s.aMemMappings[1].fAccess & (IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK)) == fAccess)
    2632         return 1;
    2633     if (   pVCpu->iem.s.aMemMappings[2].pv == pvMem
    2634         && (pVCpu->iem.s.aMemMappings[2].fAccess & (IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK)) == fAccess)
    2635         return 2;
    2636     return VERR_NOT_FOUND;
    2637 }
    2638 #endif
    2639 
    2640 /**
    2641  * Finds a free memmap entry when using iNextMapping doesn't work.
    2642  *
    2643  * @returns Memory mapping index, 1024 on failure.
    2644  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    2645  */
    2646 static unsigned iemMemMapFindFree(PVMCPUCC pVCpu)
    2647 {
    2648     /*
    2649      * The easy case.
    2650      */
    2651     if (pVCpu->iem.s.cActiveMappings == 0)
    2652     {
    2653         pVCpu->iem.s.iNextMapping = 1;
    2654         return 0;
    2655     }
    2656 
    2657     /* There should be enough mappings for all instructions. */
    2658     AssertReturn(pVCpu->iem.s.cActiveMappings < RT_ELEMENTS(pVCpu->iem.s.aMemMappings), 1024);
    2659 
    2660     for (unsigned i = 0; i < RT_ELEMENTS(pVCpu->iem.s.aMemMappings); i++)
    2661         if (pVCpu->iem.s.aMemMappings[i].fAccess == IEM_ACCESS_INVALID)
    2662             return i;
    2663 
    2664     AssertFailedReturn(1024);
    2665 }
    2666 
    2667 
    2668 /**
    2669  * Commits a bounce buffer that needs writing back and unmaps it.
    2670  *
    2671  * @returns Strict VBox status code.
    2672  * @param   pVCpu           The cross context virtual CPU structure of the calling thread.
    2673  * @param   iMemMap         The index of the buffer to commit.
    2674  * @param   fPostponeFail   Whether we can postpone writer failures to ring-3.
    2675  *                          Always false in ring-3, obviously.
    2676  */
    2677 static VBOXSTRICTRC iemMemBounceBufferCommitAndUnmap(PVMCPUCC pVCpu, unsigned iMemMap, bool fPostponeFail)
    2678 {
    2679     Assert(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED);
    2680     Assert(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE);
    2681 #ifdef IN_RING3
    2682     Assert(!fPostponeFail);
    2683     RT_NOREF_PV(fPostponeFail);
    2684 #endif
    2685 
    2686     /*
    2687      * Do the writing.
    2688      */
    2689     PVMCC pVM = pVCpu->CTX_SUFF(pVM);
    2690     if (!pVCpu->iem.s.aMemBbMappings[iMemMap].fUnassigned)
    2691     {
    2692         uint16_t const  cbFirst  = pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst;
    2693         uint16_t const  cbSecond = pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond;
    2694         uint8_t const  *pbBuf    = &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0];
    2695         if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))
    2696         {
    2697             /*
    2698              * Carefully and efficiently dealing with access handler return
    2699              * codes make this a little bloated.
    2700              */
    2701             VBOXSTRICTRC rcStrict = PGMPhysWrite(pVM,
    2702                                                  pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst,
    2703                                                  pbBuf,
    2704                                                  cbFirst,
    2705                                                  PGMACCESSORIGIN_IEM);
    2706             if (rcStrict == VINF_SUCCESS)
    2707             {
    2708                 if (cbSecond)
    2709                 {
    2710                     rcStrict = PGMPhysWrite(pVM,
    2711                                             pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond,
    2712                                             pbBuf + cbFirst,
    2713                                             cbSecond,
    2714                                             PGMACCESSORIGIN_IEM);
    2715                     if (rcStrict == VINF_SUCCESS)
    2716                     { /* nothing */ }
    2717                     else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    2718                     {
    2719                         LogEx(LOG_GROUP_IEM,
    2720                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc\n",
    2721                               pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    2722                               pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));
    2723                         rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    2724                     }
    2725 #ifndef IN_RING3
    2726                     else if (fPostponeFail)
    2727                     {
    2728                         LogEx(LOG_GROUP_IEM,
    2729                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (postponed)\n",
    2730                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    2731                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));
    2732                         pVCpu->iem.s.aMemMappings[iMemMap].fAccess |= IEM_ACCESS_PENDING_R3_WRITE_2ND;
    2733                         VMCPU_FF_SET(pVCpu, VMCPU_FF_IEM);
    2734                         return iemSetPassUpStatus(pVCpu, rcStrict);
    2735                     }
    2736 #endif
    2737                     else
    2738                     {
    2739                         LogEx(LOG_GROUP_IEM,
    2740                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (!!)\n",
    2741                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    2742                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));
    2743                         return rcStrict;
    2744                     }
    2745                 }
    2746             }
    2747             else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    2748             {
    2749                 if (!cbSecond)
    2750                 {
    2751                     LogEx(LOG_GROUP_IEM,
    2752                           ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc\n",
    2753                            pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict) ));
    2754                     rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    2755                 }
    2756                 else
    2757                 {
    2758                     VBOXSTRICTRC rcStrict2 = PGMPhysWrite(pVM,
    2759                                                           pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond,
    2760                                                           pbBuf + cbFirst,
    2761                                                           cbSecond,
    2762                                                           PGMACCESSORIGIN_IEM);
    2763                     if (rcStrict2 == VINF_SUCCESS)
    2764                     {
    2765                         LogEx(LOG_GROUP_IEM,
    2766                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc GCPhysSecond=%RGp/%#x\n",
    2767                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict),
    2768                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond));
    2769                         rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    2770                     }
    2771                     else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict2))
    2772                     {
    2773                         LogEx(LOG_GROUP_IEM,
    2774                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc GCPhysSecond=%RGp/%#x %Rrc\n",
    2775                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict),
    2776                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict2) ));
    2777                         PGM_PHYS_RW_DO_UPDATE_STRICT_RC(rcStrict, rcStrict2);
    2778                         rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    2779                     }
    2780 #ifndef IN_RING3
    2781                     else if (fPostponeFail)
    2782                     {
    2783                         LogEx(LOG_GROUP_IEM,
    2784                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (postponed)\n",
    2785                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    2786                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));
    2787                         pVCpu->iem.s.aMemMappings[iMemMap].fAccess |= IEM_ACCESS_PENDING_R3_WRITE_2ND;
    2788                         VMCPU_FF_SET(pVCpu, VMCPU_FF_IEM);
    2789                         return iemSetPassUpStatus(pVCpu, rcStrict);
    2790                     }
    2791 #endif
    2792                     else
    2793                     {
    2794                         LogEx(LOG_GROUP_IEM,
    2795                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc GCPhysSecond=%RGp/%#x %Rrc (!!)\n",
    2796                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict),
    2797                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict2) ));
    2798                         return rcStrict2;
    2799                     }
    2800                 }
    2801             }
    2802 #ifndef IN_RING3
    2803             else if (fPostponeFail)
    2804             {
    2805                 LogEx(LOG_GROUP_IEM,
    2806                       ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (postponed)\n",
    2807                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    2808                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));
    2809                 if (!cbSecond)
    2810                     pVCpu->iem.s.aMemMappings[iMemMap].fAccess |= IEM_ACCESS_PENDING_R3_WRITE_1ST;
    2811                 else
    2812                     pVCpu->iem.s.aMemMappings[iMemMap].fAccess |= IEM_ACCESS_PENDING_R3_WRITE_1ST | IEM_ACCESS_PENDING_R3_WRITE_2ND;
    2813                 VMCPU_FF_SET(pVCpu, VMCPU_FF_IEM);
    2814                 return iemSetPassUpStatus(pVCpu, rcStrict);
    2815             }
    2816 #endif
    2817             else
    2818             {
    2819                 LogEx(LOG_GROUP_IEM,
    2820                       ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc [GCPhysSecond=%RGp/%#x] (!!)\n",
    2821                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict),
    2822                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond));
    2823                 return rcStrict;
    2824             }
    2825         }
    2826         else
    2827         {
    2828             /*
    2829              * No access handlers, much simpler.
    2830              */
    2831             int rc = PGMPhysSimpleWriteGCPhys(pVM, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, pbBuf, cbFirst);
    2832             if (RT_SUCCESS(rc))
    2833             {
    2834                 if (cbSecond)
    2835                 {
    2836                     rc = PGMPhysSimpleWriteGCPhys(pVM, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, pbBuf + cbFirst, cbSecond);
    2837                     if (RT_SUCCESS(rc))
    2838                     { /* likely */ }
    2839                     else
    2840                     {
    2841                         LogEx(LOG_GROUP_IEM,
    2842                               ("iemMemBounceBufferCommitAndUnmap: PGMPhysSimpleWriteGCPhys GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (!!)\n",
    2843                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    2844                                pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, rc));
    2845                         return rc;
    2846                     }
    2847                 }
    2848             }
    2849             else
    2850             {
    2851                 LogEx(LOG_GROUP_IEM,
    2852                       ("iemMemBounceBufferCommitAndUnmap: PGMPhysSimpleWriteGCPhys GCPhysFirst=%RGp/%#x %Rrc [GCPhysSecond=%RGp/%#x] (!!)\n",
    2853                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, rc,
    2854                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond));
    2855                 return rc;
    2856             }
    2857         }
    2858     }
    2859 
    2860 #if defined(IEM_LOG_MEMORY_WRITES)
    2861     Log5(("IEM Wrote %RGp: %.*Rhxs\n", pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst,
    2862           RT_MAX(RT_MIN(pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst, 64), 1), &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0]));
    2863     if (pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond)
    2864         Log5(("IEM Wrote %RGp: %.*Rhxs [2nd page]\n", pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond,
    2865               RT_MIN(pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond, 64),
    2866               &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst]));
    2867 
    2868     size_t cbWrote = pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst + pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond;
    2869     g_cbIemWrote = cbWrote;
    2870     memcpy(g_abIemWrote, &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0], RT_MIN(cbWrote, sizeof(g_abIemWrote)));
    2871 #endif
    2872 
    2873     /*
    2874      * Free the mapping entry.
    2875      */
    2876     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    2877     Assert(pVCpu->iem.s.cActiveMappings != 0);
    2878     pVCpu->iem.s.cActiveMappings--;
    2879     return VINF_SUCCESS;
    2880 }
    2881 
    2882 
    2883 /**
    2884  * Helper for iemMemMap, iemMemMapJmp and iemMemBounceBufferMapCrossPage.
    2885  */
    2886 DECL_FORCE_INLINE(uint32_t)
    2887 iemMemCheckDataBreakpoint(PVMCC pVM, PVMCPUCC pVCpu, RTGCPTR GCPtrMem, size_t cbMem, uint32_t fAccess)
    2888 {
    2889     bool const  fSysAccess = (fAccess & IEM_ACCESS_WHAT_MASK) == IEM_ACCESS_WHAT_SYS;
    2890     if (fAccess & IEM_ACCESS_TYPE_WRITE)
    2891         return DBGFBpCheckDataWrite(pVM, pVCpu, GCPtrMem, (uint32_t)cbMem, fSysAccess);
    2892     return DBGFBpCheckDataRead(pVM, pVCpu, GCPtrMem, (uint32_t)cbMem, fSysAccess);
    2893 }
    2894 
    2895 
    2896 /**
    2897  * iemMemMap worker that deals with a request crossing pages.
    2898  */
    2899 static VBOXSTRICTRC
    2900 iemMemBounceBufferMapCrossPage(PVMCPUCC pVCpu, int iMemMap, void **ppvMem, uint8_t *pbUnmapInfo,
    2901                                size_t cbMem, RTGCPTR GCPtrFirst, uint32_t fAccess)
    2902 {
    2903     STAM_COUNTER_INC(&pVCpu->iem.s.StatMemBounceBufferCrossPage);
    2904     Assert(cbMem <= GUEST_PAGE_SIZE);
    2905 
    2906     /*
    2907      * Do the address translations.
    2908      */
    2909     uint32_t const cbFirstPage  = GUEST_PAGE_SIZE - (uint32_t)(GCPtrFirst & GUEST_PAGE_OFFSET_MASK);
    2910     RTGCPHYS GCPhysFirst;
    2911     VBOXSTRICTRC rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, GCPtrFirst, cbFirstPage, fAccess, &GCPhysFirst);
    2912     if (rcStrict != VINF_SUCCESS)
    2913         return rcStrict;
    2914     Assert((GCPhysFirst & GUEST_PAGE_OFFSET_MASK) == (GCPtrFirst & GUEST_PAGE_OFFSET_MASK));
    2915 
    2916     uint32_t const cbSecondPage = (uint32_t)cbMem - cbFirstPage;
    2917     RTGCPHYS GCPhysSecond;
    2918     rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, (GCPtrFirst + (cbMem - 1)) & ~(RTGCPTR)GUEST_PAGE_OFFSET_MASK,
    2919                                                  cbSecondPage, fAccess, &GCPhysSecond);
    2920     if (rcStrict != VINF_SUCCESS)
    2921         return rcStrict;
    2922     Assert((GCPhysSecond & GUEST_PAGE_OFFSET_MASK) == 0);
    2923     GCPhysSecond &= ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK; /** @todo why? */
    2924 
    2925     PVMCC pVM = pVCpu->CTX_SUFF(pVM);
    2926 
    2927     /*
    2928      * Check for data breakpoints.
    2929      */
    2930     if (RT_LIKELY(!(pVCpu->iem.s.fExec & IEM_F_PENDING_BRK_DATA)))
    2931     { /* likely */ }
    2932     else
    2933     {
    2934         uint32_t fDataBps = iemMemCheckDataBreakpoint(pVM, pVCpu, GCPtrFirst, cbFirstPage, fAccess);
    2935         fDataBps         |= iemMemCheckDataBreakpoint(pVM, pVCpu, (GCPtrFirst + (cbMem - 1)) & ~(RTGCPTR)GUEST_PAGE_OFFSET_MASK,
    2936                                                       cbSecondPage, fAccess);
    2937         pVCpu->cpum.GstCtx.eflags.uBoth |= fDataBps & (CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK);
    2938         if (fDataBps > 1)
    2939             LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapCrossPage: Data breakpoint: fDataBps=%#x for %RGv LB %zx; fAccess=%#x cs:rip=%04x:%08RX64\n",
    2940                                   fDataBps, GCPtrFirst, cbMem, fAccess, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    2941     }
    2942 
    2943     /*
    2944      * Read in the current memory content if it's a read, execute or partial
    2945      * write access.
    2946      */
    2947     uint8_t * const pbBuf = &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0];
    2948 
    2949     if (fAccess & (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_EXEC | IEM_ACCESS_PARTIAL_WRITE))
    2950     {
    2951         if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))
    2952         {
    2953             /*
    2954              * Must carefully deal with access handler status codes here,
    2955              * makes the code a bit bloated.
    2956              */
    2957             rcStrict = PGMPhysRead(pVM, GCPhysFirst, pbBuf, cbFirstPage, PGMACCESSORIGIN_IEM);
    2958             if (rcStrict == VINF_SUCCESS)
    2959             {
    2960                 rcStrict = PGMPhysRead(pVM, GCPhysSecond, pbBuf + cbFirstPage, cbSecondPage, PGMACCESSORIGIN_IEM);
    2961                 if (rcStrict == VINF_SUCCESS)
    2962                 { /*likely */ }
    2963                 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    2964                     rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    2965                 else
    2966                 {
    2967                     LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysSecond=%RGp rcStrict2=%Rrc (!!)\n",
    2968                                           GCPhysSecond, VBOXSTRICTRC_VAL(rcStrict) ));
    2969                     return rcStrict;
    2970                 }
    2971             }
    2972             else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    2973             {
    2974                 VBOXSTRICTRC rcStrict2 = PGMPhysRead(pVM, GCPhysSecond, pbBuf + cbFirstPage, cbSecondPage, PGMACCESSORIGIN_IEM);
    2975                 if (PGM_PHYS_RW_IS_SUCCESS(rcStrict2))
    2976                 {
    2977                     PGM_PHYS_RW_DO_UPDATE_STRICT_RC(rcStrict, rcStrict2);
    2978                     rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    2979                 }
    2980                 else
    2981                 {
    2982                     LogEx(LOG_GROUP_IEM,
    2983                           ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysSecond=%RGp rcStrict2=%Rrc (rcStrict=%Rrc) (!!)\n",
    2984                            GCPhysSecond, VBOXSTRICTRC_VAL(rcStrict2), VBOXSTRICTRC_VAL(rcStrict2) ));
    2985                     return rcStrict2;
    2986                 }
    2987             }
    2988             else
    2989             {
    2990                 LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysFirst=%RGp rcStrict=%Rrc (!!)\n",
    2991                                       GCPhysFirst, VBOXSTRICTRC_VAL(rcStrict) ));
    2992                 return rcStrict;
    2993             }
    2994         }
    2995         else
    2996         {
    2997             /*
    2998              * No informational status codes here, much more straight forward.
    2999              */
    3000             int rc = PGMPhysSimpleReadGCPhys(pVM, pbBuf, GCPhysFirst, cbFirstPage);
    3001             if (RT_SUCCESS(rc))
    3002             {
    3003                 Assert(rc == VINF_SUCCESS);
    3004                 rc = PGMPhysSimpleReadGCPhys(pVM, pbBuf + cbFirstPage, GCPhysSecond, cbSecondPage);
    3005                 if (RT_SUCCESS(rc))
    3006                     Assert(rc == VINF_SUCCESS);
    3007                 else
    3008                 {
    3009                     LogEx(LOG_GROUP_IEM,
    3010                           ("iemMemBounceBufferMapPhys: PGMPhysSimpleReadGCPhys GCPhysSecond=%RGp rc=%Rrc (!!)\n", GCPhysSecond, rc));
    3011                     return rc;
    3012                 }
    3013             }
    3014             else
    3015             {
    3016                 LogEx(LOG_GROUP_IEM,
    3017                       ("iemMemBounceBufferMapPhys: PGMPhysSimpleReadGCPhys GCPhysFirst=%RGp rc=%Rrc (!!)\n", GCPhysFirst, rc));
    3018                 return rc;
    3019             }
    3020         }
    3021     }
    3022 #ifdef VBOX_STRICT
    3023     else
    3024         memset(pbBuf, 0xcc, cbMem);
    3025     if (cbMem < sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab))
    3026         memset(pbBuf + cbMem, 0xaa, sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab) - cbMem);
    3027 #endif
    3028     AssertCompileMemberAlignment(VMCPU, iem.s.aBounceBuffers, 64);
    3029 
    3030     /*
    3031      * Commit the bounce buffer entry.
    3032      */
    3033     pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst    = GCPhysFirst;
    3034     pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond   = GCPhysSecond;
    3035     pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst        = (uint16_t)cbFirstPage;
    3036     pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond       = (uint16_t)cbSecondPage;
    3037     pVCpu->iem.s.aMemBbMappings[iMemMap].fUnassigned    = false;
    3038     pVCpu->iem.s.aMemMappings[iMemMap].pv               = pbBuf;
    3039     pVCpu->iem.s.aMemMappings[iMemMap].fAccess          = fAccess | IEM_ACCESS_BOUNCE_BUFFERED;
    3040     pVCpu->iem.s.iNextMapping = iMemMap + 1;
    3041     pVCpu->iem.s.cActiveMappings++;
    3042 
    3043     *ppvMem = pbBuf;
    3044     *pbUnmapInfo = iMemMap | 0x08 | ((fAccess & IEM_ACCESS_TYPE_MASK) << 4);
    3045     return VINF_SUCCESS;
    3046 }
    3047 
    3048 
    3049 /**
    3050  * iemMemMap woker that deals with iemMemPageMap failures.
    3051  */
    3052 static VBOXSTRICTRC iemMemBounceBufferMapPhys(PVMCPUCC pVCpu, unsigned iMemMap, void **ppvMem, uint8_t *pbUnmapInfo, size_t cbMem,
    3053                                               RTGCPHYS GCPhysFirst, uint32_t fAccess, VBOXSTRICTRC rcMap)
    3054 {
    3055     STAM_COUNTER_INC(&pVCpu->iem.s.StatMemBounceBufferMapPhys);
    3056 
    3057     /*
    3058      * Filter out conditions we can handle and the ones which shouldn't happen.
    3059      */
    3060     if (   rcMap != VERR_PGM_PHYS_TLB_CATCH_WRITE
    3061         && rcMap != VERR_PGM_PHYS_TLB_CATCH_ALL
    3062         && rcMap != VERR_PGM_PHYS_TLB_UNASSIGNED)
    3063     {
    3064         AssertReturn(RT_FAILURE_NP(rcMap), VERR_IEM_IPE_8);
    3065         return rcMap;
    3066     }
    3067     pVCpu->iem.s.cPotentialExits++;
    3068 
    3069     /*
    3070      * Read in the current memory content if it's a read, execute or partial
    3071      * write access.
    3072      */
    3073     uint8_t *pbBuf = &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0];
    3074     if (fAccess & (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_EXEC | IEM_ACCESS_PARTIAL_WRITE))
    3075     {
    3076         if (rcMap == VERR_PGM_PHYS_TLB_UNASSIGNED)
    3077             memset(pbBuf, 0xff, cbMem);
    3078         else
    3079         {
    3080             int rc;
    3081             if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))
    3082             {
    3083                 VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), GCPhysFirst, pbBuf, cbMem, PGMACCESSORIGIN_IEM);
    3084                 if (rcStrict == VINF_SUCCESS)
    3085                 { /* nothing */ }
    3086                 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
    3087                     rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
    3088                 else
    3089                 {
    3090                     LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysFirst=%RGp rcStrict=%Rrc (!!)\n",
    3091                                           GCPhysFirst, VBOXSTRICTRC_VAL(rcStrict) ));
    3092                     return rcStrict;
    3093                 }
    3094             }
    3095             else
    3096             {
    3097                 rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), pbBuf, GCPhysFirst, cbMem);
    3098                 if (RT_SUCCESS(rc))
    3099                 { /* likely */ }
    3100                 else
    3101                 {
    3102                     LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysSimpleReadGCPhys GCPhysFirst=%RGp rcStrict=%Rrc (!!)\n",
    3103                                           GCPhysFirst, rc));
    3104                     return rc;
    3105                 }
    3106             }
    3107         }
    3108     }
    3109 #ifdef VBOX_STRICT
    3110     else
    3111         memset(pbBuf, 0xcc, cbMem);
    3112 #endif
    3113 #ifdef VBOX_STRICT
    3114     if (cbMem < sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab))
    3115         memset(pbBuf + cbMem, 0xaa, sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab) - cbMem);
    3116 #endif
    3117 
    3118     /*
    3119      * Commit the bounce buffer entry.
    3120      */
    3121     pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst    = GCPhysFirst;
    3122     pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond   = NIL_RTGCPHYS;
    3123     pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst        = (uint16_t)cbMem;
    3124     pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond       = 0;
    3125     pVCpu->iem.s.aMemBbMappings[iMemMap].fUnassigned    = rcMap == VERR_PGM_PHYS_TLB_UNASSIGNED;
    3126     pVCpu->iem.s.aMemMappings[iMemMap].pv               = pbBuf;
    3127     pVCpu->iem.s.aMemMappings[iMemMap].fAccess          = fAccess | IEM_ACCESS_BOUNCE_BUFFERED;
    3128     pVCpu->iem.s.iNextMapping = iMemMap + 1;
    3129     pVCpu->iem.s.cActiveMappings++;
    3130 
    3131     *ppvMem = pbBuf;
    3132     *pbUnmapInfo = iMemMap | 0x08 | ((fAccess & IEM_ACCESS_TYPE_MASK) << 4);
    3133     return VINF_SUCCESS;
    3134 }
    3135 
    3136 
    3137 
    3138 /**
    3139  * Maps the specified guest memory for the given kind of access.
    3140  *
    3141  * This may be using bounce buffering of the memory if it's crossing a page
    3142  * boundary or if there is an access handler installed for any of it.  Because
    3143  * of lock prefix guarantees, we're in for some extra clutter when this
    3144  * happens.
    3145  *
    3146  * This may raise a \#GP, \#SS, \#PF or \#AC.
    3147  *
    3148  * @returns VBox strict status code.
    3149  *
    3150  * @param   pVCpu       The cross context virtual CPU structure of the calling thread.
    3151  * @param   ppvMem      Where to return the pointer to the mapped memory.
    3152  * @param   pbUnmapInfo Where to return unmap info to be passed to
    3153  *                      iemMemCommitAndUnmap or iemMemRollbackAndUnmap when
    3154  *                      done.
    3155  * @param   cbMem       The number of bytes to map.  This is usually 1, 2, 4, 6,
    3156  *                      8, 12, 16, 32 or 512.  When used by string operations
    3157  *                      it can be up to a page.
    3158  * @param   iSegReg     The index of the segment register to use for this
    3159  *                      access.  The base and limits are checked. Use UINT8_MAX
    3160  *                      to indicate that no segmentation is required (for IDT,
    3161  *                      GDT and LDT accesses).
    3162  * @param   GCPtrMem    The address of the guest memory.
    3163  * @param   fAccess     How the memory is being accessed.  The
    3164  *                      IEM_ACCESS_TYPE_XXX part is used to figure out how to
    3165  *                      map the memory, while the IEM_ACCESS_WHAT_XXX part is
    3166  *                      used when raising exceptions.  The IEM_ACCESS_ATOMIC and
    3167  *                      IEM_ACCESS_PARTIAL_WRITE bits are also allowed to be
    3168  *                      set.
    3169  * @param   uAlignCtl   Alignment control:
    3170  *                          - Bits 15:0 is the alignment mask.
    3171  *                          - Bits 31:16 for flags like IEM_MEMMAP_F_ALIGN_GP,
    3172  *                            IEM_MEMMAP_F_ALIGN_SSE, and
    3173  *                            IEM_MEMMAP_F_ALIGN_GP_OR_AC.
    3174  *                      Pass zero to skip alignment.
    3175  */
    3176 VBOXSTRICTRC iemMemMap(PVMCPUCC pVCpu, void **ppvMem, uint8_t *pbUnmapInfo, size_t cbMem, uint8_t iSegReg, RTGCPTR GCPtrMem,
    3177                        uint32_t fAccess, uint32_t uAlignCtl) RT_NOEXCEPT
    3178 {
    3179     STAM_COUNTER_INC(&pVCpu->iem.s.StatMemMapNoJmp);
    3180 
    3181     /*
    3182      * Check the input and figure out which mapping entry to use.
    3183      */
    3184     Assert(cbMem <= sizeof(pVCpu->iem.s.aBounceBuffers[0]));
    3185     Assert(   cbMem <= 64 || cbMem == 512 || cbMem == 256 || cbMem == 108 || cbMem == 104 || cbMem == 102 || cbMem == 94
    3186            || (iSegReg == UINT8_MAX && uAlignCtl == 0 && fAccess == IEM_ACCESS_DATA_R /* for the CPUID logging interface */) );
    3187     Assert(!(fAccess & ~(IEM_ACCESS_TYPE_MASK | IEM_ACCESS_WHAT_MASK | IEM_ACCESS_ATOMIC | IEM_ACCESS_PARTIAL_WRITE)));
    3188     Assert(pVCpu->iem.s.cActiveMappings < RT_ELEMENTS(pVCpu->iem.s.aMemMappings));
    3189 
    3190     unsigned iMemMap = pVCpu->iem.s.iNextMapping;
    3191     if (   iMemMap >= RT_ELEMENTS(pVCpu->iem.s.aMemMappings)
    3192         || pVCpu->iem.s.aMemMappings[iMemMap].fAccess != IEM_ACCESS_INVALID)
    3193     {
    3194         iMemMap = iemMemMapFindFree(pVCpu);
    3195         AssertLogRelMsgReturn(iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings),
    3196                               ("active=%d fAccess[0] = {%#x, %#x, %#x}\n", pVCpu->iem.s.cActiveMappings,
    3197                                pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemMappings[1].fAccess,
    3198                                pVCpu->iem.s.aMemMappings[2].fAccess),
    3199                               VERR_IEM_IPE_9);
    3200     }
    3201 
    3202     /*
    3203      * Map the memory, checking that we can actually access it.  If something
    3204      * slightly complicated happens, fall back on bounce buffering.
    3205      */
    3206     VBOXSTRICTRC rcStrict = iemMemApplySegment(pVCpu, fAccess, iSegReg, cbMem, &GCPtrMem);
    3207     if (rcStrict == VINF_SUCCESS)
    3208     { /* likely */ }
    3209     else
    3210         return rcStrict;
    3211 
    3212     if ((GCPtrMem & GUEST_PAGE_OFFSET_MASK) + cbMem <= GUEST_PAGE_SIZE) /* Crossing a page boundary? */
    3213     { /* likely */ }
    3214     else
    3215         return iemMemBounceBufferMapCrossPage(pVCpu, iMemMap, ppvMem, pbUnmapInfo, cbMem, GCPtrMem, fAccess);
    3216 
    3217     /*
    3218      * Alignment check.
    3219      */
    3220     if ( (GCPtrMem & (uAlignCtl & UINT16_MAX)) == 0 )
    3221     { /* likelyish */ }
    3222     else
    3223     {
    3224         /* Misaligned access. */
    3225         if ((fAccess & IEM_ACCESS_WHAT_MASK) != IEM_ACCESS_WHAT_SYS)
    3226         {
    3227             if (   !(uAlignCtl & IEM_MEMMAP_F_ALIGN_GP)
    3228                 || (   (uAlignCtl & IEM_MEMMAP_F_ALIGN_SSE)
    3229                     && (pVCpu->cpum.GstCtx.XState.x87.MXCSR & X86_MXCSR_MM)) )
    3230             {
    3231                 AssertCompile(X86_CR0_AM == X86_EFL_AC);
    3232 
    3233                 if (!iemMemAreAlignmentChecksEnabled(pVCpu))
    3234                 { /* likely */ }
    3235                 else
    3236                     return iemRaiseAlignmentCheckException(pVCpu);
    3237             }
    3238             else if (   (uAlignCtl & IEM_MEMMAP_F_ALIGN_GP_OR_AC)
    3239                      && (GCPtrMem & 3) /* The value 4 matches 10980xe's FXSAVE and helps make bs3-cpu-basic2 work. */
    3240                     /** @todo may only apply to 2, 4 or 8 byte misalignments depending on the CPU
    3241                      * implementation. See FXSAVE/FRSTOR/XSAVE/XRSTOR/++.  Using 4 for now as
    3242                      * that's what FXSAVE does on a 10980xe. */
    3243                      && iemMemAreAlignmentChecksEnabled(pVCpu))
    3244                 return iemRaiseAlignmentCheckException(pVCpu);
    3245             else
    3246                 return iemRaiseGeneralProtectionFault0(pVCpu);
    3247         }
    3248 
    3249 #if (defined(RT_ARCH_AMD64) && defined(RT_OS_LINUX)) || defined(RT_ARCH_ARM64)
    3250         /* If the access is atomic there are host platform alignmnet restrictions
    3251            we need to conform with. */
    3252         if (   !(fAccess & IEM_ACCESS_ATOMIC)
    3253 # if defined(RT_ARCH_AMD64)
    3254             || (64U - (GCPtrMem & 63U) >= cbMem) /* split-lock detection. ASSUMES 64 byte cache line. */
    3255 # elif defined(RT_ARCH_ARM64)
    3256             || (16U - (GCPtrMem & 15U) >= cbMem) /* LSE2 allows atomics anywhere within a 16 byte sized & aligned block. */
    3257 # else
    3258 #  error port me
    3259 # endif
    3260            )
    3261         { /* okay */ }
    3262         else
    3263         {
    3264             LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv LB %u - misaligned atomic fallback.\n", GCPtrMem, cbMem));
    3265             pVCpu->iem.s.cMisalignedAtomics += 1;
    3266             return VINF_EM_EMULATE_SPLIT_LOCK;
    3267         }
    3268 #endif
    3269     }
    3270 
    3271 #ifdef IEM_WITH_DATA_TLB
    3272     Assert(!(fAccess & IEM_ACCESS_TYPE_EXEC));
    3273 
    3274     /*
    3275      * Get the TLB entry for this page and check PT flags.
    3276      *
    3277      * We reload the TLB entry if we need to set the dirty bit (accessed
    3278      * should in theory always be set).
    3279      */
    3280     uint8_t           *pbMem     = NULL;
    3281     uint64_t const     uTagNoRev = IEMTLB_CALC_TAG_NO_REV(GCPtrMem);
    3282     PIEMTLBENTRY       pTlbe     = IEMTLB_TAG_TO_EVEN_ENTRY(&pVCpu->iem.s.DataTlb, uTagNoRev);
    3283     uint64_t const     fTlbeAD   = IEMTLBE_F_PT_NO_ACCESSED | (fAccess & IEM_ACCESS_TYPE_WRITE ? IEMTLBE_F_PT_NO_DIRTY : 0);
    3284     if (   (   pTlbe->uTag               == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevision)
    3285             && !(pTlbe->fFlagsAndPhysRev & fTlbeAD) )
    3286         || (   (pTlbe = pTlbe + 1)->uTag == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevisionGlobal)
    3287             && !(pTlbe->fFlagsAndPhysRev & fTlbeAD) ) )
    3288     {
    3289 # ifdef IEM_WITH_TLB_STATISTICS
    3290         pVCpu->iem.s.DataTlb.cTlbCoreHits++;
    3291 # endif
    3292 
    3293         /* If the page is either supervisor only or non-writable, we need to do
    3294            more careful access checks. */
    3295         if (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_USER | IEMTLBE_F_PT_NO_WRITE))
    3296         {
    3297             /* Write to read only memory? */
    3298             if (   (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_WRITE)
    3299                 && (fAccess & IEM_ACCESS_TYPE_WRITE)
    3300                 && (   (    IEM_GET_CPL(pVCpu) == 3
    3301                         && !(fAccess & IEM_ACCESS_WHAT_SYS))
    3302                     || (pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)))
    3303             {
    3304                 LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - read-only page -> #PF\n", GCPtrMem));
    3305                 return iemRaisePageFault(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess & ~IEM_ACCESS_TYPE_READ, VERR_ACCESS_DENIED);
    3306             }
    3307 
    3308             /* Kernel memory accessed by userland? */
    3309             if (   (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER)
    3310                 && IEM_GET_CPL(pVCpu) == 3
    3311                 && !(fAccess & IEM_ACCESS_WHAT_SYS))
    3312             {
    3313                 LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - user access to kernel page -> #PF\n", GCPtrMem));
    3314                 return iemRaisePageFault(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, VERR_ACCESS_DENIED);
    3315             }
    3316         }
    3317 
    3318         /* Look up the physical page info if necessary. */
    3319         if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pVCpu->iem.s.DataTlb.uTlbPhysRev)
    3320 # ifdef IN_RING3
    3321             pbMem = pTlbe->pbMappingR3;
    3322 # else
    3323             pbMem = NULL;
    3324 # endif
    3325         else
    3326         {
    3327             if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR))
    3328             { /* likely */ }
    3329             else
    3330                 IEMTlbInvalidateAllPhysicalSlow(pVCpu);
    3331             pTlbe->pbMappingR3       = NULL;
    3332             pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK;
    3333             int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
    3334                                                 &pbMem, &pTlbe->fFlagsAndPhysRev);
    3335             AssertRCReturn(rc, rc);
    3336 # ifdef IN_RING3
    3337             pTlbe->pbMappingR3 = pbMem;
    3338 # endif
    3339         }
    3340     }
    3341     else
    3342     {
    3343         pVCpu->iem.s.DataTlb.cTlbCoreMisses++;
    3344 
    3345         /* This page table walking will set A bits as required by the access while performing the walk.
    3346            ASSUMES these are set when the address is translated rather than on commit... */
    3347         /** @todo testcase: check when A bits are actually set by the CPU for code.  */
    3348         PGMPTWALKFAST WalkFast;
    3349         AssertCompile(IEM_ACCESS_TYPE_READ  == PGMQPAGE_F_READ);
    3350         AssertCompile(IEM_ACCESS_TYPE_WRITE == PGMQPAGE_F_WRITE);
    3351         AssertCompile(IEM_ACCESS_TYPE_EXEC  == PGMQPAGE_F_EXECUTE);
    3352         AssertCompile(X86_CR0_WP            == PGMQPAGE_F_CR0_WP0);
    3353         uint32_t fQPage = (fAccess & (PGMQPAGE_F_READ | IEM_ACCESS_TYPE_WRITE | PGMQPAGE_F_EXECUTE))
    3354                         | (((uint32_t)pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP) ^ X86_CR0_WP);
    3355         if (IEM_GET_CPL(pVCpu) == 3 && !(fAccess & IEM_ACCESS_WHAT_SYS))
    3356             fQPage |= PGMQPAGE_F_USER_MODE;
    3357         int rc = PGMGstQueryPageFast(pVCpu, GCPtrMem, fQPage, &WalkFast);
    3358         if (RT_SUCCESS(rc))
    3359             Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
    3360         else
    3361         {
    3362             LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - failed to fetch page -> #PF\n", GCPtrMem));
    3363 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    3364             if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    3365                 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
    3366 # endif
    3367             return iemRaisePageFault(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, rc);
    3368         }
    3369 
    3370         uint32_t fDataBps;
    3371         if (   RT_LIKELY(!(pVCpu->iem.s.fExec & IEM_F_PENDING_BRK_DATA))
    3372             || RT_LIKELY(!(fDataBps = iemMemCheckDataBreakpoint(pVCpu->CTX_SUFF(pVM), pVCpu, GCPtrMem, cbMem, fAccess))))
    3373         {
    3374             if (   !(WalkFast.fEffective & PGM_PTATTRS_G_MASK)
    3375                 || IEM_GET_CPL(pVCpu) != 0) /* optimization: Only use the PTE.G=1 entries in ring-0. */
    3376             {
    3377                 pTlbe--;
    3378                 pTlbe->uTag         = uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevision;
    3379                 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE)
    3380                     iemTlbLoadedLargePage<false>(pVCpu, &pVCpu->iem.s.DataTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE));
    3381 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    3382                 else
    3383                     ASMBitClear(pVCpu->iem.s.DataTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev));
    3384 # endif
    3385             }
    3386             else
    3387             {
    3388                 pVCpu->iem.s.DataTlb.cTlbCoreGlobalLoads++;
    3389                 pTlbe->uTag         = uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevisionGlobal;
    3390                 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE)
    3391                     iemTlbLoadedLargePage<true>(pVCpu, &pVCpu->iem.s.DataTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE));
    3392 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    3393                 else
    3394                     ASMBitClear(pVCpu->iem.s.DataTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + 1);
    3395 # endif
    3396             }
    3397         }
    3398         else
    3399         {
    3400             /* If we hit a data breakpoint, we use a dummy TLBE to force all accesses
    3401                to the page with the data access breakpoint armed on it to pass thru here. */
    3402             if (fDataBps > 1)
    3403                 LogEx(LOG_GROUP_IEM, ("iemMemMap: Data breakpoint: fDataBps=%#x for %RGv LB %zx; fAccess=%#x cs:rip=%04x:%08RX64\n",
    3404                                       fDataBps, GCPtrMem, cbMem, fAccess, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    3405             pVCpu->cpum.GstCtx.eflags.uBoth |= fDataBps & (CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK);
    3406             pTlbe = &pVCpu->iem.s.DataBreakpointTlbe;
    3407             pTlbe->uTag = uTagNoRev;
    3408         }
    3409         pTlbe->fFlagsAndPhysRev = (~WalkFast.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A) /* skipping NX */)
    3410                                 | (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE);
    3411         RTGCPHYS const GCPhysPg = WalkFast.GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
    3412         pTlbe->GCPhys           = GCPhysPg;
    3413         pTlbe->pbMappingR3      = NULL;
    3414         Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED));
    3415         Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_DIRTY) || !(fAccess & IEM_ACCESS_TYPE_WRITE));
    3416         Assert(   !(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_WRITE)
    3417                || !(fAccess & IEM_ACCESS_TYPE_WRITE)
    3418                || (fQPage & (PGMQPAGE_F_CR0_WP0 | PGMQPAGE_F_USER_MODE)) == PGMQPAGE_F_CR0_WP0);
    3419         Assert(   !(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER)
    3420                || IEM_GET_CPL(pVCpu) != 3
    3421                || (fAccess & IEM_ACCESS_WHAT_SYS));
    3422 
    3423         if (pTlbe != &pVCpu->iem.s.DataBreakpointTlbe)
    3424         {
    3425             if (!((uintptr_t)pTlbe & (sizeof(*pTlbe) * 2 - 1)))
    3426                 IEMTLBTRACE_LOAD(       pVCpu, GCPtrMem, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, true);
    3427             else
    3428                 IEMTLBTRACE_LOAD_GLOBAL(pVCpu, GCPtrMem, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, true);
    3429         }
    3430 
    3431         /* Resolve the physical address. */
    3432         Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_GCPHYS2PTR_MASK));
    3433         rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhysPg, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
    3434                                         &pbMem, &pTlbe->fFlagsAndPhysRev);
    3435         AssertRCReturn(rc, rc);
    3436 # ifdef IN_RING3
    3437         pTlbe->pbMappingR3 = pbMem;
    3438 # endif
    3439     }
    3440 
    3441     /*
    3442      * Check the physical page level access and mapping.
    3443      */
    3444     if (   !(pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PG_NO_WRITE | IEMTLBE_F_PG_NO_READ))
    3445         || !(pTlbe->fFlagsAndPhysRev & (  (fAccess & IEM_ACCESS_TYPE_WRITE ? IEMTLBE_F_PG_NO_WRITE : 0)
    3446                                         | (fAccess & IEM_ACCESS_TYPE_READ  ? IEMTLBE_F_PG_NO_READ  : 0))) )
    3447     { /* probably likely */ }
    3448     else
    3449         return iemMemBounceBufferMapPhys(pVCpu, iMemMap, ppvMem, pbUnmapInfo, cbMem,
    3450                                          pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK), fAccess,
    3451                                            pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_UNASSIGNED ? VERR_PGM_PHYS_TLB_UNASSIGNED
    3452                                          : pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_NO_READ    ? VERR_PGM_PHYS_TLB_CATCH_ALL
    3453                                                                                              : VERR_PGM_PHYS_TLB_CATCH_WRITE);
    3454     Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_NO_MAPPINGR3)); /* ASSUMPTIONS about PGMPhysIemGCPhys2PtrNoLock behaviour. */
    3455 
    3456     if (pbMem)
    3457     {
    3458         Assert(!((uintptr_t)pbMem & GUEST_PAGE_OFFSET_MASK));
    3459         pbMem    = pbMem + (GCPtrMem & GUEST_PAGE_OFFSET_MASK);
    3460         fAccess |= IEM_ACCESS_NOT_LOCKED;
    3461     }
    3462     else
    3463     {
    3464         Assert(!(fAccess & IEM_ACCESS_NOT_LOCKED));
    3465         RTGCPHYS const GCPhysFirst = pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK);
    3466         rcStrict = iemMemPageMap(pVCpu, GCPhysFirst, fAccess, (void **)&pbMem, &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    3467         if (rcStrict != VINF_SUCCESS)
    3468             return iemMemBounceBufferMapPhys(pVCpu, iMemMap, ppvMem, pbUnmapInfo, cbMem, GCPhysFirst, fAccess, rcStrict);
    3469     }
    3470 
    3471     void * const pvMem = pbMem;
    3472 
    3473     if (fAccess & IEM_ACCESS_TYPE_WRITE)
    3474         Log6(("IEM WR %RGv (%RGp) LB %#zx\n", GCPtrMem, pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK), cbMem));
    3475     if (fAccess & IEM_ACCESS_TYPE_READ)
    3476         Log2(("IEM RD %RGv (%RGp) LB %#zx\n", GCPtrMem, pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK), cbMem));
    3477 
    3478 #else  /* !IEM_WITH_DATA_TLB */
    3479 
    3480     RTGCPHYS GCPhysFirst;
    3481     rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, &GCPhysFirst);
    3482     if (rcStrict != VINF_SUCCESS)
    3483         return rcStrict;
    3484 
    3485     if (fAccess & IEM_ACCESS_TYPE_WRITE)
    3486         Log6(("IEM WR %RGv (%RGp) LB %#zx\n", GCPtrMem, GCPhysFirst, cbMem));
    3487     if (fAccess & IEM_ACCESS_TYPE_READ)
    3488         Log2(("IEM RD %RGv (%RGp) LB %#zx\n", GCPtrMem, GCPhysFirst, cbMem));
    3489 
    3490     void *pvMem;
    3491     rcStrict = iemMemPageMap(pVCpu, GCPhysFirst, fAccess, &pvMem, &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    3492     if (rcStrict != VINF_SUCCESS)
    3493         return iemMemBounceBufferMapPhys(pVCpu, iMemMap, ppvMem, pbUnmapInfo, cbMem, GCPhysFirst, fAccess, rcStrict);
    3494 
    3495 #endif /* !IEM_WITH_DATA_TLB */
    3496 
    3497     /*
    3498      * Fill in the mapping table entry.
    3499      */
    3500     pVCpu->iem.s.aMemMappings[iMemMap].pv      = pvMem;
    3501     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = fAccess;
    3502     pVCpu->iem.s.iNextMapping     = iMemMap + 1;
    3503     pVCpu->iem.s.cActiveMappings += 1;
    3504 
    3505     *ppvMem = pvMem;
    3506     *pbUnmapInfo = iMemMap | 0x08 | ((fAccess & IEM_ACCESS_TYPE_MASK) << 4);
    3507     AssertCompile(IEM_ACCESS_TYPE_MASK <= 0xf);
    3508     AssertCompile(RT_ELEMENTS(pVCpu->iem.s.aMemMappings) < 8);
    3509 
    3510     return VINF_SUCCESS;
    3511 }
    3512 
    3513 
    3514 /**
    3515  * Commits the guest memory if bounce buffered and unmaps it.
    3516  *
    3517  * @returns Strict VBox status code.
    3518  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    3519  * @param   bUnmapInfo          Unmap info set by iemMemMap.
    3520  */
    3521 VBOXSTRICTRC iemMemCommitAndUnmap(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT
    3522 {
    3523     uintptr_t const iMemMap = bUnmapInfo & 0x7;
    3524     AssertMsgReturn(   (bUnmapInfo & 0x08)
    3525                     && iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings)
    3526                     && (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_TYPE_MASK | 0xf)) == ((unsigned)bUnmapInfo >> 4),
    3527                     ("%#x fAccess=%#x\n", bUnmapInfo, pVCpu->iem.s.aMemMappings[iMemMap].fAccess),
    3528                     VERR_NOT_FOUND);
    3529 
    3530     /* If it's bounce buffered, we may need to write back the buffer. */
    3531     if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED)
    3532     {
    3533         if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE)
    3534             return iemMemBounceBufferCommitAndUnmap(pVCpu, iMemMap, false /*fPostponeFail*/);
    3535     }
    3536     /* Otherwise unlock it. */
    3537     else if (!(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_NOT_LOCKED))
    3538         PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    3539 
    3540     /* Free the entry. */
    3541     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    3542     Assert(pVCpu->iem.s.cActiveMappings != 0);
    3543     pVCpu->iem.s.cActiveMappings--;
    3544     return VINF_SUCCESS;
    3545 }
    3546 
    3547 
    3548 /**
    3549  * Rolls back the guest memory (conceptually only) and unmaps it.
    3550  *
    3551  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    3552  * @param   bUnmapInfo          Unmap info set by iemMemMap.
    3553  */
    3554 void iemMemRollbackAndUnmap(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT
    3555 {
    3556     uintptr_t const iMemMap = bUnmapInfo & 0x7;
    3557     AssertMsgReturnVoid(   (bUnmapInfo & 0x08)
    3558                         && iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings)
    3559                         &&    (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_TYPE_MASK | 0xf))
    3560                            == ((unsigned)bUnmapInfo >> 4),
    3561                         ("%#x fAccess=%#x\n", bUnmapInfo, pVCpu->iem.s.aMemMappings[iMemMap].fAccess));
    3562 
    3563     /* Unlock it if necessary. */
    3564     if (!(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_NOT_LOCKED))
    3565         PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    3566 
    3567     /* Free the entry. */
    3568     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    3569     Assert(pVCpu->iem.s.cActiveMappings != 0);
    3570     pVCpu->iem.s.cActiveMappings--;
    3571 }
    3572 
    3573 #ifdef IEM_WITH_SETJMP
    3574 
    3575 /**
    3576  * Maps the specified guest memory for the given kind of access, longjmp on
    3577  * error.
    3578  *
    3579  * This may be using bounce buffering of the memory if it's crossing a page
    3580  * boundary or if there is an access handler installed for any of it.  Because
    3581  * of lock prefix guarantees, we're in for some extra clutter when this
    3582  * happens.
    3583  *
    3584  * This may raise a \#GP, \#SS, \#PF or \#AC.
    3585  *
    3586  * @returns Pointer to the mapped memory.
    3587  *
    3588  * @param   pVCpu       The cross context virtual CPU structure of the calling thread.
    3589  * @param   bUnmapInfo  Where to return unmap info to be passed to
    3590  *                      iemMemCommitAndUnmapJmp, iemMemCommitAndUnmapRwSafeJmp,
    3591  *                      iemMemCommitAndUnmapWoSafeJmp,
    3592  *                      iemMemCommitAndUnmapRoSafeJmp,
    3593  *                      iemMemRollbackAndUnmapWoSafe or iemMemRollbackAndUnmap
    3594  *                      when done.
    3595  * @param   cbMem       The number of bytes to map.  This is usually 1,
    3596  *                      2, 4, 6, 8, 12, 16, 32 or 512.  When used by
    3597  *                      string operations it can be up to a page.
    3598  * @param   iSegReg     The index of the segment register to use for
    3599  *                      this access.  The base and limits are checked.
    3600  *                      Use UINT8_MAX to indicate that no segmentation
    3601  *                      is required (for IDT, GDT and LDT accesses).
    3602  * @param   GCPtrMem    The address of the guest memory.
    3603  * @param   fAccess     How the memory is being accessed. The
    3604  *                      IEM_ACCESS_TYPE_XXX part is used to figure out how to
    3605  *                      map the memory, while the IEM_ACCESS_WHAT_XXX part is
    3606  *                      used when raising exceptions. The IEM_ACCESS_ATOMIC and
    3607  *                      IEM_ACCESS_PARTIAL_WRITE bits are also allowed to be
    3608  *                      set.
    3609  * @param   uAlignCtl   Alignment control:
    3610  *                          - Bits 15:0 is the alignment mask.
    3611  *                          - Bits 31:16 for flags like IEM_MEMMAP_F_ALIGN_GP,
    3612  *                            IEM_MEMMAP_F_ALIGN_SSE, and
    3613  *                            IEM_MEMMAP_F_ALIGN_GP_OR_AC.
    3614  *                      Pass zero to skip alignment.
    3615  * @tparam  a_fSafe     Whether this is a call from "safe" fallback function in
    3616  *                      IEMAllMemRWTmpl.cpp.h (@c true) or a generic one that
    3617  *                      needs counting as such in the statistics.
    3618  */
    3619 template<bool a_fSafeCall = false>
    3620 static void *iemMemMapJmp(PVMCPUCC pVCpu, uint8_t *pbUnmapInfo, size_t cbMem, uint8_t iSegReg, RTGCPTR GCPtrMem,
    3621                           uint32_t fAccess, uint32_t uAlignCtl) IEM_NOEXCEPT_MAY_LONGJMP
    3622 {
    3623     STAM_COUNTER_INC(&pVCpu->iem.s.StatMemMapJmp);
    3624 
    3625     /*
    3626      * Check the input, check segment access and adjust address
    3627      * with segment base.
    3628      */
    3629     Assert(cbMem <= 64 || cbMem == 512 || cbMem == 108 || cbMem == 104 || cbMem == 94); /* 512 is the max! */
    3630     Assert(!(fAccess & ~(IEM_ACCESS_TYPE_MASK | IEM_ACCESS_WHAT_MASK | IEM_ACCESS_ATOMIC | IEM_ACCESS_PARTIAL_WRITE)));
    3631     Assert(pVCpu->iem.s.cActiveMappings < RT_ELEMENTS(pVCpu->iem.s.aMemMappings));
    3632 
    3633     VBOXSTRICTRC rcStrict = iemMemApplySegment(pVCpu, fAccess, iSegReg, cbMem, &GCPtrMem);
    3634     if (rcStrict == VINF_SUCCESS) { /*likely*/ }
    3635     else IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    3636 
    3637     /*
    3638      * Alignment check.
    3639      */
    3640     if ( (GCPtrMem & (uAlignCtl & UINT16_MAX)) == 0 )
    3641     { /* likelyish */ }
    3642     else
    3643     {
    3644         /* Misaligned access. */
    3645         if ((fAccess & IEM_ACCESS_WHAT_MASK) != IEM_ACCESS_WHAT_SYS)
    3646         {
    3647             if (   !(uAlignCtl & IEM_MEMMAP_F_ALIGN_GP)
    3648                 || (   (uAlignCtl & IEM_MEMMAP_F_ALIGN_SSE)
    3649                     && (pVCpu->cpum.GstCtx.XState.x87.MXCSR & X86_MXCSR_MM)) )
    3650             {
    3651                 AssertCompile(X86_CR0_AM == X86_EFL_AC);
    3652 
    3653                 if (iemMemAreAlignmentChecksEnabled(pVCpu))
    3654                     iemRaiseAlignmentCheckExceptionJmp(pVCpu);
    3655             }
    3656             else if (   (uAlignCtl & IEM_MEMMAP_F_ALIGN_GP_OR_AC)
    3657                      && (GCPtrMem & 3) /* The value 4 matches 10980xe's FXSAVE and helps make bs3-cpu-basic2 work. */
    3658                     /** @todo may only apply to 2, 4 or 8 byte misalignments depending on the CPU
    3659                      * implementation. See FXSAVE/FRSTOR/XSAVE/XRSTOR/++.  Using 4 for now as
    3660                      * that's what FXSAVE does on a 10980xe. */
    3661                      && iemMemAreAlignmentChecksEnabled(pVCpu))
    3662                 iemRaiseAlignmentCheckExceptionJmp(pVCpu);
    3663             else
    3664                 iemRaiseGeneralProtectionFault0Jmp(pVCpu);
    3665         }
    3666 
    3667 #if (defined(RT_ARCH_AMD64) && defined(RT_OS_LINUX)) || defined(RT_ARCH_ARM64)
    3668         /* If the access is atomic there are host platform alignmnet restrictions
    3669            we need to conform with. */
    3670         if (   !(fAccess & IEM_ACCESS_ATOMIC)
    3671 # if defined(RT_ARCH_AMD64)
    3672             || (64U - (GCPtrMem & 63U) >= cbMem) /* split-lock detection. ASSUMES 64 byte cache line. */
    3673 # elif defined(RT_ARCH_ARM64)
    3674             || (16U - (GCPtrMem & 15U) >= cbMem) /* LSE2 allows atomics anywhere within a 16 byte sized & aligned block. */
    3675 # else
    3676 #  error port me
    3677 # endif
    3678            )
    3679         { /* okay */ }
    3680         else
    3681         {
    3682             LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv LB %u - misaligned atomic fallback.\n", GCPtrMem, cbMem));
    3683             pVCpu->iem.s.cMisalignedAtomics += 1;
    3684             IEM_DO_LONGJMP(pVCpu, VINF_EM_EMULATE_SPLIT_LOCK);
    3685         }
    3686 #endif
    3687     }
    3688 
    3689     /*
    3690      * Figure out which mapping entry to use.
    3691      */
    3692     unsigned iMemMap = pVCpu->iem.s.iNextMapping;
    3693     if (   iMemMap >= RT_ELEMENTS(pVCpu->iem.s.aMemMappings)
    3694         || pVCpu->iem.s.aMemMappings[iMemMap].fAccess != IEM_ACCESS_INVALID)
    3695     {
    3696         iMemMap = iemMemMapFindFree(pVCpu);
    3697         AssertLogRelMsgStmt(iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings),
    3698                             ("active=%d fAccess[0] = {%#x, %#x, %#x}\n", pVCpu->iem.s.cActiveMappings,
    3699                              pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemMappings[1].fAccess,
    3700                              pVCpu->iem.s.aMemMappings[2].fAccess),
    3701                             IEM_DO_LONGJMP(pVCpu, VERR_IEM_IPE_9));
    3702     }
    3703 
    3704     /*
    3705      * Crossing a page boundary?
    3706      */
    3707     if ((GCPtrMem & GUEST_PAGE_OFFSET_MASK) + cbMem <= GUEST_PAGE_SIZE)
    3708     { /* No (likely). */ }
    3709     else
    3710     {
    3711         void *pvMem;
    3712         rcStrict = iemMemBounceBufferMapCrossPage(pVCpu, iMemMap, &pvMem, pbUnmapInfo, cbMem, GCPtrMem, fAccess);
    3713         if (rcStrict == VINF_SUCCESS)
    3714             return pvMem;
    3715         IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    3716     }
    3717 
    3718 #ifdef IEM_WITH_DATA_TLB
    3719     Assert(!(fAccess & IEM_ACCESS_TYPE_EXEC));
    3720 
    3721     /*
    3722      * Get the TLB entry for this page checking that it has the A & D bits
    3723      * set as per fAccess flags.
    3724      */
    3725     /** @todo make the caller pass these in with fAccess. */
    3726     uint64_t const     fNoUser          = (fAccess & IEM_ACCESS_WHAT_MASK) != IEM_ACCESS_WHAT_SYS && IEM_GET_CPL(pVCpu) == 3
    3727                                         ? IEMTLBE_F_PT_NO_USER : 0;
    3728     uint64_t const     fNoWriteNoDirty  = fAccess & IEM_ACCESS_TYPE_WRITE
    3729                                         ? IEMTLBE_F_PG_NO_WRITE | IEMTLBE_F_PT_NO_DIRTY
    3730                                           | (   (pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)
    3731                                              || (IEM_GET_CPL(pVCpu) == 3 && (fAccess & IEM_ACCESS_WHAT_MASK) != IEM_ACCESS_WHAT_SYS)
    3732                                              ? IEMTLBE_F_PT_NO_WRITE : 0)
    3733                                         : 0;
    3734     uint64_t const     fNoRead          = fAccess & IEM_ACCESS_TYPE_READ ? IEMTLBE_F_PG_NO_READ : 0;
    3735     uint64_t const     uTagNoRev        = IEMTLB_CALC_TAG_NO_REV(GCPtrMem);
    3736     PIEMTLBENTRY       pTlbe            = IEMTLB_TAG_TO_EVEN_ENTRY(&pVCpu->iem.s.DataTlb, uTagNoRev);
    3737     uint64_t const     fTlbeAD          = IEMTLBE_F_PT_NO_ACCESSED | (fNoWriteNoDirty & IEMTLBE_F_PT_NO_DIRTY);
    3738     if (   (   pTlbe->uTag               == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevision)
    3739             && !(pTlbe->fFlagsAndPhysRev & fTlbeAD) )
    3740         || (   (pTlbe = pTlbe + 1)->uTag == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevisionGlobal)
    3741             && !(pTlbe->fFlagsAndPhysRev & fTlbeAD) ) )
    3742     {
    3743 # ifdef IEM_WITH_TLB_STATISTICS
    3744         if (a_fSafeCall)
    3745             pVCpu->iem.s.DataTlb.cTlbSafeHits++;
    3746         else
    3747             pVCpu->iem.s.DataTlb.cTlbCoreHits++;
    3748 # endif
    3749     }
    3750     else
    3751     {
    3752         if (a_fSafeCall)
    3753             pVCpu->iem.s.DataTlb.cTlbSafeMisses++;
    3754         else
    3755             pVCpu->iem.s.DataTlb.cTlbCoreMisses++;
    3756 
    3757         /* This page table walking will set A and D bits as required by the
    3758            access while performing the walk.
    3759            ASSUMES these are set when the address is translated rather than on commit... */
    3760         /** @todo testcase: check when A and D bits are actually set by the CPU.  */
    3761         PGMPTWALKFAST WalkFast;
    3762         AssertCompile(IEM_ACCESS_TYPE_READ  == PGMQPAGE_F_READ);
    3763         AssertCompile(IEM_ACCESS_TYPE_WRITE == PGMQPAGE_F_WRITE);
    3764         AssertCompile(IEM_ACCESS_TYPE_EXEC  == PGMQPAGE_F_EXECUTE);
    3765         AssertCompile(X86_CR0_WP            == PGMQPAGE_F_CR0_WP0);
    3766         uint32_t fQPage = (fAccess & (PGMQPAGE_F_READ | IEM_ACCESS_TYPE_WRITE | PGMQPAGE_F_EXECUTE))
    3767                         | (((uint32_t)pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP) ^ X86_CR0_WP);
    3768         if (IEM_GET_CPL(pVCpu) == 3 && !(fAccess & IEM_ACCESS_WHAT_SYS))
    3769             fQPage |= PGMQPAGE_F_USER_MODE;
    3770         int rc = PGMGstQueryPageFast(pVCpu, GCPtrMem, fQPage, &WalkFast);
    3771         if (RT_SUCCESS(rc))
    3772             Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
    3773         else
    3774         {
    3775             LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - failed to fetch page -> #PF\n", GCPtrMem));
    3776 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    3777             if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
    3778                 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
    3779 # endif
    3780             iemRaisePageFaultJmp(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, rc);
    3781         }
    3782 
    3783         uint32_t fDataBps;
    3784         if (   RT_LIKELY(!(pVCpu->iem.s.fExec & IEM_F_PENDING_BRK_DATA))
    3785             || RT_LIKELY(!(fDataBps = iemMemCheckDataBreakpoint(pVCpu->CTX_SUFF(pVM), pVCpu, GCPtrMem, cbMem, fAccess))))
    3786         {
    3787             if (   !(WalkFast.fEffective & PGM_PTATTRS_G_MASK)
    3788                 || IEM_GET_CPL(pVCpu) != 0) /* optimization: Only use the PTE.G=1 entries in ring-0. */
    3789             {
    3790                 pTlbe--;
    3791                 pTlbe->uTag         = uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevision;
    3792                 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE)
    3793                     iemTlbLoadedLargePage<false>(pVCpu, &pVCpu->iem.s.DataTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE));
    3794 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    3795                 else
    3796                     ASMBitClear(pVCpu->iem.s.DataTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev));
    3797 # endif
    3798             }
    3799             else
    3800             {
    3801                 if (a_fSafeCall)
    3802                     pVCpu->iem.s.DataTlb.cTlbSafeGlobalLoads++;
    3803                 else
    3804                     pVCpu->iem.s.DataTlb.cTlbCoreGlobalLoads++;
    3805                 pTlbe->uTag         = uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevisionGlobal;
    3806                 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE)
    3807                     iemTlbLoadedLargePage<true>(pVCpu, &pVCpu->iem.s.DataTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE));
    3808 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP
    3809                 else
    3810                     ASMBitClear(pVCpu->iem.s.DataTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + 1);
    3811 # endif
    3812             }
    3813         }
    3814         else
    3815         {
    3816             /* If we hit a data breakpoint, we use a dummy TLBE to force all accesses
    3817                to the page with the data access breakpoint armed on it to pass thru here. */
    3818             if (fDataBps > 1)
    3819                 LogEx(LOG_GROUP_IEM, ("iemMemMapJmp<%d>: Data breakpoint: fDataBps=%#x for %RGv LB %zx; fAccess=%#x cs:rip=%04x:%08RX64\n",
    3820                                       a_fSafeCall, fDataBps, GCPtrMem, cbMem, fAccess, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    3821             pVCpu->cpum.GstCtx.eflags.uBoth |= fDataBps & (CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK);
    3822             pTlbe = &pVCpu->iem.s.DataBreakpointTlbe;
    3823             pTlbe->uTag = uTagNoRev;
    3824         }
    3825         pTlbe->fFlagsAndPhysRev = (~WalkFast.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A) /* skipping NX */)
    3826                                 | (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE);
    3827         RTGCPHYS const GCPhysPg = WalkFast.GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
    3828         pTlbe->GCPhys           = GCPhysPg;
    3829         pTlbe->pbMappingR3      = NULL;
    3830         Assert(!(pTlbe->fFlagsAndPhysRev & ((fNoWriteNoDirty & IEMTLBE_F_PT_NO_DIRTY) | IEMTLBE_F_PT_NO_ACCESSED)));
    3831         Assert(   !(pTlbe->fFlagsAndPhysRev & fNoWriteNoDirty & IEMTLBE_F_PT_NO_WRITE)
    3832                || (fQPage & (PGMQPAGE_F_CR0_WP0 | PGMQPAGE_F_USER_MODE)) == PGMQPAGE_F_CR0_WP0);
    3833         Assert(!(pTlbe->fFlagsAndPhysRev & fNoUser & IEMTLBE_F_PT_NO_USER));
    3834 
    3835         if (pTlbe != &pVCpu->iem.s.DataBreakpointTlbe)
    3836         {
    3837             if (!((uintptr_t)pTlbe & (sizeof(*pTlbe) * 2 - 1)))
    3838                 IEMTLBTRACE_LOAD(       pVCpu, GCPtrMem, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, true);
    3839             else
    3840                 IEMTLBTRACE_LOAD_GLOBAL(pVCpu, GCPtrMem, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, true);
    3841         }
    3842 
    3843         /* Resolve the physical address. */
    3844         Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_GCPHYS2PTR_MASK));
    3845         uint8_t *pbMemFullLoad = NULL;
    3846         rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhysPg, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
    3847                                         &pbMemFullLoad, &pTlbe->fFlagsAndPhysRev);
    3848         AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc));
    3849 # ifdef IN_RING3
    3850         pTlbe->pbMappingR3 = pbMemFullLoad;
    3851 # endif
    3852     }
    3853 
    3854     /*
    3855      * Check the flags and physical revision.
    3856      * Note! This will revalidate the uTlbPhysRev after a full load.  This is
    3857      *       just to keep the code structure simple (i.e. avoid gotos or similar).
    3858      */
    3859     uint8_t *pbMem;
    3860     if (   (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PHYS_REV | IEMTLBE_F_PT_NO_ACCESSED | fNoRead | fNoWriteNoDirty | fNoUser))
    3861         == pVCpu->iem.s.DataTlb.uTlbPhysRev)
    3862 # ifdef IN_RING3
    3863         pbMem = pTlbe->pbMappingR3;
    3864 # else
    3865         pbMem = NULL;
    3866 # endif
    3867     else
    3868     {
    3869         Assert(!(pTlbe->fFlagsAndPhysRev & ((fNoWriteNoDirty & IEMTLBE_F_PT_NO_DIRTY) | IEMTLBE_F_PT_NO_ACCESSED)));
    3870 
    3871         /*
    3872          * Okay, something isn't quite right or needs refreshing.
    3873          */
    3874         /* Write to read only memory? */
    3875         if (pTlbe->fFlagsAndPhysRev & fNoWriteNoDirty & IEMTLBE_F_PT_NO_WRITE)
    3876         {
    3877             LogEx(LOG_GROUP_IEM, ("iemMemMapJmp: GCPtrMem=%RGv - read-only page -> #PF\n", GCPtrMem));
    3878 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    3879 /** @todo TLB: EPT isn't integrated into the TLB stuff, so we don't know whether
    3880  *        to trigger an \#PG or a VM nested paging exit here yet! */
    3881             if (Walk.fFailed & PGM_WALKFAIL_EPT)
    3882                 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
    3883 # endif
    3884             iemRaisePageFaultJmp(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess & ~IEM_ACCESS_TYPE_READ, VERR_ACCESS_DENIED);
    3885         }
    3886 
    3887         /* Kernel memory accessed by userland? */
    3888         if (pTlbe->fFlagsAndPhysRev & fNoUser & IEMTLBE_F_PT_NO_USER)
    3889         {
    3890             LogEx(LOG_GROUP_IEM, ("iemMemMapJmp: GCPtrMem=%RGv - user access to kernel page -> #PF\n", GCPtrMem));
    3891 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
    3892 /** @todo TLB: See above. */
    3893             if (Walk.fFailed & PGM_WALKFAIL_EPT)
    3894                 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
    3895 # endif
    3896             iemRaisePageFaultJmp(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, VERR_ACCESS_DENIED);
    3897         }
    3898 
    3899         /*
    3900          * Check if the physical page info needs updating.
    3901          */
    3902         if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pVCpu->iem.s.DataTlb.uTlbPhysRev)
    3903 # ifdef IN_RING3
    3904             pbMem = pTlbe->pbMappingR3;
    3905 # else
    3906             pbMem = NULL;
    3907 # endif
    3908         else
    3909         {
    3910             pTlbe->pbMappingR3       = NULL;
    3911             pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK;
    3912             pbMem = NULL;
    3913             int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
    3914                                                 &pbMem, &pTlbe->fFlagsAndPhysRev);
    3915             AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc));
    3916 # ifdef IN_RING3
    3917             pTlbe->pbMappingR3 = pbMem;
    3918 # endif
    3919         }
    3920 
    3921         /*
    3922          * Check the physical page level access and mapping.
    3923          */
    3924         if (!(pTlbe->fFlagsAndPhysRev & ((fNoWriteNoDirty | fNoRead) & (IEMTLBE_F_PG_NO_WRITE | IEMTLBE_F_PG_NO_READ))))
    3925         { /* probably likely */ }
    3926         else
    3927         {
    3928             rcStrict = iemMemBounceBufferMapPhys(pVCpu, iMemMap, (void **)&pbMem, pbUnmapInfo, cbMem,
    3929                                                  pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK), fAccess,
    3930                                                    pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_UNASSIGNED ? VERR_PGM_PHYS_TLB_UNASSIGNED
    3931                                                  : pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_NO_READ    ? VERR_PGM_PHYS_TLB_CATCH_ALL
    3932                                                                                                      : VERR_PGM_PHYS_TLB_CATCH_WRITE);
    3933             if (rcStrict == VINF_SUCCESS)
    3934                 return pbMem;
    3935             IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    3936         }
    3937     }
    3938     Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_NO_MAPPINGR3)); /* ASSUMPTIONS about PGMPhysIemGCPhys2PtrNoLock behaviour. */
    3939 
    3940     if (pbMem)
    3941     {
    3942         Assert(!((uintptr_t)pbMem & GUEST_PAGE_OFFSET_MASK));
    3943         pbMem    = pbMem + (GCPtrMem & GUEST_PAGE_OFFSET_MASK);
    3944         fAccess |= IEM_ACCESS_NOT_LOCKED;
    3945     }
    3946     else
    3947     {
    3948         Assert(!(fAccess & IEM_ACCESS_NOT_LOCKED));
    3949         RTGCPHYS const GCPhysFirst = pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK);
    3950         rcStrict = iemMemPageMap(pVCpu, GCPhysFirst, fAccess, (void **)&pbMem, &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    3951         if (rcStrict == VINF_SUCCESS)
    3952         {
    3953             *pbUnmapInfo = iMemMap | 0x08 | ((fAccess & IEM_ACCESS_TYPE_MASK) << 4);
    3954             return pbMem;
    3955         }
    3956         IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    3957     }
    3958 
    3959     void * const pvMem = pbMem;
    3960 
    3961     if (fAccess & IEM_ACCESS_TYPE_WRITE)
    3962         Log6(("IEM WR %RGv (%RGp) LB %#zx\n", GCPtrMem, pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK), cbMem));
    3963     if (fAccess & IEM_ACCESS_TYPE_READ)
    3964         Log2(("IEM RD %RGv (%RGp) LB %#zx\n", GCPtrMem, pTlbe->GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK), cbMem));
    3965 
    3966 #else  /* !IEM_WITH_DATA_TLB */
    3967 
    3968 
    3969     RTGCPHYS GCPhysFirst;
    3970     rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, &GCPhysFirst);
    3971     if (rcStrict == VINF_SUCCESS) { /*likely*/ }
    3972     else IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    3973 
    3974     if (fAccess & IEM_ACCESS_TYPE_WRITE)
    3975         Log6(("IEM WR %RGv (%RGp) LB %#zx\n", GCPtrMem, GCPhysFirst, cbMem));
    3976     if (fAccess & IEM_ACCESS_TYPE_READ)
    3977         Log2(("IEM RD %RGv (%RGp) LB %#zx\n", GCPtrMem, GCPhysFirst, cbMem));
    3978 
    3979     void *pvMem;
    3980     rcStrict = iemMemPageMap(pVCpu, GCPhysFirst, fAccess, &pvMem, &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    3981     if (rcStrict == VINF_SUCCESS)
    3982     { /* likely */ }
    3983     else
    3984     {
    3985         rcStrict = iemMemBounceBufferMapPhys(pVCpu, iMemMap, &pvMem, pbUnmapInfo, cbMem, GCPhysFirst, fAccess, rcStrict);
    3986         if (rcStrict == VINF_SUCCESS)
    3987             return pvMem;
    3988         IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    3989     }
    3990 
    3991 #endif /* !IEM_WITH_DATA_TLB */
    3992 
    3993     /*
    3994      * Fill in the mapping table entry.
    3995      */
    3996     pVCpu->iem.s.aMemMappings[iMemMap].pv      = pvMem;
    3997     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = fAccess;
    3998     pVCpu->iem.s.iNextMapping = iMemMap + 1;
    3999     pVCpu->iem.s.cActiveMappings++;
    4000 
    4001     *pbUnmapInfo = iMemMap | 0x08 | ((fAccess & IEM_ACCESS_TYPE_MASK) << 4);
    4002     return pvMem;
    4003 }
    4004 
    4005 
    4006 /** @see iemMemMapJmp */
    4007 static void *iemMemMapSafeJmp(PVMCPUCC pVCpu, uint8_t *pbUnmapInfo, size_t cbMem, uint8_t iSegReg, RTGCPTR GCPtrMem,
    4008                               uint32_t fAccess, uint32_t uAlignCtl) IEM_NOEXCEPT_MAY_LONGJMP
    4009 {
    4010     return iemMemMapJmp<true /*a_fSafeCall*/>(pVCpu, pbUnmapInfo, cbMem, iSegReg, GCPtrMem, fAccess, uAlignCtl);
    4011 }
    4012 
    4013 
    4014 /**
    4015  * Commits the guest memory if bounce buffered and unmaps it, longjmp on error.
    4016  *
    4017  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4018  * @param   pvMem               The mapping.
    4019  * @param   fAccess             The kind of access.
    4020  */
    4021 void iemMemCommitAndUnmapJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP
    4022 {
    4023     uintptr_t const iMemMap = bUnmapInfo & 0x7;
    4024     AssertMsgReturnVoid(   (bUnmapInfo & 0x08)
    4025                         && iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings)
    4026                         &&    (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_TYPE_MASK | 0xf))
    4027                            == ((unsigned)bUnmapInfo >> 4),
    4028                         ("%#x fAccess=%#x\n", bUnmapInfo, pVCpu->iem.s.aMemMappings[iMemMap].fAccess));
    4029 
    4030     /* If it's bounce buffered, we may need to write back the buffer. */
    4031     if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED)
    4032     {
    4033         if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE)
    4034         {
    4035             VBOXSTRICTRC rcStrict = iemMemBounceBufferCommitAndUnmap(pVCpu, iMemMap, false /*fPostponeFail*/);
    4036             if (rcStrict == VINF_SUCCESS)
    4037                 return;
    4038             IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
    4039         }
    4040     }
    4041     /* Otherwise unlock it. */
    4042     else if (!(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_NOT_LOCKED))
    4043         PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    4044 
    4045     /* Free the entry. */
    4046     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    4047     Assert(pVCpu->iem.s.cActiveMappings != 0);
    4048     pVCpu->iem.s.cActiveMappings--;
    4049 }
    4050 
    4051 
    4052 /** Fallback for iemMemCommitAndUnmapRwJmp.  */
    4053 void iemMemCommitAndUnmapRwSafeJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP
    4054 {
    4055     Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_WRITE));
    4056     iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);
    4057 }
    4058 
    4059 
    4060 /** Fallback for iemMemCommitAndUnmapAtJmp.  */
    4061 void iemMemCommitAndUnmapAtSafeJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP
    4062 {
    4063     Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_WRITE));
    4064     iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);
    4065 }
    4066 
    4067 
    4068 /** Fallback for iemMemCommitAndUnmapWoJmp.  */
    4069 void iemMemCommitAndUnmapWoSafeJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP
    4070 {
    4071     Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == IEM_ACCESS_TYPE_WRITE);
    4072     iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);
    4073 }
    4074 
    4075 
    4076 /** Fallback for iemMemCommitAndUnmapRoJmp.  */
    4077 void iemMemCommitAndUnmapRoSafeJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP
    4078 {
    4079     Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == IEM_ACCESS_TYPE_READ);
    4080     iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);
    4081 }
    4082 
    4083 
    4084 /** Fallback for iemMemRollbackAndUnmapWo.  */
    4085 void iemMemRollbackAndUnmapWoSafe(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT
    4086 {
    4087     Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == IEM_ACCESS_TYPE_WRITE);
    4088     iemMemRollbackAndUnmap(pVCpu, bUnmapInfo);
    4089 }
    4090 
    4091 #endif /* IEM_WITH_SETJMP */
    4092 
    4093 #ifndef IN_RING3
    4094 /**
    4095  * Commits the guest memory if bounce buffered and unmaps it, if any bounce
    4096  * buffer part shows trouble it will be postponed to ring-3 (sets FF and stuff).
    4097  *
    4098  * Allows the instruction to be completed and retired, while the IEM user will
    4099  * return to ring-3 immediately afterwards and do the postponed writes there.
    4100  *
    4101  * @returns VBox status code (no strict statuses).  Caller must check
    4102  *          VMCPU_FF_IEM before repeating string instructions and similar stuff.
    4103  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4104  * @param   pvMem               The mapping.
    4105  * @param   fAccess             The kind of access.
    4106  */
    4107 VBOXSTRICTRC iemMemCommitAndUnmapPostponeTroubleToR3(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT
    4108 {
    4109     uintptr_t const iMemMap = bUnmapInfo & 0x7;
    4110     AssertMsgReturn(   (bUnmapInfo & 0x08)
    4111                     && iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings)
    4112                     &&    (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_TYPE_MASK | 0xf))
    4113                        == ((unsigned)bUnmapInfo >> 4),
    4114                     ("%#x fAccess=%#x\n", bUnmapInfo, pVCpu->iem.s.aMemMappings[iMemMap].fAccess),
    4115                     VERR_NOT_FOUND);
    4116 
    4117     /* If it's bounce buffered, we may need to write back the buffer. */
    4118     if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED)
    4119     {
    4120         if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE)
    4121             return iemMemBounceBufferCommitAndUnmap(pVCpu, iMemMap, true /*fPostponeFail*/);
    4122     }
    4123     /* Otherwise unlock it. */
    4124     else if (!(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_NOT_LOCKED))
    4125         PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    4126 
    4127     /* Free the entry. */
    4128     pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    4129     Assert(pVCpu->iem.s.cActiveMappings != 0);
    4130     pVCpu->iem.s.cActiveMappings--;
    4131     return VINF_SUCCESS;
    4132 }
    4133 #endif
    4134 
    4135 
    4136 /**
    4137  * Rollbacks mappings, releasing page locks and such.
    4138  *
    4139  * The caller shall only call this after checking cActiveMappings.
    4140  *
    4141  * @param   pVCpu       The cross context virtual CPU structure of the calling thread.
    4142  */
    4143 void iemMemRollback(PVMCPUCC pVCpu) RT_NOEXCEPT
    4144 {
    4145     Assert(pVCpu->iem.s.cActiveMappings > 0);
    4146 
    4147     uint32_t iMemMap = RT_ELEMENTS(pVCpu->iem.s.aMemMappings);
    4148     while (iMemMap-- > 0)
    4149     {
    4150         uint32_t const fAccess = pVCpu->iem.s.aMemMappings[iMemMap].fAccess;
    4151         if (fAccess != IEM_ACCESS_INVALID)
    4152         {
    4153             AssertMsg(!(fAccess & ~IEM_ACCESS_VALID_MASK) && fAccess != 0, ("%#x\n", fAccess));
    4154             pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    4155             if (!(fAccess & (IEM_ACCESS_BOUNCE_BUFFERED | IEM_ACCESS_NOT_LOCKED)))
    4156                 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);
    4157             AssertMsg(pVCpu->iem.s.cActiveMappings > 0,
    4158                       ("iMemMap=%u fAccess=%#x pv=%p GCPhysFirst=%RGp GCPhysSecond=%RGp\n",
    4159                        iMemMap, fAccess, pVCpu->iem.s.aMemMappings[iMemMap].pv,
    4160                        pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond));
    4161             pVCpu->iem.s.cActiveMappings--;
    4162         }
    4163     }
    4164 }
    4165 
    4166 
    4167 /*
    4168  * Instantiate R/W templates.
    4169  */
    4170 #define TMPL_MEM_WITH_STACK
    4171 
    4172 #define TMPL_MEM_TYPE       uint8_t
    4173 #define TMPL_MEM_FN_SUFF    U8
    4174 #define TMPL_MEM_FMT_TYPE   "%#04x"
    4175 #define TMPL_MEM_FMT_DESC   "byte"
    4176 #include "IEMAllMemRWTmpl.cpp.h"
    4177 
    4178 #define TMPL_MEM_TYPE       uint16_t
    4179 #define TMPL_MEM_FN_SUFF    U16
    4180 #define TMPL_MEM_FMT_TYPE   "%#06x"
    4181 #define TMPL_MEM_FMT_DESC   "word"
    4182 #include "IEMAllMemRWTmpl.cpp.h"
    4183 
    4184 #define TMPL_WITH_PUSH_SREG
    4185 #define TMPL_MEM_TYPE       uint32_t
    4186 #define TMPL_MEM_FN_SUFF    U32
    4187 #define TMPL_MEM_FMT_TYPE   "%#010x"
    4188 #define TMPL_MEM_FMT_DESC   "dword"
    4189 #include "IEMAllMemRWTmpl.cpp.h"
    4190 #undef TMPL_WITH_PUSH_SREG
    4191 
    4192 #define TMPL_MEM_TYPE       uint64_t
    4193 #define TMPL_MEM_FN_SUFF    U64
    4194 #define TMPL_MEM_FMT_TYPE   "%#018RX64"
    4195 #define TMPL_MEM_FMT_DESC   "qword"
    4196 #include "IEMAllMemRWTmpl.cpp.h"
    4197 
    4198 #undef TMPL_MEM_WITH_STACK
    4199 
    4200 #define TMPL_MEM_TYPE       uint32_t
    4201 #define TMPL_MEM_TYPE_ALIGN 0
    4202 #define TMPL_MEM_FN_SUFF    U32NoAc
    4203 #define TMPL_MEM_FMT_TYPE   "%#010x"
    4204 #define TMPL_MEM_FMT_DESC   "dword"
    4205 #include "IEMAllMemRWTmpl.cpp.h"
    4206 #undef TMPL_WITH_PUSH_SREG
    4207 
    4208 #define TMPL_MEM_TYPE       uint64_t
    4209 #define TMPL_MEM_TYPE_ALIGN 0
    4210 #define TMPL_MEM_FN_SUFF    U64NoAc
    4211 #define TMPL_MEM_FMT_TYPE   "%#018RX64"
    4212 #define TMPL_MEM_FMT_DESC   "qword"
    4213 #include "IEMAllMemRWTmpl.cpp.h"
    4214 
    4215 #define TMPL_MEM_TYPE       uint64_t
    4216 #define TMPL_MEM_TYPE_ALIGN (sizeof(uint64_t) * 2 - 1)
    4217 #define TMPL_MEM_FN_SUFF    U64AlignedU128
    4218 #define TMPL_MEM_FMT_TYPE   "%#018RX64"
    4219 #define TMPL_MEM_FMT_DESC   "qword"
    4220 #include "IEMAllMemRWTmpl.cpp.h"
    4221 
    4222 /* See IEMAllMemRWTmplInline.cpp.h */
    4223 #define TMPL_MEM_BY_REF
    4224 
    4225 #define TMPL_MEM_TYPE       RTFLOAT80U
    4226 #define TMPL_MEM_TYPE_ALIGN (sizeof(uint64_t) - 1)
    4227 #define TMPL_MEM_FN_SUFF    R80
    4228 #define TMPL_MEM_FMT_TYPE   "%.10Rhxs"
    4229 #define TMPL_MEM_FMT_DESC   "tword"
    4230 #include "IEMAllMemRWTmpl.cpp.h"
    4231 
    4232 #define TMPL_MEM_TYPE       RTPBCD80U
    4233 #define TMPL_MEM_TYPE_ALIGN (sizeof(uint64_t) - 1) /** @todo testcase: 80-bit BCD alignment */
    4234 #define TMPL_MEM_FN_SUFF    D80
    4235 #define TMPL_MEM_FMT_TYPE   "%.10Rhxs"
    4236 #define TMPL_MEM_FMT_DESC   "tword"
    4237 #include "IEMAllMemRWTmpl.cpp.h"
    4238 
    4239 #define TMPL_MEM_TYPE       RTUINT128U
    4240 #define TMPL_MEM_TYPE_ALIGN (sizeof(RTUINT128U) - 1)
    4241 #define TMPL_MEM_FN_SUFF    U128
    4242 #define TMPL_MEM_FMT_TYPE   "%.16Rhxs"
    4243 #define TMPL_MEM_FMT_DESC   "dqword"
    4244 #include "IEMAllMemRWTmpl.cpp.h"
    4245 
    4246 #define TMPL_MEM_TYPE           RTUINT128U
    4247 #define TMPL_MEM_TYPE_ALIGN     (sizeof(RTUINT128U) - 1)
    4248 #define TMPL_MEM_MAP_FLAGS_ADD  (IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_SSE)
    4249 #define TMPL_MEM_FN_SUFF        U128AlignedSse
    4250 #define TMPL_MEM_FMT_TYPE       "%.16Rhxs"
    4251 #define TMPL_MEM_FMT_DESC       "dqword"
    4252 #include "IEMAllMemRWTmpl.cpp.h"
    4253 
    4254 #define TMPL_MEM_TYPE       RTUINT128U
    4255 #define TMPL_MEM_TYPE_ALIGN 0
    4256 #define TMPL_MEM_FN_SUFF    U128NoAc
    4257 #define TMPL_MEM_FMT_TYPE   "%.16Rhxs"
    4258 #define TMPL_MEM_FMT_DESC   "dqword"
    4259 #include "IEMAllMemRWTmpl.cpp.h"
    4260 
    4261 #define TMPL_MEM_TYPE       RTUINT256U
    4262 #define TMPL_MEM_TYPE_ALIGN 0
    4263 #define TMPL_MEM_FN_SUFF    U256NoAc
    4264 #define TMPL_MEM_FMT_TYPE   "%.32Rhxs"
    4265 #define TMPL_MEM_FMT_DESC   "qqword"
    4266 #include "IEMAllMemRWTmpl.cpp.h"
    4267 
    4268 #define TMPL_MEM_TYPE           RTUINT256U
    4269 #define TMPL_MEM_TYPE_ALIGN     (sizeof(RTUINT256U) - 1)
    4270 #define TMPL_MEM_MAP_FLAGS_ADD  IEM_MEMMAP_F_ALIGN_GP
    4271 #define TMPL_MEM_FN_SUFF        U256AlignedAvx
    4272 #define TMPL_MEM_FMT_TYPE       "%.32Rhxs"
    4273 #define TMPL_MEM_FMT_DESC       "qqword"
    4274 #include "IEMAllMemRWTmpl.cpp.h"
    4275 
    4276 /**
    4277  * Fetches a data dword and zero extends it to a qword.
    4278  *
    4279  * @returns Strict VBox status code.
    4280  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4281  * @param   pu64Dst             Where to return the qword.
    4282  * @param   iSegReg             The index of the segment register to use for
    4283  *                              this access.  The base and limits are checked.
    4284  * @param   GCPtrMem            The address of the guest memory.
    4285  */
    4286 VBOXSTRICTRC iemMemFetchDataU32_ZX_U64(PVMCPUCC pVCpu, uint64_t *pu64Dst, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4287 {
    4288     /* The lazy approach for now... */
    4289     uint8_t         bUnmapInfo;
    4290     uint32_t const *pu32Src;
    4291     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pu32Src, &bUnmapInfo, sizeof(*pu32Src), iSegReg, GCPtrMem,
    4292                                 IEM_ACCESS_DATA_R, sizeof(*pu32Src) - 1);
    4293     if (rc == VINF_SUCCESS)
    4294     {
    4295         *pu64Dst = *pu32Src;
    4296         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4297         Log(("IEM RD dword %d|%RGv: %#010RX64\n", iSegReg, GCPtrMem, *pu64Dst));
    4298     }
    4299     return rc;
    4300 }
    4301 
    4302 
    4303 #ifdef SOME_UNUSED_FUNCTION
    4304 /**
    4305  * Fetches a data dword and sign extends it to a qword.
    4306  *
    4307  * @returns Strict VBox status code.
    4308  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4309  * @param   pu64Dst             Where to return the sign extended value.
    4310  * @param   iSegReg             The index of the segment register to use for
    4311  *                              this access.  The base and limits are checked.
    4312  * @param   GCPtrMem            The address of the guest memory.
    4313  */
    4314 VBOXSTRICTRC iemMemFetchDataS32SxU64(PVMCPUCC pVCpu, uint64_t *pu64Dst, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4315 {
    4316     /* The lazy approach for now... */
    4317     uint8_t        bUnmapInfo;
    4318     int32_t const *pi32Src;
    4319     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pi32Src, &bUnmapInfo, sizeof(*pi32Src), iSegReg, GCPtrMem,
    4320                                 IEM_ACCESS_DATA_R, sizeof(*pi32Src) - 1);
    4321     if (rc == VINF_SUCCESS)
    4322     {
    4323         *pu64Dst = *pi32Src;
    4324         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4325         Log(("IEM RD dword %d|%RGv: %#010x\n", iSegReg, GCPtrMem, (uint32_t)*pu64Dst));
    4326     }
    4327 #ifdef __GNUC__ /* warning: GCC may be a royal pain */
    4328     else
    4329         *pu64Dst = 0;
    4330 #endif
    4331     return rc;
    4332 }
    4333 #endif
    4334 
    4335 
    4336 /**
    4337  * Fetches a descriptor register (lgdt, lidt).
    4338  *
    4339  * @returns Strict VBox status code.
    4340  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4341  * @param   pcbLimit            Where to return the limit.
    4342  * @param   pGCPtrBase          Where to return the base.
    4343  * @param   iSegReg             The index of the segment register to use for
    4344  *                              this access.  The base and limits are checked.
    4345  * @param   GCPtrMem            The address of the guest memory.
    4346  * @param   enmOpSize           The effective operand size.
    4347  */
    4348 VBOXSTRICTRC iemMemFetchDataXdtr(PVMCPUCC pVCpu, uint16_t *pcbLimit, PRTGCPTR pGCPtrBase, uint8_t iSegReg,
    4349                                  RTGCPTR GCPtrMem, IEMMODE enmOpSize) RT_NOEXCEPT
    4350 {
    4351     /*
    4352      * Just like SIDT and SGDT, the LIDT and LGDT instructions are a
    4353      * little special:
    4354      *      - The two reads are done separately.
    4355      *      - Operand size override works in 16-bit and 32-bit code, but 64-bit.
    4356      *      - We suspect the 386 to actually commit the limit before the base in
    4357      *        some cases (search for 386 in  bs3CpuBasic2_lidt_lgdt_One).  We
    4358      *        don't try emulate this eccentric behavior, because it's not well
    4359      *        enough understood and rather hard to trigger.
    4360      *      - The 486 seems to do a dword limit read when the operand size is 32-bit.
    4361      */
    4362     VBOXSTRICTRC rcStrict;
    4363     if (IEM_IS_64BIT_CODE(pVCpu))
    4364     {
    4365         rcStrict = iemMemFetchDataU16(pVCpu, pcbLimit, iSegReg, GCPtrMem);
    4366         if (rcStrict == VINF_SUCCESS)
    4367             rcStrict = iemMemFetchDataU64(pVCpu, pGCPtrBase, iSegReg, GCPtrMem + 2);
    4368     }
    4369     else
    4370     {
    4371         uint32_t uTmp = 0; /* (Visual C++ maybe used uninitialized) */
    4372         if (enmOpSize == IEMMODE_32BIT)
    4373         {
    4374             if (IEM_GET_TARGET_CPU(pVCpu) != IEMTARGETCPU_486)
    4375             {
    4376                 rcStrict = iemMemFetchDataU16(pVCpu, pcbLimit, iSegReg, GCPtrMem);
    4377                 if (rcStrict == VINF_SUCCESS)
    4378                     rcStrict = iemMemFetchDataU32(pVCpu, &uTmp, iSegReg, GCPtrMem + 2);
    4379             }
    4380             else
    4381             {
    4382                 rcStrict = iemMemFetchDataU32(pVCpu, &uTmp, iSegReg, GCPtrMem);
    4383                 if (rcStrict == VINF_SUCCESS)
    4384                 {
    4385                     *pcbLimit = (uint16_t)uTmp;
    4386                     rcStrict = iemMemFetchDataU32(pVCpu, &uTmp, iSegReg, GCPtrMem + 2);
    4387                 }
    4388             }
    4389             if (rcStrict == VINF_SUCCESS)
    4390                 *pGCPtrBase = uTmp;
    4391         }
    4392         else
    4393         {
    4394             rcStrict = iemMemFetchDataU16(pVCpu, pcbLimit, iSegReg, GCPtrMem);
    4395             if (rcStrict == VINF_SUCCESS)
    4396             {
    4397                 rcStrict = iemMemFetchDataU32(pVCpu, &uTmp, iSegReg, GCPtrMem + 2);
    4398                 if (rcStrict == VINF_SUCCESS)
    4399                     *pGCPtrBase = uTmp & UINT32_C(0x00ffffff);
    4400             }
    4401         }
    4402     }
    4403     return rcStrict;
    4404 }
    4405 
    4406 
    4407 /**
    4408  * Stores a data dqword, SSE aligned.
    4409  *
    4410  * @returns Strict VBox status code.
    4411  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4412  * @param   iSegReg             The index of the segment register to use for
    4413  *                              this access.  The base and limits are checked.
    4414  * @param   GCPtrMem            The address of the guest memory.
    4415  * @param   u128Value           The value to store.
    4416  */
    4417 VBOXSTRICTRC iemMemStoreDataU128AlignedSse(PVMCPUCC pVCpu, uint8_t iSegReg, RTGCPTR GCPtrMem, RTUINT128U u128Value) RT_NOEXCEPT
    4418 {
    4419     /* The lazy approach for now... */
    4420     uint8_t      bUnmapInfo;
    4421     PRTUINT128U  pu128Dst;
    4422     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pu128Dst, &bUnmapInfo, sizeof(*pu128Dst), iSegReg, GCPtrMem, IEM_ACCESS_DATA_W,
    4423                                 (sizeof(*pu128Dst) - 1) | IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_SSE);
    4424     if (rc == VINF_SUCCESS)
    4425     {
    4426         pu128Dst->au64[0] = u128Value.au64[0];
    4427         pu128Dst->au64[1] = u128Value.au64[1];
    4428         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4429         Log5(("IEM WR dqword %d|%RGv: %.16Rhxs\n", iSegReg, GCPtrMem, pu128Dst));
    4430     }
    4431     return rc;
    4432 }
    4433 
    4434 
    4435 #ifdef IEM_WITH_SETJMP
    4436 /**
    4437  * Stores a data dqword, SSE aligned.
    4438  *
    4439  * @returns Strict VBox status code.
    4440  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4441  * @param   iSegReg             The index of the segment register to use for
    4442  *                              this access.  The base and limits are checked.
    4443  * @param   GCPtrMem            The address of the guest memory.
    4444  * @param   u128Value           The value to store.
    4445  */
    4446 void iemMemStoreDataU128AlignedSseJmp(PVMCPUCC pVCpu, uint8_t iSegReg, RTGCPTR GCPtrMem,
    4447                                       RTUINT128U u128Value) IEM_NOEXCEPT_MAY_LONGJMP
    4448 {
    4449     /* The lazy approach for now... */
    4450     uint8_t     bUnmapInfo;
    4451     PRTUINT128U pu128Dst = (PRTUINT128U)iemMemMapJmp(pVCpu, &bUnmapInfo, sizeof(*pu128Dst), iSegReg, GCPtrMem, IEM_ACCESS_DATA_W,
    4452                                                      (sizeof(*pu128Dst) - 1) | IEM_MEMMAP_F_ALIGN_GP | IEM_MEMMAP_F_ALIGN_SSE);
    4453     pu128Dst->au64[0] = u128Value.au64[0];
    4454     pu128Dst->au64[1] = u128Value.au64[1];
    4455     iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);
    4456     Log5(("IEM WR dqword %d|%RGv: %.16Rhxs\n", iSegReg, GCPtrMem, pu128Dst));
    4457 }
    4458 #endif
    4459 
    4460 
    4461 /**
    4462  * Stores a data dqword.
    4463  *
    4464  * @returns Strict VBox status code.
    4465  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4466  * @param   iSegReg             The index of the segment register to use for
    4467  *                              this access.  The base and limits are checked.
    4468  * @param   GCPtrMem            The address of the guest memory.
    4469  * @param   pu256Value          Pointer to the value to store.
    4470  */
    4471 VBOXSTRICTRC iemMemStoreDataU256(PVMCPUCC pVCpu, uint8_t iSegReg, RTGCPTR GCPtrMem, PCRTUINT256U pu256Value) RT_NOEXCEPT
    4472 {
    4473     /* The lazy approach for now... */
    4474     uint8_t      bUnmapInfo;
    4475     PRTUINT256U  pu256Dst;
    4476     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pu256Dst, &bUnmapInfo, sizeof(*pu256Dst), iSegReg, GCPtrMem,
    4477                                 IEM_ACCESS_DATA_W, 0 /* NO_AC variant */);
    4478     if (rc == VINF_SUCCESS)
    4479     {
    4480         pu256Dst->au64[0] = pu256Value->au64[0];
    4481         pu256Dst->au64[1] = pu256Value->au64[1];
    4482         pu256Dst->au64[2] = pu256Value->au64[2];
    4483         pu256Dst->au64[3] = pu256Value->au64[3];
    4484         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4485         Log5(("IEM WR qqword %d|%RGv: %.32Rhxs\n", iSegReg, GCPtrMem, pu256Dst));
    4486     }
    4487     return rc;
    4488 }
    4489 
    4490 
    4491 #ifdef IEM_WITH_SETJMP
    4492 /**
    4493  * Stores a data dqword, longjmp on error.
    4494  *
    4495  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4496  * @param   iSegReg             The index of the segment register to use for
    4497  *                              this access.  The base and limits are checked.
    4498  * @param   GCPtrMem            The address of the guest memory.
    4499  * @param   pu256Value          Pointer to the value to store.
    4500  */
    4501 void iemMemStoreDataU256Jmp(PVMCPUCC pVCpu, uint8_t iSegReg, RTGCPTR GCPtrMem, PCRTUINT256U pu256Value) IEM_NOEXCEPT_MAY_LONGJMP
    4502 {
    4503     /* The lazy approach for now... */
    4504     uint8_t     bUnmapInfo;
    4505     PRTUINT256U pu256Dst = (PRTUINT256U)iemMemMapJmp(pVCpu, &bUnmapInfo, sizeof(*pu256Dst), iSegReg, GCPtrMem,
    4506                                                      IEM_ACCESS_DATA_W, 0 /* NO_AC variant */);
    4507     pu256Dst->au64[0] = pu256Value->au64[0];
    4508     pu256Dst->au64[1] = pu256Value->au64[1];
    4509     pu256Dst->au64[2] = pu256Value->au64[2];
    4510     pu256Dst->au64[3] = pu256Value->au64[3];
    4511     iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);
    4512     Log5(("IEM WR qqword %d|%RGv: %.32Rhxs\n", iSegReg, GCPtrMem, pu256Dst));
    4513 }
    4514 #endif
    4515 
    4516 
    4517 /**
    4518  * Stores a descriptor register (sgdt, sidt).
    4519  *
    4520  * @returns Strict VBox status code.
    4521  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4522  * @param   cbLimit             The limit.
    4523  * @param   GCPtrBase           The base address.
    4524  * @param   iSegReg             The index of the segment register to use for
    4525  *                              this access.  The base and limits are checked.
    4526  * @param   GCPtrMem            The address of the guest memory.
    4527  */
    4528 VBOXSTRICTRC iemMemStoreDataXdtr(PVMCPUCC pVCpu, uint16_t cbLimit, RTGCPTR GCPtrBase, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4529 {
    4530     /*
    4531      * The SIDT and SGDT instructions actually stores the data using two
    4532      * independent writes (see bs3CpuBasic2_sidt_sgdt_One).  The instructions
    4533      * does not respond to opsize prefixes.
    4534      */
    4535     VBOXSTRICTRC rcStrict = iemMemStoreDataU16(pVCpu, iSegReg, GCPtrMem, cbLimit);
    4536     if (rcStrict == VINF_SUCCESS)
    4537     {
    4538         if (IEM_IS_16BIT_CODE(pVCpu))
    4539             rcStrict = iemMemStoreDataU32(pVCpu, iSegReg, GCPtrMem + 2,
    4540                                           IEM_GET_TARGET_CPU(pVCpu) <= IEMTARGETCPU_286
    4541                                           ? (uint32_t)GCPtrBase | UINT32_C(0xff000000) : (uint32_t)GCPtrBase);
    4542         else if (IEM_IS_32BIT_CODE(pVCpu))
    4543             rcStrict = iemMemStoreDataU32(pVCpu, iSegReg, GCPtrMem + 2, (uint32_t)GCPtrBase);
    4544         else
    4545             rcStrict = iemMemStoreDataU64(pVCpu, iSegReg, GCPtrMem + 2, GCPtrBase);
    4546     }
    4547     return rcStrict;
    4548 }
    4549 
    4550 
    4551 /**
    4552  * Begin a special stack push (used by interrupt, exceptions and such).
    4553  *
    4554  * This will raise \#SS or \#PF if appropriate.
    4555  *
    4556  * @returns Strict VBox status code.
    4557  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4558  * @param   cbMem               The number of bytes to push onto the stack.
    4559  * @param   cbAlign             The alignment mask (7, 3, 1).
    4560  * @param   ppvMem              Where to return the pointer to the stack memory.
    4561  *                              As with the other memory functions this could be
    4562  *                              direct access or bounce buffered access, so
    4563  *                              don't commit register until the commit call
    4564  *                              succeeds.
    4565  * @param   pbUnmapInfo         Where to store unmap info for
    4566  *                              iemMemStackPushCommitSpecial.
    4567  * @param   puNewRsp            Where to return the new RSP value.  This must be
    4568  *                              passed unchanged to
    4569  *                              iemMemStackPushCommitSpecial().
    4570  */
    4571 VBOXSTRICTRC iemMemStackPushBeginSpecial(PVMCPUCC pVCpu, size_t cbMem, uint32_t cbAlign,
    4572                                          void **ppvMem, uint8_t *pbUnmapInfo, uint64_t *puNewRsp) RT_NOEXCEPT
    4573 {
    4574     Assert(cbMem < UINT8_MAX);
    4575     RTGCPTR GCPtrTop = iemRegGetRspForPush(pVCpu, (uint8_t)cbMem, puNewRsp);
    4576     return iemMemMap(pVCpu, ppvMem, pbUnmapInfo, cbMem, X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_W, cbAlign);
    4577 }
    4578 
    4579 
    4580 /**
    4581  * Commits a special stack push (started by iemMemStackPushBeginSpecial).
    4582  *
    4583  * This will update the rSP.
    4584  *
    4585  * @returns Strict VBox status code.
    4586  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4587  * @param   bUnmapInfo          Unmap info set by iemMemStackPushBeginSpecial.
    4588  * @param   uNewRsp             The new RSP value returned by
    4589  *                              iemMemStackPushBeginSpecial().
    4590  */
    4591 VBOXSTRICTRC iemMemStackPushCommitSpecial(PVMCPUCC pVCpu, uint8_t bUnmapInfo, uint64_t uNewRsp) RT_NOEXCEPT
    4592 {
    4593     VBOXSTRICTRC rcStrict = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4594     if (rcStrict == VINF_SUCCESS)
    4595         pVCpu->cpum.GstCtx.rsp = uNewRsp;
    4596     return rcStrict;
    4597 }
    4598 
    4599 
    4600 /**
    4601  * Begin a special stack pop (used by iret, retf and such).
    4602  *
    4603  * This will raise \#SS or \#PF if appropriate.
    4604  *
    4605  * @returns Strict VBox status code.
    4606  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4607  * @param   cbMem               The number of bytes to pop from the stack.
    4608  * @param   cbAlign             The alignment mask (7, 3, 1).
    4609  * @param   ppvMem              Where to return the pointer to the stack memory.
    4610  * @param   pbUnmapInfo         Where to store unmap info for
    4611  *                              iemMemStackPopDoneSpecial.
    4612  * @param   puNewRsp            Where to return the new RSP value.  This must be
    4613  *                              assigned to CPUMCTX::rsp manually some time
    4614  *                              after iemMemStackPopDoneSpecial() has been
    4615  *                              called.
    4616  */
    4617 VBOXSTRICTRC iemMemStackPopBeginSpecial(PVMCPUCC pVCpu, size_t cbMem, uint32_t cbAlign,
    4618                                         void const **ppvMem, uint8_t *pbUnmapInfo, uint64_t *puNewRsp) RT_NOEXCEPT
    4619 {
    4620     Assert(cbMem < UINT8_MAX);
    4621     RTGCPTR     GCPtrTop = iemRegGetRspForPop(pVCpu, (uint8_t)cbMem, puNewRsp);
    4622     return iemMemMap(pVCpu, (void **)ppvMem, pbUnmapInfo, cbMem, X86_SREG_SS, GCPtrTop, IEM_ACCESS_STACK_R, cbAlign);
    4623 }
    4624 
    4625 
    4626 /**
    4627  * Continue a special stack pop (used by iret and retf), for the purpose of
    4628  * retrieving a new stack pointer.
    4629  *
    4630  * This will raise \#SS or \#PF if appropriate.
    4631  *
    4632  * @returns Strict VBox status code.
    4633  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4634  * @param   off                 Offset from the top of the stack. This is zero
    4635  *                              except in the retf case.
    4636  * @param   cbMem               The number of bytes to pop from the stack.
    4637  * @param   ppvMem              Where to return the pointer to the stack memory.
    4638  * @param   pbUnmapInfo         Where to store unmap info for
    4639  *                              iemMemStackPopDoneSpecial.
    4640  * @param   uCurNewRsp          The current uncommitted RSP value.  (No need to
    4641  *                              return this because all use of this function is
    4642  *                              to retrieve a new value and anything we return
    4643  *                              here would be discarded.)
    4644  */
    4645 VBOXSTRICTRC iemMemStackPopContinueSpecial(PVMCPUCC pVCpu, size_t off, size_t cbMem,
    4646                                            void const **ppvMem, uint8_t *pbUnmapInfo, uint64_t uCurNewRsp) RT_NOEXCEPT
    4647 {
    4648     Assert(cbMem < UINT8_MAX);
    4649 
    4650     /* The essense of iemRegGetRspForPopEx and friends: */ /** @todo put this into a inlined function? */
    4651     RTGCPTR GCPtrTop;
    4652     if (IEM_IS_64BIT_CODE(pVCpu))
    4653         GCPtrTop = uCurNewRsp;
    4654     else if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
    4655         GCPtrTop = (uint32_t)uCurNewRsp;
    4656     else
    4657         GCPtrTop = (uint16_t)uCurNewRsp;
    4658 
    4659     return iemMemMap(pVCpu, (void **)ppvMem, pbUnmapInfo, cbMem, X86_SREG_SS, GCPtrTop + off, IEM_ACCESS_STACK_R,
    4660                      0 /* checked in iemMemStackPopBeginSpecial */);
    4661 }
    4662 
    4663 
    4664 /**
    4665  * Done with a special stack pop (started by iemMemStackPopBeginSpecial or
    4666  * iemMemStackPopContinueSpecial).
    4667  *
    4668  * The caller will manually commit the rSP.
    4669  *
    4670  * @returns Strict VBox status code.
    4671  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4672  * @param   bUnmapInfo          Unmap information returned by
    4673  *                              iemMemStackPopBeginSpecial() or
    4674  *                              iemMemStackPopContinueSpecial().
    4675  */
    4676 VBOXSTRICTRC iemMemStackPopDoneSpecial(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT
    4677 {
    4678     return iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4679 }
    4680 
    4681 
    4682 /**
    4683  * Fetches a system table byte.
    4684  *
    4685  * @returns Strict VBox status code.
    4686  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4687  * @param   pbDst               Where to return the byte.
    4688  * @param   iSegReg             The index of the segment register to use for
    4689  *                              this access.  The base and limits are checked.
    4690  * @param   GCPtrMem            The address of the guest memory.
    4691  */
    4692 VBOXSTRICTRC iemMemFetchSysU8(PVMCPUCC pVCpu, uint8_t *pbDst, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4693 {
    4694     /* The lazy approach for now... */
    4695     uint8_t        bUnmapInfo;
    4696     uint8_t const *pbSrc;
    4697     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pbSrc, &bUnmapInfo, sizeof(*pbSrc), iSegReg, GCPtrMem, IEM_ACCESS_SYS_R, 0);
    4698     if (rc == VINF_SUCCESS)
    4699     {
    4700         *pbDst = *pbSrc;
    4701         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4702     }
    4703     return rc;
    4704 }
    4705 
    4706 
    4707 /**
    4708  * Fetches a system table word.
    4709  *
    4710  * @returns Strict VBox status code.
    4711  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4712  * @param   pu16Dst             Where to return the word.
    4713  * @param   iSegReg             The index of the segment register to use for
    4714  *                              this access.  The base and limits are checked.
    4715  * @param   GCPtrMem            The address of the guest memory.
    4716  */
    4717 VBOXSTRICTRC iemMemFetchSysU16(PVMCPUCC pVCpu, uint16_t *pu16Dst, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4718 {
    4719     /* The lazy approach for now... */
    4720     uint8_t         bUnmapInfo;
    4721     uint16_t const *pu16Src;
    4722     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pu16Src, &bUnmapInfo, sizeof(*pu16Src), iSegReg, GCPtrMem, IEM_ACCESS_SYS_R, 0);
    4723     if (rc == VINF_SUCCESS)
    4724     {
    4725         *pu16Dst = *pu16Src;
    4726         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4727     }
    4728     return rc;
    4729 }
    4730 
    4731 
    4732 /**
    4733  * Fetches a system table dword.
    4734  *
    4735  * @returns Strict VBox status code.
    4736  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4737  * @param   pu32Dst             Where to return the dword.
    4738  * @param   iSegReg             The index of the segment register to use for
    4739  *                              this access.  The base and limits are checked.
    4740  * @param   GCPtrMem            The address of the guest memory.
    4741  */
    4742 VBOXSTRICTRC iemMemFetchSysU32(PVMCPUCC pVCpu, uint32_t *pu32Dst, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4743 {
    4744     /* The lazy approach for now... */
    4745     uint8_t         bUnmapInfo;
    4746     uint32_t const *pu32Src;
    4747     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pu32Src, &bUnmapInfo, sizeof(*pu32Src), iSegReg, GCPtrMem, IEM_ACCESS_SYS_R, 0);
    4748     if (rc == VINF_SUCCESS)
    4749     {
    4750         *pu32Dst = *pu32Src;
    4751         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4752     }
    4753     return rc;
    4754 }
    4755 
    4756 
    4757 /**
    4758  * Fetches a system table qword.
    4759  *
    4760  * @returns Strict VBox status code.
    4761  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4762  * @param   pu64Dst             Where to return the qword.
    4763  * @param   iSegReg             The index of the segment register to use for
    4764  *                              this access.  The base and limits are checked.
    4765  * @param   GCPtrMem            The address of the guest memory.
    4766  */
    4767 VBOXSTRICTRC iemMemFetchSysU64(PVMCPUCC pVCpu, uint64_t *pu64Dst, uint8_t iSegReg, RTGCPTR GCPtrMem) RT_NOEXCEPT
    4768 {
    4769     /* The lazy approach for now... */
    4770     uint8_t         bUnmapInfo;
    4771     uint64_t const *pu64Src;
    4772     VBOXSTRICTRC rc = iemMemMap(pVCpu, (void **)&pu64Src, &bUnmapInfo, sizeof(*pu64Src), iSegReg, GCPtrMem, IEM_ACCESS_SYS_R, 0);
    4773     if (rc == VINF_SUCCESS)
    4774     {
    4775         *pu64Dst = *pu64Src;
    4776         rc = iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4777     }
    4778     return rc;
    4779 }
    4780 
    4781 
    4782 /**
    4783  * Fetches a descriptor table entry with caller specified error code.
    4784  *
    4785  * @returns Strict VBox status code.
    4786  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4787  * @param   pDesc               Where to return the descriptor table entry.
    4788  * @param   uSel                The selector which table entry to fetch.
    4789  * @param   uXcpt               The exception to raise on table lookup error.
    4790  * @param   uErrorCode          The error code associated with the exception.
    4791  */
    4792 VBOXSTRICTRC iemMemFetchSelDescWithErr(PVMCPUCC pVCpu, PIEMSELDESC pDesc, uint16_t uSel,
    4793                                        uint8_t uXcpt, uint16_t uErrorCode)  RT_NOEXCEPT
    4794 {
    4795     AssertPtr(pDesc);
    4796     IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_GDTR | CPUMCTX_EXTRN_LDTR);
    4797 
    4798     /** @todo did the 286 require all 8 bytes to be accessible? */
    4799     /*
    4800      * Get the selector table base and check bounds.
    4801      */
    4802     RTGCPTR GCPtrBase;
    4803     if (uSel & X86_SEL_LDT)
    4804     {
    4805         if (   !pVCpu->cpum.GstCtx.ldtr.Attr.n.u1Present
    4806             || (uSel | X86_SEL_RPL_LDT) > pVCpu->cpum.GstCtx.ldtr.u32Limit )
    4807         {
    4808             LogEx(LOG_GROUP_IEM, ("iemMemFetchSelDesc: LDT selector %#x is out of bounds (%3x) or ldtr is NP (%#x)\n",
    4809                    uSel, pVCpu->cpum.GstCtx.ldtr.u32Limit, pVCpu->cpum.GstCtx.ldtr.Sel));
    4810             return iemRaiseXcptOrInt(pVCpu, 0, uXcpt, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR,
    4811                                      uErrorCode, 0);
    4812         }
    4813 
    4814         Assert(pVCpu->cpum.GstCtx.ldtr.Attr.n.u1Present);
    4815         GCPtrBase = pVCpu->cpum.GstCtx.ldtr.u64Base;
    4816     }
    4817     else
    4818     {
    4819         if ((uSel | X86_SEL_RPL_LDT) > pVCpu->cpum.GstCtx.gdtr.cbGdt)
    4820         {
    4821             LogEx(LOG_GROUP_IEM, ("iemMemFetchSelDesc: GDT selector %#x is out of bounds (%3x)\n", uSel, pVCpu->cpum.GstCtx.gdtr.cbGdt));
    4822             return iemRaiseXcptOrInt(pVCpu, 0, uXcpt, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR,
    4823                                      uErrorCode, 0);
    4824         }
    4825         GCPtrBase = pVCpu->cpum.GstCtx.gdtr.pGdt;
    4826     }
    4827 
    4828     /*
    4829      * Read the legacy descriptor and maybe the long mode extensions if
    4830      * required.
    4831      */
    4832     VBOXSTRICTRC rcStrict;
    4833     if (IEM_GET_TARGET_CPU(pVCpu) > IEMTARGETCPU_286)
    4834         rcStrict = iemMemFetchSysU64(pVCpu, &pDesc->Legacy.u, UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK));
    4835     else
    4836     {
    4837         rcStrict     = iemMemFetchSysU16(pVCpu, &pDesc->Legacy.au16[0], UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK) + 0);
    4838         if (rcStrict == VINF_SUCCESS)
    4839             rcStrict = iemMemFetchSysU16(pVCpu, &pDesc->Legacy.au16[1], UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK) + 2);
    4840         if (rcStrict == VINF_SUCCESS)
    4841             rcStrict = iemMemFetchSysU16(pVCpu, &pDesc->Legacy.au16[2], UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK) + 4);
    4842         if (rcStrict == VINF_SUCCESS)
    4843             pDesc->Legacy.au16[3] = 0;
    4844         else
    4845             return rcStrict;
    4846     }
    4847 
    4848     if (rcStrict == VINF_SUCCESS)
    4849     {
    4850         if (   !IEM_IS_LONG_MODE(pVCpu)
    4851             || pDesc->Legacy.Gen.u1DescType)
    4852             pDesc->Long.au64[1] = 0;
    4853         else if (   (uint32_t)(uSel | X86_SEL_RPL_LDT) + 8
    4854                  <= (uSel & X86_SEL_LDT ? pVCpu->cpum.GstCtx.ldtr.u32Limit : pVCpu->cpum.GstCtx.gdtr.cbGdt))
    4855             rcStrict = iemMemFetchSysU64(pVCpu, &pDesc->Long.au64[1], UINT8_MAX, GCPtrBase + (uSel | X86_SEL_RPL_LDT) + 1);
    4856         else
    4857         {
    4858             LogEx(LOG_GROUP_IEM,("iemMemFetchSelDesc: system selector %#x is out of bounds\n", uSel));
    4859             /** @todo is this the right exception? */
    4860             return iemRaiseXcptOrInt(pVCpu, 0, uXcpt, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR, uErrorCode, 0);
    4861         }
    4862     }
    4863     return rcStrict;
    4864 }
    4865 
    4866 
    4867 /**
    4868  * Fetches a descriptor table entry.
    4869  *
    4870  * @returns Strict VBox status code.
    4871  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4872  * @param   pDesc               Where to return the descriptor table entry.
    4873  * @param   uSel                The selector which table entry to fetch.
    4874  * @param   uXcpt               The exception to raise on table lookup error.
    4875  */
    4876 VBOXSTRICTRC iemMemFetchSelDesc(PVMCPUCC pVCpu, PIEMSELDESC pDesc, uint16_t uSel, uint8_t uXcpt) RT_NOEXCEPT
    4877 {
    4878     return iemMemFetchSelDescWithErr(pVCpu, pDesc, uSel, uXcpt, uSel & X86_SEL_MASK_OFF_RPL);
    4879 }
    4880 
    4881 
    4882 /**
    4883  * Marks the selector descriptor as accessed (only non-system descriptors).
    4884  *
    4885  * This function ASSUMES that iemMemFetchSelDesc has be called previously and
    4886  * will therefore skip the limit checks.
    4887  *
    4888  * @returns Strict VBox status code.
    4889  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4890  * @param   uSel                The selector.
    4891  */
    4892 VBOXSTRICTRC iemMemMarkSelDescAccessed(PVMCPUCC pVCpu, uint16_t uSel) RT_NOEXCEPT
    4893 {
    4894     /*
    4895      * Get the selector table base and calculate the entry address.
    4896      */
    4897     RTGCPTR GCPtr = uSel & X86_SEL_LDT
    4898                   ? pVCpu->cpum.GstCtx.ldtr.u64Base
    4899                   : pVCpu->cpum.GstCtx.gdtr.pGdt;
    4900     GCPtr += uSel & X86_SEL_MASK;
    4901 
    4902     /*
    4903      * ASMAtomicBitSet will assert if the address is misaligned, so do some
    4904      * ugly stuff to avoid this.  This will make sure it's an atomic access
    4905      * as well more or less remove any question about 8-bit or 32-bit accesss.
    4906      */
    4907     VBOXSTRICTRC        rcStrict;
    4908     uint8_t             bUnmapInfo;
    4909     uint32_t volatile  *pu32;
    4910     if ((GCPtr & 3) == 0)
    4911     {
    4912         /* The normal case, map the 32-bit bits around the accessed bit (40). */
    4913         GCPtr += 2 + 2;
    4914         rcStrict = iemMemMap(pVCpu, (void **)&pu32, &bUnmapInfo, 4, UINT8_MAX, GCPtr, IEM_ACCESS_SYS_RW, 0);
    4915         if (rcStrict != VINF_SUCCESS)
    4916             return rcStrict;
    4917         ASMAtomicBitSet(pu32, 8); /* X86_SEL_TYPE_ACCESSED is 1, but it is preceeded by u8BaseHigh1. */
    4918     }
    4919     else
    4920     {
    4921         /* The misaligned GDT/LDT case, map the whole thing. */
    4922         rcStrict = iemMemMap(pVCpu, (void **)&pu32, &bUnmapInfo, 8, UINT8_MAX, GCPtr, IEM_ACCESS_SYS_RW, 0);
    4923         if (rcStrict != VINF_SUCCESS)
    4924             return rcStrict;
    4925         switch ((uintptr_t)pu32 & 3)
    4926         {
    4927             case 0: ASMAtomicBitSet(pu32,                         40 + 0 -  0); break;
    4928             case 1: ASMAtomicBitSet((uint8_t volatile *)pu32 + 3, 40 + 0 - 24); break;
    4929             case 2: ASMAtomicBitSet((uint8_t volatile *)pu32 + 2, 40 + 0 - 16); break;
    4930             case 3: ASMAtomicBitSet((uint8_t volatile *)pu32 + 1, 40 + 0 -  8); break;
    4931         }
    4932     }
    4933 
    4934     return iemMemCommitAndUnmap(pVCpu, bUnmapInfo);
    4935 }
    4936 
    4937 
    4938 #undef  LOG_GROUP
    4939 #define LOG_GROUP LOG_GROUP_IEM
    4940 
    4941 /** @} */
    4942 
    4943 /** @name   Opcode Helpers.
    4944  * @{
    4945  */
    4946 
    4947 /**
    4948  * Calculates the effective address of a ModR/M memory operand.
    4949  *
    4950  * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR.
    4951  *
    4952  * @return  Strict VBox status code.
    4953  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    4954  * @param   bRm                 The ModRM byte.
    4955  * @param   cbImmAndRspOffset   - First byte: The size of any immediate
    4956  *                                following the effective address opcode bytes
    4957  *                                (only for RIP relative addressing).
    4958  *                              - Second byte: RSP displacement (for POP [ESP]).
    4959  * @param   pGCPtrEff           Where to return the effective address.
    4960  */
    4961 VBOXSTRICTRC iemOpHlpCalcRmEffAddr(PVMCPUCC pVCpu, uint8_t bRm, uint32_t cbImmAndRspOffset, PRTGCPTR pGCPtrEff) RT_NOEXCEPT
    4962 {
    4963     Log5(("iemOpHlpCalcRmEffAddr: bRm=%#x\n", bRm));
    4964 # define SET_SS_DEF() \
    4965     do \
    4966     { \
    4967         if (!(pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SEG_MASK)) \
    4968             pVCpu->iem.s.iEffSeg = X86_SREG_SS; \
    4969     } while (0)
    4970 
    4971     if (!IEM_IS_64BIT_CODE(pVCpu))
    4972     {
    4973 /** @todo Check the effective address size crap! */
    4974         if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_16BIT)
    4975         {
    4976             uint16_t u16EffAddr;
    4977 
    4978             /* Handle the disp16 form with no registers first. */
    4979             if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)
    4980                 IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);
    4981             else
    4982             {
    4983                 /* Get the displacment. */
    4984                 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    4985                 {
    4986                     case 0:  u16EffAddr = 0;                             break;
    4987                     case 1:  IEM_OPCODE_GET_NEXT_S8_SX_U16(&u16EffAddr); break;
    4988                     case 2:  IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);       break;
    4989                     default: AssertFailedReturn(VERR_IEM_IPE_1); /* (caller checked for these) */
    4990                 }
    4991 
    4992                 /* Add the base and index registers to the disp. */
    4993                 switch (bRm & X86_MODRM_RM_MASK)
    4994                 {
    4995                     case 0: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.si; break;
    4996                     case 1: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.di; break;
    4997                     case 2: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.si; SET_SS_DEF(); break;
    4998                     case 3: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.di; SET_SS_DEF(); break;
    4999                     case 4: u16EffAddr += pVCpu->cpum.GstCtx.si;            break;
    5000                     case 5: u16EffAddr += pVCpu->cpum.GstCtx.di;            break;
    5001                     case 6: u16EffAddr += pVCpu->cpum.GstCtx.bp;            SET_SS_DEF(); break;
    5002                     case 7: u16EffAddr += pVCpu->cpum.GstCtx.bx;            break;
    5003                 }
    5004             }
    5005 
    5006             *pGCPtrEff = u16EffAddr;
    5007         }
    5008         else
    5009         {
    5010             Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5011             uint32_t u32EffAddr;
    5012 
    5013             /* Handle the disp32 form with no registers first. */
    5014             if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    5015                 IEM_OPCODE_GET_NEXT_U32(&u32EffAddr);
    5016             else
    5017             {
    5018                 /* Get the register (or SIB) value. */
    5019                 switch ((bRm & X86_MODRM_RM_MASK))
    5020                 {
    5021                     case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    5022                     case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    5023                     case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    5024                     case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    5025                     case 4: /* SIB */
    5026                     {
    5027                         uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
    5028 
    5029                         /* Get the index and scale it. */
    5030                         switch ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)
    5031                         {
    5032                             case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    5033                             case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    5034                             case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    5035                             case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    5036                             case 4: u32EffAddr = 0; /*none */ break;
    5037                             case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;
    5038                             case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    5039                             case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    5040                             IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5041                         }
    5042                         u32EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    5043 
    5044                         /* add base */
    5045                         switch (bSib & X86_SIB_BASE_MASK)
    5046                         {
    5047                             case 0: u32EffAddr += pVCpu->cpum.GstCtx.eax; break;
    5048                             case 1: u32EffAddr += pVCpu->cpum.GstCtx.ecx; break;
    5049                             case 2: u32EffAddr += pVCpu->cpum.GstCtx.edx; break;
    5050                             case 3: u32EffAddr += pVCpu->cpum.GstCtx.ebx; break;
    5051                             case 4: u32EffAddr += pVCpu->cpum.GstCtx.esp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
    5052                             case 5:
    5053                                 if ((bRm & X86_MODRM_MOD_MASK) != 0)
    5054                                 {
    5055                                     u32EffAddr += pVCpu->cpum.GstCtx.ebp;
    5056                                     SET_SS_DEF();
    5057                                 }
    5058                                 else
    5059                                 {
    5060                                     uint32_t u32Disp;
    5061                                     IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5062                                     u32EffAddr += u32Disp;
    5063                                 }
    5064                                 break;
    5065                             case 6: u32EffAddr += pVCpu->cpum.GstCtx.esi; break;
    5066                             case 7: u32EffAddr += pVCpu->cpum.GstCtx.edi; break;
    5067                             IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5068                         }
    5069                         break;
    5070                     }
    5071                     case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; SET_SS_DEF(); break;
    5072                     case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    5073                     case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    5074                     IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5075                 }
    5076 
    5077                 /* Get and add the displacement. */
    5078                 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5079                 {
    5080                     case 0:
    5081                         break;
    5082                     case 1:
    5083                     {
    5084                         int8_t i8Disp; IEM_OPCODE_GET_NEXT_S8(&i8Disp);
    5085                         u32EffAddr += i8Disp;
    5086                         break;
    5087                     }
    5088                     case 2:
    5089                     {
    5090                         uint32_t u32Disp; IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5091                         u32EffAddr += u32Disp;
    5092                         break;
    5093                     }
    5094                     default:
    5095                         AssertFailedReturn(VERR_IEM_IPE_2); /* (caller checked for these) */
    5096                 }
    5097 
    5098             }
    5099             Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5100             *pGCPtrEff = u32EffAddr;
    5101         }
    5102     }
    5103     else
    5104     {
    5105         uint64_t u64EffAddr;
    5106 
    5107         /* Handle the rip+disp32 form with no registers first. */
    5108         if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    5109         {
    5110             IEM_OPCODE_GET_NEXT_S32_SX_U64(&u64EffAddr);
    5111             u64EffAddr += pVCpu->cpum.GstCtx.rip + IEM_GET_INSTR_LEN(pVCpu) + (cbImmAndRspOffset & UINT32_C(0xff));
    5112         }
    5113         else
    5114         {
    5115             /* Get the register (or SIB) value. */
    5116             switch ((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB)
    5117             {
    5118                 case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    5119                 case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    5120                 case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    5121                 case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    5122                 case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; SET_SS_DEF(); break;
    5123                 case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    5124                 case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    5125                 case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    5126                 case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    5127                 case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    5128                 case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    5129                 case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    5130                 case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    5131                 case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    5132                 /* SIB */
    5133                 case 4:
    5134                 case 12:
    5135                 {
    5136                     uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
    5137 
    5138                     /* Get the index and scale it. */
    5139                     switch (((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) | pVCpu->iem.s.uRexIndex)
    5140                     {
    5141                         case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    5142                         case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    5143                         case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    5144                         case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    5145                         case  4: u64EffAddr = 0; /*none */ break;
    5146                         case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;
    5147                         case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    5148                         case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    5149                         case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    5150                         case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    5151                         case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    5152                         case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    5153                         case 12: u64EffAddr = pVCpu->cpum.GstCtx.r12; break;
    5154                         case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    5155                         case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    5156                         case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    5157                         IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5158                     }
    5159                     u64EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    5160 
    5161                     /* add base */
    5162                     switch ((bSib & X86_SIB_BASE_MASK) | pVCpu->iem.s.uRexB)
    5163                     {
    5164                         case  0: u64EffAddr += pVCpu->cpum.GstCtx.rax; break;
    5165                         case  1: u64EffAddr += pVCpu->cpum.GstCtx.rcx; break;
    5166                         case  2: u64EffAddr += pVCpu->cpum.GstCtx.rdx; break;
    5167                         case  3: u64EffAddr += pVCpu->cpum.GstCtx.rbx; break;
    5168                         case  4: u64EffAddr += pVCpu->cpum.GstCtx.rsp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
    5169                         case  6: u64EffAddr += pVCpu->cpum.GstCtx.rsi; break;
    5170                         case  7: u64EffAddr += pVCpu->cpum.GstCtx.rdi; break;
    5171                         case  8: u64EffAddr += pVCpu->cpum.GstCtx.r8;  break;
    5172                         case  9: u64EffAddr += pVCpu->cpum.GstCtx.r9;  break;
    5173                         case 10: u64EffAddr += pVCpu->cpum.GstCtx.r10; break;
    5174                         case 11: u64EffAddr += pVCpu->cpum.GstCtx.r11; break;
    5175                         case 12: u64EffAddr += pVCpu->cpum.GstCtx.r12; break;
    5176                         case 14: u64EffAddr += pVCpu->cpum.GstCtx.r14; break;
    5177                         case 15: u64EffAddr += pVCpu->cpum.GstCtx.r15; break;
    5178                         /* complicated encodings */
    5179                         case 5:
    5180                         case 13:
    5181                             if ((bRm & X86_MODRM_MOD_MASK) != 0)
    5182                             {
    5183                                 if (!pVCpu->iem.s.uRexB)
    5184                                 {
    5185                                     u64EffAddr += pVCpu->cpum.GstCtx.rbp;
    5186                                     SET_SS_DEF();
    5187                                 }
    5188                                 else
    5189                                     u64EffAddr += pVCpu->cpum.GstCtx.r13;
    5190                             }
    5191                             else
    5192                             {
    5193                                 uint32_t u32Disp;
    5194                                 IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5195                                 u64EffAddr += (int32_t)u32Disp;
    5196                             }
    5197                             break;
    5198                         IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5199                     }
    5200                     break;
    5201                 }
    5202                 IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5203             }
    5204 
    5205             /* Get and add the displacement. */
    5206             switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5207             {
    5208                 case 0:
    5209                     break;
    5210                 case 1:
    5211                 {
    5212                     int8_t i8Disp;
    5213                     IEM_OPCODE_GET_NEXT_S8(&i8Disp);
    5214                     u64EffAddr += i8Disp;
    5215                     break;
    5216                 }
    5217                 case 2:
    5218                 {
    5219                     uint32_t u32Disp;
    5220                     IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5221                     u64EffAddr += (int32_t)u32Disp;
    5222                     break;
    5223                 }
    5224                 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* (caller checked for these) */
    5225             }
    5226 
    5227         }
    5228 
    5229         if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)
    5230             *pGCPtrEff = u64EffAddr;
    5231         else
    5232         {
    5233             Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5234             *pGCPtrEff = u64EffAddr & UINT32_MAX;
    5235         }
    5236     }
    5237 
    5238     Log5(("iemOpHlpCalcRmEffAddr: EffAddr=%#010RGv\n", *pGCPtrEff));
    5239     return VINF_SUCCESS;
    5240 }
    5241 
    5242 
    5243 #ifdef IEM_WITH_SETJMP
    5244 /**
    5245  * Calculates the effective address of a ModR/M memory operand.
    5246  *
    5247  * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR.
    5248  *
    5249  * May longjmp on internal error.
    5250  *
    5251  * @return  The effective address.
    5252  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    5253  * @param   bRm                 The ModRM byte.
    5254  * @param   cbImmAndRspOffset   - First byte: The size of any immediate
    5255  *                                following the effective address opcode bytes
    5256  *                                (only for RIP relative addressing).
    5257  *                              - Second byte: RSP displacement (for POP [ESP]).
    5258  */
    5259 RTGCPTR iemOpHlpCalcRmEffAddrJmp(PVMCPUCC pVCpu, uint8_t bRm, uint32_t cbImmAndRspOffset) IEM_NOEXCEPT_MAY_LONGJMP
    5260 {
    5261     Log5(("iemOpHlpCalcRmEffAddrJmp: bRm=%#x\n", bRm));
    5262 # define SET_SS_DEF() \
    5263     do \
    5264     { \
    5265         if (!(pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SEG_MASK)) \
    5266             pVCpu->iem.s.iEffSeg = X86_SREG_SS; \
    5267     } while (0)
    5268 
    5269     if (!IEM_IS_64BIT_CODE(pVCpu))
    5270     {
    5271 /** @todo Check the effective address size crap! */
    5272         if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_16BIT)
    5273         {
    5274             uint16_t u16EffAddr;
    5275 
    5276             /* Handle the disp16 form with no registers first. */
    5277             if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)
    5278                 IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);
    5279             else
    5280             {
    5281                 /* Get the displacment. */
    5282                 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5283                 {
    5284                     case 0:  u16EffAddr = 0;                             break;
    5285                     case 1:  IEM_OPCODE_GET_NEXT_S8_SX_U16(&u16EffAddr); break;
    5286                     case 2:  IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);       break;
    5287                     default: AssertFailedStmt(IEM_DO_LONGJMP(pVCpu, VERR_IEM_IPE_1)); /* (caller checked for these) */
    5288                 }
    5289 
    5290                 /* Add the base and index registers to the disp. */
    5291                 switch (bRm & X86_MODRM_RM_MASK)
    5292                 {
    5293                     case 0: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.si; break;
    5294                     case 1: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.di; break;
    5295                     case 2: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.si; SET_SS_DEF(); break;
    5296                     case 3: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.di; SET_SS_DEF(); break;
    5297                     case 4: u16EffAddr += pVCpu->cpum.GstCtx.si;            break;
    5298                     case 5: u16EffAddr += pVCpu->cpum.GstCtx.di;            break;
    5299                     case 6: u16EffAddr += pVCpu->cpum.GstCtx.bp;            SET_SS_DEF(); break;
    5300                     case 7: u16EffAddr += pVCpu->cpum.GstCtx.bx;            break;
    5301                 }
    5302             }
    5303 
    5304             Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#06RX16\n", u16EffAddr));
    5305             return u16EffAddr;
    5306         }
    5307 
    5308         Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5309         uint32_t u32EffAddr;
    5310 
    5311         /* Handle the disp32 form with no registers first. */
    5312         if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    5313             IEM_OPCODE_GET_NEXT_U32(&u32EffAddr);
    5314         else
    5315         {
    5316             /* Get the register (or SIB) value. */
    5317             switch ((bRm & X86_MODRM_RM_MASK))
    5318             {
    5319                 case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    5320                 case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    5321                 case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    5322                 case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    5323                 case 4: /* SIB */
    5324                 {
    5325                     uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
    5326 
    5327                     /* Get the index and scale it. */
    5328                     switch ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)
    5329                     {
    5330                         case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    5331                         case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    5332                         case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    5333                         case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    5334                         case 4: u32EffAddr = 0; /*none */ break;
    5335                         case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;
    5336                         case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    5337                         case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    5338                         IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
    5339                     }
    5340                     u32EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    5341 
    5342                     /* add base */
    5343                     switch (bSib & X86_SIB_BASE_MASK)
    5344                     {
    5345                         case 0: u32EffAddr += pVCpu->cpum.GstCtx.eax; break;
    5346                         case 1: u32EffAddr += pVCpu->cpum.GstCtx.ecx; break;
    5347                         case 2: u32EffAddr += pVCpu->cpum.GstCtx.edx; break;
    5348                         case 3: u32EffAddr += pVCpu->cpum.GstCtx.ebx; break;
    5349                         case 4: u32EffAddr += pVCpu->cpum.GstCtx.esp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
    5350                         case 5:
    5351                             if ((bRm & X86_MODRM_MOD_MASK) != 0)
    5352                             {
    5353                                 u32EffAddr += pVCpu->cpum.GstCtx.ebp;
    5354                                 SET_SS_DEF();
    5355                             }
    5356                             else
    5357                             {
    5358                                 uint32_t u32Disp;
    5359                                 IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5360                                 u32EffAddr += u32Disp;
    5361                             }
    5362                             break;
    5363                         case 6: u32EffAddr += pVCpu->cpum.GstCtx.esi; break;
    5364                         case 7: u32EffAddr += pVCpu->cpum.GstCtx.edi; break;
    5365                         IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
    5366                     }
    5367                     break;
    5368                 }
    5369                 case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; SET_SS_DEF(); break;
    5370                 case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    5371                 case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    5372                 IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
    5373             }
    5374 
    5375             /* Get and add the displacement. */
    5376             switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5377             {
    5378                 case 0:
    5379                     break;
    5380                 case 1:
    5381                 {
    5382                     int8_t i8Disp; IEM_OPCODE_GET_NEXT_S8(&i8Disp);
    5383                     u32EffAddr += i8Disp;
    5384                     break;
    5385                 }
    5386                 case 2:
    5387                 {
    5388                     uint32_t u32Disp; IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5389                     u32EffAddr += u32Disp;
    5390                     break;
    5391                 }
    5392                 default:
    5393                     AssertFailedStmt(IEM_DO_LONGJMP(pVCpu, VERR_IEM_IPE_2)); /* (caller checked for these) */
    5394             }
    5395         }
    5396 
    5397         Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5398         Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RX32\n", u32EffAddr));
    5399         return u32EffAddr;
    5400     }
    5401 
    5402     uint64_t u64EffAddr;
    5403 
    5404     /* Handle the rip+disp32 form with no registers first. */
    5405     if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    5406     {
    5407         IEM_OPCODE_GET_NEXT_S32_SX_U64(&u64EffAddr);
    5408         u64EffAddr += pVCpu->cpum.GstCtx.rip + IEM_GET_INSTR_LEN(pVCpu) + (cbImmAndRspOffset & UINT32_C(0xff));
    5409     }
    5410     else
    5411     {
    5412         /* Get the register (or SIB) value. */
    5413         switch ((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB)
    5414         {
    5415             case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    5416             case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    5417             case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    5418             case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    5419             case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; SET_SS_DEF(); break;
    5420             case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    5421             case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    5422             case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    5423             case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    5424             case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    5425             case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    5426             case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    5427             case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    5428             case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    5429             /* SIB */
    5430             case 4:
    5431             case 12:
    5432             {
    5433                 uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
    5434 
    5435                 /* Get the index and scale it. */
    5436                 switch (((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) | pVCpu->iem.s.uRexIndex)
    5437                 {
    5438                     case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    5439                     case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    5440                     case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    5441                     case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    5442                     case  4: u64EffAddr = 0; /*none */ break;
    5443                     case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;
    5444                     case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    5445                     case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    5446                     case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    5447                     case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    5448                     case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    5449                     case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    5450                     case 12: u64EffAddr = pVCpu->cpum.GstCtx.r12; break;
    5451                     case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    5452                     case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    5453                     case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    5454                     IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
    5455                 }
    5456                 u64EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    5457 
    5458                 /* add base */
    5459                 switch ((bSib & X86_SIB_BASE_MASK) | pVCpu->iem.s.uRexB)
    5460                 {
    5461                     case  0: u64EffAddr += pVCpu->cpum.GstCtx.rax; break;
    5462                     case  1: u64EffAddr += pVCpu->cpum.GstCtx.rcx; break;
    5463                     case  2: u64EffAddr += pVCpu->cpum.GstCtx.rdx; break;
    5464                     case  3: u64EffAddr += pVCpu->cpum.GstCtx.rbx; break;
    5465                     case  4: u64EffAddr += pVCpu->cpum.GstCtx.rsp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
    5466                     case  6: u64EffAddr += pVCpu->cpum.GstCtx.rsi; break;
    5467                     case  7: u64EffAddr += pVCpu->cpum.GstCtx.rdi; break;
    5468                     case  8: u64EffAddr += pVCpu->cpum.GstCtx.r8;  break;
    5469                     case  9: u64EffAddr += pVCpu->cpum.GstCtx.r9;  break;
    5470                     case 10: u64EffAddr += pVCpu->cpum.GstCtx.r10; break;
    5471                     case 11: u64EffAddr += pVCpu->cpum.GstCtx.r11; break;
    5472                     case 12: u64EffAddr += pVCpu->cpum.GstCtx.r12; break;
    5473                     case 14: u64EffAddr += pVCpu->cpum.GstCtx.r14; break;
    5474                     case 15: u64EffAddr += pVCpu->cpum.GstCtx.r15; break;
    5475                     /* complicated encodings */
    5476                     case 5:
    5477                     case 13:
    5478                         if ((bRm & X86_MODRM_MOD_MASK) != 0)
    5479                         {
    5480                             if (!pVCpu->iem.s.uRexB)
    5481                             {
    5482                                 u64EffAddr += pVCpu->cpum.GstCtx.rbp;
    5483                                 SET_SS_DEF();
    5484                             }
    5485                             else
    5486                                 u64EffAddr += pVCpu->cpum.GstCtx.r13;
    5487                         }
    5488                         else
    5489                         {
    5490                             uint32_t u32Disp;
    5491                             IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5492                             u64EffAddr += (int32_t)u32Disp;
    5493                         }
    5494                         break;
    5495                     IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
    5496                 }
    5497                 break;
    5498             }
    5499             IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
    5500         }
    5501 
    5502         /* Get and add the displacement. */
    5503         switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5504         {
    5505             case 0:
    5506                 break;
    5507             case 1:
    5508             {
    5509                 int8_t i8Disp;
    5510                 IEM_OPCODE_GET_NEXT_S8(&i8Disp);
    5511                 u64EffAddr += i8Disp;
    5512                 break;
    5513             }
    5514             case 2:
    5515             {
    5516                 uint32_t u32Disp;
    5517                 IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5518                 u64EffAddr += (int32_t)u32Disp;
    5519                 break;
    5520             }
    5521             IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX); /* (caller checked for these) */
    5522         }
    5523 
    5524     }
    5525 
    5526     if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)
    5527     {
    5528         Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RGv\n", u64EffAddr));
    5529         return u64EffAddr;
    5530     }
    5531     Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5532     Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RGv\n", u64EffAddr & UINT32_MAX));
    5533     return u64EffAddr & UINT32_MAX;
    5534 }
    5535 #endif /* IEM_WITH_SETJMP */
    5536 
    5537 
    5538 /**
    5539  * Calculates the effective address of a ModR/M memory operand, extended version
    5540  * for use in the recompilers.
    5541  *
    5542  * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR.
    5543  *
    5544  * @return  Strict VBox status code.
    5545  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    5546  * @param   bRm                 The ModRM byte.
    5547  * @param   cbImmAndRspOffset   - First byte: The size of any immediate
    5548  *                                following the effective address opcode bytes
    5549  *                                (only for RIP relative addressing).
    5550  *                              - Second byte: RSP displacement (for POP [ESP]).
    5551  * @param   pGCPtrEff           Where to return the effective address.
    5552  * @param   puInfo              Extra info: 32-bit displacement (bits 31:0) and
    5553  *                              SIB byte (bits 39:32).
    5554  */
    5555 VBOXSTRICTRC iemOpHlpCalcRmEffAddrEx(PVMCPUCC pVCpu, uint8_t bRm, uint32_t cbImmAndRspOffset, PRTGCPTR pGCPtrEff, uint64_t *puInfo) RT_NOEXCEPT
    5556 {
    5557     Log5(("iemOpHlpCalcRmEffAddr: bRm=%#x\n", bRm));
    5558 # define SET_SS_DEF() \
    5559     do \
    5560     { \
    5561         if (!(pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SEG_MASK)) \
    5562             pVCpu->iem.s.iEffSeg = X86_SREG_SS; \
    5563     } while (0)
    5564 
    5565     uint64_t uInfo;
    5566     if (!IEM_IS_64BIT_CODE(pVCpu))
    5567     {
    5568 /** @todo Check the effective address size crap! */
    5569         if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_16BIT)
    5570         {
    5571             uint16_t u16EffAddr;
    5572 
    5573             /* Handle the disp16 form with no registers first. */
    5574             if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)
    5575             {
    5576                 IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);
    5577                 uInfo = u16EffAddr;
    5578             }
    5579             else
    5580             {
    5581                 /* Get the displacment. */
    5582                 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5583                 {
    5584                     case 0:  u16EffAddr = 0;                             break;
    5585                     case 1:  IEM_OPCODE_GET_NEXT_S8_SX_U16(&u16EffAddr); break;
    5586                     case 2:  IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);       break;
    5587                     default: AssertFailedReturn(VERR_IEM_IPE_1); /* (caller checked for these) */
    5588                 }
    5589                 uInfo = u16EffAddr;
    5590 
    5591                 /* Add the base and index registers to the disp. */
    5592                 switch (bRm & X86_MODRM_RM_MASK)
    5593                 {
    5594                     case 0: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.si; break;
    5595                     case 1: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.di; break;
    5596                     case 2: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.si; SET_SS_DEF(); break;
    5597                     case 3: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.di; SET_SS_DEF(); break;
    5598                     case 4: u16EffAddr += pVCpu->cpum.GstCtx.si;            break;
    5599                     case 5: u16EffAddr += pVCpu->cpum.GstCtx.di;            break;
    5600                     case 6: u16EffAddr += pVCpu->cpum.GstCtx.bp;            SET_SS_DEF(); break;
    5601                     case 7: u16EffAddr += pVCpu->cpum.GstCtx.bx;            break;
    5602                 }
    5603             }
    5604 
    5605             *pGCPtrEff = u16EffAddr;
    5606         }
    5607         else
    5608         {
    5609             Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5610             uint32_t u32EffAddr;
    5611 
    5612             /* Handle the disp32 form with no registers first. */
    5613             if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    5614             {
    5615                 IEM_OPCODE_GET_NEXT_U32(&u32EffAddr);
    5616                 uInfo = u32EffAddr;
    5617             }
    5618             else
    5619             {
    5620                 /* Get the register (or SIB) value. */
    5621                 uInfo = 0;
    5622                 switch ((bRm & X86_MODRM_RM_MASK))
    5623                 {
    5624                     case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    5625                     case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    5626                     case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    5627                     case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    5628                     case 4: /* SIB */
    5629                     {
    5630                         uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
    5631                         uInfo = (uint64_t)bSib << 32;
    5632 
    5633                         /* Get the index and scale it. */
    5634                         switch ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)
    5635                         {
    5636                             case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    5637                             case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    5638                             case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    5639                             case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    5640                             case 4: u32EffAddr = 0; /*none */ break;
    5641                             case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;
    5642                             case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    5643                             case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    5644                             IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5645                         }
    5646                         u32EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    5647 
    5648                         /* add base */
    5649                         switch (bSib & X86_SIB_BASE_MASK)
    5650                         {
    5651                             case 0: u32EffAddr += pVCpu->cpum.GstCtx.eax; break;
    5652                             case 1: u32EffAddr += pVCpu->cpum.GstCtx.ecx; break;
    5653                             case 2: u32EffAddr += pVCpu->cpum.GstCtx.edx; break;
    5654                             case 3: u32EffAddr += pVCpu->cpum.GstCtx.ebx; break;
    5655                             case 4: u32EffAddr += pVCpu->cpum.GstCtx.esp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
    5656                             case 5:
    5657                                 if ((bRm & X86_MODRM_MOD_MASK) != 0)
    5658                                 {
    5659                                     u32EffAddr += pVCpu->cpum.GstCtx.ebp;
    5660                                     SET_SS_DEF();
    5661                                 }
    5662                                 else
    5663                                 {
    5664                                     uint32_t u32Disp;
    5665                                     IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5666                                     u32EffAddr += u32Disp;
    5667                                     uInfo      |= u32Disp;
    5668                                 }
    5669                                 break;
    5670                             case 6: u32EffAddr += pVCpu->cpum.GstCtx.esi; break;
    5671                             case 7: u32EffAddr += pVCpu->cpum.GstCtx.edi; break;
    5672                             IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5673                         }
    5674                         break;
    5675                     }
    5676                     case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; SET_SS_DEF(); break;
    5677                     case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    5678                     case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    5679                     IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5680                 }
    5681 
    5682                 /* Get and add the displacement. */
    5683                 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5684                 {
    5685                     case 0:
    5686                         break;
    5687                     case 1:
    5688                     {
    5689                         int8_t i8Disp; IEM_OPCODE_GET_NEXT_S8(&i8Disp);
    5690                         u32EffAddr += i8Disp;
    5691                         uInfo |= (uint32_t)(int32_t)i8Disp;
    5692                         break;
    5693                     }
    5694                     case 2:
    5695                     {
    5696                         uint32_t u32Disp; IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5697                         u32EffAddr += u32Disp;
    5698                         uInfo      |= (uint32_t)u32Disp;
    5699                         break;
    5700                     }
    5701                     default:
    5702                         AssertFailedReturn(VERR_IEM_IPE_2); /* (caller checked for these) */
    5703                 }
    5704 
    5705             }
    5706             Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5707             *pGCPtrEff = u32EffAddr;
    5708         }
    5709     }
    5710     else
    5711     {
    5712         uint64_t u64EffAddr;
    5713 
    5714         /* Handle the rip+disp32 form with no registers first. */
    5715         if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    5716         {
    5717             IEM_OPCODE_GET_NEXT_S32_SX_U64(&u64EffAddr);
    5718             uInfo = (uint32_t)u64EffAddr;
    5719             u64EffAddr += pVCpu->cpum.GstCtx.rip + IEM_GET_INSTR_LEN(pVCpu) + (cbImmAndRspOffset & UINT32_C(0xff));
    5720         }
    5721         else
    5722         {
    5723             /* Get the register (or SIB) value. */
    5724             uInfo = 0;
    5725             switch ((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB)
    5726             {
    5727                 case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    5728                 case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    5729                 case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    5730                 case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    5731                 case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; SET_SS_DEF(); break;
    5732                 case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    5733                 case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    5734                 case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    5735                 case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    5736                 case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    5737                 case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    5738                 case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    5739                 case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    5740                 case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    5741                 /* SIB */
    5742                 case 4:
    5743                 case 12:
    5744                 {
    5745                     uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
    5746                     uInfo = (uint64_t)bSib << 32;
    5747 
    5748                     /* Get the index and scale it. */
    5749                     switch (((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) | pVCpu->iem.s.uRexIndex)
    5750                     {
    5751                         case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    5752                         case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    5753                         case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    5754                         case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    5755                         case  4: u64EffAddr = 0; /*none */ break;
    5756                         case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;
    5757                         case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    5758                         case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    5759                         case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    5760                         case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    5761                         case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    5762                         case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    5763                         case 12: u64EffAddr = pVCpu->cpum.GstCtx.r12; break;
    5764                         case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    5765                         case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    5766                         case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    5767                         IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5768                     }
    5769                     u64EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    5770 
    5771                     /* add base */
    5772                     switch ((bSib & X86_SIB_BASE_MASK) | pVCpu->iem.s.uRexB)
    5773                     {
    5774                         case  0: u64EffAddr += pVCpu->cpum.GstCtx.rax; break;
    5775                         case  1: u64EffAddr += pVCpu->cpum.GstCtx.rcx; break;
    5776                         case  2: u64EffAddr += pVCpu->cpum.GstCtx.rdx; break;
    5777                         case  3: u64EffAddr += pVCpu->cpum.GstCtx.rbx; break;
    5778                         case  4: u64EffAddr += pVCpu->cpum.GstCtx.rsp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
    5779                         case  6: u64EffAddr += pVCpu->cpum.GstCtx.rsi; break;
    5780                         case  7: u64EffAddr += pVCpu->cpum.GstCtx.rdi; break;
    5781                         case  8: u64EffAddr += pVCpu->cpum.GstCtx.r8;  break;
    5782                         case  9: u64EffAddr += pVCpu->cpum.GstCtx.r9;  break;
    5783                         case 10: u64EffAddr += pVCpu->cpum.GstCtx.r10; break;
    5784                         case 11: u64EffAddr += pVCpu->cpum.GstCtx.r11; break;
    5785                         case 12: u64EffAddr += pVCpu->cpum.GstCtx.r12; break;
    5786                         case 14: u64EffAddr += pVCpu->cpum.GstCtx.r14; break;
    5787                         case 15: u64EffAddr += pVCpu->cpum.GstCtx.r15; break;
    5788                         /* complicated encodings */
    5789                         case 5:
    5790                         case 13:
    5791                             if ((bRm & X86_MODRM_MOD_MASK) != 0)
    5792                             {
    5793                                 if (!pVCpu->iem.s.uRexB)
    5794                                 {
    5795                                     u64EffAddr += pVCpu->cpum.GstCtx.rbp;
    5796                                     SET_SS_DEF();
    5797                                 }
    5798                                 else
    5799                                     u64EffAddr += pVCpu->cpum.GstCtx.r13;
    5800                             }
    5801                             else
    5802                             {
    5803                                 uint32_t u32Disp;
    5804                                 IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5805                                 u64EffAddr += (int32_t)u32Disp;
    5806                                 uInfo      |= u32Disp;
    5807                             }
    5808                             break;
    5809                         IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5810                     }
    5811                     break;
    5812                 }
    5813                 IEM_NOT_REACHED_DEFAULT_CASE_RET();
    5814             }
    5815 
    5816             /* Get and add the displacement. */
    5817             switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    5818             {
    5819                 case 0:
    5820                     break;
    5821                 case 1:
    5822                 {
    5823                     int8_t i8Disp;
    5824                     IEM_OPCODE_GET_NEXT_S8(&i8Disp);
    5825                     u64EffAddr += i8Disp;
    5826                     uInfo      |= (uint32_t)(int32_t)i8Disp;
    5827                     break;
    5828                 }
    5829                 case 2:
    5830                 {
    5831                     uint32_t u32Disp;
    5832                     IEM_OPCODE_GET_NEXT_U32(&u32Disp);
    5833                     u64EffAddr += (int32_t)u32Disp;
    5834                     uInfo      |= u32Disp;
    5835                     break;
    5836                 }
    5837                 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* (caller checked for these) */
    5838             }
    5839 
    5840         }
    5841 
    5842         if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)
    5843             *pGCPtrEff = u64EffAddr;
    5844         else
    5845         {
    5846             Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
    5847             *pGCPtrEff = u64EffAddr & UINT32_MAX;
    5848         }
    5849     }
    5850     *puInfo = uInfo;
    5851 
    5852     Log5(("iemOpHlpCalcRmEffAddrEx: EffAddr=%#010RGv uInfo=%RX64\n", *pGCPtrEff, uInfo));
    5853     return VINF_SUCCESS;
    5854 }
    5855 
    5856 /** @}  */
    5857 
    5858 
    5859 #ifdef LOG_ENABLED
    5860 /**
    5861  * Logs the current instruction.
    5862  * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
    5863  * @param   fSameCtx    Set if we have the same context information as the VMM,
    5864  *                      clear if we may have already executed an instruction in
    5865  *                      our debug context. When clear, we assume IEMCPU holds
    5866  *                      valid CPU mode info.
    5867  *
    5868  *                      The @a fSameCtx parameter is now misleading and obsolete.
    5869  * @param   pszFunction The IEM function doing the execution.
    5870  */
    5871 static void iemLogCurInstr(PVMCPUCC pVCpu, bool fSameCtx, const char *pszFunction) RT_NOEXCEPT
    5872 {
    5873 # ifdef IN_RING3
    5874     if (LogIs2Enabled())
    5875     {
    5876         char     szInstr[256];
    5877         uint32_t cbInstr = 0;
    5878         if (fSameCtx)
    5879             DBGFR3DisasInstrEx(pVCpu->pVMR3->pUVM, pVCpu->idCpu, 0, 0,
    5880                                DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_DEFAULT_MODE,
    5881                                szInstr, sizeof(szInstr), &cbInstr);
    5882         else
    5883         {
    5884             uint32_t fFlags = 0;
    5885             switch (IEM_GET_CPU_MODE(pVCpu))
    5886             {
    5887                 case IEMMODE_64BIT: fFlags |= DBGF_DISAS_FLAGS_64BIT_MODE; break;
    5888                 case IEMMODE_32BIT: fFlags |= DBGF_DISAS_FLAGS_32BIT_MODE; break;
    5889                 case IEMMODE_16BIT:
    5890                     if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE) || pVCpu->cpum.GstCtx.eflags.Bits.u1VM)
    5891                         fFlags |= DBGF_DISAS_FLAGS_16BIT_REAL_MODE;
    5892                     else
    5893                         fFlags |= DBGF_DISAS_FLAGS_16BIT_MODE;
    5894                     break;
    5895             }
    5896             DBGFR3DisasInstrEx(pVCpu->pVMR3->pUVM, pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, fFlags,
    5897                                szInstr, sizeof(szInstr), &cbInstr);
    5898         }
    5899 
    5900         PCX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
    5901         Log2(("**** %s fExec=%x\n"
    5902               " eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n"
    5903               " eip=%08x esp=%08x ebp=%08x iopl=%d tr=%04x\n"
    5904               " cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x efl=%08x\n"
    5905               " fsw=%04x fcw=%04x ftw=%02x mxcsr=%04x/%04x\n"
    5906               " %s\n"
    5907               , pszFunction, pVCpu->iem.s.fExec,
    5908               pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ebx, pVCpu->cpum.GstCtx.ecx, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.esi, pVCpu->cpum.GstCtx.edi,
    5909               pVCpu->cpum.GstCtx.eip, pVCpu->cpum.GstCtx.esp, pVCpu->cpum.GstCtx.ebp, pVCpu->cpum.GstCtx.eflags.Bits.u2IOPL, pVCpu->cpum.GstCtx.tr.Sel,
    5910               pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.ds.Sel, pVCpu->cpum.GstCtx.es.Sel,
    5911               pVCpu->cpum.GstCtx.fs.Sel, pVCpu->cpum.GstCtx.gs.Sel, pVCpu->cpum.GstCtx.eflags.u,
    5912               pFpuCtx->FSW, pFpuCtx->FCW, pFpuCtx->FTW, pFpuCtx->MXCSR, pFpuCtx->MXCSR_MASK,
    5913               szInstr));
    5914 
    5915         /* This stuff sucks atm. as it fills the log with MSRs. */
    5916         //if (LogIs3Enabled())
    5917         //    DBGFR3InfoEx(pVCpu->pVMR3->pUVM, pVCpu->idCpu, "cpumguest", "verbose", NULL);
    5918     }
    5919     else
    5920 # endif
    5921         LogFlow(("%s: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x\n", pszFunction, pVCpu->cpum.GstCtx.cs.Sel,
    5922                  pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u));
    5923     RT_NOREF_PV(pVCpu); RT_NOREF_PV(fSameCtx);
    5924 }
    5925 #endif /* LOG_ENABLED */
    5926 
    5927 
    5928 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    5929 /**
    5930  * Deals with VMCPU_FF_VMX_APIC_WRITE, VMCPU_FF_VMX_MTF, VMCPU_FF_VMX_NMI_WINDOW,
    5931  * VMCPU_FF_VMX_PREEMPT_TIMER and VMCPU_FF_VMX_INT_WINDOW.
    5932  *
    5933  * @returns Modified rcStrict.
    5934  * @param   pVCpu       The cross context virtual CPU structure of the calling thread.
    5935  * @param   rcStrict    The instruction execution status.
    5936  */
    5937 static VBOXSTRICTRC iemHandleNestedInstructionBoundaryFFs(PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict) RT_NOEXCEPT
    5938 {
    5939     Assert(CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu)));
    5940     if (!VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF))
    5941     {
    5942         /* VMX preemption timer takes priority over NMI-window exits. */
    5943         if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER))
    5944         {
    5945             rcStrict = iemVmxVmexitPreemptTimer(pVCpu);
    5946             Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER));
    5947         }
    5948         /*
    5949          * Check remaining intercepts.
    5950          *
    5951          * NMI-window and Interrupt-window VM-exits.
    5952          * Interrupt shadow (block-by-STI and Mov SS) inhibits interrupts and may also block NMIs.
    5953          * Event injection during VM-entry takes priority over NMI-window and interrupt-window VM-exits.
    5954          *
    5955          * See Intel spec. 26.7.6 "NMI-Window Exiting".
    5956          * See Intel spec. 26.7.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
    5957          */
    5958         else if (   VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW | VMCPU_FF_VMX_INT_WINDOW)
    5959                  && !CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)
    5960                  && !TRPMHasTrap(pVCpu))
    5961         {
    5962             Assert(CPUMIsGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx));
    5963             if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW)
    5964                 && CPUMIsGuestVmxVirtNmiBlocking(&pVCpu->cpum.GstCtx))
    5965             {
    5966                 rcStrict = iemVmxVmexit(pVCpu, VMX_EXIT_NMI_WINDOW, 0 /* u64ExitQual */);
    5967                 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW));
    5968             }
    5969             else if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW)
    5970                      && CPUMIsGuestVmxVirtIntrEnabled(&pVCpu->cpum.GstCtx))
    5971             {
    5972                 rcStrict = iemVmxVmexit(pVCpu, VMX_EXIT_INT_WINDOW, 0 /* u64ExitQual */);
    5973                 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW));
    5974             }
    5975         }
    5976     }
    5977     /* TPR-below threshold/APIC write has the highest priority. */
    5978     else  if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
    5979     {
    5980         rcStrict = iemVmxApicWriteEmulation(pVCpu);
    5981         Assert(!CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx));
    5982         Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE));
    5983     }
    5984     /* MTF takes priority over VMX-preemption timer. */
    5985     else
    5986     {
    5987         rcStrict = iemVmxVmexit(pVCpu, VMX_EXIT_MTF, 0 /* u64ExitQual */);
    5988         Assert(!CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx));
    5989         Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF));
    5990     }
    5991     return rcStrict;
    5992 }
    5993 #endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
    5994 
    5995 
    5996 /**
    5997  * The actual code execution bits of IEMExecOne, IEMExecOneWithPrefetchedByPC,
    5998  * IEMExecOneBypass and friends.
    5999  *
    6000  * Similar code is found in IEMExecLots.
    6001  *
    6002  * @return  Strict VBox status code.
    6003  * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
    6004  * @param   fExecuteInhibit     If set, execute the instruction following CLI,
    6005  *                      POP SS and MOV SS,GR.
    6006  * @param   pszFunction The calling function name.
    6007  */
    6008 DECLINLINE(VBOXSTRICTRC) iemExecOneInner(PVMCPUCC pVCpu, bool fExecuteInhibit, const char *pszFunction)
    6009 {
    6010     AssertMsg(pVCpu->iem.s.aMemMappings[0].fAccess == IEM_ACCESS_INVALID, ("0: %#x %RGp\n", pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemBbMappings[0].GCPhysFirst));
    6011     AssertMsg(pVCpu->iem.s.aMemMappings[1].fAccess == IEM_ACCESS_INVALID, ("1: %#x %RGp\n", pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemBbMappings[1].GCPhysFirst));
    6012     AssertMsg(pVCpu->iem.s.aMemMappings[2].fAccess == IEM_ACCESS_INVALID, ("2: %#x %RGp\n", pVCpu->iem.s.aMemMappings[2].fAccess, pVCpu->iem.s.aMemBbMappings[2].GCPhysFirst));
    6013     RT_NOREF_PV(pszFunction);
    6014 
    6015 #ifdef IEM_WITH_SETJMP
    6016     VBOXSTRICTRC rcStrict;
    6017     IEM_TRY_SETJMP(pVCpu, rcStrict)
    6018     {
    6019         uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);
    6020         rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);
    6021     }
    6022     IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);
    6023     {
    6024         pVCpu->iem.s.cLongJumps++;
    6025     }
    6026     IEM_CATCH_LONGJMP_END(pVCpu);
    6027 #else
    6028     uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);
    6029     VBOXSTRICTRC rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);
    6030 #endif
    6031     if (rcStrict == VINF_SUCCESS)
    6032         pVCpu->iem.s.cInstructions++;
    6033     if (pVCpu->iem.s.cActiveMappings > 0)
    6034     {
    6035         Assert(rcStrict != VINF_SUCCESS);
    6036         iemMemRollback(pVCpu);
    6037     }
    6038     AssertMsg(pVCpu->iem.s.aMemMappings[0].fAccess == IEM_ACCESS_INVALID, ("0: %#x %RGp\n", pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemBbMappings[0].GCPhysFirst));
    6039     AssertMsg(pVCpu->iem.s.aMemMappings[1].fAccess == IEM_ACCESS_INVALID, ("1: %#x %RGp\n", pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemBbMappings[1].GCPhysFirst));
    6040     AssertMsg(pVCpu->iem.s.aMemMappings[2].fAccess == IEM_ACCESS_INVALID, ("2: %#x %RGp\n", pVCpu->iem.s.aMemMappings[2].fAccess, pVCpu->iem.s.aMemBbMappings[2].GCPhysFirst));
    6041 
    6042 //#ifdef DEBUG
    6043 //    AssertMsg(IEM_GET_INSTR_LEN(pVCpu) == cbInstr || rcStrict != VINF_SUCCESS, ("%u %u\n", IEM_GET_INSTR_LEN(pVCpu), cbInstr));
    6044 //#endif
    6045 
    6046 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    6047     /*
    6048      * Perform any VMX nested-guest instruction boundary actions.
    6049      *
    6050      * If any of these causes a VM-exit, we must skip executing the next
    6051      * instruction (would run into stale page tables). A VM-exit makes sure
    6052      * there is no interrupt-inhibition, so that should ensure we don't go
    6053      * to try execute the next instruction. Clearing fExecuteInhibit is
    6054      * problematic because of the setjmp/longjmp clobbering above.
    6055      */
    6056     if (   !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER
    6057                                      | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW)
    6058         || rcStrict != VINF_SUCCESS)
    6059     { /* likely */ }
    6060     else
    6061         rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);
    6062 #endif
    6063 
    6064     /* Execute the next instruction as well if a cli, pop ss or
    6065        mov ss, Gr has just completed successfully. */
    6066     if (   fExecuteInhibit
    6067         && rcStrict == VINF_SUCCESS
    6068         && CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx))
    6069     {
    6070         rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, pVCpu->iem.s.fExec & (IEM_F_BYPASS_HANDLERS | IEM_F_X86_DISREGARD_LOCK));
    6071         if (rcStrict == VINF_SUCCESS)
    6072         {
    6073 #ifdef LOG_ENABLED
    6074             iemLogCurInstr(pVCpu, false, pszFunction);
    6075 #endif
    6076 #ifdef IEM_WITH_SETJMP
    6077             IEM_TRY_SETJMP_AGAIN(pVCpu, rcStrict)
    6078             {
    6079                 uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);
    6080                 rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);
    6081             }
    6082             IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);
    6083             {
    6084                 pVCpu->iem.s.cLongJumps++;
    6085             }
    6086             IEM_CATCH_LONGJMP_END(pVCpu);
    6087 #else
    6088             IEM_OPCODE_GET_FIRST_U8(&b);
    6089             rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);
    6090 #endif
    6091             if (rcStrict == VINF_SUCCESS)
    6092             {
    6093                 pVCpu->iem.s.cInstructions++;
    6094 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    6095                 if (!VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER
    6096                                               | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW))
    6097                 { /* likely */ }
    6098                 else
    6099                     rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);
    6100 #endif
    6101             }
    6102             if (pVCpu->iem.s.cActiveMappings > 0)
    6103             {
    6104                 Assert(rcStrict != VINF_SUCCESS);
    6105                 iemMemRollback(pVCpu);
    6106             }
    6107             AssertMsg(pVCpu->iem.s.aMemMappings[0].fAccess == IEM_ACCESS_INVALID, ("0: %#x %RGp\n", pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemBbMappings[0].GCPhysFirst));
    6108             AssertMsg(pVCpu->iem.s.aMemMappings[1].fAccess == IEM_ACCESS_INVALID, ("1: %#x %RGp\n", pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemBbMappings[1].GCPhysFirst));
    6109             AssertMsg(pVCpu->iem.s.aMemMappings[2].fAccess == IEM_ACCESS_INVALID, ("2: %#x %RGp\n", pVCpu->iem.s.aMemMappings[2].fAccess, pVCpu->iem.s.aMemBbMappings[2].GCPhysFirst));
    6110         }
    6111         else if (pVCpu->iem.s.cActiveMappings > 0)
    6112             iemMemRollback(pVCpu);
    6113         /** @todo drop this after we bake this change into RIP advancing. */
    6114         CPUMClearInterruptShadow(&pVCpu->cpum.GstCtx); /* hope this is correct for all exceptional cases... */
    6115     }
    6116 
    6117     /*
    6118      * Return value fiddling, statistics and sanity assertions.
    6119      */
    6120     rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6121 
    6122     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));
    6123     Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
    6124     return rcStrict;
    6125 }
    6126 
    6127 
    6128 /**
    6129  * Execute one instruction.
    6130  *
    6131  * @return  Strict VBox status code.
    6132  * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
    6133  */
    6134 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOne(PVMCPUCC pVCpu)
    6135 {
    6136     AssertCompile(sizeof(pVCpu->iem.s) <= sizeof(pVCpu->iem.padding)); /* (tstVMStruct can't do it's job w/o instruction stats) */
    6137 #ifdef LOG_ENABLED
    6138     iemLogCurInstr(pVCpu, true, "IEMExecOne");
    6139 #endif
    6140 
    6141     /*
    6142      * Do the decoding and emulation.
    6143      */
    6144     VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, 0 /*fExecOpts*/);
    6145     if (rcStrict == VINF_SUCCESS)
    6146         rcStrict = iemExecOneInner(pVCpu, true, "IEMExecOne");
    6147     else if (pVCpu->iem.s.cActiveMappings > 0)
    6148         iemMemRollback(pVCpu);
    6149 
    6150     if (rcStrict != VINF_SUCCESS)
    6151         LogFlow(("IEMExecOne: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc\n",
    6152                  pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict)));
    6153     return rcStrict;
    6154 }
    6155 
    6156 
    6157 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOneWithPrefetchedByPC(PVMCPUCC pVCpu, uint64_t OpcodeBytesPC,
    6158                                                         const void *pvOpcodeBytes, size_t cbOpcodeBytes)
    6159 {
    6160     VBOXSTRICTRC rcStrict;
    6161     if (   cbOpcodeBytes
    6162         && pVCpu->cpum.GstCtx.rip == OpcodeBytesPC)
    6163     {
    6164         iemInitDecoder(pVCpu, 0 /*fExecOpts*/);
    6165 #ifdef IEM_WITH_CODE_TLB
    6166         pVCpu->iem.s.uInstrBufPc      = OpcodeBytesPC;
    6167         pVCpu->iem.s.pbInstrBuf       = (uint8_t const *)pvOpcodeBytes;
    6168         pVCpu->iem.s.cbInstrBufTotal  = (uint16_t)RT_MIN(X86_PAGE_SIZE, cbOpcodeBytes);
    6169         pVCpu->iem.s.offCurInstrStart = 0;
    6170         pVCpu->iem.s.offInstrNextByte = 0;
    6171         pVCpu->iem.s.GCPhysInstrBuf   = NIL_RTGCPHYS;
    6172 #else
    6173         pVCpu->iem.s.cbOpcode = (uint8_t)RT_MIN(cbOpcodeBytes, sizeof(pVCpu->iem.s.abOpcode));
    6174         memcpy(pVCpu->iem.s.abOpcode, pvOpcodeBytes, pVCpu->iem.s.cbOpcode);
    6175 #endif
    6176         rcStrict = VINF_SUCCESS;
    6177     }
    6178     else
    6179         rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, 0 /*fExecOpts*/);
    6180     if (rcStrict == VINF_SUCCESS)
    6181         rcStrict = iemExecOneInner(pVCpu, true, "IEMExecOneWithPrefetchedByPC");
    6182     else if (pVCpu->iem.s.cActiveMappings > 0)
    6183         iemMemRollback(pVCpu);
    6184 
    6185     return rcStrict;
    6186 }
    6187 
    6188 
    6189 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOneBypass(PVMCPUCC pVCpu)
    6190 {
    6191     VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, IEM_F_BYPASS_HANDLERS);
    6192     if (rcStrict == VINF_SUCCESS)
    6193         rcStrict = iemExecOneInner(pVCpu, false, "IEMExecOneBypass");
    6194     else if (pVCpu->iem.s.cActiveMappings > 0)
    6195         iemMemRollback(pVCpu);
    6196 
    6197     return rcStrict;
    6198 }
    6199 
    6200 
    6201 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOneBypassWithPrefetchedByPC(PVMCPUCC pVCpu, uint64_t OpcodeBytesPC,
    6202                                                               const void *pvOpcodeBytes, size_t cbOpcodeBytes)
    6203 {
    6204     VBOXSTRICTRC rcStrict;
    6205     if (   cbOpcodeBytes
    6206         && pVCpu->cpum.GstCtx.rip == OpcodeBytesPC)
    6207     {
    6208         iemInitDecoder(pVCpu, IEM_F_BYPASS_HANDLERS);
    6209 #ifdef IEM_WITH_CODE_TLB
    6210         pVCpu->iem.s.uInstrBufPc      = OpcodeBytesPC;
    6211         pVCpu->iem.s.pbInstrBuf       = (uint8_t const *)pvOpcodeBytes;
    6212         pVCpu->iem.s.cbInstrBufTotal  = (uint16_t)RT_MIN(X86_PAGE_SIZE, cbOpcodeBytes);
    6213         pVCpu->iem.s.offCurInstrStart = 0;
    6214         pVCpu->iem.s.offInstrNextByte = 0;
    6215         pVCpu->iem.s.GCPhysInstrBuf   = NIL_RTGCPHYS;
    6216 #else
    6217         pVCpu->iem.s.cbOpcode = (uint8_t)RT_MIN(cbOpcodeBytes, sizeof(pVCpu->iem.s.abOpcode));
    6218         memcpy(pVCpu->iem.s.abOpcode, pvOpcodeBytes, pVCpu->iem.s.cbOpcode);
    6219 #endif
    6220         rcStrict = VINF_SUCCESS;
    6221     }
    6222     else
    6223         rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, IEM_F_BYPASS_HANDLERS);
    6224     if (rcStrict == VINF_SUCCESS)
    6225         rcStrict = iemExecOneInner(pVCpu, false, "IEMExecOneBypassWithPrefetchedByPC");
    6226     else if (pVCpu->iem.s.cActiveMappings > 0)
    6227         iemMemRollback(pVCpu);
    6228 
    6229     return rcStrict;
    6230 }
    6231 
    6232 
    6233 /**
    6234  * For handling split cacheline lock operations when the host has split-lock
    6235  * detection enabled.
    6236  *
    6237  * This will cause the interpreter to disregard the lock prefix and implicit
    6238  * locking (xchg).
    6239  *
    6240  * @returns Strict VBox status code.
    6241  * @param   pVCpu   The cross context virtual CPU structure of the calling EMT.
    6242  */
    6243 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOneIgnoreLock(PVMCPUCC pVCpu)
    6244 {
    6245     /*
    6246      * Do the decoding and emulation.
    6247      */
    6248     VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, IEM_F_X86_DISREGARD_LOCK);
    6249     if (rcStrict == VINF_SUCCESS)
    6250         rcStrict = iemExecOneInner(pVCpu, true, "IEMExecOneIgnoreLock");
    6251     else if (pVCpu->iem.s.cActiveMappings > 0)
    6252         iemMemRollback(pVCpu);
    6253 
    6254     if (rcStrict != VINF_SUCCESS)
    6255         LogFlow(("IEMExecOneIgnoreLock: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc\n",
    6256                  pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict)));
    6257     return rcStrict;
    6258 }
    6259 
    6260 
    6261 /**
    6262  * Code common to IEMExecLots and IEMExecRecompilerThreaded that attempts to
    6263  * inject a pending TRPM trap.
    6264  */
    6265 VBOXSTRICTRC iemExecInjectPendingTrap(PVMCPUCC pVCpu)
    6266 {
    6267     Assert(TRPMHasTrap(pVCpu));
    6268 
    6269     if (   !CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)
    6270         && !CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx))
    6271     {
    6272         /** @todo Can we centralize this under CPUMCanInjectInterrupt()? */
    6273 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
    6274         bool fIntrEnabled = CPUMGetGuestGif(&pVCpu->cpum.GstCtx);
    6275         if (fIntrEnabled)
    6276         {
    6277             if (!CPUMIsGuestInNestedHwvirtMode(IEM_GET_CTX(pVCpu)))
    6278                 fIntrEnabled = pVCpu->cpum.GstCtx.eflags.Bits.u1IF;
    6279             else if (CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu)))
    6280                 fIntrEnabled = CPUMIsGuestVmxPhysIntrEnabled(IEM_GET_CTX(pVCpu));
    6281             else
    6282             {
    6283                 Assert(CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)));
    6284                 fIntrEnabled = CPUMIsGuestSvmPhysIntrEnabled(pVCpu, IEM_GET_CTX(pVCpu));
    6285             }
    6286         }
    6287 #else
    6288         bool fIntrEnabled = pVCpu->cpum.GstCtx.eflags.Bits.u1IF;
    6289 #endif
    6290         if (fIntrEnabled)
    6291         {
    6292             uint8_t     u8TrapNo;
    6293             TRPMEVENT   enmType;
    6294             uint32_t    uErrCode;
    6295             RTGCPTR     uCr2;
    6296             int rc2 = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrCode, &uCr2, NULL /*pu8InstLen*/, NULL /*fIcebp*/);
    6297             AssertRC(rc2);
    6298             Assert(enmType == TRPM_HARDWARE_INT);
    6299             VBOXSTRICTRC rcStrict = IEMInjectTrap(pVCpu, u8TrapNo, enmType, (uint16_t)uErrCode, uCr2, 0 /*cbInstr*/);
    6300 
    6301             TRPMResetTrap(pVCpu);
    6302 
    6303 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
    6304             /* Injecting an event may cause a VM-exit. */
    6305             if (   rcStrict != VINF_SUCCESS
    6306                 && rcStrict != VINF_IEM_RAISED_XCPT)
    6307                 return iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6308 #else
    6309             NOREF(rcStrict);
    6310 #endif
    6311         }
    6312     }
    6313 
    6314     return VINF_SUCCESS;
    6315 }
    6316 
    6317 
    6318 VMM_INT_DECL(VBOXSTRICTRC) IEMExecLots(PVMCPUCC pVCpu, uint32_t cMaxInstructions, uint32_t cPollRate, uint32_t *pcInstructions)
    6319 {
    6320     uint32_t const cInstructionsAtStart = pVCpu->iem.s.cInstructions;
    6321     AssertMsg(RT_IS_POWER_OF_TWO(cPollRate + 1), ("%#x\n", cPollRate));
    6322     Assert(cMaxInstructions > 0);
    6323 
    6324     /*
    6325      * See if there is an interrupt pending in TRPM, inject it if we can.
    6326      */
    6327     /** @todo What if we are injecting an exception and not an interrupt? Is that
    6328      *        possible here? For now we assert it is indeed only an interrupt. */
    6329     if (!TRPMHasTrap(pVCpu))
    6330     { /* likely */ }
    6331     else
    6332     {
    6333         VBOXSTRICTRC rcStrict = iemExecInjectPendingTrap(pVCpu);
    6334         if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    6335         { /*likely */ }
    6336         else
    6337             return rcStrict;
    6338     }
    6339 
    6340     /*
    6341      * Initial decoder init w/ prefetch, then setup setjmp.
    6342      */
    6343     VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, 0 /*fExecOpts*/);
    6344     if (rcStrict == VINF_SUCCESS)
    6345     {
    6346 #ifdef IEM_WITH_SETJMP
    6347         pVCpu->iem.s.cActiveMappings = 0; /** @todo wtf? */
    6348         IEM_TRY_SETJMP(pVCpu, rcStrict)
    6349 #endif
    6350         {
    6351             /*
    6352              * The run loop.  We limit ourselves to 4096 instructions right now.
    6353              */
    6354             uint32_t cMaxInstructionsGccStupidity = cMaxInstructions;
    6355             PVMCC pVM = pVCpu->CTX_SUFF(pVM);
    6356             for (;;)
    6357             {
    6358                 /*
    6359                  * Log the state.
    6360                  */
    6361 #ifdef LOG_ENABLED
    6362                 iemLogCurInstr(pVCpu, true, "IEMExecLots");
    6363 #endif
    6364 
    6365                 /*
    6366                  * Do the decoding and emulation.
    6367                  */
    6368                 uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);
    6369                 rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);
    6370 #ifdef VBOX_STRICT
    6371                 CPUMAssertGuestRFlagsCookie(pVM, pVCpu);
    6372 #endif
    6373                 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    6374                 {
    6375                     Assert(pVCpu->iem.s.cActiveMappings == 0);
    6376                     pVCpu->iem.s.cInstructions++;
    6377 
    6378 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    6379                     /* Perform any VMX nested-guest instruction boundary actions. */
    6380                     uint64_t fCpu = pVCpu->fLocalForcedActions;
    6381                     if (!(fCpu & (  VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER
    6382                                   | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW)))
    6383                     { /* likely */ }
    6384                     else
    6385                     {
    6386                         rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);
    6387                         if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    6388                             fCpu = pVCpu->fLocalForcedActions;
    6389                         else
    6390                         {
    6391                             rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6392                             break;
    6393                         }
    6394                     }
    6395 #endif
    6396                     if (RT_LIKELY(pVCpu->iem.s.rcPassUp == VINF_SUCCESS))
    6397                     {
    6398 #ifndef VBOX_WITH_NESTED_HWVIRT_VMX
    6399                         uint64_t fCpu = pVCpu->fLocalForcedActions;
    6400 #endif
    6401                         fCpu &= VMCPU_FF_ALL_MASK & ~(  VMCPU_FF_PGM_SYNC_CR3
    6402                                                       | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
    6403                                                       | VMCPU_FF_TLB_FLUSH
    6404                                                       | VMCPU_FF_UNHALT );
    6405 
    6406                         if (RT_LIKELY(   (   !fCpu
    6407                                           || (   !(fCpu & ~(VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
    6408                                               && !pVCpu->cpum.GstCtx.rflags.Bits.u1IF) )
    6409                                       && !VM_FF_IS_ANY_SET(pVM, VM_FF_ALL_MASK) ))
    6410                         {
    6411                             if (--cMaxInstructionsGccStupidity > 0)
    6412                             {
    6413                                 /* Poll timers every now an then according to the caller's specs. */
    6414                                 if (   (cMaxInstructionsGccStupidity & cPollRate) != 0
    6415                                     || !TMTimerPollBool(pVM, pVCpu))
    6416                                 {
    6417                                     Assert(pVCpu->iem.s.cActiveMappings == 0);
    6418                                     iemReInitDecoder(pVCpu);
    6419                                     continue;
    6420                                 }
    6421                             }
    6422                         }
    6423                     }
    6424                     Assert(pVCpu->iem.s.cActiveMappings == 0);
    6425                 }
    6426                 else if (pVCpu->iem.s.cActiveMappings > 0)
    6427                     iemMemRollback(pVCpu);
    6428                 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6429                 break;
    6430             }
    6431         }
    6432 #ifdef IEM_WITH_SETJMP
    6433         IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);
    6434         {
    6435             if (pVCpu->iem.s.cActiveMappings > 0)
    6436                 iemMemRollback(pVCpu);
    6437 # if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
    6438             rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6439 # endif
    6440             pVCpu->iem.s.cLongJumps++;
    6441         }
    6442         IEM_CATCH_LONGJMP_END(pVCpu);
    6443 #endif
    6444 
    6445         /*
    6446          * Assert hidden register sanity (also done in iemInitDecoder and iemReInitDecoder).
    6447          */
    6448         Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));
    6449         Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
    6450     }
    6451     else
    6452     {
    6453         if (pVCpu->iem.s.cActiveMappings > 0)
    6454             iemMemRollback(pVCpu);
    6455 
    6456 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
    6457         /*
    6458          * When a nested-guest causes an exception intercept (e.g. #PF) when fetching
    6459          * code as part of instruction execution, we need this to fix-up VINF_SVM_VMEXIT.
    6460          */
    6461         rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6462 #endif
    6463     }
    6464 
    6465     /*
    6466      * Maybe re-enter raw-mode and log.
    6467      */
    6468     if (rcStrict != VINF_SUCCESS)
    6469         LogFlow(("IEMExecLots: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc\n",
    6470                  pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict)));
    6471     if (pcInstructions)
    6472         *pcInstructions = pVCpu->iem.s.cInstructions - cInstructionsAtStart;
    6473     return rcStrict;
    6474 }
    6475 
    6476 
    6477 /**
    6478  * Interface used by EMExecuteExec, does exit statistics and limits.
    6479  *
    6480  * @returns Strict VBox status code.
    6481  * @param   pVCpu               The cross context virtual CPU structure.
    6482  * @param   fWillExit           To be defined.
    6483  * @param   cMinInstructions    Minimum number of instructions to execute before checking for FFs.
    6484  * @param   cMaxInstructions    Maximum number of instructions to execute.
    6485  * @param   cMaxInstructionsWithoutExits
    6486  *                              The max number of instructions without exits.
    6487  * @param   pStats              Where to return statistics.
    6488  */
    6489 VMM_INT_DECL(VBOXSTRICTRC)
    6490 IEMExecForExits(PVMCPUCC pVCpu, uint32_t fWillExit, uint32_t cMinInstructions, uint32_t cMaxInstructions,
    6491                 uint32_t cMaxInstructionsWithoutExits, PIEMEXECFOREXITSTATS pStats)
    6492 {
    6493     NOREF(fWillExit); /** @todo define flexible exit crits */
    6494 
    6495     /*
    6496      * Initialize return stats.
    6497      */
    6498     pStats->cInstructions    = 0;
    6499     pStats->cExits           = 0;
    6500     pStats->cMaxExitDistance = 0;
    6501     pStats->cReserved        = 0;
    6502 
    6503     /*
    6504      * Initial decoder init w/ prefetch, then setup setjmp.
    6505      */
    6506     VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, 0 /*fExecOpts*/);
    6507     if (rcStrict == VINF_SUCCESS)
    6508     {
    6509 #ifdef IEM_WITH_SETJMP
    6510         pVCpu->iem.s.cActiveMappings     = 0; /** @todo wtf?!? */
    6511         IEM_TRY_SETJMP(pVCpu, rcStrict)
    6512 #endif
    6513         {
    6514 #ifdef IN_RING0
    6515             bool const fCheckPreemptionPending   = !RTThreadPreemptIsPossible() || !RTThreadPreemptIsEnabled(NIL_RTTHREAD);
    6516 #endif
    6517             uint32_t   cInstructionSinceLastExit = 0;
    6518 
    6519             /*
    6520              * The run loop.  We limit ourselves to 4096 instructions right now.
    6521              */
    6522             PVM pVM = pVCpu->CTX_SUFF(pVM);
    6523             for (;;)
    6524             {
    6525                 /*
    6526                  * Log the state.
    6527                  */
    6528 #ifdef LOG_ENABLED
    6529                 iemLogCurInstr(pVCpu, true, "IEMExecForExits");
    6530 #endif
    6531 
    6532                 /*
    6533                  * Do the decoding and emulation.
    6534                  */
    6535                 uint32_t const cPotentialExits = pVCpu->iem.s.cPotentialExits;
    6536 
    6537                 uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);
    6538                 rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);
    6539 
    6540                 if (   cPotentialExits != pVCpu->iem.s.cPotentialExits
    6541                     && cInstructionSinceLastExit > 0 /* don't count the first */ )
    6542                 {
    6543                     pStats->cExits += 1;
    6544                     if (cInstructionSinceLastExit > pStats->cMaxExitDistance)
    6545                         pStats->cMaxExitDistance = cInstructionSinceLastExit;
    6546                     cInstructionSinceLastExit = 0;
    6547                 }
    6548 
    6549                 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    6550                 {
    6551                     Assert(pVCpu->iem.s.cActiveMappings == 0);
    6552                     pVCpu->iem.s.cInstructions++;
    6553                     pStats->cInstructions++;
    6554                     cInstructionSinceLastExit++;
    6555 
    6556 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    6557                     /* Perform any VMX nested-guest instruction boundary actions. */
    6558                     uint64_t fCpu = pVCpu->fLocalForcedActions;
    6559                     if (!(fCpu & (  VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER
    6560                                   | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW)))
    6561                     { /* likely */ }
    6562                     else
    6563                     {
    6564                         rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);
    6565                         if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    6566                             fCpu = pVCpu->fLocalForcedActions;
    6567                         else
    6568                         {
    6569                             rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6570                             break;
    6571                         }
    6572                     }
    6573 #endif
    6574                     if (RT_LIKELY(pVCpu->iem.s.rcPassUp == VINF_SUCCESS))
    6575                     {
    6576 #ifndef VBOX_WITH_NESTED_HWVIRT_VMX
    6577                         uint64_t fCpu = pVCpu->fLocalForcedActions;
    6578 #endif
    6579                         fCpu &= VMCPU_FF_ALL_MASK & ~(  VMCPU_FF_PGM_SYNC_CR3
    6580                                                       | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
    6581                                                       | VMCPU_FF_TLB_FLUSH
    6582                                                       | VMCPU_FF_UNHALT );
    6583                         if (RT_LIKELY(   (   (   !fCpu
    6584                                               || (   !(fCpu & ~(VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
    6585                                                   && !pVCpu->cpum.GstCtx.rflags.Bits.u1IF))
    6586                                           && !VM_FF_IS_ANY_SET(pVM, VM_FF_ALL_MASK) )
    6587                                       || pStats->cInstructions < cMinInstructions))
    6588                         {
    6589                             if (pStats->cInstructions < cMaxInstructions)
    6590                             {
    6591                                 if (cInstructionSinceLastExit <= cMaxInstructionsWithoutExits)
    6592                                 {
    6593 #ifdef IN_RING0
    6594                                     if (   !fCheckPreemptionPending
    6595                                         || !RTThreadPreemptIsPending(NIL_RTTHREAD))
    6596 #endif
    6597                                     {
    6598                                         Assert(pVCpu->iem.s.cActiveMappings == 0);
    6599                                         iemReInitDecoder(pVCpu);
    6600                                         continue;
    6601                                     }
    6602 #ifdef IN_RING0
    6603                                     rcStrict = VINF_EM_RAW_INTERRUPT;
    6604                                     break;
    6605 #endif
    6606                                 }
    6607                             }
    6608                         }
    6609                         Assert(!(fCpu & VMCPU_FF_IEM));
    6610                     }
    6611                     Assert(pVCpu->iem.s.cActiveMappings == 0);
    6612                 }
    6613                 else if (pVCpu->iem.s.cActiveMappings > 0)
    6614                         iemMemRollback(pVCpu);
    6615                 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6616                 break;
    6617             }
    6618         }
    6619 #ifdef IEM_WITH_SETJMP
    6620         IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);
    6621         {
    6622             if (pVCpu->iem.s.cActiveMappings > 0)
    6623                 iemMemRollback(pVCpu);
    6624             pVCpu->iem.s.cLongJumps++;
    6625         }
    6626         IEM_CATCH_LONGJMP_END(pVCpu);
    6627 #endif
    6628 
    6629         /*
    6630          * Assert hidden register sanity (also done in iemInitDecoder and iemReInitDecoder).
    6631          */
    6632         Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));
    6633         Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
    6634     }
    6635     else
    6636     {
    6637         if (pVCpu->iem.s.cActiveMappings > 0)
    6638             iemMemRollback(pVCpu);
    6639 
    6640 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
    6641         /*
    6642          * When a nested-guest causes an exception intercept (e.g. #PF) when fetching
    6643          * code as part of instruction execution, we need this to fix-up VINF_SVM_VMEXIT.
    6644          */
    6645         rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
    6646 #endif
    6647     }
    6648 
    6649     /*
    6650      * Maybe re-enter raw-mode and log.
    6651      */
    6652     if (rcStrict != VINF_SUCCESS)
    6653         LogFlow(("IEMExecForExits: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc; ins=%u exits=%u maxdist=%u\n",
    6654                  pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp,
    6655                  pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict), pStats->cInstructions, pStats->cExits, pStats->cMaxExitDistance));
    6656     return rcStrict;
    6657 }
    6658 
    6659 
    6660 /**
    6661  * Injects a trap, fault, abort, software interrupt or external interrupt.
    6662  *
    6663  * The parameter list matches TRPMQueryTrapAll pretty closely.
    6664  *
    6665  * @returns Strict VBox status code.
    6666  * @param   pVCpu               The cross context virtual CPU structure of the calling EMT.
    6667  * @param   u8TrapNo            The trap number.
    6668  * @param   enmType             What type is it (trap/fault/abort), software
    6669  *                              interrupt or hardware interrupt.
    6670  * @param   uErrCode            The error code if applicable.
    6671  * @param   uCr2                The CR2 value if applicable.
    6672  * @param   cbInstr             The instruction length (only relevant for
    6673  *                              software interrupts).
    6674  * @note    x86 specific, but difficult to move due to iemInitDecoder dep.
    6675  */
    6676 VMM_INT_DECL(VBOXSTRICTRC) IEMInjectTrap(PVMCPUCC pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType, uint16_t uErrCode, RTGCPTR uCr2,
    6677                                          uint8_t cbInstr)
    6678 {
    6679     iemInitDecoder(pVCpu, 0 /*fExecOpts*/); /** @todo wrong init function! */
    6680 #ifdef DBGFTRACE_ENABLED
    6681     RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "IEMInjectTrap: %x %d %x %llx",
    6682                       u8TrapNo, enmType, uErrCode, uCr2);
    6683 #endif
    6684 
    6685     uint32_t fFlags;
    6686     switch (enmType)
    6687     {
    6688         case TRPM_HARDWARE_INT:
    6689             Log(("IEMInjectTrap: %#4x ext\n", u8TrapNo));
    6690             fFlags = IEM_XCPT_FLAGS_T_EXT_INT;
    6691             uErrCode = uCr2 = 0;
    6692             break;
    6693 
    6694         case TRPM_SOFTWARE_INT:
    6695             Log(("IEMInjectTrap: %#4x soft\n", u8TrapNo));
    6696             fFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
    6697             uErrCode = uCr2 = 0;
    6698             break;
    6699 
    6700         case TRPM_TRAP:
    6701         case TRPM_NMI: /** @todo Distinguish NMI from exception 2. */
    6702             Log(("IEMInjectTrap: %#4x trap err=%#x cr2=%#RGv\n", u8TrapNo, uErrCode, uCr2));
    6703             fFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
    6704             if (u8TrapNo == X86_XCPT_PF)
    6705                 fFlags |= IEM_XCPT_FLAGS_CR2;
    6706             switch (u8TrapNo)
    6707             {
    6708                 case X86_XCPT_DF:
    6709                 case X86_XCPT_TS:
    6710                 case X86_XCPT_NP:
    6711                 case X86_XCPT_SS:
    6712                 case X86_XCPT_PF:
    6713                 case X86_XCPT_AC:
    6714                 case X86_XCPT_GP:
    6715                     fFlags |= IEM_XCPT_FLAGS_ERR;
    6716                     break;
    6717             }
    6718             break;
    6719 
    6720         IEM_NOT_REACHED_DEFAULT_CASE_RET();
    6721     }
    6722 
    6723     VBOXSTRICTRC rcStrict = iemRaiseXcptOrInt(pVCpu, cbInstr, u8TrapNo, fFlags, uErrCode, uCr2);
    6724 
    6725     if (pVCpu->iem.s.cActiveMappings > 0)
    6726         iemMemRollback(pVCpu);
    6727 
    6728     return rcStrict;
    6729 }
    6730 
    6731 
    6732 /**
    6733  * Injects the active TRPM event.
    6734  *
    6735  * @returns Strict VBox status code.
    6736  * @param   pVCpu               The cross context virtual CPU structure.
    6737  */
    6738 VMM_INT_DECL(VBOXSTRICTRC) IEMInjectTrpmEvent(PVMCPUCC pVCpu)
    6739 {
    6740 #ifndef IEM_IMPLEMENTS_TASKSWITCH
    6741     IEM_RETURN_ASPECT_NOT_IMPLEMENTED_LOG(("Event injection\n"));
    6742 #else
    6743     uint8_t     u8TrapNo;
    6744     TRPMEVENT   enmType;
    6745     uint32_t    uErrCode;
    6746     RTGCUINTPTR uCr2;
    6747     uint8_t     cbInstr;
    6748     int rc = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrCode, &uCr2, &cbInstr, NULL /* fIcebp */);
    6749     if (RT_FAILURE(rc))
    6750         return rc;
    6751 
    6752     /** @todo r=ramshankar: Pass ICEBP info. to IEMInjectTrap() below and handle
    6753      *        ICEBP \#DB injection as a special case. */
    6754     VBOXSTRICTRC rcStrict = IEMInjectTrap(pVCpu, u8TrapNo, enmType, uErrCode, uCr2, cbInstr);
    6755 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM
    6756     if (rcStrict == VINF_SVM_VMEXIT)
    6757         rcStrict = VINF_SUCCESS;
    6758 #endif
    6759 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    6760     if (rcStrict == VINF_VMX_VMEXIT)
    6761         rcStrict = VINF_SUCCESS;
    6762 #endif
    6763     /** @todo Are there any other codes that imply the event was successfully
    6764      *        delivered to the guest? See @bugref{6607}.  */
    6765     if (   rcStrict == VINF_SUCCESS
    6766         || rcStrict == VINF_IEM_RAISED_XCPT)
    6767         TRPMResetTrap(pVCpu);
    6768 
    6769     return rcStrict;
    6770 #endif
    6771 }
    6772 
    6773 
    6774 VMM_INT_DECL(int) IEMBreakpointSet(PVM pVM, RTGCPTR GCPtrBp)
    6775 {
    6776     RT_NOREF_PV(pVM); RT_NOREF_PV(GCPtrBp);
    6777     return VERR_NOT_IMPLEMENTED;
    6778 }
    6779 
    6780 
    6781 VMM_INT_DECL(int) IEMBreakpointClear(PVM pVM, RTGCPTR GCPtrBp)
    6782 {
    6783     RT_NOREF_PV(pVM); RT_NOREF_PV(GCPtrBp);
    6784     return VERR_NOT_IMPLEMENTED;
    6785 }
    6786 
    6787 #ifdef IN_RING3
    6788 
    6789 /**
    6790  * Handles the unlikely and probably fatal merge cases.
    6791  *
    6792  * @returns Merged status code.
    6793  * @param   rcStrict        Current EM status code.
    6794  * @param   rcStrictCommit  The IOM I/O or MMIO write commit status to merge
    6795  *                          with @a rcStrict.
    6796  * @param   iMemMap         The memory mapping index. For error reporting only.
    6797  * @param   pVCpu           The cross context virtual CPU structure of the calling
    6798  *                          thread, for error reporting only.
    6799  */
    6800 DECL_NO_INLINE(static, VBOXSTRICTRC) iemR3MergeStatusSlow(VBOXSTRICTRC rcStrict, VBOXSTRICTRC rcStrictCommit,
    6801                                                           unsigned iMemMap, PVMCPUCC pVCpu)
    6802 {
    6803     if (RT_FAILURE_NP(rcStrict))
    6804         return rcStrict;
    6805 
    6806     if (RT_FAILURE_NP(rcStrictCommit))
    6807         return rcStrictCommit;
    6808 
    6809     if (rcStrict == rcStrictCommit)
    6810         return rcStrictCommit;
    6811 
    6812     AssertLogRelMsgFailed(("rcStrictCommit=%Rrc rcStrict=%Rrc iMemMap=%u fAccess=%#x FirstPg=%RGp LB %u SecondPg=%RGp LB %u\n",
    6813                            VBOXSTRICTRC_VAL(rcStrictCommit), VBOXSTRICTRC_VAL(rcStrict), iMemMap,
    6814                            pVCpu->iem.s.aMemMappings[iMemMap].fAccess,
    6815                            pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst,
    6816                            pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond));
    6817     return VERR_IOM_FF_STATUS_IPE;
    6818 }
    6819 
    6820 
    6821 /**
    6822  * Helper for IOMR3ProcessForceFlag.
    6823  *
    6824  * @returns Merged status code.
    6825  * @param   rcStrict        Current EM status code.
    6826  * @param   rcStrictCommit  The IOM I/O or MMIO write commit status to merge
    6827  *                          with @a rcStrict.
    6828  * @param   iMemMap         The memory mapping index. For error reporting only.
    6829  * @param   pVCpu           The cross context virtual CPU structure of the calling
    6830  *                          thread, for error reporting only.
    6831  */
    6832 DECLINLINE(VBOXSTRICTRC) iemR3MergeStatus(VBOXSTRICTRC rcStrict, VBOXSTRICTRC rcStrictCommit, unsigned iMemMap, PVMCPUCC pVCpu)
    6833 {
    6834     /* Simple. */
    6835     if (RT_LIKELY(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RAW_TO_R3))
    6836         return rcStrictCommit;
    6837 
    6838     if (RT_LIKELY(rcStrictCommit == VINF_SUCCESS))
    6839         return rcStrict;
    6840 
    6841     /* EM scheduling status codes. */
    6842     if (RT_LIKELY(   rcStrict >= VINF_EM_FIRST
    6843                   && rcStrict <= VINF_EM_LAST))
    6844     {
    6845         if (RT_LIKELY(   rcStrictCommit >= VINF_EM_FIRST
    6846                       && rcStrictCommit <= VINF_EM_LAST))
    6847             return rcStrict < rcStrictCommit ? rcStrict : rcStrictCommit;
    6848     }
    6849 
    6850     /* Unlikely */
    6851     return iemR3MergeStatusSlow(rcStrict, rcStrictCommit, iMemMap, pVCpu);
    6852 }
    6853 
    6854 
    6855 /**
    6856  * Called by force-flag handling code when VMCPU_FF_IEM is set.
    6857  *
    6858  * @returns Merge between @a rcStrict and what the commit operation returned.
    6859  * @param   pVM         The cross context VM structure.
    6860  * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
    6861  * @param   rcStrict    The status code returned by ring-0 or raw-mode.
    6862  */
    6863 VMMR3_INT_DECL(VBOXSTRICTRC) IEMR3ProcessForceFlag(PVM pVM, PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict)
    6864 {
    6865     /*
    6866      * Reset the pending commit.
    6867      */
    6868     AssertMsg(  (pVCpu->iem.s.aMemMappings[0].fAccess | pVCpu->iem.s.aMemMappings[1].fAccess | pVCpu->iem.s.aMemMappings[2].fAccess)
    6869               & (IEM_ACCESS_PENDING_R3_WRITE_1ST | IEM_ACCESS_PENDING_R3_WRITE_2ND),
    6870               ("%#x %#x %#x\n",
    6871                pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemMappings[2].fAccess));
    6872     VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_IEM);
    6873 
    6874     /*
    6875      * Commit the pending bounce buffers (usually just one).
    6876      */
    6877     unsigned cBufs = 0;
    6878     unsigned iMemMap = RT_ELEMENTS(pVCpu->iem.s.aMemMappings);
    6879     while (iMemMap-- > 0)
    6880         if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_PENDING_R3_WRITE_1ST | IEM_ACCESS_PENDING_R3_WRITE_2ND))
    6881         {
    6882             Assert(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE);
    6883             Assert(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED);
    6884             Assert(!pVCpu->iem.s.aMemBbMappings[iMemMap].fUnassigned);
    6885 
    6886             uint16_t const  cbFirst  = pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst;
    6887             uint16_t const  cbSecond = pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond;
    6888             uint8_t const  *pbBuf    = &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0];
    6889 
    6890             if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_PENDING_R3_WRITE_1ST)
    6891             {
    6892                 VBOXSTRICTRC rcStrictCommit1 = PGMPhysWrite(pVM,
    6893                                                             pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst,
    6894                                                             pbBuf,
    6895                                                             cbFirst,
    6896                                                             PGMACCESSORIGIN_IEM);
    6897                 rcStrict = iemR3MergeStatus(rcStrict, rcStrictCommit1, iMemMap, pVCpu);
    6898                 Log(("IEMR3ProcessForceFlag: iMemMap=%u GCPhysFirst=%RGp LB %#x %Rrc => %Rrc\n",
    6899                      iMemMap, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,
    6900                      VBOXSTRICTRC_VAL(rcStrictCommit1), VBOXSTRICTRC_VAL(rcStrict)));
    6901             }
    6902 
    6903             if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_PENDING_R3_WRITE_2ND)
    6904             {
    6905                 VBOXSTRICTRC rcStrictCommit2 = PGMPhysWrite(pVM,
    6906                                                             pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond,
    6907                                                             pbBuf + cbFirst,
    6908                                                             cbSecond,
    6909                                                             PGMACCESSORIGIN_IEM);
    6910                 rcStrict = iemR3MergeStatus(rcStrict, rcStrictCommit2, iMemMap, pVCpu);
    6911                 Log(("IEMR3ProcessForceFlag: iMemMap=%u GCPhysSecond=%RGp LB %#x %Rrc => %Rrc\n",
    6912                      iMemMap, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond,
    6913                      VBOXSTRICTRC_VAL(rcStrictCommit2), VBOXSTRICTRC_VAL(rcStrict)));
    6914             }
    6915             cBufs++;
    6916             pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
    6917         }
    6918 
    6919     AssertMsg(cBufs > 0 && cBufs == pVCpu->iem.s.cActiveMappings,
    6920               ("cBufs=%u cActiveMappings=%u - %#x %#x %#x\n", cBufs, pVCpu->iem.s.cActiveMappings,
    6921                pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemMappings[2].fAccess));
    6922     pVCpu->iem.s.cActiveMappings = 0;
    6923     return rcStrict;
    6924 }
    6925 
    6926 #endif /* IN_RING3 */
    6927 
     456#endif /* !VMM_INCLUDED_SRC_VMMAll_target_x86_IEMAllTlbInline_x86_h */
  • trunk/src/VBox/VMM/include/IEMInternal.h

    r108195 r108226  
    31603160/** @name   Memory access.
    31613161 * @{ */
     3162VBOXSTRICTRC    iemMemBounceBufferMapCrossPage(PVMCPUCC pVCpu, int iMemMap, void **ppvMem, uint8_t *pbUnmapInfo,
     3163                                               size_t cbMem, RTGCPTR GCPtrFirst, uint32_t fAccess) RT_NOEXCEPT;
     3164VBOXSTRICTRC    iemMemBounceBufferMapPhys(PVMCPUCC pVCpu, unsigned iMemMap, void **ppvMem, uint8_t *pbUnmapInfo, size_t cbMem,
     3165                                          RTGCPHYS GCPhysFirst, uint32_t fAccess, VBOXSTRICTRC rcMap) RT_NOEXCEPT;
    31623166VBOXSTRICTRC    iemMemCommitAndUnmap(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT;
    31633167#ifndef IN_RING3
     
    31753179void            iemMemRollbackAndUnmapWoSafe(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT;
    31763180#endif
     3181
     3182void            iemTlbInvalidateAllPhysicalSlow(PVMCPUCC pVCpu) RT_NOEXCEPT;
    31773183/** @} */
    31783184
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette