VirtualBox

Ignore:
Timestamp:
Apr 19, 2007 8:54:41 AM (18 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
20546
Message:

Moved ins/outs handling to the VMMAll directory.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMGC/IOMGC.cpp

    r2116 r2201  
    420420}
    421421
    422 
    423 /**
    424  * [REP*] INSB/INSW/INSD
    425  * 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_STATISTICS
    436     STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIns);
    437 #endif
    438 
    439     /*
    440      * We do not support REPNE, 16-bit addressing or decrementing destination
    441      * pointer. Segment prefixes are deliberately ignored, as per the instruction specification.
    442      */
    443     if (   pCpu->prefix & PREFIX_REPNE
    444         || (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 the
    450      * 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     else
    457         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 as
    499          * 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/OUTSD
    529  * 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_STATISTICS
    540     STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOuts);
    541 #endif
    542 
    543     /*
    544      * We do not support segment prefixes, REPNE, 16-bit addressing or
    545      * 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     else
    563         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 as
    605          * 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 
    636422/**
    637423 * Attempts to service an IN/OUT instruction.
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette