- Timestamp:
- Apr 19, 2007 12:00:24 PM (18 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
r2201 r2217 1587 1587 * ES:EDI,DX[,ECX] 1588 1588 * 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 */ 1599 IOMDECL(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 * 1589 1688 * @returns VBox status code. 1590 1689 * … … 1595 1694 IOMDECL(int) IOMInterpretINS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu) 1596 1695 { 1597 #ifdef VBOX_WITH_STATISTICS1598 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIns);1599 #endif1600 1601 /*1602 * We do not support REPNE or decrementing destination1603 * pointer. Segment prefixes are deliberately ignored, as per the instruction specification.1604 */1605 if ( pCpu->prefix & PREFIX_REPNE1606 || pRegFrame->eflags.Bits.u1DF)1607 return VINF_IOM_HC_IOPORT_READ;1608 1609 1696 /* 1610 1697 * Get port number directly from the register (no need to bother the … … 1619 1706 1620 1707 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 */ 1728 IOMDECL(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); 1650 1793 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 1657 1803 #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; 1688 1810 return rc; 1689 1811 } … … 1703 1825 IOMDECL(int) IOMInterpretOUTS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu) 1704 1826 { 1705 #ifdef VBOX_WITH_STATISTICS1706 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOuts);1707 #endif1708 1709 /*1710 * We do not support segment prefixes, REPNE or1711 * 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 1827 /* 1718 1828 * Get port number from the first parameter. … … 1729 1839 1730 1840 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 1221 1221 } 1222 1222 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 1227 1225 ) 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 1228 1245 { 1229 1246 if (IoExitInfo.n.u1Type == 0) … … 1246 1263 } 1247 1264 } 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; 1260 1275 1261 1276 Log2(("Failed IO at %VGv %x size %d\n", pCtx->eip, IoExitInfo.n.u16Port, uIOSize)); 1262 1263 1277 break; 1264 1278 }
Note:
See TracChangeset
for help on using the changeset viewer.