VirtualBox

Changeset 2226 in vbox for trunk


Ignore:
Timestamp:
Apr 19, 2007 1:48:01 PM (18 years ago)
Author:
vboxsync
Message:

Cleanup of emR3RawExecuteIOInstruction: use existing IOM functions.
Moved IOMInterpretIN & IOMInterpretOUT to the VMMAll directory.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/EM.cpp

    r2177 r2226  
    12711271    if (VBOX_SUCCESS(rc))
    12721272    {
    1273 #ifdef VBOX_WITH_STATISTICS
    1274         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 #endif
    1289 
    12901273        if (!(Cpu.prefix & (PREFIX_REP | PREFIX_REPNE)))
    12911274        {
    1292             OP_PARAMVAL ParmVal;
    1293             int         rc;
    12941275            switch (Cpu.pCurInstr->opcode)
    12951276            {
    12961277                case OP_IN:
    12971278                {
    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)
    13091283                    {
    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);
    13131293                        return rc;
    13141294                    }
    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 */
    13651296                    break;
    13661297                }
     
    13681299                case OP_OUT:
    13691300                {
    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)
    13841305                    {
    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);
    13881315                        return rc;
    13891316                    }
    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 */
    14341318                    break;
    14351319                }
     
    14461330                case OP_INSWD:
    14471331                {
    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)
    14731335                    {
    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;
    14871338                        return rc;
    14881339                    }
    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)
    14981342                    {
    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;
    15061346                    }
    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;
    15131349                }
    15141350                case OP_OUTSB:
    15151351                case OP_OUTSWD:
    15161352                {
    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)
    15411356                    {
    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;
    15551359                        return rc;
    15561360                    }
    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)
    15661363                    {
    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;
    15741367                    }
    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;
    15811370                }
    15821371            }
  • trunk/src/VBox/VMM/VMMAll/IOMAll.cpp

    r2201 r2226  
    3838
    3939
     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 */
     47static 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 */
     73static 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 */
     103static 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 */
     177static 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 */
     215inline 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
    40239/**
    41240 * Registers a Port IO GC handler.
     
    10941293    return VINF_SUCCESS;
    10951294}
     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 */
     1305IOMDECL(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 */
     1352IOMDECL(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  
    4646
    4747
    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 by
    185  * 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_STATISTICS
    235     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 #else
    252     NOREF(pVM); NOREF(cb);
    253 #endif
    254 }
    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_STATISTICS
    269     STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIn);
    270 #endif
    271 
    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_STATISTICS
    316     STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOut);
    317 #endif
    318 
    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 }
    34248
    34349/**
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