VirtualBox

Ignore:
Timestamp:
Mar 5, 2025 9:04:20 AM (7 weeks ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
167821
Message:

VMM/GIC: bugref:10404 Combine highest priorit pending interrupt gathering into a single function.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/GICAll.cpp

    r108443 r108447  
    18131813
    18141814
     1815#if 1
     1816/**
     1817 * Gets the highest priority pending interrupt that can be signalled to the PE.
     1818 *
     1819 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT if no interrupt
     1820 *          is pending or not in a state to be signalled to the PE.
     1821 * @param   pGicDev     The GIC distributor state.
     1822 * @param   pGicCpu     The GIC redistributor and CPU interface state.
     1823 * @param   fGroup0     Whether to consider group 0 interrupts.
     1824 * @param   fGroup1     Whether to consider group 1 interrupts.
     1825 * @param   pidxIntr    Where to store the distributor interrupt index for the
     1826 *                      returned interrupt ID. UINT16_MAX if this function returns
     1827 *                      GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT. Optional, can be
     1828 *                      NULL.
     1829 * @param   pbPriority  Where to store the priority of the returned interrupt ID.
     1830 *                      GIC_IDLE_PRIORITY if this function returns
     1831 *                      GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT.
     1832 */
     1833static uint16_t gicGetHighestPrioPendingIntrEx(PCGICDEV pGicDev, PCGICCPU pGicCpu, bool fGroup0, bool fGroup1,
     1834                                               uint16_t *pidxIntr, uint8_t *pbPriority)
     1835{
     1836#define GIC_DIST_INTR_COUNT     RT_ELEMENTS(pGicDev->bmIntrPending)
     1837#define GIC_REDIST_INTR_COUNT   RT_ELEMENTS(pGicCpu->bmIntrPending)
     1838
     1839    /*
     1840     * Collect interrupts that are pending, enabled and inactive.
     1841     * Discard interrupts if the group they belong to is disabled.
     1842     */
     1843    uint32_t bmIntrPending[GIC_REDIST_INTR_COUNT + GIC_DIST_INTR_COUNT];
     1844    for (uint16_t i = 0; i < GIC_REDIST_INTR_COUNT; i++)
     1845    {
     1846        bmIntrPending[i] = (pGicCpu->bmIntrPending[i] & pGicCpu->bmIntrEnabled[i]) & ~pGicCpu->bmIntrActive[i];
     1847        if (!fGroup1)
     1848            bmIntrPending[i] &= ~pGicCpu->bmIntrGroup[i];
     1849        if (!fGroup0)
     1850            bmIntrPending[i] &= pGicCpu->bmIntrGroup[i];
     1851    }
     1852    for (uint16_t i = 0; i < GIC_DIST_INTR_COUNT; i++)
     1853    {
     1854        uint16_t const idxPending = i + GIC_REDIST_INTR_COUNT;
     1855        bmIntrPending[idxPending] = (pGicDev->bmIntrPending[i] & pGicDev->bmIntrEnabled[i]) & ~pGicDev->bmIntrActive[i];
     1856        if (!fGroup1)
     1857            bmIntrPending[idxPending] &= ~pGicDev->bmIntrGroup[i];
     1858        if (!fGroup0)
     1859            bmIntrPending[idxPending] &= pGicDev->bmIntrGroup[i];
     1860    }
     1861
     1862    /*
     1863     * Among the collected interrupts, pick the one with the highest, non-idle priority.
     1864     */
     1865    uint16_t uIntId     = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
     1866    uint16_t idxHighest = UINT16_MAX;
     1867    uint8_t  uPriority  = GIC_IDLE_PRIORITY;
     1868    /* Redistributor. */
     1869    {
     1870        const void    *pvIntrs = &bmIntrPending[0];
     1871        uint32_t const cIntrs  = sizeof(pGicCpu->bmIntrPending) * 8; AssertCompile(!(cIntrs % 32));
     1872        int32_t        idxIntr = ASMBitFirstSet(pvIntrs, cIntrs);
     1873        if (idxIntr >= 0)
     1874        {
     1875            do
     1876            {
     1877                if (pGicCpu->abIntrPriority[idxIntr] < uPriority)
     1878                {
     1879                    idxHighest = (uint16_t)idxIntr;
     1880                    uPriority  = pGicCpu->abIntrPriority[idxIntr];
     1881                }
     1882                idxIntr = ASMBitNextSet(pvIntrs, cIntrs, idxIntr);
     1883            } while (idxIntr != -1);
     1884            if (uPriority != GIC_IDLE_PRIORITY)
     1885                uIntId = gicReDistGetIntIdFromIndex(idxHighest);
     1886        }
     1887    }
     1888    /* Distributor. */
     1889    {
     1890        const void    *pvIntrs = &bmIntrPending[GIC_REDIST_INTR_COUNT];
     1891        uint32_t const cIntrs  = sizeof(pGicDev->bmIntrPending) * 8; AssertCompile(!(cIntrs % 32));
     1892        int32_t        idxIntr = ASMBitFirstSet(pvIntrs, cIntrs);
     1893        if (idxIntr >= 0)
     1894        {
     1895            do
     1896            {
     1897                if (pGicDev->abIntrPriority[idxIntr] < uPriority)
     1898                {
     1899                    idxHighest = (uint16_t)idxIntr;
     1900                    uPriority  = pGicDev->abIntrPriority[idxIntr];
     1901                }
     1902                idxIntr = ASMBitNextSet(pvIntrs, cIntrs, idxIntr);
     1903            } while (idxIntr != -1);
     1904            if (uPriority != GIC_IDLE_PRIORITY)
     1905                uIntId = gicDistGetIntIdFromIndex(idxHighest);
     1906        }
     1907    }
     1908
     1909    /* Sanity check if the interrupt ID is within known ranges. */
     1910    Assert(   GIC_IS_INTR_SGI_OR_PPI(uIntId)
     1911           || GIC_IS_INTR_EXT_PPI(uIntId)
     1912           || GIC_IS_INTR_SPI(uIntId)
     1913           || GIC_IS_INTR_EXT_PPI(uIntId)
     1914           || GIC_IS_INTR_EXT_SPI(uIntId)
     1915           || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
     1916    /* Ensure that if no interrupt is pending, the idle priority is returned. */
     1917    Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || uPriority == GIC_IDLE_PRIORITY);
     1918
     1919    if (pbPriority)
     1920        *pbPriority = uPriority;
     1921    if (pidxIntr)
     1922        *pidxIntr = idxHighest;
     1923
     1924    LogFlowFunc(("uIntId=%u [idxHighest=%u uPriority=%u]\n", uIntId, idxHighest, uPriority));
     1925    return uIntId;
     1926
     1927#undef GIC_DIST_INTR_COUNT
     1928#undef GIC_REDIST_INTR_COUNT
     1929}
     1930#else
    18151931/**
    18161932 * Gets the highest priority pending interrupt that can be signalled to the PE.
     
    18531969    return uIntId;
    18541970}
     1971#endif
    18551972
    18561973
     
    33803497#else
    33813498            AssertReleaseFailed();
    3382             *pu64Value = gicGetHighestPrioPendingIntr(pVCpu, pGicDev, false /*fGroup0*/, true /*fGroup1*/);
     3499            *pu64Value = gicGetHighestPrioPendingIntrEx(pGicDev, pGicCpu, false /*fGroup0*/, true /*fGroup1*/, NULL /*pidxIntr*/,
     3500                                                        NULL /*pbPriority*/);
    33833501#endif
    33843502            break;
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette