Changeset 60874 in vbox for trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
- Timestamp:
- May 7, 2016 5:55:21 PM (9 years ago)
- svn:sync-xref-src-repo-rev:
- 107086
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
r60854 r60874 47 47 48 48 49 /*********************************************************************************************************************************50 * Defined Constants And Macros *51 *********************************************************************************************************************************/52 /** @def IEM_USE_IEM_INSTEAD53 * Use IEM instead of IOM for interpreting MMIO accesses.54 * Because of PATM/CSAM issues in raw-mode, we've split this up into 2nd and 3rd55 * IEM deployment step. */56 #if ((defined(IN_RING3) || defined(IN_RING0)) && defined(VBOX_WITH_2ND_IEM_STEP)) \57 || defined(VBOX_WITH_3RD_IEM_STEP) || defined(DOXYGEN_RUNNING)58 # define IEM_USE_IEM_INSTEAD59 #endif60 61 62 /*********************************************************************************************************************************63 * Global Variables *64 *********************************************************************************************************************************/65 66 /**67 * Array for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.68 */69 static const unsigned g_aSize2Shift[] =70 {71 ~0U, /* 0 - invalid */72 0, /* *1 == 2^0 */73 1, /* *2 == 2^1 */74 ~0U, /* 3 - invalid */75 2, /* *4 == 2^2 */76 ~0U, /* 5 - invalid */77 ~0U, /* 6 - invalid */78 ~0U, /* 7 - invalid */79 3 /* *8 == 2^3 */80 };81 82 /**83 * Macro for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.84 */85 #define SIZE_2_SHIFT(cb) (g_aSize2Shift[cb])86 87 88 /**89 * Returns the contents of register or immediate data of instruction's parameter.90 *91 * @returns true on success.92 *93 * @todo Get rid of this code. Use DISQueryParamVal instead94 *95 * @param pCpu Pointer to current disassembler context.96 * @param pParam Pointer to parameter of instruction to process.97 * @param pRegFrame Pointer to CPUMCTXCORE guest structure.98 * @param pu64Data Where to store retrieved data.99 * @param pcbSize Where to store the size of data (1, 2, 4, 8).100 */101 bool iomGetRegImmData(PDISCPUSTATE pCpu, PCDISOPPARAM pParam, PCPUMCTXCORE pRegFrame, uint64_t *pu64Data, unsigned *pcbSize)102 {103 NOREF(pCpu);104 if (pParam->fUse & (DISUSE_BASE | DISUSE_INDEX | DISUSE_SCALE | DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32))105 {106 *pcbSize = 0;107 *pu64Data = 0;108 return false;109 }110 111 /* divide and conquer */112 if (pParam->fUse & (DISUSE_REG_GEN64 | DISUSE_REG_GEN32 | DISUSE_REG_GEN16 | DISUSE_REG_GEN8))113 {114 if (pParam->fUse & DISUSE_REG_GEN32)115 {116 *pcbSize = 4;117 DISFetchReg32(pRegFrame, pParam->Base.idxGenReg, (uint32_t *)pu64Data);118 return true;119 }120 121 if (pParam->fUse & DISUSE_REG_GEN16)122 {123 *pcbSize = 2;124 DISFetchReg16(pRegFrame, pParam->Base.idxGenReg, (uint16_t *)pu64Data);125 return true;126 }127 128 if (pParam->fUse & DISUSE_REG_GEN8)129 {130 *pcbSize = 1;131 DISFetchReg8(pRegFrame, pParam->Base.idxGenReg, (uint8_t *)pu64Data);132 return true;133 }134 135 Assert(pParam->fUse & DISUSE_REG_GEN64);136 *pcbSize = 8;137 DISFetchReg64(pRegFrame, pParam->Base.idxGenReg, pu64Data);138 return true;139 }140 else141 {142 if (pParam->fUse & (DISUSE_IMMEDIATE64 | DISUSE_IMMEDIATE64_SX8))143 {144 *pcbSize = 8;145 *pu64Data = pParam->uValue;146 return true;147 }148 149 if (pParam->fUse & (DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE32_SX8))150 {151 *pcbSize = 4;152 *pu64Data = (uint32_t)pParam->uValue;153 return true;154 }155 156 if (pParam->fUse & (DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE16_SX8))157 {158 *pcbSize = 2;159 *pu64Data = (uint16_t)pParam->uValue;160 return true;161 }162 163 if (pParam->fUse & DISUSE_IMMEDIATE8)164 {165 *pcbSize = 1;166 *pu64Data = (uint8_t)pParam->uValue;167 return true;168 }169 170 if (pParam->fUse & DISUSE_REG_SEG)171 {172 *pcbSize = 2;173 DISFetchRegSeg(pRegFrame, (DISSELREG)pParam->Base.idxSegReg, (RTSEL *)pu64Data);174 return true;175 } /* Else - error. */176 177 AssertFailed();178 *pcbSize = 0;179 *pu64Data = 0;180 return false;181 }182 }183 184 185 /**186 * Saves data to 8/16/32 general purpose or segment register defined by187 * instruction's parameter.188 *189 * @returns true on success.190 * @param pCpu Pointer to current disassembler context.191 * @param pParam Pointer to parameter of instruction to process.192 * @param pRegFrame Pointer to CPUMCTXCORE guest structure.193 * @param u64Data 8/16/32/64 bit data to store.194 */195 bool iomSaveDataToReg(PDISCPUSTATE pCpu, PCDISOPPARAM pParam, PCPUMCTXCORE pRegFrame, uint64_t u64Data)196 {197 NOREF(pCpu);198 if (pParam->fUse & (DISUSE_BASE | DISUSE_INDEX | DISUSE_SCALE | DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE32_SX8 | DISUSE_IMMEDIATE16_SX8))199 {200 return false;201 }202 203 if (pParam->fUse & DISUSE_REG_GEN32)204 {205 DISWriteReg32(pRegFrame, pParam->Base.idxGenReg, (uint32_t)u64Data);206 return true;207 }208 209 if (pParam->fUse & DISUSE_REG_GEN64)210 {211 DISWriteReg64(pRegFrame, pParam->Base.idxGenReg, u64Data);212 return true;213 }214 215 if (pParam->fUse & DISUSE_REG_GEN16)216 {217 DISWriteReg16(pRegFrame, pParam->Base.idxGenReg, (uint16_t)u64Data);218 return true;219 }220 221 if (pParam->fUse & DISUSE_REG_GEN8)222 {223 DISWriteReg8(pRegFrame, pParam->Base.idxGenReg, (uint8_t)u64Data);224 return true;225 }226 227 if (pParam->fUse & DISUSE_REG_SEG)228 {229 DISWriteRegSeg(pRegFrame, (DISSELREG)pParam->Base.idxSegReg, (RTSEL)u64Data);230 return true;231 }232 233 /* Else - error. */234 return false;235 }236 237 49 238 50 #ifndef IN_RING3 … … 769 581 770 582 771 #ifndef IEM_USE_IEM_INSTEAD772 773 /**774 * MOV reg, mem (read)775 * MOVZX reg, mem (read)776 * MOVSX reg, mem (read)777 *778 * @returns VBox status code.779 *780 * @param pVM The cross context VM structure.781 * @param pVCpu The cross context virtual CPU structure of the calling EMT.782 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.783 * @param pCpu Disassembler CPU state.784 * @param pRange Pointer MMIO range.785 * @param GCPhysFault The GC physical address corresponding to pvFault.786 */787 static int iomInterpretMOVxXRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu,788 PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault)789 {790 Assert(pRange->CTX_SUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3);791 792 /*793 * Get the data size from parameter 2,794 * and call the handler function to get the data.795 */796 unsigned cb = DISGetParamSize(pCpu, &pCpu->Param2);797 AssertMsg(cb > 0 && cb <= sizeof(uint64_t), ("cb=%d\n", cb));798 799 uint64_t u64Data = 0;800 int rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, &u64Data, cb));801 if (rc == VINF_SUCCESS)802 {803 /*804 * Do sign extension for MOVSX.805 */806 /** @todo checkup MOVSX implementation! */807 if (pCpu->pCurInstr->uOpcode == OP_MOVSX)808 {809 if (cb == 1)810 {811 /* DWORD <- BYTE */812 int64_t iData = (int8_t)u64Data;813 u64Data = (uint64_t)iData;814 }815 else816 {817 /* DWORD <- WORD */818 int64_t iData = (int16_t)u64Data;819 u64Data = (uint64_t)iData;820 }821 }822 823 /*824 * Store the result to register (parameter 1).825 */826 bool fRc = iomSaveDataToReg(pCpu, &pCpu->Param1, pRegFrame, u64Data);827 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);828 }829 830 if (rc == VINF_SUCCESS)831 iomMMIOStatLength(pVM, cb);832 return rc;833 }834 835 836 /**837 * MOV mem, reg|imm (write)838 *839 * @returns VBox status code.840 *841 * @param pVM The cross context VM structure.842 * @param pVCpu The cross context virtual CPU structure of the calling EMT.843 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.844 * @param pCpu Disassembler CPU state.845 * @param pRange Pointer MMIO range.846 * @param GCPhysFault The GC physical address corresponding to pvFault.847 */848 static int iomInterpretMOVxXWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu,849 PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault)850 {851 Assert(pRange->CTX_SUFF(pfnWriteCallback) || !pRange->pfnWriteCallbackR3);852 853 /*854 * Get data to write from second parameter,855 * and call the callback to write it.856 */857 unsigned cb = 0;858 uint64_t u64Data = 0;859 bool fRc = iomGetRegImmData(pCpu, &pCpu->Param2, pRegFrame, &u64Data, &cb);860 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);861 862 int rc = VBOXSTRICTRC_TODO(iomMMIODoWrite(pVM, pVCpu, pRange, GCPhysFault, &u64Data, cb));863 if (rc == VINF_SUCCESS)864 iomMMIOStatLength(pVM, cb);865 return rc;866 }867 868 869 /** Wrapper for reading virtual memory. */870 DECLINLINE(int) iomRamRead(PVMCPU pVCpu, void *pDest, RTGCPTR GCSrc, uint32_t cb)871 {872 /* Note: This will fail in R0 or RC if it hits an access handler. That873 isn't a problem though since the operation can be restarted in REM. */874 #ifdef IN_RC875 NOREF(pVCpu);876 int rc = MMGCRamReadNoTrapHandler(pDest, (void *)(uintptr_t)GCSrc, cb);877 /* Page may be protected and not directly accessible. */878 if (rc == VERR_ACCESS_DENIED)879 rc = VINF_IOM_R3_IOPORT_WRITE;880 return rc;881 #else882 return VBOXSTRICTRC_VAL(PGMPhysReadGCPtr(pVCpu, pDest, GCSrc, cb, PGMACCESSORIGIN_IOM));883 #endif884 }885 886 887 /** Wrapper for writing virtual memory. */888 DECLINLINE(int) iomRamWrite(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, RTGCPTR GCPtrDst, void *pvSrc, uint32_t cb)889 {890 /** @todo Need to update PGMVerifyAccess to take access handlers into account for Ring-0 and891 * raw mode code. Some thought needs to be spent on theoretical concurrency issues as892 * as well since we're not behind the pgm lock and handler may change between calls.893 *894 * PGMPhysInterpretedWriteNoHandlers/PGMPhysWriteGCPtr may mess up895 * the state of some shadowed structures. */896 #if defined(IN_RING0) || defined(IN_RC)897 return PGMPhysInterpretedWriteNoHandlers(pVCpu, pCtxCore, GCPtrDst, pvSrc, cb, false /*fRaiseTrap*/);898 #else899 NOREF(pCtxCore);900 return VBOXSTRICTRC_VAL(PGMPhysWriteGCPtr(pVCpu, GCPtrDst, pvSrc, cb, PGMACCESSORIGIN_IOM));901 #endif902 }903 904 905 #if defined(IOM_WITH_MOVS_SUPPORT) && 0 /* locking prevents this from working. has buggy ecx handling. */906 /**907 * [REP] MOVSB908 * [REP] MOVSW909 * [REP] MOVSD910 *911 * Restricted implementation.912 *913 *914 * @returns VBox status code.915 *916 * @param pVM The cross context VM structure.917 * @param uErrorCode CPU Error code.918 * @param pRegFrame Trap register frame.919 * @param GCPhysFault The GC physical address corresponding to pvFault.920 * @param pCpu Disassembler CPU state.921 * @param pRange Pointer MMIO range.922 * @param ppStat Which sub-sample to attribute this call to.923 */924 static int iomInterpretMOVS(PVM pVM, bool fWriteAccess, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange,925 PSTAMPROFILE *ppStat)926 {927 /*928 * We do not support segment prefixes or REPNE.929 */930 if (pCpu->fPrefix & (DISPREFIX_SEG | DISPREFIX_REPNE))931 return VINF_IOM_R3_MMIO_READ_WRITE; /** @todo -> interpret whatever. */932 933 PVMCPU pVCpu = VMMGetCpu(pVM);934 935 /*936 * Get bytes/words/dwords/qword count to copy.937 */938 uint32_t cTransfers = 1;939 if (pCpu->fPrefix & DISPREFIX_REP)940 {941 #ifndef IN_RC942 if ( CPUMIsGuestIn64BitCode(pVCpu, pRegFrame)943 && pRegFrame->rcx >= _4G)944 return VINF_EM_RAW_EMULATE_INSTR;945 #endif946 947 cTransfers = pRegFrame->ecx;948 if (SELMGetCpuModeFromSelector(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) == DISCPUMODE_16BIT)949 cTransfers &= 0xffff;950 951 if (!cTransfers)952 return VINF_SUCCESS;953 }954 955 /* Get the current privilege level. */956 uint32_t cpl = CPUMGetGuestCPL(pVCpu, pRegFrame);957 958 /*959 * Get data size.960 */961 unsigned cb = DISGetParamSize(pCpu, &pCpu->Param1);962 AssertMsg(cb > 0 && cb <= sizeof(uint64_t), ("cb=%d\n", cb));963 int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cb : (signed)cb;964 965 #ifdef VBOX_WITH_STATISTICS966 if (pVM->iom.s.cMovsMaxBytes < (cTransfers << SIZE_2_SHIFT(cb)))967 pVM->iom.s.cMovsMaxBytes = cTransfers << SIZE_2_SHIFT(cb);968 #endif969 970 /** @todo re-evaluate on page boundaries. */971 972 RTGCPHYS Phys = GCPhysFault;973 int rc;974 if (fWriteAccess)975 {976 /*977 * Write operation: [Mem] -> [MMIO]978 * ds:esi (Virt Src) -> es:edi (Phys Dst)979 */980 STAM_STATS({ *ppStat = &pVM->iom.s.StatRZInstMovsToMMIO; });981 982 /* Check callback. */983 if (!pRange->CTX_SUFF(pfnWriteCallback))984 return VINF_IOM_R3_MMIO_WRITE;985 986 /* Convert source address ds:esi. */987 RTGCUINTPTR pu8Virt;988 rc = SELMToFlatEx(pVM, DISSELREG_DS, pRegFrame, (RTGCPTR)pRegFrame->rsi,989 SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,990 (PRTGCPTR)&pu8Virt);991 if (RT_SUCCESS(rc))992 {993 994 /* Access verification first; we currently can't recover properly from traps inside this instruction */995 rc = PGMVerifyAccess(pVCpu, pu8Virt, cTransfers * cb, (cpl == 3) ? X86_PTE_US : 0);996 if (rc != VINF_SUCCESS)997 {998 Log(("MOVS will generate a trap -> recompiler, rc=%d\n", rc));999 return VINF_EM_RAW_EMULATE_INSTR;1000 }1001 1002 #ifdef IN_RC1003 MMGCRamRegisterTrapHandler(pVM);1004 #endif1005 1006 /* copy loop. */1007 while (cTransfers)1008 {1009 uint32_t u32Data = 0;1010 rc = iomRamRead(pVCpu, &u32Data, (RTGCPTR)pu8Virt, cb);1011 if (rc != VINF_SUCCESS)1012 break;1013 rc = VBOXSTRICTRC_TODO(iomMMIODoWrite(pVM, pRange, Phys, &u32Data, cb));1014 if (rc != VINF_SUCCESS)1015 break;1016 1017 pu8Virt += offIncrement;1018 Phys += offIncrement;1019 pRegFrame->rsi += offIncrement;1020 pRegFrame->rdi += offIncrement;1021 cTransfers--;1022 }1023 #ifdef IN_RC1024 MMGCRamDeregisterTrapHandler(pVM);1025 #endif1026 /* Update ecx. */1027 if (pCpu->fPrefix & DISPREFIX_REP)1028 pRegFrame->ecx = cTransfers;1029 }1030 else1031 rc = VINF_IOM_R3_MMIO_READ_WRITE;1032 }1033 else1034 {1035 /*1036 * Read operation: [MMIO] -> [mem] or [MMIO] -> [MMIO]1037 * ds:[eSI] (Phys Src) -> es:[eDI] (Virt Dst)1038 */1039 STAM_STATS({ *ppStat = &pVM->iom.s.StatRZInstMovsFromMMIO; });1040 1041 /* Check callback. */1042 if (!pRange->CTX_SUFF(pfnReadCallback))1043 return VINF_IOM_R3_MMIO_READ;1044 1045 /* Convert destination address. */1046 RTGCUINTPTR pu8Virt;1047 rc = SELMToFlatEx(pVM, DISSELREG_ES, pRegFrame, (RTGCPTR)pRegFrame->rdi,1048 SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,1049 (RTGCPTR *)&pu8Virt);1050 if (RT_FAILURE(rc))1051 return VINF_IOM_R3_MMIO_READ;1052 1053 /* Check if destination address is MMIO. */1054 PIOMMMIORANGE pMMIODst;1055 RTGCPHYS PhysDst;1056 rc = PGMGstGetPage(pVCpu, (RTGCPTR)pu8Virt, NULL, &PhysDst);1057 PhysDst |= (RTGCUINTPTR)pu8Virt & PAGE_OFFSET_MASK;1058 if ( RT_SUCCESS(rc)1059 && (pMMIODst = iomMmioGetRangeWithRef(pVM, PhysDst)))1060 {1061 /** @todo implement per-device locks for MMIO access. */1062 Assert(!pMMIODst->CTX_SUFF(pDevIns)->CTX_SUFF(pCritSect));1063 1064 /*1065 * Extra: [MMIO] -> [MMIO]1066 */1067 STAM_STATS({ *ppStat = &pVM->iom.s.StatRZInstMovsMMIO; });1068 if (!pMMIODst->CTX_SUFF(pfnWriteCallback) && pMMIODst->pfnWriteCallbackR3)1069 {1070 iomMmioReleaseRange(pVM, pRange);1071 return VINF_IOM_R3_MMIO_READ_WRITE;1072 }1073 1074 /* copy loop. */1075 while (cTransfers)1076 {1077 uint32_t u32Data;1078 rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pRange, Phys, &u32Data, cb));1079 if (rc != VINF_SUCCESS)1080 break;1081 rc = VBOXSTRICTRC_TODO(iomMMIODoWrite(pVM, pMMIODst, PhysDst, &u32Data, cb));1082 if (rc != VINF_SUCCESS)1083 break;1084 1085 Phys += offIncrement;1086 PhysDst += offIncrement;1087 pRegFrame->rsi += offIncrement;1088 pRegFrame->rdi += offIncrement;1089 cTransfers--;1090 }1091 iomMmioReleaseRange(pVM, pRange);1092 }1093 else1094 {1095 /*1096 * Normal: [MMIO] -> [Mem]1097 */1098 /* Access verification first; we currently can't recover properly from traps inside this instruction */1099 rc = PGMVerifyAccess(pVCpu, pu8Virt, cTransfers * cb, X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0));1100 if (rc != VINF_SUCCESS)1101 {1102 Log(("MOVS will generate a trap -> recompiler, rc=%d\n", rc));1103 return VINF_EM_RAW_EMULATE_INSTR;1104 }1105 1106 /* copy loop. */1107 #ifdef IN_RC1108 MMGCRamRegisterTrapHandler(pVM);1109 #endif1110 while (cTransfers)1111 {1112 uint32_t u32Data;1113 rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pRange, Phys, &u32Data, cb));1114 if (rc != VINF_SUCCESS)1115 break;1116 rc = iomRamWrite(pVCpu, pRegFrame, (RTGCPTR)pu8Virt, &u32Data, cb);1117 if (rc != VINF_SUCCESS)1118 {1119 Log(("iomRamWrite %08X size=%d failed with %d\n", pu8Virt, cb, rc));1120 break;1121 }1122 1123 pu8Virt += offIncrement;1124 Phys += offIncrement;1125 pRegFrame->rsi += offIncrement;1126 pRegFrame->rdi += offIncrement;1127 cTransfers--;1128 }1129 #ifdef IN_RC1130 MMGCRamDeregisterTrapHandler(pVM);1131 #endif1132 }1133 1134 /* Update ecx on exit. */1135 if (pCpu->fPrefix & DISPREFIX_REP)1136 pRegFrame->ecx = cTransfers;1137 }1138 1139 /* work statistics. */1140 if (rc == VINF_SUCCESS)1141 iomMMIOStatLength(pVM, cb);1142 NOREF(ppStat);1143 return rc;1144 }1145 #endif /* IOM_WITH_MOVS_SUPPORT */1146 1147 1148 /**1149 * Gets the address / opcode mask corresponding to the given CPU mode.1150 *1151 * @returns Mask.1152 * @param enmCpuMode CPU mode.1153 */1154 static uint64_t iomDisModeToMask(DISCPUMODE enmCpuMode)1155 {1156 switch (enmCpuMode)1157 {1158 case DISCPUMODE_16BIT: return UINT16_MAX;1159 case DISCPUMODE_32BIT: return UINT32_MAX;1160 case DISCPUMODE_64BIT: return UINT64_MAX;1161 default:1162 AssertFailedReturn(UINT32_MAX);1163 }1164 }1165 1166 1167 /**1168 * [REP] STOSB1169 * [REP] STOSW1170 * [REP] STOSD1171 *1172 * Restricted implementation.1173 *1174 *1175 * @returns VBox status code.1176 *1177 * @param pVM The cross context VM structure.1178 * @param pVCpu The cross context virtual CPU structure of the calling EMT.1179 * @param pRegFrame Trap register frame.1180 * @param GCPhysFault The GC physical address corresponding to pvFault.1181 * @param pCpu Disassembler CPU state.1182 * @param pRange Pointer MMIO range.1183 */1184 static int iomInterpretSTOS(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault,1185 PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)1186 {1187 /*1188 * We do not support segment prefixes or REPNE..1189 */1190 if (pCpu->fPrefix & (DISPREFIX_SEG | DISPREFIX_REPNE))1191 return VINF_IOM_R3_MMIO_READ_WRITE; /** @todo -> REM instead of HC */1192 1193 /*1194 * Get bytes/words/dwords/qwords count to copy.1195 */1196 uint64_t const fAddrMask = iomDisModeToMask((DISCPUMODE)pCpu->uAddrMode);1197 RTGCUINTREG cTransfers = 1;1198 if (pCpu->fPrefix & DISPREFIX_REP)1199 {1200 #ifndef IN_RC1201 if ( CPUMIsGuestIn64BitCode(pVCpu)1202 && pRegFrame->rcx >= _4G)1203 return VINF_EM_RAW_EMULATE_INSTR;1204 #endif1205 1206 cTransfers = pRegFrame->rcx & fAddrMask;1207 if (!cTransfers)1208 return VINF_SUCCESS;1209 }1210 1211 /** @todo r=bird: bounds checks! */1212 1213 /*1214 * Get data size.1215 */1216 unsigned cb = DISGetParamSize(pCpu, &pCpu->Param1);1217 AssertMsg(cb > 0 && cb <= sizeof(uint64_t), ("cb=%d\n", cb));1218 int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cb : (signed)cb;1219 1220 #ifdef VBOX_WITH_STATISTICS1221 if (pVM->iom.s.cStosMaxBytes < (cTransfers << SIZE_2_SHIFT(cb)))1222 pVM->iom.s.cStosMaxBytes = cTransfers << SIZE_2_SHIFT(cb);1223 #endif1224 1225 1226 RTGCPHYS Phys = GCPhysFault;1227 int rc;1228 if ( pRange->CTX_SUFF(pfnFillCallback)1229 && cb <= 4 /* can only fill 32-bit values */)1230 {1231 /*1232 * Use the fill callback.1233 */1234 /** @todo pfnFillCallback must return number of bytes successfully written!!! */1235 if (offIncrement > 0)1236 {1237 /* addr++ variant. */1238 rc = pRange->CTX_SUFF(pfnFillCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser), Phys,1239 pRegFrame->eax, cb, cTransfers);1240 if (rc == VINF_SUCCESS)1241 {1242 /* Update registers. */1243 pRegFrame->rdi = ((pRegFrame->rdi + (cTransfers << SIZE_2_SHIFT(cb))) & fAddrMask)1244 | (pRegFrame->rdi & ~fAddrMask);1245 if (pCpu->fPrefix & DISPREFIX_REP)1246 pRegFrame->rcx &= ~fAddrMask;1247 }1248 }1249 else1250 {1251 /* addr-- variant. */1252 rc = pRange->CTX_SUFF(pfnFillCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),1253 Phys - ((cTransfers - 1) << SIZE_2_SHIFT(cb)),1254 pRegFrame->eax, cb, cTransfers);1255 if (rc == VINF_SUCCESS)1256 {1257 /* Update registers. */1258 pRegFrame->rdi = ((pRegFrame->rdi - (cTransfers << SIZE_2_SHIFT(cb))) & fAddrMask)1259 | (pRegFrame->rdi & ~fAddrMask);1260 if (pCpu->fPrefix & DISPREFIX_REP)1261 pRegFrame->rcx &= ~fAddrMask;1262 }1263 }1264 }1265 else1266 {1267 /*1268 * Use the write callback.1269 */1270 Assert(pRange->CTX_SUFF(pfnWriteCallback) || !pRange->pfnWriteCallbackR3);1271 uint64_t u64Data = pRegFrame->rax;1272 1273 /* fill loop. */1274 do1275 {1276 rc = VBOXSTRICTRC_TODO(iomMMIODoWrite(pVM, pVCpu, pRange, Phys, &u64Data, cb));1277 if (rc != VINF_SUCCESS)1278 break;1279 1280 Phys += offIncrement;1281 pRegFrame->rdi = ((pRegFrame->rdi + offIncrement) & fAddrMask)1282 | (pRegFrame->rdi & ~fAddrMask);1283 cTransfers--;1284 } while (cTransfers);1285 1286 /* Update rcx on exit. */1287 if (pCpu->fPrefix & DISPREFIX_REP)1288 pRegFrame->rcx = (cTransfers & fAddrMask)1289 | (pRegFrame->rcx & ~fAddrMask);1290 }1291 1292 /*1293 * Work statistics and return.1294 */1295 if (rc == VINF_SUCCESS)1296 iomMMIOStatLength(pVM, cb);1297 return rc;1298 }1299 1300 1301 /**1302 * [REP] LODSB1303 * [REP] LODSW1304 * [REP] LODSD1305 *1306 * Restricted implementation.1307 *1308 *1309 * @returns VBox status code.1310 *1311 * @param pVM The cross context VM structure.1312 * @param pVCpu The cross context virtual CPU structure of the calling EMT.1313 * @param pRegFrame Trap register frame.1314 * @param GCPhysFault The GC physical address corresponding to pvFault.1315 * @param pCpu Disassembler CPU state.1316 * @param pRange Pointer MMIO range.1317 */1318 static int iomInterpretLODS(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu,1319 PIOMMMIORANGE pRange)1320 {1321 Assert(pRange->CTX_SUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3);1322 1323 /*1324 * We do not support segment prefixes or REP*.1325 */1326 if (pCpu->fPrefix & (DISPREFIX_SEG | DISPREFIX_REP | DISPREFIX_REPNE))1327 return VINF_IOM_R3_MMIO_READ_WRITE; /** @todo -> REM instead of HC */1328 1329 /*1330 * Get data size.1331 */1332 unsigned cb = DISGetParamSize(pCpu, &pCpu->Param2);1333 AssertMsg(cb > 0 && cb <= sizeof(uint64_t), ("cb=%d\n", cb));1334 int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cb : (signed)cb;1335 1336 /*1337 * Perform read.1338 */1339 int rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, &pRegFrame->rax, cb));1340 if (rc == VINF_SUCCESS)1341 {1342 uint64_t const fAddrMask = iomDisModeToMask((DISCPUMODE)pCpu->uAddrMode);1343 pRegFrame->rsi = ((pRegFrame->rsi + offIncrement) & fAddrMask)1344 | (pRegFrame->rsi & ~fAddrMask);1345 }1346 1347 /*1348 * Work statistics and return.1349 */1350 if (rc == VINF_SUCCESS)1351 iomMMIOStatLength(pVM, cb);1352 return rc;1353 }1354 1355 1356 /**1357 * CMP [MMIO], reg|imm1358 * CMP reg|imm, [MMIO]1359 *1360 * Restricted implementation.1361 *1362 *1363 * @returns VBox status code.1364 *1365 * @param pVM The cross context VM structure.1366 * @param pRegFrame Trap register frame.1367 * @param GCPhysFault The GC physical address corresponding to pvFault.1368 * @param pCpu Disassembler CPU state.1369 * @param pRange Pointer MMIO range.1370 */1371 static int iomInterpretCMP(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu,1372 PIOMMMIORANGE pRange)1373 {1374 Assert(pRange->CTX_SUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3);1375 1376 /*1377 * Get the operands.1378 */1379 unsigned cb = 0;1380 uint64_t uData1 = 0;1381 uint64_t uData2 = 0;1382 int rc;1383 if (iomGetRegImmData(pCpu, &pCpu->Param1, pRegFrame, &uData1, &cb))1384 /* cmp reg, [MMIO]. */1385 rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, &uData2, cb));1386 else if (iomGetRegImmData(pCpu, &pCpu->Param2, pRegFrame, &uData2, &cb))1387 /* cmp [MMIO], reg|imm. */1388 rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, &uData1, cb));1389 else1390 {1391 AssertMsgFailed(("Disassember CMP problem..\n"));1392 rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;1393 }1394 1395 if (rc == VINF_SUCCESS)1396 {1397 #if HC_ARCH_BITS == 321398 /* Can't deal with 8 byte operands in our 32-bit emulation code. */1399 if (cb > 4)1400 return VINF_IOM_R3_MMIO_READ_WRITE;1401 #endif1402 /* Emulate CMP and update guest flags. */1403 uint32_t eflags = EMEmulateCmp(uData1, uData2, cb);1404 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))1405 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));1406 iomMMIOStatLength(pVM, cb);1407 }1408 1409 return rc;1410 }1411 1412 1413 /**1414 * AND [MMIO], reg|imm1415 * AND reg, [MMIO]1416 * OR [MMIO], reg|imm1417 * OR reg, [MMIO]1418 *1419 * Restricted implementation.1420 *1421 *1422 * @returns VBox status code.1423 *1424 * @param pVM The cross context VM structure.1425 * @param pVCpu The cross context virtual CPU structure of the calling EMT.1426 * @param pRegFrame Trap register frame.1427 * @param GCPhysFault The GC physical address corresponding to pvFault.1428 * @param pCpu Disassembler CPU state.1429 * @param pRange Pointer MMIO range.1430 * @param pfnEmulate Instruction emulation function.1431 */1432 static int iomInterpretOrXorAnd(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu,1433 PIOMMMIORANGE pRange, PFNEMULATEPARAM3 pfnEmulate)1434 {1435 unsigned cb = 0;1436 uint64_t uData1 = 0;1437 uint64_t uData2 = 0;1438 bool fAndWrite;1439 int rc;1440 1441 #ifdef LOG_ENABLED1442 const char *pszInstr;1443 1444 if (pCpu->pCurInstr->uOpcode == OP_XOR)1445 pszInstr = "Xor";1446 else if (pCpu->pCurInstr->uOpcode == OP_OR)1447 pszInstr = "Or";1448 else if (pCpu->pCurInstr->uOpcode == OP_AND)1449 pszInstr = "And";1450 else1451 pszInstr = "OrXorAnd??";1452 #endif1453 1454 if (iomGetRegImmData(pCpu, &pCpu->Param1, pRegFrame, &uData1, &cb))1455 {1456 #if HC_ARCH_BITS == 321457 /* Can't deal with 8 byte operands in our 32-bit emulation code. */1458 if (cb > 4)1459 return VINF_IOM_R3_MMIO_READ_WRITE;1460 #endif1461 /* and reg, [MMIO]. */1462 Assert(pRange->CTX_SUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3);1463 fAndWrite = false;1464 rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, &uData2, cb));1465 }1466 else if (iomGetRegImmData(pCpu, &pCpu->Param2, pRegFrame, &uData2, &cb))1467 {1468 #if HC_ARCH_BITS == 321469 /* Can't deal with 8 byte operands in our 32-bit emulation code. */1470 if (cb > 4)1471 return VINF_IOM_R3_MMIO_READ_WRITE;1472 #endif1473 /* and [MMIO], reg|imm. */1474 fAndWrite = true;1475 if ( (pRange->CTX_SUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3)1476 && (pRange->CTX_SUFF(pfnWriteCallback) || !pRange->pfnWriteCallbackR3))1477 rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, &uData1, cb));1478 else1479 rc = VINF_IOM_R3_MMIO_READ_WRITE;1480 }1481 else1482 {1483 AssertMsgFailed(("Disassember AND problem..\n"));1484 return VERR_IOM_MMIO_HANDLER_DISASM_ERROR;1485 }1486 1487 if (rc == VINF_SUCCESS)1488 {1489 /* Emulate AND and update guest flags. */1490 uint32_t eflags = pfnEmulate((uint32_t *)&uData1, uData2, cb);1491 1492 LogFlow(("iomInterpretOrXorAnd %s result %RX64\n", pszInstr, uData1));1493 1494 if (fAndWrite)1495 /* Store result to MMIO. */1496 rc = VBOXSTRICTRC_TODO(iomMMIODoWrite(pVM, pVCpu, pRange, GCPhysFault, &uData1, cb));1497 else1498 {1499 /* Store result to register. */1500 bool fRc = iomSaveDataToReg(pCpu, &pCpu->Param1, pRegFrame, uData1);1501 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);1502 }1503 if (rc == VINF_SUCCESS)1504 {1505 /* Update guest's eflags and finish. */1506 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))1507 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));1508 iomMMIOStatLength(pVM, cb);1509 }1510 }1511 1512 return rc;1513 }1514 1515 1516 /**1517 * TEST [MMIO], reg|imm1518 * TEST reg, [MMIO]1519 *1520 * Restricted implementation.1521 *1522 *1523 * @returns VBox status code.1524 *1525 * @param pVM The cross context VM structure.1526 * @param pVCpu The cross context virtual CPU structure of the calling EMT.1527 * @param pRegFrame Trap register frame.1528 * @param GCPhysFault The GC physical address corresponding to pvFault.1529 * @param pCpu Disassembler CPU state.1530 * @param pRange Pointer MMIO range.1531 */1532 static int iomInterpretTEST(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu,1533 PIOMMMIORANGE pRange)1534 {1535 Assert(pRange->CTX_SUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3);1536 1537 unsigned cb = 0;1538 uint64_t uData1 = 0;1539 uint64_t uData2 = 0;1540 int rc;1541 1542 if (iomGetRegImmData(pCpu, &pCpu->Param1, pRegFrame, &uData1, &cb))1543 {1544 /* and test, [MMIO]. */1545 rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, &uData2, cb));1546 }1547 else if (iomGetRegImmData(pCpu, &pCpu->Param2, pRegFrame, &uData2, &cb))1548 {1549 /* test [MMIO], reg|imm. */1550 rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, &uData1, cb));1551 }1552 else1553 {1554 AssertMsgFailed(("Disassember TEST problem..\n"));1555 return VERR_IOM_MMIO_HANDLER_DISASM_ERROR;1556 }1557 1558 if (rc == VINF_SUCCESS)1559 {1560 #if HC_ARCH_BITS == 321561 /* Can't deal with 8 byte operands in our 32-bit emulation code. */1562 if (cb > 4)1563 return VINF_IOM_R3_MMIO_READ_WRITE;1564 #endif1565 1566 /* Emulate TEST (=AND without write back) and update guest EFLAGS. */1567 uint32_t eflags = EMEmulateAnd((uint32_t *)&uData1, uData2, cb);1568 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))1569 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));1570 iomMMIOStatLength(pVM, cb);1571 }1572 1573 return rc;1574 }1575 1576 1577 /**1578 * BT [MMIO], reg|imm1579 *1580 * Restricted implementation.1581 *1582 *1583 * @returns VBox status code.1584 *1585 * @param pVM The cross context VM structure.1586 * @param pVCpu The cross context virtual CPU structure of the calling EMT.1587 * @param pRegFrame Trap register frame.1588 * @param GCPhysFault The GC physical address corresponding to pvFault.1589 * @param pCpu Disassembler CPU state.1590 * @param pRange Pointer MMIO range.1591 */1592 static int iomInterpretBT(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu,1593 PIOMMMIORANGE pRange)1594 {1595 Assert(pRange->CTX_SUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3);1596 1597 uint64_t uBit = 0;1598 uint64_t uData = 0;1599 unsigned cbIgnored;1600 1601 if (!iomGetRegImmData(pCpu, &pCpu->Param2, pRegFrame, &uBit, &cbIgnored))1602 {1603 AssertMsgFailed(("Disassember BT problem..\n"));1604 return VERR_IOM_MMIO_HANDLER_DISASM_ERROR;1605 }1606 /* The size of the memory operand only matters here. */1607 unsigned cbData = DISGetParamSize(pCpu, &pCpu->Param1);1608 1609 /* bt [MMIO], reg|imm. */1610 int rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, &uData, cbData));1611 if (rc == VINF_SUCCESS)1612 {1613 /* Find the bit inside the faulting address */1614 pRegFrame->eflags.Bits.u1CF = (uData >> uBit);1615 iomMMIOStatLength(pVM, cbData);1616 }1617 1618 return rc;1619 }1620 1621 /**1622 * XCHG [MMIO], reg1623 * XCHG reg, [MMIO]1624 *1625 * Restricted implementation.1626 *1627 *1628 * @returns VBox status code.1629 *1630 * @param pVM The cross context VM structure.1631 * @param pVCpu The cross context virtual CPU structure of the calling EMT.1632 * @param pRegFrame Trap register frame.1633 * @param GCPhysFault The GC physical address corresponding to pvFault.1634 * @param pCpu Disassembler CPU state.1635 * @param pRange Pointer MMIO range.1636 */1637 static int iomInterpretXCHG(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu,1638 PIOMMMIORANGE pRange)1639 {1640 /* Check for read & write handlers since IOMMMIOHandler doesn't cover this. */1641 if ( (!pRange->CTX_SUFF(pfnReadCallback) && pRange->pfnReadCallbackR3)1642 || (!pRange->CTX_SUFF(pfnWriteCallback) && pRange->pfnWriteCallbackR3))1643 return VINF_IOM_R3_MMIO_READ_WRITE;1644 1645 int rc;1646 unsigned cb = 0;1647 uint64_t uData1 = 0;1648 uint64_t uData2 = 0;1649 if (iomGetRegImmData(pCpu, &pCpu->Param1, pRegFrame, &uData1, &cb))1650 {1651 /* xchg reg, [MMIO]. */1652 rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, &uData2, cb));1653 if (rc == VINF_SUCCESS)1654 {1655 /* Store result to MMIO. */1656 rc = VBOXSTRICTRC_TODO(iomMMIODoWrite(pVM, pVCpu, pRange, GCPhysFault, &uData1, cb));1657 1658 if (rc == VINF_SUCCESS)1659 {1660 /* Store result to register. */1661 bool fRc = iomSaveDataToReg(pCpu, &pCpu->Param1, pRegFrame, uData2);1662 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);1663 }1664 else1665 Assert(rc == VINF_IOM_R3_MMIO_WRITE || rc == VINF_PATM_HC_MMIO_PATCH_WRITE);1666 }1667 else1668 Assert(rc == VINF_IOM_R3_MMIO_READ || rc == VINF_PATM_HC_MMIO_PATCH_READ);1669 }1670 else if (iomGetRegImmData(pCpu, &pCpu->Param2, pRegFrame, &uData2, &cb))1671 {1672 /* xchg [MMIO], reg. */1673 rc = VBOXSTRICTRC_TODO(iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, &uData1, cb));1674 if (rc == VINF_SUCCESS)1675 {1676 /* Store result to MMIO. */1677 rc = VBOXSTRICTRC_TODO(iomMMIODoWrite(pVM, pVCpu, pRange, GCPhysFault, &uData2, cb));1678 if (rc == VINF_SUCCESS)1679 {1680 /* Store result to register. */1681 bool fRc = iomSaveDataToReg(pCpu, &pCpu->Param2, pRegFrame, uData1);1682 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);1683 }1684 else1685 AssertMsg(rc == VINF_IOM_R3_MMIO_READ_WRITE || rc == VINF_IOM_R3_MMIO_WRITE || rc == VINF_PATM_HC_MMIO_PATCH_WRITE || rc == VINF_EM_RAW_EMULATE_IO_BLOCK, ("rc=%Rrc\n", rc));1686 }1687 else1688 AssertMsg(rc == VINF_IOM_R3_MMIO_READ_WRITE || rc == VINF_IOM_R3_MMIO_READ || rc == VINF_PATM_HC_MMIO_PATCH_READ || rc == VINF_EM_RAW_EMULATE_IO_BLOCK, ("rc=%Rrc\n", rc));1689 }1690 else1691 {1692 AssertMsgFailed(("Disassember XCHG problem..\n"));1693 rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;1694 }1695 return rc;1696 }1697 1698 #endif /* !IEM_USE_IEM_INSTEAD */1699 583 1700 584 /** … … 1787 671 } 1788 672 1789 #ifdef IEM_USE_IEM_INSTEAD1790 1791 673 /* 1792 674 * Let IEM call us back via iomMmioHandler. … … 1807 689 } 1808 690 return rcStrict; 1809 1810 #else1811 1812 /*1813 * Disassemble the instruction and interpret it.1814 */1815 PDISCPUSTATE pDis = &pVCpu->iom.s.DisState;1816 unsigned cbOp;1817 rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, &cbOp);1818 if (RT_FAILURE(rc))1819 {1820 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));1821 iomMmioReleaseRange(pVM, pRange);1822 return rc;1823 }1824 switch (pDis->pCurInstr->uOpcode)1825 {1826 case OP_MOV:1827 case OP_MOVZX:1828 case OP_MOVSX:1829 {1830 STAM_PROFILE_START(&pVM->iom.s.StatRZInstMov, b);1831 AssertMsg(uErrorCode == UINT32_MAX || DISUSE_IS_EFFECTIVE_ADDR(pDis->Param1.fUse) == !!(uErrorCode & X86_TRAP_PF_RW), ("flags1=%#llx/%RTbool flags2=%#llx/%RTbool ErrCd=%#x\n", pDis->Param1.fUse, DISUSE_IS_EFFECTIVE_ADDR(pDis->Param1.fUse), pDis->Param2.fUse, DISUSE_IS_EFFECTIVE_ADDR(pDis->Param2.fUse), uErrorCode));1832 if (uErrorCode != UINT32_MAX /* EPT+MMIO optimization */1833 ? uErrorCode & X86_TRAP_PF_RW1834 : DISUSE_IS_EFFECTIVE_ADDR(pDis->Param1.fUse))1835 rc = iomInterpretMOVxXWrite(pVM, pVCpu, pCtxCore, pDis, pRange, GCPhysFault);1836 else1837 rc = iomInterpretMOVxXRead(pVM, pVCpu, pCtxCore, pDis, pRange, GCPhysFault);1838 STAM_PROFILE_STOP(&pVM->iom.s.StatRZInstMov, b);1839 break;1840 }1841 1842 1843 # ifdef IOM_WITH_MOVS_SUPPORT1844 case OP_MOVSB:1845 case OP_MOVSWD:1846 {1847 if (uErrorCode == UINT32_MAX)1848 rc = VINF_IOM_R3_MMIO_READ_WRITE;1849 else1850 {1851 STAM_PROFILE_ADV_START(&pVM->iom.s.StatRZInstMovs, c);1852 PSTAMPROFILE pStat = NULL;1853 rc = iomInterpretMOVS(pVM, !!(uErrorCode & X86_TRAP_PF_RW), pCtxCore, GCPhysFault, pDis, pRange, &pStat);1854 STAM_PROFILE_ADV_STOP_EX(&pVM->iom.s.StatRZInstMovs, pStat, c);1855 }1856 break;1857 }1858 # endif1859 1860 case OP_STOSB:1861 case OP_STOSWD:1862 Assert(uErrorCode & X86_TRAP_PF_RW);1863 STAM_PROFILE_START(&pVM->iom.s.StatRZInstStos, d);1864 rc = iomInterpretSTOS(pVM, pVCpu, pCtxCore, GCPhysFault, pDis, pRange);1865 STAM_PROFILE_STOP(&pVM->iom.s.StatRZInstStos, d);1866 break;1867 1868 case OP_LODSB:1869 case OP_LODSWD:1870 Assert(!(uErrorCode & X86_TRAP_PF_RW) || uErrorCode == UINT32_MAX);1871 STAM_PROFILE_START(&pVM->iom.s.StatRZInstLods, e);1872 rc = iomInterpretLODS(pVM, pVCpu, pCtxCore, GCPhysFault, pDis, pRange);1873 STAM_PROFILE_STOP(&pVM->iom.s.StatRZInstLods, e);1874 break;1875 1876 case OP_CMP:1877 Assert(!(uErrorCode & X86_TRAP_PF_RW) || uErrorCode == UINT32_MAX);1878 STAM_PROFILE_START(&pVM->iom.s.StatRZInstCmp, f);1879 rc = iomInterpretCMP(pVM, pVCpu, pCtxCore, GCPhysFault, pDis, pRange);1880 STAM_PROFILE_STOP(&pVM->iom.s.StatRZInstCmp, f);1881 break;1882 1883 case OP_AND:1884 STAM_PROFILE_START(&pVM->iom.s.StatRZInstAnd, g);1885 rc = iomInterpretOrXorAnd(pVM, pVCpu, pCtxCore, GCPhysFault, pDis, pRange, EMEmulateAnd);1886 STAM_PROFILE_STOP(&pVM->iom.s.StatRZInstAnd, g);1887 break;1888 1889 case OP_OR:1890 STAM_PROFILE_START(&pVM->iom.s.StatRZInstOr, k);1891 rc = iomInterpretOrXorAnd(pVM, pVCpu, pCtxCore, GCPhysFault, pDis, pRange, EMEmulateOr);1892 STAM_PROFILE_STOP(&pVM->iom.s.StatRZInstOr, k);1893 break;1894 1895 case OP_XOR:1896 STAM_PROFILE_START(&pVM->iom.s.StatRZInstXor, m);1897 rc = iomInterpretOrXorAnd(pVM, pVCpu, pCtxCore, GCPhysFault, pDis, pRange, EMEmulateXor);1898 STAM_PROFILE_STOP(&pVM->iom.s.StatRZInstXor, m);1899 break;1900 1901 case OP_TEST:1902 Assert(!(uErrorCode & X86_TRAP_PF_RW) || uErrorCode == UINT32_MAX);1903 STAM_PROFILE_START(&pVM->iom.s.StatRZInstTest, h);1904 rc = iomInterpretTEST(pVM, pVCpu, pCtxCore, GCPhysFault, pDis, pRange);1905 STAM_PROFILE_STOP(&pVM->iom.s.StatRZInstTest, h);1906 break;1907 1908 case OP_BT:1909 Assert(!(uErrorCode & X86_TRAP_PF_RW) || uErrorCode == UINT32_MAX);1910 STAM_PROFILE_START(&pVM->iom.s.StatRZInstBt, l);1911 rc = iomInterpretBT(pVM, pVCpu, pCtxCore, GCPhysFault, pDis, pRange);1912 STAM_PROFILE_STOP(&pVM->iom.s.StatRZInstBt, l);1913 break;1914 1915 case OP_XCHG:1916 STAM_PROFILE_START(&pVM->iom.s.StatRZInstXchg, i);1917 rc = iomInterpretXCHG(pVM, pVCpu, pCtxCore, GCPhysFault, pDis, pRange);1918 STAM_PROFILE_STOP(&pVM->iom.s.StatRZInstXchg, i);1919 break;1920 1921 1922 /*1923 * The instruction isn't supported. Hand it on to ring-3.1924 */1925 default:1926 STAM_COUNTER_INC(&pVM->iom.s.StatRZInstOther);1927 rc = VINF_IOM_R3_MMIO_READ_WRITE;1928 break;1929 }1930 1931 /*1932 * On success advance EIP.1933 */1934 if (rc == VINF_SUCCESS)1935 pCtxCore->rip += cbOp;1936 else1937 {1938 STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOFailures);1939 # if defined(VBOX_WITH_STATISTICS) && !defined(IN_RING3)1940 switch (rc)1941 {1942 case VINF_IOM_R3_MMIO_READ:1943 case VINF_IOM_R3_MMIO_READ_WRITE:1944 STAM_COUNTER_INC(&pStats->CTX_MID_Z(Read,ToR3));1945 break;1946 case VINF_IOM_R3_MMIO_WRITE:1947 STAM_COUNTER_INC(&pStats->CTX_MID_Z(Write,ToR3));1948 break;1949 }1950 # endif1951 }1952 1953 STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);1954 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));1955 iomMmioReleaseRange(pVM, pRange);1956 return rc;1957 #endif /* !IEM_USE_IEM_INSTEAD */1958 691 } 1959 692 … … 2353 1086 2354 1087 #endif /* IN_RING3 - only used by REM. */ 2355 #ifndef IEM_USE_IEM_INSTEAD2356 2357 /**2358 * [REP*] INSB/INSW/INSD2359 * ES:EDI,DX[,ECX]2360 *2361 * @remark Assumes caller checked the access privileges (IOMInterpretCheckPortIOAccess)2362 *2363 * @returns Strict VBox status code. Informational status codes other than the one documented2364 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.2365 * @retval VINF_SUCCESS Success.2366 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the2367 * status code must be passed on to EM.2368 * @retval VINF_IOM_R3_IOPORT_READ Defer the read to ring-3. (R0/GC only)2369 * @retval VINF_EM_RAW_EMULATE_INSTR Defer the read to the REM.2370 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)2371 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)2372 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)2373 *2374 * @param pVM The cross context VM structure.2375 * @param pVCpu The cross context virtual CPU structure of the calling EMT.2376 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.2377 * @param uPort IO Port2378 * @param uPrefix IO instruction prefix2379 * @param enmAddrMode The address mode.2380 * @param cbTransfer Size of transfer unit2381 */2382 VMMDECL(VBOXSTRICTRC) IOMInterpretINSEx(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix,2383 DISCPUMODE enmAddrMode, uint32_t cbTransfer)2384 {2385 STAM_COUNTER_INC(&pVM->iom.s.StatInstIns);2386 Assert(pVCpu->iom.s.PendingMmioWrite.cbValue == 0);2387 2388 /*2389 * We do not support REPNE or decrementing destination2390 * pointer. Segment prefixes are deliberately ignored, as per the instruction specification.2391 */2392 if ( (uPrefix & DISPREFIX_REPNE)2393 || pRegFrame->eflags.Bits.u1DF)2394 return VINF_EM_RAW_EMULATE_INSTR;2395 2396 /*2397 * Get bytes/words/dwords count to transfer.2398 */2399 uint64_t const fAddrMask = iomDisModeToMask(enmAddrMode);2400 RTGCUINTREG cTransfers = 1;2401 if (uPrefix & DISPREFIX_REP)2402 {2403 #ifndef IN_RC2404 if ( CPUMIsGuestIn64BitCode(pVCpu)2405 && pRegFrame->rcx >= _4G)2406 return VINF_EM_RAW_EMULATE_INSTR;2407 #endif2408 cTransfers = pRegFrame->rcx & fAddrMask;2409 if (!cTransfers)2410 return VINF_SUCCESS;2411 }2412 2413 /* Convert destination address es:edi. */2414 RTGCPTR GCPtrDst;2415 int rc2 = SELMToFlatEx(pVCpu, DISSELREG_ES, pRegFrame, pRegFrame->rdi & fAddrMask,2416 SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,2417 &GCPtrDst);2418 if (RT_FAILURE(rc2))2419 {2420 Log(("INS destination address conversion failed -> fallback, rc2=%d\n", rc2));2421 return VINF_EM_RAW_EMULATE_INSTR;2422 }2423 2424 /* Access verification first; we can't recover from traps inside this instruction, as the port read cannot be repeated. */2425 uint32_t const cpl = CPUMGetGuestCPL(pVCpu);2426 rc2 = PGMVerifyAccess(pVCpu, (RTGCUINTPTR)GCPtrDst, cTransfers * cbTransfer,2427 X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0));2428 if (rc2 != VINF_SUCCESS)2429 {2430 Log(("INS will generate a trap -> fallback, rc2=%d\n", rc2));2431 return VINF_EM_RAW_EMULATE_INSTR;2432 }2433 2434 Log(("IOM: rep ins%d port %#x count %d\n", cbTransfer * 8, uPort, cTransfers));2435 VBOXSTRICTRC rcStrict = VINF_SUCCESS;2436 if (cTransfers > 1)2437 {2438 /*2439 * Work the string page by page, letting the device handle as much2440 * as it likes via the string I/O interface.2441 */2442 for (;;)2443 {2444 PGMPAGEMAPLOCK Lock;2445 void *pvDst;2446 rc2 = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrDst, &pvDst, &Lock);2447 if (RT_SUCCESS(rc2))2448 {2449 uint32_t cMaxThisTime = (PAGE_SIZE - (GCPtrDst & PAGE_OFFSET_MASK)) / cbTransfer;2450 if (cMaxThisTime > cTransfers)2451 cMaxThisTime = cTransfers;2452 if (!cMaxThisTime)2453 break;2454 uint32_t cThisTime = cMaxThisTime;2455 2456 rcStrict = IOMIOPortReadString(pVM, pVCpu, uPort, pvDst, &cThisTime, cbTransfer);2457 AssertRC(VBOXSTRICTRC_VAL(rcStrict));2458 Assert(cThisTime <= cMaxThisTime); /* cThisTime is now how many transfers we have left. */2459 2460 uint32_t const cActual = cMaxThisTime - cThisTime;2461 if (cActual)2462 { /* Must dirty the page. */2463 uint8_t b = *(uint8_t *)pvDst;2464 iomRamWrite(pVCpu, pRegFrame, GCPtrDst, &b, 1);2465 }2466 2467 PGMPhysReleasePageMappingLock(pVM, &Lock);2468 2469 uint32_t const cbActual = cActual * cbTransfer;2470 cTransfers -= cActual;2471 pRegFrame->rdi = ((pRegFrame->rdi + cbActual) & fAddrMask)2472 | (pRegFrame->rdi & ~fAddrMask);2473 GCPtrDst += cbActual;2474 2475 if ( cThisTime2476 || !cTransfers2477 || rcStrict != VINF_SUCCESS2478 || (GCPtrDst & PAGE_OFFSET_MASK))2479 break;2480 }2481 else2482 {2483 Log(("IOMInterpretOUTSEx: PGMPhysGCPtr2CCPtr %#RGv -> %Rrc\n", GCPtrDst, rc2));2484 break;2485 }2486 }2487 }2488 2489 /*2490 * Single transfer / unmapped memory fallback.2491 */2492 #ifdef IN_RC2493 MMGCRamRegisterTrapHandler(pVM);2494 #endif2495 while (cTransfers && rcStrict == VINF_SUCCESS)2496 {2497 uint32_t u32Value;2498 rcStrict = IOMIOPortRead(pVM, pVCpu, uPort, &u32Value, cbTransfer);2499 if (!IOM_SUCCESS(rcStrict))2500 break;2501 rc2 = iomRamWrite(pVCpu, pRegFrame, GCPtrDst, &u32Value, cbTransfer);2502 Assert(rc2 == VINF_SUCCESS); NOREF(rc2);2503 GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + cbTransfer);2504 pRegFrame->rdi = ((pRegFrame->rdi + cbTransfer) & fAddrMask)2505 | (pRegFrame->rdi & ~fAddrMask);2506 cTransfers--;2507 }2508 #ifdef IN_RC2509 MMGCRamDeregisterTrapHandler(pVM);2510 #endif2511 2512 /* Update rcx on exit. */2513 if (uPrefix & DISPREFIX_REP)2514 pRegFrame->rcx = (cTransfers & fAddrMask)2515 | (pRegFrame->rcx & ~fAddrMask);2516 2517 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IOM_R3_IOPORT_READ || (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST) || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));2518 return rcStrict;2519 }2520 2521 2522 /**2523 * [REP*] OUTSB/OUTSW/OUTSD2524 * DS:ESI,DX[,ECX]2525 *2526 * @remark Assumes caller checked the access privileges (IOMInterpretCheckPortIOAccess)2527 *2528 * @returns Strict VBox status code. Informational status codes other than the one documented2529 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.2530 * @retval VINF_SUCCESS Success.2531 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the2532 * status code must be passed on to EM.2533 * @retval VINF_IOM_R3_IOPORT_WRITE Defer the write to ring-3. (R0/GC only)2534 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)2535 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)2536 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)2537 *2538 * @param pVM The cross context VM structure.2539 * @param pVCpu The cross context virtual CPU structure of the calling EMT.2540 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.2541 * @param uPort IO Port2542 * @param uPrefix IO instruction prefix2543 * @param enmAddrMode The address mode.2544 * @param cbTransfer Size of transfer unit2545 *2546 * @remarks This API will probably be relaced by IEM before long, so no use in2547 * optimizing+fixing stuff too much here.2548 */2549 VMMDECL(VBOXSTRICTRC) IOMInterpretOUTSEx(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix,2550 DISCPUMODE enmAddrMode, uint32_t cbTransfer)2551 {2552 STAM_COUNTER_INC(&pVM->iom.s.StatInstOuts);2553 Assert(pVCpu->iom.s.PendingMmioWrite.cbValue == 0);2554 2555 /*2556 * We do not support segment prefixes, REPNE or2557 * decrementing source pointer.2558 */2559 if ( (uPrefix & (DISPREFIX_SEG | DISPREFIX_REPNE))2560 || pRegFrame->eflags.Bits.u1DF)2561 return VINF_EM_RAW_EMULATE_INSTR;2562 2563 /*2564 * Get bytes/words/dwords count to transfer.2565 */2566 uint64_t const fAddrMask = iomDisModeToMask(enmAddrMode);2567 RTGCUINTREG cTransfers = 1;2568 if (uPrefix & DISPREFIX_REP)2569 {2570 #ifndef IN_RC2571 if ( CPUMIsGuestIn64BitCode(pVCpu)2572 && pRegFrame->rcx >= _4G)2573 return VINF_EM_RAW_EMULATE_INSTR;2574 #endif2575 cTransfers = pRegFrame->rcx & fAddrMask;2576 if (!cTransfers)2577 return VINF_SUCCESS;2578 }2579 2580 /* Convert source address ds:esi. */2581 RTGCPTR GCPtrSrc;2582 int rc2 = SELMToFlatEx(pVCpu, DISSELREG_DS, pRegFrame, pRegFrame->rsi & fAddrMask,2583 SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,2584 &GCPtrSrc);2585 if (RT_FAILURE(rc2))2586 {2587 Log(("OUTS source address conversion failed -> fallback, rc2=%Rrc\n", rc2));2588 return VINF_EM_RAW_EMULATE_INSTR;2589 }2590 2591 /* Access verification first; we currently can't recover properly from traps inside this instruction */2592 uint32_t const cpl = CPUMGetGuestCPL(pVCpu);2593 rc2 = PGMVerifyAccess(pVCpu, (RTGCUINTPTR)GCPtrSrc, cTransfers * cbTransfer,2594 (cpl == 3) ? X86_PTE_US : 0);2595 if (rc2 != VINF_SUCCESS)2596 {2597 Log(("OUTS will generate a trap -> fallback, rc2=%Rrc\n", rc2));2598 return VINF_EM_RAW_EMULATE_INSTR;2599 }2600 2601 Log(("IOM: rep outs%d port %#x count %d\n", cbTransfer * 8, uPort, cTransfers));2602 VBOXSTRICTRC rcStrict = VINF_SUCCESS;2603 if (cTransfers > 1)2604 {2605 /*2606 * Work the string page by page, letting the device handle as much2607 * as it likes via the string I/O interface.2608 */2609 for (;;)2610 {2611 PGMPAGEMAPLOCK Lock;2612 void const *pvSrc;2613 rc2 = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, GCPtrSrc, &pvSrc, &Lock);2614 if (RT_SUCCESS(rc2))2615 {2616 uint32_t cMaxThisTime = (PAGE_SIZE - (GCPtrSrc & PAGE_OFFSET_MASK)) / cbTransfer;2617 if (cMaxThisTime > cTransfers)2618 cMaxThisTime = cTransfers;2619 if (!cMaxThisTime)2620 break;2621 uint32_t cThisTime = cMaxThisTime;2622 2623 rcStrict = IOMIOPortWriteString(pVM, pVCpu, uPort, pvSrc, &cThisTime, cbTransfer);2624 AssertRC(VBOXSTRICTRC_VAL(rcStrict));2625 Assert(cThisTime <= cMaxThisTime); /* cThisTime is now how many transfers we have left. */2626 2627 PGMPhysReleasePageMappingLock(pVM, &Lock);2628 2629 uint32_t const cActual = cMaxThisTime - cThisTime;2630 uint32_t const cbActual = cActual * cbTransfer;2631 cTransfers -= cActual;2632 pRegFrame->rsi = ((pRegFrame->rsi + cbActual) & fAddrMask)2633 | (pRegFrame->rsi & ~fAddrMask);2634 GCPtrSrc += cbActual;2635 2636 if ( cThisTime2637 || !cTransfers2638 || rcStrict != VINF_SUCCESS2639 || (GCPtrSrc & PAGE_OFFSET_MASK))2640 break;2641 }2642 else2643 {2644 Log(("IOMInterpretOUTSEx: PGMPhysGCPtr2CCPtrReadOnly %#RGv -> %Rrc\n", GCPtrSrc, rc2));2645 break;2646 }2647 }2648 }2649 2650 /*2651 * Single transfer / unmapped memory fallback.2652 */2653 #ifdef IN_RC2654 MMGCRamRegisterTrapHandler(pVM);2655 #endif2656 2657 while (cTransfers && rcStrict == VINF_SUCCESS)2658 {2659 uint32_t u32Value = 0;2660 rcStrict = iomRamRead(pVCpu, &u32Value, GCPtrSrc, cbTransfer);2661 if (rcStrict != VINF_SUCCESS)2662 break;2663 rcStrict = IOMIOPortWrite(pVM, pVCpu, uPort, u32Value, cbTransfer);2664 if (!IOM_SUCCESS(rcStrict))2665 break;2666 GCPtrSrc = (RTGCPTR)((RTUINTPTR)GCPtrSrc + cbTransfer);2667 pRegFrame->rsi = ((pRegFrame->rsi + cbTransfer) & fAddrMask)2668 | (pRegFrame->rsi & ~fAddrMask);2669 cTransfers--;2670 }2671 2672 #ifdef IN_RC2673 MMGCRamDeregisterTrapHandler(pVM);2674 #endif2675 2676 /* Update rcx on exit. */2677 if (uPrefix & DISPREFIX_REP)2678 pRegFrame->rcx = (cTransfers & fAddrMask)2679 | (pRegFrame->rcx & ~fAddrMask);2680 2681 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IOM_R3_IOPORT_WRITE || (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST) || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));2682 return rcStrict;2683 }2684 2685 #endif /* !IEM_USE_IEM_INSTEAD */2686 2687 2688 1088 #ifndef IN_RC 2689 1089
Note:
See TracChangeset
for help on using the changeset viewer.