VirtualBox

Changeset 56413 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Jun 14, 2015 3:43:56 AM (10 years ago)
Author:
vboxsync
Message:

IOM,DevATA,Dev*SCSI: Redid the string I/O callbacks so the devices doesn't need to talk to PGM. (scsi bits are untested)

Location:
trunk/src/VBox/Devices/Storage
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DevATA.cpp

    r56408 r56413  
    528528PDMBOTHCBDECL(int) ataIOPortWrite1Data(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    529529PDMBOTHCBDECL(int) ataIOPortRead1Data(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *u32, unsigned cb);
    530 PDMBOTHCBDECL(int) ataIOPortWriteStr1Data(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb);
    531 PDMBOTHCBDECL(int) ataIOPortReadStr1Data(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb);
     530PDMBOTHCBDECL(int) ataIOPortWriteStr1Data(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t const *pbSrc,
     531                                          uint32_t *pcTransfers, unsigned cb);
     532PDMBOTHCBDECL(int) ataIOPortReadStr1Data(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t *pbDst,
     533                                         uint32_t *pcTransfers, unsigned cb);
    532534PDMBOTHCBDECL(int) ataIOPortWrite1Other(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    533535PDMBOTHCBDECL(int) ataIOPortRead1Other(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *u32, unsigned cb);
     
    50205022}
    50215023
    5022 #ifndef IN_RING0 /** @todo do this in ring-0 as well - after IEM specific interface rewrite! */
    50235024
    50245025/**
     
    50265027 * @see FNIOMIOPORTINSTRING for details.
    50275028 */
    5028 PDMBOTHCBDECL(int) ataIOPortReadStr1Data(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst,
    5029                                          PRTGCUINTREG pcTransfer, unsigned cb)
    5030 {
    5031     uint32_t       i = (uint32_t)(uintptr_t)pvUser;
     5029PDMBOTHCBDECL(int) ataIOPortReadStr1Data(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t *pbDst,
     5030                                         uint32_t *pcTransfers, unsigned cb)
     5031{
     5032    uint32_t       i     = (uint32_t)(uintptr_t)pvUser;
    50325033    PCIATAState   *pThis = PDMINS_2_DATA(pDevIns, PCIATAState *);
    5033     PATACONTROLLER pCtl = &pThis->aCts[i];
    5034     int            rc = VINF_SUCCESS;
     5034    PATACONTROLLER pCtl  = &pThis->aCts[i];
    50355035
    50365036    Assert(i < 2);
    50375037    Assert(Port == pCtl->IOPortBase1);
    5038 
    5039     rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_R3_IOPORT_READ);
    5040     if (rc == VINF_SUCCESS)
    5041     {
    5042         ATADevState *s = &pCtl->aIfs[pCtl->iSelectedIf];
    5043         uint32_t    cTransAvailable;
    5044         uint32_t    cTransfer = *pcTransfer;
    5045         uint32_t    cbTransfer;
    5046         RTGCPTR     GCDst = *pGCPtrDst;
    5047         Assert(cb == 2 || cb == 4);
    5048 
    5049         cTransAvailable = (s->iIOBufferPIODataEnd - s->iIOBufferPIODataStart) / cb;
    5050 # ifndef IN_RING3
    5051         /* Deal with the unlikely case where no data (or not enough for the read length operation) is available; go back to ring 3. */
    5052         if (!cTransAvailable)
    5053         {
     5038    Assert(*pcTransfers > 0);
     5039
     5040    int rc;
     5041    if (cb == 2 || cb == 4)
     5042    {
     5043        rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_R3_IOPORT_READ);
     5044        if (rc == VINF_SUCCESS)
     5045        {
     5046            ATADevState *s = &pCtl->aIfs[pCtl->iSelectedIf];
     5047
     5048            uint32_t const offStart = s->iIOBufferPIODataStart;
     5049            if (offStart < s->iIOBufferPIODataEnd)
     5050            {
     5051                /*
     5052                 * Figure how much we can copy.  Usually it's the same as the request.
     5053                 * The last transfer unit cannot be handled in RC, as it involves
     5054                 * thread communication.  In R0 we let the non-string callback handle it,
     5055                 * and ditto for overflows/dummy data.
     5056                 */
     5057                uint32_t cAvailable = (s->iIOBufferPIODataEnd - offStart) / cb;
     5058#ifndef IN_RING3
     5059                if (cAvailable > 0)
     5060                    cAvailable--;
     5061#endif
     5062                uint32_t const cRequested = *pcTransfers;
     5063                if (cAvailable > cRequested)
     5064                    cAvailable = cRequested;
     5065                uint32_t const cbTransfer = cAvailable * cb;
     5066                if (   offStart + cbTransfer <= s->cbIOBuffer
     5067                    && cbTransfer > 0)
     5068                {
     5069                    /*
     5070                     * Do the transfer.
     5071                     */
     5072                    uint8_t const *pbSrc = s->CTX_SUFF(pbIOBuffer) + offStart;
     5073                    memcpy(pbDst, pbSrc, cbTransfer);
     5074                    Log3(("%s: addr=%#x cb=%#x cbTransfer=%#x val=%.*Rhxd\n",
     5075                          __FUNCTION__, Port, cb, cbTransfer, cbTransfer, pbSrc));
     5076                    s->iIOBufferPIODataStart = offStart + cbTransfer;
     5077
     5078#ifdef IN_RING3
     5079                    if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
     5080                        ataHCPIOTransferFinish(pCtl, s);
     5081#endif
     5082                    *pcTransfers = cRequested - cAvailable;
     5083                }
     5084                else
     5085                    Log2(("%s: DUMMY/Overflow!\n", __FUNCTION__));
     5086            }
     5087            else
     5088            {
     5089                /*
     5090                 * Dummy read (shouldn't happen) return 0xff like the non-string handler.
     5091                 */
     5092                Log2(("%s: DUMMY data (%#x bytes)\n", __FUNCTION__, *pcTransfers * cb));
     5093                memset(pbDst, 0xff, *pcTransfers * cb);
     5094                *pcTransfers = 0;
     5095            }
     5096
    50545097            PDMCritSectLeave(&pCtl->lock);
    5055             return VINF_IOM_R3_IOPORT_READ;
    5056         }
    5057         /* The last transfer unit cannot be handled in GC, as it involves thread communication. */
    5058         cTransAvailable--;
    5059 # endif /* !IN_RING3 */
    5060         /* Do not handle the dummy transfer stuff here, leave it to the single-word transfers.
    5061          * They are not performance-critical and generally shouldn't occur at all. */
    5062         if (cTransAvailable > cTransfer)
    5063             cTransAvailable = cTransfer;
    5064         cbTransfer = cTransAvailable * cb;
    5065 
    5066         rc = PGMPhysSimpleDirtyWriteGCPtr(PDMDevHlpGetVMCPU(pDevIns), GCDst, s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart, cbTransfer);
    5067 # ifndef IN_RING3
    5068         /* Paranoia. */
    5069         if (RT_FAILURE(rc))
    5070         {
    5071             PDMCritSectLeave(&pCtl->lock);
    5072             AssertFailed();
    5073             return VINF_IOM_R3_IOPORT_READ;
    5074         }
    5075 # else
    5076         Assert(rc == VINF_SUCCESS);
    5077 # endif
    5078 
    5079         if (cbTransfer)
    5080             Log3(("%s: addr=%#x val=%.*Rhxs\n", __FUNCTION__, Port, cbTransfer, s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart));
    5081         s->iIOBufferPIODataStart += cbTransfer;
    5082         *pGCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCDst + cbTransfer);
    5083         *pcTransfer = cTransfer - cTransAvailable;
    5084 # ifdef IN_RING3
    5085         if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
    5086             ataHCPIOTransferFinish(pCtl, s);
    5087 # endif /* IN_RING3 */
    5088         PDMCritSectLeave(&pCtl->lock);
     5098        }
     5099    }
     5100    /*
     5101     * Let the non-string I/O callback handle 1 byte reads.
     5102     */
     5103    else
     5104    {
     5105        Log2(("%s: 1 byte read (%#x transfers)\n", *pcTransfers));
     5106        AssertFailed();
     5107        rc = VINF_SUCCESS;
    50895108    }
    50905109    return rc;
     
    50965115 * @see FNIOMIOPORTOUTSTRING for details.
    50975116 */
    5098 PDMBOTHCBDECL(int) ataIOPortWriteStr1Data(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc,
    5099                                           PRTGCUINTREG pcTransfer, unsigned cb)
    5100 {
    5101     uint32_t       i = (uint32_t)(uintptr_t)pvUser;
     5117PDMBOTHCBDECL(int) ataIOPortWriteStr1Data(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t const *pbSrc,
     5118                                          uint32_t *pcTransfers, unsigned cb)
     5119{
     5120    uint32_t       i     = (uint32_t)(uintptr_t)pvUser;
    51025121    PCIATAState   *pThis = PDMINS_2_DATA(pDevIns, PCIATAState *);
    5103     PATACONTROLLER pCtl = &pThis->aCts[i];
    5104     int            rc;
     5122    PATACONTROLLER pCtl  = &pThis->aCts[i];
    51055123
    51065124    Assert(i < 2);
    51075125    Assert(Port == pCtl->IOPortBase1);
    5108 
    5109     rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_R3_IOPORT_WRITE);
    5110     if (rc == VINF_SUCCESS)
    5111     {
    5112         ATADevState *s = &pCtl->aIfs[pCtl->iSelectedIf];
    5113         uint32_t cTransfer = *pcTransfer;
    5114         uint32_t cbTransfer;
    5115         RTGCPTR GCSrc = *pGCPtrSrc;
    5116         Assert(cb == 2 || cb == 4);
    5117 
    5118         uint32_t cTransAvailable = (s->iIOBufferPIODataEnd - s->iIOBufferPIODataStart) / cb;
    5119 # ifndef IN_RING3
    5120         /* Deal with the unlikely case where no data (or not enough for the read length operation) is available; go back to ring 3. */
    5121         if (!cTransAvailable)
    5122         {
     5126    Assert(*pcTransfers > 0);
     5127
     5128    int rc;
     5129    if (cb == 2 || cb == 4)
     5130    {
     5131        rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_R3_IOPORT_WRITE);
     5132        if (rc == VINF_SUCCESS)
     5133        {
     5134            ATADevState *s = &pCtl->aIfs[pCtl->iSelectedIf];
     5135
     5136            uint32_t const offStart = s->iIOBufferPIODataStart;
     5137            if (offStart < s->iIOBufferPIODataEnd)
     5138            {
     5139                /*
     5140                 * Figure how much we can copy.  Usually it's the same as the request.
     5141                 * The last transfer unit cannot be handled in RC, as it involves
     5142                 * thread communication.  In R0 we let the non-string callback handle it,
     5143                 * and ditto for overflows/dummy data.
     5144                 */
     5145                uint32_t cAvailable = (s->iIOBufferPIODataEnd - offStart) / cb;
     5146#ifndef IN_RING3
     5147                if (cAvailable)
     5148                    cAvailable--;
     5149#endif
     5150                uint32_t const cRequested = *pcTransfers;
     5151                if (cAvailable > cRequested)
     5152                    cAvailable = cRequested;
     5153                uint32_t const cbTransfer = cAvailable * cb;
     5154                if (   offStart + cbTransfer <= s->cbIOBuffer
     5155                    && cbTransfer)
     5156                {
     5157                    /*
     5158                     * Do the transfer.
     5159                     */
     5160                    void *pvDst = s->CTX_SUFF(pbIOBuffer) + offStart;
     5161                    memcpy(pvDst, pbSrc, cbTransfer);
     5162                    Log3(("%s: addr=%#x val=%.*Rhxs\n", __FUNCTION__, Port, cbTransfer, pvDst));
     5163                    s->iIOBufferPIODataStart = offStart + cbTransfer;
     5164
     5165#ifdef IN_RING3
     5166                    if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
     5167                        ataHCPIOTransferFinish(pCtl, s);
     5168#endif
     5169                    *pcTransfers = cRequested - cAvailable;
     5170                }
     5171                else
     5172                    Log2(("%s: DUMMY/Overflow!\n", __FUNCTION__));
     5173            }
     5174            else
     5175            {
     5176                Log2(("%s: DUMMY data (%#x bytes)\n", __FUNCTION__, *pcTransfers * cb));
     5177                *pcTransfers = 0;
     5178            }
     5179
    51235180            PDMCritSectLeave(&pCtl->lock);
    5124             return VINF_IOM_R3_IOPORT_WRITE;
    5125         }
    5126         /* The last transfer unit cannot be handled in GC, as it involves thread communication. */
    5127         cTransAvailable--;
    5128 # endif /* !IN_RING3 */
    5129         /* Do not handle the dummy transfer stuff here, leave it to the single-word transfers.
    5130          * They are not performance-critical and generally shouldn't occur at all. */
    5131         if (cTransAvailable > cTransfer)
    5132             cTransAvailable = cTransfer;
    5133         cbTransfer = cTransAvailable * cb;
    5134 
    5135         rc = PGMPhysSimpleReadGCPtr(PDMDevHlpGetVMCPU(pDevIns), s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart, GCSrc, cbTransfer);
    5136 # ifndef IN_RING3
    5137         /* Paranoia. */
    5138         if (RT_FAILURE(rc))
    5139         {
    5140             PDMCritSectLeave(&pCtl->lock);
    5141             AssertFailed();
    5142             return VINF_IOM_R3_IOPORT_WRITE;
    5143         }
    5144 # else
    5145         Assert(rc == VINF_SUCCESS);
    5146 # endif
    5147 
    5148         if (cbTransfer)
    5149             Log3(("%s: addr=%#x val=%.*Rhxs\n", __FUNCTION__, Port, cbTransfer, s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart));
    5150         s->iIOBufferPIODataStart += cbTransfer;
    5151         *pGCPtrSrc = (RTGCPTR)((RTGCUINTPTR)GCSrc + cbTransfer);
    5152         *pcTransfer = cTransfer - cTransAvailable;
    5153 # ifdef IN_RING3
    5154         if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
    5155             ataHCPIOTransferFinish(pCtl, s);
    5156 # endif /* IN_RING3 */
    5157         PDMCritSectLeave(&pCtl->lock);
    5158     }
     5181        }
     5182    }
     5183    /*
     5184     * Let the non-string I/O callback handle 1 byte reads.
     5185     */
     5186    else
     5187    {
     5188        Log2(("%s: 1 byte write (%#x transfers)\n", *pcTransfers));
     5189        AssertFailed();
     5190        rc = VINF_SUCCESS;
     5191    }
     5192
    51595193    return rc;
    51605194}
    5161 
    5162 #endif /* !IN_RING0 */
    51635195
    51645196
     
    74917523        if (fR0Enabled)
    74927524        {
    7493 #if 1
     7525#if 0
    74947526            rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->aCts[i].IOPortBase1, 1, (RTR0PTR)i,
    74957527                                           "ataIOPortWrite1Data", "ataIOPortRead1Data", NULL, NULL, "ATA I/O Base 1 - Data");
  • trunk/src/VBox/Devices/Storage/DevBusLogic.cpp

    r56292 r56413  
    25752575 * @see FNIOMIOPORTOUTSTRING for details.
    25762576 */
    2577 static DECLCALLBACK(int) buslogicR3BiosIoPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc,
    2578                                                       PRTGCUINTREG pcTransfer, unsigned cb)
     2577static DECLCALLBACK(int) buslogicR3BiosIoPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
     2578                                                      uint8_t const *pbSrc, uint32_t *pcTransfers, unsigned cb)
    25792579{
    25802580    PBUSLOGIC pBusLogic = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
    2581     int rc;
    2582 
    2583     Log2(("#%d %s: pvUser=%#p cb=%d Port=%#x\n",
    2584           pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port));
    2585 
    2586     rc = vboxscsiWriteString(pDevIns, &pBusLogic->VBoxSCSI, (Port - BUSLOGIC_BIOS_IO_PORT),
    2587                              pGCPtrSrc, pcTransfer, cb);
     2581    Log2(("#%d %s: pvUser=%#p cb=%d Port=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port));
     2582
     2583    int rc = vboxscsiWriteString(pDevIns, &pBusLogic->VBoxSCSI, (Port - BUSLOGIC_BIOS_IO_PORT), pbSrc, pcTransfers, cb);
    25882584    if (rc == VERR_MORE_DATA)
    25892585    {
     
    26012597 * @see FNIOMIOPORTINSTRING for details.
    26022598 */
    2603 static DECLCALLBACK(int) buslogicR3BiosIoPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst,
    2604                                                      PRTGCUINTREG pcTransfer, unsigned cb)
     2599static DECLCALLBACK(int) buslogicR3BiosIoPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
     2600                                                     uint8_t *pbDst, uint32_t *pcTransfers, unsigned cb)
    26052601{
    26062602    PBUSLOGIC pBusLogic = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
    2607 
    2608     LogFlowFunc(("#%d %s: pvUser=%#p cb=%d Port=%#x\n",
    2609                  pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port));
     2603    LogFlowFunc(("#%d %s: pvUser=%#p cb=%d Port=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port));
    26102604
    26112605    return vboxscsiReadString(pDevIns, &pBusLogic->VBoxSCSI, (Port - BUSLOGIC_BIOS_IO_PORT),
    2612                               pGCPtrDst, pcTransfer, cb);
     2606                              pbDst, pcTransfers, cb);
    26132607}
    26142608
  • trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp

    r56292 r56413  
    38523852 */
    38533853static DECLCALLBACK(int) lsilogicR3IsaIOPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
    3854                                                      PRTGCPTR pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
     3854                                                     uint8_t const *pbSrc, uint32_t *pcTransfers, unsigned cb)
    38553855{
    38563856    PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
     
    38603860                      ? Port - LSILOGIC_BIOS_IO_PORT
    38613861                      : Port - LSILOGIC_SAS_BIOS_IO_PORT;
    3862     int rc = vboxscsiWriteString(pDevIns, &pThis->VBoxSCSI, iRegister, pGCPtrSrc, pcTransfer, cb);
     3862    int rc = vboxscsiWriteString(pDevIns, &pThis->VBoxSCSI, iRegister, pbSrc, pcTransfers, cb);
    38633863    if (rc == VERR_MORE_DATA)
    38643864    {
     
    38763876 * Port I/O Handler for primary port range IN string operations.}
    38773877 */
    3878 static DECLCALLBACK(int) lsilogicR3IsaIOPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst,
    3879                                                   PRTGCUINTREG pcTransfer, unsigned cb)
     3878static DECLCALLBACK(int) lsilogicR3IsaIOPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
     3879                                                    uint8_t *pbDst, uint32_t *pcTransfers, unsigned cb)
    38803880{
    38813881    PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
    3882 
    3883     LogFlowFunc(("#%d %s: pvUser=%#p cb=%d Port=%#x\n",
    3884                  pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port));
     3882    LogFlowFunc(("#%d %s: pvUser=%#p cb=%d Port=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port));
    38853883
    38863884    uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
    38873885                      ? Port - LSILOGIC_BIOS_IO_PORT
    38883886                      : Port - LSILOGIC_SAS_BIOS_IO_PORT;
    3889     return vboxscsiReadString(pDevIns, &pThis->VBoxSCSI, iRegister, pGCPtrDst, pcTransfer, cb);
     3887    return vboxscsiReadString(pDevIns, &pThis->VBoxSCSI, iRegister, pbDst, pcTransfers, cb);
    38903888}
    38913889
  • trunk/src/VBox/Devices/Storage/VBoxSCSI.cpp

    r56292 r56413  
    3939 * Resets the state.
    4040 */
    41 static void vboxscsiReset(PVBOXSCSI pVBoxSCSI)
    42 {
    43     pVBoxSCSI->regIdentify   = 0;
     41static void vboxscsiReset(PVBOXSCSI pVBoxSCSI, bool fEverything)
     42{
     43    if (fEverything)
     44    {
     45        pVBoxSCSI->regIdentify = 0;
     46        pVBoxSCSI->fBusy       = false;
     47    }
    4448    pVBoxSCSI->cbCDB         = 0;
    45     memset(pVBoxSCSI->abCDB, 0, sizeof(pVBoxSCSI->abCDB));
     49    RT_ZERO(pVBoxSCSI->abCDB);
    4650    pVBoxSCSI->iCDB          = 0;
    47     pVBoxSCSI->fBusy         = false;
    4851    pVBoxSCSI->rcCompletion  = 0;
    4952    pVBoxSCSI->uTargetDevice = 0;
     
    5255    if (pVBoxSCSI->pbBuf)
    5356        RTMemFree(pVBoxSCSI->pbBuf);
    54 
    5557    pVBoxSCSI->pbBuf         = NULL;
    5658    pVBoxSCSI->enmState      = VBOXSCSISTATE_NO_COMMAND;
     
    6668{
    6769    pVBoxSCSI->pbBuf = NULL;
    68     vboxscsiReset(pVBoxSCSI);
     70    vboxscsiReset(pVBoxSCSI, true /*fEverything*/);
    6971
    7072    return VINF_SUCCESS;
     
    102104        {
    103105            /* If we're not in the 'command ready' state, there may not even be a buffer yet. */
    104             if ((pVBoxSCSI->enmState == VBOXSCSISTATE_COMMAND_READY) && pVBoxSCSI->cbBuf > 0)
     106            if (   pVBoxSCSI->enmState == VBOXSCSISTATE_COMMAND_READY
     107                && pVBoxSCSI->cbBuf > 0)
    105108            {
    106109                AssertMsg(pVBoxSCSI->pbBuf, ("pBuf is NULL\n"));
    107                 Assert(pVBoxSCSI->enmState == VBOXSCSISTATE_COMMAND_READY);
    108110                Assert(!pVBoxSCSI->fBusy);
    109111                uVal = pVBoxSCSI->pbBuf[pVBoxSCSI->iBuf];
    110112                pVBoxSCSI->iBuf++;
    111113                pVBoxSCSI->cbBuf--;
     114
     115                /* When the guest reads the last byte from the data in buffer, clear
     116                   everything and reset command buffer. */
    112117                if (pVBoxSCSI->cbBuf == 0)
    113                 {
    114                     /** The guest read the last byte from the data in buffer.
    115                      *  Clear everything and reset command buffer.
    116                      */
    117                     RTMemFree(pVBoxSCSI->pbBuf);
    118                     pVBoxSCSI->pbBuf = NULL;
    119                     pVBoxSCSI->cbCDB = 0;
    120                     pVBoxSCSI->iCDB  = 0;
    121                     pVBoxSCSI->iBuf  = 0;
    122                     pVBoxSCSI->rcCompletion = 0;
    123                     pVBoxSCSI->uTargetDevice = 0;
    124                     pVBoxSCSI->enmState = VBOXSCSISTATE_NO_COMMAND;
    125                     memset(pVBoxSCSI->abCDB, 0, sizeof(pVBoxSCSI->abCDB));
    126                 }
     118                    vboxscsiReset(pVBoxSCSI, false /*fEverything*/);
    127119            }
    128120            break;
     
    151143 *
    152144 * @returns VBox status code.
    153  *          VERR_MORE_DATA if a command is ready to be sent to the SCSI driver.
     145 * @retval  VERR_MORE_DATA if a command is ready to be sent to the SCSI driver.
    154146 * @param   pVBoxSCSI    Pointer to the SCSI state.
    155147 * @param   iRegister    Index of the register to write to.
     
    172164            {
    173165                if (uVal != VBOXSCSI_TXDIR_FROM_DEVICE && uVal != VBOXSCSI_TXDIR_TO_DEVICE)
    174                     vboxscsiReset(pVBoxSCSI);
     166                    vboxscsiReset(pVBoxSCSI, true /*fEverything*/);
    175167                else
    176168                {
     
    181173            else if (pVBoxSCSI->enmState == VBOXSCSISTATE_READ_CDB_SIZE_BUFHI)
    182174            {
    183                 uint8_t     cbCDB = uVal & 0x0F;
    184 
     175                uint8_t cbCDB = uVal & 0x0F;
    185176                if (cbCDB > VBOXSCSI_CDB_SIZE_MAX)
    186                     vboxscsiReset(pVBoxSCSI);
     177                    vboxscsiReset(pVBoxSCSI, true /*fEverything*/);
    187178                else
    188179                {
     
    231222            break;
    232223        }
     224
    233225        case 1:
    234226        {
     
    237229            {
    238230                /* Reset the state */
    239                 vboxscsiReset(pVBoxSCSI);
    240             }
    241             else
     231                vboxscsiReset(pVBoxSCSI, true /*fEverything*/);
     232            }
     233            else if (pVBoxSCSI->cbBuf > 0)
    242234            {
    243235                pVBoxSCSI->pbBuf[pVBoxSCSI->iBuf++] = uVal;
    244                 if (pVBoxSCSI->iBuf == pVBoxSCSI->cbBuf)
     236                pVBoxSCSI->cbBuf--;
     237                if (pVBoxSCSI->cbBuf == 0)
    245238                {
    246239                    rc = VERR_MORE_DATA;
     
    248241                }
    249242            }
    250             break;
    251         }
     243            /* else: Ignore extra data, request pending or something. */
     244            break;
     245        }
     246
    252247        case 2:
    253248        {
     
    255250            break;
    256251        }
     252
    257253        case 3:
    258254        {
    259255            /* Reset */
    260             vboxscsiReset(pVBoxSCSI);
    261             break;
    262         }
     256            vboxscsiReset(pVBoxSCSI, true /*fEverything*/);
     257            break;
     258        }
     259
    263260        default:
    264261            AssertMsgFailed(("Invalid register to write to %u\n", iRegister));
     
    335332
    336333    if (pVBoxSCSI->uTxDir == VBOXSCSI_TXDIR_TO_DEVICE)
    337     {
    338         if (pVBoxSCSI->pbBuf)
    339             RTMemFree(pVBoxSCSI->pbBuf);
    340         pVBoxSCSI->pbBuf  = NULL;
    341         pVBoxSCSI->cbBuf = 0;
    342         pVBoxSCSI->cbCDB = 0;
    343         pVBoxSCSI->iCDB  = 0;
    344         pVBoxSCSI->iBuf  = 0;
    345         pVBoxSCSI->uTargetDevice = 0;
    346         pVBoxSCSI->enmState = VBOXSCSISTATE_NO_COMMAND;
    347         memset(pVBoxSCSI->abCDB, 0, sizeof(pVBoxSCSI->abCDB));
    348     }
     334        vboxscsiReset(pVBoxSCSI, false /*fEverything*/);
    349335
    350336    pVBoxSCSI->rcCompletion = rcCompletion;
     
    356342
    357343int vboxscsiReadString(PPDMDEVINS pDevIns, PVBOXSCSI pVBoxSCSI, uint8_t iRegister,
    358                        RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
    359 {
    360     RTGCPTR  GCDst      = *pGCPtrDst;
    361     uint32_t cbTransfer = *pcTransfer * cb;
    362 
    363     LogFlowFunc(("pDevIns=%#p pVBoxSCSI=%#p iRegister=%d cTransfer=%u cb=%u\n",
    364                  pDevIns, pVBoxSCSI, iRegister, *pcTransfer, cb));
     344                       uint8_t *pbDst, uint32_t *pcTransfers, unsigned cb)
     345{
     346    LogFlowFunc(("pDevIns=%#p pVBoxSCSI=%#p iRegister=%d cTransfers=%u cb=%u\n",
     347                 pDevIns, pVBoxSCSI, iRegister, *pcTransfers, cb));
     348
     349    /*
     350     * Check preconditions, fall back to non-string I/O handler.
     351     */
     352    Assert(*pcTransfers > 0);
    365353
    366354    /* Read string only valid for data in register. */
    367     AssertMsg(iRegister == 1, ("Hey only register 1 can be read from with string\n"));
     355    AssertMsgReturn(iRegister == 1, ("Hey! Only register 1 can be read from with string!\n"), VINF_SUCCESS);
    368356
    369357    /* Accesses without a valid buffer will be ignored. */
    370     if (!pVBoxSCSI->pbBuf)
    371         return VINF_SUCCESS;
    372 
    373     /* Also ignore attempts to read more data than is available. */
    374     Assert(cbTransfer <= pVBoxSCSI->cbBuf);
    375     if (cbTransfer > pVBoxSCSI->cbBuf)
    376         cbTransfer = pVBoxSCSI->cbBuf;  /* Ignore excess data (not supposed to happen). */
    377 
    378     int rc = PGMPhysSimpleDirtyWriteGCPtr(PDMDevHlpGetVMCPU(pDevIns), GCDst, pVBoxSCSI->pbBuf + pVBoxSCSI->iBuf, cbTransfer);
    379     AssertRC(rc);
    380 
    381     *pGCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCDst + cbTransfer);
    382     *pcTransfer = 0;
    383 
    384     /* Advance current buffer position. */
    385     pVBoxSCSI->iBuf  += cbTransfer;
    386     pVBoxSCSI->cbBuf -= cbTransfer;
    387 
    388     if (pVBoxSCSI->cbBuf == 0)
    389     {
    390         /** The guest read the last byte from the data in buffer.
    391          *  Clear everything and reset command buffer.
    392          */
    393         RTMemFree(pVBoxSCSI->pbBuf);
    394         pVBoxSCSI->pbBuf  = NULL;
    395         pVBoxSCSI->cbCDB = 0;
    396         pVBoxSCSI->iCDB  = 0;
    397         pVBoxSCSI->iBuf  = 0;
    398         pVBoxSCSI->uTargetDevice = 0;
    399         pVBoxSCSI->enmState = VBOXSCSISTATE_NO_COMMAND;
    400         memset(pVBoxSCSI->abCDB, 0, sizeof(pVBoxSCSI->abCDB));
    401     }
     358    AssertReturn(!pVBoxSCSI->pbBuf, VINF_SUCCESS);
     359
     360    /* Check state. */
     361    AssertReturn(pVBoxSCSI->enmState == VBOXSCSISTATE_COMMAND_READY, VINF_SUCCESS);
     362    Assert(!pVBoxSCSI->fBusy);
     363
     364    /*
     365     * Also ignore attempts to read more data than is available.
     366     */
     367    int rc = VINF_SUCCESS;
     368    uint32_t cbTransfer = *pcTransfers * cb;
     369    if (pVBoxSCSI->cbBuf > 0) /* Think cbBufLeft, not cbBuf! */
     370    {
     371        Assert(cbTransfer <= pVBoxSCSI->cbBuf);
     372        if (cbTransfer > pVBoxSCSI->cbBuf)
     373        {
     374            memset(pbDst + pVBoxSCSI->cbBuf, 0xff, cbTransfer - pVBoxSCSI->cbBuf);
     375            cbTransfer = pVBoxSCSI->cbBuf;  /* Ignore excess data (not supposed to happen). */
     376        }
     377
     378        /* Copy the data and adance the buffer position. */
     379        memcpy(pbDst, pVBoxSCSI->pbBuf + pVBoxSCSI->iBuf, cbTransfer);
     380
     381        /* Advance current buffer position. */
     382        pVBoxSCSI->iBuf  += cbTransfer;
     383        pVBoxSCSI->cbBuf -= cbTransfer;
     384
     385        /* When the guest reads the last byte from the data in buffer, clear
     386           everything and reset command buffer. */
     387        if (pVBoxSCSI->cbBuf == 0)
     388            vboxscsiReset(pVBoxSCSI, false /*fEverything*/);
     389    }
     390    else
     391    {
     392        AssertFailed();
     393        memset(pbDst, 0, cbTransfer);
     394    }
     395    *pcTransfers = 0;
    402396
    403397    return rc;
     
    405399
    406400int vboxscsiWriteString(PPDMDEVINS pDevIns, PVBOXSCSI pVBoxSCSI, uint8_t iRegister,
    407                         RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
    408 {
    409     RTGCPTR  GCSrc      = *pGCPtrSrc;
    410     uint32_t cbTransfer = *pcTransfer * cb;
    411 
     401                        uint8_t const *pbSrc, uint32_t *pcTransfers, unsigned cb)
     402{
     403    /*
     404     * Check preconditions, fall back to non-string I/O handler.
     405     */
     406    Assert(*pcTransfers > 0);
    412407    /* Write string only valid for data in/out register. */
    413     AssertMsg(iRegister == 1, ("Hey only register 1 can be written to with string\n"));
     408    AssertMsgReturn(iRegister == 1, ("Hey! Only register 1 can be written to with string!\n"), VINF_SUCCESS);
    414409
    415410    /* Accesses without a valid buffer will be ignored. */
    416     if (!pVBoxSCSI->pbBuf)
    417         return VINF_SUCCESS;
    418 
    419     Assert(cbTransfer <= pVBoxSCSI->cbBuf);
    420     if (cbTransfer > pVBoxSCSI->cbBuf)
    421         cbTransfer = pVBoxSCSI->cbBuf;  /* Ignore excess data (not supposed to happen). */
    422 
    423     int rc = PDMDevHlpPhysReadGCVirt(pDevIns, pVBoxSCSI->pbBuf + pVBoxSCSI->iBuf, GCSrc, cbTransfer);
    424     AssertRC(rc);
    425 
    426     /* Advance current buffer position. */
    427     pVBoxSCSI->iBuf  += cbTransfer;
    428     pVBoxSCSI->cbBuf -= cbTransfer;
    429 
    430     *pGCPtrSrc = (RTGCPTR)((RTGCUINTPTR)GCSrc + cbTransfer);
    431     *pcTransfer = 0;
    432 
    433     ASMAtomicXchgBool(&pVBoxSCSI->fBusy, true);
    434     return VERR_MORE_DATA;
     411    AssertReturn(!pVBoxSCSI->pbBuf, VINF_SUCCESS);
     412
     413    /* State machine assumptions. */
     414    AssertReturn(pVBoxSCSI->enmState == VBOXSCSISTATE_COMMAND_READY, VINF_SUCCESS);
     415    AssertReturn(pVBoxSCSI->uTxDir == VBOXSCSI_TXDIR_TO_DEVICE, VINF_SUCCESS);
     416
     417    /*
     418     * Ignore excess data (not supposed to happen).
     419     */
     420    int rc = VINF_SUCCESS;
     421    if (pVBoxSCSI->cbBuf > 0) /* Think cbBufLeft, not cbBuf! */
     422    {
     423        uint32_t cbTransfer = *pcTransfers * cb;
     424        if (cbTransfer > pVBoxSCSI->cbBuf) /* Think cbBufLeft, not cbBuf! */
     425        {
     426            /** @todo the non-string version of the code would cause a reset here. */
     427            cbTransfer = pVBoxSCSI->cbBuf;
     428        }
     429
     430        /* Copy the data and adance the buffer position. */
     431        memcpy(pVBoxSCSI->pbBuf + pVBoxSCSI->iBuf, pbSrc, cbTransfer);
     432        pVBoxSCSI->iBuf  += cbTransfer;
     433        pVBoxSCSI->cbBuf -= cbTransfer;
     434
     435        /* If we've reached the end, tell the caller to submit the command. */
     436        if (pVBoxSCSI->cbBuf == 0)
     437        {
     438            ASMAtomicXchgBool(&pVBoxSCSI->fBusy, true);
     439            rc = VERR_MORE_DATA;
     440        }
     441    }
     442    else
     443        AssertFailed();
     444    *pcTransfers = 0;
     445
     446    return rc;
    435447}
    436448
  • trunk/src/VBox/Devices/Storage/VBoxSCSI.h

    r56292 r56413  
    111111    /** Pointer to the buffer holding the data. */
    112112    R3PTRTYPE(uint8_t *) pbBuf;
    113     /** Size of the buffer in bytes. */
     113    /** Size of the buffer in bytes.
     114     *
     115     * @todo r=bird: Misleading docs and member name.  This is actually not the
     116     *               buffer size, it's the number of bytes left to read/write in the
     117     *               buffer.  It is decremented when the guest (BIOS) accesses
     118     *               the buffer data. */
    114119    uint32_t             cbBuf;
    115120    /** Current position in the buffer (offBuf if you like). */
     
    138143void vboxscsiSetRequestRedo(PVBOXSCSI pVBoxSCSI, PPDMSCSIREQUEST pScsiRequest);
    139144int vboxscsiWriteString(PPDMDEVINS pDevIns, PVBOXSCSI pVBoxSCSI, uint8_t iRegister,
    140                         RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb);
     145                        uint8_t const *pbSrc, uint32_t *pcTransfers, unsigned cb);
    141146int vboxscsiReadString(PPDMDEVINS pDevIns, PVBOXSCSI pVBoxSCSI, uint8_t iRegister,
    142                        RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb);
     147                       uint8_t *pbDst, uint32_t *pcTransfers, unsigned cb);
    143148RT_C_DECLS_END
    144149#endif /* IN_RING3 */
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