Changeset 102720 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Dec 28, 2023 12:28:00 AM (13 months ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompiler.cpp
r102717 r102720 6796 6796 if (idxStackSlot < IEMNATIVE_FRAME_VAR_SLOTS) 6797 6797 { 6798 Assert(fInitialized); 6798 6799 int32_t const offDispBp = iemNativeStackCalcBpDisp(idxStackSlot); 6799 6800 switch (pReNative->Core.aVars[idxVar].cbVar) … … 10894 10895 off = iemNativeRegMoveAndFreeAndFlushAtCall(pReNative, off, 0 /* vacate all non-volatile regs */); 10895 10896 10897 /* The bUnmapInfo variable will get a register in the tlb-hit code path, 10898 while the tlb-miss codepath will temporarily put it on the stack. 10899 Set the the type to stack here so we don't need to do it twice below. */ 10900 iemNativeVarSetKindToStack(pReNative, idxVarUnmapInfo); 10901 10896 10902 /* 10897 10903 * Define labels and allocate the result register (trying for the return … … 10908 10914 * First we try to go via the TLB. 10909 10915 */ 10910 #if defined(RT_ARCH_AMD64) && 0 /* untested code sketch */ 10911 uint8_t const idxRegPtr = iemNativeVarRegisterAcquire(pReNative, idxVarGCPtrMem, &off, 10912 true /*fInitialized*/, IEMNATIVE_CALL_ARG2_GREG); 10913 uint8_t const idxRegSegBase = iSegReg == UINT8_MAX ? UINT8_MAX 10914 : iemNativeRegAllocTmpForGuestReg(pReNative, &off, IEMNATIVEGSTREG_SEG_BASE(iSegReg)); 10915 uint8_t const idxRegSegLimit = iSegReg == UINT8_MAX && (pReNative->fExec & IEM_F_MODE_CPUMODE_MASK) != IEMMODE_64BIT 10916 ? UINT8_MAX 10917 : iemNativeRegAllocTmpForGuestReg(pReNative, &off, IEMNATIVEGSTREG_SEG_LIMIT(iSegReg)); 10918 uint8_t const idxRegSegAttrib = iSegReg == UINT8_MAX && (pReNative->fExec & IEM_F_MODE_CPUMODE_MASK) != IEMMODE_64BIT 10919 ? UINT8_MAX 10920 : iemNativeRegAllocTmpForGuestReg(pReNative, &off, IEMNATIVEGSTREG_SEG_ATTRIB(iSegReg)); 10921 uint8_t const idxReg1 = iemNativeRegAllocTmp(pReNative, &off); 10922 uint8_t const idxReg2 = iemNativeRegAllocTmp(pReNative, &off); 10923 uint8_t * const pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 256); 10916 #if defined(RT_ARCH_AMD64) && 1 10917 /* Immediate addresses are a pain if they wrap around the 32-bit space, so 10918 always fall back for those. In 64-bit mode this is less like. */ 10919 if ( pReNative->Core.aVars[idxVarGCPtrMem].enmKind != kIemNativeVarKind_Immediate 10920 || (uint64_t)((uint64_t)UINT32_MAX - pReNative->Core.aVars[idxVarGCPtrMem].u.uValue) <= (uint32_t)UINT32_MAX) 10921 { 10922 uint8_t const idxRegPtr = pReNative->Core.aVars[idxVarGCPtrMem].enmKind != kIemNativeVarKind_Immediate 10923 ? iemNativeVarRegisterAcquire(pReNative, idxVarGCPtrMem, &off, 10924 true /*fInitialized*/, IEMNATIVE_CALL_ARG2_GREG) 10925 : UINT8_MAX; 10926 uint64_t const uAbsPtr = pReNative->Core.aVars[idxVarGCPtrMem].enmKind != kIemNativeVarKind_Immediate 10927 ? UINT32_MAX 10928 : pReNative->Core.aVars[idxVarGCPtrMem].u.uValue; 10929 uint8_t const idxRegSegBase = iSegReg == UINT8_MAX ? UINT8_MAX 10930 : iemNativeRegAllocTmpForGuestReg(pReNative, &off, IEMNATIVEGSTREG_SEG_BASE(iSegReg)); 10931 uint8_t const idxRegSegLimit = iSegReg == UINT8_MAX && (pReNative->fExec & IEM_F_MODE_CPUMODE_MASK) != IEMMODE_64BIT 10932 ? UINT8_MAX 10933 : iemNativeRegAllocTmpForGuestReg(pReNative, &off, IEMNATIVEGSTREG_SEG_LIMIT(iSegReg)); 10934 uint8_t const idxRegSegAttrib = iSegReg == UINT8_MAX && (pReNative->fExec & IEM_F_MODE_CPUMODE_MASK) != IEMMODE_64BIT 10935 ? UINT8_MAX 10936 : iemNativeRegAllocTmpForGuestReg(pReNative, &off, IEMNATIVEGSTREG_SEG_ATTRIB(iSegReg)); 10937 uint8_t const idxReg1 = iemNativeRegAllocTmp(pReNative, &off); 10938 uint8_t const idxReg2 = iemNativeRegAllocTmp(pReNative, &off); 10939 uint8_t * const pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 256); 10940 10941 /* 10942 * 1. Segmentation. 10943 * 10944 * 1a. Check segment limit and attributes if non-flat 32-bit code. This is complicated. 10945 */ 10946 if (iSegReg != UINT8_MAX && (pReNative->fExec & IEM_F_MODE_CPUMODE_MASK) != IEMMODE_64BIT) 10947 { 10948 /* If we're accessing more than one byte, put the last address we'll be 10949 accessing in idxReg2 (64-bit). */ 10950 if (cbMem > 1 && idxRegPtr != UINT8_MAX) 10951 { 10952 # if 1 10953 Assert(cbMem - 1 <= 127); 10954 /* mov reg2, regptr */ 10955 off = iemNativeEmitLoadGprFromGpr32Ex(pbCodeBuf, off, idxReg2, idxRegPtr); 10956 /* add reg2, cbMem-1 */ 10957 off = iemNativeEmitAddGpr32Imm8Ex(pbCodeBuf, off, idxReg2, cbMem - 1); 10958 # else 10959 /* mov reg2, cbMem-1 */ 10960 off = iemNativeEmitLoadGpr32ImmEx(pbCodeBuf, off, idxReg2, cbMem - 1); 10961 /* add reg2, regptr */ 10962 off = iemNativeEmitAddTwoGprsEx(pbCodeBuf, off, idxReg2, idxRegPtr); 10963 # endif 10964 } 10965 10966 /* Check that we've got a segment loaded and that it allows the access. 10967 For write access this means a writable data segment. 10968 For read-only accesses this means a readable code segment or any data segment. */ 10969 if (fAccess & IEM_ACCESS_TYPE_WRITE) 10970 { 10971 uint32_t const fMustBe1 = X86DESCATTR_P | X86DESCATTR_DT | X86_SEL_TYPE_WRITE; 10972 uint32_t const fMustBe0 = X86DESCATTR_UNUSABLE | X86_SEL_TYPE_CODE; 10973 /* mov reg1, must1|must0 */ 10974 off = iemNativeEmitLoadGpr32ImmEx(pbCodeBuf, off, idxReg1, fMustBe1 | fMustBe0); 10975 /* and reg1, segattrs */ 10976 off = iemNativeEmitAndGpr32ByGpr32Ex(pbCodeBuf, off, idxReg1, idxRegSegAttrib); 10977 /* cmp reg1, must1 */ 10978 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxReg1, fMustBe1); 10979 /* jne tlbmiss */ 10980 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_ne); 10981 } 10982 else 10983 { 10984 /* U | !P |!DT |!CD | RW | 10985 16 | 8 | 4 | 3 | 1 | 10986 ------------------------------- 10987 0 | 0 | 0 | 0 | 0 | execute-only code segment. - must be excluded 10988 0 | 0 | 0 | 0 | 1 | execute-read code segment. 10989 0 | 0 | 0 | 1 | 0 | read-only data segment. 10990 0 | 0 | 0 | 1 | 1 | read-write data segment. - last valid combination 10991 */ 10992 /* mov reg1, relevant attributes */ 10993 off = iemNativeEmitLoadGpr32ImmEx(pbCodeBuf, off, idxReg1, 10994 X86DESCATTR_UNUSABLE | X86DESCATTR_P | X86DESCATTR_DT 10995 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE); 10996 /* and reg1, segattrs */ 10997 off = iemNativeEmitAndGpr32ByGpr32Ex(pbCodeBuf, off, idxReg1, idxRegSegAttrib); 10998 /* xor reg1, X86DESCATTR_P | X86DESCATTR_DT | X86_SEL_TYPE_CODE ; place C=1 RW=0 at the bottom & limit the range. 10999 ; EO-code=0, ER-code=2, RO-data=8, RW-data=10 */ 11000 off = iemNativeEmitXorGpr32ByImmEx(pbCodeBuf, off, idxReg1, X86DESCATTR_P | X86DESCATTR_DT | X86_SEL_TYPE_CODE); 11001 /* sub reg1, X86_SEL_TYPE_WRITE ; EO-code=-2, ER-code=0, RO-data=6, RW-data=8 */ 11002 off = iemNativeEmitSubGpr32ImmEx(pbCodeBuf, off, idxReg1, X86_SEL_TYPE_WRITE /* ER-code */); 11003 /* cmp reg1, X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE */ 11004 AssertCompile(X86_SEL_TYPE_CODE == 8); 11005 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxReg1, X86_SEL_TYPE_CODE); 11006 /* ja tlbmiss */ 11007 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_nbe); 11008 } 11009 11010 /* 11011 * Check the limit. If this is a write access, we know that it's a 11012 * data segment and includes the expand_down bit. For read-only accesses 11013 * we need to check that code/data=0 and expanddown=1 before continuing. 11014 */ 11015 uint32_t offFixupCheckExpandDown; 11016 if (fAccess & IEM_ACCESS_TYPE_WRITE) 11017 { 11018 /* test segattrs, X86_SEL_TYPE_DOWN */ 11019 AssertCompile(X86_SEL_TYPE_DOWN < 128); 11020 off = iemNativeEmitTestAnyBitsInGpr8Ex(pbCodeBuf, off, idxRegSegAttrib, X86_SEL_TYPE_DOWN); 11021 /* jnz check_expand_down */ 11022 offFixupCheckExpandDown = off; 11023 off = iemNativeEmitJccToFixedEx(pbCodeBuf, off, off /*ASSUMES rel8 suffices*/, kIemNativeInstrCond_ne); 11024 } 11025 else 11026 { 11027 /* mov reg1, segattrs */ 11028 off = iemNativeEmitLoadGprFromGpr32Ex(pbCodeBuf, off, idxReg1, idxRegSegAttrib); 11029 /* and reg1, code | down */ 11030 off = iemNativeEmitAndGpr32ByImmEx(pbCodeBuf, off, idxReg1, X86_SEL_TYPE_CODE | X86_SEL_TYPE_DOWN); 11031 /* cmp reg1, down */ 11032 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxReg1, X86_SEL_TYPE_DOWN); 11033 /* je check_expand_down */ 11034 offFixupCheckExpandDown = off; 11035 off = iemNativeEmitJccToFixedEx(pbCodeBuf, off, off /*ASSUMES rel8 suffices*/, kIemNativeInstrCond_e); 11036 } 11037 11038 /* expand_up: 11039 cmp seglim, regptr/reg2/imm */ 11040 if (idxRegPtr != UINT8_MAX) 11041 off = iemNativeEmitCmpGprWithGprEx(pbCodeBuf, off, idxRegSegLimit, cbMem > 1 ? idxReg2 : idxRegPtr); 11042 else 11043 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxRegSegLimit, (uint32_t)uAbsPtr); 11044 /* jbe tlbmiss */ 11045 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_be); 11046 /* jmp limitdone */ 11047 uint32_t const offFixupLimitDone = off; 11048 off = iemNativeEmitJmpToFixedEx(pbCodeBuf, off, off /*ASSUMES rel8 suffices*/); 11049 11050 /* check_expand_down: ; complicted! */ 11051 iemNativeFixupFixedJump(pReNative, offFixupCheckExpandDown, off); 10924 11052 pbCodeBuf[off++] = 0xcc; 10925 10926 /* 10927 * 1. Segmentation. 10928 * 10929 * 1a. Check segment limit and attributes if non-flat 32-bit code. This is complicated. 10930 */ 10931 if (iSegReg != UINT8_MAX && (pReNative->fExec & IEM_F_MODE_CPUMODE_MASK) != IEMMODE_64BIT) 10932 { 10933 /* If we're accessing more than one byte, put the last address we'll be 10934 accessing in idxReg2 (64-bit). */ 10935 if (cbMem > 1) 11053 /* cmp seglim, regptr */ 11054 if (idxRegPtr != UINT8_MAX) 11055 off = iemNativeEmitCmpGprWithGprEx(pbCodeBuf, off, idxRegSegLimit, idxRegPtr); 11056 else 11057 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxRegSegLimit, (uint32_t)uAbsPtr); 11058 /* ja tlbmiss */ 11059 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_nbe); 11060 /* mov reg1, X86DESCATTR_D (0x4000) */ 11061 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxReg1, X86DESCATTR_D); 11062 /* and reg1, segattr */ 11063 off = iemNativeEmitAndGpr32ByGpr32Ex(pbCodeBuf, off, idxReg1, idxRegSegAttrib); 11064 /* xor reg1, X86DESCATTR_D */ 11065 off = iemNativeEmitXorGpr32ByImmEx(pbCodeBuf, off, idxReg1, X86DESCATTR_D); 11066 /* shl reg1, 2 (16 - 14) */ 11067 AssertCompile((X86DESCATTR_D << 2) == UINT32_C(0x10000)); 11068 off = iemNativeEmitShiftGpr32LeftEx(pbCodeBuf, off, idxReg1, 2); 11069 /* dec reg1 (=> 0xffff if D=0; 0xffffffff if D=1) */ 11070 off = iemNativeEmitSubGpr32ImmEx(pbCodeBuf, off, idxReg1, 1); 11071 /* cmp reg1, reg2 (64-bit) / imm (32-bit) */ 11072 if (idxRegPtr != UINT8_MAX) 11073 off = iemNativeEmitCmpGprWithGprEx(pbCodeBuf, off, idxReg1, idxReg2); 11074 else 11075 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxReg1, (uint32_t)(uAbsPtr + cbMem - 1)); 11076 /* jbe tlbmiss */ 11077 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_be); 11078 11079 /* limitdone: */ 11080 iemNativeFixupFixedJump(pReNative, offFixupLimitDone, off); 11081 } 11082 11083 /* 1b. Add the segment base. We use idxRegMemResult for the ptr register if this step is 11084 required or if the address is a constant (simplicity). */ 11085 uint8_t const idxRegFlatPtr = iSegReg != UINT8_MAX || idxRegPtr == UINT8_MAX ? idxRegMemResult : idxRegPtr; 11086 if (iSegReg != UINT8_MAX) 10936 11087 { 10937 /* mov reg2, cbMem-1 */ 10938 off = iemNativeEmitLoadGpr32ImmEx(pbCodeBuf, off, idxReg2, cbMem - 1); 10939 /* add reg2, regptr */ 10940 off = iemNativeEmitAddTwoGprsEx(pbCodeBuf, off, idxReg2, idxRegPtr); 11088 /** @todo this can be done using LEA as well. */ 11089 if ((pReNative->fExec & IEM_F_MODE_MASK) == IEM_F_MODE_X86_64BIT) 11090 { 11091 Assert(iSegReg >= X86_SREG_FS); 11092 /* mov regflat, regptr/imm */ 11093 if (idxRegPtr != UINT8_MAX) 11094 off = iemNativeEmitLoadGprFromGprEx(pbCodeBuf, off, idxRegFlatPtr, idxRegPtr); 11095 else 11096 off = iemNativeEmitLoadGprImmEx(pbCodeBuf, off, idxRegFlatPtr, uAbsPtr); 11097 /* add regflat, seg.base */ 11098 off = iemNativeEmitAddTwoGprsEx(pbCodeBuf, off, idxRegFlatPtr, idxRegSegBase); 11099 } 11100 else 11101 { 11102 /* mov regflat, regptr/imm */ 11103 if (idxRegPtr != UINT8_MAX) 11104 off = iemNativeEmitLoadGprFromGpr32Ex(pbCodeBuf, off, idxRegFlatPtr, idxRegPtr); 11105 else 11106 off = iemNativeEmitLoadGpr32ImmEx(pbCodeBuf, off, idxRegFlatPtr, uAbsPtr); 11107 /* add regflat, seg.base */ 11108 off = iemNativeEmitAddTwoGprs32Ex(pbCodeBuf, off, idxRegFlatPtr, idxRegSegBase); 11109 } 10941 11110 } 10942 10943 /* Check that we've got a segment loaded and that it allows the access. 10944 For write access this means a writable data segment. 10945 For read-only accesses this means a readable code segment or any data segment. */ 10946 if (fAccess & IEM_ACCESS_TYPE_WRITE) 11111 else if (idxRegPtr == UINT8_MAX) 11112 off = iemNativeEmitLoadGprImmEx(pbCodeBuf, off, idxRegFlatPtr, uAbsPtr); 11113 11114 /* 11115 * 2. Check that the address doesn't cross a page boundrary and doesn't have alignment issues. 11116 * 11117 * 2a. Alignment check using fAlignMask. 11118 */ 11119 if (fAlignMask) 10947 11120 { 10948 uint32_t const fMustBe1 = X86DESCATTR_P | X86DESCATTR_DT | X86_SEL_TYPE_WRITE; 10949 uint32_t const fMustBe0 = X86DESCATTR_UNUSABLE | X86_SEL_TYPE_CODE; 10950 /* mov reg1, must1|must0 */ 10951 off = iemNativeEmitLoadGpr32ImmEx(pbCodeBuf, off, idxReg1, fMustBe1 | fMustBe0); 10952 /* and reg1, segattrs */ 10953 off = iemNativeEmitAndGpr32ByGpr32Ex(pbCodeBuf, off, idxReg1, idxRegSegAttrib); 10954 /* cmp reg1, must1 */ 10955 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxReg1, fMustBe1); 10956 /* jne tlbmiss */ 11121 Assert(RT_IS_POWER_OF_TWO(fAlignMask + 1)); 11122 Assert(fAlignMask < 128); 11123 /* test regflat, fAlignMask */ 11124 off = iemNativeEmitTestAnyBitsInGpr8Ex(pbCodeBuf, off, idxRegFlatPtr, fAlignMask); 11125 /* jnz tlbmiss */ 10957 11126 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_ne); 11127 } 11128 11129 /* 11130 * 2b. Check that it's not crossing page a boundrary. This is implicit in 11131 * the previous test if the alignment is same or larger than the type. 11132 */ 11133 if (cbMem > fAlignMask + 1) 11134 { 11135 /* mov reg1, 0xfff */ 11136 off = iemNativeEmitLoadGpr32ImmEx(pbCodeBuf, off, idxReg1, GUEST_PAGE_OFFSET_MASK); 11137 /* and reg1, regflat */ 11138 off = iemNativeEmitAndGpr32ByGpr32Ex(pbCodeBuf, off, idxReg1, idxRegFlatPtr); 11139 /* neg reg1 */ 11140 off = iemNativeEmitNegGpr32Ex(pbCodeBuf, off, idxReg1); 11141 /* add reg1, 0x1000 */ 11142 off = iemNativeEmitAddGpr32ImmEx(pbCodeBuf, off, idxReg1, GUEST_PAGE_SIZE); 11143 /* cmp reg1, cbMem */ 11144 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxReg1, GUEST_PAGE_SIZE); 11145 /* ja tlbmiss */ 11146 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_nbe); 11147 } 11148 11149 /* 11150 * 3. TLB lookup. 11151 * 11152 * 3a. Calculate the TLB tag value (IEMTLB_CALC_TAG). 11153 * In 64-bit mode we will also check for non-canonical addresses here. 11154 */ 11155 if ((pReNative->fExec & IEM_F_MODE_MASK) == IEM_F_MODE_X86_64BIT) 11156 { 11157 /* mov reg1, regflat */ 11158 off = iemNativeEmitLoadGprFromGprEx(pbCodeBuf, off, idxReg1, idxRegFlatPtr); 11159 /* rol reg1, 16 */ 11160 off = iemNativeEmitRotateGprLeftEx(pbCodeBuf, off, idxReg1, 16); 11161 /** @todo Would 'movsx reg2, word reg1' and working on reg2 in dwords be faster? */ 11162 /* inc word reg1 */ 11163 pbCodeBuf[off++] = X86_OP_PRF_SIZE_OP; 11164 if (idxReg1 >= 8) 11165 pbCodeBuf[off++] = X86_OP_REX_B; 11166 pbCodeBuf[off++] = 0xff; 11167 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 0, idxReg1 & 7); 11168 /* cmp word reg1, 1 */ 11169 pbCodeBuf[off++] = X86_OP_PRF_SIZE_OP; 11170 if (idxReg1 >= 8) 11171 pbCodeBuf[off++] = X86_OP_REX_B; 11172 pbCodeBuf[off++] = 0x83; 11173 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 7, idxReg1 & 7); 11174 pbCodeBuf[off++] = 1; 11175 /* ja tlbmiss */ 11176 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_nbe); 11177 /* shr reg1, 16 + GUEST_PAGE_SHIFT */ 11178 off = iemNativeEmitShiftGprRightEx(pbCodeBuf, off, idxReg1, 16 + GUEST_PAGE_SHIFT); 10958 11179 } 10959 11180 else 10960 11181 { 10961 /* U | !P |!DT |!CD | RW | 10962 16 | 8 | 4 | 3 | 1 | 10963 ------------------------------- 10964 0 | 0 | 0 | 0 | 0 | execute-only code segment. - must be excluded 10965 0 | 0 | 0 | 0 | 1 | execute-read code segment. 10966 0 | 0 | 0 | 1 | 0 | read-only data segment. 10967 0 | 0 | 0 | 1 | 1 | read-write data segment. - last valid combination 10968 */ 10969 /* mov reg1, relevant attributes */ 10970 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxReg1, 10971 X86DESCATTR_UNUSABLE | X86DESCATTR_P | X86DESCATTR_DT 10972 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE); 10973 /* and reg1, segattrs */ 10974 off = iemNativeEmitAndGpr32ByGpr32Ex(pbCodeBuf, off, idxReg1, idxRegSegAttrib); 10975 /* xor reg1, X86DESCATTR_P | X86DESCATTR_DT | X86_SEL_TYPE_CODE ; place C=1 RW=0 at the bottom & limit the range. */ 10976 off = iemNativeEmitXorGpr32ByImmEx(pbCodeBuf, off, idxReg1, X86DESCATTR_P | X86DESCATTR_DT | X86_SEL_TYPE_CODE); 10977 /* sub reg1, X86_SEL_TYPE_WRITE ; ER-code=0, EO-code=0xffffffff, R0-data=7, RW-data=9 */ 10978 off = iemNativeEmitSubGpr32ImmEx(pbCodeBuf, off, idxReg1, X86_SEL_TYPE_WRITE); 10979 /* cmp reg1, X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE */ 10980 AssertCompile((X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE) - 1 == 9); 10981 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxReg1, (X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE) - 1); 10982 /* ja tlbmiss */ 10983 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_nbe); 11182 /* mov reg1, regflat */ 11183 off = iemNativeEmitLoadGprFromGpr32Ex(pbCodeBuf, off, idxReg1, idxRegFlatPtr); 11184 /* shr reg1, GUEST_PAGE_SHIFT */ 11185 off = iemNativeEmitShiftGpr32RightEx(pbCodeBuf, off, idxReg1, GUEST_PAGE_SHIFT); 10984 11186 } 11187 /* or reg1, [qword pVCpu->iem.s.DataTlb.uTlbRevision] */ 11188 pbCodeBuf[off++] = idxReg1 < 8 ? X86_OP_REX_W : X86_OP_REX_W | X86_OP_REX_R; 11189 pbCodeBuf[off++] = 0x0b; /* OR r64,r/m64 */ 11190 off = iemNativeEmitGprByVCpuDisp(pbCodeBuf, off, idxReg1, RT_UOFFSETOF(VMCPUCC, iem.s.DataTlb.uTlbRevision)); 10985 11191 10986 11192 /* 10987 * Check the limit. If this is a write access, we know that it's a 10988 * data segment and includes the expand_down bit. For read-only accesses 10989 * we need to check that code/data=0 and expanddown=1 before continuing. 11193 * 3b. Calc pTlbe. 10990 11194 */ 10991 uint32_t offFixupCheckExpandDown; 10992 if (fAccess & IEM_ACCESS_TYPE_WRITE) 11195 /* movzx reg2, byte reg1 */ 11196 off = iemNativeEmitLoadGprFromGpr8Ex(pbCodeBuf, off, idxReg2, idxReg1); 11197 /* shl reg2, 5 ; reg2 *= sizeof(IEMTLBENTRY) */ 11198 AssertCompileSize(IEMTLBENTRY, 32); 11199 off = iemNativeEmitShiftGprLeftEx(pbCodeBuf, off, idxReg2, 5); 11200 /* lea reg2, [pVCpu->iem.s.DataTlb.aEntries + reg2] */ 11201 AssertCompile(IEMNATIVE_REG_FIXED_PVMCPU < 8); 11202 pbCodeBuf[off++] = idxReg2 < 8 ? X86_OP_REX_W : X86_OP_REX_W | X86_OP_REX_X | X86_OP_REX_R; 11203 pbCodeBuf[off++] = 0x8d; 11204 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM4, idxReg2 & 7, 4 /*SIB*/); 11205 pbCodeBuf[off++] = X86_SIB_MAKE(IEMNATIVE_REG_FIXED_PVMCPU & 7, idxReg2 & 7, 0); 11206 pbCodeBuf[off++] = RT_BYTE1(RT_UOFFSETOF(VMCPUCC, iem.s.DataTlb.aEntries)); 11207 pbCodeBuf[off++] = RT_BYTE2(RT_UOFFSETOF(VMCPUCC, iem.s.DataTlb.aEntries)); 11208 pbCodeBuf[off++] = RT_BYTE3(RT_UOFFSETOF(VMCPUCC, iem.s.DataTlb.aEntries)); 11209 pbCodeBuf[off++] = RT_BYTE4(RT_UOFFSETOF(VMCPUCC, iem.s.DataTlb.aEntries)); 11210 11211 /* 11212 * 3c. Compare the TLBE.uTag with the one from 2a (reg1). 11213 */ 11214 /* cmp reg1, [reg2] */ 11215 pbCodeBuf[off++] = X86_OP_REX_W | (idxReg1 < 8 ? 0 : X86_OP_REX_R) | (idxReg2 < 8 ? 0 : X86_OP_REX_B); 11216 pbCodeBuf[off++] = 0x3b; 11217 off = iemNativeEmitGprByGprDisp(pbCodeBuf, off, idxReg1, idxReg2, RT_UOFFSETOF(IEMTLBENTRY, uTag)); 11218 /* jne tlbmiss */ 11219 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_ne); 11220 11221 /* 11222 * 4. Check TLB page table level access flags and physical page revision #. 11223 */ 11224 /* mov reg1, mask */ 11225 AssertCompile(IEMTLBE_F_PT_NO_USER == 4); 11226 uint64_t const fNoUser = (((pReNative->fExec >> IEM_F_X86_CPL_SHIFT) & IEM_F_X86_CPL_SMASK) + 1) & IEMTLBE_F_PT_NO_USER; 11227 off = iemNativeEmitLoadGprImmEx(pbCodeBuf, off, idxReg1, 11228 IEMTLBE_F_PHYS_REV | IEMTLBE_F_NO_MAPPINGR3 11229 | IEMTLBE_F_PG_UNASSIGNED | IEMTLBE_F_PG_NO_READ 11230 | IEMTLBE_F_PT_NO_ACCESSED | fNoUser); 11231 /* and reg1, [reg2->fFlagsAndPhysRev] */ 11232 pbCodeBuf[off++] = X86_OP_REX_W | (idxReg1 < 8 ? 0 : X86_OP_REX_R) | (idxReg2 < 8 ? 0 : X86_OP_REX_B); 11233 pbCodeBuf[off++] = 0x23; 11234 off = iemNativeEmitGprByGprDisp(pbCodeBuf, off, idxReg1, idxReg2, RT_UOFFSETOF(IEMTLBENTRY, fFlagsAndPhysRev)); 11235 11236 /* cmp reg1, [pVCpu->iem.s.DataTlb.uTlbPhysRev] */ 11237 pbCodeBuf[off++] = X86_OP_REX_W | (idxReg1 < 8 ? 0 : X86_OP_REX_R); 11238 pbCodeBuf[off++] = 0x3b; 11239 off = iemNativeEmitGprByGprDisp(pbCodeBuf, off, idxReg1, IEMNATIVE_REG_FIXED_PVMCPU, 11240 RT_UOFFSETOF(VMCPUCC, iem.s.DataTlb.uTlbPhysRev)); 11241 /* jne tlbmiss */ 11242 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_ne); 11243 11244 /* 11245 * 5. Check that pbMappingR3 isn't NULL (paranoia) and calculate the 11246 * resulting pointer. 11247 */ 11248 /* mov reg1, [reg2->pbMappingR3] */ 11249 pbCodeBuf[off++] = X86_OP_REX_W | (idxReg1 < 8 ? 0 : X86_OP_REX_R) | (idxReg2 < 8 ? 0 : X86_OP_REX_B); 11250 pbCodeBuf[off++] = 0x8b; 11251 off = iemNativeEmitGprByGprDisp(pbCodeBuf, off, idxReg1, idxReg2, RT_UOFFSETOF(IEMTLBENTRY, pbMappingR3)); 11252 11253 /** @todo eliminate the need for this test? */ 11254 /* test reg1, reg1 */ 11255 pbCodeBuf[off++] = X86_OP_REX_W | (idxReg1 < 8 ? 0 : X86_OP_REX_R | X86_OP_REX_B); 11256 pbCodeBuf[off++] = 0x85; 11257 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, idxReg1 & 7, idxReg1 & 7); 11258 11259 /* jz tlbmiss */ 11260 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbDone, kIemNativeInstrCond_e); 11261 11262 if (idxRegFlatPtr == idxRegMemResult) /* See step 1b. */ 10993 11263 { 10994 /* test segattrs, X86_SEL_TYPE_DOWN */ 10995 AssertCompile(X86_SEL_TYPE_DOWN < 128); 10996 off = iemNativeEmitTestAnyBitsInGpr8Ex(pbCodeBuf, off, idxRegSegAttrib, X86_SEL_TYPE_DOWN); 10997 /* jnz check_expand_down */ 10998 offFixupCheckExpandDown = off; 10999 off = iemNativeEmitJccToFixedEx(pbCodeBuf, off, off /*ASSUMES rel8 suffices*/, kIemNativeInstrCond_ne); 11264 /* and result, 0xfff */ 11265 off = iemNativeEmitAndGpr32ByImmEx(pbCodeBuf, off, idxRegMemResult, GUEST_PAGE_OFFSET_MASK); 11000 11266 } 11001 11267 else 11002 11268 { 11003 /* mov reg1, segattrs */ 11004 off = iemNativeEmitLoadGprFromGpr32Ex(pbCodeBuf, off, idxReg1, idxRegSegAttrib); 11005 /* and reg1, code | down */ 11006 off = iemNativeEmitAndGpr32ByImmEx(pbCodeBuf, off, idxReg1, X86_SEL_TYPE_CODE | X86_SEL_TYPE_DOWN); 11007 /* cmp reg1, down */ 11008 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxReg1, X86_SEL_TYPE_DOWN); 11009 /* je check_expand_down */ 11010 offFixupCheckExpandDown = off; 11011 off = iemNativeEmitJccToFixedEx(pbCodeBuf, off, off /*ASSUMES rel8 suffices*/, kIemNativeInstrCond_e); 11269 Assert(idxRegFlatPtr == idxRegPtr); 11270 /* mov result, 0xfff */ 11271 off = iemNativeEmitLoadGpr32ImmEx(pbCodeBuf, off, idxRegMemResult, GUEST_PAGE_OFFSET_MASK); 11272 /* and result, regflat */ 11273 off = iemNativeEmitAndGpr32ByGpr32Ex(pbCodeBuf, off, idxRegMemResult, idxRegFlatPtr); 11012 11274 } 11013 11014 /* expand_up: 11015 cmp regptr/reg2, seglim */ 11016 off = iemNativeEmitCmpGprWithGprEx(pbCodeBuf, off, cbMem > 1 ? idxReg2 : idxRegPtr, idxRegSegLimit); 11017 /* ja tlbmiss */ 11018 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_nbe); 11019 /* jmp limitdone */ 11020 uint32_t const offFixupLimitDone = off; 11021 off = iemNativeEmitJmpToFixedEx(pbCodeBuf, off, off /*ASSUMES rel8 suffices*/); 11022 11023 /* check_expand_down: ; complicted! */ 11024 iemNativeFixupFixedJump(pReNative, offFixupCheckExpandDown, off); 11025 /* cmp regptr, seglim */ 11026 off = iemNativeEmitCmpGprWithGprEx(pbCodeBuf, off, idxRegPtr, idxRegSegLimit); 11027 /* jbe tlbmiss */ 11028 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_be); 11029 /* mov reg1, X86DESCATTR_D (0x4000) */ 11030 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxReg1, X86DESCATTR_D); 11031 /* and reg1, segattr */ 11032 off = iemNativeEmitAndGpr32ByGpr32Ex(pbCodeBuf, off, idxReg1, idxRegSegAttrib); 11033 /* xor reg1, X86DESCATTR_D */ 11034 off = iemNativeEmitXorGpr32ByImmEx(pbCodeBuf, off, idxReg1, X86DESCATTR_D); 11035 /* shl reg1, 2 (16 - 14) */ 11036 AssertCompile((X86DESCATTR_D << 2) == UINT32_C(0x10000)); 11037 off = iemNativeEmitShiftGpr32LeftEx(pbCodeBuf, off, idxReg1, 2); 11038 /* dec reg1 (=> 0xffff if D=0; 0xffffffff if D=1) */ 11039 off = iemNativeEmitSubGpr32ImmEx(pbCodeBuf, off, idxReg1, 1); 11040 /* cmp reg2, reg1 (64-bit) */ 11041 off = iemNativeEmitCmpGpr32WithGprEx(pbCodeBuf, off, idxReg2, idxReg1); 11042 /* ja tlbmiss */ 11043 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_nbe); 11044 11045 /* limitdone: */ 11046 iemNativeFixupFixedJump(pReNative, offFixupLimitDone, off); 11047 } 11048 11049 /* 1b. Add the segment base. We use idxRegMemResult for the ptr register if this step is required. */ 11050 uint8_t const idxRegFlatPtr = iSegReg != UINT8_MAX ? idxRegMemResult : idxRegPtr; 11051 if (iSegReg != UINT8_MAX) 11052 { 11053 if ((pReNative->fExec & IEM_F_MODE_MASK) == IEM_F_MODE_X86_64BIT) 11275 /* add result, reg1 */ 11276 off = iemNativeEmitAddTwoGprsEx(pbCodeBuf, off, idxRegMemResult, idxReg1); 11277 11278 if (idxRegPtr != UINT8_MAX) 11279 iemNativeVarRegisterRelease(pReNative, idxVarGCPtrMem); 11280 if (idxRegSegBase != UINT8_MAX) 11281 iemNativeRegFreeTmp(pReNative, idxRegSegBase); 11282 if (idxRegSegLimit != UINT8_MAX) 11054 11283 { 11055 Assert(iSegReg >= X86_SREG_FS); 11056 /* mov regflat, regptr */ 11057 off = iemNativeEmitLoadGprFromGprEx(pbCodeBuf, off, idxRegFlatPtr, idxRegPtr); 11058 /* add regflat, seg.base */ 11059 off = iemNativeEmitAddTwoGprsEx(pbCodeBuf, off, idxRegFlatPtr, idxRegSegBase); 11284 iemNativeRegFreeTmp(pReNative, idxRegSegLimit); 11285 iemNativeRegFreeTmp(pReNative, idxRegSegAttrib); 11060 11286 } 11061 11287 else 11062 { 11063 /* mov regflat, regptr */ 11064 off = iemNativeEmitLoadGprFromGpr32Ex(pbCodeBuf, off, idxRegFlatPtr, idxRegPtr); 11065 /* add regflat, seg.base */ 11066 off = iemNativeEmitAddTwoGprs32Ex(pbCodeBuf, off, idxRegFlatPtr, idxRegSegBase); 11067 } 11068 } 11069 11070 /* 11071 * 2. Check that the address doesn't cross a page boundrary and doesn't have alignment issues. 11072 * 11073 * 2a. Alignment check using fAlignMask. 11074 */ 11075 Assert(RT_IS_POWER_OF_TWO(fAlignMask + 1)); 11076 Assert(fAlignMask < 128); 11077 /* test regflat, fAlignMask */ 11078 off = iemNativeEmitTestAnyBitsInGpr8Ex(pbCodeBuf, off, idxRegFlatPtr, fAlignMask); 11079 /* jnz tlbmiss */ 11080 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_ne); 11081 11082 /* 11083 * 2b. Check that it's not crossing page a boundrary. This is implicit in 11084 * the previous test if the alignment is same or larger than the type. 11085 */ 11086 if (cbMem > fAlignMask + 1) 11087 { 11088 /* mov reg1, 0xfff */ 11089 off = iemNativeEmitLoadGpr32ImmEx(pbCodeBuf, off, idxReg1, GUEST_PAGE_OFFSET_MASK); 11090 /* and reg1, regflat */ 11091 off = iemNativeEmitAndGpr32ByGpr32Ex(pbCodeBuf, off, idxReg1, idxRegFlatPtr); 11092 /* neg reg1 */ 11093 off = iemNativeEmitNegGpr32Ex(pbCodeBuf, off, idxReg1); 11094 /* add reg1, 0x1000 */ 11095 off = iemNativeEmitAddGpr32ImmEx(pbCodeBuf, off, idxReg1, GUEST_PAGE_SIZE); 11096 /* cmp reg1, cbMem */ 11097 off = iemNativeEmitCmpGpr32WithImmEx(pbCodeBuf, off, idxReg1, GUEST_PAGE_SIZE); 11098 /* ja tlbmiss */ 11099 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_nbe); 11100 } 11101 11102 /* 11103 * 3. TLB lookup. 11104 * 11105 * 3a. Calculate the TLB tag value (IEMTLB_CALC_TAG). 11106 * In 64-bit mode we will also check for non-canonical addresses here. 11107 */ 11108 if ((pReNative->fExec & IEM_F_MODE_MASK) == IEM_F_MODE_X86_64BIT) 11109 { 11110 /* mov reg1, regflat */ 11111 off = iemNativeEmitLoadGprFromGprEx(pbCodeBuf, off, idxReg1, idxRegFlatPtr); 11112 /* rol reg1, 16 */ 11113 off = iemNativeEmitRotateGprLeftEx(pbCodeBuf, off, idxReg1, 16); 11114 /** @todo Would 'movsx reg2, word reg1' and working on reg2 in dwords be faster? */ 11115 /* inc word reg1 */ 11116 pbCodeBuf[off++] = X86_OP_PRF_SIZE_OP; 11117 if (idxReg1 >= 8) 11118 pbCodeBuf[off++] = X86_OP_REX_B; 11119 pbCodeBuf[off++] = 0xff; 11120 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 0, idxReg1 & 7); 11121 /* cmp word reg1, 1 */ 11122 pbCodeBuf[off++] = X86_OP_PRF_SIZE_OP; 11123 if (idxReg1 >= 8) 11124 pbCodeBuf[off++] = X86_OP_REX_B; 11125 pbCodeBuf[off++] = 0x83; 11126 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 7, idxReg1 & 7); 11127 pbCodeBuf[off++] = 1; 11128 /* ja tlbmiss */ 11129 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_nbe); 11130 /* shr reg1, 16 + GUEST_PAGE_SHIFT */ 11131 off = iemNativeEmitShiftGprRightEx(pbCodeBuf, off, idxReg1, 16 + GUEST_PAGE_SHIFT); 11132 } 11288 Assert(idxRegSegAttrib == UINT8_MAX); 11289 iemNativeRegFreeTmp(pReNative, idxReg2); 11290 iemNativeRegFreeTmp(pReNative, idxReg1); 11291 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 11292 } 11293 /* Problematic absolute address, jmp to tlbmiss. Caller will be generate 11294 some unused tail code, but whatever. */ 11133 11295 else 11134 { 11135 /* mov reg1, regflat */ 11136 off = iemNativeEmitLoadGprFromGpr32Ex(pbCodeBuf, off, idxReg1, idxRegFlatPtr); 11137 /* shr reg1, GUEST_PAGE_SHIFT */ 11138 off = iemNativeEmitShiftGpr32RightEx(pbCodeBuf, off, idxReg1, GUEST_PAGE_SHIFT); 11139 } 11140 /* or reg1, [qword pVCpu->iem.s.DataTlb.uTlbRevision] */ 11141 pbCodeBuf[off++] = idxReg1 < 8 ? X86_OP_REX_W : X86_OP_REX_W | X86_OP_REX_R; 11142 pbCodeBuf[off++] = 0x0b; /* OR r64,r/m64 */ 11143 off = iemNativeEmitGprByVCpuDisp(pbCodeBuf, off, idxReg1, RT_UOFFSETOF(VMCPUCC, iem.s.DataTlb.uTlbRevision)); 11144 11145 /* 11146 * 3b. Calc pTlbe. 11147 */ 11148 /* movzx reg2, byte reg1 */ 11149 off = iemNativeEmitLoadGprFromGpr8Ex(pbCodeBuf, off, idxReg2, idxReg1); 11150 /* shl reg2, 5 ; reg2 *= sizeof(IEMTLBENTRY) */ 11151 AssertCompileSize(IEMTLBENTRY, 32); 11152 off = iemNativeEmitShiftGprLeftEx(pbCodeBuf, off, idxReg2, 5); 11153 /* lea reg2, [pVCpu->iem.s.DataTlb.aEntries + reg2] */ 11154 AssertCompile(IEMNATIVE_REG_FIXED_PVMCPU < 8); 11155 pbCodeBuf[off++] = idxReg2 < 8 ? X86_OP_REX_W : X86_OP_REX_W | X86_OP_REX_X | X86_OP_REX_R; 11156 pbCodeBuf[off++] = 0x8d; 11157 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM4, idxReg2 & 7, 4 /*SIB*/); 11158 pbCodeBuf[off++] = X86_SIB_MAKE(IEMNATIVE_REG_FIXED_PVMCPU & 7, idxReg2 & 7, 0); 11159 pbCodeBuf[off++] = RT_BYTE1(RT_UOFFSETOF(VMCPUCC, iem.s.DataTlb.aEntries)); 11160 pbCodeBuf[off++] = RT_BYTE2(RT_UOFFSETOF(VMCPUCC, iem.s.DataTlb.aEntries)); 11161 pbCodeBuf[off++] = RT_BYTE3(RT_UOFFSETOF(VMCPUCC, iem.s.DataTlb.aEntries)); 11162 pbCodeBuf[off++] = RT_BYTE4(RT_UOFFSETOF(VMCPUCC, iem.s.DataTlb.aEntries)); 11163 11164 /* 11165 * 3c. Compare the TLBE.uTag with the one from 2a (reg1). 11166 */ 11167 /* cmp reg1, [reg2] */ 11168 pbCodeBuf[off++] = X86_OP_REX_W | (idxReg1 < 8 ? 0 : X86_OP_REX_R) | (idxReg2 < 8 ? 0 : X86_OP_REX_B); 11169 pbCodeBuf[off++] = 0x3b; 11170 off = iemNativeEmitGprByGprDisp(pbCodeBuf, off, idxReg1, idxReg2, RT_UOFFSETOF(IEMTLBENTRY, uTag)); 11171 /* jne tlbmiss */ 11172 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_ne); 11173 11174 /* 11175 * 4. Check TLB page table level access flags and physical page revision #. 11176 */ 11177 /* mov reg1, mask */ 11178 AssertCompile(IEMTLBE_F_PT_NO_USER == 4); 11179 uint64_t const fNoUser = (((pReNative->fExec >> IEM_F_X86_CPL_SHIFT) & IEM_F_X86_CPL_SMASK) + 1) & IEMTLBE_F_PT_NO_USER; 11180 off = iemNativeEmitLoadGprImmEx(pbCodeBuf, off, idxReg1, 11181 IEMTLBE_F_PHYS_REV | IEMTLBE_F_NO_MAPPINGR3 11182 | IEMTLBE_F_PG_UNASSIGNED | IEMTLBE_F_PG_NO_READ 11183 | IEMTLBE_F_PT_NO_ACCESSED | fNoUser); 11184 /* and reg1, [reg2->fFlagsAndPhysRev] */ 11185 pbCodeBuf[off++] = X86_OP_REX_W | (idxReg1 < 8 ? 0 : X86_OP_REX_R) | (idxReg2 < 8 ? 0 : X86_OP_REX_B); 11186 pbCodeBuf[off++] = 0x23; 11187 off = iemNativeEmitGprByGprDisp(pbCodeBuf, off, idxReg1, idxReg2, RT_UOFFSETOF(IEMTLBENTRY, fFlagsAndPhysRev)); 11188 11189 /* cmp reg1, [pVCpu->iem.s.DataTlb.uTlbPhysRev] */ 11190 pbCodeBuf[off++] = X86_OP_REX_W | (idxReg1 < 8 ? 0 : X86_OP_REX_R); 11191 pbCodeBuf[off++] = 0x3b; 11192 off = iemNativeEmitGprByGprDisp(pbCodeBuf, off, idxReg1, IEMNATIVE_REG_FIXED_PVMCPU, 11193 RT_UOFFSETOF(VMCPUCC, iem.s.DataTlb.uTlbPhysRev)); 11194 /* jne tlbmiss */ 11195 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbMiss, kIemNativeInstrCond_ne); 11196 11197 /* 11198 * 5. Check that pbMappingR3 isn't NULL (paranoia) and calculate the 11199 * resulting pointer. 11200 */ 11201 /* mov reg1, [reg2->pbMappingR3] */ 11202 pbCodeBuf[off++] = X86_OP_REX_W | (idxReg1 < 8 ? 0 : X86_OP_REX_R) | (idxReg2 < 8 ? 0 : X86_OP_REX_B); 11203 pbCodeBuf[off++] = 0x8b; 11204 off = iemNativeEmitGprByGprDisp(pbCodeBuf, off, idxRegMemResult, idxReg2, RT_UOFFSETOF(IEMTLBENTRY, pbMappingR3)); 11205 11206 /** @todo eliminate the need for this test? */ 11207 /* test reg1, reg1 */ 11208 pbCodeBuf[off++] = X86_OP_REX_W | (idxReg1 < 8 ? 0 : X86_OP_REX_R | X86_OP_REX_B); 11209 pbCodeBuf[off++] = 0x85; 11210 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, idxReg1 & 7, idxReg1 & 7); 11211 11212 /* jz tlbmiss */ 11213 off = iemNativeEmitJccToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbDone, kIemNativeInstrCond_e); 11214 11215 if (idxRegFlatPtr == idxRegMemResult) /* See step 1b. */ 11216 { 11217 /* and result, 0xfff */ 11218 off = iemNativeEmitAndGpr32ByImmEx(pbCodeBuf, off, idxRegMemResult, GUEST_PAGE_OFFSET_MASK); 11219 } 11220 else 11221 { 11222 Assert(idxRegFlatPtr == idxRegPtr); 11223 /* mov result, 0xfff */ 11224 off = iemNativeEmitLoadGpr32ImmEx(pbCodeBuf, off, idxRegMemResult, GUEST_PAGE_OFFSET_MASK); 11225 /* and result, regflat */ 11226 off = iemNativeEmitAndGpr32ByGpr32Ex(pbCodeBuf, off, idxRegMemResult, idxRegFlatPtr); 11227 } 11228 /* add result, reg1 */ 11229 off = iemNativeEmitAddTwoGprsEx(pbCodeBuf, off, idxRegMemResult, idxReg1); 11296 off = iemNativeEmitJmpToLabel(pReNative, off, idxLabelTlbMiss); 11297 11298 /* 11299 * Tail code, specific to the MC when the above is moved into a separate function. 11300 */ 11301 uint8_t * const pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 32); 11302 11303 /* [idxVarUnmapInfo] = 0 - allocate register for it. There must be free ones now, so no spilling required. */ 11304 uint32_t const offSaved = off; 11305 uint8_t const idxRegUnmapInfo = iemNativeVarRegisterAcquire(pReNative, idxVarUnmapInfo, &off); 11306 AssertStmt(off == offSaved, IEMNATIVE_DO_LONGJMP(pReNative, VERR_IEM_VAR_IPE_9)); 11307 off = iemNativeEmitLoadGpr32ImmEx(pbCodeBuf, off, idxRegUnmapInfo, 0); 11230 11308 11231 11309 /* jmp tlbdone */ 11232 11310 off = iemNativeEmitJmpToLabelEx(pReNative, pbCodeBuf, off, idxLabelTlbDone); 11233 11311 11234 iemNativeVarRegisterRelease(pReNative, idxRegPtr); 11235 iemNativeRegFree(pReNative, idxRegSegBase); 11236 iemNativeRegFree(pReNative, idxRegSegLimit); 11237 iemNativeRegFree(pReNative, idxRegSegAttrib); 11238 iemNativeRegFree(pReNative, idxReg2); 11239 iemNativeRegFree(pReNative, idxReg1); 11240 11312 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 11241 11313 #else 11242 11314 /** @todo arm64 TLB code */ … … 11266 11338 off = iemNativeEmitLoadArgGregFromImmOrStackVar(pReNative, off, IEMNATIVE_CALL_ARG2_GREG, idxVarGCPtrMem); 11267 11339 11268 /* IEMNATIVE_CALL_ARG1_GREG = &idxVarUnmapInfo */11269 iemNativeVarSetKindToStack(pReNative, idxVarUnmapInfo); 11340 /* IEMNATIVE_CALL_ARG1_GREG = &idxVarUnmapInfo; stackslot address, load any register with result after the call. */ 11341 #if 0 11270 11342 off = iemNativeEmitLoadArgGregWithVarAddr(pReNative, off, IEMNATIVE_CALL_ARG1_GREG, idxVarUnmapInfo, true /*fFlushShadows*/); 11343 #else 11344 int32_t const offBpDispVarUnmapInfo = iemNativeStackCalcBpDisp(iemNativeVarGetStackSlot(pReNative, idxVarUnmapInfo)); 11345 off = iemNativeEmitLeaGprByBp(pReNative, off, IEMNATIVE_CALL_ARG1_GREG, offBpDispVarUnmapInfo); 11346 #endif 11271 11347 11272 11348 /* IEMNATIVE_CALL_ARG0_GREG = pVCpu */ … … 11277 11353 11278 11354 /* 11279 * Put the result in the right register.11355 * Put the output in the right registers. 11280 11356 */ 11281 11357 Assert(idxRegMemResult == pReNative->Core.aVars[idxVarMem].idxReg); … … 11283 11359 off = iemNativeEmitLoadGprFromGpr(pReNative, off, idxRegMemResult, IEMNATIVE_CALL_RET_GREG); 11284 11360 iemNativeVarRegisterRelease(pReNative, idxVarMem); 11361 11362 #if defined(RT_ARCH_AMD64) 11363 Assert(pReNative->Core.aVars[idxVarUnmapInfo].idxReg == idxRegUnmapInfo); 11364 off = iemNativeEmitLoadGprByBpU8(pReNative, off, idxRegUnmapInfo, offBpDispVarUnmapInfo); 11365 iemNativeVarRegisterRelease(pReNative, idxVarUnmapInfo); 11366 #endif 11285 11367 11286 11368 iemNativeLabelDefine(pReNative, idxLabelTlbDone, off); -
trunk/src/VBox/VMM/include/IEMN8veRecompilerEmit.h
r102718 r102720 174 174 * - ARM64: 4 instruction words (16 bytes). 175 175 */ 176 DECLINLINE(uint32_t) iemNativeEmitLoadGprImmEx(PIEMNATIVEINSTR pCodeBuf, uint32_t off, uint8_t iGpr, uint64_t uImm64) 176 DECL_FORCE_INLINE(uint32_t) 177 iemNativeEmitLoadGprImmEx(PIEMNATIVEINSTR pCodeBuf, uint32_t off, uint8_t iGpr, uint64_t uImm64) 177 178 { 178 179 #ifdef RT_ARCH_AMD64 … … 191 192 pCodeBuf[off++] = X86_OP_REX_B; 192 193 pCodeBuf[off++] = 0xb8 + (iGpr & 7); 194 pCodeBuf[off++] = RT_BYTE1(uImm64); 195 pCodeBuf[off++] = RT_BYTE2(uImm64); 196 pCodeBuf[off++] = RT_BYTE3(uImm64); 197 pCodeBuf[off++] = RT_BYTE4(uImm64); 198 } 199 else if (uImm64 == (uint64_t)(int32_t)uImm64) 200 { 201 /* mov gpr, sx(imm32) */ 202 if (iGpr < 8) 203 pCodeBuf[off++] = X86_OP_REX_W; 204 else 205 pCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_B; 206 pCodeBuf[off++] = 0xc7; 207 pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 0, iGpr & 7); 193 208 pCodeBuf[off++] = RT_BYTE1(uImm64); 194 209 pCodeBuf[off++] = RT_BYTE2(uImm64); … … 3101 3116 if (iGprLeft >= 8) 3102 3117 pCodeBuf[off++] = X86_OP_REX_B; 3103 if (uImm <= UINT32_C(0x ff))3118 if (uImm <= UINT32_C(0x7f)) 3104 3119 { 3105 3120 /* cmp Ev, Ib */
Note:
See TracChangeset
for help on using the changeset viewer.