VirtualBox

Ignore:
Timestamp:
May 7, 2016 5:55:21 PM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
107086
Message:

IOMRC.cpp,++: Use IEM for IN and OUT too, cleaning out unnecessary code.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp

    r60854 r60874  
    4747
    4848
    49 /*********************************************************************************************************************************
    50 *   Defined Constants And Macros                                                                                                 *
    51 *********************************************************************************************************************************/
    52 /** @def IEM_USE_IEM_INSTEAD
    53  * 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 3rd
    55  * 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_INSTEAD
    59 #endif
    60 
    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 instead
    94  *
    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     else
    141     {
    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 by
    187  * 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 
    23749
    23850#ifndef IN_RING3
     
    769581
    770582
    771 #ifndef IEM_USE_IEM_INSTEAD
    772 
    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             else
    816             {
    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. That
    873              isn't a problem though since the operation can be restarted in REM. */
    874 #ifdef IN_RC
    875     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 #else
    882     return VBOXSTRICTRC_VAL(PGMPhysReadGCPtr(pVCpu, pDest, GCSrc, cb, PGMACCESSORIGIN_IOM));
    883 #endif
    884 }
    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 and
    891      *        raw mode code. Some thought needs to be spent on theoretical concurrency issues as
    892      *        as well since we're not behind the pgm lock and handler may change between calls.
    893      *
    894      *        PGMPhysInterpretedWriteNoHandlers/PGMPhysWriteGCPtr may mess up
    895      *        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 #else
    899     NOREF(pCtxCore);
    900     return VBOXSTRICTRC_VAL(PGMPhysWriteGCPtr(pVCpu, GCPtrDst, pvSrc, cb, PGMACCESSORIGIN_IOM));
    901 #endif
    902 }
    903 
    904 
    905 #if defined(IOM_WITH_MOVS_SUPPORT) && 0 /* locking prevents this from working. has buggy ecx handling. */
    906 /**
    907  * [REP] MOVSB
    908  * [REP] MOVSW
    909  * [REP] MOVSD
    910  *
    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_RC
    942         if (    CPUMIsGuestIn64BitCode(pVCpu, pRegFrame)
    943             &&  pRegFrame->rcx >= _4G)
    944             return VINF_EM_RAW_EMULATE_INSTR;
    945 #endif
    946 
    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_STATISTICS
    966     if (pVM->iom.s.cMovsMaxBytes < (cTransfers << SIZE_2_SHIFT(cb)))
    967         pVM->iom.s.cMovsMaxBytes = cTransfers << SIZE_2_SHIFT(cb);
    968 #endif
    969 
    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_RC
    1003             MMGCRamRegisterTrapHandler(pVM);
    1004 #endif
    1005 
    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_RC
    1024             MMGCRamDeregisterTrapHandler(pVM);
    1025 #endif
    1026             /* Update ecx. */
    1027             if (pCpu->fPrefix & DISPREFIX_REP)
    1028                 pRegFrame->ecx = cTransfers;
    1029         }
    1030         else
    1031             rc = VINF_IOM_R3_MMIO_READ_WRITE;
    1032     }
    1033     else
    1034     {
    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         else
    1094         {
    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_RC
    1108             MMGCRamRegisterTrapHandler(pVM);
    1109 #endif
    1110             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_RC
    1130             MMGCRamDeregisterTrapHandler(pVM);
    1131 #endif
    1132         }
    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] STOSB
    1169  * [REP] STOSW
    1170  * [REP] STOSD
    1171  *
    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_RC
    1201         if (    CPUMIsGuestIn64BitCode(pVCpu)
    1202             &&  pRegFrame->rcx >= _4G)
    1203             return VINF_EM_RAW_EMULATE_INSTR;
    1204 #endif
    1205 
    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_STATISTICS
    1221     if (pVM->iom.s.cStosMaxBytes < (cTransfers << SIZE_2_SHIFT(cb)))
    1222         pVM->iom.s.cStosMaxBytes = cTransfers << SIZE_2_SHIFT(cb);
    1223 #endif
    1224 
    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         else
    1250         {
    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     else
    1266     {
    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         do
    1275         {
    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] LODSB
    1303  * [REP] LODSW
    1304  * [REP] LODSD
    1305  *
    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|imm
    1358  * 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     else
    1390     {
    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 == 32
    1398         /* 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 #endif
    1402         /* 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|imm
    1415  * AND reg, [MMIO]
    1416  * OR [MMIO], reg|imm
    1417  * 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_ENABLED
    1442     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     else
    1451         pszInstr = "OrXorAnd??";
    1452 #endif
    1453 
    1454     if (iomGetRegImmData(pCpu, &pCpu->Param1, pRegFrame, &uData1, &cb))
    1455     {
    1456 #if HC_ARCH_BITS == 32
    1457         /* 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 #endif
    1461         /* 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 == 32
    1469         /* 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 #endif
    1473         /* 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         else
    1479             rc = VINF_IOM_R3_MMIO_READ_WRITE;
    1480     }
    1481     else
    1482     {
    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         else
    1498         {
    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|imm
    1518  * 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     else
    1553     {
    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 == 32
    1561         /* 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 #endif
    1565 
    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|imm
    1579  *
    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], reg
    1623  * 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             else
    1665                 Assert(rc == VINF_IOM_R3_MMIO_WRITE || rc == VINF_PATM_HC_MMIO_PATCH_WRITE);
    1666         }
    1667         else
    1668             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             else
    1685                 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         else
    1688             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     else
    1691     {
    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 */
    1699583
    1700584/**
     
    1787671    }
    1788672
    1789 #ifdef IEM_USE_IEM_INSTEAD
    1790 
    1791673    /*
    1792674     * Let IEM call us back via iomMmioHandler.
     
    1807689    }
    1808690    return rcStrict;
    1809 
    1810 #else
    1811 
    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_RW
    1834                 : DISUSE_IS_EFFECTIVE_ADDR(pDis->Param1.fUse))
    1835                 rc = iomInterpretMOVxXWrite(pVM, pVCpu, pCtxCore, pDis, pRange, GCPhysFault);
    1836             else
    1837                 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_SUPPORT
    1844         case OP_MOVSB:
    1845         case OP_MOVSWD:
    1846         {
    1847             if (uErrorCode == UINT32_MAX)
    1848                 rc = VINF_IOM_R3_MMIO_READ_WRITE;
    1849             else
    1850             {
    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 # endif
    1859 
    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     else
    1937     {
    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 # endif
    1951     }
    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 */
    1958691}
    1959692
     
    23531086
    23541087#endif /* IN_RING3 - only used by REM. */
    2355 #ifndef IEM_USE_IEM_INSTEAD
    2356 
    2357 /**
    2358  * [REP*] INSB/INSW/INSD
    2359  * 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 documented
    2364  *          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()), the
    2367  *                                      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 Port
    2378  * @param   uPrefix         IO instruction prefix
    2379  * @param   enmAddrMode     The address mode.
    2380  * @param   cbTransfer      Size of transfer unit
    2381  */
    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 destination
    2390      * 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_RC
    2404         if (    CPUMIsGuestIn64BitCode(pVCpu)
    2405             &&  pRegFrame->rcx >= _4G)
    2406             return VINF_EM_RAW_EMULATE_INSTR;
    2407 #endif
    2408         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 much
    2440          * 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 (   cThisTime
    2476                     || !cTransfers
    2477                     || rcStrict != VINF_SUCCESS
    2478                     || (GCPtrDst & PAGE_OFFSET_MASK))
    2479                     break;
    2480             }
    2481             else
    2482             {
    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_RC
    2493     MMGCRamRegisterTrapHandler(pVM);
    2494 #endif
    2495     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_RC
    2509     MMGCRamDeregisterTrapHandler(pVM);
    2510 #endif
    2511 
    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/OUTSD
    2524  * 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 documented
    2529  *          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()), the
    2532  *                                      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 Port
    2542  * @param   uPrefix         IO instruction prefix
    2543  * @param   enmAddrMode     The address mode.
    2544  * @param   cbTransfer      Size of transfer unit
    2545  *
    2546  * @remarks This API will probably be relaced by IEM before long, so no use in
    2547  *          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 or
    2557      * 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_RC
    2571         if (    CPUMIsGuestIn64BitCode(pVCpu)
    2572             &&  pRegFrame->rcx >= _4G)
    2573             return VINF_EM_RAW_EMULATE_INSTR;
    2574 #endif
    2575         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 much
    2607          * 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 (   cThisTime
    2637                     || !cTransfers
    2638                     || rcStrict != VINF_SUCCESS
    2639                     || (GCPtrSrc & PAGE_OFFSET_MASK))
    2640                     break;
    2641             }
    2642             else
    2643             {
    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_RC
    2654     MMGCRamRegisterTrapHandler(pVM);
    2655 #endif
    2656 
    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_RC
    2673     MMGCRamDeregisterTrapHandler(pVM);
    2674 #endif
    2675 
    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 
    26881088#ifndef IN_RC
    26891089
Note: See TracChangeset for help on using the changeset viewer.

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