VirtualBox

Changeset 82152 in vbox for trunk/src


Ignore:
Timestamp:
Nov 25, 2019 8:13:52 AM (5 years ago)
Author:
vboxsync
Message:

DevFdc: Introduced IRQDelay option to postpone interrupts, needed for old guests which assume that floppy drives are not infinitely fast.

File:
1 edited

Legend:

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

    r82025 r82152  
    465465static void fdctrl_reset(fdctrl_t *fdctrl, int do_irq);
    466466static void fdctrl_reset_fifo(fdctrl_t *fdctrl);
    467 static void fdctrl_raise_irq(fdctrl_t *fdctrl, uint8_t status0);
    468467static fdrive_t *get_cur_drv(fdctrl_t *fdctrl);
    469468
     
    651650    /* Controller state */
    652651    TMTIMERHANDLE hResultTimer;
     652
     653    /* Interrupt delay timers. */
     654    TMTIMERHANDLE hXferDelayTimer;
     655    TMTIMERHANDLE hIrqDelayTimer;
     656    uint16_t uIrqDelayMsec;
     657    uint8_t st0;
     658    uint8_t st1;
     659    uint8_t st2;
     660
    653661    uint8_t sra;
    654662    uint8_t srb;
     
    770778}
    771779
    772 static void fdctrl_raise_irq(fdctrl_t *fdctrl, uint8_t status0)
     780static void fdctrl_raise_irq_now(fdctrl_t *fdctrl, uint8_t status0)
    773781{
    774782    if (!(fdctrl->sra & FD_SRA_INTPEND)) {
     
    789797    fdctrl->status0 = status0;
    790798    FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0);
     799}
     800
     801static void fdctrl_raise_irq(fdctrl_t *fdctrl, uint8_t status0)
     802{
     803    if (!fdctrl->uIrqDelayMsec)
     804    {
     805        /* If not IRQ delay needed, trigger the interrupt now. */
     806        fdctrl_raise_irq_now(fdctrl, status0);
     807    }
     808    else
     809    {
     810        /* Otherwise schedule completion after a short while. */
     811        fdctrl->st0 = status0;
     812        PDMDevHlpTimerSetMillies(fdctrl->pDevIns, fdctrl->hIrqDelayTimer, fdctrl->uIrqDelayMsec);
     813    }
    791814}
    792815
     
    10941117
    10951118/* Callback for transfer end (stop or abort) */
    1096 static void fdctrl_stop_transfer(fdctrl_t *fdctrl, uint8_t status0,
    1097                                  uint8_t status1, uint8_t status2)
     1119static void fdctrl_stop_transfer_now(fdctrl_t *fdctrl, uint8_t status0,
     1120                                     uint8_t status1, uint8_t status2)
    10981121{
    10991122    fdrive_t *cur_drv;
     
    11211144    fdctrl->msr &= ~FD_MSR_NONDMA;
    11221145    fdctrl_set_fifo(fdctrl, 7, 1);
     1146}
     1147
     1148static void fdctrl_stop_transfer(fdctrl_t *fdctrl, uint8_t status0,
     1149                                 uint8_t status1, uint8_t status2)
     1150{
     1151    if (!fdctrl->uIrqDelayMsec)
     1152    {
     1153        /* If not IRQ delay needed, just stop the transfer and trigger IRQ now. */
     1154        fdctrl_stop_transfer_now(fdctrl, status0, status1, status2);
     1155    }
     1156    else
     1157    {
     1158        /* Otherwise schedule completion after a short while. */
     1159        fdctrl->st0 = status0;
     1160        fdctrl->st1 = status1;
     1161        fdctrl->st2 = status2;
     1162        PDMDevHlpTimerSetMillies(fdctrl->pDevIns, fdctrl->hXferDelayTimer, fdctrl->uIrqDelayMsec);
     1163    }
    11231164}
    11241165
     
    12421283    if (direction != FD_DIR_WRITE)
    12431284        fdctrl->msr |= FD_MSR_DIO;
     1285
    12441286    /* IO based transfer: calculate len */
    12451287    fdctrl_raise_irq(fdctrl, 0x00);
    1246 
    12471288    return;
    12481289}
     
    21682209        FLOPPY_DPRINTF("read id when no disk in drive\n");
    21692210        /// @todo This is wrong! Command should not complete.
    2170         fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA | FD_SR1_ND, FD_SR2_MD);
     2211        fdctrl_stop_transfer_now(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA | FD_SR1_ND, FD_SR2_MD);
    21712212    } else if ((fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) {
    21722213        FLOPPY_DPRINTF("read id rate mismatch (fdc=%d, media=%d)\n",
    21732214                       fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate);
    2174         fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA | FD_SR1_ND, FD_SR2_MD);
     2215        fdctrl_stop_transfer_now(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA | FD_SR1_ND, FD_SR2_MD);
    21752216    } else if (cur_drv->track >= cur_drv->max_track) {
    21762217        FLOPPY_DPRINTF("read id past last track (%d >= %d)\n",
    21772218                       cur_drv->track, cur_drv->max_track);
    21782219        cur_drv->ltrk = 0;
    2179         fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA | FD_SR1_ND, FD_SR2_MD);
     2220        fdctrl_stop_transfer_now(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA | FD_SR1_ND, FD_SR2_MD);
    21802221    }
    21812222    else
    2182         fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
     2223        fdctrl_stop_transfer_now(fdctrl, 0x00, 0x00, 0x00);
    21832224}
    21842225
     
    22332274
    22342275/**
     2276 * @callback_method_impl{FNTMTIMERDEV}
     2277 */
     2278static DECLCALLBACK(void) fdcTransferDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
     2279{
     2280    RT_NOREF(pDevIns, pTimer);
     2281    fdctrl_t *fdctrl = (fdctrl_t *)pvUser;
     2282    fdctrl_stop_transfer_now(fdctrl, fdctrl->st0, fdctrl->st1, fdctrl->st2);
     2283}
     2284
     2285/**
     2286 * @callback_method_impl{FNTMTIMERDEV}
     2287 */
     2288static DECLCALLBACK(void) fdcIrqDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
     2289{
     2290    RT_NOREF(pDevIns, pTimer);
     2291    fdctrl_t *fdctrl = (fdctrl_t *)pvUser;
     2292    fdctrl_raise_irq_now(fdctrl, fdctrl->st0);
     2293}
     2294
     2295
     2296
     2297/* -=-=-=-=-=-=-=-=- I/O Port Access Handlers -=-=-=-=-=-=-=-=- */
     2298/**
    22352299 * @callback_method_impl{FNIOMIOPORTNEWIN, Handling 0x3f1..0x3f5 accesses.}
    22362300 */
     
    22912355    PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
    22922356    unsigned int i;
     2357    int rc;
    22932358
    22942359    /* Save the FDC I/O registers... */
     
    23382403        pHlp->pfnSSMPutU8(pSSM, d->sect);
    23392404    }
     2405    rc = pHlp->pfnTimerSave(pDevIns, pThis->hXferDelayTimer, pSSM);
     2406    if (RT_FAILURE(rc))
     2407        return rc;
     2408
     2409    rc = pHlp->pfnTimerSave(pDevIns, pThis->hIrqDelayTimer, pSSM);
     2410    if (RT_FAILURE(rc))
     2411        return rc;
     2412
    23402413    return pHlp->pfnTimerSave(pDevIns, pThis->hResultTimer, pSSM);
    23412414}
     
    27582831     * Validate configuration.
    27592832     */
    2760     PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IRQ|DMA|MemMapped|IOBase|StatusA", "");
     2833    PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IRQ|DMA|MemMapped|IOBase|StatusA|IRQDelay", "");
    27612834
    27622835    /*
     
    27752848    rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "MemMapped", &fMemMapped, false);
    27762849    AssertMsgRCReturn(rc, ("Configuration error: Failed to read bool value MemMapped rc=%Rrc\n", rc), rc);
     2850
     2851    uint16_t uIrqDelay;
     2852    rc = CFGMR3QueryU16Def(pCfg, "IRQDelay", &uIrqDelay, 0);
     2853    AssertMsgRCReturn(rc, ("Configuration error: Failed to read U16 IRQDelay, rc=%Rrc\n", rc), rc);
    27772854
    27782855    bool fStatusA;
     
    28222899                                TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "FDC Timer", &pThis->hResultTimer);
    28232900    AssertRCReturn(rc, rc);
     2901
     2902    /*
     2903     * Create the transfer delay timer.
     2904     */
     2905    rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, fdcTransferDelayTimer, pThis,
     2906                              TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "FDC Transfer Delay Timer", &pThis->hXferDelayTimer);
     2907    if (RT_FAILURE(rc))
     2908        return rc;
     2909
     2910    /*
     2911     * Create the IRQ delay timer.
     2912     */
     2913    rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, fdcIrqDelayTimer, pThis,
     2914                              TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "FDC IRQ Delay Timer", &pThis->hIrqDelayTimer);
     2915    if (RT_FAILURE(rc))
     2916        return rc;
     2917
     2918    pThis->uIrqDelayMsec = uIrqDelay;
    28242919
    28252920    /*
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