VirtualBox

Ignore:
Timestamp:
Sep 22, 2020 7:08:56 AM (4 years ago)
Author:
vboxsync
Message:

AMD IOMMU: bugref:9654 Extract common code in preparation for reworking MMIO register reads (to support high 32-bit reads on 64-bit registers).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp

    r86209 r86210  
    15751575};
    15761576AssertCompile(RT_ELEMENTS(g_aRegAccess2) == (IOMMU_MMIO_OFF_QWORD_TABLE_2_END - IOMMU_MMIO_OFF_QWORD_TABLE_2_START) / 8);
     1577
     1578
     1579/**
     1580 * Gets the register access structure given its MMIO offset.
     1581 *
     1582 * @returns The register access structure, or NULL if the offset is invalid.
     1583 * @param   off     The MMIO offset of the register being accessed.
     1584 */
     1585static PCIOMMUREGACC iommuAmdGetRegAccessForOffset(uint32_t off)
     1586{
     1587    /* Figure out which table the register belongs to and validate its index. */
     1588    PCIOMMUREGACC pReg;
     1589    if (off < IOMMU_MMIO_OFF_QWORD_TABLE_0_END)
     1590    {
     1591        uint32_t const idxReg = off >> 3;
     1592        Assert(idxReg < RT_ELEMENTS(g_aRegAccess0));
     1593        pReg = &g_aRegAccess0[idxReg];
     1594    }
     1595    else if (   off <  IOMMU_MMIO_OFF_QWORD_TABLE_1_END
     1596             && off >= IOMMU_MMIO_OFF_QWORD_TABLE_1_START)
     1597    {
     1598        uint32_t const idxReg = (off - IOMMU_MMIO_OFF_QWORD_TABLE_1_START) >> 3;
     1599        Assert(idxReg < RT_ELEMENTS(g_aRegAccess1));
     1600        pReg = &g_aRegAccess1[idxReg];
     1601    }
     1602    else if (   off <  IOMMU_MMIO_OFF_QWORD_TABLE_2_END
     1603             && off >= IOMMU_MMIO_OFF_QWORD_TABLE_2_START)
     1604    {
     1605        uint32_t const idxReg = (off - IOMMU_MMIO_OFF_QWORD_TABLE_2_START) >> 3;
     1606        Assert(idxReg < RT_ELEMENTS(g_aRegAccess2));
     1607        pReg = &g_aRegAccess2[idxReg];
     1608    }
     1609    else
     1610        return NULL;
     1611
     1612    return pReg;
     1613}
    15771614#endif
    15781615
     
    17171754    }
    17181755#else
    1719     /*
    1720      * Figure out which table the register belongs to and validate its index.
    1721      */
    1722     PCIOMMUREGACC pReg;
    1723     if (off < IOMMU_MMIO_OFF_QWORD_TABLE_0_END)
    1724     {
    1725         uint32_t const idxReg = off >> 3;
    1726         Assert(idxReg < RT_ELEMENTS(g_aRegAccess0));
    1727         pReg = &g_aRegAccess0[idxReg];
    1728     }
    1729     else if (   off <  IOMMU_MMIO_OFF_QWORD_TABLE_1_END
    1730              && off >= IOMMU_MMIO_OFF_QWORD_TABLE_1_START)
    1731     {
    1732         uint32_t const idxReg = (off - IOMMU_MMIO_OFF_QWORD_TABLE_1_START) >> 3;
    1733         Assert(idxReg < RT_ELEMENTS(g_aRegAccess1));
    1734         pReg = &g_aRegAccess1[idxReg];
    1735     }
    1736     else if (   off <  IOMMU_MMIO_OFF_QWORD_TABLE_2_END
    1737              && off >= IOMMU_MMIO_OFF_QWORD_TABLE_2_START)
    1738     {
    1739         uint32_t const idxReg = (off - IOMMU_MMIO_OFF_QWORD_TABLE_2_START) >> 3;
    1740         Assert(idxReg < RT_ELEMENTS(g_aRegAccess2));
    1741         pReg = &g_aRegAccess2[idxReg];
    1742     }
     1756    PCIOMMUREGACC pReg = iommuAmdGetRegAccessForOffset(off);
     1757    if (pReg)
     1758    { /* likely */ }
    17431759    else
    17441760    {
     
    17471763    }
    17481764
     1765    /* If a write handler doesn't exist, it's either a reserved or read-only register. */
     1766    if (pReg->pfnWrite)
     1767    { /* likely */ }
     1768    else
     1769    {
     1770        LogFunc(("Writing reserved or read-only register off=%#x (cb=%u) with %#RX64 -> Ignored\n", off, cb, uValue));
     1771        return VINF_SUCCESS;
     1772    }
     1773
    17491774    /*
    1750      * Ensure the register is writable and proceed.
    1751      * If a write handler doesn't exist, it's either a reserved or read-only register.
     1775     * If the write access is aligned and matches the register size, dispatch right away.
     1776     * This handles all aligned, 32-bit writes as well as aligned 64-bit writes.
    17521777     */
    1753     if (pReg->pfnWrite)
     1778    if (   cb == pReg->cb
     1779        && !(off & (cb - 1)))
     1780        return pReg->pfnWrite(pDevIns, pThis, off, uValue);
     1781
     1782    /*
     1783     * A 32-bit write for a 64-bit register.
     1784     * We shouldn't get sizes other than 32 bits here as we've specified so with IOM.
     1785     */
     1786    Assert(cb == 4);
     1787    if (!(off & 7))
    17541788    {
    17551789        /*
    1756          * If the write access is aligned and matches the register size, dispatch right away.
    1757          * This handles all aligned, 32-bit writes as well as aligned 64-bit writes.
     1790         * Lower 32 bits of the register is being written.
     1791         * Merge with higher 32 bits (after reading the full value from the register).
    17581792         */
    1759         if (   cb == pReg->cb
    1760             && !(off & (cb - 1)))
    1761             return pReg->pfnWrite(pDevIns, pThis, off, uValue);
    1762 
    1763         /*
    1764          * A 32-bit write for a 64-bit register.
    1765          * We shouldn't get sizes other than 32 bits here as we've specified so with IOM.
    1766          */
    1767         Assert(cb == 4);
    1768         if (!(off & 7))
    1769         {
    1770             /*
    1771              * Lower 32 bits of the register is being written.
    1772              * Merge with higher 32 bits (after reading the full value from the register).
    1773              */
    1774             uint64_t u64Read;
    1775             if (pReg->pfnRead)
    1776             {
    1777                 VBOXSTRICTRC rcStrict = pReg->pfnRead(pDevIns, pThis, off, &u64Read);
    1778                 if (RT_FAILURE(rcStrict))
    1779                 {
    1780                     LogFunc(("Reading off %#x during split write failed! rc=%Rrc\n -> Ignored", off, VBOXSTRICTRC_VAL(rcStrict)));
    1781                     return rcStrict;
    1782                 }
    1783             }
    1784             else
    1785                 u64Read = 0;
    1786 
    1787             uValue = (u64Read & UINT64_C(0xffffffff00000000)) | uValue;
    1788             return pReg->pfnWrite(pDevIns, pThis, off, uValue);
    1789         }
    1790 
    1791         /*
    1792          * Higher 32 bits of the register is being written.
    1793          * Merge with lower 32 bits (after reading the full value from the register).
    1794          */
    1795         Assert(!(off & 3));
    1796         Assert(off & 7);
    1797         Assert(off > 4);
    17981793        uint64_t u64Read;
    17991794        if (pReg->pfnRead)
    18001795        {
    1801             VBOXSTRICTRC rcStrict = pReg->pfnRead(pDevIns, pThis, off - 4, &u64Read);
     1796            VBOXSTRICTRC rcStrict = pReg->pfnRead(pDevIns, pThis, off, &u64Read);
    18021797            if (RT_FAILURE(rcStrict))
    18031798            {
     
    18091804            u64Read = 0;
    18101805
    1811         uValue = (uValue << 32) | (u64Read & UINT64_C(0xffffffff));
    1812         return pReg->pfnWrite(pDevIns, pThis, off - 4, uValue);
     1806        uValue = (u64Read & UINT64_C(0xffffffff00000000)) | uValue;
     1807        return pReg->pfnWrite(pDevIns, pThis, off, uValue);
     1808    }
     1809
     1810    /*
     1811     * Higher 32 bits of the register is being written.
     1812     * Merge with lower 32 bits (after reading the full value from the register).
     1813     */
     1814    Assert(!(off & 3));
     1815    Assert(off & 7);
     1816    Assert(off > 4);
     1817    uint64_t u64Read;
     1818    if (pReg->pfnRead)
     1819    {
     1820        VBOXSTRICTRC rcStrict = pReg->pfnRead(pDevIns, pThis, off - 4, &u64Read);
     1821        if (RT_FAILURE(rcStrict))
     1822        {
     1823            LogFunc(("Reading off %#x during split write failed! rc=%Rrc\n -> Ignored", off, VBOXSTRICTRC_VAL(rcStrict)));
     1824            return rcStrict;
     1825        }
    18131826    }
    18141827    else
    1815         LogFunc(("Writing reserved or read-only register off=%#x (cb=%u) with %#RX64 -> Ignored\n", off, cb, uValue));
    1816 
    1817     return VINF_SUCCESS;
     1828        u64Read = 0;
     1829
     1830    uValue = (uValue << 32) | (u64Read & UINT64_C(0xffffffff));
     1831    return pReg->pfnWrite(pDevIns, pThis, off - 4, uValue);
    18181832#endif
    18191833}
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