- Timestamp:
- Apr 19, 2007 2:19:16 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/EM.cpp
r2229 r2232 1270 1270 if (VBOX_SUCCESS(rc)) 1271 1271 { 1272 #ifdef VBOX_WITH_STATISTICS1273 switch (Cpu.pCurInstr->opcode)1274 {1275 case OP_INSB:1276 case OP_INSWD:1277 case OP_IN:1278 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->StatIn);1279 break;1280 1281 case OP_OUTSB:1282 case OP_OUTSWD:1283 case OP_OUT:1284 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->StatOut);1285 break;1286 }1287 #endif1288 1289 1272 if (!(Cpu.prefix & (PREFIX_REP | PREFIX_REPNE))) 1290 1273 { 1291 OP_PARAMVAL ParmVal;1292 int rc;1293 1274 switch (Cpu.pCurInstr->opcode) 1294 1275 { 1295 1276 case OP_IN: 1296 1277 { 1297 rc = DISQueryParamVal(CPUMCTX2CORE(pCtx), &Cpu, &Cpu.param2, &ParmVal, PARAM_SOURCE); 1298 if ( VBOX_FAILURE(rc) 1299 || ParmVal.type != PARMTYPE_IMMEDIATE) 1300 break; 1301 1302 if (!(Cpu.param1.flags & (USE_REG_GEN8 | USE_REG_GEN16 | USE_REG_GEN32))) 1303 break; 1304 1305 /* Make sure port access is allowed */ 1306 rc = IOMInterpretCheckPortIOAccess(pVM, CPUMCTX2CORE(pCtx), ParmVal.val.val16, Cpu.param1.size); 1307 if (rc != VINF_SUCCESS) 1278 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->StatIn); 1279 1280 rc = IOMInterpretIN(pVM, CPUMCTX2CORE(pCtx), &Cpu); 1281 if (rc == VINF_SUCCESS) 1308 1282 { 1309 if (rc == VINF_EM_RAW_GUEST_TRAP) 1310 rc = emR3RawGuestTrap(pVM); 1311 1283 pCtx->eip += Cpu.opsize; 1284 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1285 return VINF_SUCCESS; 1286 } 1287 else 1288 if (rc == VINF_EM_RAW_GUEST_TRAP) 1289 { 1290 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1291 rc = emR3RawGuestTrap(pVM); 1312 1292 return rc; 1313 1293 } 1314 1315 uint32_t u32Value = 0; 1316 switch (Cpu.param1.size) 1317 { 1318 case 1: 1319 Assert(Cpu.param1.base.reg_gen8 == USE_REG_AL); 1320 rc = IOMIOPortRead(pVM, ParmVal.val.val16, &u32Value, sizeof(uint8_t)); 1321 if (VBOX_SUCCESS(rc)) 1322 { 1323 pCtx->eax = (pCtx->eax & ~0xFF) | (uint8_t)u32Value; 1324 Log(("EMU: in8 %x, %x\n", ParmVal.val.val16, pCtx->eax & 0xFF)); 1325 pCtx->eip += Cpu.opsize; 1326 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1327 return rc; 1328 } 1329 AssertRC(rc); 1330 break; 1331 1332 case 2: 1333 Assert(Cpu.param1.base.reg_gen16 == USE_REG_AX); 1334 rc = IOMIOPortRead(pVM, ParmVal.val.val16, &u32Value, sizeof(uint16_t)); 1335 if (VBOX_SUCCESS(rc)) 1336 { 1337 pCtx->eax = (pCtx->eax & ~0xFFFF) | (uint16_t)u32Value; 1338 Log(("EMU: in16 %x, %x\n", ParmVal.val.val16, pCtx->eax & 0xFFFF)); 1339 pCtx->eip += Cpu.opsize; 1340 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1341 return rc; 1342 } 1343 AssertRC(rc); 1344 break; 1345 1346 case 4: 1347 Assert(Cpu.param1.base.reg_gen32 == USE_REG_EAX); 1348 rc = IOMIOPortRead(pVM, ParmVal.val.val16, &u32Value, sizeof(uint32_t)); 1349 if (VBOX_SUCCESS(rc)) 1350 { 1351 pCtx->eax = u32Value; 1352 Log(("EMU: in32 %x, %x\n", ParmVal.val.val16, pCtx->eax)); 1353 pCtx->eip += Cpu.opsize; 1354 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1355 return rc; 1356 } 1357 AssertRC(rc); 1358 break; 1359 1360 default: 1361 AssertMsgFailed(("Unexpected port size %d\n", ParmVal.size)); 1362 break; 1363 } 1294 /* emulate in the recompiler */ 1364 1295 break; 1365 1296 } … … 1367 1298 case OP_OUT: 1368 1299 { 1369 // it really is the destination, but we're interested in the destination value. hence we specify PARAM_SOURCE (bit of a hack) 1370 rc = DISQueryParamVal(CPUMCTX2CORE(pCtx), &Cpu, &Cpu.param1, &ParmVal, PARAM_SOURCE); 1371 if ( VBOX_FAILURE(rc) 1372 || ParmVal.type != PARMTYPE_IMMEDIATE) 1373 break; 1374 OP_PARAMVAL ParmVal2; 1375 rc = DISQueryParamVal(CPUMCTX2CORE(pCtx), &Cpu, &Cpu.param2, &ParmVal2, PARAM_SOURCE); 1376 if ( VBOX_FAILURE(rc) 1377 || ParmVal2.type != PARMTYPE_IMMEDIATE) 1378 break; 1379 1380 /* Make sure port access is allowed */ 1381 rc = IOMInterpretCheckPortIOAccess(pVM, CPUMCTX2CORE(pCtx), ParmVal.val.val16, Cpu.param1.size); 1382 if (rc != VINF_SUCCESS) 1300 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->StatOut); 1301 1302 rc = IOMInterpretOUT(pVM, CPUMCTX2CORE(pCtx), &Cpu); 1303 if (rc == VINF_SUCCESS) 1383 1304 { 1384 if (rc == VINF_EM_RAW_GUEST_TRAP) 1385 rc = emR3RawGuestTrap(pVM); 1386 1305 pCtx->eip += Cpu.opsize; 1306 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1307 return VINF_SUCCESS; 1308 } 1309 else 1310 if (rc == VINF_EM_RAW_GUEST_TRAP) 1311 { 1312 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1313 rc = emR3RawGuestTrap(pVM); 1387 1314 return rc; 1388 1315 } 1389 1390 AssertMsg(Cpu.param2.size == ParmVal2.size, ("size %d vs %d\n", Cpu.param2.size, ParmVal2.size)); 1391 switch (ParmVal2.size) 1392 { 1393 case 1: 1394 Log(("EMU: out8 %x, %x\n", ParmVal.val.val16, ParmVal2.val.val8)); 1395 rc = IOMIOPortWrite(pVM, ParmVal.val.val16, ParmVal2.val.val8, sizeof(ParmVal2.val.val8)); 1396 if (VBOX_SUCCESS(rc)) 1397 { 1398 pCtx->eip += Cpu.opsize; 1399 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1400 return rc; 1401 } 1402 AssertRC(rc); 1403 break; 1404 1405 case 2: 1406 Log(("EMU: out16 %x, %x\n", ParmVal.val.val16, ParmVal2.val.val16)); 1407 rc = IOMIOPortWrite(pVM, ParmVal.val.val16, ParmVal2.val.val16, sizeof(ParmVal2.val.val16)); 1408 if (VBOX_SUCCESS(rc)) 1409 { 1410 pCtx->eip += Cpu.opsize; 1411 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1412 return rc; 1413 } 1414 AssertRC(rc); 1415 break; 1416 1417 case 4: 1418 Log(("EMU: out32 %x, %x\n", ParmVal.val.val16, ParmVal2.val.val32)); 1419 rc = IOMIOPortWrite(pVM, ParmVal.val.val16, ParmVal2.val.val32, sizeof(ParmVal2.val.val32)); 1420 if (VBOX_SUCCESS(rc)) 1421 { 1422 pCtx->eip += Cpu.opsize; 1423 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1424 return rc; 1425 } 1426 AssertRC(rc); 1427 break; 1428 1429 default: 1430 AssertMsgFailed(("Unexpected port size %d\n", ParmVal2.size)); 1431 break; 1432 } 1316 /* emulate in the recompiler */ 1433 1317 break; 1434 1318 } … … 1445 1329 case OP_INSWD: 1446 1330 { 1447 /* 1448 * Do not optimize the destination address decrement case (not worth the effort) 1449 * and likewise for 16 bit address size (would need to use and update only cx/di). 1450 */ 1451 if (pCtx->eflags.Bits.u1DF || Cpu.addrmode != CPUMODE_32BIT) 1452 break; 1453 /* 1454 * Get port number and transfer count directly from the registers (no need to bother the 1455 * disassembler). And get the I/O register size from the opcode / prefix. 1456 */ 1457 uint32_t uPort = pCtx->edx & 0xffff; 1458 RTGCUINTREG cTransfers = pCtx->ecx; 1459 unsigned cbUnit; 1460 if (Cpu.pCurInstr->opcode == OP_INSB) 1461 cbUnit = 1; 1462 else 1463 cbUnit = Cpu.opmode == CPUMODE_32BIT ? 4 : 2; 1464 1465 RTGCPTR GCPtrDst = pCtx->edi; 1466 uint32_t cpl = (pCtx->eflags.Bits.u1VM) ? 3 : (pCtx->ss & X86_SEL_RPL); 1467 1468 /* Access verification first; we can't recover from traps inside this instruction, as the port read cannot be repeated. */ 1469 rc = PGMVerifyAccess(pVM, GCPtrDst, cTransfers * cbUnit, 1470 X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0)); 1471 if (rc != VINF_SUCCESS) 1331 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->StatIn); 1332 rc = IOMInterpretINS(pVM, CPUMCTX2CORE(pCtx), &Cpu); 1333 if (rc == VINF_SUCCESS) 1472 1334 { 1473 Log(("EMU: rep ins%d will generate a trap -> fallback, rc=%d\n", cbUnit * 8, rc)); 1474 break; 1475 } 1476 1477 Log(("EMU: rep ins%d port %#x count %d\n", cbUnit * 8, uPort, cTransfers)); 1478 1479 /* Make sure port access is allowed */ 1480 rc = IOMInterpretCheckPortIOAccess(pVM, CPUMCTX2CORE(pCtx), uPort, cbUnit); 1481 if (rc != VINF_SUCCESS) 1482 { 1483 if (rc == VINF_EM_RAW_GUEST_TRAP) 1484 rc = emR3RawGuestTrap(pVM); 1485 1335 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1336 pCtx->eip += Cpu.opsize; 1486 1337 return rc; 1487 1338 } 1488 1489 /* 1490 * If the device supports string transfers, ask it to do as 1491 * much as it wants. The rest is done with single-word transfers. 1492 */ 1493 rc = IOMIOPortReadString(pVM, uPort, &GCPtrDst, &cTransfers, cbUnit); 1494 AssertRC(rc); Assert(cTransfers <= pCtx->ecx); 1495 1496 while (cTransfers && rc == VINF_SUCCESS) 1339 else 1340 if (rc == VINF_EM_RAW_GUEST_TRAP) 1497 1341 { 1498 uint32_t u32Value; 1499 rc = IOMIOPortRead(pVM, uPort, &u32Value, cbUnit); 1500 AssertRC(rc); 1501 int rc2 = PGMPhysWriteGCPtrDirty(pVM, GCPtrDst, &u32Value, cbUnit); 1502 AssertRC(rc2); 1503 GCPtrDst += cbUnit; 1504 cTransfers--; 1342 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1343 rc = emR3RawGuestTrap(pVM); 1344 return rc; 1505 1345 } 1506 pCtx->edi += (pCtx->ecx - cTransfers) * cbUnit; 1507 pCtx->ecx = cTransfers; 1508 if (!cTransfers && VBOX_SUCCESS(rc)) 1509 pCtx->eip += Cpu.opsize; 1510 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1511 return rc; 1346 /* emulate in the recompiler */ 1347 break; 1512 1348 } 1513 1349 case OP_OUTSB: 1514 1350 case OP_OUTSWD: 1515 1351 { 1516 /* 1517 * Do not optimize the source address decrement case (not worth the effort) 1518 * and likewise for 16 bit address size (would need to use and update only cx/si). 1519 */ 1520 if (pCtx->eflags.Bits.u1DF || Cpu.addrmode != CPUMODE_32BIT) 1521 break; 1522 /* 1523 * Get port number and transfer count directly from the registers (no need to bother the 1524 * disassembler). And get the I/O register size from the opcode / prefix. 1525 */ 1526 uint32_t uPort = pCtx->edx & 0xffff; 1527 RTGCUINTREG cTransfers = pCtx->ecx; 1528 unsigned cbUnit; 1529 if (Cpu.pCurInstr->opcode == OP_OUTSB) 1530 cbUnit = 1; 1531 else 1532 cbUnit = Cpu.opmode == CPUMODE_32BIT ? 4 : 2; 1533 1534 RTGCPTR GCPtrSrc = pCtx->esi; 1535 uint32_t cpl = (pCtx->eflags.Bits.u1VM) ? 3 : (pCtx->ss & X86_SEL_RPL); 1536 1537 /* Access verification first; we currently can't recover properly from traps inside this instruction */ 1538 rc = PGMVerifyAccess(pVM, GCPtrSrc, cTransfers * cbUnit, ((cpl == 3) ? X86_PTE_US : 0)); 1539 if (rc != VINF_SUCCESS) 1352 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->StatOut); 1353 rc = IOMInterpretOUTS(pVM, CPUMCTX2CORE(pCtx), &Cpu); 1354 if (rc == VINF_SUCCESS) 1540 1355 { 1541 Log(("EMU: rep outs%d will generate a trap -> fallback, rc=%d\n", cbUnit * 8, rc)); 1542 break; 1543 } 1544 1545 Log(("EMU: rep outs%d port %#x count %d\n", cbUnit * 8, uPort, cTransfers)); 1546 1547 /* Make sure port access is allowed */ 1548 rc = IOMInterpretCheckPortIOAccess(pVM, CPUMCTX2CORE(pCtx), uPort, cbUnit); 1549 if (rc != VINF_SUCCESS) 1550 { 1551 if (rc == VINF_EM_RAW_GUEST_TRAP) 1552 rc = emR3RawGuestTrap(pVM); 1553 1356 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1357 pCtx->eip += Cpu.opsize; 1554 1358 return rc; 1555 1359 } 1556 1557 /* 1558 * If the device supports string transfers, ask it to do as 1559 * much as it wants. The rest is done with single-word transfers. 1560 */ 1561 rc = IOMIOPortWriteString(pVM, uPort, &GCPtrSrc, &cTransfers, cbUnit); 1562 AssertRC(rc); Assert(cTransfers <= pCtx->ecx); 1563 1564 while (cTransfers && rc == VINF_SUCCESS) 1360 else 1361 if (rc == VINF_EM_RAW_GUEST_TRAP) 1565 1362 { 1566 uint32_t u32Value; 1567 rc = PGMPhysReadGCPtr(pVM, &u32Value, GCPtrSrc, cbUnit); 1568 Assert(rc == VINF_SUCCESS); 1569 rc = IOMIOPortWrite(pVM, uPort, u32Value, cbUnit); 1570 AssertRC(rc); 1571 GCPtrSrc += cbUnit; 1572 cTransfers--; 1363 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1364 rc = emR3RawGuestTrap(pVM); 1365 return rc; 1573 1366 } 1574 pCtx->esi += (pCtx->ecx - cTransfers) * cbUnit; 1575 pCtx->ecx = cTransfers; 1576 if (!cTransfers && VBOX_SUCCESS(rc)) 1577 pCtx->eip += Cpu.opsize; 1578 STAM_PROFILE_STOP(&pVM->em.s.StatIOEmu, a); 1579 return rc; 1367 /* emulate in the recompiler */ 1368 break; 1580 1369 } 1581 1370 } … … 2899 2688 #endif 2900 2689 2901 // DBGFR3InfoLog(pVM, "cpumguest", "PRE");2902 // DBGFR3DisasInstrCurrentLog(pVM, "PRE");2903 2904 2690 /* 2905 2691 * Execute the code. … … 2911 2697 VMMR3Lock(pVM); 2912 2698 STAM_PROFILE_STOP(&pVM->em.s.StatHwAccExec, x); 2913 2914 // DBGFR3InfoLog(pVM, "cpumguest", "POST");2915 // DBGFR3DisasInstrCurrentLog(pVM, "POST");2916 2699 2917 2700 /*
Note:
See TracChangeset
for help on using the changeset viewer.