VirtualBox

Changeset 50018 in vbox


Ignore:
Timestamp:
Jan 2, 2014 3:50:08 PM (11 years ago)
Author:
vboxsync
Message:

Storage/AHCI: Make sure all threads are idling before finishing the controller reset, don't process garbage FIS structures

Location:
trunk/src/VBox/Devices
Files:
2 edited

Legend:

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

    r49218 r50018  
    675675    /** Bitmask of ports which asserted an interrupt. */
    676676    volatile uint32_t               u32PortsInterrupted;
     677    /** Number of I/O threads currently active - used for async controller reset handling. */
     678    volatile uint32_t               cThreadsActive;
    677679    /** Device is in a reset state. */
    678680    bool                            fReset;
     
    698700    /** Flag whether we have written the first 4bytes in an 8byte MMIO write successfully. */
    699701    volatile bool                   f8ByteMMIO4BytesWrittenSuccessfully;
     702
     703#if HC_ARCH_BITS == 64
     704    uint32_t                        Alignment7;
     705#endif
    700706
    701707    /** The support driver session handle. */
     
    17351741    return VINF_IOM_R3_MMIO_WRITE;
    17361742#else
    1737     ahci->regHbaCtrl = (u32Value & AHCI_HBA_CTRL_RW_MASK) | AHCI_HBA_CTRL_AE;
    1738     if (ahci->regHbaCtrl & AHCI_HBA_CTRL_HR)
     1743    /*
     1744     * Increase the active thread counter because we might set the host controller
     1745     * reset bit.
     1746     */
     1747    ASMAtomicIncU32(&ahci->cThreadsActive);
     1748    ASMAtomicWriteU32(&ahci->regHbaCtrl, (u32Value & AHCI_HBA_CTRL_RW_MASK) | AHCI_HBA_CTRL_AE);
     1749
     1750    /*
     1751     * Do the HBA reset if requested and there is no other active thread at the moment,
     1752     * the work is deferred to the last active thread otherwise.
     1753     */
     1754    uint32_t cThreadsActive = ASMAtomicDecU32(&ahci->cThreadsActive);
     1755    if (   (u32Value & AHCI_HBA_CTRL_HR)
     1756        && !cThreadsActive)
    17391757        ahciHBAReset(ahci);
     1758
    17401759    return VINF_SUCCESS;
    17411760#endif
     
    63216340 * Retrieve a command FIS from guest memory.
    63226341 *
    6323  * @returns nothing
     6342 * @returns whether the H2D FIS was successfully read from the guest memory.
    63246343 * @param pAhciReq The state of the actual task.
    63256344 */
    6326 static void ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
     6345static bool ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
    63276346{
    63286347    RTGCPHYS  GCPhysAddrCmdTbl;
    63296348
    6330     AssertMsg(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb, ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__));
     6349    AssertMsgReturn(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb,
     6350                    ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__),
     6351                    false);
    63316352
    63326353    /*
     
    63476368    GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr);
    63486369
    6349     AssertMsg((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
    6350               ("This is not a command FIS!!\n"));
     6370    AssertMsgReturn((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
     6371                    ("This is not a command FIS!!\n"),
     6372                    false);
    63516373
    63526374    /* Read the command Fis. */
    63536375    LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
    63546376    PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
     6377
     6378    AssertMsgReturn(pAhciReq->cmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D,
     6379                    ("This is not a command FIS\n"),
     6380                    false);
    63556381
    63566382    /* Set transfer direction. */
     
    63996425    }
    64006426#endif
     6427
     6428    return true;
    64016429}
    64026430
     
    64466474        unsigned idx = 0;
    64476475        uint32_t u32Tasks = 0;
     6476        uint32_t u32RegHbaCtrl = 0;
    64486477
    64496478        ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, true);
     
    64616490
    64626491        ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, false);
     6492        ASMAtomicIncU32(&pAhci->cThreadsActive);
     6493
     6494        /*
     6495         * Check whether the global host controller bit is set and go to sleep immediately again
     6496         * if it is set.
     6497         */
     6498        u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
     6499        if (   u32RegHbaCtrl & AHCI_HBA_CTRL_HR
     6500            && !ASMAtomicDecU32(&pAhci->cThreadsActive))
     6501        {
     6502            ahciHBAReset(pAhci);
     6503            continue;
     6504        }
     6505
    64636506        idx = ASMBitFirstSetU32(u32Tasks);
    64646507        while (idx)
     
    64986541            ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag);
    64996542
    6500             ahciPortTaskGetCommandFis(pAhciPort, pAhciReq);
     6543            bool fFisRead = ahciPortTaskGetCommandFis(pAhciPort, pAhciReq);
     6544            if (RT_UNLIKELY(!fFisRead))
     6545            {
     6546                /*
     6547                 * Couldn't find anything in either the AHCI or SATA spec which
     6548                 * indicates what should be done if the FIS is not read successfully.
     6549                 * The closes thing is in the state machine, stating that the device
     6550                 * should go into idle state again (SATA spec 1.0 chapter 8.7.1).
     6551                 * Do the same here and ignore any corrupt FIS types, after all
     6552                 * the guest messed up everything and this behavior is undefined.
     6553                 */
     6554                ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
     6555                Assert(fXchg);
     6556                u32Tasks &= ~RT_BIT_32(idx); /* Clear task bit. */
     6557                idx = ASMBitFirstSetU32(u32Tasks);
     6558                continue;
     6559            }
    65016560
    65026561            /* Mark the task as processed by the HBA if this is a queued task so that it doesn't occur in the CI register anymore. */
     
    65156574                    pAhciPort->fResetDevice = true;
    65166575                    ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
    6517 
    6518                     ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
    6519                     AssertMsg(fXchg, ("Task is not active\n"));
    6520                     break;
    65216576                }
    65226577                else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
    6523                 {
    65246578                    ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
    6525 
    6526                     ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
    6527                     AssertMsg(fXchg, ("Task is not active\n"));
    6528                     break;
    6529                 }
    65306579                else /* We are not in a reset state update the control registers. */
    65316580                    AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
     6581
     6582                ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
     6583                AssertMsg(fXchg, ("Task is not active\n"));
     6584                break;
    65326585            }
    65336586            else
     
    66366689            idx = ASMBitFirstSetU32(u32Tasks);
    66376690        } /* while tasks available */
     6691
     6692        /*
     6693         * Check whether a host controller reset is pending and execute the reset
     6694         * if this is the last active thread.
     6695         */
     6696        u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
     6697        uint32_t cThreadsActive = ASMAtomicDecU32(&pAhci->cThreadsActive);
     6698        if (   (u32RegHbaCtrl & AHCI_HBA_CTRL_HR)
     6699            && !cThreadsActive)
     6700            ahciHBAReset(pAhci);
    66386701    } /* While running */
    66396702
     
    79988061    PCIDevSetWord(&pThis->dev, 0xaa, 0x0010);      /* Revision */
    79998062    PCIDevSetDWord(&pThis->dev, 0xac, 0x00000028); /* SATA Capability Register 1 */
     8063
     8064    pThis->cThreadsActive = 0;
    80008065
    80018066    /* Initialize port members. */
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp

    r49958 r50018  
    12841284    GEN_CHECK_OFF(AHCI, lock);
    12851285    GEN_CHECK_OFF(AHCI, u32PortsInterrupted);
     1286    GEN_CHECK_OFF(AHCI, cThreadsActive);
    12861287    GEN_CHECK_OFF(AHCI, fReset);
    12871288    GEN_CHECK_OFF(AHCI, f64BitAddr);
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