- Timestamp:
- Apr 19, 2007 1:48:01 PM (18 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/EM.cpp
r2177 r2226 1271 1271 if (VBOX_SUCCESS(rc)) 1272 1272 { 1273 #ifdef VBOX_WITH_STATISTICS1274 switch (Cpu.pCurInstr->opcode)1275 {1276 case OP_INSB:1277 case OP_INSWD:1278 case OP_IN:1279 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->StatIn);1280 break;1281 1282 case OP_OUTSB:1283 case OP_OUTSWD:1284 case OP_OUT:1285 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->StatOut);1286 break;1287 }1288 #endif1289 1290 1273 if (!(Cpu.prefix & (PREFIX_REP | PREFIX_REPNE))) 1291 1274 { 1292 OP_PARAMVAL ParmVal;1293 int rc;1294 1275 switch (Cpu.pCurInstr->opcode) 1295 1276 { 1296 1277 case OP_IN: 1297 1278 { 1298 rc = DISQueryParamVal(CPUMCTX2CORE(pCtx), &Cpu, &Cpu.param2, &ParmVal, PARAM_SOURCE); 1299 if ( VBOX_FAILURE(rc) 1300 || ParmVal.type != PARMTYPE_IMMEDIATE) 1301 break; 1302 1303 if (!(Cpu.param1.flags & (USE_REG_GEN8 | USE_REG_GEN16 | USE_REG_GEN32))) 1304 break; 1305 1306 /* Make sure port access is allowed */ 1307 rc = IOMInterpretCheckPortIOAccess(pVM, CPUMCTX2CORE(pCtx), ParmVal.val.val16, Cpu.param1.size); 1308 if (rc != VINF_SUCCESS) 1279 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->StatIn); 1280 1281 rc = IOMInterpretIN(pVM, CPUMCTX2CORE(pCtx), &Cpu); 1282 if (rc == VINF_SUCCESS) 1309 1283 { 1310 if (rc == VINF_EM_RAW_GUEST_TRAP) 1311 rc = emR3RawGuestTrap(pVM); 1312 1284 pCtx->eip += Cpu.opsize; 1285 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1286 return VINF_SUCCESS; 1287 } 1288 else 1289 if (rc == VINF_EM_RAW_GUEST_TRAP) 1290 { 1291 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1292 rc = emR3RawGuestTrap(pVM); 1313 1293 return rc; 1314 1294 } 1315 1316 uint32_t u32Value = 0; 1317 switch (Cpu.param1.size) 1318 { 1319 case 1: 1320 Assert(Cpu.param1.base.reg_gen8 == USE_REG_AL); 1321 rc = IOMIOPortRead(pVM, ParmVal.val.val16, &u32Value, sizeof(uint8_t)); 1322 if (VBOX_SUCCESS(rc)) 1323 { 1324 pCtx->eax = (pCtx->eax & ~0xFF) | (uint8_t)u32Value; 1325 Log(("EMU: in8 %x, %x\n", ParmVal.val.val16, pCtx->eax & 0xFF)); 1326 pCtx->eip += Cpu.opsize; 1327 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1328 return rc; 1329 } 1330 AssertRC(rc); 1331 break; 1332 1333 case 2: 1334 Assert(Cpu.param1.base.reg_gen16 == USE_REG_AX); 1335 rc = IOMIOPortRead(pVM, ParmVal.val.val16, &u32Value, sizeof(uint16_t)); 1336 if (VBOX_SUCCESS(rc)) 1337 { 1338 pCtx->eax = (pCtx->eax & ~0xFFFF) | (uint16_t)u32Value; 1339 Log(("EMU: in16 %x, %x\n", ParmVal.val.val16, pCtx->eax & 0xFFFF)); 1340 pCtx->eip += Cpu.opsize; 1341 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1342 return rc; 1343 } 1344 AssertRC(rc); 1345 break; 1346 1347 case 4: 1348 Assert(Cpu.param1.base.reg_gen32 == USE_REG_EAX); 1349 rc = IOMIOPortRead(pVM, ParmVal.val.val16, &u32Value, sizeof(uint32_t)); 1350 if (VBOX_SUCCESS(rc)) 1351 { 1352 pCtx->eax = u32Value; 1353 Log(("EMU: in32 %x, %x\n", ParmVal.val.val16, pCtx->eax)); 1354 pCtx->eip += Cpu.opsize; 1355 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1356 return rc; 1357 } 1358 AssertRC(rc); 1359 break; 1360 1361 default: 1362 AssertMsgFailed(("Unexpected port size %d\n", ParmVal.size)); 1363 break; 1364 } 1295 /* emulate in the recompiler */ 1365 1296 break; 1366 1297 } … … 1368 1299 case OP_OUT: 1369 1300 { 1370 // it really is the destination, but we're interested in the destination value. hence we specify PARAM_SOURCE (bit of a hack) 1371 rc = DISQueryParamVal(CPUMCTX2CORE(pCtx), &Cpu, &Cpu.param1, &ParmVal, PARAM_SOURCE); 1372 if ( VBOX_FAILURE(rc) 1373 || ParmVal.type != PARMTYPE_IMMEDIATE) 1374 break; 1375 OP_PARAMVAL ParmVal2; 1376 rc = DISQueryParamVal(CPUMCTX2CORE(pCtx), &Cpu, &Cpu.param2, &ParmVal2, PARAM_SOURCE); 1377 if ( VBOX_FAILURE(rc) 1378 || ParmVal2.type != PARMTYPE_IMMEDIATE) 1379 break; 1380 1381 /* Make sure port access is allowed */ 1382 rc = IOMInterpretCheckPortIOAccess(pVM, CPUMCTX2CORE(pCtx), ParmVal.val.val16, Cpu.param1.size); 1383 if (rc != VINF_SUCCESS) 1301 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->StatOut); 1302 1303 rc = IOMInterpretOUT(pVM, CPUMCTX2CORE(pCtx), &Cpu); 1304 if (rc == VINF_SUCCESS) 1384 1305 { 1385 if (rc == VINF_EM_RAW_GUEST_TRAP) 1386 rc = emR3RawGuestTrap(pVM); 1387 1306 pCtx->eip += Cpu.opsize; 1307 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1308 return VINF_SUCCESS; 1309 } 1310 else 1311 if (rc == VINF_EM_RAW_GUEST_TRAP) 1312 { 1313 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1314 rc = emR3RawGuestTrap(pVM); 1388 1315 return rc; 1389 1316 } 1390 1391 AssertMsg(Cpu.param2.size == ParmVal2.size, ("size %d vs %d\n", Cpu.param2.size, ParmVal2.size)); 1392 switch (ParmVal2.size) 1393 { 1394 case 1: 1395 Log(("EMU: out8 %x, %x\n", ParmVal.val.val16, ParmVal2.val.val8)); 1396 rc = IOMIOPortWrite(pVM, ParmVal.val.val16, ParmVal2.val.val8, sizeof(ParmVal2.val.val8)); 1397 if (VBOX_SUCCESS(rc)) 1398 { 1399 pCtx->eip += Cpu.opsize; 1400 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1401 return rc; 1402 } 1403 AssertRC(rc); 1404 break; 1405 1406 case 2: 1407 Log(("EMU: out16 %x, %x\n", ParmVal.val.val16, ParmVal2.val.val16)); 1408 rc = IOMIOPortWrite(pVM, ParmVal.val.val16, ParmVal2.val.val16, sizeof(ParmVal2.val.val16)); 1409 if (VBOX_SUCCESS(rc)) 1410 { 1411 pCtx->eip += Cpu.opsize; 1412 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1413 return rc; 1414 } 1415 AssertRC(rc); 1416 break; 1417 1418 case 4: 1419 Log(("EMU: out32 %x, %x\n", ParmVal.val.val16, ParmVal2.val.val32)); 1420 rc = IOMIOPortWrite(pVM, ParmVal.val.val16, ParmVal2.val.val32, sizeof(ParmVal2.val.val32)); 1421 if (VBOX_SUCCESS(rc)) 1422 { 1423 pCtx->eip += Cpu.opsize; 1424 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1425 return rc; 1426 } 1427 AssertRC(rc); 1428 break; 1429 1430 default: 1431 AssertMsgFailed(("Unexpected port size %d\n", ParmVal2.size)); 1432 break; 1433 } 1317 /* emulate in the recompiler */ 1434 1318 break; 1435 1319 } … … 1446 1330 case OP_INSWD: 1447 1331 { 1448 /* 1449 * Do not optimize the destination address decrement case (not worth the effort) 1450 * and likewise for 16 bit address size (would need to use and update only cx/di). 1451 */ 1452 if (pCtx->eflags.Bits.u1DF || Cpu.addrmode != CPUMODE_32BIT) 1453 break; 1454 /* 1455 * Get port number and transfer count directly from the registers (no need to bother the 1456 * disassembler). And get the I/O register size from the opcode / prefix. 1457 */ 1458 uint32_t uPort = pCtx->edx & 0xffff; 1459 RTGCUINTREG cTransfers = pCtx->ecx; 1460 unsigned cbUnit; 1461 if (Cpu.pCurInstr->opcode == OP_INSB) 1462 cbUnit = 1; 1463 else 1464 cbUnit = Cpu.opmode == CPUMODE_32BIT ? 4 : 2; 1465 1466 RTGCPTR GCPtrDst = pCtx->edi; 1467 uint32_t cpl = (pCtx->eflags.Bits.u1VM) ? 3 : (pCtx->ss & X86_SEL_RPL); 1468 1469 /* Access verification first; we can't recover from traps inside this instruction, as the port read cannot be repeated. */ 1470 rc = PGMVerifyAccess(pVM, GCPtrDst, cTransfers * cbUnit, 1471 X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0)); 1472 if (rc != VINF_SUCCESS) 1332 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->StatIn); 1333 rc = IOMInterpretINS(pVM, CPUMCTX2CORE(pCtx), &Cpu); 1334 if (rc == VINF_SUCCESS) 1473 1335 { 1474 Log(("EMU: rep ins%d will generate a trap -> fallback, rc=%d\n", cbUnit * 8, rc)); 1475 break; 1476 } 1477 1478 Log(("EMU: rep ins%d port %#x count %d\n", cbUnit * 8, uPort, cTransfers)); 1479 1480 /* Make sure port access is allowed */ 1481 rc = IOMInterpretCheckPortIOAccess(pVM, CPUMCTX2CORE(pCtx), uPort, cbUnit); 1482 if (rc != VINF_SUCCESS) 1483 { 1484 if (rc == VINF_EM_RAW_GUEST_TRAP) 1485 rc = emR3RawGuestTrap(pVM); 1486 1336 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1337 pCtx->eip += Cpu.opsize; 1487 1338 return rc; 1488 1339 } 1489 1490 /* 1491 * If the device supports string transfers, ask it to do as 1492 * much as it wants. The rest is done with single-word transfers. 1493 */ 1494 rc = IOMIOPortReadString(pVM, uPort, &GCPtrDst, &cTransfers, cbUnit); 1495 AssertRC(rc); Assert(cTransfers <= pCtx->ecx); 1496 1497 while (cTransfers && rc == VINF_SUCCESS) 1340 else 1341 if (rc == VINF_EM_RAW_GUEST_TRAP) 1498 1342 { 1499 uint32_t u32Value; 1500 rc = IOMIOPortRead(pVM, uPort, &u32Value, cbUnit); 1501 AssertRC(rc); 1502 int rc2 = PGMPhysWriteGCPtrDirty(pVM, GCPtrDst, &u32Value, cbUnit); 1503 AssertRC(rc2); 1504 GCPtrDst += cbUnit; 1505 cTransfers--; 1343 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1344 rc = emR3RawGuestTrap(pVM); 1345 return rc; 1506 1346 } 1507 pCtx->edi += (pCtx->ecx - cTransfers) * cbUnit; 1508 pCtx->ecx = cTransfers; 1509 if (!cTransfers && VBOX_SUCCESS(rc)) 1510 pCtx->eip += Cpu.opsize; 1511 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1512 return rc; 1347 /* emulate in the recompiler */ 1348 break; 1513 1349 } 1514 1350 case OP_OUTSB: 1515 1351 case OP_OUTSWD: 1516 1352 { 1517 /* 1518 * Do not optimize the source address decrement case (not worth the effort) 1519 * and likewise for 16 bit address size (would need to use and update only cx/si). 1520 */ 1521 if (pCtx->eflags.Bits.u1DF || Cpu.addrmode != CPUMODE_32BIT) 1522 break; 1523 /* 1524 * Get port number and transfer count directly from the registers (no need to bother the 1525 * disassembler). And get the I/O register size from the opcode / prefix. 1526 */ 1527 uint32_t uPort = pCtx->edx & 0xffff; 1528 RTGCUINTREG cTransfers = pCtx->ecx; 1529 unsigned cbUnit; 1530 if (Cpu.pCurInstr->opcode == OP_OUTSB) 1531 cbUnit = 1; 1532 else 1533 cbUnit = Cpu.opmode == CPUMODE_32BIT ? 4 : 2; 1534 1535 RTGCPTR GCPtrSrc = pCtx->esi; 1536 uint32_t cpl = (pCtx->eflags.Bits.u1VM) ? 3 : (pCtx->ss & X86_SEL_RPL); 1537 1538 /* Access verification first; we currently can't recover properly from traps inside this instruction */ 1539 rc = PGMVerifyAccess(pVM, GCPtrSrc, cTransfers * cbUnit, ((cpl == 3) ? X86_PTE_US : 0)); 1540 if (rc != VINF_SUCCESS) 1353 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->StatOut); 1354 rc = IOMInterpretOUTS(pVM, CPUMCTX2CORE(pCtx), &Cpu); 1355 if (rc == VINF_SUCCESS) 1541 1356 { 1542 Log(("EMU: rep outs%d will generate a trap -> fallback, rc=%d\n", cbUnit * 8, rc)); 1543 break; 1544 } 1545 1546 Log(("EMU: rep outs%d port %#x count %d\n", cbUnit * 8, uPort, cTransfers)); 1547 1548 /* Make sure port access is allowed */ 1549 rc = IOMInterpretCheckPortIOAccess(pVM, CPUMCTX2CORE(pCtx), uPort, cbUnit); 1550 if (rc != VINF_SUCCESS) 1551 { 1552 if (rc == VINF_EM_RAW_GUEST_TRAP) 1553 rc = emR3RawGuestTrap(pVM); 1554 1357 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1358 pCtx->eip += Cpu.opsize; 1555 1359 return rc; 1556 1360 } 1557 1558 /* 1559 * If the device supports string transfers, ask it to do as 1560 * much as it wants. The rest is done with single-word transfers. 1561 */ 1562 rc = IOMIOPortWriteString(pVM, uPort, &GCPtrSrc, &cTransfers, cbUnit); 1563 AssertRC(rc); Assert(cTransfers <= pCtx->ecx); 1564 1565 while (cTransfers && rc == VINF_SUCCESS) 1361 else 1362 if (rc == VINF_EM_RAW_GUEST_TRAP) 1566 1363 { 1567 uint32_t u32Value; 1568 rc = PGMPhysReadGCPtr(pVM, &u32Value, GCPtrSrc, cbUnit); 1569 Assert(rc == VINF_SUCCESS); 1570 rc = IOMIOPortWrite(pVM, uPort, u32Value, cbUnit); 1571 AssertRC(rc); 1572 GCPtrSrc += cbUnit; 1573 cTransfers--; 1364 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1365 rc = emR3RawGuestTrap(pVM); 1366 return rc; 1574 1367 } 1575 pCtx->esi += (pCtx->ecx - cTransfers) * cbUnit; 1576 pCtx->ecx = cTransfers; 1577 if (!cTransfers && VBOX_SUCCESS(rc)) 1578 pCtx->eip += Cpu.opsize; 1579 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1580 return rc; 1368 /* emulate in the recompiler */ 1369 break; 1581 1370 } 1582 1371 } -
trunk/src/VBox/VMM/VMMAll/IOMAll.cpp
r2201 r2226 38 38 39 39 40 /******************************************************************************* 41 * Global Variables * 42 *******************************************************************************/ 43 44 /** 45 * Array for fast recode of the operand size (1/2/4/8 bytes) to bit shift value. 46 */ 47 static const unsigned g_aSize2Shift[] = 48 { 49 ~0, /* 0 - invalid */ 50 0, /* *1 == 2^0 */ 51 1, /* *2 == 2^1 */ 52 ~0, /* 3 - invalid */ 53 2, /* *4 == 2^2 */ 54 ~0, /* 5 - invalid */ 55 ~0, /* 6 - invalid */ 56 ~0, /* 7 - invalid */ 57 3 /* *8 == 2^3 */ 58 }; 59 60 /** 61 * Macro for fast recode of the operand size (1/2/4/8 bytes) to bit shift value. 62 */ 63 #define SIZE2SHIFT(cb) (g_aSize2Shift[cb]) 64 65 /** 66 * Calculates the size of register parameter. 67 * 68 * @returns 1, 2, 4 on success. 69 * @returns 0 if non-register parameter. 70 * @param pCpu Pointer to current disassembler context. 71 * @param pParam Pointer to parameter of instruction to proccess. 72 */ 73 static unsigned iomGCGetRegSize(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam) 74 { 75 if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_IMMEDIATE8 | USE_IMMEDIATE16 | USE_IMMEDIATE32 | USE_IMMEDIATE16_SX8 | USE_IMMEDIATE32_SX8)) 76 return 0; 77 78 if (pParam->flags & USE_REG_GEN32) 79 return 4; 80 81 if (pParam->flags & USE_REG_GEN16) 82 return 2; 83 84 if (pParam->flags & USE_REG_GEN8) 85 return 1; 86 87 if (pParam->flags & USE_REG_SEG) 88 return 2; 89 return 0; 90 } 91 92 /** 93 * Returns the contents of register or immediate data of instruction's parameter. 94 * 95 * @returns true on success. 96 * 97 * @param pCpu Pointer to current disassembler context. 98 * @param pParam Pointer to parameter of instruction to proccess. 99 * @param pRegFrame Pointer to CPUMCTXCORE guest structure. 100 * @param pu32Data Where to store retrieved data. 101 * @param pcbSize Where to store the size of data (1, 2, 4). 102 */ 103 static bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize) 104 { 105 if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32)) 106 { 107 *pcbSize = 0; 108 *pu32Data = 0; 109 return false; 110 } 111 112 if (pParam->flags & USE_REG_GEN32) 113 { 114 *pcbSize = 4; 115 DISFetchReg32(pRegFrame, pParam->base.reg_gen32, pu32Data); 116 return true; 117 } 118 119 if (pParam->flags & USE_REG_GEN16) 120 { 121 *pcbSize = 2; 122 DISFetchReg16(pRegFrame, pParam->base.reg_gen16, (uint16_t *)pu32Data); 123 return true; 124 } 125 126 if (pParam->flags & USE_REG_GEN8) 127 { 128 *pcbSize = 1; 129 DISFetchReg8(pRegFrame, pParam->base.reg_gen8, (uint8_t *)pu32Data); 130 return true; 131 } 132 133 if (pParam->flags & (USE_IMMEDIATE32|USE_IMMEDIATE32_SX8)) 134 { 135 *pcbSize = 4; 136 *pu32Data = (uint32_t)pParam->parval; 137 return true; 138 } 139 140 if (pParam->flags & (USE_IMMEDIATE16|USE_IMMEDIATE16_SX8)) 141 { 142 *pcbSize = 2; 143 *pu32Data = (uint16_t)pParam->parval; 144 return true; 145 } 146 147 if (pParam->flags & USE_IMMEDIATE8) 148 { 149 *pcbSize = 1; 150 *pu32Data = (uint8_t)pParam->parval; 151 return true; 152 } 153 154 if (pParam->flags & USE_REG_SEG) 155 { 156 *pcbSize = 2; 157 DISFetchRegSeg(pRegFrame, pParam->base.reg_seg, (RTSEL *)pu32Data); 158 return true; 159 } /* Else - error. */ 160 161 *pcbSize = 0; 162 *pu32Data = 0; 163 return false; 164 } 165 166 167 /** 168 * Saves data to 8/16/32 general purpose or segment register defined by 169 * instruction's parameter. 170 * 171 * @returns true on success. 172 * @param pCpu Pointer to current disassembler context. 173 * @param pParam Pointer to parameter of instruction to proccess. 174 * @param pRegFrame Pointer to CPUMCTXCORE guest structure. 175 * @param u32Data 8/16/32 bit data to store. 176 */ 177 static bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, unsigned u32Data) 178 { 179 if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_IMMEDIATE8 | USE_IMMEDIATE16 | USE_IMMEDIATE32 | USE_IMMEDIATE32_SX8 | USE_IMMEDIATE16_SX8)) 180 { 181 return false; 182 } 183 184 if (pParam->flags & USE_REG_GEN32) 185 { 186 DISWriteReg32(pRegFrame, pParam->base.reg_gen32, u32Data); 187 return true; 188 } 189 190 if (pParam->flags & USE_REG_GEN16) 191 { 192 DISWriteReg16(pRegFrame, pParam->base.reg_gen16, (uint16_t)u32Data); 193 return true; 194 } 195 196 if (pParam->flags & USE_REG_GEN8) 197 { 198 DISWriteReg8(pRegFrame, pParam->base.reg_gen8, (uint8_t)u32Data); 199 return true; 200 } 201 202 if (pParam->flags & USE_REG_SEG) 203 { 204 DISWriteRegSeg(pRegFrame, pParam->base.reg_seg, (RTSEL)u32Data); 205 return true; 206 } 207 208 /* Else - error. */ 209 return false; 210 } 211 212 /* 213 * Internal - statistics only. 214 */ 215 inline void iomGCMMIOStatLength(PVM pVM, unsigned cb) 216 { 217 #ifdef VBOX_WITH_STATISTICS 218 switch (cb) 219 { 220 case 1: 221 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO1Byte); 222 break; 223 case 2: 224 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO2Bytes); 225 break; 226 case 4: 227 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO4Bytes); 228 break; 229 default: 230 /* No way. */ 231 AssertMsgFailed(("Invalid data length %d\n", cb)); 232 break; 233 } 234 #else 235 NOREF(pVM); NOREF(cb); 236 #endif 237 } 238 40 239 /** 41 240 * Registers a Port IO GC handler. … … 1094 1293 return VINF_SUCCESS; 1095 1294 } 1295 1296 /** 1297 * IN <AL|AX|EAX>, <DX|imm16> 1298 * 1299 * @returns VBox status code. 1300 * 1301 * @param pVM The virtual machine (GC pointer ofcourse). 1302 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure. 1303 * @param pCpu Disassembler CPU state. 1304 */ 1305 IOMDECL(int) IOMInterpretIN(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu) 1306 { 1307 #ifdef IN_GC 1308 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIn); 1309 #endif 1310 1311 /* 1312 * Get port number from second parameter. 1313 * And get the register size from the first parameter. 1314 */ 1315 uint32_t uPort = 0; 1316 unsigned cbSize = 0; 1317 bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uPort, &cbSize); 1318 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc); 1319 1320 cbSize = iomGCGetRegSize(pCpu, &pCpu->param1); 1321 Assert(cbSize > 0); 1322 int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize); 1323 if (rc == VINF_SUCCESS) 1324 { 1325 /* 1326 * Attemp to read the port. 1327 */ 1328 uint32_t u32Data = ~0U; 1329 rc = IOMIOPortRead(pVM, uPort, &u32Data, cbSize); 1330 if (rc == VINF_SUCCESS) 1331 { 1332 /* 1333 * Store the result in the AL|AX|EAX register. 1334 */ 1335 fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, u32Data); 1336 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc); 1337 } 1338 } 1339 return rc; 1340 } 1341 1342 1343 /** 1344 * OUT <DX|imm16>, <AL|AX|EAX> 1345 * 1346 * @returns VBox status code. 1347 * 1348 * @param pVM The virtual machine (GC pointer ofcourse). 1349 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure. 1350 * @param pCpu Disassembler CPU state. 1351 */ 1352 IOMDECL(int) IOMInterpretOUT(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu) 1353 { 1354 #ifdef IN_GC 1355 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOut); 1356 #endif 1357 1358 /* 1359 * Get port number from first parameter. 1360 * And get the register size and value from the second parameter. 1361 */ 1362 uint32_t uPort = 0; 1363 unsigned cbSize = 0; 1364 bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uPort, &cbSize); 1365 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc); 1366 1367 int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize); 1368 if (rc == VINF_SUCCESS) 1369 { 1370 uint32_t u32Data = 0; 1371 fRc = iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &u32Data, &cbSize); 1372 AssertMsg(fRc, ("Failed to get reg value!\n")); NOREF(fRc); 1373 1374 /* 1375 * Attemp to write to the port. 1376 */ 1377 rc = IOMIOPortWrite(pVM, uPort, u32Data, cbSize); 1378 } 1379 return rc; 1380 } -
trunk/src/VBox/VMM/VMMGC/IOMGC.cpp
r2202 r2226 46 46 47 47 48 /*******************************************************************************49 * Internal Functions *50 *******************************************************************************/51 static unsigned iomGCGetRegSize(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam);52 static bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize);53 static bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t u32Data);54 55 56 /*******************************************************************************57 * Global Variables *58 *******************************************************************************/59 60 /**61 * Array for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.62 */63 static const unsigned g_aSize2Shift[] =64 {65 ~0, /* 0 - invalid */66 0, /* *1 == 2^0 */67 1, /* *2 == 2^1 */68 ~0, /* 3 - invalid */69 2, /* *4 == 2^2 */70 ~0, /* 5 - invalid */71 ~0, /* 6 - invalid */72 ~0, /* 7 - invalid */73 3 /* *8 == 2^3 */74 };75 76 /**77 * Macro for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.78 */79 #define SIZE2SHIFT(cb) (g_aSize2Shift[cb])80 81 /**82 * Calculates the size of register parameter.83 *84 * @returns 1, 2, 4 on success.85 * @returns 0 if non-register parameter.86 * @param pCpu Pointer to current disassembler context.87 * @param pParam Pointer to parameter of instruction to proccess.88 */89 static unsigned iomGCGetRegSize(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam)90 {91 if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_IMMEDIATE8 | USE_IMMEDIATE16 | USE_IMMEDIATE32 | USE_IMMEDIATE16_SX8 | USE_IMMEDIATE32_SX8))92 return 0;93 94 if (pParam->flags & USE_REG_GEN32)95 return 4;96 97 if (pParam->flags & USE_REG_GEN16)98 return 2;99 100 if (pParam->flags & USE_REG_GEN8)101 return 1;102 103 if (pParam->flags & USE_REG_SEG)104 return 2;105 return 0;106 }107 108 /**109 * Returns the contents of register or immediate data of instruction's parameter.110 *111 * @returns true on success.112 *113 * @param pCpu Pointer to current disassembler context.114 * @param pParam Pointer to parameter of instruction to proccess.115 * @param pRegFrame Pointer to CPUMCTXCORE guest structure.116 * @param pu32Data Where to store retrieved data.117 * @param pcbSize Where to store the size of data (1, 2, 4).118 */119 static bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize)120 {121 if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32))122 {123 *pcbSize = 0;124 *pu32Data = 0;125 return false;126 }127 128 if (pParam->flags & USE_REG_GEN32)129 {130 *pcbSize = 4;131 DISFetchReg32(pRegFrame, pParam->base.reg_gen32, pu32Data);132 return true;133 }134 135 if (pParam->flags & USE_REG_GEN16)136 {137 *pcbSize = 2;138 DISFetchReg16(pRegFrame, pParam->base.reg_gen16, (uint16_t *)pu32Data);139 return true;140 }141 142 if (pParam->flags & USE_REG_GEN8)143 {144 *pcbSize = 1;145 DISFetchReg8(pRegFrame, pParam->base.reg_gen8, (uint8_t *)pu32Data);146 return true;147 }148 149 if (pParam->flags & (USE_IMMEDIATE32|USE_IMMEDIATE32_SX8))150 {151 *pcbSize = 4;152 *pu32Data = (uint32_t)pParam->parval;153 return true;154 }155 156 if (pParam->flags & (USE_IMMEDIATE16|USE_IMMEDIATE16_SX8))157 {158 *pcbSize = 2;159 *pu32Data = (uint16_t)pParam->parval;160 return true;161 }162 163 if (pParam->flags & USE_IMMEDIATE8)164 {165 *pcbSize = 1;166 *pu32Data = (uint8_t)pParam->parval;167 return true;168 }169 170 if (pParam->flags & USE_REG_SEG)171 {172 *pcbSize = 2;173 DISFetchRegSeg(pRegFrame, pParam->base.reg_seg, (RTSEL *)pu32Data);174 return true;175 } /* Else - error. */176 177 *pcbSize = 0;178 *pu32Data = 0;179 return false;180 }181 182 183 /**184 * Saves data to 8/16/32 general purpose or segment register defined by185 * instruction's parameter.186 *187 * @returns true on success.188 * @param pCpu Pointer to current disassembler context.189 * @param pParam Pointer to parameter of instruction to proccess.190 * @param pRegFrame Pointer to CPUMCTXCORE guest structure.191 * @param u32Data 8/16/32 bit data to store.192 */193 static bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, unsigned u32Data)194 {195 if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_IMMEDIATE8 | USE_IMMEDIATE16 | USE_IMMEDIATE32 | USE_IMMEDIATE32_SX8 | USE_IMMEDIATE16_SX8))196 {197 return false;198 }199 200 if (pParam->flags & USE_REG_GEN32)201 {202 DISWriteReg32(pRegFrame, pParam->base.reg_gen32, u32Data);203 return true;204 }205 206 if (pParam->flags & USE_REG_GEN16)207 {208 DISWriteReg16(pRegFrame, pParam->base.reg_gen16, (uint16_t)u32Data);209 return true;210 }211 212 if (pParam->flags & USE_REG_GEN8)213 {214 DISWriteReg8(pRegFrame, pParam->base.reg_gen8, (uint8_t)u32Data);215 return true;216 }217 218 if (pParam->flags & USE_REG_SEG)219 {220 DISWriteRegSeg(pRegFrame, pParam->base.reg_seg, (RTSEL)u32Data);221 return true;222 }223 224 /* Else - error. */225 return false;226 }227 228 229 /*230 * Internal - statistics only.231 */232 inline void iomGCMMIOStatLength(PVM pVM, unsigned cb)233 {234 #ifdef VBOX_WITH_STATISTICS235 switch (cb)236 {237 case 1:238 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO1Byte);239 break;240 case 2:241 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO2Bytes);242 break;243 case 4:244 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO4Bytes);245 break;246 default:247 /* No way. */248 AssertMsgFailed(("Invalid data length %d\n", cb));249 break;250 }251 #else252 NOREF(pVM); NOREF(cb);253 #endif254 }255 256 257 /**258 * IN <AL|AX|EAX>, <DX|imm16>259 *260 * @returns VBox status code.261 *262 * @param pVM The virtual machine (GC pointer ofcourse).263 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.264 * @param pCpu Disassembler CPU state.265 */266 IOMDECL(int) IOMInterpretIN(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)267 {268 #ifdef VBOX_WITH_STATISTICS269 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIn);270 #endif271 272 /*273 * Get port number from second parameter.274 * And get the register size from the first parameter.275 */276 uint32_t uPort = 0;277 unsigned cbSize = 0;278 bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uPort, &cbSize);279 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);280 281 cbSize = iomGCGetRegSize(pCpu, &pCpu->param1);282 Assert(cbSize > 0);283 int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);284 if (rc == VINF_SUCCESS)285 {286 /*287 * Attemp to read the port.288 */289 uint32_t u32Data = ~0U;290 rc = IOMIOPortRead(pVM, uPort, &u32Data, cbSize);291 if (rc == VINF_SUCCESS)292 {293 /*294 * Store the result in the AL|AX|EAX register.295 */296 fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, u32Data);297 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);298 }299 }300 return rc;301 }302 303 304 /**305 * OUT <DX|imm16>, <AL|AX|EAX>306 *307 * @returns VBox status code.308 *309 * @param pVM The virtual machine (GC pointer ofcourse).310 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.311 * @param pCpu Disassembler CPU state.312 */313 IOMDECL(int) IOMInterpretOUT(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)314 {315 #ifdef VBOX_WITH_STATISTICS316 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOut);317 #endif318 319 /*320 * Get port number from first parameter.321 * And get the register size and value from the second parameter.322 */323 uint32_t uPort = 0;324 unsigned cbSize = 0;325 bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uPort, &cbSize);326 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);327 328 int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);329 if (rc == VINF_SUCCESS)330 {331 uint32_t u32Data = 0;332 fRc = iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &u32Data, &cbSize);333 AssertMsg(fRc, ("Failed to get reg value!\n")); NOREF(fRc);334 335 /*336 * Attemp to write to the port.337 */338 rc = IOMIOPortWrite(pVM, uPort, u32Data, cbSize);339 }340 return rc;341 }342 48 343 49 /**
Note:
See TracChangeset
for help on using the changeset viewer.