VirtualBox

Changeset 77579 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Mar 6, 2019 10:21:16 AM (6 years ago)
Author:
vboxsync
Message:

DevATA: Added empty bus port handler to simplify logic elsewhere.

File:
1 edited

Legend:

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

    r77392 r77579  
    3636#define ATA_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS    17
    3737/** @} */
     38
     39/** Values read from an empty (with no devices attached) ATA bus. */
     40#define ATA_EMPTY_BUS_DATA      0x7F
     41#define ATA_EMPTY_BUS_DATA_32   0x7F7F7F7F
    3842
    3943
     
    44744478
    44754479    /* Check if the guest is reading from a non-existent device. */
    4476     if (!s->pDrvMedia)
     4480    if (RT_UNLIKELY(!s->pDrvMedia))
    44774481    {
    44784482        if (pCtl->iSelectedIf)  /* Device 1 selected, Device 0 responding for it. */
    44794483        {
    4480             if (!pCtl->aIfs[0].pDrvMedia)   /** @todo this case should never get here! */
    4481             {
    4482                 Log2(("%s: addr=%#x: no device on channel\n", __FUNCTION__, addr));
    4483                 return VERR_IOM_IOPORT_UNUSED;
    4484             }
     4484            Assert(pCtl->aIfs[0].pDrvMedia);
     4485
     4486            /* When an ATAPI device 0 responds for non-present device 1, it generally
     4487             * returns zeros on reads. The Error register is an exception. See clause 7.1,
     4488             * table 16 in ATA-6 specification.
     4489             */
    44854490            if (((addr & 7) != 1) && pCtl->aIfs[0].fATAPI) {
    44864491                Log2(("%s: addr=%#x, val=0: LUN#%d not attached/LUN#%d ATAPI\n", __FUNCTION__, addr,
     
    44934498        else                    /* Device 0 selected (but not present). */
    44944499        {
    4495             /* ATA-3 and later specifies that the host must have a pull-down resistor on DD7; ATA-5 explains
    4496              * that this causes the BSY bit to always be read as clear when there is no device on a given
    4497              * channel. Software then does not need to wait a long time for non-existent drives; note that
    4498              * EFI (TianoCore) relies on this behavior.
     4500            /* Because device 1 has no way to tell if there is device 0, the behavior is the same
     4501             * as for an empty bus; see comments in ataIOPortReadEmptyBus(). Note that EFI (TianoCore)
     4502             * relies on this behavior when detecting devices.
    44994503             */
    4500             *pu32 = 0x7F;
     4504            *pu32 = ATA_EMPTY_BUS_DATA;
    45014505            Log2(("%s: addr=%#x: LUN#%d not attached, val=%#02x\n", __FUNCTION__, addr, s->iLUN, *pu32));
    45024506            return VINF_SUCCESS;
     
    46424646
    46434647
     4648/*
     4649 * Read the Alternate status register. Does not affect interrupts.
     4650 */
    46444651static uint32_t ataStatusRead(PATACONTROLLER pCtl, uint32_t addr)
    46454652{
     
    46484655    RT_NOREF1(addr);
    46494656
    4650     /// @todo The handler should not be even registered if there
    4651     // is no device on an IDE channel.
    4652     if (!pCtl->aIfs[0].pDrvMedia && !pCtl->aIfs[1].pDrvMedia)
    4653         val = 0xff;
    4654     else if (pCtl->iSelectedIf == 1 && !s->pDrvMedia)
     4657    Assert(pCtl->aIfs[0].pDrvMedia || pCtl->aIfs[1].pDrvMedia); /* Channel must not be empty. */
     4658    if (pCtl->iSelectedIf == 1 && !s->pDrvMedia)
    46554659        val = 0;    /* Device 1 selected, Device 0 responding for it. */
    46564660    else
    46574661        val = s->uATARegStatus;
    4658     Log2(("%s: addr=%#x val=%#04x\n", __FUNCTION__, addr, val));
     4662    Log2(("%s: LUN#%d read addr=%#x val=%#04x\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN, addr, val));
    46594663    return val;
    46604664}
     
    46684672#endif /* !IN_RING3 */
    46694673
    4670     Log2(("%s: addr=%#x val=%#04x\n", __FUNCTION__, addr, val));
     4674    Log2(("%s: LUN#%d write addr=%#x val=%#04x\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN, addr, val));
    46714675    /* RESET is common for both drives attached to a controller. */
    46724676    if (   !(pCtl->aIfs[0].uATARegDevCtl & ATA_DEVCTL_RESET)
     
    48494853         * the case for write operations or generally for not yet finished
    48504854         * transfers (some data might need to be read). */
     4855        ataSetStatus(s, ATA_STAT_BUSY);
    48514856        ataUnsetStatus(s, ATA_STAT_READY | ATA_STAT_DRQ);
    4852         ataSetStatus(s, ATA_STAT_BUSY);
    48534857
    48544858        Log2(("%s: Ctl#%d: message to async I/O thread, continuing PIO transfer\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
     
    63016305
    63026306/**
     6307 * Port I/O Handler for OUT operations on unpopulated IDE channels.
     6308 * @see FNIOMIOPORTOUT for details.
     6309 */
     6310PDMBOTHCBDECL(int) ataIOPortWriteEmptyBus(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     6311{
     6312    uint32_t       i = (uint32_t)(uintptr_t)pvUser;
     6313    PCIATAState   *pThis = PDMINS_2_DATA(pDevIns, PCIATAState *);
     6314    PATACONTROLLER pCtl = &pThis->aCts[i];
     6315#ifndef VBOX_LOG_ENABLED
     6316    RT_NOREF(Port); RT_NOREF(cb); RT_NOREF(u32); RT_NOREF(pCtl);
     6317#endif
     6318
     6319    Assert(i < 2);
     6320    Assert(!pCtl->aIfs[0].pDrvMedia && !pCtl->aIfs[1].pDrvMedia);
     6321
     6322    /* This is simply a black hole, writes on unpopulated IDE channels elicit no response. */
     6323    LogFunc(("Empty bus: Ignoring write to port %x val=%x size=%d\n", Port, u32, cb));
     6324    return VINF_SUCCESS;
     6325}
     6326
     6327
     6328/**
     6329 * Port I/O Handler for IN operations on unpopulated IDE channels.
     6330 * @see FNIOMIOPORTIN for details.
     6331 */
     6332PDMBOTHCBDECL(int) ataIOPortReadEmptyBus(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
     6333{
     6334    uint32_t       i = (uint32_t)(uintptr_t)pvUser;
     6335    PCIATAState   *pThis = PDMINS_2_DATA(pDevIns, PCIATAState *);
     6336    PATACONTROLLER pCtl = &pThis->aCts[i];
     6337#ifndef VBOX_LOG_ENABLED
     6338    RT_NOREF(Port); RT_NOREF(pCtl);
     6339#endif
     6340
     6341    Assert(i < 2);
     6342    Assert(cb <= 4);
     6343    Assert(!pCtl->aIfs[0].pDrvMedia && !pCtl->aIfs[1].pDrvMedia);
     6344
     6345    /*
     6346     * Reads on unpopulated IDE channels behave in a unique way. Newer ATA specifications
     6347     * mandate that the host must have a pull-down resistor on signal DD7. As a consequence,
     6348     * bit 7 is always read as zero. This greatly aids in ATA device detection because
     6349     * the empty bus does not look to the host like a permanently busy drive, and no long
     6350     * timeouts (on the order of 30 seconds) are needed.
     6351     *
     6352     * The response is entirely static and does not require any locking or other fancy
     6353     * stuff. Breaking it out simplifies the I/O handling for non-empty IDE channels which
     6354     * is quite complicated enough already.
     6355     */
     6356    *pu32 = ATA_EMPTY_BUS_DATA_32 >> ((4 - cb) * 8);
     6357    LogFunc(("Empty bus: port %x val=%x size=%d\n", Port, *pu32, cb));
     6358    return VINF_SUCCESS;
     6359}
     6360
     6361
     6362/**
    63036363 * Port I/O Handler for primary port range OUT operations.
    63046364 * @see FNIOMIOPORTOUT for details.
     
    63926452    }
    63936453    else
     6454    {
     6455        Log(("ataIOPortWrite2: ignoring write to port %x size=%d!\n", Port, cb));
    63946456        rc = VINF_SUCCESS;
     6457    }
    63956458    return rc;
    63966459}
     
    64206483    }
    64216484    else
     6485    {
     6486        Log(("ataIOPortRead2: ignoring read from port %x size=%d!\n", Port, cb));
    64226487        rc = VERR_IOM_IOPORT_UNUSED;
     6488    }
    64236489    return rc;
    64246490}
     
    76227688
    76237689    /*
    7624      * Register the I/O ports.
    7625      * The ports are all hardcoded and enforced by the PIIX3 host bridge controller.
     7690     * Register stats, create critical sections.
    76267691     */
    76277692    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
    76287693    {
    7629         rc = PDMDevHlpIOPortRegister(pDevIns, pThis->aCts[i].IOPortBase1, 1, (RTHCPTR)(uintptr_t)i,
    7630                                      ataIOPortWrite1Data, ataIOPortRead1Data,
    7631                                      ataIOPortWriteStr1Data, ataIOPortReadStr1Data, "ATA I/O Base 1 - Data");
    7632         AssertLogRelRCReturn(rc, rc);
    7633         rc = PDMDevHlpIOPortRegister(pDevIns, pThis->aCts[i].IOPortBase1 + 1, 7, (RTHCPTR)(uintptr_t)i,
    7634                                      ataIOPortWrite1Other, ataIOPortRead1Other, NULL, NULL, "ATA I/O Base 1 - Other");
    7635 
    7636         AssertLogRelRCReturn(rc, rc);
    7637         if (fRCEnabled)
    7638         {
    7639             rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->aCts[i].IOPortBase1, 1, (RTGCPTR)i,
    7640                                            "ataIOPortWrite1Data", "ataIOPortRead1Data",
    7641                                            "ataIOPortWriteStr1Data", "ataIOPortReadStr1Data", "ATA I/O Base 1 - Data");
    7642             AssertLogRelRCReturn(rc, rc);
    7643             rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->aCts[i].IOPortBase1 + 1, 7, (RTGCPTR)i,
    7644                                            "ataIOPortWrite1Other", "ataIOPortRead1Other", NULL, NULL, "ATA I/O Base 1 - Other");
    7645             AssertLogRelRCReturn(rc, rc);
    7646         }
    7647 
    7648         if (fR0Enabled)
    7649         {
    7650 #if 0
    7651             rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->aCts[i].IOPortBase1, 1, (RTR0PTR)i,
    7652                                            "ataIOPortWrite1Data", "ataIOPortRead1Data", NULL, NULL, "ATA I/O Base 1 - Data");
    7653 #else
    7654             rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->aCts[i].IOPortBase1, 1, (RTR0PTR)i,
    7655                                            "ataIOPortWrite1Data", "ataIOPortRead1Data",
    7656                                            "ataIOPortWriteStr1Data", "ataIOPortReadStr1Data", "ATA I/O Base 1 - Data");
    7657 #endif
    7658             AssertLogRelRCReturn(rc, rc);
    7659             rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->aCts[i].IOPortBase1 + 1, 7, (RTR0PTR)i,
    7660                                            "ataIOPortWrite1Other", "ataIOPortRead1Other", NULL, NULL, "ATA I/O Base 1 - Other");
    7661             AssertLogRelRCReturn(rc, rc);
    7662         }
    7663 
    7664         rc = PDMDevHlpIOPortRegister(pDevIns, pThis->aCts[i].IOPortBase2, 1, (RTHCPTR)(uintptr_t)i,
    7665                                      ataIOPortWrite2, ataIOPortRead2, NULL, NULL, "ATA I/O Base 2");
    7666         if (RT_FAILURE(rc))
    7667             return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register base2 I/O handlers"));
    7668 
    7669         if (fRCEnabled)
    7670         {
    7671             rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->aCts[i].IOPortBase2, 1, (RTGCPTR)i,
    7672                                            "ataIOPortWrite2", "ataIOPortRead2", NULL, NULL, "ATA I/O Base 2");
    7673             if (RT_FAILURE(rc))
    7674                 return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register base2 I/O handlers (GC)"));
    7675         }
    7676         if (fR0Enabled)
    7677         {
    7678             rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->aCts[i].IOPortBase2, 1, (RTR0PTR)i,
    7679                                            "ataIOPortWrite2", "ataIOPortRead2", NULL, NULL, "ATA I/O Base 2");
    7680             if (RT_FAILURE(rc))
    7681                 return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register base2 I/O handlers (R0)"));
    7682         }
    7683 
    76847694        for (uint32_t j = 0; j < RT_ELEMENTS(pThis->aCts[i].aIfs); j++)
    76857695        {
     
    79327942            }
    79337943            cbTotalBuffer += pIf->cbIOBuffer;
     7944        }
     7945    }
     7946
     7947    /*
     7948     * Register the I/O ports.
     7949     * The ports are all hardcoded and enforced by the PIIX3 host bridge controller.
     7950     */
     7951    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
     7952    {
     7953        if (!pThis->aCts[i].aIfs[0].pDrvMedia && !pThis->aCts[i].aIfs[1].pDrvMedia)
     7954        {
     7955            /* No device present on this ATA bus; requires special handling. */
     7956            rc = PDMDevHlpIOPortRegister(pDevIns, pThis->aCts[i].IOPortBase1, 8, (RTHCPTR)(uintptr_t)i,
     7957                                         ataIOPortWriteEmptyBus, ataIOPortReadEmptyBus, NULL, NULL, "ATA I/O Base 1 - Empty Bus");
     7958
     7959            AssertLogRelRCReturn(rc, rc);
     7960            rc = PDMDevHlpIOPortRegister(pDevIns, pThis->aCts[i].IOPortBase2, 1, (RTHCPTR)(uintptr_t)i,
     7961                                         ataIOPortWriteEmptyBus, ataIOPortReadEmptyBus, NULL, NULL, "ATA I/O Base 2 - Empty Bus");
     7962            AssertLogRelRCReturn(rc, rc);
     7963
     7964            if (fRCEnabled)
     7965            {
     7966                rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->aCts[i].IOPortBase1, 8, (RTGCPTR)i,
     7967                                               "ataIOPortWriteEmptyBus", "ataIOPortReadEmptyBus", NULL, NULL, "ATA I/O Base 1 - Empty Bus");
     7968                AssertLogRelRCReturn(rc, rc);
     7969                rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->aCts[i].IOPortBase2, 1, (RTGCPTR)i,
     7970                                               "ataIOPortWriteEmptyBus", "ataIOPortReadEmptyBus", NULL, NULL, "ATA I/O Base 2 - Empty Bus");
     7971                AssertLogRelRCReturn(rc, rc);
     7972            }
     7973
     7974            if (fR0Enabled)
     7975            {
     7976                rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->aCts[i].IOPortBase1, 8, (RTR0PTR)i,
     7977                                               "ataIOPortWriteEmptyBus", "ataIOPortReadEmptyBus", NULL, NULL, "ATA I/O Base 1 - Empty Bus");
     7978                AssertLogRelRCReturn(rc, rc);
     7979                rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->aCts[i].IOPortBase2, 1, (RTR0PTR)i,
     7980                                               "ataIOPortWriteEmptyBus", "ataIOPortReadEmptyBus", NULL, NULL, "ATA I/O Base 2 - Empty Bus");
     7981                AssertLogRelRCReturn(rc, rc);
     7982            }
     7983        }
     7984        else
     7985        {
     7986            /* At least one device present, register regular handlers. */
     7987            rc = PDMDevHlpIOPortRegister(pDevIns, pThis->aCts[i].IOPortBase1, 1, (RTHCPTR)(uintptr_t)i,
     7988                                         ataIOPortWrite1Data, ataIOPortRead1Data,
     7989                                         ataIOPortWriteStr1Data, ataIOPortReadStr1Data, "ATA I/O Base 1 - Data");
     7990            AssertLogRelRCReturn(rc, rc);
     7991            rc = PDMDevHlpIOPortRegister(pDevIns, pThis->aCts[i].IOPortBase1 + 1, 7, (RTHCPTR)(uintptr_t)i,
     7992                                         ataIOPortWrite1Other, ataIOPortRead1Other, NULL, NULL, "ATA I/O Base 1 - Other");
     7993
     7994            AssertLogRelRCReturn(rc, rc);
     7995            if (fRCEnabled)
     7996            {
     7997                rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->aCts[i].IOPortBase1, 1, (RTGCPTR)i,
     7998                                               "ataIOPortWrite1Data", "ataIOPortRead1Data",
     7999                                               "ataIOPortWriteStr1Data", "ataIOPortReadStr1Data", "ATA I/O Base 1 - Data");
     8000                AssertLogRelRCReturn(rc, rc);
     8001                rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->aCts[i].IOPortBase1 + 1, 7, (RTGCPTR)i,
     8002                                               "ataIOPortWrite1Other", "ataIOPortRead1Other", NULL, NULL, "ATA I/O Base 1 - Other");
     8003                AssertLogRelRCReturn(rc, rc);
     8004            }
     8005
     8006            if (fR0Enabled)
     8007            {
     8008    #if 0
     8009                rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->aCts[i].IOPortBase1, 1, (RTR0PTR)i,
     8010                                               "ataIOPortWrite1Data", "ataIOPortRead1Data", NULL, NULL, "ATA I/O Base 1 - Data");
     8011    #else
     8012                rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->aCts[i].IOPortBase1, 1, (RTR0PTR)i,
     8013                                               "ataIOPortWrite1Data", "ataIOPortRead1Data",
     8014                                               "ataIOPortWriteStr1Data", "ataIOPortReadStr1Data", "ATA I/O Base 1 - Data");
     8015    #endif
     8016                AssertLogRelRCReturn(rc, rc);
     8017                rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->aCts[i].IOPortBase1 + 1, 7, (RTR0PTR)i,
     8018                                               "ataIOPortWrite1Other", "ataIOPortRead1Other", NULL, NULL, "ATA I/O Base 1 - Other");
     8019                AssertLogRelRCReturn(rc, rc);
     8020            }
     8021
     8022            rc = PDMDevHlpIOPortRegister(pDevIns, pThis->aCts[i].IOPortBase2, 1, (RTHCPTR)(uintptr_t)i,
     8023                                         ataIOPortWrite2, ataIOPortRead2, NULL, NULL, "ATA I/O Base 2");
     8024            if (RT_FAILURE(rc))
     8025                return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register base2 I/O handlers"));
     8026
     8027            if (fRCEnabled)
     8028            {
     8029                rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->aCts[i].IOPortBase2, 1, (RTGCPTR)i,
     8030                                               "ataIOPortWrite2", "ataIOPortRead2", NULL, NULL, "ATA I/O Base 2");
     8031                if (RT_FAILURE(rc))
     8032                    return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register base2 I/O handlers (GC)"));
     8033            }
     8034            if (fR0Enabled)
     8035            {
     8036                rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->aCts[i].IOPortBase2, 1, (RTR0PTR)i,
     8037                                               "ataIOPortWrite2", "ataIOPortRead2", NULL, NULL, "ATA I/O Base 2");
     8038                if (RT_FAILURE(rc))
     8039                    return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register base2 I/O handlers (R0)"));
     8040            }
    79348041        }
    79358042    }
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