- Timestamp:
- Apr 19, 2007 8:54:41 AM (18 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/Makefile
r2163 r2201 100 100 VMMAll/DBGFAll.cpp \ 101 101 VMMAll/IOMAll.cpp \ 102 VMMAll/IOMAllMMIO.cpp \ 102 103 VMMAll/MMAll.cpp \ 103 104 VMMAll/MMAllHyper.cpp \ -
trunk/src/VBox/VMM/VMMAll/IOMAll.cpp
r1828 r2201 884 884 return VINF_SUCCESS; 885 885 } 886 887 888 886 /** 889 887 * Writes the string buffer of an I/O port register. … … 1005 1003 } 1006 1004 1007 1008 //#undef LOG_GROUP1009 //#define LOG_GROUP LOG_GROUP_IOM_MMIO1010 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_STATISTICS1030 PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys);1031 if (!pStats && (!pRange || pRange->cbSize <= PAGE_SIZE))1032 # ifdef IN_RING31033 pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange ? pRange->pszDesc : NULL);1034 # else1035 return VINF_IOM_HC_MMIO_READ;1036 # endif1037 #endif /* VBOX_WITH_STATISTICS */1038 #ifdef IN_RING31039 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_STATISTICS1048 if (pStats)1049 STAM_PROFILE_ADV_START(&pStats->CTXALLSUFF(ProfRead), a);1050 #endif1051 int rc = pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhys, pu32Value, cbValue);1052 #ifdef VBOX_WITH_STATISTICS1053 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 #endif1058 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_RING31090 /*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_STATISTICS1099 if (pStats)1100 STAM_COUNTER_INC(&pStats->CTXALLSUFF(Read));1101 # endif1102 *pu32Value = 0;1103 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));1104 return VINF_SUCCESS;1105 }1106 #endif1107 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_STATISTICS1131 PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys);1132 if (!pStats && (!pRange || pRange->cbSize <= PAGE_SIZE))1133 # ifdef IN_RING31134 pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange ? pRange->pszDesc : NULL);1135 # else1136 return VINF_IOM_HC_MMIO_WRITE;1137 # endif1138 #endif /* VBOX_WITH_STATISTICS */1139 1140 /*1141 * Perform the write if we found a range.1142 */1143 #ifdef IN_RING31144 if (pRange)1145 #else /* !IN_RING3 */1146 if (pRange && pRange->pfnWriteCallback)1147 #endif /* !IN_RING3 */1148 {1149 #ifdef VBOX_WITH_STATISTICS1150 if (pStats)1151 STAM_PROFILE_ADV_START(&pStats->CTXALLSUFF(ProfWrite), a);1152 #endif1153 int rc = pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhys, &u32Value, cbValue);1154 #ifdef VBOX_WITH_STATISTICS1155 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 #endif1160 Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, u32Value, cbValue, rc));1161 return rc;1162 }1163 1164 #ifndef IN_RING31165 /*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_STATISTICS1174 if (pStats)1175 STAM_COUNTER_INC(&pStats->CTXALLSUFF(Write));1176 # endif1177 Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, u32Value, cbValue));1178 return VINF_SUCCESS;1179 }1180 #endif1181 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 1187 1005 /** 1188 1006 * Checks that the operation is allowed according to the IOPL -
trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
r2180 r2201 45 45 #include <iprt/string.h> 46 46 47 #ifndef IN_RING348 49 /** @def IOMGC_MOVS_SUPPORT50 * Define IOMGC_MOVS_SUPPORT for movsb/w/d support in GC and R0.51 */52 #define IOMGC_MOVS_SUPPORT53 54 47 /******************************************************************************* 55 48 * Internal Functions * … … 467 460 468 461 469 #ifdef IOMGC_MOVS_SUPPORT470 471 462 inline int iomRamRead(PVM pVM, void *pDest, RTGCPTR GCSrc, uint32_t cb) 472 463 { … … 715 706 if (rc != VINF_SUCCESS) 716 707 { 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)); 718 709 break; 719 710 } … … 744 735 return rc; 745 736 } 746 #endif /* IOMGC_MOVS_SUPPORT */747 737 748 738 … … 1417 1407 1418 1408 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 */ 1419 IOMDECL(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) 1419 1440 #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 */ 1521 IOMDECL(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 */ 1595 IOMDECL(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 */ 1703 IOMDECL(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 420 420 } 421 421 422 423 /**424 * [REP*] INSB/INSW/INSD425 * 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_STATISTICS436 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIns);437 #endif438 439 /*440 * We do not support REPNE, 16-bit addressing or decrementing destination441 * pointer. Segment prefixes are deliberately ignored, as per the instruction specification.442 */443 if ( pCpu->prefix & PREFIX_REPNE444 || (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 the450 * 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 else457 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 as499 * 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/OUTSD529 * 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_STATISTICS540 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOuts);541 #endif542 543 /*544 * We do not support segment prefixes, REPNE, 16-bit addressing or545 * 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 else563 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 as605 * 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 636 422 /** 637 423 * Attempts to service an IN/OUT instruction.
Note:
See TracChangeset
for help on using the changeset viewer.