VirtualBox

Changeset 2217 in vbox for trunk


Ignore:
Timestamp:
Apr 19, 2007 12:00:24 PM (18 years ago)
Author:
vboxsync
Message:

Added IOMInterpretINSEx & IOMInterpretOUTSEx.
Support ins/outs emulation for SVM. (currently useless, because IDE has no handler for ring 0)

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

Legend:

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

    r2201 r2217  
    15871587 * ES:EDI,DX[,ECX]
    15881588 *
     1589 * @note Assumes caller checked the access privileges (IOMInterpretCheckPortIOAccess)
     1590 *
     1591 * @returns VBox status code.
     1592 *
     1593 * @param   pVM             The virtual machine (GC pointer ofcourse).
     1594 * @param   pRegFrame       Pointer to CPUMCTXCORE guest registers structure.
     1595 * @param   uPort           IO Port
     1596 * @param   uPrefix         IO instruction prefix
     1597 * @param   cbTransfer      Size of transfer unit
     1598 */
     1599IOMDECL(int) IOMInterpretINSEx(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix, uint32_t cbTransfer)
     1600{
     1601    int rc = VINF_SUCCESS;
     1602
     1603#ifdef VBOX_WITH_STATISTICS
     1604    STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIns);
     1605#endif
     1606
     1607    /*
     1608     * We do not support REPNE or decrementing destination
     1609     * pointer. Segment prefixes are deliberately ignored, as per the instruction specification.
     1610     */
     1611    if (   (uPrefix & PREFIX_REPNE)
     1612        || pRegFrame->eflags.Bits.u1DF)
     1613        return VINF_IOM_HC_IOPORT_READ;
     1614
     1615    /*
     1616     * Get bytes/words/dwords count to transfer.
     1617     */
     1618    RTGCUINTREG cTransfers = 1;
     1619    if (uPrefix & PREFIX_REP)
     1620    {
     1621        cTransfers = pRegFrame->ecx;
     1622        if (!cTransfers)
     1623            return VINF_SUCCESS;
     1624    }
     1625
     1626    /* Convert destination address es:edi. */
     1627    RTGCPTR GCPtrDst;
     1628    rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->es, (RTGCPTR)pRegFrame->edi, &pRegFrame->esHid,
     1629                      SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
     1630                      &GCPtrDst, NULL);
     1631    if (VBOX_FAILURE(rc))
     1632    {
     1633        Log(("INS destination address conversion failed -> fallback, rc=%d\n", rc));
     1634        return VINF_IOM_HC_IOPORT_READ;
     1635    }
     1636
     1637    /* Access verification first; we can't recover from traps inside this instruction, as the port read cannot be repeated. */
     1638    uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
     1639
     1640    rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrDst, cTransfers * cbTransfer,
     1641                         X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0));
     1642    if (rc != VINF_SUCCESS)
     1643    {
     1644        Log(("INS will generate a trap -> fallback, rc=%d\n", rc));
     1645        return VINF_IOM_HC_IOPORT_READ;
     1646    }
     1647
     1648    Log(("IOM: rep ins%d port %#x count %d\n", cbTransfer * 8, uPort, cTransfers));
     1649#ifdef IN_GC
     1650    MMGCRamRegisterTrapHandler(pVM);
     1651#endif
     1652
     1653    /* If the device supports string transfers, ask it to do as
     1654     * much as it wants. The rest is done with single-word transfers. */
     1655    const RTGCUINTREG cTransfersOrg = cTransfers;
     1656    rc = IOMIOPortReadString(pVM, uPort, &GCPtrDst, &cTransfers, cbTransfer);
     1657    AssertRC(rc); Assert(cTransfers <= cTransfersOrg);
     1658    pRegFrame->edi += (cTransfersOrg - cTransfers) * cbTransfer;
     1659
     1660    while (cTransfers && rc == VINF_SUCCESS)
     1661    {
     1662        uint32_t u32Value;
     1663        rc = IOMIOPortRead(pVM, uPort, &u32Value, cbTransfer);
     1664        if (rc == VINF_IOM_HC_IOPORT_READ || VBOX_FAILURE(rc))
     1665            break;
     1666        int rc2 = iomRamWrite(pVM, GCPtrDst, &u32Value, cbTransfer);
     1667        Assert(rc2 == VINF_SUCCESS); NOREF(rc2);
     1668        GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + cbTransfer);
     1669        pRegFrame->edi += cbTransfer;
     1670        cTransfers--;
     1671    }
     1672#ifdef IN_GC
     1673    MMGCRamDeregisterTrapHandler(pVM);
     1674#endif
     1675
     1676    /* Update ecx on exit. */
     1677    if (uPrefix & PREFIX_REP)
     1678        pRegFrame->ecx = cTransfers;
     1679
     1680    return rc;
     1681}
     1682
     1683
     1684/**
     1685 * [REP*] INSB/INSW/INSD
     1686 * ES:EDI,DX[,ECX]
     1687 *
    15891688 * @returns VBox status code.
    15901689 *
     
    15951694IOMDECL(int) IOMInterpretINS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
    15961695{
    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 
    16091696    /*
    16101697     * Get port number directly from the register (no need to bother the
     
    16191706
    16201707    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));
     1708    if (RT_UNLIKELY(VBOX_FAILURE(rc)))
     1709        return rc;
     1710
     1711    return IOMInterpretINSEx(pVM, pRegFrame, uPort, pCpu->prefix, cbSize);
     1712}
     1713
     1714/**
     1715 * [REP*] OUTSB/OUTSW/OUTSD
     1716 * DS:ESI,DX[,ECX]
     1717 *
     1718 * @note Assumes caller checked the access privileges (IOMInterpretCheckPortIOAccess)
     1719 *
     1720 * @returns VBox status code.
     1721 *
     1722 * @param   pVM             The virtual machine (GC pointer ofcourse).
     1723 * @param   pRegFrame       Pointer to CPUMCTXCORE guest registers structure.
     1724 * @param   uPort           IO Port
     1725 * @param   uPrefix         IO instruction prefix
     1726 * @param   cbTransfer      Size of transfer unit
     1727 */
     1728IOMDECL(int) IOMInterpretOUTSEx(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix, uint32_t cbTransfer)
     1729{
     1730    int rc = VINF_SUCCESS;
     1731
     1732#ifdef VBOX_WITH_STATISTICS
     1733    STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOuts);
     1734#endif
     1735
     1736    /*
     1737     * We do not support segment prefixes, REPNE or
     1738     * decrementing source pointer.
     1739     */
     1740    if (   (uPrefix & (PREFIX_SEG | PREFIX_REPNE))
     1741        || pRegFrame->eflags.Bits.u1DF)
     1742        return VINF_IOM_HC_IOPORT_WRITE;
     1743
     1744    /*
     1745     * Get bytes/words/dwords count to transfer.
     1746     */
     1747    RTGCUINTREG cTransfers = 1;
     1748    if (uPrefix & PREFIX_REP)
     1749    {
     1750        cTransfers = pRegFrame->ecx;
     1751        if (!cTransfers)
     1752            return VINF_SUCCESS;
     1753    }
     1754
     1755    /* Convert source address ds:esi. */
     1756    RTGCPTR GCPtrSrc;
     1757    rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->ds, (RTGCPTR)pRegFrame->esi, &pRegFrame->dsHid,
     1758                      SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
     1759                      &GCPtrSrc, NULL);
     1760    if (VBOX_FAILURE(rc))
     1761    {
     1762        Log(("OUTS source address conversion failed -> fallback, rc=%d\n", rc));
     1763        return VINF_IOM_HC_IOPORT_WRITE;
     1764    }
     1765
     1766    /* Access verification first; we currently can't recover properly from traps inside this instruction */
     1767    uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
     1768    rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrSrc, cTransfers * cbTransfer,
     1769                         (cpl == 3) ? X86_PTE_US : 0);
     1770    if (rc != VINF_SUCCESS)
     1771    {
     1772        Log(("OUTS will generate a trap -> fallback, rc=%d\n", rc));
     1773        return VINF_IOM_HC_IOPORT_WRITE;
     1774    }
     1775
     1776    Log(("IOM: rep outs%d port %#x count %d\n", cbTransfer * 8, uPort, cTransfers));
     1777#ifdef IN_GC
     1778    MMGCRamRegisterTrapHandler(pVM);
     1779#endif
     1780    /*
     1781     * If the device supports string transfers, ask it to do as
     1782     * much as it wants. The rest is done with single-word transfers.
     1783     */
     1784    const RTGCUINTREG cTransfersOrg = cTransfers;
     1785    rc = IOMIOPortWriteString(pVM, uPort, &GCPtrSrc, &cTransfers, cbTransfer);
     1786    AssertRC(rc); Assert(cTransfers <= cTransfersOrg);
     1787    pRegFrame->esi += (cTransfersOrg - cTransfers) * cbTransfer;
     1788
     1789    while (cTransfers && rc == VINF_SUCCESS)
     1790    {
     1791        uint32_t u32Value;
     1792        rc = iomRamRead(pVM, &u32Value, GCPtrSrc, cbTransfer);
    16501793        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));
     1794            break;
     1795        rc = IOMIOPortWrite(pVM, uPort, u32Value, cbTransfer);
     1796        if (rc == VINF_IOM_HC_IOPORT_WRITE)
     1797            break;
     1798        GCPtrSrc = (RTGCPTR)((RTUINTPTR)GCPtrSrc + cbTransfer);
     1799        pRegFrame->esi += cbTransfer;
     1800        cTransfers--;
     1801    }
     1802
    16571803#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     }
     1804    MMGCRamDeregisterTrapHandler(pVM);
     1805#endif
     1806
     1807    /* Update ecx on exit. */
     1808    if (uPrefix & PREFIX_REP)
     1809        pRegFrame->ecx = cTransfers;
    16881810    return rc;
    16891811}
     
    17031825IOMDECL(int) IOMInterpretOUTS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
    17041826{
    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 
    17171827    /*
    17181828     * Get port number from the first parameter.
     
    17291839
    17301840    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 }
     1841    if (RT_UNLIKELY(VBOX_FAILURE(rc)))
     1842        return rc;
     1843
     1844    return IOMInterpretOUTSEx(pVM, pRegFrame, uPort, pCpu->prefix, cbSize);
     1845}
  • trunk/src/VBox/VMM/VMMR0/HWSVMR0.cpp

    r2176 r2217  
    12211221        }
    12221222
    1223         /* First simple in and out instructions. */
    1224         /** @todo str & rep */
    1225         if (    !IoExitInfo.n.u1REP
    1226             &&  !IoExitInfo.n.u1STR
     1223        if (    IoExitInfo.n.u1REP
     1224            ||  IoExitInfo.n.u1STR
    12271225           )
     1226        {
     1227            uint32_t prefix = 0;
     1228            if (IoExitInfo.n.u1REP)
     1229                prefix |= PREFIX_REP;
     1230
     1231            if (IoExitInfo.n.u1Type == 0)
     1232            {
     1233                Log2(("IOMInterpretOUTSEx %VGv %x size=%d\n", pCtx->eip, IoExitInfo.n.u16Port, uIOSize));
     1234                STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitIOStringWrite);
     1235                rc = IOMInterpretOUTSEx(pVM, CPUMCTX2CORE(pCtx), IoExitInfo.n.u16Port, prefix, uIOSize);
     1236            }
     1237            else
     1238            {
     1239                Log2(("IOMInterpretINSEx  %VGv %x size=%d\n", pCtx->eip, IoExitInfo.n.u16Port, uIOSize));
     1240                STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitIOStringRead);
     1241                rc = IOMInterpretINSEx(pVM, CPUMCTX2CORE(pCtx), IoExitInfo.n.u16Port, prefix, uIOSize);
     1242            }
     1243        }
     1244        else
    12281245        {
    12291246            if (IoExitInfo.n.u1Type == 0)
     
    12461263                }
    12471264            }
    1248             if (rc == VINF_SUCCESS)
    1249             {
    1250                 /* Update EIP and continue execution. */
    1251                 pCtx->eip = pVMCB->ctrl.u64ExitInfo2;      /* RIP/EIP of the next instruction is saved in EXITINFO2. */
    1252                 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
    1253                 goto ResumeExecution;
    1254             }
    1255             Assert(rc == VINF_IOM_HC_IOPORT_READ || rc == VINF_IOM_HC_IOPORT_WRITE);
    1256             rc = (IoExitInfo.n.u1Type == 0) ? VINF_IOM_HC_IOPORT_WRITE : VINF_IOM_HC_IOPORT_READ;
    1257         }
    1258         else
    1259             rc = VINF_IOM_HC_IOPORT_READWRITE;
     1265        }
     1266        if (rc == VINF_SUCCESS)
     1267        {
     1268            /* Update EIP and continue execution. */
     1269            pCtx->eip = pVMCB->ctrl.u64ExitInfo2;      /* RIP/EIP of the next instruction is saved in EXITINFO2. */
     1270            STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
     1271            goto ResumeExecution;
     1272        }
     1273        Assert(rc == VINF_IOM_HC_IOPORT_READ || rc == VINF_IOM_HC_IOPORT_WRITE);
     1274        rc = (IoExitInfo.n.u1Type == 0) ? VINF_IOM_HC_IOPORT_WRITE : VINF_IOM_HC_IOPORT_READ;
    12601275
    12611276        Log2(("Failed IO at %VGv %x size %d\n", pCtx->eip, IoExitInfo.n.u16Port, uIOSize));
    1262 
    12631277        break;
    12641278    }
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