VirtualBox

Changeset 2201 in vbox for trunk


Ignore:
Timestamp:
Apr 19, 2007 8:54:41 AM (18 years ago)
Author:
vboxsync
Message:

Moved ins/outs handling to the VMMAll directory.

Location:
trunk/src/VBox/VMM
Files:
4 edited

Legend:

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

    r2163 r2201  
    100100        VMMAll/DBGFAll.cpp \
    101101        VMMAll/IOMAll.cpp \
     102        VMMAll/IOMAllMMIO.cpp \
    102103        VMMAll/MMAll.cpp \
    103104        VMMAll/MMAllHyper.cpp \
  • trunk/src/VBox/VMM/VMMAll/IOMAll.cpp

    r1828 r2201  
    884884    return VINF_SUCCESS;
    885885}
    886 
    887 
    888886/**
    889887 * Writes the string buffer of an I/O port register.
     
    10051003}
    10061004
    1007 
    1008 //#undef LOG_GROUP
    1009 //#define LOG_GROUP LOG_GROUP_IOM_MMIO
    1010 
    1011 /**
    1012  * Reads a MMIO register.
    1013  *
    1014  * @returns VBox status code.
    1015  *
    1016  * @param   pVM         VM handle.
    1017  * @param   GCPhys      The physical address to read.
    1018  * @param   pu32Value   Where to store the value read.
    1019  * @param   cbValue     The size of the register to read in bytes. 1, 2 or 4 bytes.
    1020  */
    1021 IOMDECL(int) IOMMMIORead(PVM pVM, RTGCPHYS GCPhys, uint32_t *pu32Value, size_t cbValue)
    1022 {
    1023 /** @todo add return to ring-3 statistics when this function is used in GC! */
    1024 
    1025     /*
    1026      * Lookup the current context range node and statistics.
    1027      */
    1028     CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
    1029 #ifdef VBOX_WITH_STATISTICS
    1030     PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys);
    1031     if (!pStats && (!pRange || pRange->cbSize <= PAGE_SIZE))
    1032 # ifdef IN_RING3
    1033         pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange ? pRange->pszDesc : NULL);
    1034 # else
    1035         return VINF_IOM_HC_MMIO_READ;
    1036 # endif
    1037 #endif /* VBOX_WITH_STATISTICS */
    1038 #ifdef IN_RING3
    1039     if (pRange)
    1040 #else /* !IN_RING3 */
    1041     if (pRange && pRange->pfnReadCallback)
    1042 #endif /* !IN_RING3 */
    1043     {
    1044         /*
    1045          * Perform the read and deal with the result.
    1046          */
    1047 #ifdef VBOX_WITH_STATISTICS
    1048         if (pStats)
    1049             STAM_PROFILE_ADV_START(&pStats->CTXALLSUFF(ProfRead), a);
    1050 #endif
    1051         int rc = pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhys, pu32Value, cbValue);
    1052 #ifdef VBOX_WITH_STATISTICS
    1053         if (pStats)
    1054             STAM_PROFILE_ADV_STOP(&pStats->CTXALLSUFF(ProfRead), a);
    1055         if (pStats && rc != VINF_IOM_HC_MMIO_READ)
    1056             STAM_COUNTER_INC(&pStats->CTXALLSUFF(Read));
    1057 #endif
    1058         switch (rc)
    1059         {
    1060             case VINF_SUCCESS:
    1061             default:
    1062                 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, *pu32Value, cbValue, rc));
    1063                 return rc;
    1064 
    1065             case VINF_IOM_MMIO_UNUSED_00:
    1066                 switch (cbValue)
    1067                 {
    1068                     case 1: *(uint8_t *)pu32Value  = 0x00; break;
    1069                     case 2: *(uint16_t *)pu32Value = 0x0000; break;
    1070                     case 4: *(uint32_t *)pu32Value = 0x00000000; break;
    1071                     default: AssertReleaseMsgFailed(("cbValue=%d GCPhys=%VGp\n", cbValue, GCPhys)); break;
    1072                 }
    1073                 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, *pu32Value, cbValue, rc));
    1074                 return VINF_SUCCESS;
    1075 
    1076             case VINF_IOM_MMIO_UNUSED_FF:
    1077                 switch (cbValue)
    1078                 {
    1079                     case 1: *(uint8_t *)pu32Value  = 0xff; break;
    1080                     case 2: *(uint16_t *)pu32Value = 0xffff; break;
    1081                     case 4: *(uint32_t *)pu32Value = 0xffffffff; break;
    1082                     default: AssertReleaseMsgFailed(("cbValue=%d GCPhys=%VGp\n", cbValue, GCPhys)); break;
    1083                 }
    1084                 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, *pu32Value, cbValue, rc));
    1085                 return VINF_SUCCESS;
    1086         }
    1087     }
    1088 
    1089 #ifndef IN_RING3
    1090     /*
    1091      * Lookup the ring-3 range.
    1092      */
    1093     PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhys);
    1094     if (pRangeR3)
    1095     {
    1096         if (pRangeR3->pfnReadCallback)
    1097             return VINF_IOM_HC_MMIO_READ;
    1098 # ifdef VBOX_WITH_STATISTICS
    1099         if (pStats)
    1100             STAM_COUNTER_INC(&pStats->CTXALLSUFF(Read));
    1101 # endif
    1102         *pu32Value = 0;
    1103         Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
    1104         return VINF_SUCCESS;
    1105     }
    1106 #endif
    1107 
    1108     AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue));
    1109     return VERR_INTERNAL_ERROR;
    1110 }
    1111 
    1112 
    1113 /**
    1114  * Writes to a MMIO register.
    1115  *
    1116  * @returns VBox status code.
    1117  *
    1118  * @param   pVM         VM handle.
    1119  * @param   GCPhys      The physical address to write to.
    1120  * @param   u32Value    The value to write.
    1121  * @param   cbValue     The size of the register to read in bytes. 1, 2 or 4 bytes.
    1122  */
    1123 IOMDECL(int) IOMMMIOWrite(PVM pVM, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue)
    1124 {
    1125 /** @todo add return to ring-3 statistics when this function is used in GC! */
    1126     /*
    1127      * Lookup the current context range node.
    1128      */
    1129     CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
    1130 #ifdef VBOX_WITH_STATISTICS
    1131     PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys);
    1132     if (!pStats && (!pRange || pRange->cbSize <= PAGE_SIZE))
    1133 # ifdef IN_RING3
    1134         pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange ? pRange->pszDesc : NULL);
    1135 # else
    1136         return VINF_IOM_HC_MMIO_WRITE;
    1137 # endif
    1138 #endif /* VBOX_WITH_STATISTICS */
    1139 
    1140     /*
    1141      * Perform the write if we found a range.
    1142      */
    1143 #ifdef IN_RING3
    1144     if (pRange)
    1145 #else /* !IN_RING3 */
    1146     if (pRange && pRange->pfnWriteCallback)
    1147 #endif /* !IN_RING3 */
    1148     {
    1149 #ifdef VBOX_WITH_STATISTICS
    1150         if (pStats)
    1151             STAM_PROFILE_ADV_START(&pStats->CTXALLSUFF(ProfWrite), a);
    1152 #endif
    1153         int rc = pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhys, &u32Value, cbValue);
    1154 #ifdef VBOX_WITH_STATISTICS
    1155         if (pStats)
    1156             STAM_PROFILE_ADV_STOP(&pStats->CTXALLSUFF(ProfWrite), a);
    1157         if (pStats && rc != VINF_IOM_HC_MMIO_WRITE)
    1158             STAM_COUNTER_INC(&pStats->CTXALLSUFF(Write));
    1159 #endif
    1160         Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, u32Value, cbValue, rc));
    1161         return rc;
    1162     }
    1163 
    1164 #ifndef IN_RING3
    1165     /*
    1166      * Lookup the ring-3 range.
    1167      */
    1168     PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhys);
    1169     if (pRangeR3)
    1170     {
    1171         if (pRangeR3->pfnWriteCallback)
    1172             return VINF_IOM_HC_MMIO_WRITE;
    1173 # ifdef VBOX_WITH_STATISTICS
    1174         if (pStats)
    1175             STAM_COUNTER_INC(&pStats->CTXALLSUFF(Write));
    1176 # endif
    1177         Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, u32Value, cbValue));
    1178         return VINF_SUCCESS;
    1179     }
    1180 #endif
    1181 
    1182     AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue));
    1183     return VERR_INTERNAL_ERROR;
    1184 }
    1185 
    1186 
    11871005/**
    11881006 * Checks that the operation is allowed according to the IOPL
  • trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp

    r2180 r2201  
    4545#include <iprt/string.h>
    4646
    47 #ifndef IN_RING3
    48 
    49 /** @def IOMGC_MOVS_SUPPORT
    50  * Define IOMGC_MOVS_SUPPORT for movsb/w/d support in GC and R0.
    51  */
    52 #define IOMGC_MOVS_SUPPORT
    53 
    5447/*******************************************************************************
    5548*   Internal Functions                                                         *
     
    467460
    468461
    469 #ifdef IOMGC_MOVS_SUPPORT
    470 
    471462inline int iomRamRead(PVM pVM, void *pDest, RTGCPTR GCSrc, uint32_t cb)
    472463{
     
    715706                if (rc != VINF_SUCCESS)
    716707                {
    717                     Log(("MMGCRamWriteNoTrapHandler %08X size=%d failed with %d\n", pu8Virt, cbSize, rc));
     708                    Log(("iomRamWrite %08X size=%d failed with %d\n", pu8Virt, cbSize, rc));
    718709                    break;
    719710                }
     
    744735    return rc;
    745736}
    746 #endif /* IOMGC_MOVS_SUPPORT */
    747737
    748738
     
    14171407
    14181408
     1409/**
     1410 * Reads a MMIO register.
     1411 *
     1412 * @returns VBox status code.
     1413 *
     1414 * @param   pVM         VM handle.
     1415 * @param   GCPhys      The physical address to read.
     1416 * @param   pu32Value   Where to store the value read.
     1417 * @param   cbValue     The size of the register to read in bytes. 1, 2 or 4 bytes.
     1418 */
     1419IOMDECL(int) IOMMMIORead(PVM pVM, RTGCPHYS GCPhys, uint32_t *pu32Value, size_t cbValue)
     1420{
     1421/** @todo add return to ring-3 statistics when this function is used in GC! */
     1422
     1423    /*
     1424     * Lookup the current context range node and statistics.
     1425     */
     1426    CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
     1427#ifdef VBOX_WITH_STATISTICS
     1428    PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys);
     1429    if (!pStats && (!pRange || pRange->cbSize <= PAGE_SIZE))
     1430# ifdef IN_RING3
     1431        pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange ? pRange->pszDesc : NULL);
     1432# else
     1433        return VINF_IOM_HC_MMIO_READ;
     1434# endif
     1435#endif /* VBOX_WITH_STATISTICS */
     1436#ifdef IN_RING3
     1437    if (pRange)
     1438#else /* !IN_RING3 */
     1439    if (pRange && pRange->pfnReadCallback)
    14191440#endif /* !IN_RING3 */
     1441    {
     1442        /*
     1443         * Perform the read and deal with the result.
     1444         */
     1445#ifdef VBOX_WITH_STATISTICS
     1446        if (pStats)
     1447            STAM_PROFILE_ADV_START(&pStats->CTXALLSUFF(ProfRead), a);
     1448#endif
     1449        int rc = pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhys, pu32Value, cbValue);
     1450#ifdef VBOX_WITH_STATISTICS
     1451        if (pStats)
     1452            STAM_PROFILE_ADV_STOP(&pStats->CTXALLSUFF(ProfRead), a);
     1453        if (pStats && rc != VINF_IOM_HC_MMIO_READ)
     1454            STAM_COUNTER_INC(&pStats->CTXALLSUFF(Read));
     1455#endif
     1456        switch (rc)
     1457        {
     1458            case VINF_SUCCESS:
     1459            default:
     1460                Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, *pu32Value, cbValue, rc));
     1461                return rc;
     1462
     1463            case VINF_IOM_MMIO_UNUSED_00:
     1464                switch (cbValue)
     1465                {
     1466                    case 1: *(uint8_t *)pu32Value  = 0x00; break;
     1467                    case 2: *(uint16_t *)pu32Value = 0x0000; break;
     1468                    case 4: *(uint32_t *)pu32Value = 0x00000000; break;
     1469                    default: AssertReleaseMsgFailed(("cbValue=%d GCPhys=%VGp\n", cbValue, GCPhys)); break;
     1470                }
     1471                Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, *pu32Value, cbValue, rc));
     1472                return VINF_SUCCESS;
     1473
     1474            case VINF_IOM_MMIO_UNUSED_FF:
     1475                switch (cbValue)
     1476                {
     1477                    case 1: *(uint8_t *)pu32Value  = 0xff; break;
     1478                    case 2: *(uint16_t *)pu32Value = 0xffff; break;
     1479                    case 4: *(uint32_t *)pu32Value = 0xffffffff; break;
     1480                    default: AssertReleaseMsgFailed(("cbValue=%d GCPhys=%VGp\n", cbValue, GCPhys)); break;
     1481                }
     1482                Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, *pu32Value, cbValue, rc));
     1483                return VINF_SUCCESS;
     1484        }
     1485    }
     1486
     1487#ifndef IN_RING3
     1488    /*
     1489     * Lookup the ring-3 range.
     1490     */
     1491    PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhys);
     1492    if (pRangeR3)
     1493    {
     1494        if (pRangeR3->pfnReadCallback)
     1495            return VINF_IOM_HC_MMIO_READ;
     1496# ifdef VBOX_WITH_STATISTICS
     1497        if (pStats)
     1498            STAM_COUNTER_INC(&pStats->CTXALLSUFF(Read));
     1499# endif
     1500        *pu32Value = 0;
     1501        Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
     1502        return VINF_SUCCESS;
     1503    }
     1504#endif
     1505
     1506    AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue));
     1507    return VERR_INTERNAL_ERROR;
     1508}
     1509
     1510
     1511/**
     1512 * Writes to a MMIO register.
     1513 *
     1514 * @returns VBox status code.
     1515 *
     1516 * @param   pVM         VM handle.
     1517 * @param   GCPhys      The physical address to write to.
     1518 * @param   u32Value    The value to write.
     1519 * @param   cbValue     The size of the register to read in bytes. 1, 2 or 4 bytes.
     1520 */
     1521IOMDECL(int) IOMMMIOWrite(PVM pVM, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue)
     1522{
     1523/** @todo add return to ring-3 statistics when this function is used in GC! */
     1524    /*
     1525     * Lookup the current context range node.
     1526     */
     1527    CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
     1528#ifdef VBOX_WITH_STATISTICS
     1529    PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys);
     1530    if (!pStats && (!pRange || pRange->cbSize <= PAGE_SIZE))
     1531# ifdef IN_RING3
     1532        pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange ? pRange->pszDesc : NULL);
     1533# else
     1534        return VINF_IOM_HC_MMIO_WRITE;
     1535# endif
     1536#endif /* VBOX_WITH_STATISTICS */
     1537
     1538    /*
     1539     * Perform the write if we found a range.
     1540     */
     1541#ifdef IN_RING3
     1542    if (pRange)
     1543#else /* !IN_RING3 */
     1544    if (pRange && pRange->pfnWriteCallback)
     1545#endif /* !IN_RING3 */
     1546    {
     1547#ifdef VBOX_WITH_STATISTICS
     1548        if (pStats)
     1549            STAM_PROFILE_ADV_START(&pStats->CTXALLSUFF(ProfWrite), a);
     1550#endif
     1551        int rc = pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhys, &u32Value, cbValue);
     1552#ifdef VBOX_WITH_STATISTICS
     1553        if (pStats)
     1554            STAM_PROFILE_ADV_STOP(&pStats->CTXALLSUFF(ProfWrite), a);
     1555        if (pStats && rc != VINF_IOM_HC_MMIO_WRITE)
     1556            STAM_COUNTER_INC(&pStats->CTXALLSUFF(Write));
     1557#endif
     1558        Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, u32Value, cbValue, rc));
     1559        return rc;
     1560    }
     1561
     1562#ifndef IN_RING3
     1563    /*
     1564     * Lookup the ring-3 range.
     1565     */
     1566    PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhys);
     1567    if (pRangeR3)
     1568    {
     1569        if (pRangeR3->pfnWriteCallback)
     1570            return VINF_IOM_HC_MMIO_WRITE;
     1571# ifdef VBOX_WITH_STATISTICS
     1572        if (pStats)
     1573            STAM_COUNTER_INC(&pStats->CTXALLSUFF(Write));
     1574# endif
     1575        Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, u32Value, cbValue));
     1576        return VINF_SUCCESS;
     1577    }
     1578#endif
     1579
     1580    AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue));
     1581    return VERR_INTERNAL_ERROR;
     1582}
     1583
     1584
     1585/**
     1586 * [REP*] INSB/INSW/INSD
     1587 * ES:EDI,DX[,ECX]
     1588 *
     1589 * @returns VBox status code.
     1590 *
     1591 * @param   pVM         The virtual machine (GC pointer ofcourse).
     1592 * @param   pRegFrame   Pointer to CPUMCTXCORE guest registers structure.
     1593 * @param   pCpu        Disassembler CPU state.
     1594 */
     1595IOMDECL(int) IOMInterpretINS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
     1596{
     1597#ifdef VBOX_WITH_STATISTICS
     1598    STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIns);
     1599#endif
     1600
     1601    /*
     1602     * We do not support REPNE or decrementing destination
     1603     * pointer. Segment prefixes are deliberately ignored, as per the instruction specification.
     1604     */
     1605    if (   pCpu->prefix & PREFIX_REPNE
     1606        || pRegFrame->eflags.Bits.u1DF)
     1607        return VINF_IOM_HC_IOPORT_READ;
     1608
     1609    /*
     1610     * Get port number directly from the register (no need to bother the
     1611     * disassembler). And get the I/O register size from the opcode / prefix.
     1612     */
     1613    uint32_t    uPort = pRegFrame->edx & 0xffff;
     1614    unsigned    cbSize = 0;
     1615    if (pCpu->pCurInstr->opcode == OP_INSB)
     1616        cbSize = 1;
     1617    else
     1618        cbSize = pCpu->opmode == CPUMODE_32BIT ? 4 : 2;
     1619
     1620    int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
     1621    if (rc == VINF_SUCCESS)
     1622    {
     1623        /*
     1624         * Get bytes/words/dwords count to transfer.
     1625         */
     1626        RTGCUINTREG cTransfers = 1;
     1627        if (pCpu->prefix & PREFIX_REP)
     1628        {
     1629            cTransfers = pRegFrame->ecx;
     1630            if (!cTransfers)
     1631                return VINF_SUCCESS;
     1632        }
     1633
     1634        /* Convert destination address es:edi. */
     1635        RTGCPTR GCPtrDst;
     1636        rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->es, (RTGCPTR)pRegFrame->edi, &pRegFrame->esHid,
     1637                          SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
     1638                          &GCPtrDst, NULL);
     1639        if (VBOX_FAILURE(rc))
     1640        {
     1641            Log(("INS destination address conversion failed -> fallback, rc=%d\n", rc));
     1642            return VINF_IOM_HC_IOPORT_READ;
     1643        }
     1644
     1645        /* Access verification first; we can't recover from traps inside this instruction, as the port read cannot be repeated. */
     1646        uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
     1647
     1648        rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrDst, cTransfers * cbSize,
     1649                             X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0));
     1650        if (rc != VINF_SUCCESS)
     1651        {
     1652            Log(("INS will generate a trap -> fallback, rc=%d\n", rc));
     1653            return VINF_IOM_HC_IOPORT_READ;
     1654        }
     1655
     1656        Log(("IOM: rep ins%d port %#x count %d\n", cbSize * 8, uPort, cTransfers));
     1657#ifdef IN_GC
     1658        MMGCRamRegisterTrapHandler(pVM);
     1659#endif
     1660
     1661        /* If the device supports string transfers, ask it to do as
     1662         * much as it wants. The rest is done with single-word transfers. */
     1663        const RTGCUINTREG cTransfersOrg = cTransfers;
     1664        rc = IOMIOPortReadString(pVM, uPort, &GCPtrDst, &cTransfers, cbSize);
     1665        AssertRC(rc); Assert(cTransfers <= cTransfersOrg);
     1666        pRegFrame->edi += (cTransfersOrg - cTransfers) * cbSize;
     1667
     1668        while (cTransfers && rc == VINF_SUCCESS)
     1669        {
     1670            uint32_t u32Value;
     1671            rc = IOMIOPortRead(pVM, uPort, &u32Value, cbSize);
     1672            if (rc == VINF_IOM_HC_IOPORT_READ || VBOX_FAILURE(rc))
     1673                break;
     1674            int rc2 = iomRamWrite(pVM, GCPtrDst, &u32Value, cbSize);
     1675            Assert(rc2 == VINF_SUCCESS); NOREF(rc2);
     1676            GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + cbSize);
     1677            pRegFrame->edi += cbSize;
     1678            cTransfers--;
     1679        }
     1680#ifdef IN_GC
     1681        MMGCRamDeregisterTrapHandler(pVM);
     1682#endif
     1683
     1684        /* Update ecx on exit. */
     1685        if (pCpu->prefix & PREFIX_REP)
     1686            pRegFrame->ecx = cTransfers;
     1687    }
     1688    return rc;
     1689}
     1690
     1691
     1692
     1693/**
     1694 * [REP*] OUTSB/OUTSW/OUTSD
     1695 * DS:ESI,DX[,ECX]
     1696 *
     1697 * @returns VBox status code.
     1698 *
     1699 * @param   pVM         The virtual machine (GC pointer ofcourse).
     1700 * @param   pRegFrame   Pointer to CPUMCTXCORE guest registers structure.
     1701 * @param   pCpu        Disassembler CPU state.
     1702 */
     1703IOMDECL(int) IOMInterpretOUTS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
     1704{
     1705#ifdef VBOX_WITH_STATISTICS
     1706    STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOuts);
     1707#endif
     1708
     1709    /*
     1710     * We do not support segment prefixes, REPNE or
     1711     * decrementing source pointer.
     1712     */
     1713    if (   pCpu->prefix & (PREFIX_SEG | PREFIX_REPNE)
     1714        || pRegFrame->eflags.Bits.u1DF)
     1715        return VINF_IOM_HC_IOPORT_WRITE;
     1716
     1717    /*
     1718     * Get port number from the first parameter.
     1719     * And get the I/O register size from the opcode / prefix.
     1720     */
     1721    uint32_t    uPort = 0;
     1722    unsigned    cbSize = 0;
     1723    bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uPort, &cbSize);
     1724    AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
     1725    if (pCpu->pCurInstr->opcode == OP_OUTSB)
     1726        cbSize = 1;
     1727    else
     1728        cbSize = (pCpu->opmode == CPUMODE_32BIT) ? 4 : 2;
     1729
     1730    int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
     1731    if (rc == VINF_SUCCESS)
     1732    {
     1733        /*
     1734         * Get bytes/words/dwords count to transfer.
     1735         */
     1736        RTGCUINTREG cTransfers = 1;
     1737        if (pCpu->prefix & PREFIX_REP)
     1738        {
     1739            cTransfers = pRegFrame->ecx;
     1740            if (!cTransfers)
     1741                return VINF_SUCCESS;
     1742        }
     1743
     1744        /* Convert source address ds:esi. */
     1745        RTGCPTR GCPtrSrc;
     1746        rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->ds, (RTGCPTR)pRegFrame->esi, &pRegFrame->dsHid,
     1747                          SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
     1748                          &GCPtrSrc, NULL);
     1749        if (VBOX_FAILURE(rc))
     1750        {
     1751            Log(("OUTS source address conversion failed -> fallback, rc=%d\n", rc));
     1752            return VINF_IOM_HC_IOPORT_WRITE;
     1753        }
     1754
     1755        /* Access verification first; we currently can't recover properly from traps inside this instruction */
     1756        uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
     1757        rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrSrc, cTransfers * cbSize,
     1758                             (cpl == 3) ? X86_PTE_US : 0);
     1759        if (rc != VINF_SUCCESS)
     1760        {
     1761            Log(("OUTS will generate a trap -> fallback, rc=%d\n", rc));
     1762            return VINF_IOM_HC_IOPORT_WRITE;
     1763        }
     1764
     1765        Log(("IOM: rep outs%d port %#x count %d\n", cbSize * 8, uPort, cTransfers));
     1766#ifdef IN_GC
     1767        MMGCRamRegisterTrapHandler(pVM);
     1768#endif
     1769        /*
     1770         * If the device supports string transfers, ask it to do as
     1771         * much as it wants. The rest is done with single-word transfers.
     1772         */
     1773        const RTGCUINTREG cTransfersOrg = cTransfers;
     1774        rc = IOMIOPortWriteString(pVM, uPort, &GCPtrSrc, &cTransfers, cbSize);
     1775        AssertRC(rc); Assert(cTransfers <= cTransfersOrg);
     1776        pRegFrame->esi += (cTransfersOrg - cTransfers) * cbSize;
     1777
     1778        while (cTransfers && rc == VINF_SUCCESS)
     1779        {
     1780            uint32_t u32Value;
     1781            rc = iomRamRead(pVM, &u32Value, GCPtrSrc, cbSize);
     1782            if (rc != VINF_SUCCESS)
     1783                break;
     1784            rc = IOMIOPortWrite(pVM, uPort, u32Value, cbSize);
     1785            if (rc == VINF_IOM_HC_IOPORT_WRITE)
     1786                break;
     1787            GCPtrSrc = (RTGCPTR)((RTUINTPTR)GCPtrSrc + cbSize);
     1788            pRegFrame->esi += cbSize;
     1789            cTransfers--;
     1790        }
     1791
     1792#ifdef IN_GC
     1793        MMGCRamDeregisterTrapHandler(pVM);
     1794#endif
     1795
     1796        /* Update ecx on exit. */
     1797        if (pCpu->prefix & PREFIX_REP)
     1798            pRegFrame->ecx = cTransfers;
     1799    }
     1800    return rc;
     1801}
  • trunk/src/VBox/VMM/VMMGC/IOMGC.cpp

    r2116 r2201  
    420420}
    421421
    422 
    423 /**
    424  * [REP*] INSB/INSW/INSD
    425  * ES:EDI,DX[,ECX]
    426  *
    427  * @returns VBox status code.
    428  *
    429  * @param   pVM         The virtual machine (GC pointer ofcourse).
    430  * @param   pRegFrame   Pointer to CPUMCTXCORE guest registers structure.
    431  * @param   pCpu        Disassembler CPU state.
    432  */
    433 IOMDECL(int) IOMInterpretINS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
    434 {
    435 #ifdef VBOX_WITH_STATISTICS
    436     STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIns);
    437 #endif
    438 
    439     /*
    440      * We do not support REPNE, 16-bit addressing or decrementing destination
    441      * pointer. Segment prefixes are deliberately ignored, as per the instruction specification.
    442      */
    443     if (   pCpu->prefix & PREFIX_REPNE
    444         || (pCpu->addrmode != CPUMODE_32BIT)
    445         || pRegFrame->eflags.Bits.u1DF)
    446         return VINF_IOM_HC_IOPORT_READ;
    447 
    448     /*
    449      * Get port number directly from the register (no need to bother the
    450      * disassembler). And get the I/O register size from the opcode / prefix.
    451      */
    452     uint32_t    uPort = pRegFrame->edx & 0xffff;
    453     unsigned    cbSize = 0;
    454     if (pCpu->pCurInstr->opcode == OP_INSB)
    455         cbSize = 1;
    456     else
    457         cbSize = pCpu->opmode == CPUMODE_32BIT ? 4 : 2;
    458 
    459     int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
    460     if (rc == VINF_SUCCESS)
    461     {
    462         /*
    463          * Get bytes/words/dwords count to transfer.
    464          */
    465         RTGCUINTREG cTransfers = 1;
    466         if (pCpu->prefix & PREFIX_REP)
    467         {
    468             cTransfers = pRegFrame->ecx;
    469             if (!cTransfers)
    470                 return VINF_SUCCESS;
    471         }
    472 
    473         /* Convert destination address es:edi. */
    474         RTGCPTR GCPtrDst;
    475         rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->es, (RTGCPTR)pRegFrame->edi, &pRegFrame->esHid,
    476                           SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
    477                           &GCPtrDst, NULL);
    478         if (VBOX_FAILURE(rc))
    479         {
    480             Log(("INS destination address conversion failed -> fallback, rc=%d\n", rc));
    481             return VINF_IOM_HC_IOPORT_READ;
    482         }
    483 
    484         /* Access verification first; we can't recover from traps inside this instruction, as the port read cannot be repeated. */
    485         uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
    486 
    487         rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrDst, cTransfers * cbSize,
    488                              X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0));
    489         if (rc != VINF_SUCCESS)
    490         {
    491             Log(("INS will generate a trap -> fallback, rc=%d\n", rc));
    492             return VINF_IOM_HC_IOPORT_READ;
    493         }
    494 
    495         Log(("IOMGC: rep ins%d port %#x count %d\n", cbSize * 8, uPort, cTransfers));
    496         MMGCRamRegisterTrapHandler(pVM);
    497 
    498         /* If the device supports string transfers, ask it to do as
    499          * much as it wants. The rest is done with single-word transfers. */
    500         const RTGCUINTREG cTransfersOrg = cTransfers;
    501         rc = IOMIOPortReadString(pVM, uPort, &GCPtrDst, &cTransfers, cbSize);
    502         AssertRC(rc); Assert(cTransfers <= cTransfersOrg);
    503         pRegFrame->edi += (cTransfersOrg - cTransfers) * cbSize;
    504 
    505         while (cTransfers && rc == VINF_SUCCESS)
    506         {
    507             uint32_t u32Value;
    508             rc = IOMIOPortRead(pVM, uPort, &u32Value, cbSize);
    509             if (rc == VINF_IOM_HC_IOPORT_READ || VBOX_FAILURE(rc))
    510                 break;
    511             int rc2 = MMGCRamWriteNoTrapHandler(GCPtrDst, &u32Value, cbSize);
    512             Assert(rc2 == VINF_SUCCESS); NOREF(rc2);
    513             GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + cbSize);
    514             pRegFrame->edi += cbSize;
    515             cTransfers--;
    516         }
    517         MMGCRamDeregisterTrapHandler(pVM);
    518 
    519         /* Update ecx on exit. */
    520         if (pCpu->prefix & PREFIX_REP)
    521             pRegFrame->ecx = cTransfers;
    522     }
    523     return rc;
    524 }
    525 
    526 
    527 /**
    528  * [REP*] OUTSB/OUTSW/OUTSD
    529  * DS:ESI,DX[,ECX]
    530  *
    531  * @returns VBox status code.
    532  *
    533  * @param   pVM         The virtual machine (GC pointer ofcourse).
    534  * @param   pRegFrame   Pointer to CPUMCTXCORE guest registers structure.
    535  * @param   pCpu        Disassembler CPU state.
    536  */
    537 IOMDECL(int) IOMInterpretOUTS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
    538 {
    539 #ifdef VBOX_WITH_STATISTICS
    540     STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOuts);
    541 #endif
    542 
    543     /*
    544      * We do not support segment prefixes, REPNE, 16-bit addressing or
    545      * decrementing source pointer.
    546      */
    547     if (   pCpu->prefix & (PREFIX_SEG | PREFIX_REPNE)
    548         || (pCpu->addrmode != CPUMODE_32BIT)
    549         || pRegFrame->eflags.Bits.u1DF)
    550         return VINF_IOM_HC_IOPORT_WRITE;
    551 
    552     /*
    553      * Get port number from the first parameter.
    554      * And get the I/O register size from the opcode / prefix.
    555      */
    556     uint32_t    uPort = 0;
    557     unsigned    cbSize = 0;
    558     bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uPort, &cbSize);
    559     AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
    560     if (pCpu->pCurInstr->opcode == OP_OUTSB)
    561         cbSize = 1;
    562     else
    563         cbSize = pCpu->opmode == CPUMODE_32BIT ? 4 : 2;
    564 
    565     int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
    566     if (rc == VINF_SUCCESS)
    567     {
    568         /*
    569          * Get bytes/words/dwords count to transfer.
    570          */
    571         RTGCUINTREG cTransfers = 1;
    572         if (pCpu->prefix & PREFIX_REP)
    573         {
    574             cTransfers = pRegFrame->ecx;
    575             if (!cTransfers)
    576                 return VINF_SUCCESS;
    577         }
    578 
    579         /* Convert source address ds:esi. */
    580         RTGCPTR GCPtrSrc;
    581         rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->ds, (RTGCPTR)pRegFrame->esi, &pRegFrame->dsHid,
    582                           SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
    583                           &GCPtrSrc, NULL);
    584         if (VBOX_FAILURE(rc))
    585         {
    586             Log(("OUTS source address conversion failed -> fallback, rc=%d\n", rc));
    587             return VINF_IOM_HC_IOPORT_WRITE;
    588         }
    589 
    590         /* Access verification first; we currently can't recover properly from traps inside this instruction */
    591         uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
    592         rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrSrc, cTransfers * cbSize,
    593                              (cpl == 3) ? X86_PTE_US : 0);
    594         if (rc != VINF_SUCCESS)
    595         {
    596             Log(("OUTS will generate a trap -> fallback, rc=%d\n", rc));
    597             return VINF_IOM_HC_IOPORT_WRITE;
    598         }
    599 
    600         Log(("IOMGC: rep outs%d port %#x count %d\n", cbSize * 8, uPort, cTransfers));
    601         MMGCRamRegisterTrapHandler(pVM);
    602 
    603         /*
    604          * If the device supports string transfers, ask it to do as
    605          * much as it wants. The rest is done with single-word transfers.
    606          */
    607         const RTGCUINTREG cTransfersOrg = cTransfers;
    608         rc = IOMIOPortWriteString(pVM, uPort, &GCPtrSrc, &cTransfers, cbSize);
    609         AssertRC(rc); Assert(cTransfers <= cTransfersOrg);
    610         pRegFrame->esi += (cTransfersOrg - cTransfers) * cbSize;
    611 
    612         while (cTransfers && rc == VINF_SUCCESS)
    613         {
    614             uint32_t u32Value;
    615             rc = MMGCRamReadNoTrapHandler(&u32Value, GCPtrSrc, cbSize);
    616             if (rc != VINF_SUCCESS)
    617                 break;
    618             rc = IOMIOPortWrite(pVM, uPort, u32Value, cbSize);
    619             if (rc == VINF_IOM_HC_IOPORT_WRITE)
    620                 break;
    621             GCPtrSrc = (RTGCPTR)((RTUINTPTR)GCPtrSrc + cbSize);
    622             pRegFrame->esi += cbSize;
    623             cTransfers--;
    624         }
    625 
    626         MMGCRamDeregisterTrapHandler(pVM);
    627 
    628         /* Update ecx on exit. */
    629         if (pCpu->prefix & PREFIX_REP)
    630             pRegFrame->ecx = cTransfers;
    631     }
    632     return rc;
    633 }
    634 
    635 
    636422/**
    637423 * Attempts to service an IN/OUT instruction.
Note: See TracChangeset for help on using the changeset viewer.

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