VirtualBox

Changeset 99885 in vbox for trunk


Ignore:
Timestamp:
May 22, 2023 10:31:37 AM (20 months ago)
Author:
vboxsync
Message:

VMM/GIC: Updates to the emulation implementation, some basic SPI interrupt support, bugref:10404

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

Legend:

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

    r99737 r99885  
    134134
    135135
    136 /**
    137  * Updates the internal IRQ state and sets or clears the appropirate force action flags.
    138  *
    139  * @returns Strict VBox status code.
    140  * @param   pThis           The GIC re-distributor state for the associated vCPU.
    141  * @param   pVCpu           The cross context virtual CPU structure.
    142  */
    143 static VBOXSTRICTRC gicReDistUpdateIrqState(PGICCPU pThis, PVMCPUCC pVCpu)
     136DECLINLINE(void) gicUpdateInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
     137{
     138    if (fIrq || fFiq)
     139        gicSetInterruptFF(pVCpu, fIrq, fFiq);
     140
     141    if (!fIrq || !fFiq)
     142        gicClearInterruptFF(pVCpu, !fIrq, !fFiq);
     143}
     144
     145
     146DECLINLINE(void) gicReDistHasIrqPending(PGICCPU pThis, bool *pfIrq, bool *pfFiq)
    144147{
    145148    /* Read the interrupt state. */
     
    156159    {
    157160        /* Determine whether we have to assert the IRQ or FIQ line. */
    158         bool fIrq = RT_BOOL(bmIntForward & u32RegIGrp0) && fIrqGrp1Enabled;
    159         bool fFiq = RT_BOOL(bmIntForward & ~u32RegIGrp0) && fIrqGrp0Enabled;
    160 
    161         if (fIrq || fFiq)
    162             gicSetInterruptFF(pVCpu, fIrq, fFiq);
    163 
    164         if (!fIrq || !fFiq)
    165             gicClearInterruptFF(pVCpu, !fIrq, !fFiq);
     161        *pfIrq = RT_BOOL(bmIntForward & u32RegIGrp0) && fIrqGrp1Enabled;
     162        *pfFiq = RT_BOOL(bmIntForward & ~u32RegIGrp0) && fIrqGrp0Enabled;
    166163    }
    167164    else
    168         gicClearInterruptFF(pVCpu, true /*fIrq*/, true /*fFiq*/);
    169 
     165    {
     166        *pfIrq = false;
     167        *pfFiq = false;
     168    }
     169}
     170
     171
     172DECLINLINE(void) gicDistHasIrqPendingForVCpu(PGICDEV pThis, bool *pfIrq, bool *pfFiq)
     173{
     174    /* Read the interrupt state. */
     175    uint32_t u32RegIGrp0  = ASMAtomicReadU32(&pThis->u32RegIGrp0);
     176    uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
     177    uint32_t bmIntPending = ASMAtomicReadU32(&pThis->bmIntPending);
     178    uint32_t bmIntActive  = ASMAtomicReadU32(&pThis->bmIntActive);
     179    bool fIrqGrp0Enabled  = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled);
     180    bool fIrqGrp1Enabled  = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled);
     181
     182    /* Is anything enabled at all? */
     183    uint32_t bmIntForward = (bmIntPending & bmIntEnabled) & ~bmIntActive; /* Exclude the currently active interrupt. */
     184    if (bmIntForward)
     185    {
     186        /* Determine whether we have to assert the IRQ or FIQ line. */
     187        *pfIrq = RT_BOOL(bmIntForward & u32RegIGrp0) && fIrqGrp1Enabled;
     188        *pfFiq = RT_BOOL(bmIntForward & ~u32RegIGrp0) && fIrqGrp0Enabled;
     189    }
     190    else
     191    {
     192        *pfIrq = false;
     193        *pfFiq = false;
     194    }
     195}
     196
     197
     198/**
     199 * Updates the internal IRQ state and sets or clears the appropirate force action flags.
     200 *
     201 * @returns Strict VBox status code.
     202 * @param   pThis           The GIC re-distributor state for the associated vCPU.
     203 * @param   pVCpu           The cross context virtual CPU structure.
     204 */
     205static VBOXSTRICTRC gicReDistUpdateIrqState(PGICCPU pThis, PVMCPUCC pVCpu)
     206{
     207    bool fIrq, fFiq;
     208    gicReDistHasIrqPending(pThis, &fIrq, &fFiq);
     209
     210    PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
     211    PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
     212    bool fIrqDist, fFiqDist;
     213    gicDistHasIrqPendingForVCpu(pGicDev, &fIrqDist, &fFiqDist);
     214    fIrq |= fIrqDist;
     215    fFiq |= fFiqDist;
     216
     217    gicUpdateInterruptFF(pVCpu, fIrq, fFiq);
     218    return VINF_SUCCESS;
     219}
     220
     221
     222/**
     223 * Updates the internal IRQ state of the distributor and sets or clears the appropirate force action flags.
     224 *
     225 * @returns Strict VBox status code.
     226 * @param   pVM             The cross context VM state.
     227 * @param   pThis           The GIC distributor state.
     228 */
     229static VBOXSTRICTRC gicDistUpdateIrqState(PVMCC pVM, PGICDEV pThis)
     230{
     231    PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[0]; /** @todo SMP */
     232
     233    bool fIrq, fFiq;
     234    gicReDistHasIrqPending(VMCPU_TO_GICCPU(pVCpu), &fIrq, &fFiq);
     235
     236    bool fIrqDist, fFiqDist;
     237    gicDistHasIrqPendingForVCpu(pThis, &fIrqDist, &fFiqDist);
     238    fIrq |= fIrqDist;
     239    fFiq |= fFiqDist;
     240
     241    gicUpdateInterruptFF(pVCpu, fIrq, fFiq);
    170242    return VINF_SUCCESS;
    171243}
     
    205277DECLINLINE(VBOXSTRICTRC) gicDistRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
    206278{
    207     VMCPU_ASSERT_EMT(pVCpu);
    208     RT_NOREF(pDevIns, pVCpu, offReg);
     279    VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
     280    PGICDEV pThis  = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
    209281
    210282    switch (offReg)
    211283    {
     284        case GIC_DIST_REG_CTLR_OFF:
     285            *puValue =   (ASMAtomicReadBool(&pThis->fIrqGrp0Enabled) ? GIC_DIST_REG_CTRL_ENABLE_GRP0 : 0)
     286                       | (ASMAtomicReadBool(&pThis->fIrqGrp1Enabled) ? GIC_DIST_REG_CTRL_ENABLE_GRP1_NS : 0);
     287            break;
    212288        case GIC_DIST_REG_TYPER_OFF:
    213289            *puValue =   GIC_DIST_REG_TYPER_NUM_ITLINES_SET(1)  /** @todo 32 SPIs for now. */
     
    220296                       | GIC_DIST_REG_TYPER_IDBITS_SET(16);
    221297            break;
     298        case GIC_DIST_REG_STATUSR_OFF:
     299            AssertReleaseFailed();
     300            break;
     301        case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
     302            AssertReleaseFailed();
     303            break;
     304        case GIC_DIST_REG_ISENABLERn_OFF_START + 4: /* Only 32 lines for now. */
     305        case GIC_DIST_REG_ICENABLERn_OFF_START + 4: /* Only 32 lines for now. */
     306            *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
     307            break;
     308        case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
     309            AssertReleaseFailed();
     310            break;
     311        case GIC_DIST_REG_ICPENDRn_OFF_START: /* Only 32 lines for now. */
     312            AssertReleaseFailed();
     313            break;
     314        case GIC_DIST_REG_ISACTIVERn_OFF_START: /* Only 32 lines for now. */
     315            AssertReleaseFailed();
     316            break;
     317        case GIC_DIST_REG_ICACTIVERn_OFF_START: /* Only 32 lines for now. */
     318            AssertReleaseFailed();
     319            break;
     320        case GIC_DIST_REG_IPRIORITYn_OFF_START + 32: /* Only 32 lines for now. */
     321        {
     322            /* Figure out the register which is written. */
     323            uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START - 32;
     324            Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
     325
     326            uint32_t u32Value = 0;
     327            for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
     328                u32Value |= pThis->abIntPriority[i] << ((i - idxPrio) * 8);
     329
     330            *puValue = u32Value;
     331            break;
     332        }
     333        case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
     334            AssertReleaseFailed();
     335            break;
     336        case GIC_DIST_REG_ICFGRn_OFF_START: /* Only 32 lines for now. */
     337            AssertReleaseFailed();
     338            break;
     339        case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
     340            AssertReleaseFailed();
     341            break;
     342        case GIC_DIST_REG_NSACRn_OFF_START: /* Only 32 lines for now. */
     343            AssertReleaseFailed();
     344            break;
     345        case GIC_DIST_REG_SGIR_OFF:
     346            AssertReleaseFailed();
     347            break;
     348        case GIC_DIST_REG_CPENDSGIRn_OFF_START:
     349            AssertReleaseFailed();
     350            break;
     351        case GIC_DIST_REG_SPENDSGIRn_OFF_START:
     352            AssertReleaseFailed();
     353            break;
     354        case GIC_DIST_REG_INMIn_OFF_START:
     355            AssertReleaseFailed();
     356            break;
     357        case GIC_DIST_REG_IROUTERn_OFF_START: /* Only 32 lines for now. */
     358            *puValue = 0; /** @todo */
     359            break;
    222360        case GIC_DIST_REG_PIDR2_OFF:
    223361            *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(GIC_REDIST_REG_PIDR2_ARCH_REV_GICV3);
     
    225363        case GIC_DIST_REG_IIDR_OFF:
    226364        case GIC_DIST_REG_TYPER2_OFF:
     365            *puValue = 0;
     366            break;
    227367        default:
    228368            *puValue = 0;
     
    243383DECLINLINE(VBOXSTRICTRC) gicDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
    244384{
    245     VMCPU_ASSERT_EMT(pVCpu);
    246     RT_NOREF(pDevIns, pVCpu, offReg, uValue);
     385    VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
     386    PGICDEV pThis  = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
     387    PVMCC    pVM   = PDMDevHlpGetVM(pDevIns);
    247388
    248389    VBOXSTRICTRC rcStrict = VINF_SUCCESS;
     390    switch (offReg)
     391    {
     392        case GIC_DIST_REG_CTLR_OFF:
     393            ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP0));
     394            ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP1_NS));
     395            rcStrict = gicDistUpdateIrqState(pVM, pThis);
     396            break;
     397        case GIC_DIST_REG_STATUSR_OFF:
     398            AssertReleaseFailed();
     399            break;
     400        case GIC_DIST_REG_SETSPI_NSR_OFF:
     401            AssertReleaseFailed();
     402            break;
     403        case GIC_DIST_REG_CLRSPI_NSR_OFF:
     404            AssertReleaseFailed();
     405            break;
     406        case GIC_DIST_REG_SETSPI_SR_OFF:
     407            AssertReleaseFailed();
     408            break;
     409        case GIC_DIST_REG_CLRSPI_SR_OFF:
     410            AssertReleaseFailed();
     411            break;
     412        case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
     413            AssertReleaseFailed();
     414            break;
     415        case GIC_DIST_REG_IGROUPRn_OFF_START + 4: /* Only 32 lines for now. */
     416            ASMAtomicOrU32(&pThis->u32RegIGrp0, uValue);
     417            rcStrict = gicDistUpdateIrqState(pVM, pThis);
     418            break;
     419        case GIC_DIST_REG_ISENABLERn_OFF_START + 4: /* Only 32 lines for now. */
     420            ASMAtomicOrU32(&pThis->bmIntEnabled, uValue);
     421            rcStrict = gicDistUpdateIrqState(pVM, pThis);
     422            break;
     423        case GIC_DIST_REG_ICENABLERn_OFF_START:
     424            //AssertReleaseFailed();
     425            break;
     426        case GIC_DIST_REG_ICENABLERn_OFF_START + 4: /* Only 32 lines for now. */
     427            ASMAtomicAndU32(&pThis->bmIntEnabled, ~uValue);
     428            rcStrict = gicDistUpdateIrqState(pVM, pThis);
     429            break;
     430        case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
     431            AssertReleaseFailed();
     432            break;
     433        case GIC_DIST_REG_ICPENDRn_OFF_START: /* Only 32 lines for now. */
     434            AssertReleaseFailed();
     435            break;
     436        case GIC_DIST_REG_ISACTIVERn_OFF_START: /* Only 32 lines for now. */
     437            AssertReleaseFailed();
     438            break;
     439        case GIC_DIST_REG_ICACTIVERn_OFF_START + 4: /* Only 32 lines for now. */
     440            ASMAtomicAndU32(&pThis->bmIntActive, ~uValue);
     441            rcStrict = gicDistUpdateIrqState(pVM, pThis);
     442            break;
     443        case GIC_DIST_REG_IPRIORITYn_OFF_START + 32: /* Only 32 lines for now. */
     444        case GIC_DIST_REG_IPRIORITYn_OFF_START + 36:
     445        case GIC_DIST_REG_IPRIORITYn_OFF_START + 40:
     446        case GIC_DIST_REG_IPRIORITYn_OFF_START + 44:
     447        case GIC_DIST_REG_IPRIORITYn_OFF_START + 48:
     448        case GIC_DIST_REG_IPRIORITYn_OFF_START + 52:
     449        case GIC_DIST_REG_IPRIORITYn_OFF_START + 56:
     450        case GIC_DIST_REG_IPRIORITYn_OFF_START + 60:
     451        {
     452            /* Figure out the register whch is written. */
     453            uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START - 32;
     454            Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
     455            for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
     456            {
     457                pThis->abIntPriority[i] = (uint8_t)(uValue & 0xff);
     458                uValue >>= 8;
     459            }
     460            break;
     461        }
     462        case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
     463            AssertReleaseFailed();
     464            break;
     465        case GIC_DIST_REG_ICFGRn_OFF_START + 8: /* Only 32 lines for now. */
     466            ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
     467            break;
     468        case GIC_DIST_REG_ICFGRn_OFF_START+ 12:
     469            ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
     470            break;
     471        case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
     472            AssertReleaseFailed();
     473            break;
     474        case GIC_DIST_REG_NSACRn_OFF_START: /* Only 32 lines for now. */
     475            AssertReleaseFailed();
     476            break;
     477        case GIC_DIST_REG_SGIR_OFF:
     478            AssertReleaseFailed();
     479            break;
     480        case GIC_DIST_REG_CPENDSGIRn_OFF_START:
     481            AssertReleaseFailed();
     482            break;
     483        case GIC_DIST_REG_SPENDSGIRn_OFF_START:
     484            AssertReleaseFailed();
     485            break;
     486        case GIC_DIST_REG_INMIn_OFF_START:
     487            AssertReleaseFailed();
     488            break;
     489        case GIC_DIST_REG_IROUTERn_OFF_START ... GIC_DIST_REG_IROUTERn_OFF_LAST: /* Only 32 lines for now. */
     490            /** @todo Ignored for now, probably make this a MMIO2 region as it begins on 0x6000, see 12.9.22 of the GICv3 architecture
     491             * reference manual. */
     492            break;
     493        default:
     494            //AssertReleaseFailed();
     495            break;
     496    }
     497
    249498    return rcStrict;
    250499}
     
    316565        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 28:
    317566        {
    318             /* Figure out the register whch is written. */
     567            /* Figure out the register which is written. */
    319568            uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START;
    320569            Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
     
    458707    *pu64Value = 0;
    459708    PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
     709    PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
     710    PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
    460711    switch (u32Reg)
    461712    {
     
    529780            }
    530781            else
    531                 *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
     782            {
     783                /** @todo This is wrong as the guest might decide to prioritize PPIs and SPIs differently. */
     784                bmPending = ASMAtomicReadU32(&pGicDev->bmIntPending);
     785                idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
     786                if (idxIntPending > -1)
     787                {
     788                    /* Mark the interrupt as active. */
     789                    ASMAtomicOrU32(&pGicDev->bmIntActive, idxIntPending);
     790                    *pu64Value = idxIntPending + GIC_INTID_RANGE_SPI_START;
     791                }
     792                else
     793                    *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
     794            }
    532795            break;
    533796        }
     
    583846
    584847    PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
     848    PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
     849    PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
    585850    switch (u32Reg)
    586851    {
     
    648913        {
    649914            /* Mark the interrupt as not active anymore, though it might still be pending. */
    650             Assert(u64Value < GIC_INTID_RANGE_SPI_START);
    651             ASMAtomicAndU32(&pThis->bmIntActive, (uint32_t)u64Value);
     915            if (u64Value < GIC_INTID_RANGE_SPI_START)
     916                ASMAtomicAndU32(&pThis->bmIntActive, (uint32_t)u64Value);
     917            else
     918                ASMAtomicAndU32(&pGicDev->bmIntActive, (uint32_t)u64Value);
     919            gicReDistUpdateIrqState(pThis, pVCpu);
    652920            break;
    653921        }
     
    690958VMM_INT_DECL(int) GICSpiSet(PVMCC pVM, uint32_t uIntId, bool fAsserted)
    691959{
    692     RT_NOREF(pVM, uIntId, fAsserted);
    693     AssertReleaseFailed();
    694     return VERR_NOT_IMPLEMENTED;
     960    AssertReturn(uIntId < GIC_SPI_MAX, VERR_INVALID_PARAMETER);
     961
     962    PGIC    pGic   = VM_TO_GIC(pVM);
     963    PGICDEV pThis  = PDMDEVINS_2_DATA(pGic->CTX_SUFF(pDevIns), PGICDEV);
     964
     965    /* Update the interrupts pending state. */
     966    if (fAsserted)
     967        ASMAtomicOrU32(&pThis->bmIntPending, RT_BIT_32(uIntId));
     968    else
     969        ASMAtomicAndU32(&pThis->bmIntPending, ~RT_BIT_32(uIntId));
     970
     971    return VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pThis));
    695972}
    696973
     
    706983VMM_INT_DECL(int) GICPpiSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
    707984{
     985    LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u fAsserted=%RTbool\n",
     986                 pVCpu, pVCpu->idCpu, uIntId, fAsserted));
     987
    708988    AssertReturn(uIntId >= 0 && uIntId <= (GIC_INTID_RANGE_PPI_LAST - GIC_INTID_RANGE_PPI_START), VERR_INVALID_PARAMETER);
    709989    return gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_PPI_START, fAsserted);
  • trunk/src/VBox/VMM/include/GICInternal.h

    r99734 r99885  
    5151#endif
    5252
     53/** Maximum number of SPI interrupts. */
     54#define GIC_SPI_MAX                         32
     55
    5356/**
    5457 * GIC PDM instance data (per-VM).
     
    6063    /** The redistributor MMIO handle. */
    6164    IOMMMIOHANDLE               hMmioReDist;
     65
     66    /** @name SPI disitributor register state.
     67     * @{ */
     68    /** Interrupt Group 0 Register. */
     69    volatile uint32_t           u32RegIGrp0;
     70    /** Interrupt Configuration Register 0. */
     71    volatile uint32_t           u32RegICfg0;
     72    /** Interrupt Configuration Register 1. */
     73    volatile uint32_t           u32RegICfg1;
     74    /** Interrupt enabled bitmap. */
     75    volatile uint32_t           bmIntEnabled;
     76    /** Current interrupt pending state. */
     77    volatile uint32_t           bmIntPending;
     78    /** The current interrupt active state. */
     79    volatile uint32_t           bmIntActive;
     80    /** The interrupt priority for each of the SGI/PPIs */
     81    volatile uint8_t            abIntPriority[GIC_SPI_MAX];
     82
     83    /** Flag whether group 0 interrupts are currently enabled. */
     84    volatile bool               fIrqGrp0Enabled;
     85    /** Flag whether group 1 interrupts are currently enabled. */
     86    volatile bool               fIrqGrp1Enabled;
     87    /** @} */
     88
    6289} GICDEV;
    6390/** Pointer to a GIC device. */
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