VirtualBox

Ignore:
Timestamp:
Mar 7, 2025 7:23:33 AM (6 weeks ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
167846
Message:

VMM/GIC: bugref:10404 Implement honoring group and sub-group interrupt priorities during interrupt preemption.

File:
1 edited

Legend:

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

    r108466 r108470  
    18291829 *                      GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT.
    18301830 */
    1831 static uint16_t gicGetHighestPrioPendingIntrEx(PCGICDEV pGicDev, PCGICCPU pGicCpu, bool fGroup0, bool fGroup1,
    1832                                                uint16_t *pidxIntr, uint8_t *pbPriority)
     1831static uint16_t gicGetHighestPriorityPendingIntrEx(PCGICDEV pGicDev, PCGICCPU pGicCpu, bool fGroup0, bool fGroup1,
     1832                                                   uint16_t *pidxIntr, uint8_t *pbPriority)
    18331833{
    18341834#define GIC_DIST_INTR_COUNT     RT_ELEMENTS(pGicDev->bmIntrPending)
     
    19801980 * @param   fGroup1     Whether to consider group 1 interrupts.
    19811981 */
    1982 static uint16_t gicAckHighestPrioPendingIntr(PGICDEV pGicDev, PVMCPUCC pVCpu, bool fGroup0, bool fGroup1)
     1982static uint16_t gicAckHighestPriorityPendingIntr(PGICDEV pGicDev, PVMCPUCC pVCpu, bool fGroup0, bool fGroup1)
    19831983{
    19841984    Assert(fGroup0 || fGroup1);
    19851985    LogFlowFunc(("fGroup0=%RTbool fGroup1=%RTbool\n", fGroup0, fGroup1));
    19861986
    1987     /* Get highest priority pending interrupt from the distributor. */
    1988     uint8_t   bPriority;
    1989     uint16_t  idxIntr;
    1990     PGICCPU   pGicCpu = VMCPU_TO_GICCPU(pVCpu);
    1991     uint16_t const uIntId = gicGetHighestPrioPendingIntrEx(pGicDev, pGicCpu, fGroup0, fGroup1, &idxIntr, &bPriority);
    1992 
    1993     /* If the priority must be higher than the priority mask for the interrupt to be signalled/acknowledged. */
    1994     if (pGicCpu->bIntrPriorityMask <= bPriority)
    1995         return GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
    1996 
    1997     /* Acknowledge the interrupt. */
     1987    /*
     1988     * Get the pending interrupt with the highest priority for the given group.
     1989     */
     1990    uint8_t  bIntrPriority;
     1991    uint16_t idxIntr;
     1992    PGICCPU  pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     1993    uint16_t const uIntId = gicGetHighestPriorityPendingIntrEx(pGicDev, pGicCpu, fGroup0, fGroup1, &idxIntr, &bIntrPriority);
     1994
    19981995    if (uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT)
    19991996    {
     1997        /*
     1998         * The interrupt priority must be higher than the priority mask of the CPU interface for the
     1999         * interrupt to be signalled/acknowledged. Here, we must NOT use priority grouping when comparing
     2000         * the priority of a pending interrupt with this priority mask (threshold).
     2001         *
     2002         * See ARM GIC spec. 4.8.6 "Priority masking".
     2003         */
     2004        if (bIntrPriority >= pGicCpu->bIntrPriorityMask)
     2005            return GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
     2006
     2007        /*
     2008         * The group priority of the pending interrupt must be higher than that of the running priority.
     2009         * The number of bits for the group priority depends on the the binary point registers.
     2010         * We mask the sub-priority bits and only compare the group priority.
     2011         *
     2012         * When the binary point registers indicates no preemption, we must allow interrupts that have
     2013         * a higher priority than the idle. Hence the two different masks here.
     2014         *
     2015         * See ARM GIC spec. 4.8.3 "Priority grouping".
     2016         * See ARM GIC spec. 4.8.5 "Preemption".
     2017         */
     2018        static uint8_t const s_afGroupPriorityMasks[8]   = { 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00 };
     2019        static uint8_t const s_afRunningPriorityMasks[8] = { 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0xff };
     2020        uint8_t const idxPriorityMask       = (fGroup0 || (pGicCpu->uIccCtlr & ARMV8_ICC_CTLR_EL1_AARCH64_CBPR))
     2021                                            ? pGicCpu->bBinaryPtGroup0 & 7
     2022                                            : pGicCpu->bBinaryPtGroup1 & 7;
     2023        uint8_t const fGroupPriorityMask    = s_afGroupPriorityMasks[idxPriorityMask];
     2024        uint8_t const fRunningPriorityMask  = s_afRunningPriorityMasks[idxPriorityMask];
     2025        uint8_t const bRunningPriority      = pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority];
     2026        uint8_t const bRunningGroupPriority = bRunningPriority & fRunningPriorityMask;
     2027        uint8_t const bIntrGroupPriority    = bIntrPriority    & fGroupPriorityMask;
     2028        if (bIntrGroupPriority >= bRunningGroupPriority)
     2029            return GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
     2030
     2031        /*
     2032         * Acknowledge the interrupt.
     2033         */
    20002034        bool const fIsRedistIntId = GIC_IS_INTR_SGI_OR_PPI(uIntId) || GIC_IS_INTR_EXT_PPI(uIntId);
    20012035        if (fIsRedistIntId)
    20022036        {
    2003             /** @todo Check if the interrupt has sufficient priority (preemption level
    2004              *        checking?). */
    2005 
    20062037            /* Mark the interrupt as active. */
    20072038            AssertMsg(idxIntr < sizeof(pGicCpu->bmIntrActive) * 8, ("idxIntr=%u\n", idxIntr));
     
    20132044            LogFlowFunc(("Dropping interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
    20142045                         pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority],
    2015                          bPriority,
     2046                         bIntrPriority,
    20162047                         pGicCpu->idxRunningPriority, pGicCpu->idxRunningPriority + 1));
    2017             pGicCpu->abRunningPriorities[++pGicCpu->idxRunningPriority] = bPriority;
     2048            pGicCpu->abRunningPriorities[++pGicCpu->idxRunningPriority] = bIntrPriority;
    20182049
    20192050            /* If it is an edge-triggered interrupt, mark it as no longer pending. */
     
    20232054                ASMBitClear(&pGicCpu->bmIntrPending[0], idxIntr);
    20242055
    2025             /* Update the redistributor IRQ state to reflect change in active interrupt. */
     2056            /* Update the redistributor IRQ state to reflect change to the active interrupt. */
    20262057            gicReDistUpdateIrqState(pGicDev, pVCpu);
    20272058        }
    20282059        else
    20292060        {
    2030             /** @todo Check if the interrupt has sufficient priority (preemption level
    2031              *        checking?). */
    2032 
    20332061            /* Sanity check if the interrupt ID belongs to the distirbutor. */
    20342062            Assert(GIC_IS_INTR_SPI(uIntId) || GIC_IS_INTR_EXT_SPI(uIntId));
     
    20432071            LogFlowFunc(("Dropping interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
    20442072                         pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority],
    2045                          bPriority,
     2073                         bIntrPriority,
    20462074                         pGicCpu->idxRunningPriority, pGicCpu->idxRunningPriority + 1));
    2047             pGicCpu->abRunningPriorities[++pGicCpu->idxRunningPriority] = bPriority;
     2075            pGicCpu->abRunningPriorities[++pGicCpu->idxRunningPriority] = bIntrPriority;
    20482076
    20492077            /* If it is an edge-triggered interrupt, mark it as no longer pending. */
     
    20532081                ASMBitClear(&pGicDev->bmIntrPending[0], idxIntr);
    20542082
    2055             /* Update the distributor IRQ state to reflect change in active interrupt. */
     2083            /* Update the distributor IRQ state to reflect change to the active interrupt. */
    20562084            gicDistUpdateIrqState(pVCpu->CTX_SUFF(pVM), pGicDev);
    20572085        }
    20582086    }
    20592087    else
    2060         Assert(bPriority == GIC_IDLE_PRIORITY);
     2088        Assert(bIntrPriority == GIC_IDLE_PRIORITY);
    20612089
    20622090    LogFlowFunc(("uIntId=%u\n", uIntId));
     
    34623490            }
    34633491#else
    3464             *pu64Value = gicAckHighestPrioPendingIntr(pGicDev, pVCpu, false /*fGroup0*/, true /*fGroup1*/);
     3492            *pu64Value = gicAckHighestPriorityPendingIntr(pGicDev, pVCpu, false /*fGroup0*/, true /*fGroup1*/);
    34653493#endif
    34663494            break;
     
    34933521#else
    34943522            AssertReleaseFailed();
    3495             *pu64Value = gicGetHighestPrioPendingIntrEx(pGicDev, pGicCpu, false /*fGroup0*/, true /*fGroup1*/, NULL /*pidxIntr*/,
    3496                                                         NULL /*pbPriority*/);
     3523            *pu64Value = gicGetHighestPriorityPendingIntrEx(pGicDev, pGicCpu, false /*fGroup0*/, true /*fGroup1*/,
     3524                                                            NULL /*pidxIntr*/, NULL /*pbPriority*/);
    34973525#endif
    34983526            break;
     
    38373865    /* The binary point register are undefined on reset, initialized
    38383866       with arbitrarily chosen values in our implementation. */
    3839     pGicCpu->bBinaryPtGroup0 = 3;
    3840     pGicCpu->bBinaryPtGroup1 = 3;
     3867    pGicCpu->bBinaryPtGroup0 = 0;
     3868    pGicCpu->bBinaryPtGroup1 = 0;
    38413869}
    38423870
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