VirtualBox

Changeset 36878 in vbox


Ignore:
Timestamp:
Apr 28, 2011 7:48:01 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
71456
Message:

AHCI: Support access through the index/data register pair from the I/O port space (as described in 10.14 of the AHCI 1.2 spec). Required for the BIOS driver

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

Legend:

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

    r36800 r36878  
    580580    /** Base address of the MMIO region. */
    581581    RTGCPHYS                        MMIOBase;
     582    /** Base address of the I/O port region for Idx/Data. */
     583    RTIOPORT                        IOPortBase;
    582584
    583585    /** Global Host Control register of the HBA */
     
    597599    /** Command completion coalescing ports */
    598600    uint32_t                        regHbaCccPorts;
     601
     602    /** Index register for BIOS access. */
     603    uint32_t                        regIdx;
    599604
    600605#if HC_ARCH_BITS == 64
     
    20372042
    20382043/**
     2044 * Reads from a AHCI controller register.
     2045 *
     2046 * @returns VBox status code.
     2047 *
     2048 * @param   pAhci       The AHCI instance.
     2049 * @param   uReg        The register to write.
     2050 * @param   pv          Where to store the result.
     2051 * @param   cb          Number of bytes read.
     2052 */
     2053static int ahciRegisterRead(PAHCI pAhci, uint32_t uReg, void *pv, unsigned cb)
     2054{
     2055    int rc = VINF_SUCCESS;
     2056    uint32_t iReg;
     2057
     2058    /*
     2059     * If the access offset is smaller than AHCI_HBA_GLOBAL_SIZE the guest accesses the global registers.
     2060     * Otherwise it accesses the registers of a port.
     2061     */
     2062    if (uReg < AHCI_HBA_GLOBAL_SIZE)
     2063    {
     2064        iReg = uReg >> 2;
     2065        Log3(("%s: Trying to read from global register %u\n", __FUNCTION__, iReg));
     2066        if (iReg < RT_ELEMENTS(g_aOpRegs))
     2067        {
     2068            const AHCIOPREG *pReg = &g_aOpRegs[iReg];
     2069            rc = pReg->pfnRead(pAhci, iReg, (uint32_t *)pv);
     2070        }
     2071        else
     2072        {
     2073            Log3(("%s: Trying to read global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
     2074            *(uint32_t *)pv = 0;
     2075        }
     2076    }
     2077    else
     2078    {
     2079        uint32_t iRegOffset;
     2080        uint32_t iPort;
     2081
     2082        /* Calculate accessed port. */
     2083        uReg -= AHCI_HBA_GLOBAL_SIZE;
     2084        iPort = uReg / AHCI_PORT_REGISTER_SIZE;
     2085        iRegOffset  = (uReg % AHCI_PORT_REGISTER_SIZE);
     2086        iReg = iRegOffset >> 2;
     2087
     2088        Log3(("%s: Trying to read from port %u and register %u\n", __FUNCTION__, iPort, iReg));
     2089
     2090        if (RT_LIKELY(   iPort < pAhci->cPortsImpl
     2091                      && iReg < RT_ELEMENTS(g_aPortOpRegs)))
     2092        {
     2093            const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
     2094            rc = pPortReg->pfnRead(pAhci, &pAhci->ahciPort[iPort], iReg, (uint32_t *)pv);
     2095        }
     2096        else
     2097        {
     2098            Log3(("%s: Trying to read port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
     2099            rc = VINF_IOM_MMIO_UNUSED_00;
     2100        }
     2101
     2102        /*
     2103         * Windows Vista tries to read one byte from some registers instead of four.
     2104         * Correct the value according to the read size.
     2105         */
     2106        if (RT_SUCCESS(rc) && cb != sizeof(uint32_t))
     2107        {
     2108            switch (cb)
     2109            {
     2110                case 1:
     2111                {
     2112                    uint8_t uNewValue;
     2113                    uint8_t *p = (uint8_t *)pv;
     2114
     2115                    iRegOffset &= 3;
     2116                    Log3(("%s: iRegOffset=%u\n", __FUNCTION__, iRegOffset));
     2117                    uNewValue = p[iRegOffset];
     2118                    /* Clear old value */
     2119                    *(uint32_t *)pv = 0;
     2120                    *(uint8_t *)pv = uNewValue;
     2121                    break;
     2122                }
     2123                default:
     2124                    AssertMsgFailed(("%s: unsupported access width cb=%d iPort=%x iRegOffset=%x iReg=%x!!!\n",
     2125                                     __FUNCTION__, cb, iPort, iRegOffset, iReg));
     2126            }
     2127        }
     2128    }
     2129
     2130    return rc;
     2131}
     2132
     2133/**
     2134 * Writes a value to one of the AHCI controller registers.
     2135 *
     2136 * @returns VBox status code.
     2137 *
     2138 * @param   pAhci       The AHCI instance.
     2139 * @param   uReg        The register to write.
     2140 * @param   pv          Where to fetch the result.
     2141 * @param   cb          Number of bytes to write.
     2142 */
     2143static int ahciRegisterWrite(PAHCI pAhci, uint32_t uReg, void *pv, unsigned cb)
     2144{
     2145    int rc = VINF_SUCCESS;
     2146    uint32_t iReg;
     2147
     2148    if (uReg < AHCI_HBA_GLOBAL_SIZE)
     2149    {
     2150        Log3(("Write global HBA register\n"));
     2151        iReg = uReg >> 2;
     2152        if (iReg < RT_ELEMENTS(g_aOpRegs))
     2153        {
     2154            const AHCIOPREG *pReg = &g_aOpRegs[iReg];
     2155            rc = pReg->pfnWrite(pAhci, iReg, *(uint32_t *)pv);
     2156        }
     2157        else
     2158        {
     2159            Log3(("%s: Trying to write global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
     2160            rc = VINF_SUCCESS;
     2161        }
     2162    }
     2163    else
     2164    {
     2165        uint32_t iPort;
     2166        Log3(("Write Port register\n"));
     2167        /* Calculate accessed port. */
     2168        uReg -= AHCI_HBA_GLOBAL_SIZE;
     2169        iPort = uReg / AHCI_PORT_REGISTER_SIZE;
     2170        iReg  = (uReg % AHCI_PORT_REGISTER_SIZE) >> 2;
     2171        Log3(("%s: Trying to write to port %u and register %u\n", __FUNCTION__, iPort, iReg));
     2172        if (RT_LIKELY(   iPort < pAhci->cPortsImpl
     2173                      && iReg < RT_ELEMENTS(g_aPortOpRegs)))
     2174        {
     2175            const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
     2176            rc = pPortReg->pfnWrite(pAhci, &pAhci->ahciPort[iPort], iReg, *(uint32_t *)pv);
     2177        }
     2178        else
     2179        {
     2180            Log3(("%s: Trying to write port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
     2181            rc = VINF_SUCCESS;
     2182        }
     2183    }
     2184
     2185    return rc;
     2186}
     2187
     2188/**
    20392189 * Memory mapped I/O Handler for read operations.
    20402190 *
     
    20652215          pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
    20662216
    2067     /*
    2068      * If the access offset is smaller than AHCI_HBA_GLOBAL_SIZE the guest accesses the global registers.
    2069      * Otherwise it accesses the registers of a port.
    2070      */
    20712217    uint32_t uOffset = (GCPhysAddr - pAhci->MMIOBase);
    2072     uint32_t iReg;
    2073 
    2074     if (uOffset < AHCI_HBA_GLOBAL_SIZE)
    2075     {
    2076         iReg = uOffset >> 2;
    2077         Log3(("%s: Trying to read from global register %u\n", __FUNCTION__, iReg));
    2078         if (iReg < RT_ELEMENTS(g_aOpRegs))
    2079         {
    2080             const AHCIOPREG *pReg = &g_aOpRegs[iReg];
    2081             rc = pReg->pfnRead(pAhci, iReg, (uint32_t *)pv);
    2082         }
    2083         else
    2084         {
    2085             Log3(("%s: Trying to read global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
    2086             *(uint32_t *)pv = 0;
    2087         }
    2088     }
    2089     else
    2090     {
    2091         uint32_t iRegOffset;
    2092         uint32_t iPort;
    2093 
    2094         /* Calculate accessed port. */
    2095         uOffset -= AHCI_HBA_GLOBAL_SIZE;
    2096         iPort = uOffset / AHCI_PORT_REGISTER_SIZE;
    2097         iRegOffset  = (uOffset % AHCI_PORT_REGISTER_SIZE);
    2098         iReg = iRegOffset >> 2;
    2099 
    2100         Log3(("%s: Trying to read from port %u and register %u\n", __FUNCTION__, iPort, iReg));
    2101 
    2102         if (RT_LIKELY(   iPort < pAhci->cPortsImpl
    2103                       && iReg < RT_ELEMENTS(g_aPortOpRegs)))
    2104         {
    2105             const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
    2106             rc = pPortReg->pfnRead(pAhci, &pAhci->ahciPort[iPort], iReg, (uint32_t *)pv);
    2107         }
    2108         else
    2109         {
    2110             Log3(("%s: Trying to read port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
    2111             rc = VINF_IOM_MMIO_UNUSED_00;
    2112         }
    2113 
    2114         /*
    2115          * Windows Vista tries to read one byte from some registers instead of four.
    2116          * Correct the value according to the read size.
    2117          */
    2118         if (RT_SUCCESS(rc) && cb != sizeof(uint32_t))
    2119         {
    2120             switch (cb)
    2121             {
    2122                 case 1:
    2123                 {
    2124                     uint8_t uNewValue;
    2125                     uint8_t *p = (uint8_t *)pv;
    2126 
    2127                     iRegOffset &= 3;
    2128                     Log3(("%s: iRegOffset=%u\n", __FUNCTION__, iRegOffset));
    2129                     uNewValue = p[iRegOffset];
    2130                     /* Clear old value */
    2131                     *(uint32_t *)pv = 0;
    2132                     *(uint8_t *)pv = uNewValue;
    2133                     break;
    2134                 }
    2135                 default:
    2136                     AssertMsgFailed(("%s: unsupported access width cb=%d uOffset=%x iPort=%x iRegOffset=%x iReg=%x!!!\n", __FUNCTION__, cb, uOffset, iPort, iRegOffset, iReg));
    2137             }
    2138         }
    2139     }
     2218    rc = ahciRegisterRead(pAhci, uOffset, pv, cb);
    21402219
    21412220    Log2(("#%d ahciMMIORead: return pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
     
    22112290     */
    22122291    uint32_t uOffset = (GCPhysAddr - pAhci->MMIOBase);
    2213     uint32_t iReg;
    2214     if (uOffset < AHCI_HBA_GLOBAL_SIZE)
    2215     {
    2216         Log3(("Write global HBA register\n"));
    2217         iReg = uOffset >> 2;
    2218         if (iReg < RT_ELEMENTS(g_aOpRegs))
    2219         {
    2220             const AHCIOPREG *pReg = &g_aOpRegs[iReg];
    2221             rc = pReg->pfnWrite(pAhci, iReg, *(uint32_t *)pv);
    2222         }
    2223         else
    2224         {
    2225             Log3(("%s: Trying to write global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
    2226             rc = VINF_SUCCESS;
    2227         }
    2228     }
    2229     else
    2230     {
    2231         uint32_t iPort;
    2232         Log3(("Write Port register\n"));
    2233         /* Calculate accessed port. */
    2234         uOffset -= AHCI_HBA_GLOBAL_SIZE;
    2235         iPort = uOffset / AHCI_PORT_REGISTER_SIZE;
    2236         iReg  = (uOffset % AHCI_PORT_REGISTER_SIZE) >> 2;
    2237         Log3(("%s: Trying to write to port %u and register %u\n", __FUNCTION__, iPort, iReg));
    2238         if (RT_LIKELY(   iPort < pAhci->cPortsImpl
    2239                       && iReg < RT_ELEMENTS(g_aPortOpRegs)))
    2240         {
    2241             const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
    2242             rc = pPortReg->pfnWrite(pAhci, &pAhci->ahciPort[iPort], iReg, *(uint32_t *)pv);
    2243         }
    2244         else
    2245         {
    2246             Log3(("%s: Trying to write port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
    2247             rc = VINF_SUCCESS;
    2248         }
    2249     }
     2292    rc = ahciRegisterWrite(pAhci, uOffset, pv, cb);
    22502293
    22512294    return rc;
     
    23062349    AssertMsgFailed(("Should not happen\n"));
    23072350    return VINF_SUCCESS;
     2351}
     2352
     2353/**
     2354 * I/O port handler for writes to the index/data register pair.
     2355 *
     2356 * @returns VBox status code.
     2357 *
     2358 * @param   pDevIns     The device instance.
     2359 * @param   pvUser      User argument.
     2360 * @param   Port        Port address where the write starts.
     2361 * @param   pv          Where to fetch the result.
     2362 * @param   cb          Number of bytes to write.
     2363 */
     2364PDMBOTHCBDECL(int) ahciIdxDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     2365{
     2366    PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
     2367    int   rc = VINF_SUCCESS;
     2368
     2369    if (Port - pAhci->IOPortBase >= 8)
     2370    {
     2371        unsigned iReg = (Port - pAhci->IOPortBase - 8) / 4;
     2372
     2373        Assert(cb == 4);
     2374
     2375        if (iReg == 0)
     2376        {
     2377            /* Write the index register. */
     2378            pAhci->regIdx = u32;
     2379        }
     2380        else
     2381        {
     2382            Assert(iReg == 1);
     2383            rc = ahciRegisterWrite(pAhci, pAhci->regIdx, &u32, cb);
     2384        }
     2385    }
     2386    /* else: ignore */
     2387
     2388    Log2(("#%d ahciIdxDataWrite: pu32=%p:{%.*Rhxs} cb=%d Port=%#x rc=%Rrc\n",
     2389          pDevIns->iInstance, &u32, cb, &u32, cb, Port, rc));
     2390    return rc;
     2391}
     2392
     2393/**
     2394 * I/O port handler for reads from the index/data register pair.
     2395 *
     2396 * @returns VBox status code.
     2397 *
     2398 * @param   pDevIns     The device instance.
     2399 * @param   pvUser      User argument.
     2400 * @param   Port        Port address where the read starts.
     2401 * @param   pv          Where to fetch the result.
     2402 * @param   cb          Number of bytes to write.
     2403 */
     2404PDMBOTHCBDECL(int) ahciIdxDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
     2405{
     2406    PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
     2407    int   rc = VINF_SUCCESS;
     2408
     2409    if (Port - pAhci->IOPortBase >= 8)
     2410    {
     2411        unsigned iReg = (Port - pAhci->IOPortBase - 8) / 4;
     2412
     2413        Assert(cb == 4);
     2414
     2415        if (iReg == 0)
     2416        {
     2417            /* Read the index register. */
     2418            *pu32 = pAhci->regIdx;
     2419        }
     2420        else
     2421        {
     2422            Assert(iReg == 1);
     2423            rc = ahciRegisterRead(pAhci, pAhci->regIdx, pu32, cb);
     2424        }
     2425    }
     2426    else
     2427        *pu32 = UINT32_C(0xffffffff);
     2428
     2429    Log2(("#%d ahciIdxDataRead: pu32=%p:{%.*Rhxs} cb=%d Port=%#x rc=%Rrc\n",
     2430          pDevIns->iInstance, pu32, cb, pu32, cb, Port, rc));
     2431    return rc;
    23082432}
    23092433
     
    24152539    }
    24162540
     2541    return rc;
     2542}
     2543
     2544/**
     2545 * Map the BMDMA I/O port range (used for the Index/Data pair register access)
     2546 */
     2547static DECLCALLBACK(int) ahciR3IdxDataIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
     2548{
     2549    PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
     2550    PPDMDEVINS pDevIns = pPciDev->pDevIns;
     2551    int   rc = VINF_SUCCESS;
     2552
     2553    Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
     2554
     2555    Assert(enmType == PCI_ADDRESS_SPACE_IO);
     2556
     2557    /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
     2558    rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, cb, NULL,
     2559                                 ahciIdxDataWrite, ahciIdxDataRead, NULL, NULL, "AHCI IDX/DATA");
     2560    if (RT_FAILURE(rc))
     2561        return rc;
     2562
     2563    if (pThis->fR0Enabled)
     2564    {
     2565        rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
     2566                                       "ahciIdxDataWrite", "ahciIdxDataRead", NULL, NULL, "AHCI IDX/DATA");
     2567        if (RT_FAILURE(rc))
     2568            return rc;
     2569    }
     2570
     2571    if (pThis->fGCEnabled)
     2572    {
     2573        rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
     2574                                       "ahciIdxDataWrite", "ahciIdxDataRead", NULL, NULL, "AHCI IDX/DATA");
     2575        if (RT_FAILURE(rc))
     2576            return rc;
     2577    }
     2578
     2579    pThis->IOPortBase = (RTIOPORT)GCPhysAddress;
    24172580    return rc;
    24182581}
     
    80478210
    80488211    pThis->dev.config[0x70] = VBOX_PCI_CAP_ID_PM; /* Capability ID: PCI Power Management Interface */
    8049     pThis->dev.config[0x71] = 0x00; /* next */
     8212    pThis->dev.config[0x71] = 0xa8; /* next */
    80508213    pThis->dev.config[0x72] = 0x03; /* version ? */
    80518214
     
    80558218    pThis->dev.config[0x95] = 0x01;
    80568219    pThis->dev.config[0x97] = 0x78;
     8220
     8221    pThis->dev.config[0xa8] = 0x12;                /* SATACR capability */
     8222    pThis->dev.config[0xa9] = 0x00;                /* next */
     8223    PCIDevSetWord(&pThis->dev, 0xaa, 0x0010);      /* Revision */
     8224    PCIDevSetDWord(&pThis->dev, 0xac, 0x00000028); /* SATA Capability Register 1 */
    80578225
    80588226    /*
     
    81088276                                N_("AHCI cannot register PCI I/O region"));
    81098277
    8110     rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
     8278    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciR3IdxDataIORangeMap);
    81118279    if (RT_FAILURE(rc))
    81128280        return PDMDEV_SET_ERROR(pDevIns, rc,
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp

    r36870 r36878  
    12101210    GEN_CHECK_OFF(AHCIPort, fAsyncInterface);
    12111211    GEN_CHECK_OFF(AHCIPort, fResetDevice);
     1212    GEN_CHECK_OFF(AHCIPort, fAsyncIOThreadIdle);
     1213    GEN_CHECK_OFF(AHCIPort, fRedo);
    12121214    GEN_CHECK_OFF(AHCIPort, cTotalSectors);
    12131215    GEN_CHECK_OFF(AHCIPort, cMultSectors);
     
    12791281    GEN_CHECK_OFF(AHCI, regHbaCccCtl);
    12801282    GEN_CHECK_OFF(AHCI, regHbaCccPorts);
     1283    GEN_CHECK_OFF(AHCI, regIdx);
    12811284    GEN_CHECK_OFF(AHCI, pHbaCccTimerR3);
    12821285    GEN_CHECK_OFF(AHCI, pHbaCccTimerR0);
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