Changeset 108226 in vbox
- Timestamp:
- Feb 14, 2025 3:54:48 PM (4 weeks ago)
- svn:sync-xref-src-repo-rev:
- 167546
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 4 edited
- 2 copied
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/Makefile.kmk
r108220 r108226 196 196 VMMAll/IEMAll.cpp \ 197 197 VMMAll/target-x86/IEMAllExec-x86.cpp \ 198 VMMAll/target-x86/IEMAllMem-x86.cpp \ 198 199 VMMAll/target-x86/IEMAllXcpt-x86.cpp \ 199 200 VMMAll/target-x86/IEMAllHlpFpu-x86.cpp \ … … 941 942 VMMAll/IEMAll.cpp \ 942 943 VMMAll/target-x86/IEMAllExec-x86.cpp \ 944 VMMAll/target-x86/IEMAllMem-x86.cpp \ 943 945 VMMAll/target-x86/IEMAllXcpt-x86.cpp \ 944 946 VMMAll/target-x86/IEMAllHlpFpu-x86.cpp \ … … 1158 1160 VMMAll/IEMAll.cpp_CXXFLAGS += -noover -O2xy 1159 1161 VMMAll/target-x86/IEMAllExec-x86.cpp_CXXFLAGS += -noover -O2xy 1162 VMMAll/target-x86/IEMAllMem-x86.cpp_CXXFLAGS += -noover -O2xy 1160 1163 VMMAll/target-x86/IEMAllXcpt-x86.cpp_CXXFLAGS += -noover -O2xy 1161 1164 VMMAll/target-x86/IEMAllHlpFpu-x86.cpp_CXXFLAGS += -noover -O2xy … … 1172 1175 VMMAll/IEMAll.cpp_CXXFLAGS += -O2 -fomit-frame-pointer 1173 1176 VMMAll/target-x86/IEMAllExec-x86.cpp_CXXFLAGS += -O2 -fomit-frame-pointer 1177 VMMAll/target-x86/IEMAllMem-x86.cpp_CXXFLAGS += -O2 -fomit-frame-pointer 1174 1178 VMMAll/target-x86/IEMAllXcpt-x86.cpp_CXXFLAGS += -O2 -fomit-frame-pointer 1175 1179 VMMAll/target-x86/IEMAllHlpFpu-x86.cpp_CXXFLAGS += -O2 -fomit-frame-pointer -
trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
r108220 r108226 163 163 164 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; 165 #ifdef VBOX_VMM_TARGET_X86 166 # include "target-x86/IEMAllTlbInline-x86.h" 167 #endif 180 168 181 169 … … 635 623 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) 636 624 /** 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 else645 pTlb->cTlbNonGlobalLargePageCurLoads++;646 647 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP648 RTGCPTR const idxBit = IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + a_fGlobal;649 ASMBitSet(pTlb->bmLargePage, idxBit);650 # endif651 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_fGlobal655 ? &pTlb->GlobalLargePageRange656 : &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 #endif668 669 670 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB)671 /**672 625 * Worker for iemTlbInvalidateAll. 673 626 */ … … 777 730 778 731 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_SIZE784 # define RT_CACHELINE_SIZE 128785 # endif786 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 # else794 # define MY_PREFETCH(a_pvAddr) ((void)0)795 # endif796 # if 0797 # undef MY_PREFETCH798 # define MY_PREFETCH(a_pvAddr) ((void)0)799 # endif800 801 /** @def MY_PREFETCH_64802 * 64 byte prefetch hint, could be more depending on cache line size. */803 /** @def MY_PREFETCH_128804 * 128 byte prefetch hint. */805 /** @def MY_PREFETCH_256806 * 256 byte prefetch hint. */807 # if RT_CACHELINE_SIZE >= 128808 /* 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 # else816 /* 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 # endif829 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_NOEXCEPT833 {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 map846 * 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 mask848 * 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: 0xfffffffffffffeff851 *852 * MY_PREFETCH: Hope that prefetching 256 bytes at the time is okay for853 * 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_BITMAP858 uintptr_t idxBitmap = fPartialScan ? IEMTLB_TAG_TO_EVEN_INDEX(GCPtrTag) / 64 : 0;859 uintptr_t const idxBitmapEnd = fPartialScan ? idxBitmap + ((a_f2MbLargePage ? 512 : 1024) * 2) / 64860 : IEMTLB_ENTRY_COUNT * 2 / 64;861 #else862 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 #endif866 RTGCPTR const GCPtrTagMask = fPartialScan ? ~(RTGCPTR)0867 : ~(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_fDataTlb876 && 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_BITMAP890 uint64_t const bmMask = a_fGlobal && a_fNonGlobal ? UINT64_MAX891 : a_fGlobal ? UINT64_C(0xaaaaaaaaaaaaaaaa) : UINT64_C(0x5555555555555555);892 /* Scan bitmap entries (64 bits at the time): */893 for (;;)894 {895 # if 1896 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_PAIR953 }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 # else967 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_PAIRS1038 1039 /* Clear the large page flags we covered. */1040 pTlb->bmLargePage[idxBitmap] &= ~bmToClear;1041 }1042 # endif1043 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_ITERATION1093 }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_NOEXCEPT1100 {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.uFirstTag1105 && GCPtrTag <= pTlb->GlobalLargePageRange.uLastTag)1106 {1107 if ( GCPtrTag < pTlb->NonGlobalLargePageRange.uFirstTag1108 || GCPtrTag > pTlb->NonGlobalLargePageRange.uLastTag)1109 iemTlbInvalidateLargePageWorkerInner<a_fDataTlb, a_f2MbLargePage, true, false>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag);1110 else1111 iemTlbInvalidateLargePageWorkerInner<a_fDataTlb, a_f2MbLargePage, true, true>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag);1112 }1113 else if ( GCPtrTag < pTlb->NonGlobalLargePageRange.uFirstTag1114 || 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 else1120 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_NOEXCEPT1125 {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 the1148 * address being flushed may involve one of those, as then we'd have to1149 * 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 # else1154 if (pTlb->GlobalLargePageRange.uLastTag || pTlb->NonGlobalLargePageRange.uLastTag)1155 # endif1156 {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 else1161 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 732 /** 1168 733 * Invalidates a page in the TLBs. … … 1204 769 * @thread EMT(pVCpu) 1205 770 */ 1206 static void IEMTlbInvalidateAllPhysicalSlow(PVMCPUCC pVCpu) 1207 { 1208 Log10((" IEMTlbInvalidateAllPhysicalSlow\n"));771 void iemTlbInvalidateAllPhysicalSlow(PVMCPUCC pVCpu) RT_NOEXCEPT 772 { 773 Log10(("iemTlbInvalidateAllPhysicalSlow\n")); 1209 774 ASMAtomicWriteU64(&pVCpu->iem.s.CodeTlb.uTlbPhysRev, IEMTLB_PHYS_REV_INCR * 2); 1210 775 ASMAtomicWriteU64(&pVCpu->iem.s.DataTlb.uTlbPhysRev, IEMTLB_PHYS_REV_INCR * 2); … … 1265 830 } 1266 831 else 1267 IEMTlbInvalidateAllPhysicalSlow(pVCpu);832 iemTlbInvalidateAllPhysicalSlow(pVCpu); 1268 833 #else 1269 834 NOREF(pVCpu); … … 1307 872 else 1308 873 { 1309 IEMTlbInvalidateAllPhysicalSlow(pVCpu);874 iemTlbInvalidateAllPhysicalSlow(pVCpu); 1310 875 continue; 1311 876 } … … 1483 1048 { /* likely */ } 1484 1049 else 1485 IEMTlbInvalidateAllPhysicalSlow(pVCpu);1050 iemTlbInvalidateAllPhysicalSlow(pVCpu); 1486 1051 pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK; 1487 1052 int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.CodeTlb.uTlbPhysRev, … … 1556 1121 { /* likely */ } 1557 1122 else 1558 IEMTlbInvalidateAllPhysicalSlow(pVCpu);1123 iemTlbInvalidateAllPhysicalSlow(pVCpu); 1559 1124 Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_GCPHYS2PTR_MASK)); 1560 1125 rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhysPg, &pVCpu->iem.s.CodeTlb.uTlbPhysRev, … … 2427 1992 #undef LOG_GROUP 2428 1993 #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 apply2444 * segmentation to. Input and output parameter.2445 */2446 VBOXSTRICTRC iemMemApplySegment(PVMCPUCC pVCpu, uint32_t fAccess, uint8_t iSegReg, size_t cbMem, PRTGCPTR pGCPtrMem) RT_NOEXCEPT2447 {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.u1Present2462 && !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->u32Limit2482 || GCPtrLast32 > pSel->u32Limit) /* yes, in real mode too (since 80286). */2483 return iemRaiseSelectorBounds(pVCpu, iSegReg, fAccess);2484 }2485 else2486 {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 else2497 {2498 /*2499 * Code selector and usually be used to read thru, writing is2500 * 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->u32Limit2509 || 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 else2521 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 we2547 * 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 for2552 * 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_NOEXCEPT2558 {2559 /** @todo Need a different PGM interface here. We're currently using2560 * generic / REM interfaces. this won't cut it for R0. */2561 /** @todo If/when PGM handles paged real-mode, we can remove the hack in2562 * iemSvmWorldSwitch/iemVmxWorldSwitch to work around raising a page-fault2563 * 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, all2580 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) != 32585 || (fAccess & IEM_ACCESS_WHAT_SYS))2586 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)) )2587 && ( (WalkFast.fEffective & X86_PTE_US)2588 || IEM_GET_CPL(pVCpu) != 32589 || (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_EPT2607 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 #endif2610 *pGCPhysMem = NIL_RTGCPHYS;2611 return iemRaisePageFault(pVCpu, GCPtrMem, cbAccess, fAccess, rc);2612 }2613 1994 2614 1995 #if 0 /*unused*/ … … 2883 2264 /** 2884 2265 * Helper for iemMemMap, iemMemMapJmp and iemMemBounceBufferMapCrossPage. 2266 * @todo duplicated 2885 2267 */ 2886 2268 DECL_FORCE_INLINE(uint32_t) … … 2897 2279 * iemMemMap worker that deals with a request crossing pages. 2898 2280 */ 2899 static VBOXSTRICTRC 2900 iemMemBounceBufferMapCrossPage(PVMCPUCC pVCpu, int iMemMap, void **ppvMem, uint8_t *pbUnmapInfo, 2901 size_t cbMem, RTGCPTR GCPtrFirst, uint32_t fAccess) 2281 VBOXSTRICTRC iemMemBounceBufferMapCrossPage(PVMCPUCC pVCpu, int iMemMap, void **ppvMem, uint8_t *pbUnmapInfo, 2282 size_t cbMem, RTGCPTR GCPtrFirst, uint32_t fAccess) RT_NOEXCEPT 2902 2283 { 2903 2284 STAM_COUNTER_INC(&pVCpu->iem.s.StatMemBounceBufferCrossPage); … … 3050 2431 * iemMemMap woker that deals with iemMemPageMap failures. 3051 2432 */ 3052 staticVBOXSTRICTRC iemMemBounceBufferMapPhys(PVMCPUCC pVCpu, unsigned iMemMap, void **ppvMem, uint8_t *pbUnmapInfo, size_t cbMem,3053 RTGCPHYS GCPhysFirst, uint32_t fAccess, VBOXSTRICTRC rcMap)2433 VBOXSTRICTRC iemMemBounceBufferMapPhys(PVMCPUCC pVCpu, unsigned iMemMap, void **ppvMem, uint8_t *pbUnmapInfo, size_t cbMem, 2434 RTGCPHYS GCPhysFirst, uint32_t fAccess, VBOXSTRICTRC rcMap) RT_NOEXCEPT 3054 2435 { 3055 2436 STAM_COUNTER_INC(&pVCpu->iem.s.StatMemBounceBufferMapPhys); … … 3137 2518 3138 2519 /** 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 page3142 * boundary or if there is an access handler installed for any of it. Because3143 * of lock prefix guarantees, we're in for some extra clutter when this3144 * 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 to3153 * iemMemCommitAndUnmap or iemMemRollbackAndUnmap when3154 * 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 operations3157 * it can be up to a page.3158 * @param iSegReg The index of the segment register to use for this3159 * access. The base and limits are checked. Use UINT8_MAX3160 * 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. The3164 * IEM_ACCESS_TYPE_XXX part is used to figure out how to3165 * map the memory, while the IEM_ACCESS_WHAT_XXX part is3166 * used when raising exceptions. The IEM_ACCESS_ATOMIC and3167 * IEM_ACCESS_PARTIAL_WRITE bits are also allowed to be3168 * 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, and3173 * 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_NOEXCEPT3178 {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 == 943186 || (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 something3204 * 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 else3210 return rcStrict;3211 3212 if ((GCPtrMem & GUEST_PAGE_OFFSET_MASK) + cbMem <= GUEST_PAGE_SIZE) /* Crossing a page boundary? */3213 { /* likely */ }3214 else3215 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 else3223 {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 else3236 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 CPU3241 * implementation. See FXSAVE/FRSTOR/XSAVE/XRSTOR/++. Using 4 for now as3242 * that's what FXSAVE does on a 10980xe. */3243 && iemMemAreAlignmentChecksEnabled(pVCpu))3244 return iemRaiseAlignmentCheckException(pVCpu);3245 else3246 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 restrictions3251 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 # else3258 # error port me3259 # endif3260 )3261 { /* okay */ }3262 else3263 {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 #endif3269 }3270 3271 #ifdef IEM_WITH_DATA_TLB3272 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 (accessed3278 * 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_STATISTICS3290 pVCpu->iem.s.DataTlb.cTlbCoreHits++;3291 # endif3292 3293 /* If the page is either supervisor only or non-writable, we need to do3294 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) == 33301 && !(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) == 33311 && !(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_RING33321 pbMem = pTlbe->pbMappingR3;3322 # else3323 pbMem = NULL;3324 # endif3325 else3326 {3327 if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR))3328 { /* likely */ }3329 else3330 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_RING33337 pTlbe->pbMappingR3 = pbMem;3338 # endif3339 }3340 }3341 else3342 {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 else3361 {3362 LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - failed to fetch page -> #PF\n", GCPtrMem));3363 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT3364 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 # endif3367 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_BITMAP3382 else3383 ASMBitClear(pVCpu->iem.s.DataTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev));3384 # endif3385 }3386 else3387 {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_BITMAP3393 else3394 ASMBitClear(pVCpu->iem.s.DataTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + 1);3395 # endif3396 }3397 }3398 else3399 {3400 /* If we hit a data breakpoint, we use a dummy TLBE to force all accesses3401 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) != 33421 || (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 else3428 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_RING33437 pTlbe->pbMappingR3 = pbMem;3438 # endif3439 }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 else3449 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_UNASSIGNED3452 : pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_NO_READ ? VERR_PGM_PHYS_TLB_CATCH_ALL3453 : 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 else3463 {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 2520 * Commits the guest memory if bounce buffered and unmaps it. 3516 2521 * … … 3572 2577 3573 2578 #ifdef IEM_WITH_SETJMP 3574 3575 /**3576 * Maps the specified guest memory for the given kind of access, longjmp on3577 * error.3578 *3579 * This may be using bounce buffering of the memory if it's crossing a page3580 * boundary or if there is an access handler installed for any of it. Because3581 * of lock prefix guarantees, we're in for some extra clutter when this3582 * 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 to3590 * iemMemCommitAndUnmapJmp, iemMemCommitAndUnmapRwSafeJmp,3591 * iemMemCommitAndUnmapWoSafeJmp,3592 * iemMemCommitAndUnmapRoSafeJmp,3593 * iemMemRollbackAndUnmapWoSafe or iemMemRollbackAndUnmap3594 * 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 by3597 * string operations it can be up to a page.3598 * @param iSegReg The index of the segment register to use for3599 * this access. The base and limits are checked.3600 * Use UINT8_MAX to indicate that no segmentation3601 * 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. The3604 * IEM_ACCESS_TYPE_XXX part is used to figure out how to3605 * map the memory, while the IEM_ACCESS_WHAT_XXX part is3606 * used when raising exceptions. The IEM_ACCESS_ATOMIC and3607 * IEM_ACCESS_PARTIAL_WRITE bits are also allowed to be3608 * 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, and3613 * 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 in3616 * IEMAllMemRWTmpl.cpp.h (@c true) or a generic one that3617 * 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_LONGJMP3622 {3623 STAM_COUNTER_INC(&pVCpu->iem.s.StatMemMapJmp);3624 3625 /*3626 * Check the input, check segment access and adjust address3627 * 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 else3643 {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 CPU3659 * implementation. See FXSAVE/FRSTOR/XSAVE/XRSTOR/++. Using 4 for now as3660 * that's what FXSAVE does on a 10980xe. */3661 && iemMemAreAlignmentChecksEnabled(pVCpu))3662 iemRaiseAlignmentCheckExceptionJmp(pVCpu);3663 else3664 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 restrictions3669 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 # else3676 # error port me3677 # endif3678 )3679 { /* okay */ }3680 else3681 {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 #endif3687 }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 else3710 {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_TLB3719 Assert(!(fAccess & IEM_ACCESS_TYPE_EXEC));3720 3721 /*3722 * Get the TLB entry for this page checking that it has the A & D bits3723 * 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) == 33727 ? IEMTLBE_F_PT_NO_USER : 0;3728 uint64_t const fNoWriteNoDirty = fAccess & IEM_ACCESS_TYPE_WRITE3729 ? IEMTLBE_F_PG_NO_WRITE | IEMTLBE_F_PT_NO_DIRTY3730 | ( (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_STATISTICS3744 if (a_fSafeCall)3745 pVCpu->iem.s.DataTlb.cTlbSafeHits++;3746 else3747 pVCpu->iem.s.DataTlb.cTlbCoreHits++;3748 # endif3749 }3750 else3751 {3752 if (a_fSafeCall)3753 pVCpu->iem.s.DataTlb.cTlbSafeMisses++;3754 else3755 pVCpu->iem.s.DataTlb.cTlbCoreMisses++;3756 3757 /* This page table walking will set A and D bits as required by the3758 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 else3774 {3775 LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - failed to fetch page -> #PF\n", GCPtrMem));3776 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT3777 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 # endif3780 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_BITMAP3795 else3796 ASMBitClear(pVCpu->iem.s.DataTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev));3797 # endif3798 }3799 else3800 {3801 if (a_fSafeCall)3802 pVCpu->iem.s.DataTlb.cTlbSafeGlobalLoads++;3803 else3804 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_BITMAP3809 else3810 ASMBitClear(pVCpu->iem.s.DataTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + 1);3811 # endif3812 }3813 }3814 else3815 {3816 /* If we hit a data breakpoint, we use a dummy TLBE to force all accesses3817 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 else3840 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_RING33850 pTlbe->pbMappingR3 = pbMemFullLoad;3851 # endif3852 }3853 3854 /*3855 * Check the flags and physical revision.3856 * Note! This will revalidate the uTlbPhysRev after a full load. This is3857 * 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_RING33863 pbMem = pTlbe->pbMappingR3;3864 # else3865 pbMem = NULL;3866 # endif3867 else3868 {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_EPT3879 /** @todo TLB: EPT isn't integrated into the TLB stuff, so we don't know whether3880 * 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 # endif3884 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_EPT3892 /** @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 # endif3896 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_RING33904 pbMem = pTlbe->pbMappingR3;3905 # else3906 pbMem = NULL;3907 # endif3908 else3909 {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_RING33917 pTlbe->pbMappingR3 = pbMem;3918 # endif3919 }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 else3927 {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_UNASSIGNED3931 : pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_NO_READ ? VERR_PGM_PHYS_TLB_CATCH_ALL3932 : 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 else3947 {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 else3984 {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_LONGJMP4009 {4010 return iemMemMapJmp<true /*a_fSafeCall*/>(pVCpu, pbUnmapInfo, cbMem, iSegReg, GCPtrMem, fAccess, uAlignCtl);4011 }4012 4013 2579 4014 2580 /** … … 4163 2729 } 4164 2730 } 4165 4166 4167 /*4168 * Instantiate R/W templates.4169 */4170 #define TMPL_MEM_WITH_STACK4171 4172 #define TMPL_MEM_TYPE uint8_t4173 #define TMPL_MEM_FN_SUFF U84174 #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_t4179 #define TMPL_MEM_FN_SUFF U164180 #define TMPL_MEM_FMT_TYPE "%#06x"4181 #define TMPL_MEM_FMT_DESC "word"4182 #include "IEMAllMemRWTmpl.cpp.h"4183 4184 #define TMPL_WITH_PUSH_SREG4185 #define TMPL_MEM_TYPE uint32_t4186 #define TMPL_MEM_FN_SUFF U324187 #define TMPL_MEM_FMT_TYPE "%#010x"4188 #define TMPL_MEM_FMT_DESC "dword"4189 #include "IEMAllMemRWTmpl.cpp.h"4190 #undef TMPL_WITH_PUSH_SREG4191 4192 #define TMPL_MEM_TYPE uint64_t4193 #define TMPL_MEM_FN_SUFF U644194 #define TMPL_MEM_FMT_TYPE "%#018RX64"4195 #define TMPL_MEM_FMT_DESC "qword"4196 #include "IEMAllMemRWTmpl.cpp.h"4197 4198 #undef TMPL_MEM_WITH_STACK4199 4200 #define TMPL_MEM_TYPE uint32_t4201 #define TMPL_MEM_TYPE_ALIGN 04202 #define TMPL_MEM_FN_SUFF U32NoAc4203 #define TMPL_MEM_FMT_TYPE "%#010x"4204 #define TMPL_MEM_FMT_DESC "dword"4205 #include "IEMAllMemRWTmpl.cpp.h"4206 #undef TMPL_WITH_PUSH_SREG4207 4208 #define TMPL_MEM_TYPE uint64_t4209 #define TMPL_MEM_TYPE_ALIGN 04210 #define TMPL_MEM_FN_SUFF U64NoAc4211 #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_t4216 #define TMPL_MEM_TYPE_ALIGN (sizeof(uint64_t) * 2 - 1)4217 #define TMPL_MEM_FN_SUFF U64AlignedU1284218 #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_REF4224 4225 #define TMPL_MEM_TYPE RTFLOAT80U4226 #define TMPL_MEM_TYPE_ALIGN (sizeof(uint64_t) - 1)4227 #define TMPL_MEM_FN_SUFF R804228 #define TMPL_MEM_FMT_TYPE "%.10Rhxs"4229 #define TMPL_MEM_FMT_DESC "tword"4230 #include "IEMAllMemRWTmpl.cpp.h"4231 4232 #define TMPL_MEM_TYPE RTPBCD80U4233 #define TMPL_MEM_TYPE_ALIGN (sizeof(uint64_t) - 1) /** @todo testcase: 80-bit BCD alignment */4234 #define TMPL_MEM_FN_SUFF D804235 #define TMPL_MEM_FMT_TYPE "%.10Rhxs"4236 #define TMPL_MEM_FMT_DESC "tword"4237 #include "IEMAllMemRWTmpl.cpp.h"4238 4239 #define TMPL_MEM_TYPE RTUINT128U4240 #define TMPL_MEM_TYPE_ALIGN (sizeof(RTUINT128U) - 1)4241 #define TMPL_MEM_FN_SUFF U1284242 #define TMPL_MEM_FMT_TYPE "%.16Rhxs"4243 #define TMPL_MEM_FMT_DESC "dqword"4244 #include "IEMAllMemRWTmpl.cpp.h"4245 4246 #define TMPL_MEM_TYPE RTUINT128U4247 #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 U128AlignedSse4250 #define TMPL_MEM_FMT_TYPE "%.16Rhxs"4251 #define TMPL_MEM_FMT_DESC "dqword"4252 #include "IEMAllMemRWTmpl.cpp.h"4253 4254 #define TMPL_MEM_TYPE RTUINT128U4255 #define TMPL_MEM_TYPE_ALIGN 04256 #define TMPL_MEM_FN_SUFF U128NoAc4257 #define TMPL_MEM_FMT_TYPE "%.16Rhxs"4258 #define TMPL_MEM_FMT_DESC "dqword"4259 #include "IEMAllMemRWTmpl.cpp.h"4260 4261 #define TMPL_MEM_TYPE RTUINT256U4262 #define TMPL_MEM_TYPE_ALIGN 04263 #define TMPL_MEM_FN_SUFF U256NoAc4264 #define TMPL_MEM_FMT_TYPE "%.32Rhxs"4265 #define TMPL_MEM_FMT_DESC "qqword"4266 #include "IEMAllMemRWTmpl.cpp.h"4267 4268 #define TMPL_MEM_TYPE RTUINT256U4269 #define TMPL_MEM_TYPE_ALIGN (sizeof(RTUINT256U) - 1)4270 #define TMPL_MEM_MAP_FLAGS_ADD IEM_MEMMAP_F_ALIGN_GP4271 #define TMPL_MEM_FN_SUFF U256AlignedAvx4272 #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 for4283 * 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_NOEXCEPT4287 {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_FUNCTION4304 /**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 for4311 * 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_NOEXCEPT4315 {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 else4329 *pu64Dst = 0;4330 #endif4331 return rc;4332 }4333 #endif4334 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 for4344 * 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_NOEXCEPT4350 {4351 /*4352 * Just like SIDT and SGDT, the LIDT and LGDT instructions are a4353 * 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 in4357 * some cases (search for 386 in bs3CpuBasic2_lidt_lgdt_One). We4358 * don't try emulate this eccentric behavior, because it's not well4359 * 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 else4370 {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 else4381 {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 else4393 {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 for4413 * 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_NOEXCEPT4418 {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_SETJMP4436 /**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 for4442 * 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_LONGJMP4448 {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 #endif4459 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 for4467 * 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_NOEXCEPT4472 {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_SETJMP4492 /**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 for4497 * 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_LONGJMP4502 {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 #endif4515 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 for4525 * 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_NOEXCEPT4529 {4530 /*4531 * The SIDT and SGDT instructions actually stores the data using two4532 * independent writes (see bs3CpuBasic2_sidt_sgdt_One). The instructions4533 * 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_2864541 ? (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 else4545 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 be4562 * direct access or bounce buffered access, so4563 * don't commit register until the commit call4564 * succeeds.4565 * @param pbUnmapInfo Where to store unmap info for4566 * iemMemStackPushCommitSpecial.4567 * @param puNewRsp Where to return the new RSP value. This must be4568 * passed unchanged to4569 * iemMemStackPushCommitSpecial().4570 */4571 VBOXSTRICTRC iemMemStackPushBeginSpecial(PVMCPUCC pVCpu, size_t cbMem, uint32_t cbAlign,4572 void **ppvMem, uint8_t *pbUnmapInfo, uint64_t *puNewRsp) RT_NOEXCEPT4573 {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 by4589 * iemMemStackPushBeginSpecial().4590 */4591 VBOXSTRICTRC iemMemStackPushCommitSpecial(PVMCPUCC pVCpu, uint8_t bUnmapInfo, uint64_t uNewRsp) RT_NOEXCEPT4592 {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 for4611 * iemMemStackPopDoneSpecial.4612 * @param puNewRsp Where to return the new RSP value. This must be4613 * assigned to CPUMCTX::rsp manually some time4614 * after iemMemStackPopDoneSpecial() has been4615 * called.4616 */4617 VBOXSTRICTRC iemMemStackPopBeginSpecial(PVMCPUCC pVCpu, size_t cbMem, uint32_t cbAlign,4618 void const **ppvMem, uint8_t *pbUnmapInfo, uint64_t *puNewRsp) RT_NOEXCEPT4619 {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 of4628 * 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 zero4635 * 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 for4639 * iemMemStackPopDoneSpecial.4640 * @param uCurNewRsp The current uncommitted RSP value. (No need to4641 * return this because all use of this function is4642 * to retrieve a new value and anything we return4643 * 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_NOEXCEPT4647 {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 else4657 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 or4666 * 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 by4673 * iemMemStackPopBeginSpecial() or4674 * iemMemStackPopContinueSpecial().4675 */4676 VBOXSTRICTRC iemMemStackPopDoneSpecial(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT4677 {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 for4689 * 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_NOEXCEPT4693 {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 for4714 * 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_NOEXCEPT4718 {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 for4739 * 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_NOEXCEPT4743 {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 for4764 * 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_NOEXCEPT4768 {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_NOEXCEPT4794 {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.u1Present4806 || (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 else4818 {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 if4830 * 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 else4836 {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 else4845 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) + 84854 <= (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 else4857 {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_NOEXCEPT4877 {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 and4886 * 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_NOEXCEPT4893 {4894 /*4895 * Get the selector table base and calculate the entry address.4896 */4897 RTGCPTR GCPtr = uSel & X86_SEL_LDT4898 ? pVCpu->cpum.GstCtx.ldtr.u64Base4899 : pVCpu->cpum.GstCtx.gdtr.pGdt;4900 GCPtr += uSel & X86_SEL_MASK;4901 4902 /*4903 * ASMAtomicBitSet will assert if the address is misaligned, so do some4904 * ugly stuff to avoid this. This will make sure it's an atomic access4905 * 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 else4920 {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 2731 4938 2732 #undef LOG_GROUP -
trunk/src/VBox/VMM/VMMAll/target-x86/IEMAllHlpFpu-x86.cpp
r108220 r108226 45 45 #include <VBox/vmm/vmcc.h> 46 46 #include <VBox/log.h> 47 #include < VBox/err.h>47 #include <iprt/errcore.h> 48 48 #include <iprt/assert.h> 49 49 #include <iprt/string.h> -
trunk/src/VBox/VMM/VMMAll/target-x86/IEMAllMem-x86.cpp
r108220 r108226 1 1 /* $Id$ */ 2 2 /** @file 3 * IEM - Interpreted Execution Manager - All Contexts.3 * IEM - Interpreted Execution Manager - x86 target, memory. 4 4 */ 5 5 … … 27 27 28 28 29 /** @page pg_iem IEM - Interpreted Execution Manager30 *31 * The interpreted exeuction manager (IEM) is for executing short guest code32 * sequences that are causing too many exits / virtualization traps. It will33 * also be used to interpret single instructions, thus replacing the selective34 * interpreters in EM and IOM.35 *36 * Design goals:37 * - Relatively small footprint, although we favour speed and correctness38 * 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 thought46 * to conflict with speed as the disassembler chews things a bit too much while47 * 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 Instructions54 *55 * On x86 and AMD64 hosts, the FPU instructions are implemented by executing the56 * same or equivalent instructions on the host FPU. To make life easy, we also57 * let the FPU prioritize the unmasked exceptions for us. This however, only58 * works reliably when CR0.NE is set, i.e. when using \#MF instead the IRQ 1359 * for FPU exception delivery, because with CR0.NE=0 there is a window where we60 * can trigger spurious FPU exceptions.61 *62 * The guest FPU state is not loaded into the host CPU and kept there till we63 * leave IEM because the calling conventions have declared an all year open64 * season on much of the FPU state. For instance an innocent looking call to65 * memcpy might end up using a whole bunch of XMM or MM registers if the66 * particular implementation finds it worthwhile.67 *68 *69 * @section sec_iem_logging Logging70 *71 * The IEM code uses the \"IEM\" log group for the main logging. The different72 * 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) : Writes93 * - 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.x110 * - Level 3: Linux.111 */112 113 /* Disabled warning C4505: 'iemRaisePageFaultJmp' : unreferenced local function has been removed */114 #ifdef _MSC_VER115 # pragma warning(disable:4505)116 #endif117 118 119 29 /********************************************************************************************************************************* 120 30 * Header Files * 121 31 *********************************************************************************************************************************/ 122 #define LOG_GROUP LOG_GROUP_IEM32 #define LOG_GROUP LOG_GROUP_IEM_MEM 123 33 #define VMCPU_INCL_CPUM_GST_CTX 124 34 #ifdef IN_RING0 … … 127 37 #include <VBox/vmm/iem.h> 128 38 #include <VBox/vmm/cpum.h> 129 #include <VBox/vmm/pdmapic.h>130 #include <VBox/vmm/pdm.h>131 39 #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_SVM139 # include <VBox/vmm/em.h>140 # include <VBox/vmm/hm_svm.h>141 #endif142 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX143 # include <VBox/vmm/hmvmxinline.h>144 #endif145 #include <VBox/vmm/tm.h>146 40 #include <VBox/vmm/dbgf.h> 147 #include <VBox/vmm/dbgftrace.h>148 41 #include "IEMInternal.h" 149 42 #include <VBox/vmm/vmcc.h> 150 43 #include <VBox/log.h> 151 44 #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 #endif160 45 #include <iprt/assert.h> 161 46 #include <iprt/string.h> … … 163 48 164 49 #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 * 2268 55 * @{ 2269 56 */ 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 code2275 * 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_NOEXCEPT2284 {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.u32Limit2291 || IEM_IS_64BIT_CODE(pVCpu) /* no CS limit checks in 64-bit mode */))2292 pVCpu->cpum.GstCtx.rip = uNewIp;2293 else2294 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 else2307 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 else2319 return iemRaiseGeneralProtectionFault0(pVCpu);2320 break;2321 }2322 2323 IEM_NOT_REACHED_DEFAULT_CASE_RET();2324 }2325 2326 #ifndef IEM_WITH_CODE_TLB2327 /* Flush the prefetch buffer. */2328 pVCpu->iem.s.cbOpcode = cbInstr;2329 #endif2330 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 code2342 * 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_NOEXCEPT2350 {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.u32Limit2355 || IEM_IS_64BIT_CODE(pVCpu) /* no limit checking in 64-bit mode */))2356 pVCpu->cpum.GstCtx.rip = uNewIp;2357 else2358 return iemRaiseGeneralProtectionFault0(pVCpu);2359 2360 #ifndef IEM_WITH_CODE_TLB2361 /* Flush the prefetch buffer. */2362 pVCpu->iem.s.cbOpcode = IEM_GET_INSTR_LEN(pVCpu);2363 #endif2364 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 code2376 * 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_NOEXCEPT2386 {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 else2395 return iemRaiseGeneralProtectionFault0(pVCpu);2396 }2397 else2398 {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 else2405 return iemRaiseGeneralProtectionFault0(pVCpu);2406 }2407 2408 #ifndef IEM_WITH_CODE_TLB2409 /* Flush the prefetch buffer. */2410 pVCpu->iem.s.cbOpcode = IEM_GET_INSTR_LEN(pVCpu);2411 #endif2412 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_GROUP2428 #define LOG_GROUP LOG_GROUP_IEM_MEM2429 57 2430 58 /** … … 2612 240 } 2613 241 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 == pvMem2628 && (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 == pvMem2631 && (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 == pvMem2634 && (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 #endif2639 242 2640 243 /** … … 2667 270 2668 271 /** 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_RING32682 Assert(!fPostponeFail);2683 RT_NOREF_PV(fPostponeFail);2684 #endif2685 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 return2699 * 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_RING32726 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 #endif2737 else2738 {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 else2757 {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_RING32781 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 #endif2792 else2793 {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_RING32803 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 else2812 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 #endif2817 else2818 {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 else2827 {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 else2840 {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 else2850 {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 #endif2872 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 272 * Helper for iemMemMap, iemMemMapJmp and iemMemBounceBufferMapCrossPage. 273 * @todo duplicated 2885 274 */ 2886 275 DECL_FORCE_INLINE(uint32_t) … … 2892 281 return DBGFBpCheckDataRead(pVM, pVCpu, GCPtrMem, (uint32_t)cbMem, fSysAccess); 2893 282 } 2894 2895 2896 /**2897 * iemMemMap worker that deals with a request crossing pages.2898 */2899 static VBOXSTRICTRC2900 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 else2933 {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 partial2945 * 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 else2966 {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 else2981 {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 else2989 {2990 LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysFirst=%RGp rcStrict=%Rrc (!!)\n",2991 GCPhysFirst, VBOXSTRICTRC_VAL(rcStrict) ));2992 return rcStrict;2993 }2994 }2995 else2996 {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 else3008 {3009 LogEx(LOG_GROUP_IEM,3010 ("iemMemBounceBufferMapPhys: PGMPhysSimpleReadGCPhys GCPhysSecond=%RGp rc=%Rrc (!!)\n", GCPhysSecond, rc));3011 return rc;3012 }3013 }3014 else3015 {3016 LogEx(LOG_GROUP_IEM,3017 ("iemMemBounceBufferMapPhys: PGMPhysSimpleReadGCPhys GCPhysFirst=%RGp rc=%Rrc (!!)\n", GCPhysFirst, rc));3018 return rc;3019 }3020 }3021 }3022 #ifdef VBOX_STRICT3023 else3024 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 #endif3028 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_WRITE3061 && rcMap != VERR_PGM_PHYS_TLB_CATCH_ALL3062 && 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 partial3071 * 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 else3079 {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 else3089 {3090 LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysFirst=%RGp rcStrict=%Rrc (!!)\n",3091 GCPhysFirst, VBOXSTRICTRC_VAL(rcStrict) ));3092 return rcStrict;3093 }3094 }3095 else3096 {3097 rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), pbBuf, GCPhysFirst, cbMem);3098 if (RT_SUCCESS(rc))3099 { /* likely */ }3100 else3101 {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_STRICT3110 else3111 memset(pbBuf, 0xcc, cbMem);3112 #endif3113 #ifdef VBOX_STRICT3114 if (cbMem < sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab))3115 memset(pbBuf + cbMem, 0xaa, sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab) - cbMem);3116 #endif3117 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 283 3137 284 … … 3328 475 { /* likely */ } 3329 476 else 3330 IEMTlbInvalidateAllPhysicalSlow(pVCpu);477 iemTlbInvalidateAllPhysicalSlow(pVCpu); 3331 478 pTlbe->pbMappingR3 = NULL; 3332 479 pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK; … … 3509 656 3510 657 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_NOEXCEPT3522 {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_NOEXCEPT3555 {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 658 } 3572 659 … … 4011 1098 } 4012 1099 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_LONGJMP4022 {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_LONGJMP4054 {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_LONGJMP4062 {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_LONGJMP4070 {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_LONGJMP4078 {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_NOEXCEPT4086 {4087 Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == IEM_ACCESS_TYPE_WRITE);4088 iemMemRollbackAndUnmap(pVCpu, bUnmapInfo);4089 }4090 4091 1100 #endif /* IEM_WITH_SETJMP */ 4092 4093 #ifndef IN_RING34094 /**4095 * Commits the guest memory if bounce buffered and unmaps it, if any bounce4096 * 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 will4099 * return to ring-3 immediately afterwards and do the postponed writes there.4100 *4101 * @returns VBox status code (no strict statuses). Caller must check4102 * 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_NOEXCEPT4108 {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 #endif4134 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_NOEXCEPT4144 {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 1101 4166 1102 … … 4174 1110 #define TMPL_MEM_FMT_TYPE "%#04x" 4175 1111 #define TMPL_MEM_FMT_DESC "byte" 4176 #include "IEMAllMemRWTmpl .cpp.h"1112 #include "IEMAllMemRWTmpl-x86.cpp.h" 4177 1113 4178 1114 #define TMPL_MEM_TYPE uint16_t … … 4180 1116 #define TMPL_MEM_FMT_TYPE "%#06x" 4181 1117 #define TMPL_MEM_FMT_DESC "word" 4182 #include "IEMAllMemRWTmpl .cpp.h"1118 #include "IEMAllMemRWTmpl-x86.cpp.h" 4183 1119 4184 1120 #define TMPL_WITH_PUSH_SREG … … 4187 1123 #define TMPL_MEM_FMT_TYPE "%#010x" 4188 1124 #define TMPL_MEM_FMT_DESC "dword" 4189 #include "IEMAllMemRWTmpl .cpp.h"1125 #include "IEMAllMemRWTmpl-x86.cpp.h" 4190 1126 #undef TMPL_WITH_PUSH_SREG 4191 1127 … … 4194 1130 #define TMPL_MEM_FMT_TYPE "%#018RX64" 4195 1131 #define TMPL_MEM_FMT_DESC "qword" 4196 #include "IEMAllMemRWTmpl .cpp.h"1132 #include "IEMAllMemRWTmpl-x86.cpp.h" 4197 1133 4198 1134 #undef TMPL_MEM_WITH_STACK … … 4203 1139 #define TMPL_MEM_FMT_TYPE "%#010x" 4204 1140 #define TMPL_MEM_FMT_DESC "dword" 4205 #include "IEMAllMemRWTmpl .cpp.h"1141 #include "IEMAllMemRWTmpl-x86.cpp.h" 4206 1142 #undef TMPL_WITH_PUSH_SREG 4207 1143 … … 4211 1147 #define TMPL_MEM_FMT_TYPE "%#018RX64" 4212 1148 #define TMPL_MEM_FMT_DESC "qword" 4213 #include "IEMAllMemRWTmpl .cpp.h"1149 #include "IEMAllMemRWTmpl-x86.cpp.h" 4214 1150 4215 1151 #define TMPL_MEM_TYPE uint64_t … … 4218 1154 #define TMPL_MEM_FMT_TYPE "%#018RX64" 4219 1155 #define TMPL_MEM_FMT_DESC "qword" 4220 #include "IEMAllMemRWTmpl .cpp.h"1156 #include "IEMAllMemRWTmpl-x86.cpp.h" 4221 1157 4222 1158 /* See IEMAllMemRWTmplInline.cpp.h */ … … 4228 1164 #define TMPL_MEM_FMT_TYPE "%.10Rhxs" 4229 1165 #define TMPL_MEM_FMT_DESC "tword" 4230 #include "IEMAllMemRWTmpl .cpp.h"1166 #include "IEMAllMemRWTmpl-x86.cpp.h" 4231 1167 4232 1168 #define TMPL_MEM_TYPE RTPBCD80U … … 4235 1171 #define TMPL_MEM_FMT_TYPE "%.10Rhxs" 4236 1172 #define TMPL_MEM_FMT_DESC "tword" 4237 #include "IEMAllMemRWTmpl .cpp.h"1173 #include "IEMAllMemRWTmpl-x86.cpp.h" 4238 1174 4239 1175 #define TMPL_MEM_TYPE RTUINT128U … … 4242 1178 #define TMPL_MEM_FMT_TYPE "%.16Rhxs" 4243 1179 #define TMPL_MEM_FMT_DESC "dqword" 4244 #include "IEMAllMemRWTmpl .cpp.h"1180 #include "IEMAllMemRWTmpl-x86.cpp.h" 4245 1181 4246 1182 #define TMPL_MEM_TYPE RTUINT128U … … 4250 1186 #define TMPL_MEM_FMT_TYPE "%.16Rhxs" 4251 1187 #define TMPL_MEM_FMT_DESC "dqword" 4252 #include "IEMAllMemRWTmpl .cpp.h"1188 #include "IEMAllMemRWTmpl-x86.cpp.h" 4253 1189 4254 1190 #define TMPL_MEM_TYPE RTUINT128U … … 4257 1193 #define TMPL_MEM_FMT_TYPE "%.16Rhxs" 4258 1194 #define TMPL_MEM_FMT_DESC "dqword" 4259 #include "IEMAllMemRWTmpl .cpp.h"1195 #include "IEMAllMemRWTmpl-x86.cpp.h" 4260 1196 4261 1197 #define TMPL_MEM_TYPE RTUINT256U … … 4264 1200 #define TMPL_MEM_FMT_TYPE "%.32Rhxs" 4265 1201 #define TMPL_MEM_FMT_DESC "qqword" 4266 #include "IEMAllMemRWTmpl .cpp.h"1202 #include "IEMAllMemRWTmpl-x86.cpp.h" 4267 1203 4268 1204 #define TMPL_MEM_TYPE RTUINT256U … … 4272 1208 #define TMPL_MEM_FMT_TYPE "%.32Rhxs" 4273 1209 #define TMPL_MEM_FMT_DESC "qqword" 4274 #include "IEMAllMemRWTmpl.cpp.h" 1210 #include "IEMAllMemRWTmpl-x86.cpp.h" 1211 4275 1212 4276 1213 /** … … 4935 1872 } 4936 1873 4937 4938 #undef LOG_GROUP4939 #define LOG_GROUP LOG_GROUP_IEM4940 4941 1874 /** @} */ 4942 1875 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 immediate4956 * following the effective address opcode bytes4957 * (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_NOEXCEPT4962 {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 else4982 {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 else5009 {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 else5017 {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 else5059 {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 else5104 {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 else5114 {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 else5189 u64EffAddr += pVCpu->cpum.GstCtx.r13;5190 }5191 else5192 {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 else5232 {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_SETJMP5244 /**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 immediate5255 * following the effective address opcode bytes5256 * (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_LONGJMP5260 {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 else5280 {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 else5315 {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 else5357 {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 else5411 {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 else5486 u64EffAddr += pVCpu->cpum.GstCtx.r13;5487 }5488 else5489 {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 version5540 * 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 immediate5548 * following the effective address opcode bytes5549 * (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) and5553 * SIB byte (bits 39:32).5554 */5555 VBOXSTRICTRC iemOpHlpCalcRmEffAddrEx(PVMCPUCC pVCpu, uint8_t bRm, uint32_t cbImmAndRspOffset, PRTGCPTR pGCPtrEff, uint64_t *puInfo) RT_NOEXCEPT5556 {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 else5580 {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 else5608 {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 else5619 {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 else5663 {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 else5711 {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 else5722 {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 else5799 u64EffAddr += pVCpu->cpum.GstCtx.r13;5800 }5801 else5802 {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 else5845 {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_ENABLED5860 /**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 in5865 * our debug context. When clear, we assume IEMCPU holds5866 * 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_NOEXCEPT5872 {5873 # ifdef IN_RING35874 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 else5883 {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 else5893 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 else5920 # endif5921 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_VMX5929 /**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_NOEXCEPT5938 {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 else5986 {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_SETJMP6016 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 #else6028 uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);6029 VBOXSTRICTRC rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);6030 #endif6031 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 DEBUG6043 // AssertMsg(IEM_GET_INSTR_LEN(pVCpu) == cbInstr || rcStrict != VINF_SUCCESS, ("%u %u\n", IEM_GET_INSTR_LEN(pVCpu), cbInstr));6044 //#endif6045 6046 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX6047 /*6048 * Perform any VMX nested-guest instruction boundary actions.6049 *6050 * If any of these causes a VM-exit, we must skip executing the next6051 * instruction (would run into stale page tables). A VM-exit makes sure6052 * there is no interrupt-inhibition, so that should ensure we don't go6053 * to try execute the next instruction. Clearing fExecuteInhibit is6054 * 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_TIMER6057 | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW)6058 || rcStrict != VINF_SUCCESS)6059 { /* likely */ }6060 else6061 rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);6062 #endif6063 6064 /* Execute the next instruction as well if a cli, pop ss or6065 mov ss, Gr has just completed successfully. */6066 if ( fExecuteInhibit6067 && rcStrict == VINF_SUCCESS6068 && 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_ENABLED6074 iemLogCurInstr(pVCpu, false, pszFunction);6075 #endif6076 #ifdef IEM_WITH_SETJMP6077 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 #else6088 IEM_OPCODE_GET_FIRST_U8(&b);6089 rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);6090 #endif6091 if (rcStrict == VINF_SUCCESS)6092 {6093 pVCpu->iem.s.cInstructions++;6094 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX6095 if (!VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER6096 | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW))6097 { /* likely */ }6098 else6099 rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);6100 #endif6101 }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_ENABLED6138 iemLogCurInstr(pVCpu, true, "IEMExecOne");6139 #endif6140 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 ( cbOpcodeBytes6162 && pVCpu->cpum.GstCtx.rip == OpcodeBytesPC)6163 {6164 iemInitDecoder(pVCpu, 0 /*fExecOpts*/);6165 #ifdef IEM_WITH_CODE_TLB6166 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 #else6173 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 #endif6176 rcStrict = VINF_SUCCESS;6177 }6178 else6179 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 ( cbOpcodeBytes6206 && pVCpu->cpum.GstCtx.rip == OpcodeBytesPC)6207 {6208 iemInitDecoder(pVCpu, IEM_F_BYPASS_HANDLERS);6209 #ifdef IEM_WITH_CODE_TLB6210 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 #else6217 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 #endif6220 rcStrict = VINF_SUCCESS;6221 }6222 else6223 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-lock6235 * detection enabled.6236 *6237 * This will cause the interpreter to disregard the lock prefix and implicit6238 * 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 to6263 * 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 else6282 {6283 Assert(CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)));6284 fIntrEnabled = CPUMIsGuestSvmPhysIntrEnabled(pVCpu, IEM_GET_CTX(pVCpu));6285 }6286 }6287 #else6288 bool fIntrEnabled = pVCpu->cpum.GstCtx.eflags.Bits.u1IF;6289 #endif6290 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_SUCCESS6306 && rcStrict != VINF_IEM_RAISED_XCPT)6307 return iemExecStatusCodeFiddling(pVCpu, rcStrict);6308 #else6309 NOREF(rcStrict);6310 #endif6311 }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 that6328 * possible here? For now we assert it is indeed only an interrupt. */6329 if (!TRPMHasTrap(pVCpu))6330 { /* likely */ }6331 else6332 {6333 VBOXSTRICTRC rcStrict = iemExecInjectPendingTrap(pVCpu);6334 if (RT_LIKELY(rcStrict == VINF_SUCCESS))6335 { /*likely */ }6336 else6337 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_SETJMP6347 pVCpu->iem.s.cActiveMappings = 0; /** @todo wtf? */6348 IEM_TRY_SETJMP(pVCpu, rcStrict)6349 #endif6350 {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_ENABLED6362 iemLogCurInstr(pVCpu, true, "IEMExecLots");6363 #endif6364 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_STRICT6371 CPUMAssertGuestRFlagsCookie(pVM, pVCpu);6372 #endif6373 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_VMX6379 /* 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_TIMER6382 | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW)))6383 { /* likely */ }6384 else6385 {6386 rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);6387 if (RT_LIKELY(rcStrict == VINF_SUCCESS))6388 fCpu = pVCpu->fLocalForcedActions;6389 else6390 {6391 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);6392 break;6393 }6394 }6395 #endif6396 if (RT_LIKELY(pVCpu->iem.s.rcPassUp == VINF_SUCCESS))6397 {6398 #ifndef VBOX_WITH_NESTED_HWVIRT_VMX6399 uint64_t fCpu = pVCpu->fLocalForcedActions;6400 #endif6401 fCpu &= VMCPU_FF_ALL_MASK & ~( VMCPU_FF_PGM_SYNC_CR36402 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL6403 | VMCPU_FF_TLB_FLUSH6404 | VMCPU_FF_UNHALT );6405 6406 if (RT_LIKELY( ( !fCpu6407 || ( !(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) != 06415 || !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_SETJMP6433 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 # endif6440 pVCpu->iem.s.cLongJumps++;6441 }6442 IEM_CATCH_LONGJMP_END(pVCpu);6443 #endif6444 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 else6452 {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 fetching6459 * code as part of instruction execution, we need this to fix-up VINF_SVM_VMEXIT.6460 */6461 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);6462 #endif6463 }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 cMaxInstructionsWithoutExits6486 * 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_SETJMP6510 pVCpu->iem.s.cActiveMappings = 0; /** @todo wtf?!? */6511 IEM_TRY_SETJMP(pVCpu, rcStrict)6512 #endif6513 {6514 #ifdef IN_RING06515 bool const fCheckPreemptionPending = !RTThreadPreemptIsPossible() || !RTThreadPreemptIsEnabled(NIL_RTTHREAD);6516 #endif6517 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_ENABLED6529 iemLogCurInstr(pVCpu, true, "IEMExecForExits");6530 #endif6531 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.cPotentialExits6541 && 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_VMX6557 /* 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_TIMER6560 | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW)))6561 { /* likely */ }6562 else6563 {6564 rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);6565 if (RT_LIKELY(rcStrict == VINF_SUCCESS))6566 fCpu = pVCpu->fLocalForcedActions;6567 else6568 {6569 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);6570 break;6571 }6572 }6573 #endif6574 if (RT_LIKELY(pVCpu->iem.s.rcPassUp == VINF_SUCCESS))6575 {6576 #ifndef VBOX_WITH_NESTED_HWVIRT_VMX6577 uint64_t fCpu = pVCpu->fLocalForcedActions;6578 #endif6579 fCpu &= VMCPU_FF_ALL_MASK & ~( VMCPU_FF_PGM_SYNC_CR36580 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL6581 | VMCPU_FF_TLB_FLUSH6582 | VMCPU_FF_UNHALT );6583 if (RT_LIKELY( ( ( !fCpu6584 || ( !(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_RING06594 if ( !fCheckPreemptionPending6595 || !RTThreadPreemptIsPending(NIL_RTTHREAD))6596 #endif6597 {6598 Assert(pVCpu->iem.s.cActiveMappings == 0);6599 iemReInitDecoder(pVCpu);6600 continue;6601 }6602 #ifdef IN_RING06603 rcStrict = VINF_EM_RAW_INTERRUPT;6604 break;6605 #endif6606 }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_SETJMP6620 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 #endif6628 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 else6636 {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 fetching6643 * code as part of instruction execution, we need this to fix-up VINF_SVM_VMEXIT.6644 */6645 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);6646 #endif6647 }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), software6669 * 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 for6673 * 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_ENABLED6681 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "IEMInjectTrap: %x %d %x %llx",6682 u8TrapNo, enmType, uErrCode, uCr2);6683 #endif6684 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_TASKSWITCH6741 IEM_RETURN_ASPECT_NOT_IMPLEMENTED_LOG(("Event injection\n"));6742 #else6743 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 handle6753 * ICEBP \#DB injection as a special case. */6754 VBOXSTRICTRC rcStrict = IEMInjectTrap(pVCpu, u8TrapNo, enmType, uErrCode, uCr2, cbInstr);6755 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM6756 if (rcStrict == VINF_SVM_VMEXIT)6757 rcStrict = VINF_SUCCESS;6758 #endif6759 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX6760 if (rcStrict == VINF_VMX_VMEXIT)6761 rcStrict = VINF_SUCCESS;6762 #endif6763 /** @todo Are there any other codes that imply the event was successfully6764 * delivered to the guest? See @bugref{6607}. */6765 if ( rcStrict == VINF_SUCCESS6766 || rcStrict == VINF_IEM_RAISED_XCPT)6767 TRPMResetTrap(pVCpu);6768 6769 return rcStrict;6770 #endif6771 }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_RING36788 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 merge6795 * 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 calling6798 * 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 merge6827 * 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 calling6830 * 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_FIRST6843 && rcStrict <= VINF_EM_LAST))6844 {6845 if (RT_LIKELY( rcStrictCommit >= VINF_EM_FIRST6846 && 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 27 27 28 28 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 116 33 #endif 117 34 118 119 /*********************************************************************************************************************************120 * Header Files *121 *********************************************************************************************************************************/122 #define LOG_GROUP LOG_GROUP_IEM123 #define VMCPU_INCL_CPUM_GST_CTX124 #ifdef IN_RING0125 # define VBOX_VMM_TARGET_X86126 #endif127 #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_SVM139 # include <VBox/vmm/em.h>140 # include <VBox/vmm/hm_svm.h>141 #endif142 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX143 # include <VBox/vmm/hmvmxinline.h>144 #endif145 #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 #endif160 #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 IEMXCPTCLASS174 {175 IEMXCPTCLASS_BENIGN,176 IEMXCPTCLASS_CONTRIBUTORY,177 IEMXCPTCLASS_PAGE_FAULT,178 IEMXCPTCLASS_DOUBLE_FAULT179 } 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 #endif191 192 193 /**194 * Calculates IEM_F_BRK_PENDING_XXX (IEM_F_PENDING_BRK_MASK) flags, slow code195 * path.196 *197 * This will also invalidate TLB entries for any pages with active data198 * breakpoints on them.199 *200 * @returns IEM_F_BRK_PENDING_XXX or zero.201 * @param pVCpu The cross context virtual CPU structure of the202 * 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 TLB214 * load for as long as the breakpoint is enabled.215 */216 #ifdef IEM_WITH_DATA_TLB217 # 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 #else228 # define INVALID_TLB_ENTRY_FOR_BP(a_uValue) do { } while (0)229 #endif230 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_TLB259 IEM_CTX_IMPORT_NORET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);260 #endif261 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 the291 * calling thread.292 * @param fExecOpts Optional execution flags:293 * - IEM_F_BYPASS_HANDLERS294 * - IEM_F_X86_DISREGARD_LOCK295 */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 else322 {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_TLB336 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_BUF340 pVCpu->iem.s.offOpcode = 0;341 # endif342 # ifdef VBOX_STRICT343 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 # endif348 #else349 pVCpu->iem.s.offOpcode = 0;350 pVCpu->iem.s.cbOpcode = 0;351 #endif352 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_ENABLED358 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 #endif371 }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 else406 {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_TLB420 if (pVCpu->iem.s.pbInstrBuf)421 {422 uint64_t off = (enmMode == IEMMODE_64BIT423 ? pVCpu->cpum.GstCtx.rip424 : 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 else433 pVCpu->iem.s.cbInstrBuf = pVCpu->iem.s.cbInstrBufTotal;434 }435 else436 {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 else446 {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_STRICT452 pVCpu->iem.s.GCPhysInstrBuf = NIL_RTGCPHYS;453 # endif454 }455 # ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF456 pVCpu->iem.s.offOpcode = 0;457 # endif458 #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_ENABLED469 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 #endif482 }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 the491 * calling thread.492 * @param fExecOpts Optional execution flags:493 * - IEM_F_BYPASS_HANDLERS494 * - IEM_F_X86_DISREGARD_LOCK495 */496 static VBOXSTRICTRC iemInitDecoderAndPrefetchOpcodes(PVMCPUCC pVCpu, uint32_t fExecOpts) RT_NOEXCEPT497 {498 iemInitDecoder(pVCpu, fExecOpts);499 500 #ifndef IEM_WITH_CODE_TLB501 /*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 fetch507 * all relevant bytes from the first page, as it ASSUMES it's only ever508 * called for dealing with CS.LIM, page crossing and instructions that509 * 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 else520 return iemRaiseGeneralProtectionFault0(pVCpu);521 }522 else523 {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 else529 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 else547 {548 Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - rc=%Rrc\n", GCPtrPC, rc));549 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT550 /** @todo This isn't quite right yet, as PGM_GST_SLAT_NAME_EPT(Walk) doesn't551 * 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 # endif555 return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, rc);556 }557 #if 0558 if ((WalkFast.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3) { /* likely */ }559 else560 {561 Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - supervisor page\n", GCPtrPC));562 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT563 /** @todo this is completely wrong for EPT. WalkFast.fFailed is always zero here!*/564 # error completely wrong565 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 # endif568 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 else572 {573 Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - NX\n", GCPtrPC));574 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT575 /** @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 # endif580 return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);581 }582 #else583 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 #endif586 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 else609 {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 else618 {619 rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), pVCpu->iem.s.abOpcode, GCPhys, cbToTryRead);620 if (RT_SUCCESS(rc))621 { /* likely */ }622 else623 {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 35 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) 36 636 37 /** 637 38 * Helper for doing large page accounting at TLB load time. … … 665 66 RT_NOREF_PV(pVCpu); 666 67 } 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 780 69 781 70 /** @todo graduate this to cdefs.h or asm-mem.h. */ … … 1165 454 #endif /* defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) */ 1166 455 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 3160 3160 /** @name Memory access. 3161 3161 * @{ */ 3162 VBOXSTRICTRC iemMemBounceBufferMapCrossPage(PVMCPUCC pVCpu, int iMemMap, void **ppvMem, uint8_t *pbUnmapInfo, 3163 size_t cbMem, RTGCPTR GCPtrFirst, uint32_t fAccess) RT_NOEXCEPT; 3164 VBOXSTRICTRC iemMemBounceBufferMapPhys(PVMCPUCC pVCpu, unsigned iMemMap, void **ppvMem, uint8_t *pbUnmapInfo, size_t cbMem, 3165 RTGCPHYS GCPhysFirst, uint32_t fAccess, VBOXSTRICTRC rcMap) RT_NOEXCEPT; 3162 3166 VBOXSTRICTRC iemMemCommitAndUnmap(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT; 3163 3167 #ifndef IN_RING3 … … 3175 3179 void iemMemRollbackAndUnmapWoSafe(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT; 3176 3180 #endif 3181 3182 void iemTlbInvalidateAllPhysicalSlow(PVMCPUCC pVCpu) RT_NOEXCEPT; 3177 3183 /** @} */ 3178 3184
Note:
See TracChangeset
for help on using the changeset viewer.