VirtualBox

Ignore:
Timestamp:
Mar 4, 2025 8:21:36 AM (7 weeks ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
167801
Message:

VMM/GIC: bugref:10404 Extend the interrupt lines to the full extent supported by the GIC spec.
Added range-selector support while broadcasting SGIs.
Added highest priority interrupt calculation (still not complete, binary-point support is still a todo)
Other miscellaneous changes related to the above.

File:
1 edited

Legend:

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

    r107984 r108427  
    4444
    4545/*********************************************************************************************************************************
    46 *   Internal Functions                                                                                                           *
     46*   Defined Constants And Macros                                                                                                 *
    4747*********************************************************************************************************************************/
    48 
    49 
    50 /*********************************************************************************************************************************
    51 *   Global Variables                                                                                                             *
    52 *********************************************************************************************************************************/
     48#define GIC_IS_INTR_SGI(a_uIntId)           (a_uIntId - GIC_INTID_RANGE_SGI_START < GIC_INTID_SGI_RANGE_SIZE)
     49#define GIC_IS_INTR_PPI(a_uIntId)           (a_uIntId - GIC_INTID_RANGE_PPI_START < GIC_INTID_PPI_RANGE_SIZE)
     50#define GIC_IS_INTR_SGI_OR_PPI(a_uIntId)    (a_uIntId - GIC_INTID_RANGE_SGI_START < GIC_INTID_PPI_RANGE_SIZE)
     51#define GIC_IS_INTR_SPI(a_uIntId)           (a_uIntId - GIC_INTID_RANGE_SPI_START < GIC_INTID_SPI_RANGE_SIZE)
     52#define GIC_IS_INTR_SPECIAL(a_uIntId)       (a_uIntId - GIC_INTID_RANGE_SPECIAL_START < GIC_INTID_EXT_PPI_RANGE_SIZE)
     53#define GIC_IS_INTR_EXT_PPI(a_uIntId)       (a_uIntId - GIC_INTID_RANGE_EXT_PPI_START < GIC_INTID_EXT_PPI_RANGE_SIZE)
     54#define GIC_IS_INTR_EXT_SPI(a_uIntId)       (a_uIntId - GIC_INTID_RANGE_EXT_SPI_START < GIC_INTID_EXT_SPI_RANGE_SIZE)
     55
    5356
    5457#ifdef LOG_ENABLED
    5558/**
    56  * Returns a human readable string of the given exception class.
    57  *
    58  * @returns Pointer to the string matching the given EC.
    59  * @param   u32Ec           The exception class to return the string for.
    60  */
    61 static const char *gicIccRegisterStringify(uint32_t u32Reg)
     59 * Gets the description of a CPU interface register.
     60 *
     61 * @returns The description.
     62 * @param   u32Reg  The CPU interface register offset.
     63 */
     64static const char *gicIccGetRegDescription(uint32_t u32Reg)
    6265{
    6366    switch (u32Reg)
     
    97100    return "<UNKNOWN>";
    98101}
     102
     103
     104/**
     105 * Gets the description of a distributor register given it's register offset.
     106 *
     107 * @returns The register description.
     108 * @param   offReg  The distributor register offset.
     109 */
     110static const char *gicDistGetRegDescription(uint16_t offReg)
     111{
     112   if (offReg - GIC_DIST_REG_IGROUPRn_OFF_START     < GIC_DIST_REG_IGROUPRn_RANGE_SIZE)     return "GICD_IGROUPRn";
     113   if (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START    < GIC_DIST_REG_IGROUPRnE_RANGE_SIZE)    return "GICD_IGROUPRnE";
     114   if (offReg - GIC_DIST_REG_IROUTERn_OFF_START     < GIC_DIST_REG_IROUTERn_RANGE_SIZE)     return "GICD_IROUTERn";
     115   if (offReg - GIC_DIST_REG_IROUTERnE_OFF_START    < GIC_DIST_REG_IROUTERnE_RANGE_SIZE)    return "GICD_IROUTERnE";
     116   if (offReg - GIC_DIST_REG_ISENABLERn_OFF_START   < GIC_DIST_REG_ISENABLERn_RANGE_SIZE)   return "GICD_ISENABLERn";
     117   if (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START  < GIC_DIST_REG_ISENABLERnE_RANGE_SIZE)  return "GICD_ISENABLERnE";
     118   if (offReg - GIC_DIST_REG_ICENABLERn_OFF_START   < GIC_DIST_REG_ICENABLERn_RANGE_SIZE)   return "GICD_ICENABLERn";
     119   if (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START  < GIC_DIST_REG_ICENABLERnE_RANGE_SIZE)  return "GICD_ICENABLERnE";
     120   if (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START   < GIC_DIST_REG_ISACTIVERn_RANGE_SIZE)   return "GICD_ISACTIVERn";
     121   if (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START  < GIC_DIST_REG_ISACTIVERnE_RANGE_SIZE)  return "GICD_ISACTIVERnE";
     122   if (offReg - GIC_DIST_REG_ICACTIVERn_OFF_START   < GIC_DIST_REG_ICACTIVERn_RANGE_SIZE)   return "GICD_ICACTIVERn";
     123   if (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START  < GIC_DIST_REG_ICACTIVERnE_RANGE_SIZE)  return "GICD_ICACTIVERnE";
     124   if (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START  < GIC_DIST_REG_IPRIORITYRn_RANGE_SIZE)  return "GICD_IPRIORITYRn";
     125   if (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START < GIC_DIST_REG_IPRIORITYRnE_RANGE_SIZE) return "GICD_IPRIORITYRnE";
     126   if (offReg - GIC_DIST_REG_ISPENDRn_OFF_START     < GIC_DIST_REG_ISPENDRn_RANGE_SIZE)     return "GICD_ISPENDRn";
     127   if (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START    < GIC_DIST_REG_ISPENDRnE_RANGE_SIZE)    return "GICD_ISPENDRnE";
     128   if (offReg - GIC_DIST_REG_ICPENDRn_OFF_START     < GIC_DIST_REG_ICPENDRn_RANGE_SIZE)     return "GICD_ICPENDRn";
     129   if (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START    < GIC_DIST_REG_ICPENDRnE_RANGE_SIZE)    return "GICD_ICPENDRnE";
     130   if (offReg - GIC_DIST_REG_ICFGRn_OFF_START       < GIC_DIST_REG_ICFGRn_RANGE_SIZE)       return "GICD_ICFGRn";
     131   if (offReg - GIC_DIST_REG_ICFGRnE_OFF_START      < GIC_DIST_REG_ICFGRnE_RANGE_SIZE)      return "GICD_ICFGRnE";
     132   switch (offReg)
     133   {
     134       case GIC_DIST_REG_CTLR_OFF:             return "GICD_CTLR";
     135       case GIC_DIST_REG_TYPER_OFF:            return "GICD_TYPER";
     136       case GIC_DIST_REG_STATUSR_OFF:          return "GICD_STATUSR";
     137       case GIC_DIST_REG_ITARGETSRn_OFF_START: return "GICD_ITARGETSRn";
     138       case GIC_DIST_REG_IGRPMODRn_OFF_START:  return "GICD_IGRPMODRn";
     139       case GIC_DIST_REG_NSACRn_OFF_START:     return "GICD_NSACRn";
     140       case GIC_DIST_REG_SGIR_OFF:             return "GICD_SGIR";
     141       case GIC_DIST_REG_CPENDSGIRn_OFF_START: return "GICD_CSPENDSGIRn";
     142       case GIC_DIST_REG_SPENDSGIRn_OFF_START: return "GICD_SPENDSGIRn";
     143       case GIC_DIST_REG_INMIn_OFF_START:      return "GICD_INMIn";
     144       case GIC_DIST_REG_PIDR2_OFF:            return "GICD_PIDR2";
     145       case GIC_DIST_REG_IIDR_OFF:             return "GICD_IIDR";
     146       case GIC_DIST_REG_TYPER2_OFF:           return "GICD_TYPER2";
     147       default:
     148           return "<UNKNOWN>";
     149   }
     150}
     151
     152
     153/**
     154 * Gets the description of a redistributor register given it's register offset.
     155 *
     156 * @returns The register description.
     157 * @param   offReg  The redistributor register offset.
     158 */
     159static const char *gicReDistGetRegDescription(uint16_t offReg)
     160{
     161    if (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF          < GIC_REDIST_SGI_PPI_REG_IGROUPRnE_RANGE_SIZE)    return "GICR_IGROUPn";
     162    if (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF        < GIC_REDIST_SGI_PPI_REG_ISENABLERnE_RANGE_SIZE)  return "GICR_ISENABLERn";
     163    if (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF        < GIC_REDIST_SGI_PPI_REG_ICENABLERnE_RANGE_SIZE)  return "GICR_ICENABLERn";
     164    if (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF        < GIC_REDIST_SGI_PPI_REG_ISACTIVERnE_RANGE_SIZE)  return "GICR_ISACTIVERn";
     165    if (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF        < GIC_REDIST_SGI_PPI_REG_ICACTIVERnE_RANGE_SIZE)  return "GICR_ICACTIVERn";
     166    if (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF          < GIC_REDIST_SGI_PPI_REG_ISPENDRnE_RANGE_SIZE)    return "GICR_ISPENDRn";
     167    if (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF          < GIC_REDIST_SGI_PPI_REG_ICPENDRnE_RANGE_SIZE)    return "GICR_ICPENDRn";
     168    if (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START < GIC_REDIST_SGI_PPI_REG_IPRIORITYRnE_RANGE_SIZE) return "GICR_IPREIORITYn";
     169    if (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF            < GIC_REDIST_SGI_PPI_REG_ICFGRnE_RANGE_SIZE)      return "GICR_ICFGRn";
     170    switch (offReg)
     171    {
     172        case GIC_REDIST_REG_TYPER_OFF:          return "GICR_TYPER";
     173        case GIC_REDIST_REG_IIDR_OFF:           return "GICR_IIDR";
     174        case GIC_REDIST_REG_TYPER_AFFINITY_OFF: return "GICR_TYPER_AFF";
     175        case GIC_REDIST_REG_PIDR2_OFF:          return "GICR_PIDR2";
     176        default:
     177            return "<UNKNOWN>";
     178    }
     179}
    99180#endif
     181
     182
     183/**
     184 * Gets the interrupt ID given a distributor interrupt index.
     185 *
     186 * @returns The interrupt ID.
     187 * @param   idxIntr     The distributor interrupt index.
     188 * @remarks A distributor interrupt is an interrupt type that belong in the
     189 *          distributor (e.g. SPIs, extended SPIs).
     190 */
     191DECLHIDDEN(uint16_t) gicDistGetIntIdFromIndex(uint16_t idxIntr)
     192{
     193    /*
     194     * Distributor interrupts bits to interrupt ID mapping:
     195     * +--------------------------------------------------------+
     196     * | Range (incl) | SGI    | PPI    | SPI      | Ext SPI    |
     197     * |--------------+--------+--------+----------+------------|
     198     * | Bit          | 0..15  | 16..31 | 32..1023 | 1024..2047 |
     199     * | Int Id       | 0..15  | 16..31 | 32..1023 | 4096..5119 |
     200     * +--------------------------------------------------------+
     201     */
     202    uint16_t uIntId;
     203    /* SGIs, PPIs, SPIs and specials. */
     204    if (idxIntr < 1024)
     205        uIntId = idxIntr;
     206    /* Extended SPIs. */
     207    else if (idxIntr < 2048)
     208        uIntId = GIC_INTID_RANGE_EXT_SPI_START + idxIntr - 1024;
     209    else
     210    {
     211        uIntId = 0;
     212        AssertReleaseFailed();
     213    }
     214    Assert(   GIC_IS_INTR_SGI_OR_PPI(uIntId)
     215           || GIC_IS_INTR_SPI(uIntId)
     216           || GIC_IS_INTR_SPECIAL(uIntId)
     217           || GIC_IS_INTR_EXT_SPI(uIntId));
     218    return uIntId;
     219}
     220
     221
     222/**
     223 * Gets the distributor interrupt index given an interrupt ID.
     224 *
     225 * @returns The distributor interrupt index.
     226 * @param   uIntId  The interrupt ID.
     227 * @remarks A distributor interrupt is an interrupt type that belong in the
     228 *          distributor (e.g. SPIs, extended SPIs).
     229 */
     230static uint16_t gicDistGetIndexFromIntId(uint16_t uIntId)
     231{
     232    uint16_t idxIntr;
     233    /* SGIs, PPIs, SPIs and specials. */
     234    if (uIntId <= GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT)
     235        idxIntr = uIntId;
     236    /* Extended SPIs. */
     237    else if (uIntId - GIC_INTID_RANGE_EXT_SPI_START < GIC_INTID_EXT_SPI_RANGE_SIZE)
     238        idxIntr = 1024 + uIntId - GIC_INTID_RANGE_EXT_SPI_START;
     239    else
     240    {
     241        idxIntr = 0;
     242        AssertReleaseFailed();
     243    }
     244    Assert(idxIntr < sizeof(GICDEV::bmIntrPending) * 8);
     245    return idxIntr;
     246}
     247
     248
     249/**
     250 * Gets the interrupt ID given a redistributor interrupt index.
     251 *
     252 * @returns The interrupt ID.
     253 * @param   idxIntr     The redistributor interrupt index.
     254 * @remarks A redistributor interrupt is an interrupt type that belong in the
     255 *          redistributor (e.g. SGIs, PPIs, extended PPIs).
     256 */
     257DECLHIDDEN(uint16_t) gicReDistGetIntIdFromIndex(uint16_t idxIntr)
     258{
     259    /*
     260     * Redistributor interrupts bits to interrupt ID mapping:
     261     * +---------------------------------------------+
     262     * | Range (incl) | SGI    | PPI    | Ext PPI    |
     263     * +---------------------------------------------+
     264     * | Bit          | 0..15  | 16..31 |   32..95   |
     265     * | Int Id       | 0..15  | 16..31 | 1056..1119 |
     266     * +---------------------------------------------+
     267     */
     268    uint16_t uIntId;
     269    /* SGIs and PPIs. */
     270    if (idxIntr < 32)
     271        uIntId = idxIntr;
     272    /* Extended PPIs. */
     273    else if (idxIntr < 96)
     274        uIntId = GIC_INTID_RANGE_PPI_LAST + 1 + idxIntr - GIC_INTID_RANGE_EXT_PPI_START;
     275    else
     276    {
     277        uIntId = 0;
     278        AssertReleaseFailed();
     279    }
     280    Assert(GIC_IS_INTR_SGI_OR_PPI(uIntId) || GIC_IS_INTR_EXT_PPI(uIntId));
     281    return uIntId;
     282}
     283
     284
     285/**
     286 * Gets the redistributor interrupt index given an interrupt ID.
     287 *
     288 * @returns The interrupt ID.
     289 * @param   idxIntr
     290 * @remarks A redistributor interrupt is an interrupt type that belong in the
     291 *          redistributor (e.g. SGIs, PPIs, extended PPIs).
     292 */
     293static uint16_t gicReDistGetIndexFromIntId(uint16_t uIntId)
     294{
     295    /* SGIs and PPIs. */
     296    uint16_t idxIntr;
     297    if (uIntId <= GIC_INTID_RANGE_PPI_LAST)
     298        idxIntr = uIntId;
     299    /* Extended PPIs. */
     300    else if (uIntId - GIC_INTID_RANGE_EXT_PPI_START < GIC_INTID_EXT_PPI_RANGE_SIZE)
     301        idxIntr = 32 + uIntId - GIC_INTID_RANGE_EXT_PPI_START;
     302    else
     303    {
     304        idxIntr = 0;
     305        AssertReleaseFailed();
     306    }
     307    Assert(idxIntr < sizeof(GICCPU::bmIntrPending) * 8);
     308    return idxIntr;
     309}
    100310
    101311
     
    129339    /** @todo We could just use RTThreadNativeSelf() here, couldn't we? */
    130340#if defined(IN_RING0)
    131     PVMCC   pVM   = pVCpu->CTX_SUFF(pVM);
    132     VMCPUID idCpu = pVCpu->idCpu;
    133     if (VMMGetCpuId(pVM) != idCpu)
    134     {
    135         switch (VMCPU_GET_STATE(pVCpu))
    136         {
    137             case VMCPUSTATE_STARTED_EXEC:
    138                 Log7Func(("idCpu=%u VMCPUSTATE_STARTED_EXEC\n", idCpu));
    139                 GVMMR0SchedPokeNoGVMNoLock(pVM, idCpu);
    140                 break;
    141 
    142             case VMCPUSTATE_STARTED_HALTED:
    143                 Log7Func(("idCpu=%u VMCPUSTATE_STARTED_HALTED\n", idCpu));
    144                 GVMMR0SchedWakeUpNoGVMNoLock(pVM, idCpu);
    145                 break;
    146 
    147             default:
    148                 Log7Func(("idCpu=%u enmState=%d\n", idCpu, pVCpu->enmState));
    149                 break; /* nothing to do in other states. */
    150         }
    151     }
     341# error "Implement me!"
    152342#elif defined(IN_RING3)
    153343    PVMCC   pVM   = pVCpu->CTX_SUFF(pVM);
     
    162352
    163353
    164 /**
    165  * Clears the interrupt pending force-flag.
    166  *
    167  * @param   pVCpu           The cross context virtual CPU structure.
    168  * @param   fIrq            Flag whether to clear the IRQ flag.
    169  * @param   fFiq            Flag whether to clear the FIQ flag.
    170  */
    171 DECLINLINE(void) gicClearInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
    172 {
    173     LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n",
    174                  pVCpu, pVCpu->idCpu, fIrq, fFiq));
    175 
    176     Assert(fIrq || fFiq);
    177 
     354#if 0
     355/**
     356 * Sets the update interrupt force-flag and pokes the EMT if required.
     357 *
     358 * @param   pVCpu   The cross context virtual CPU structure.
     359 */
     360static void gicSetUpdateInterruptFF(PVMCPUCC pVCpu)
     361{
    178362#ifdef IN_RING3
    179363    /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
     
    181365#endif
    182366
     367    /* Set the update-interrupt force-flag. */
     368    VMCPU_FF_SET(pVCpu, VMCPU_FF_UPDATE_GIC);
     369
     370    /* Wake up the target CPU if we're not currently on the target EMT. */
     371#if defined(IN_RING0)
     372# error "Implement me"
     373#elif defined(IN_RING3)
     374    if (pVCpu->hNativeThread != RTThreadNativeSelf())
     375        VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_POKE);
     376#endif
     377}
     378#endif
     379
     380
     381/**
     382 * Clears the interrupt pending force-flag.
     383 *
     384 * @param   pVCpu   The cross context virtual CPU structure.
     385 * @param   fIrq    Flag whether to clear the IRQ flag.
     386 * @param   fFiq    Flag whether to clear the FIQ flag.
     387 */
     388DECLINLINE(void) gicClearInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
     389{
     390    Assert(fIrq || fFiq);
     391    LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n", pVCpu, pVCpu->idCpu, fIrq, fFiq));
     392
     393#ifdef IN_RING3
     394    /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
     395    Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
     396#endif
     397
    183398    if (fIrq)
    184399        VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_IRQ);
     
    188403
    189404
     405/**
     406 * Updates the interrupt force-flag.
     407 *
     408 * @param   pVCpu   The cross context virtual CPU structure.
     409 * @param   fIrq    Flag whether to clear the IRQ flag.
     410 * @param   fFiq    Flag whether to clear the FIQ flag.
     411 */
    190412DECLINLINE(void) gicUpdateInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
    191413{
    192     LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n",
    193                  pVCpu, pVCpu->idCpu, fIrq, fFiq));
     414    LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n", pVCpu, pVCpu->idCpu, fIrq, fFiq));
    194415
    195416    if (fIrq || fFiq)
     
    201422
    202423
    203 DECLINLINE(void) gicReDistHasIrqPending(PGICCPU pThis, bool *pfIrq, bool *pfFiq)
    204 {
     424/**
     425 * Gets whether the redistributor has pending interrupts with sufficient priority to
     426 * be signalled to the PE.
     427 *
     428 * @param   pGicCpu     The GIC redistributor and CPU interface state.
     429 * @param   pfIrq       Where to store whether IRQs can be signalled.
     430 * @param   pfFiq       Where to store whether FIQs can be signalled.
     431 */
     432DECLINLINE(void) gicReDistHasIrqPending(PCGICCPU pGicCpu, bool *pfIrq, bool *pfFiq)
     433{
     434    LogFlowFunc(("\n"));
     435#if 0
    205436    /* Read the interrupt state. */
    206437    uint32_t u32RegIGrp0  = ASMAtomicReadU32(&pThis->u32RegIGrp0);
     
    246477    LogFlowFunc(("pThis=%p bPriority=%u bmIntEnabled=%#x bmIntPending=%#x bmIntActive=%#x fIrq=%RTbool fFiq=%RTbool\n",
    247478                 pThis, bPriority, bmIntEnabled, bmIntPending, bmIntActive, *pfIrq, *pfFiq));
    248 }
    249 
    250 
    251 DECLINLINE(void) gicDistHasIrqPendingForVCpu(PGICDEV pThis, PGICCPU pGicVCpu, VMCPUID idCpu, bool *pfIrq, bool *pfFiq)
    252 {
     479#else
     480    bool const fIsGroup1Enabled = pGicCpu->fIrqGrp1Enabled;
     481    bool const fIsGroup0Enabled = pGicCpu->fIrqGrp0Enabled;
     482    LogFlowFunc(("fIsGroup0Enabled=%RTbool fIsGroup1Enabled=%RTbool\n", fIsGroup0Enabled, fIsGroup1Enabled));
     483
     484    uint32_t bmIntrs[3];
     485    for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrs); i++)
     486    {
     487        /* Collect interrupts that are pending, enabled and inactive. */
     488        bmIntrs[i] = (pGicCpu->bmIntrPending[i] & pGicCpu->bmIntrEnabled[i]) & ~pGicCpu->bmIntrActive[i];
     489
     490        /* Discard interrupts if the group they belong to is disabled. */
     491        if (!fIsGroup1Enabled)
     492            bmIntrs[i] &= ~pGicCpu->bmIntrGroup[i];
     493        if (!fIsGroup0Enabled)
     494            bmIntrs[i] &= pGicCpu->bmIntrGroup[i];
     495    }
     496
     497    /* Only allow interrupts with higher priority than the current configured and running one. */
     498    uint8_t const bPriority = RT_MIN(pGicCpu->bInterruptPriority, pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority]);
     499
     500    uint32_t const cIntrs  = sizeof(bmIntrs) * 8;
     501    int32_t        idxIntr = ASMBitFirstSet(&bmIntrs[0], cIntrs);
     502    AssertCompile(!(cIntrs % 32));
     503    if (idxIntr >= 0)
     504    {
     505        do
     506        {
     507            Assert((uint32_t)idxIntr < RT_ELEMENTS(pGicCpu->abIntrPriority));
     508            if (pGicCpu->abIntrPriority[idxIntr] < bPriority)
     509            {
     510                bool const fInGroup1 = ASMBitTest(&pGicCpu->bmIntrGroup[0], idxIntr);
     511                bool const fInGroup0 = !fInGroup1;
     512                *pfIrq = fInGroup1 && fIsGroup1Enabled;
     513                *pfFiq = fInGroup0 && fIsGroup0Enabled;
     514                return;
     515            }
     516            idxIntr = ASMBitNextSet(&bmIntrs[0], cIntrs, idxIntr);
     517        } while (idxIntr != -1);
     518    }
     519    *pfIrq = false;
     520    *pfFiq = false;
     521#endif
     522}
     523
     524
     525/**
     526 * Gets whether the distributor has pending interrupts with sufficient priority to
     527 * be signalled to the PE.
     528 *
     529 * @param   pGicDev     The GIC distributor state.
     530 * @param   pVCpu       The cross context virtual CPU structure.
     531 * @param   idCpu       The ID of the virtual CPU.
     532 * @param   pfIrq       Where to store whether there are IRQs can be signalled.
     533 * @param   pfFiq       Where to store whether there are FIQs can be signalled.
     534 */
     535DECLINLINE(void) gicDistHasIrqPendingForVCpu(PCGICDEV pGicDev, PCVMCPUCC pVCpu, VMCPUID idCpu, bool *pfIrq, bool *pfFiq)
     536{
     537    LogFlowFunc(("\n"));
     538#if 0
    253539    /* Read the interrupt state. */
    254540    uint32_t u32RegIGrp0  = ASMAtomicReadU32(&pThis->u32RegIGrp0);
     
    296582    LogFlowFunc(("pThis=%p bPriority=%u bmIntEnabled=%#x bmIntPending=%#x bmIntActive=%#x fIrq=%RTbool fFiq=%RTbool\n",
    297583                 pThis, bPriority, bmIntEnabled, bmIntPending, bmIntActive, *pfIrq, *pfFiq));
     584#else
     585    bool const fIsGroup1Enabled = pGicDev->fIrqGrp1Enabled;
     586    bool const fIsGroup0Enabled = pGicDev->fIrqGrp0Enabled;
     587    LogFlowFunc(("fIsGroup1Enabled=%RTbool fIsGroup0Enabled=%RTbool\n", fIsGroup1Enabled, fIsGroup0Enabled));
     588
     589    uint32_t bmIntrs[64];
     590    for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrs); i++)
     591    {
     592        /* Collect interrupts that are pending, enabled and inactive. */
     593        bmIntrs[i] = (pGicDev->bmIntrPending[i] & pGicDev->bmIntrEnabled[i]) & ~pGicDev->bmIntrActive[i];
     594
     595        /* Discard interrupts if the group they belong to is disabled. */
     596        if (!fIsGroup1Enabled)
     597            bmIntrs[i] &= ~pGicDev->bmIntrGroup[i];
     598        if (!fIsGroup0Enabled)
     599            bmIntrs[i] &= pGicDev->bmIntrGroup[i];
     600    }
     601
     602    /* Only allow interrupts with higher priority than the current configured and running one. */
     603    PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     604    uint8_t const bPriority = RT_MIN(pGicCpu->bInterruptPriority, pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority]);
     605
     606    /*
     607     * The distributor's interrupt pending/enabled/active bitmaps have 2048 bits which map
     608     * SGIs (16), PPIs (16), SPIs (988), reserved SPIs (4) and extended SPIs (1024).
     609     * Of these, the first 16 bits corresponding to SGIs and PPIs are RAZ/WI when affinity
     610     * routing is enabled (which it always is in our implementation).
     611     */
     612    Assert(pGicDev->fAffRoutingEnabled);
     613    uint32_t const cIntrs  = sizeof(bmIntrs) * 8;
     614    int32_t        idxIntr = ASMBitFirstSet(&bmIntrs[0], cIntrs);
     615    AssertCompile(!(cIntrs % 32));
     616    Assert(bmIntrs[0] == 0);
     617    if (idxIntr >= 0)
     618    {
     619        Assert(idxIntr > GIC_INTID_RANGE_PPI_LAST);
     620        do
     621        {
     622            AssertCompile(RT_ELEMENTS(pGicDev->abIntrPriority) == RT_ELEMENTS(pGicDev->au32IntrRouting));
     623            Assert((uint32_t)idxIntr < RT_ELEMENTS(pGicDev->abIntrPriority));
     624            Assert(idxIntr < GIC_INTID_RANGE_SPECIAL_START || idxIntr > GIC_INTID_RANGE_SPECIAL_LAST);
     625            if (   pGicDev->abIntrPriority[idxIntr] < bPriority
     626                && pGicDev->au32IntrRouting[idxIntr] == idCpu)
     627            {
     628                bool const fInGroup1 = ASMBitTest(&pGicDev->bmIntrGroup[0], idxIntr);
     629                bool const fInGroup0 = !fInGroup1;
     630                *pfFiq = fInGroup0 && fIsGroup0Enabled;
     631                *pfIrq = fInGroup1 && fIsGroup1Enabled;
     632                return;
     633            }
     634            idxIntr = ASMBitNextSet(&bmIntrs[0], cIntrs, idxIntr);
     635        } while (idxIntr != -1);
     636    }
     637    *pfIrq = false;
     638    *pfFiq = false;
     639#endif
    298640}
    299641
     
    304646 *
    305647 * @returns Strict VBox status code.
    306  * @param   pThis           The GIC re-distributor state for the associated vCPU.
    307  * @param   pVCpu           The cross context virtual CPU structure.
    308  */
    309 static VBOXSTRICTRC gicReDistUpdateIrqState(PGICCPU pThis, PVMCPUCC pVCpu)
    310 {
    311     bool fIrq, fFiq;
    312     gicReDistHasIrqPending(pThis, &fIrq, &fFiq);
    313 
    314     PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
    315     PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
    316     bool fIrqDist, fFiqDist;
    317     gicDistHasIrqPendingForVCpu(pGicDev, pThis, pVCpu->idCpu, &fIrqDist, &fFiqDist);
     648 * @param   pGicDev     The GIC distributor state.
     649 * @param   pVCpu       The cross context virtual CPU structure.
     650 */
     651static VBOXSTRICTRC gicReDistUpdateIrqState(PCGICDEV pGicDev, PVMCPUCC pVCpu)
     652{
     653    LogFlowFunc(("\n"));
     654    bool fIrq;
     655    bool fFiq;
     656    gicReDistHasIrqPending(VMCPU_TO_GICCPU(pVCpu), &fIrq, &fFiq);
     657    LogFlowFunc(("fIrq=%RTbool fFiq=%RTbool\n", fIrq, fFiq));
     658
     659    bool fIrqDist;
     660    bool fFiqDist;
     661    gicDistHasIrqPendingForVCpu(pGicDev, pVCpu, pVCpu->idCpu, &fIrqDist, &fFiqDist);
     662    LogFlowFunc(("fIrqDist=%RTbool fFiqDist=%RTbool\n", fIrqDist, fFiqDist));
     663
    318664    fIrq |= fIrqDist;
    319665    fFiq |= fFiqDist;
    320 
    321666    gicUpdateInterruptFF(pVCpu, fIrq, fFiq);
    322667    return VINF_SUCCESS;
     
    328673 *
    329674 * @returns Strict VBox status code.
    330  * @param   pVM             The cross context VM state.
    331  * @param   pThis           The GIC distributor state.
    332  */
    333 static VBOXSTRICTRC gicDistUpdateIrqState(PVMCC pVM, PGICDEV pThis)
    334 {
     675 * @param   pVM         The cross context VM state.
     676 * @param   pGicDev     The GIC distributor state.
     677 */
     678static VBOXSTRICTRC gicDistUpdateIrqState(PCVMCC pVM, PCGICDEV pGicDev)
     679{
     680    LogFlowFunc(("\n"));
    335681    for (uint32_t i = 0; i < pVM->cCpus; i++)
    336682    {
    337         PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[i];
    338         PGICCPU pGicVCpu = VMCPU_TO_GICCPU(pVCpu);
     683        PVMCPUCC pVCpu   = pVM->CTX_SUFF(apCpus)[i];
     684        PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
    339685
    340686        bool fIrq, fFiq;
    341         gicReDistHasIrqPending(pGicVCpu, &fIrq, &fFiq);
     687        gicReDistHasIrqPending(pGicCpu, &fIrq, &fFiq);
    342688
    343689        bool fIrqDist, fFiqDist;
    344         gicDistHasIrqPendingForVCpu(pThis, pGicVCpu, i, &fIrqDist, &fFiqDist);
     690        gicDistHasIrqPendingForVCpu(pGicDev, pVCpu, i, &fIrqDist, &fFiqDist);
    345691        fIrq |= fIrqDist;
    346692        fFiq |= fFiqDist;
     
    353699
    354700/**
    355  * Sets the given SGI/PPI interrupt ID on the re-distributor of the given vCPU.
    356  *
    357  * @returns VBox status code.
    358  * @param   pVCpu           The cross context virtual CPU structure.
    359  * @param   uIntId          The SGI/PPI interrupt identifier.
    360  * @param   fAsserted       Flag whether the SGI/PPI interrupt is asserted or not.
    361  */
    362 static int gicReDistInterruptSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
    363 {
    364     PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
    365 
    366     /* Update the interrupts pending state. */
    367     if (fAsserted)
    368         ASMAtomicOrU32(&pThis->bmIntPending, RT_BIT_32(uIntId));
     701 * Reads the distributor's interrupt routing register (GICD_IROUTER).
     702 *
     703 * @returns Strict VBox status code.
     704 * @param   pGicDev     The GIC distributor state.
     705 * @param   idxReg      The index of the register in the GICD_IROUTER range.
     706 * @param   puValue     Where to store the register's value.
     707 */
     708static VBOXSTRICTRC gicDistReadIntrRoutingReg(PCGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
     709{
     710    /* When affinity routing is disabled, reads return 0. */
     711    Assert(pGicDev->fAffRoutingEnabled);
     712
     713    /* Hardware does not map the first 32 registers (corresponding to SGIs and PPIs). */
     714    idxReg += GIC_INTID_RANGE_SPI_START;
     715    AssertReturn(idxReg < RT_ELEMENTS(pGicDev->au32IntrRouting), VERR_BUFFER_OVERFLOW);
     716    Assert(idxReg < sizeof(pGicDev->bmIntrRoutingMode) * 8);
     717    if (!(idxReg % 2))
     718    {
     719        /* Lower 32-bits. */
     720        uint8_t const fIrm = ASMBitTest(&pGicDev->bmIntrRoutingMode[0], idxReg);
     721        *puValue = GIC_DIST_REG_IROUTERn_SET(fIrm, pGicDev->au32IntrRouting[idxReg]);
     722    }
    369723    else
    370         ASMAtomicAndU32(&pThis->bmIntPending, ~RT_BIT_32(uIntId));
    371 
    372     return VBOXSTRICTRC_VAL(gicReDistUpdateIrqState(pThis, pVCpu));
    373 }
    374 
    375 
    376 /**
    377  * Reads a GIC distributor register.
     724    {
     725        /* Upper 32-bits. */
     726        *puValue = pGicDev->au32IntrRouting[idxReg] >> 24;
     727    }
     728
     729    LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue));
     730    return VINF_SUCCESS;
     731}
     732
     733
     734/**
     735 * Writes the distributor's interrupt routing register (GICD_IROUTER).
     736 *
     737 * @returns Strict VBox status code.
     738 * @param   pGicDev     The GIC distributor state.
     739 * @param   offReg      The offset of the register in the distributor register map.
     740 * @param   idxReg      The index of the register in the GICD_IROUTER range.
     741 * @param   uValue      The value to write to the register.
     742 */
     743static VBOXSTRICTRC gicDistWriteIntrRoutingReg(PGICDEV pGicDev, uint16_t offReg, uint16_t idxReg, uint32_t uValue)
     744{
     745    /* When affinity routing is disabled, writes are ignored. */
     746    Assert(pGicDev->fAffRoutingEnabled);
     747
     748    /* Hardware does not map the first 32 registers (corresponding to SGIs and PPIs). */
     749    idxReg += GIC_INTID_RANGE_SPI_START;
     750    AssertReturn(idxReg < RT_ELEMENTS(pGicDev->au32IntrRouting), VERR_BUFFER_OVERFLOW);
     751    Assert(idxReg < sizeof(pGicDev->bmIntrRoutingMode) * 8);
     752    if (!(offReg & 4))
     753    {
     754        /* Lower 32-bits. */
     755        bool const fIrm = GIC_DIST_REG_IROUTERn_IRM_GET(uValue);
     756        if (fIrm)
     757            ASMBitSet(&pGicDev->bmIntrRoutingMode[0], idxReg);
     758        else
     759            ASMBitClear(&pGicDev->bmIntrRoutingMode[0], idxReg);
     760        uint32_t const fAff3 = pGicDev->au32IntrRouting[idxReg] & 0xff000000;
     761        pGicDev->au32IntrRouting[idxReg] = fAff3 | (uValue & 0x00ffffff);
     762    }
     763    else
     764    {
     765        /* Upper 32-bits. */
     766        uint32_t const fAffOthers = pGicDev->au32IntrRouting[idxReg] & 0x00ffffff;
     767        pGicDev->au32IntrRouting[idxReg] = (uValue << 24) | fAffOthers;
     768    }
     769
     770    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->au32IntrRouting[idxReg]));
     771    return VINF_SUCCESS;
     772}
     773
     774
     775/**
     776 * Reads the distributor's interrupt (set/clear) enable register (GICD_ISENABLER and
     777 * GICD_ICENABLER).
     778 *
     779 * @returns Strict VBox status code.
     780 * @param   pGicDev     The GIC distributor state.
     781 * @param   idxReg      The index of the register in the GICD_ISENABLER and
     782 *                      GICD_ICENABLER range.
     783 * @param   puValue     Where to store the register's value.
     784 */
     785static VBOXSTRICTRC gicDistReadIntrEnableReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
     786{
     787    Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrEnabled));
     788    *puValue = pGicDev->bmIntrEnabled[idxReg];
     789    LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicDev->bmIntrEnabled[idxReg]));
     790    return VINF_SUCCESS;
     791}
     792
     793
     794/**
     795 * Writes the distributor's interrupt set-enable register (GICD_ISENABLER).
     796 *
     797 * @returns Strict VBox status code.
     798 * @param   pVM         The cross context VM structure.
     799 * @param   pGicDev     The GIC distributor state.
     800 * @param   idxReg      The index of the register in the GICD_ISENABLER range.
     801 * @param   uValue      The value to write to the register.
     802 */
     803static VBOXSTRICTRC gicDistWriteIntrSetEnableReg(PVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
     804{
     805    /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
     806    Assert(pGicDev->fAffRoutingEnabled);
     807    if (idxReg > 0)
     808    {
     809        Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrEnabled));
     810        pGicDev->bmIntrEnabled[idxReg] |= uValue;
     811        return gicDistUpdateIrqState(pVM, pGicDev);
     812    }
     813    else
     814        AssertReleaseFailed();
     815    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrEnabled[idxReg]));
     816    return VINF_SUCCESS;
     817}
     818
     819
     820/**
     821 * Writes the distributor's interrupt clear-enable register (GICD_ICENABLER).
     822 *
     823 * @returns Strict VBox status code.
     824 * @param   pVM         The cross context VM structure.
     825 * @param   pGicDev     The GIC distributor state.
     826 * @param   idxReg      The index of the register in the GICD_ICENABLER range.
     827 * @param   uValue      The value to write to the register.
     828 */
     829static VBOXSTRICTRC gicDistWriteIntrClearEnableReg(PVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
     830{
     831    /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
     832    Assert(pGicDev->fAffRoutingEnabled);
     833    if (idxReg > 0)
     834    {
     835        Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrEnabled));
     836        pGicDev->bmIntrEnabled[idxReg] &= ~uValue;
     837        return gicDistUpdateIrqState(pVM, pGicDev);
     838    }
     839    else
     840        AssertReleaseFailed();
     841    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrEnabled[idxReg]));
     842    return VINF_SUCCESS;
     843}
     844
     845
     846/**
     847 * Reads the distributor's interrupt active register (GICD_ISACTIVER and
     848 * GICD_ICACTIVER).
     849 *
     850 * @returns Strict VBox status code.
     851 * @param   pGicDev     The GIC distributor state.
     852 * @param   idxReg      The index of the register in the GICD_ISACTIVER and
     853 *                      GICD_ICACTIVER range.
     854 * @param   puValue     Where to store the register's value.
     855 */
     856static VBOXSTRICTRC gicDistReadIntrActiveReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
     857{
     858    Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrActive));
     859    *puValue = pGicDev->bmIntrActive[idxReg];
     860    LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicDev->bmIntrActive[idxReg]));
     861    return VINF_SUCCESS;
     862}
     863
     864
     865/**
     866 * Writes the distributor's interrupt set-active register (GICD_ISACTIVER).
     867 *
     868 * @returns Strict VBox status code.
     869 * @param   pVM         The cross context VM structure.
     870 * @param   pGicDev     The GIC distributor state.
     871 * @param   idxReg      The index of the register in the GICD_ISACTIVER range.
     872 * @param   uValue      The value to write to the register.
     873 */
     874static VBOXSTRICTRC gicDistWriteIntrSetActiveReg(PVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
     875{
     876    /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
     877    Assert(pGicDev->fAffRoutingEnabled);
     878    if (idxReg > 0)
     879    {
     880        Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrActive));
     881        pGicDev->bmIntrActive[idxReg] |= uValue;
     882        return gicDistUpdateIrqState(pVM, pGicDev);
     883    }
     884    else
     885        AssertReleaseFailed();
     886    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrActive[idxReg]));
     887    return VINF_SUCCESS;
     888}
     889
     890
     891/**
     892 * Writes the distributor's interrupt clear-active register (GICD_ICACTIVER).
     893 *
     894 * @returns Strict VBox status code.
     895 * @param   pVM         The cross context VM structure.
     896 * @param   pGicDev     The GIC distributor state.
     897 * @param   idxReg      The index of the register in the GICD_ICACTIVER range.
     898 * @param   uValue      The value to write to the register.
     899 */
     900static VBOXSTRICTRC gicDistWriteIntrClearActiveReg(PVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
     901{
     902    /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
     903    Assert(pGicDev->fAffRoutingEnabled);
     904    if (idxReg > 0)
     905    {
     906        Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrActive));
     907        pGicDev->bmIntrActive[idxReg] &= ~uValue;
     908        return gicDistUpdateIrqState(pVM, pGicDev);
     909    }
     910    else
     911        AssertReleaseFailed();
     912    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrActive[idxReg]));
     913    return VINF_SUCCESS;
     914}
     915
     916
     917/**
     918 * Reads the distributor's interrupt priority register (GICD_IPRIORITYR).
     919 *
     920 * @returns Strict VBox status code.
     921 * @param   pGicDev     The GIC distributor state.
     922 * @param   idxReg      The index of the register in the GICD_IPRIORITY range.
     923 * @param   puValue     Where to store the register's value.
     924 */
     925static VBOXSTRICTRC gicDistReadIntrPriorityReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
     926{
     927    /* When affinity routing is enabled, reads to registers 0..7 (pertaining to SGIs and PPIs) return 0. */
     928    Assert(pGicDev->fAffRoutingEnabled);
     929    Assert(idxReg < RT_ELEMENTS(pGicDev->abIntrPriority) / sizeof(uint32_t));
     930    Assert(idxReg != 255);
     931    if (idxReg > 7)
     932    {
     933        uint16_t const idxPriority = idxReg * sizeof(uint32_t);
     934        AssertReturn(idxPriority < RT_ELEMENTS(pGicDev->abIntrPriority) - sizeof(uint32_t), VERR_BUFFER_OVERFLOW);
     935        AssertCompile(sizeof(*puValue) == sizeof(uint32_t));
     936        *puValue = *(uint32_t *)&pGicDev->abIntrPriority[idxPriority];
     937    }
     938    else
     939    {
     940        AssertReleaseFailed();
     941        *puValue = 0;
     942    }
     943    LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue));
     944    return VINF_SUCCESS;
     945}
     946
     947
     948/**
     949 * Writes the distributor's interrupt priority register (GICD_IPRIORITYR).
     950 *
     951 * @returns Strict VBox status code.
     952 * @param   pGicDev     The GIC distributor state.
     953 * @param   idxReg      The index of the register in the GICD_IPRIORITY range.
     954 * @param   uValue      The value to write to the register.
     955 */
     956static VBOXSTRICTRC gicDistWriteIntrPriorityReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
     957{
     958    /* When affinity routing is enabled, writes to registers 0..7 are ignored. */
     959    Assert(pGicDev->fAffRoutingEnabled);
     960    Assert(idxReg < RT_ELEMENTS(pGicDev->abIntrPriority) / sizeof(uint32_t));
     961    Assert(idxReg != 255);
     962    if (idxReg > 7)
     963    {
     964        uint16_t const idxPriority = idxReg * sizeof(uint32_t);
     965        AssertReturn(idxPriority < RT_ELEMENTS(pGicDev->abIntrPriority) - sizeof(uint32_t), VERR_BUFFER_OVERFLOW);
     966        AssertCompile(sizeof(uValue) == sizeof(uint32_t));
     967        *(uint32_t *)&pGicDev->abIntrPriority[idxPriority] = uValue;
     968        LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, *(uint32_t *)&pGicDev->abIntrPriority[idxPriority]));
     969    }
     970    else
     971        AssertReleaseFailed();
     972    return VINF_SUCCESS;
     973}
     974
     975
     976/**
     977 * Reads the distributor's interrupt pending register (GICD_ISPENDR and
     978 * GICD_ICPENDR).
     979 *
     980 * @returns Strict VBox status code.
     981 * @param   pGicDev     The GIC distributor state.
     982 * @param   idxReg      The index of the register in the GICD_ISPENDR and
     983 *                      GICD_ICPENDR range.
     984 * @param   puValue     Where to store the register's value.
     985 */
     986static VBOXSTRICTRC gicDistReadIntrPendingReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
     987{
     988    /* When affinity routing is enabled, reads for SGIs and PPIs return 0. */
     989    Assert(pGicDev->fAffRoutingEnabled);
     990    if (idxReg > 0)
     991    {
     992        Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrPending));
     993        *puValue = pGicDev->bmIntrPending[idxReg];
     994    }
     995    else
     996    {
     997        AssertReleaseFailed();
     998        *puValue = 0;
     999    }
     1000    LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicDev->bmIntrPending[idxReg]));
     1001    return VINF_SUCCESS;
     1002}
     1003
     1004
     1005/**
     1006 * Write's the distributor's interrupt set-pending register (GICD_ISPENDR).
     1007 *
     1008 * @returns Strict VBox status code.
     1009 * @param   pVM         The cross context VM structure.
     1010 * @param   pGicDev     The GIC distributor state.
     1011 * @param   idxReg      The index of the register in the GICD_ISPENDR range.
     1012 * @param   uValue      The value to write to the register.
     1013 */
     1014static VBOXSTRICTRC gicDistWriteIntrSetPendingReg(PVMCC pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
     1015{
     1016    /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
     1017    Assert(pGicDev->fAffRoutingEnabled);
     1018    if (idxReg > 0)
     1019    {
     1020        Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrPending));
     1021        pGicDev->bmIntrPending[idxReg] |= uValue;
     1022        return gicDistUpdateIrqState(pVM, pGicDev);
     1023    }
     1024    else
     1025        AssertReleaseFailed();
     1026    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrPending[idxReg]));
     1027    return VINF_SUCCESS;
     1028}
     1029
     1030
     1031/**
     1032 * Write's the distributor's interrupt clear-pending register (GICD_ICPENDR).
     1033 *
     1034 * @returns Strict VBox status code.
     1035 * @param   pVM         The cross context VM structure.
     1036 * @param   pGicDev     The GIC distributor state.
     1037 * @param   idxReg      The index of the register in the GICD_ICPENDR range.
     1038 * @param   uValue      The value to write to the register.
     1039 */
     1040static VBOXSTRICTRC gicDistWriteIntrClearPendingReg(PVMCC pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
     1041{
     1042    /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
     1043    Assert(pGicDev->fAffRoutingEnabled);
     1044    if (idxReg > 0)
     1045    {
     1046        Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrPending));
     1047        pGicDev->bmIntrPending[idxReg] &= ~uValue;
     1048        return gicDistUpdateIrqState(pVM, pGicDev);
     1049    }
     1050    else
     1051        AssertReleaseFailed();
     1052    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrPending[idxReg]));
     1053    return VINF_SUCCESS;
     1054}
     1055
     1056
     1057/**
     1058 * Reads the distributor's interrupt config register (GICD_ICFGR).
     1059 *
     1060 * @returns Strict VBox status code.
     1061 * @param   pGicDev     The GIC distributor state.
     1062 * @param   idxReg      The index of the register in the GICD_ICFGR range.
     1063 * @param   puValue     Where to store the register's value.
     1064 */
     1065static VBOXSTRICTRC gicDistReadIntrConfigReg(PCGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
     1066{
     1067    /* SGIs are read-only and are always edge-triggered. */
     1068    if (idxReg > 0)
     1069    {
     1070        Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrConfig));
     1071        *puValue = pGicDev->bmIntrConfig[idxReg];
     1072    }
     1073    else
     1074        *puValue = 0xaaaaaaaa;
     1075    LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicDev->bmIntrConfig[idxReg]));
     1076    return VINF_SUCCESS;
     1077}
     1078
     1079
     1080/**
     1081 * Writes the distributor's interrupt config register (GICD_ICFGR).
     1082 *
     1083 * @returns Strict VBox status code.
     1084 * @param   pGicDev     The GIC distributor state.
     1085 * @param   idxReg      The index of the register in the GICD_ICFGR range.
     1086 * @param   uValue      The value to write to the register.
     1087 */
     1088static VBOXSTRICTRC gicDistWriteIntrConfigReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
     1089{
     1090    /* Writes to SGIs are ignored. */
     1091    if (idxReg > 0)
     1092    {
     1093        Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrConfig));
     1094        pGicDev->bmIntrConfig[idxReg] = uValue;
     1095    }
     1096    else
     1097        AssertReleaseFailed();
     1098    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrConfig[idxReg]));
     1099    return VINF_SUCCESS;
     1100}
     1101
     1102
     1103/**
     1104 * Reads the distributor's interrupt config register (GICD_IGROUPR).
     1105 *
     1106 * @returns Strict VBox status code.
     1107 * @param   pGicDev     The GIC distributor state.
     1108 * @param   idxReg      The index of the register in the GICD_IGROUPR range.
     1109 * @param   puValue     Where to store the register's value.
     1110 */
     1111static VBOXSTRICTRC gicDistReadIntrGroupReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
     1112{
     1113    /* When affinity routing is enabled, reads to SGIs and PPIs return 0. */
     1114    Assert(pGicDev->fAffRoutingEnabled);
     1115    if (idxReg > 0)
     1116    {
     1117        Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrGroup));
     1118        *puValue = pGicDev->bmIntrGroup[idxReg];
     1119        LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue));
     1120    }
     1121    else
     1122        AssertReleaseFailed();
     1123    return VINF_SUCCESS;
     1124}
     1125
     1126
     1127/**
     1128 * Writes the distributor's interrupt config register (GICD_ICFGR).
     1129 *
     1130 * @returns Strict VBox status code.
     1131 * @param   pVM         The cross context VM structure.
     1132 * @param   pGicDev     The GIC distributor state.
     1133 * @param   idxReg      The index of the register in the GICD_ICFGR range.
     1134 * @param   uValue      The value to write to the register.
     1135 */
     1136static VBOXSTRICTRC gicDistWriteIntrGroupReg(PCVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
     1137{
     1138    /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
     1139    Assert(pGicDev->fAffRoutingEnabled);
     1140    if (idxReg > 0)
     1141    {
     1142        pGicDev->bmIntrGroup[idxReg] = uValue;
     1143        LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrGroup[idxReg]));
     1144    }
     1145    else
     1146        AssertReleaseFailed();
     1147    return gicDistUpdateIrqState(pVM, pGicDev);
     1148}
     1149
     1150
     1151/**
     1152 * Reads the redistributor's interrupt priority register (GICR_IPRIORITYR).
     1153 *
     1154 * @returns Strict VBox status code.
     1155 * @param   pGicDev     The GIC distributor state.
     1156 * @param   pGicCpu     The GIC redistributor and CPU interface state.
     1157 * @param   idxReg      The index of the register in the GICR_IPRIORITY range.
     1158 * @param   puValue     Where to store the register's value.
     1159 */
     1160static VBOXSTRICTRC gicReDistReadIntrPriorityReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue)
     1161{
     1162    /* When affinity routing is disabled, reads return 0. */
     1163    Assert(pGicDev->fAffRoutingEnabled);
     1164    uint16_t const idxPriority = idxReg * sizeof(uint32_t);
     1165    AssertReturn(idxPriority < RT_ELEMENTS(pGicCpu->abIntrPriority) - sizeof(uint32_t), VERR_BUFFER_OVERFLOW);
     1166    AssertCompile(sizeof(*puValue) == sizeof(uint32_t));
     1167    *puValue = *(uint32_t *)&pGicCpu->abIntrPriority[idxPriority];
     1168    LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue));
     1169    return VINF_SUCCESS;
     1170}
     1171
     1172
     1173/**
     1174 * Writes the redistributor's interrupt priority register (GICR_IPRIORITYR).
     1175 *
     1176 * @returns Strict VBox status code.
     1177 * @param   pGicDev     The GIC distributor state.
     1178 * @param   pVCpu       The cross context virtual CPU structure.
     1179 * @param   idxReg      The index of the register in the GICR_IPRIORITY range.
     1180 * @param   uValue      The value to write to the register.
     1181 */
     1182static VBOXSTRICTRC gicReDistWriteIntrPriorityReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
     1183{
     1184    /* When affinity routing is disabled, writes are ignored. */
     1185    Assert(pGicDev->fAffRoutingEnabled);
     1186    PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     1187    uint16_t const idxPriority = idxReg * sizeof(uint32_t);
     1188    AssertReturn(idxPriority < RT_ELEMENTS(pGicCpu->abIntrPriority) - sizeof(uint32_t), VERR_BUFFER_OVERFLOW);
     1189    AssertCompile(sizeof(uValue) == sizeof(uint32_t));
     1190    *(uint32_t *)&pGicCpu->abIntrPriority[idxPriority] = uValue;
     1191    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, *(uint32_t *)&pGicCpu->abIntrPriority[idxPriority]));
     1192    return VINF_SUCCESS;
     1193}
     1194
     1195
     1196/**
     1197 * Reads the redistributor's interrupt pending register (GICR_ISPENDR and
     1198 * GICR_ICPENDR).
     1199 *
     1200 * @returns Strict VBox status code.
     1201 * @param   pGicDev     The GIC distributor state.
     1202 * @param   pGicCpu     The GIC redistributor and CPU interface state.
     1203 * @param   idxReg      The index of the register in the GICR_ISPENDR and
     1204 *                      GICR_ICPENDR range.
     1205 * @param   puValue     Where to store the register's value.
     1206 */
     1207static VBOXSTRICTRC gicReDistReadIntrPendingReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue)
     1208{
     1209    /* When affinity routing is disabled, reads return 0. */
     1210    Assert(pGicDev->fAffRoutingEnabled);
     1211    Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrPending));
     1212    *puValue = pGicCpu->bmIntrPending[idxReg];
     1213    LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicCpu->bmIntrPending[idxReg]));
     1214    return VINF_SUCCESS;
     1215}
     1216
     1217
     1218/**
     1219 * Writes the redistributor's interrupt set-pending register (GICR_ISPENDR).
     1220 *
     1221 * @returns Strict VBox status code.
     1222 * @param   pGicDev     The GIC distributor state.
     1223 * @param   pVCpu       The cross context virtual CPU structure.
     1224 * @param   idxReg      The index of the register in the GICR_ISPENDR range.
     1225 * @param   uValue      The value to write to the register.
     1226 */
     1227static VBOXSTRICTRC gicReDistWriteIntrSetPendingReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
     1228{
     1229    /* When affinity routing is disabled, writes are ignored. */
     1230    Assert(pGicDev->fAffRoutingEnabled);
     1231    PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     1232    Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrPending));
     1233    pGicCpu->bmIntrPending[idxReg] |= uValue;
     1234    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrPending[idxReg]));
     1235    return gicReDistUpdateIrqState(pGicDev, pVCpu);
     1236}
     1237
     1238
     1239/**
     1240 * Writes the redistributor's interrupt clear-pending register (GICR_ICPENDR).
     1241 *
     1242 * @returns Strict VBox status code.
     1243 * @param   pGicDev     The GIC distributor state.
     1244 * @param   pVCpu       The cross context virtual CPU structure.
     1245 * @param   idxReg      The index of the register in the GICR_ICPENDR range.
     1246 * @param   uValue      The value to write to the register.
     1247 */
     1248static VBOXSTRICTRC gicReDistWriteIntrClearPendingReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
     1249{
     1250    /* When affinity routing is disabled, writes are ignored. */
     1251    Assert(pGicDev->fAffRoutingEnabled);
     1252    PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     1253    Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrPending));
     1254    pGicCpu->bmIntrPending[idxReg] &= ~uValue;
     1255    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrPending[idxReg]));
     1256    return gicReDistUpdateIrqState(pGicDev, pVCpu);
     1257}
     1258
     1259
     1260/**
     1261 * Reads the redistributor's interrupt enable register (GICR_ISENABLER and
     1262 * GICR_ICENABLER).
     1263 *
     1264 * @returns Strict VBox status code.
     1265 * @param   pGicDev     The GIC distributor state.
     1266 * @param   pGicCpu     The GIC redistributor and CPU interface state.
     1267 * @param   idxReg      The index of the register in the GICR_ISENABLER and
     1268 *                      GICR_ICENABLER range.
     1269 * @param   puValue     Where to store the register's value.
     1270 */
     1271static VBOXSTRICTRC gicReDistReadIntrEnableReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue)
     1272{
     1273    Assert(pGicDev->fAffRoutingEnabled);
     1274    Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrEnabled));
     1275    *puValue = pGicCpu->bmIntrEnabled[idxReg];
     1276    LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicCpu->bmIntrEnabled[idxReg]));
     1277    return VINF_SUCCESS;
     1278}
     1279
     1280
     1281/**
     1282 * Writes the redistributor's interrupt set-enable register (GICR_ISENABLER).
     1283 *
     1284 * @returns Strict VBox status code.
     1285 * @param   pGicDev     The GIC distributor state.
     1286 * @param   pVCpu       The cross context virtual CPU structure.
     1287 * @param   idxReg      The index of the register in the GICR_ISENABLER range.
     1288 * @param   uValue      The value to write to the register.
     1289 */
     1290static VBOXSTRICTRC gicReDistWriteIntrSetEnableReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
     1291{
     1292    Assert(pGicDev->fAffRoutingEnabled);
     1293    PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     1294    Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrEnabled));
     1295    pGicCpu->bmIntrEnabled[idxReg] |= uValue;
     1296    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrEnabled[idxReg]));
     1297    return gicReDistUpdateIrqState(pGicDev, pVCpu);
     1298}
     1299
     1300
     1301/**
     1302 * Writes the redistributor's interrupt clear-enable register (GICR_ICENABLER).
     1303 *
     1304 * @returns Strict VBox status code.
     1305 * @param   pGicDev     The GIC distributor state.
     1306 * @param   pVCpu       The cross context virtual CPU structure.
     1307 * @param   idxReg      The index of the register in the GICR_ICENABLER range.
     1308 * @param   uValue      The value to write to the register.
     1309 */
     1310static VBOXSTRICTRC gicReDistWriteIntrClearEnableReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
     1311{
     1312    PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     1313    Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrEnabled));
     1314    pGicCpu->bmIntrEnabled[idxReg] &= ~uValue;
     1315    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrEnabled[idxReg]));
     1316    return gicReDistUpdateIrqState(pGicDev, pVCpu);
     1317}
     1318
     1319
     1320/**
     1321 * Reads the redistributor's interrupt active register (GICR_ISACTIVER and
     1322 * GICR_ICACTIVER).
     1323 *
     1324 * @returns Strict VBox status code.
     1325 * @param   pGicCpu     The GIC redistributor and CPU interface state.
     1326 * @param   idxReg      The index of the register in the GICR_ISACTIVER and
     1327 *                      GICR_ICACTIVER range.
     1328 * @param   puValue     Where to store the register's value.
     1329 */
     1330static VBOXSTRICTRC gicReDistReadIntrActiveReg(PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue)
     1331{
     1332    Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrActive));
     1333    *puValue = pGicCpu->bmIntrActive[idxReg];
     1334    LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicCpu->bmIntrActive[idxReg]));
     1335    return VINF_SUCCESS;
     1336}
     1337
     1338
     1339/**
     1340 * Writes the redistributor's interrupt set-active register (GICR_ISACTIVER).
     1341 *
     1342 * @returns Strict VBox status code.
     1343 * @param   pGicDev     The GIC distributor state.
     1344 * @param   pVCpu       The cross context virtual CPU structure.
     1345 * @param   idxReg      The index of the register in the GICR_ISACTIVER range.
     1346 * @param   uValue      The value to write to the register.
     1347 */
     1348static VBOXSTRICTRC gicReDistWriteIntrSetActiveReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
     1349{
     1350    PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     1351    Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrActive));
     1352    pGicCpu->bmIntrActive[idxReg] |= uValue;
     1353    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrActive[idxReg]));
     1354    return gicReDistUpdateIrqState(pGicDev, pVCpu);
     1355}
     1356
     1357
     1358/**
     1359 * Writes the redistributor's interrupt clear-active register (GICR_ICACTIVER).
     1360 *
     1361 * @returns Strict VBox status code.
     1362 * @param   pGicDev     The GIC distributor state.
     1363 * @param   pVCpu       The cross context virtual CPU structure.
     1364 * @param   idxReg      The index of the register in the GICR_ICACTIVER range.
     1365 * @param   uValue      The value to write to the register.
     1366 */
     1367static VBOXSTRICTRC gicReDistWriteIntrClearActiveReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
     1368{
     1369    PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     1370    Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrActive));
     1371    pGicCpu->bmIntrActive[idxReg] &= ~uValue;
     1372    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrActive[idxReg]));
     1373    return gicReDistUpdateIrqState(pGicDev, pVCpu);
     1374}
     1375
     1376
     1377/**
     1378 * Reads the redistributor's interrupt config register (GICR_ICFGR).
     1379 *
     1380 * @returns Strict VBox status code.
     1381 * @param   pGicDev     The GIC distributor state.
     1382 * @param   pGicCpu     The GIC redistributor and CPU interface state.
     1383 * @param   idxReg      The index of the register in the GICR_ICFGR range.
     1384 * @param   puValue     Where to store the register's value.
     1385 */
     1386static VBOXSTRICTRC gicReDistReadIntrConfigReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue)
     1387{
     1388    /* When affinity routing is disabled, reads return 0. */
     1389    Assert(pGicDev->fAffRoutingEnabled);
     1390    if (idxReg > 0)
     1391    {
     1392        Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrConfig));
     1393        *puValue = pGicCpu->bmIntrConfig[idxReg];
     1394    }
     1395    else
     1396    {
     1397        /* SGIs are read-only and are always edge-triggered. */
     1398        *puValue = 0xaaaaaaaa;
     1399    }
     1400    LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue));
     1401    return VINF_SUCCESS;
     1402}
     1403
     1404
     1405/**
     1406 * Writes the redistributor's interrupt config register (GICR_ICFGR).
     1407 *
     1408 * @returns Strict VBox status code.
     1409 * @param   pGicDev     The GIC distributor state.
     1410 * @param   pVCpu       The cross context virtual CPU structure.
     1411 * @param   idxReg      The index of the register in the GICR_ICFGR range.
     1412 * @param   uValue      The value to write to the register.
     1413 */
     1414static VBOXSTRICTRC gicReDistWriteIntrConfigReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
     1415{
     1416    /* When affinity routing is disabled, writes are ignored. */
     1417    Assert(pGicDev->fAffRoutingEnabled);
     1418    PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     1419    if (idxReg > 0)
     1420    {
     1421        Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrConfig));
     1422        pGicCpu->bmIntrConfig[idxReg] = uValue;
     1423    }
     1424    else
     1425    {
     1426        /* SGIs are always edge triggered ignore writes, verify value on strict builds (e.g. aarch64 Win11 writes this). */
     1427        Assert(uValue == 0xaaaaaaaa);
     1428        Assert(pGicCpu->bmIntrConfig[0] == uValue);
     1429    }
     1430    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrConfig[idxReg]));
     1431    return VINF_SUCCESS;
     1432}
     1433
     1434
     1435/**
     1436 * Reads the redistributor's interrupt group register (GICD_IGROUPR).
     1437 *
     1438 * @returns Strict VBox status code.
     1439 * @param   pGicDev     The GIC distributor state.
     1440 * @param   pGicCpu     The GIC redistributor and CPU interface state.
     1441 * @param   idxReg      The index of the register in the GICR_IGROUPR range.
     1442 * @param   puValue     Where to store the register's value.
     1443 */
     1444static VBOXSTRICTRC gicReDistReadIntrGroupReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue)
     1445{
     1446    /* When affinity routing is disabled, reads return 0. */
     1447    Assert(pGicDev->fAffRoutingEnabled);
     1448    Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrGroup));
     1449    *puValue = pGicCpu->bmIntrGroup[idxReg];
     1450    LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicCpu->bmIntrGroup[idxReg]));
     1451    return VINF_SUCCESS;
     1452}
     1453
     1454
     1455/**
     1456 * Writes the redistributor's interrupt group register (GICR_IGROUPR).
     1457 *
     1458 * @returns Strict VBox status code.
     1459 * @param   pGicDev     The GIC distributor state.
     1460 * @param   pVCpu       The cross context virtual CPU structure.
     1461 * @param   idxReg      The index of the register in the GICR_IGROUPR range.
     1462 * @param   uValue      The value to write to the register.
     1463 */
     1464static VBOXSTRICTRC gicReDistWriteIntrGroupReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
     1465{
     1466    /* When affinity routing is disabled, writes are ignored. */
     1467    Assert(pGicDev->fAffRoutingEnabled);
     1468    PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     1469    Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrGroup));
     1470    pGicCpu->bmIntrGroup[idxReg] = uValue;
     1471    LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrGroup[idxReg]));
     1472    return gicReDistUpdateIrqState(pGicDev, pVCpu);
     1473}
     1474
     1475
     1476#if 0
     1477/**
     1478 * Gets the IDB index for a given interrupt ID.
     1479 *
     1480 * @returns UINT16_MAX is the interrupt ID is invalid or does not map to an index,
     1481 *          otherwise returns a valid index.
     1482 * @param   uIntId      The interrupt ID.
     1483 */
     1484static uint16_t gicIntIdToIdbIndex(uint16_t uIntId)
     1485{
     1486    /*
     1487     * Interrupt Delivery Bitmap (IDB) format; bits to interrupt ID mapping:
     1488     * +---------------------------------------------------------------------+
     1489     * | Incl ranges  | SGI    | PPI    | SPI      | Ext PPI    | Ext SPI    |
     1490     * +---------------------------------------------------------------------+
     1491     * | Int Id       | 0..15  | 16..31 | 32..1019 | 1056..1119 | 4096..5119 |
     1492     * | Bit Index    | 0..15  | 16..31 | 32..1019 | 1020..1083 | 1084..2107 |
     1493     * +---------------------------------------------------------------------+
     1494     */
     1495    uint16_t const idxIdb;
     1496    if (uIntId <= GIC_INTID_RANGE_SPI_LAST)
     1497        return uIntId;
     1498    if (uIntId - GIC_INTID_RANGE_EXT_PPI_START < GIC_INTID_RANGE_EXT_PPI_RANGE_SIZE)
     1499        return GIC_INTID_RANGE_EXT_PPI_START + uIntId - GIC_INTID_RANGE_EXT_PPI_START;
     1500    if (uIntId - GIC_INTID_RANGE_EXT_SPI_START < GIC_INTID_RANGE_EXT_SPI_RANGE_SIZE)
     1501        return GIC_INTID_RANGE_EXT_SPI_START + uIntId - GIC_INTID_RANGE_EXT_SPI_START;
     1502    return UINT16_MAX;
     1503}
     1504
     1505static bool gicIsIntIdValid(uint16_t uIntId)
     1506{
     1507    if (uIntId <= GIC_INTID_RANGE_SPI_LAST)
     1508        return true;
     1509    if (uIntIt - GIC_INTID_RANGE_EXT_PPI_START < GIC_INTID_RANGE_EXT_PPI_RANGE_SIZE)
     1510        return true;
     1511    if (uIntIt - GIC_INTID_RANGE_EXT_SPI_START < GIC_INTID_RANGE_EXT_SPI_RANGE_SIZE)
     1512        return true;
     1513    return false;
     1514}
     1515
     1516
     1517static void gicSetIdxInIdb(PGICIDB pGicIdb, uint16_t idxIdb)
     1518{
     1519    if (RT_LIKELY(idxIdb < sizeof(pGicIdb->au64IntIdBitmap) * 8))
     1520        ASMAtomicBitSet(&pGicIdb->au64IntIdBitmap[0], idxIdb);
     1521    else
     1522        AssertMsgFailed(("Invalid IDB index %u for INTID %u\n" idxIdb, uIntId));
     1523}
     1524
     1525
     1526/**
     1527 * Sets an interrupt ID in an Interrupt-Delivery Bitmap (IDB).
     1528 *
     1529 * @param   pGicIdb     Pointer to the IDB.
     1530 * @param   uIntId      The interrupt ID.
     1531 */
     1532static void gicSetIntIdInIdb(PGICIDB pGicIdb, uint16_t uIntId)
     1533{
     1534    uint16_t const idxIdb =  gicIntIdToIdbIndex(uIntId);
     1535    gicSetIdxInIdb(pGicIdb, idxIdb);
     1536}
     1537
     1538
     1539/**
     1540 * Clears an interrupt ID in an Interrupt-Delivery Bitmap (IDB).
     1541 *
     1542 * @param   pGicIdb     Pointer to the IDB.
     1543 * @param   uIntId      The interrupt ID.
     1544 */
     1545static void gicClearIntIdInIdb(PGICIDB pGicIdb, uint16_t uIntId)
     1546{
     1547    uint16_t const idxIdb =  gicIntIdToIdbIndex(uIntId);
     1548    if (RT_LIKELY(idxIdb < sizeof(pGicIdb->au64IntIdBitmap) * 8))
     1549        ASMAtomicBitClear(&pGicIdb->au64IntIdBitmap[0], idxIdb);
     1550    else
     1551        AssertMsgFailed(("Invalid IDB index %u for INTID %u\n" idxIdb, uIntId));
     1552}
     1553
     1554
     1555/**
     1556 * Atomically sets the IDB notification bit.
     1557 *
     1558 * @returns non-zero if the bit was already set, 0 otherwise.
     1559 * @param   pGicIdb         Pointer to the IDB.
     1560 */
     1561static uint32_t gicSetNotificationBitInIdb(PGICIDB pGicIdb)
     1562{
     1563    return ASMAtomicXchgU32(&pGicIdb->fOutstandingNotification, RT_BIT_32(31));
     1564}
     1565
     1566
     1567/**
     1568 * Atomically tests and clears the IDB notification bit.
     1569 *
     1570 * @returns non-zero if the bit was already set, 0 otherwise.
     1571 * @param   pGicIdb         Pointer to the IDB.
     1572 */
     1573static uint32_t gicClearNotificationBitInIdb(PGICIDB pGicIdb)
     1574{
     1575    return ASMAtomicXchgU32(&pGicIdb->fOutstandingNotification, UINT32_C(0));
     1576}
     1577
     1578
     1579static VBOXSTRICTRC gicPostInterrupt(PVMCPUCC pVCpu, PVMCPUSET pCpuSet, uint16_t idxIdb)
     1580{
     1581    Assert(gicIntIdToIdbIndex(idxIdb) != UINT16_MAX);
     1582    for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
     1583    {
     1584        if (VMCPUSET_IS_PRESENT(&DestCpuSet, idCpu))
     1585        {
     1586            PVMCPUCC pTargetVCpu = pVCpu->pVMR3->CTX_SUFF(apCpus)[idCpu];
     1587            VMCPU_ASSERT_VALID_EXT_RETURN(pVCpu, VERR_INVALID_HANDLE);
     1588
     1589            PGICCPU pTargetGicCpu = VMCPU_TO_GICCPU(pTargetVCpu);
     1590            PGICIDB pTargetGicIdb = &pTargetGicCpu->IntrDeliveryBitmap;
     1591            gicSetIdxInIdb(pTargetGicIdb, idxIdb);
     1592            uint32_t const fAlreadySet = gicSetNotificationBitInIdb(pTargetGicIdb);
     1593            if (!fAlreadySet)
     1594                gicSetUpdateInterruptFF(pVCpu);
     1595        }
     1596    }
     1597}
     1598#endif
     1599
     1600
     1601/**
     1602 * Gets the virtual CPUID given the affinity values.
     1603 *
     1604 * @returns The virtual CPUID.
     1605 * @param   idCpuInterface  The virtual CPUID within the PE cluster (0..15).
     1606 * @param   uAff1           The affinity 1 value.
     1607 * @param   uAff2           The affinity 2 value.
     1608 * @param   uAff3           The affinity 3 value.
     1609 */
     1610DECL_FORCE_INLINE(VMCPUID) gicGetCpuIdFromAffinity(uint8_t idCpuInterface, uint8_t uAff1,  uint8_t uAff2,  uint8_t uAff3)
     1611{
     1612    AssertReturn(idCpuInterface < 16, VERR_INVALID_PARAMETER);
     1613    return (uAff3 * 1048576) + (uAff2 * 4096) + (uAff1 * 16) + idCpuInterface;
     1614}
     1615
     1616
     1617#if 0
     1618/**
     1619 * @interface_method_impl{PDMGICBACKEND,pfnUpdatePendingInterrupts}
     1620 */
     1621static DECLCALLBACK(void) gicUpdatePendingInterrupts(PVMCPUCC pVCpu)
     1622{
     1623    VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
     1624
     1625    PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     1626
     1627    /*
     1628     * Delivery interrupts pending in the interrupt-delivery bitmap to the PE.
     1629     */
     1630    bool    fHasPendingIntrs = false;
     1631    PGICIDB pIdb = (PGICIDB)pGicCpu->IntrDeliveryBitmap;
     1632    for (;;)
     1633    {
     1634        uint32_t const fAlreadySet = gicClearNotificationBitInIdb(pIdb);
     1635        if (!fAlreadySet)
     1636            break;
     1637
     1638        /* SGI and PPIs */
     1639        uint32_t const uSgiPpi = ASMAtomicXchgU32(&pIdb->au64IntIdBitmap[0], 0);
     1640        if (uSgiPpi)
     1641
     1642    }
     1643
     1644    STAM_PROFILE_STOP(&pApicCpu->StatUpdatePendingIntrs, a);
     1645    Log3(("APIC%u: apicUpdatePendingInterrupts: fHasPendingIntrs=%RTbool\n", pVCpu->idCpu, fHasPendingIntrs));
     1646
     1647    if (   fHasPendingIntrs
     1648        && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC))
     1649        apicSignalNextPendingIntr(pVCpu);
     1650}
     1651#endif
     1652
     1653
     1654#if 0
     1655static uint16_t gicGetHighestPrioPendingIntrFrom(const void *pvIntrPending, uint32_t cIntrs, uint8_t *pabIntrPriority,
     1656                                                 uint32_t cIntrPriority, uint8_t *pbPriority)
     1657{
     1658    uint16_t uIntIdHighest    = 0;
     1659    uint8_t  bPriority        = UINT8_MAX;
     1660
     1661    /* Find the INTID and priority of the pending interrupt with the highest priority. */
     1662    int32_t idxIntr = ASMBitFirstSet(pvIntrPending, cIntrs);
     1663    AssertCompile(!(cIntrs % 32));
     1664    if (idxIntr >= 0)
     1665    {
     1666        do
     1667        {
     1668            uint16_t const uIntId = gicGetIntIdFromIndex((uint16_t)idxIntr);
     1669            AssertRelease(uIntId < cIntrPriority);
     1670            if (pabIntrPriority[uIntId] < bPriority)
     1671            {
     1672                bPriority     = pabIntrPriority[uIntId];
     1673                uIntIdHighest = uIntId;
     1674            }
     1675            idxIntr = ASMBitNextSet(pvIntrPending, cIntrs, idxIntr);
     1676        } while (idxIntr != -1);
     1677    }
     1678    else
     1679    {
     1680        bPriority     = UINT8_MAX;
     1681        uIntIdHighest = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
     1682    }
     1683
     1684    *pbPriority = bPriority;
     1685    return uIntIdHighest;
     1686}
     1687
     1688
     1689static uint16_t gicDistGetHighestPrioPendingIntr(PCGICDEV pGicDev, uint8_t *pbPriority)
     1690{
     1691    uint16_t uIntIdHighest    = 0;
     1692    uint8_t  bPriority        = UINT8_MAX;
     1693    uint32_t const cIntrs     = sizeof(pGicDev->bmIntrPending) * 8;
     1694    void const *pvIntrPending = &pGicDev->bmIntrPending[0];
     1695
     1696    /* Find the INTID and priority of the pending interrupt with the highest priority. */
     1697    int32_t idxIntr = ASMBitFirstSet(pvIntrPending, cIntrs);
     1698    AssertCompile(!(cIntrs % 32));
     1699    if (idxIntr >= 0)
     1700    {
     1701        Assert(!pGicDev->fAffRoutingEnabled || idxIntr >= GIC_INTID_RANGE_SPI_START);
     1702        do
     1703        {
     1704            uint16_t const uIntId = gicGetIntIdFromIndex((uint16_t)idxIntr);
     1705            Assert(uIntId < RT_ELEMENTS(pGicDev->abIntrPriority));
     1706            if (pGicDev->abIntrPriority[uIntId] < bPriority)
     1707            {
     1708                bPriority     = pGicDev->abIntrPriority[idxIntr];
     1709                uIntIdHighest = uIntId;
     1710            }
     1711            idxIntr = ASMBitNextSet(pvIntrPending, cIntrs, idxIntr);
     1712        } while (idxIntr != -1);
     1713    }
     1714    else
     1715    {
     1716        bPriority     = UINT8_MAX;
     1717        uIntIdHighest = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
     1718    }
     1719
     1720    /* Sanity check if the interrupt ID is plausible. */
     1721    Assert(   GIC_IS_INTR_SGI_OR_PPI(uIntIdHighest)
     1722           || GIC_IS_INTR_SPI(uIntIdHighest)
     1723           || GIC_IS_INTR_EXT_PPI(uIntIdHighest)
     1724           || GIC_IS_INTR_EXT_SPI(uIntIdHighest)
     1725           || uIntIdHighest == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
     1726    /* Ensure if no interrupt is pending, priority is appropriate. */
     1727    Assert(uIntIdHighest != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX);
     1728
     1729    *pbPriority = bPriority;
     1730    return uIntIdHighest;
     1731}
     1732
     1733
     1734static uint16_t gicDistGetHighestPrioPendingGroupIntr(PCGICDEV pGicDev, uint8_t *pbPriority, bool fGroup0)
     1735{
     1736    uint32_t bmIntrPending[64];
     1737    for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrs); i++)
     1738    {
     1739        bmIntrPending[i] = (pGicDev->bmIntrPending[i] & pGicDev->bmIntrEnabled[i]) & ~pGicDev->bmIntrActive[i];
     1740        if (fGroup0)
     1741            bmIntrPending[i] &= ~pGicDev->bmIntrGroup[i];
     1742        else
     1743            bmIntrPending[i] &= pGicDev->bmIntrGroup[i];
     1744    }
     1745
     1746    void const *pvIntrPending = &bmIntrPending[0];
     1747    uint32_t const cIntrs     = sizeof(bmIntrPending) * 8;
     1748    uint16_t const uIntId = gicGetHighestPrioPendingIntrFrom(pvIntrPending, cIntrs, pGicDev->abIntrPriority,
     1749                                                             RT_ELEMENTS(pGicDev->abIntrPriority), pbPriority);
     1750
     1751    /* Sanity check if the interrupt ID is plausible. */
     1752    Assert(   GIC_IS_INTR_SGI_OR_PPI(uIntIdHighest)
     1753           || GIC_IS_INTR_SPI(uIntIdHighest)
     1754           || GIC_IS_INTR_EXT_PPI(uIntIdHighest)
     1755           || GIC_IS_INTR_EXT_SPI(uIntIdHighest)
     1756           || uIntIdHighest == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
     1757    /* Ensure if no interrupt is pending, priority is appropriate. */
     1758    Assert(uIntIdHighest != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX);
     1759
     1760    return uIntId;
     1761}
     1762
     1763
     1764static uint16_t gicReDistGetHighestPrioPendingGroupIntr(PCGICCPU pGicCpu, uint8_t *pbPriority, bool fGroup0)
     1765{
     1766    uint32_t bmIntrPending[3];
     1767    for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrs); i++)
     1768    {
     1769        bmIntrPending[i] = (pGicCpu->bmIntrPending[i] & pGicCpu->bmIntrEnabled[i]) & ~pGicCpu->bmIntrActive[i];
     1770        if (fGroup0)
     1771            bmIntrPending[i] &= ~pGicCpu->bmIntrGroup[i];
     1772        else
     1773            bmIntrPending[i] &= pGicCpu->bmIntrGroup[i];
     1774    }
     1775
     1776    void const *pvIntrPending = &bmIntrPending[0];
     1777    uint32_t const cIntrs     = sizeof(bmIntrPending) * 8;
     1778    uint16_t const uIntId = gicGetHighestPrioPendingIntrFrom(pvIntrPending, cIntrs, pGicCpu->abIntrPriority,
     1779                                                             RT_ELEMENTS(pGicCpu->abIntrPriority), pbPriority);
     1780
     1781    /* Sanity check if the interrupt ID is plausible. */
     1782    Assert(   GIC_IS_INTR_SGI_OR_PPI(uIntId)
     1783           || GIC_IS_INTR_EXT_PPI(uIntId)
     1784           || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
     1785    /* Ensure if no interrupt is pending, priority is appropriate. */
     1786    Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || *pbPriority == UINT8_MAX);
     1787    return uIntId;
     1788}
     1789
     1790static uint16_t gicReDistGetHighestPrioPendingIntr(PCGICCPU pGicCpu, uint8_t *pbPriority)
     1791{
     1792    uint16_t uIntIdHighest    = 0;
     1793    uint8_t  bPriority        = UINT8_MAX;
     1794    uint32_t const cIntrs     = sizeof(pGicCpu->bmIntrPending) * 8;
     1795    void const *pvIntrPending = &pGicCpu->bmIntrPending[0];
     1796
     1797    /* Find the INTID and priority of the pending interrupt with the highest priority. */
     1798    int32_t idxIntr = ASMBitFirstSet(pvIntrPending, cIntrs);
     1799    AssertCompile(!(cIntrs % 32));
     1800    if (idxIntr >= 0)
     1801    {
     1802        do
     1803        {
     1804            uint16_t const uIntId = gicGetIntIdFromIndex((uint16_t)idxIntr);
     1805            Assert(uIntId < RT_ELEMENTS(pGicCpu->abIntrPriority));
     1806            if (pGicCpu->abIntrPriority[uIntId] < bPriority)
     1807            {
     1808                bPriority     = pGicCpu->abIntrPriority[idxIntr];
     1809                uIntIdHighest = uIntId;
     1810            }
     1811            idxIntr = ASMBitNextSet(pvIntrPending, cIntrs, idxIntr);
     1812        } while (idxIntr != -1);
     1813    }
     1814    else
     1815    {
     1816        bPriority     = UINT8_MAX;
     1817        uIntIdHighest = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
     1818    }
     1819
     1820    /* Sanity check if the interrupt ID is plausible. */
     1821    Assert(   GIC_IS_INTR_SGI_OR_PPI(uIntIdHighest)
     1822           || GIC_IS_INTR_EXT_PPI(uIntIdHighest)
     1823           || uIntIdHighest == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
     1824    /* Ensure if no interrupt is pending, priority is appropriate. */
     1825    Assert(uIntIdHighest != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX);
     1826
     1827    *pbPriority = bPriority;
     1828    return uIntIdHighest;
     1829}
     1830
     1831
     1832static uint16_t gicGetHighestPrioPendingIntr(PCVMCC pVM, PGICDEV pGicDev)
     1833{
     1834    /* Get highest priority pending interrupt from the distributor. */
     1835    uint8_t  bPriority;
     1836    uint16_t uIntIdHighest = gicDistGetHighestPrioPendingIntr(pGicDev, &bPriority);
     1837
     1838    /* Compare with the highest priority pending interrupt from each redistributor. */
     1839    uint32_t const cCpus = pVM->cCpus;
     1840    for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
     1841    {
     1842        PCVMCPUCC pVCpu   = pVM->CTX_SUFF(apCpus)[idCpu];
     1843        PCGICCPU  pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     1844
     1845        uint8_t bReDistPriority;
     1846        uint16_t const uIntId = gicReDistGetHighestPrioPendingIntr(pGicCpu, &bReDistPriority);
     1847        if (   uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT
     1848            && bReDistPriority < bPriority)
     1849        {
     1850            bReDistPriority = bPriority;
     1851            uIntIdHighest   = uIntId;
     1852        }
     1853    }
     1854
     1855    /* Sanity check if the interrupt ID is plausible. */
     1856    Assert(   GIC_IS_INTR_SGI_OR_PPI(uIntIdHighest)
     1857           || GIC_IS_INTR_SPI(uIntIdHighest)
     1858           || GIC_IS_INTR_EXT_PPI(uIntIdHighest)
     1859           || GIC_IS_INTR_EXT_SPI(uIntIdHighest)
     1860           || uIntIdHighest == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
     1861    /* Ensure if no interrupt is pending, priority is appropriate. */
     1862    Assert(uIntIdHighest != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX);
     1863
     1864    return uIntIdHighest;
     1865}
     1866#endif
     1867
     1868
     1869/**
     1870 * Gets the highest priority pending distributor interrupt that can be forwarded to
     1871 * the redistributor.
     1872 *
     1873 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT if no interrupt
     1874 *          is pending or not in a state to be forwarded to the redistributor.
     1875 * @param   pGicDev     The GIC distributor state.
     1876 * @param   fGroup0     Whether to consider group 0 interrupts.
     1877 * @param   fGroup1     Whether to consider group 1 interrupts.
     1878 * @param   pidxIntr    Where to store the distributor interrupt index for the
     1879 *                      returned interrupt ID. UINT16_MAX if this function returns
     1880 *                      GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT. Optional, can be
     1881 *                      NULL.
     1882 * @param   pbPriority  Where to store the priority of the returned interrupt ID.
     1883 *                      UINT8_MAX if this function returns
     1884 *                      GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT.
     1885 */
     1886static uint16_t gicDistGetHighestPrioPendingIntr(PCGICDEV pGicDev, bool fGroup0, bool fGroup1, uint16_t *pidxIntr,
     1887                                                 uint8_t *pbPriority)
     1888{
     1889    /*
     1890     * Figure out the highest priority pending interrupt in the distributor.
     1891     * We can skip SGIs, PPIs in the distributor as we don't support legacy operation.
     1892     *
     1893     * See ARM GIC spec. 4.7.2 "Interaction of group and individual interrupt enables".
     1894     * See ARM GIC spec. 1.3.5 "GICv3 with no legacy operation".
     1895     */
     1896    Assert(pGicDev->fAffRoutingEnabled);
     1897    uint32_t bmIntrPending[64]; /** @todo SGIs, PPIs: iterate from 1 and initialize bmIntrPending[0] = 0. */
     1898    for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrPending); i++)
     1899    {
     1900        /* Collect interrupts that are pending, enabled and inactive. */
     1901        bmIntrPending[i] = (pGicDev->bmIntrPending[i] & pGicDev->bmIntrEnabled[i]) & ~pGicDev->bmIntrActive[i];
     1902
     1903        /* Discard interrupts if the group they belong to is disabled. */
     1904        if (!fGroup1)
     1905            bmIntrPending[i] &= ~pGicDev->bmIntrGroup[i];
     1906        if (!fGroup0)
     1907            bmIntrPending[i] &= pGicDev->bmIntrGroup[i];
     1908    }
     1909
     1910    /* Among the collected interrupts, pick the one with the highest priority. */
     1911    uint16_t       uIntId;
     1912    uint16_t       idxHighest;
     1913    uint16_t       uPriority = UINT16_MAX;
     1914    void const    *pvIntrs   = &bmIntrPending[0];
     1915    uint32_t const cIntrs    = sizeof(bmIntrPending) * 8;
     1916    int32_t        idxIntr   = ASMBitFirstSet(pvIntrs, cIntrs);
     1917    AssertCompile(!(cIntrs % 32));
     1918    if (idxIntr >= 0)
     1919    {
     1920        Assert(idxIntr >= 32);  /* We don't support legacy operation. */
     1921        do
     1922        {
     1923            Assert((uint32_t)idxIntr < RT_ELEMENTS(pGicDev->abIntrPriority));
     1924            if ((uint16_t)pGicDev->abIntrPriority[idxIntr] < uPriority)
     1925            {
     1926                idxHighest = (uint16_t)idxIntr;
     1927                uPriority  = pGicDev->abIntrPriority[idxIntr];
     1928                uIntId     = gicDistGetIntIdFromIndex(idxIntr);
     1929            }
     1930            idxIntr = ASMBitNextSet(pvIntrs, cIntrs, idxIntr);
     1931        } while (idxIntr != -1);
     1932    }
     1933    else
     1934    {
     1935        idxHighest = UINT16_MAX;
     1936        uPriority  = UINT8_MAX;
     1937        uIntId     = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
     1938    }
     1939
     1940    *pbPriority = uPriority;
     1941    if (pidxIntr)
     1942        *pidxIntr = idxHighest;
     1943
     1944    /* Sanity check if the interrupt ID is within known ranges. */
     1945    Assert(   GIC_IS_INTR_SPI(uIntId)
     1946           || GIC_IS_INTR_EXT_PPI(uIntId)
     1947           || GIC_IS_INTR_EXT_SPI(uIntId)
     1948           || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
     1949    /* Ensure that if no interrupt is pending, the priority is appropriate. */
     1950    Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || *pbPriority == UINT8_MAX);
     1951
     1952    LogFlowFunc(("uIntId=%u [idxIntr=%u uPriority=%u]\n", uIntId, idxIntr, uPriority));
     1953    return uIntId;
     1954}
     1955
     1956
     1957/**
     1958 * Gets the highest priority pending redistributor interrupt that can be signalled
     1959 * to the PE.
     1960 *
     1961 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT if no interrupt
     1962 *          is pending or not in a state to be signalled to the PE.
     1963 * @param   pGicCpu     The GIC redistributor and CPU interface state.
     1964 * @param   fGroup0     Whether to consider group 0 interrupts.
     1965 * @param   fGroup1     Whether to consider group 1 interrupts.
     1966 * @param   pidxIntr    Where to store the distributor interrupt index for the
     1967 *                      returned interrupt ID. UINT16_MAX if this function returns
     1968 *                      GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT. Optional, can be
     1969 *                      NULL.
     1970 * @param   pbPriority  Where to store the priority of the returned interrupt ID.
     1971 *                      UINT8_MAX if this function returns
     1972 *                      GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT.
     1973 */
     1974static uint16_t gicReDistGetHighestPrioPendingIntr(PCGICCPU pGicCpu, bool fGroup0, bool fGroup1, uint16_t *pidxIntr,
     1975                                                   uint8_t *pbPriority)
     1976{
     1977    /*
     1978     * Figure out the highest priority pending interrupt in the redistributor.
     1979     * See ARM GIC spec. 4.7.2 "Interaction of group and individual interrupt enables".
     1980     */
     1981    uint32_t bmIntrPending[3];
     1982    for (uint8_t i = 0 ; i < RT_ELEMENTS(bmIntrPending); i++)
     1983    {
     1984        /* Collect interrupts that are pending, enabled and inactive. */
     1985        bmIntrPending[i] = (pGicCpu->bmIntrPending[i] & pGicCpu->bmIntrEnabled[i]) & ~pGicCpu->bmIntrActive[i];
     1986
     1987        /* Discard interrupts if the group they belong to is disabled. */
     1988        if (!fGroup1)
     1989            bmIntrPending[i] &= ~pGicCpu->bmIntrGroup[i];
     1990        if (!fGroup0)
     1991            bmIntrPending[i] &= pGicCpu->bmIntrGroup[i];
     1992    }
     1993
     1994    /* Among the collected interrupts, pick the one with the highest priority. */
     1995    uint16_t       uIntId;
     1996    uint16_t       idxHighest;
     1997    uint16_t       uPriority = UINT16_MAX;
     1998    const void    *pvIntrs   = &bmIntrPending[0];
     1999    uint32_t const cIntrs    = sizeof(bmIntrPending) * 8;
     2000    int32_t        idxIntr   = ASMBitFirstSet(pvIntrs, cIntrs);
     2001    AssertCompile(!(cIntrs % 32));
     2002    if (idxIntr >= 0)
     2003    {
     2004        do
     2005        {
     2006            Assert((uint32_t)idxIntr < RT_ELEMENTS(pGicCpu->abIntrPriority));
     2007            if ((uint16_t)pGicCpu->abIntrPriority[idxIntr] < uPriority)
     2008            {
     2009                idxHighest = (uint16_t)idxIntr;
     2010                uPriority  = pGicCpu->abIntrPriority[idxIntr];
     2011                uIntId     = gicReDistGetIntIdFromIndex(idxIntr);
     2012            }
     2013            idxIntr = ASMBitNextSet(pvIntrs, cIntrs, idxIntr);
     2014        } while (idxIntr != -1);
     2015    }
     2016    else
     2017    {
     2018        idxHighest = UINT16_MAX;
     2019        uPriority  = UINT8_MAX;
     2020        uIntId     = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
     2021    }
     2022
     2023    *pbPriority = uPriority;
     2024    if (pidxIntr)
     2025        *pidxIntr = idxHighest;
     2026
     2027    /* Sanity check if the interrupt ID is within known ranges. */
     2028    Assert(   GIC_IS_INTR_SGI_OR_PPI(uIntId)
     2029           || GIC_IS_INTR_EXT_PPI(uIntId)
     2030           || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
     2031    /* Ensure that if no interrupt is pending, the priority is appropriate. */
     2032    Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || *pbPriority == UINT8_MAX);
     2033
     2034    LogFlowFunc(("uIntId=%u [idxIntr=%u uPriority=%u]\n", uIntId, idxIntr, uPriority));
     2035    return uIntId;
     2036}
     2037
     2038
     2039/**
     2040 * Gets the highest priority pending interrupt that can be signalled to the PE.
     2041 *
     2042 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT if no interrupt
     2043 *          is pending or not in a state to be signalled to the PE.
     2044 * @param   pVM         The cross context VM state.
     2045 * @param   pGicDev     The GIC distributor state.
     2046 * @param   fGroup0     Whether to consider group 0 interrupts.
     2047 * @param   fGroup1     Whether to consider group 1 interrupts.
     2048 */
     2049static uint16_t gicGetHighestPrioPendingIntr(PCVM pVM, PCGICDEV pGicDev, bool fGroup0, bool fGroup1)
     2050{
     2051    /* Get highest priority pending interrupt from the distributor. */
     2052    uint8_t  bPriority;
     2053    uint16_t uIntId = gicDistGetHighestPrioPendingIntr(pGicDev, fGroup0, fGroup1, NULL /*pidxIntr*/, &bPriority);
     2054
     2055    /* Compare with the highest priority pending interrupt from each redistributor. */
     2056    for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
     2057    {
     2058        PCVMCPUCC pVCpu   = pVM->CTX_SUFF(apCpus)[idCpu];
     2059        PCGICCPU  pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     2060
     2061        uint8_t bPriorityRedist;
     2062        uint16_t const uIntIdRedist = gicReDistGetHighestPrioPendingIntr(pGicCpu, fGroup0, fGroup1, NULL /*pidxIntr*/,
     2063                                                                         &bPriorityRedist);
     2064        if (   uIntIdRedist != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT
     2065            && bPriorityRedist < bPriority)
     2066        {
     2067            bPriority = bPriorityRedist;
     2068            uIntId    = uIntIdRedist;
     2069        }
     2070    }
     2071
     2072    /* Sanity check if the interrupt ID is within known ranges. */
     2073    Assert(   GIC_IS_INTR_SGI_OR_PPI(uIntId)
     2074           || GIC_IS_INTR_SPI(uIntId)
     2075           || GIC_IS_INTR_EXT_PPI(uIntId)
     2076           || GIC_IS_INTR_EXT_SPI(uIntId)
     2077           || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
     2078    /* Ensure that if no interrupt is pending, the priority is appropriate. */
     2079    Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX);
     2080
     2081    LogFlowFunc(("uIntId=%u [bPriority=%u]\n", uIntId, bPriority));
     2082    return uIntId;
     2083}
     2084
     2085
     2086/**
     2087 * Get and acknowledge the interrupt ID of a signalled interrupt.
     2088 *
     2089 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT no interrupts
     2090 *          are pending or not in a state to be signalled.
     2091 * @param   pGicDev     The GIC distributor state.
     2092 * @param   pVCpu       The cross context virtual CPU structure.
     2093 * @param   fGroup0     Whether to consider group 0 interrupts.
     2094 * @param   fGroup1     Whether to consider group 1 interrupts.
     2095 */
     2096static uint16_t gicAckHighestPrioPendingIntr(PGICDEV pGicDev, PVMCPUCC pVCpu, bool fGroup0, bool fGroup1)
     2097{
     2098    Assert(fGroup0 || fGroup1);
     2099    LogFlowFunc(("fGroup0=%RTbool fGroup1=%RTbool\n", fGroup0, fGroup1));
     2100
     2101    /* Get highest priority pending interrupt from the distributor. */
     2102    uint8_t  bPriority;
     2103    uint16_t idxIntr;
     2104    uint16_t uIntId = gicDistGetHighestPrioPendingIntr(pGicDev, fGroup0, fGroup1, &idxIntr, &bPriority);
     2105
     2106    /* Compare with the highest priority pending interrupt from each redistributor. */
     2107    bool fIntrInRedist = false;
     2108    uint32_t const cCpus = pVCpu->CTX_SUFF(pVM)->cCpus;
     2109    for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
     2110    {
     2111        PCVMCPUCC pVCpuCur = pVCpu->CTX_SUFF(pVM)->CTX_SUFF(apCpus)[idCpu];
     2112        PCGICCPU  pGicCpu  = VMCPU_TO_GICCPU(pVCpuCur);
     2113
     2114        uint8_t  bPriorityRedist;
     2115        uint16_t idxRedistIntr;
     2116        uint16_t const uIntIdRedist = gicReDistGetHighestPrioPendingIntr(pGicCpu, fGroup0, fGroup1, &idxRedistIntr,
     2117                                                                         &bPriorityRedist);
     2118        if (   uIntIdRedist != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT
     2119            && bPriorityRedist < bPriority)
     2120        {
     2121            fIntrInRedist = true;
     2122            bPriority = bPriorityRedist;
     2123            uIntId    = uIntIdRedist;
     2124            idxIntr   = idxRedistIntr;
     2125        }
     2126    }
     2127
     2128    /* Sanity check if the interrupt ID is within known ranges. */
     2129    Assert(   GIC_IS_INTR_SGI_OR_PPI(uIntId)
     2130           || GIC_IS_INTR_SPI(uIntId)
     2131           || GIC_IS_INTR_EXT_PPI(uIntId)
     2132           || GIC_IS_INTR_EXT_SPI(uIntId)
     2133           || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
     2134    /* Ensure that if no interrupt is pending, the priority is appropriate. */
     2135    Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX);
     2136
     2137    /* Acknowledge the interrupt. */
     2138    if (uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT)
     2139    {
     2140        PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     2141        if (fIntrInRedist)
     2142        {
     2143            /* Mark the interrupt as active. */
     2144            AssertMsg(idxIntr < sizeof(pGicCpu->bmIntrActive) * 8, ("idxIntr=%u\n", idxIntr));
     2145            ASMBitSet(&pGicCpu->bmIntrActive[0], idxIntr);
     2146
     2147            /* Drop priority. */
     2148            Assert(pGicCpu->idxRunningPriority < RT_ELEMENTS(pGicCpu->abRunningPriorities) - 1);
     2149
     2150            LogFlowFunc(("Dropping interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
     2151                         pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority],
     2152                         bPriority,
     2153                         pGicCpu->idxRunningPriority, pGicCpu->idxRunningPriority + 1));
     2154            pGicCpu->abRunningPriorities[++pGicCpu->idxRunningPriority] = bPriority;
     2155
     2156            /* Clear edge level interrupts like SGIs as pending. */
     2157            /** @todo do this for all edge-triggered? */
     2158            if (idxIntr <= GIC_INTID_RANGE_SGI_LAST)
     2159                ASMBitClear(&pGicCpu->bmIntrPending[0], idxIntr);
     2160
     2161            /* Update the redistributor IRQ state to reflect change in active interrupt. */
     2162            gicReDistUpdateIrqState(pGicDev, pVCpu);
     2163        }
     2164        else
     2165        {
     2166            /* Mark the interrupt as active. */
     2167            Assert(idxIntr < sizeof(pGicDev->bmIntrActive) * 8);
     2168            ASMBitSet(&pGicDev->bmIntrActive[0], idxIntr);
     2169
     2170            /* Drop priority. */
     2171            Assert(pGicCpu->idxRunningPriority < RT_ELEMENTS(pGicCpu->abRunningPriorities) - 1);
     2172
     2173            LogFlowFunc(("Dropping interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
     2174                         pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority],
     2175                         bPriority,
     2176                         pGicCpu->idxRunningPriority, pGicCpu->idxRunningPriority + 1));
     2177            pGicCpu->abRunningPriorities[++pGicCpu->idxRunningPriority] = bPriority;
     2178
     2179            /* Update the distributor IRQ state to reflect change in active interrupt. */
     2180            gicDistUpdateIrqState(pVCpu->CTX_SUFF(pVM), pGicDev);
     2181        }
     2182    }
     2183
     2184    LogFlowFunc(("uIntId=%u\n", uIntId));
     2185    return uIntId;
     2186}
     2187
     2188
     2189/**
     2190 * Reads a distributor register.
    3782191 *
    3792192 * @returns VBox status code.
     
    3832196 * @param   puValue         Where to store the register value.
    3842197 */
    385 DECLINLINE(VBOXSTRICTRC) gicDistRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
     2198DECLINLINE(VBOXSTRICTRC) gicDistReadRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
    3862199{
    3872200    VMCPU_ASSERT_EMT(pVCpu);
    388     PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
    389 
    390     if (offReg >= GIC_DIST_REG_IROUTERn_OFF_START && offReg <= GIC_DIST_REG_IROUTERn_OFF_LAST)
    391     {
    392         uint32_t idxEntry = (offReg - GIC_DIST_REG_IROUTERn_OFF_START) / 4;
    393         if (RT_LIKELY(idxEntry < RT_ELEMENTS(pThis->au32IntRouting)))
    394             *puValue = pThis->au32IntRouting[idxEntry];
    395         else
    396             *puValue = 0;
    397         return VINF_SUCCESS;
     2201    PGICDEV  pGicDev     = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
     2202    uint16_t const cbReg = sizeof(uint32_t);
     2203
     2204    /*
     2205     * GICD_IGROUPR<n> and GICD_IGROUPR<n>E.
     2206     */
     2207    {
     2208        if (offReg - GIC_DIST_REG_IGROUPRn_OFF_START < GIC_DIST_REG_IGROUPRn_RANGE_SIZE)
     2209        {
     2210            uint16_t const idxReg = (offReg - GIC_DIST_REG_IGROUPRn_OFF_START) / cbReg;
     2211            return gicDistReadIntrGroupReg(pGicDev, idxReg, puValue);
     2212        }
     2213        if (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START < GIC_DIST_REG_IGROUPRnE_RANGE_SIZE)
     2214        {
     2215            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrGroup) / 2;
     2216            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START) / cbReg;
     2217            return gicDistReadIntrGroupReg(pGicDev, idxReg, puValue);
     2218        }
     2219    }
     2220
     2221    /*
     2222     * GICD_IROUTER<n> and GICD_IROUTER<n>E.
     2223     */
     2224    {
     2225        if (offReg - GIC_DIST_REG_IROUTERn_OFF_START < GIC_DIST_REG_IROUTERn_RANGE_SIZE)
     2226        {
     2227            uint16_t const idxReg = (offReg - GIC_DIST_REG_IROUTERn_OFF_START) / cbReg;
     2228            return gicDistReadIntrRoutingReg(pGicDev, idxReg, puValue);
     2229        }
     2230        if (offReg - GIC_DIST_REG_IROUTERnE_OFF_START < GIC_DIST_REG_IROUTERnE_RANGE_SIZE)
     2231        {
     2232            uint16_t const idxExt = RT_ELEMENTS(pGicDev->au32IntrRouting) / 2;
     2233            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IROUTERnE_OFF_START) / cbReg;
     2234            return gicDistReadIntrRoutingReg(pGicDev, idxReg, puValue);
     2235        }
     2236    }
     2237
     2238    /*
     2239     * GICD_ISENABLER<n> and GICD_ISENABLER<n>E.
     2240     * GICD_ICENABLER<n> and GICD_ICENABLER<n>E.
     2241     */
     2242    {
     2243        if (offReg - GIC_DIST_REG_ISENABLERn_OFF_START  < GIC_DIST_REG_ISENABLERn_RANGE_SIZE)
     2244        {
     2245            uint16_t const idxReg = (offReg - GIC_DIST_REG_ISENABLERn_OFF_START) / cbReg;
     2246            return gicDistReadIntrEnableReg(pGicDev, idxReg, puValue);
     2247        }
     2248        if (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START < GIC_DIST_REG_ISENABLERnE_RANGE_SIZE)
     2249        {
     2250            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrEnabled) / 2;
     2251            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START) / cbReg;
     2252            return gicDistReadIntrEnableReg(pGicDev, idxReg, puValue);
     2253        }
     2254
     2255        if (offReg - GIC_DIST_REG_ICENABLERn_OFF_START  < GIC_DIST_REG_ICENABLERn_RANGE_SIZE)
     2256        {
     2257            uint16_t const idxReg = (offReg - GIC_DIST_REG_ICENABLERn_OFF_START) / cbReg;
     2258            return gicDistReadIntrEnableReg(pGicDev, idxReg, puValue);
     2259        }
     2260        if (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START < GIC_DIST_REG_ICENABLERnE_RANGE_SIZE)
     2261        {
     2262            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrEnabled) / 2;
     2263            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START) / cbReg;
     2264            return gicDistReadIntrEnableReg(pGicDev, idxReg, puValue);
     2265        }
     2266    }
     2267
     2268    /*
     2269     * GICD_ISACTIVER<n> and GICD_ISACTIVER<n>E.
     2270     * GICD_ICACTIVER<n> and GICD_ICACTIVER<n>E.
     2271     */
     2272    {
     2273        if (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START < GIC_DIST_REG_ISACTIVERn_RANGE_SIZE)
     2274        {
     2275            uint16_t const idxReg = (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START) / cbReg;
     2276            return gicDistReadIntrActiveReg(pGicDev, idxReg, puValue);
     2277        }
     2278        if (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START < GIC_DIST_REG_ISACTIVERnE_RANGE_SIZE)
     2279        {
     2280            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrActive) / 2;
     2281            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START) / cbReg;
     2282            return gicDistReadIntrActiveReg(pGicDev, idxReg, puValue);
     2283        }
     2284
     2285        if (offReg - GIC_DIST_REG_ICACTIVERn_OFF_START < GIC_DIST_REG_ICACTIVERn_RANGE_SIZE)
     2286        {
     2287            uint16_t const idxReg = (offReg - GIC_DIST_REG_ICENABLERn_OFF_START) / cbReg;
     2288            return gicDistReadIntrActiveReg(pGicDev, idxReg, puValue);
     2289        }
     2290        if (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START < GIC_DIST_REG_ICACTIVERnE_RANGE_SIZE)
     2291        {
     2292            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrActive) / 2;
     2293            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START) / cbReg;
     2294            return gicDistReadIntrActiveReg(pGicDev, idxReg, puValue);
     2295        }
     2296    }
     2297
     2298    /*
     2299     * GICD_IPRIORITYR<n> and GICD_IPRIORITYR<n>E.
     2300     */
     2301    {
     2302        if (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START < GIC_DIST_REG_IPRIORITYRn_RANGE_SIZE)
     2303        {
     2304            uint16_t const idxReg = (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START) / cbReg;
     2305            return gicDistReadIntrPriorityReg(pGicDev, idxReg, puValue);
     2306        }
     2307        if (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START < GIC_DIST_REG_IPRIORITYRnE_RANGE_SIZE)
     2308        {
     2309            uint16_t const idxExt = RT_ELEMENTS(pGicDev->abIntrPriority) / (2 * sizeof(uint32_t));
     2310            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START) / cbReg;
     2311            return gicDistReadIntrPriorityReg(pGicDev, idxReg, puValue);
     2312        }
     2313    }
     2314
     2315    /*
     2316     * GICD_ISPENDR<n> and GICD_ISPENDR<n>E.
     2317     * GICD_ICPENDR<n> and GICD_ICPENDR<n>E.
     2318     */
     2319    {
     2320        if (offReg - GIC_DIST_REG_ISPENDRn_OFF_START < GIC_DIST_REG_ISPENDRn_RANGE_SIZE)
     2321        {
     2322            uint16_t const idxReg = (offReg - GIC_DIST_REG_ISPENDRn_OFF_START) / cbReg;
     2323            return gicDistReadIntrPendingReg(pGicDev, idxReg, puValue);
     2324        }
     2325        if (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START < GIC_DIST_REG_ISPENDRnE_RANGE_SIZE)
     2326        {
     2327            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrPending) / 2;
     2328            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START) / cbReg;
     2329            return gicDistReadIntrPendingReg(pGicDev, idxReg, puValue);
     2330        }
     2331
     2332        if (offReg - GIC_DIST_REG_ICPENDRn_OFF_START < GIC_DIST_REG_ICPENDRn_RANGE_SIZE)
     2333        {
     2334            uint16_t const idxReg = (offReg - GIC_DIST_REG_ICPENDRn_OFF_START) / cbReg;
     2335            return gicDistReadIntrPendingReg(pGicDev, idxReg, puValue);
     2336        }
     2337        if (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START < GIC_DIST_REG_ICPENDRnE_RANGE_SIZE)
     2338        {
     2339            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrPending) / 2;
     2340            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START) / cbReg;
     2341            return gicDistReadIntrPendingReg(pGicDev, idxReg, puValue);
     2342        }
     2343    }
     2344
     2345    /*
     2346     * GICD_ICFGR<n> and GICD_ICFGR<n>E.
     2347     */
     2348    {
     2349        if (offReg - GIC_DIST_REG_ICFGRn_OFF_START < GIC_DIST_REG_ICFGRn_RANGE_SIZE)
     2350        {
     2351            uint16_t const idxReg = (offReg - GIC_DIST_REG_ICFGRn_OFF_START) / cbReg;
     2352            return gicDistReadIntrConfigReg(pGicDev, idxReg, puValue);
     2353        }
     2354        if (offReg - GIC_DIST_REG_ICFGRnE_OFF_START < GIC_DIST_REG_ICFGRnE_RANGE_SIZE)
     2355        {
     2356            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrConfig) / 2;
     2357            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICFGRnE_OFF_START) / cbReg;
     2358            return gicDistReadIntrConfigReg(pGicDev, idxReg, puValue);
     2359        }
    3982360    }
    3992361
     
    4012363    {
    4022364        case GIC_DIST_REG_CTLR_OFF:
    403             *puValue =   (ASMAtomicReadBool(&pThis->fIrqGrp0Enabled) ? GIC_DIST_REG_CTRL_ENABLE_GRP0 : 0)
    404                        | (ASMAtomicReadBool(&pThis->fIrqGrp1Enabled) ? GIC_DIST_REG_CTRL_ENABLE_GRP1_NS : 0)
    405                        | GIC_DIST_REG_CTRL_DS
    406                        | GIC_DIST_REG_CTRL_ARE_S;
     2365            Assert(pGicDev->fAffRoutingEnabled);    /* We don't support GICv2 backwards compatibility, so ARE bit must be set. */
     2366            *puValue = (pGicDev->fIrqGrp0Enabled ? GIC_DIST_REG_CTRL_ENABLE_GRP0    : 0)
     2367                     | (pGicDev->fIrqGrp1Enabled ? GIC_DIST_REG_CTRL_ENABLE_GRP1_NS : 0)
     2368                     | GIC_DIST_REG_CTRL_DS
     2369                     | (pGicDev->fAffRoutingEnabled ? GIC_DIST_REG_CTRL_ARE_S : 0);
    4072370            break;
    4082371        case GIC_DIST_REG_TYPER_OFF:
    409             Assert(pThis->uMaxSpi > 0 && pThis->uMaxSpi < GIC_DIST_REG_TYPER_NUM_ITLINES);
    410             *puValue =   GIC_DIST_REG_TYPER_NUM_ITLINES_SET(pThis->uMaxSpi)
    411                        | GIC_DIST_REG_TYPER_NUM_PES_SET(0)      /* 1 PE */ /** @todo r=ramshankar: Should this be pVCpu->cCpus? Currently it means 'ARE' must always be used? */
    412                        /*| GIC_DIST_REG_TYPER_ESPI*/            /** @todo */
    413                        /*| GIC_DIST_REG_TYPER_NMI*/             /** @todo Non-maskable interrupts */
    414                        /*| GIC_DIST_REG_TYPER_SECURITY_EXTN */  /** @todo */
    415                        /*| GIC_DIST_REG_TYPER_MBIS */           /** @todo Message based interrupts */
    416                        /*| GIC_DIST_REG_TYPER_LPIS */           /** @todo Support LPIs */
    417                        | GIC_DIST_REG_TYPER_IDBITS_SET(16);
     2372            Assert(pGicDev->uMaxSpi > 0 && pGicDev->uMaxSpi < GIC_DIST_REG_TYPER_NUM_ITLINES);
     2373            *puValue = GIC_DIST_REG_TYPER_NUM_ITLINES_SET(pGicDev->uMaxSpi)
     2374                     | GIC_DIST_REG_TYPER_NUM_PES_SET(0)      /* 1 PE */ /** @todo r=ramshankar: Should this be pVCpu->cCpus? Currently it means 'ARE' must always be used? */
     2375                     /*| GIC_DIST_REG_TYPER_ESPI*/            /** @todo */
     2376                     /*| GIC_DIST_REG_TYPER_NMI*/             /** @todo Non-maskable interrupts */
     2377                     /*| GIC_DIST_REG_TYPER_SECURITY_EXTN */  /** @todo */
     2378                     /*| GIC_DIST_REG_TYPER_MBIS */           /** @todo Message based interrupts */
     2379                     /*| GIC_DIST_REG_TYPER_LPIS */           /** @todo Support LPIs */
     2380                     | (pGicDev->fRangeSelSupport ? GIC_DIST_REG_TYPER_RSS : 0)
     2381                     | GIC_DIST_REG_TYPER_IDBITS_SET(16);
    4182382            break;
    4192383        case GIC_DIST_REG_STATUSR_OFF:
    4202384            AssertReleaseFailed();
    4212385            break;
     2386#if 0
    4222387        case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
    4232388            AssertReleaseFailed();
     
    4272392            *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
    4282393            break;
     2394#endif
    4292395        case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
    4302396            AssertReleaseFailed();
     
    4392405            AssertReleaseFailed();
    4402406            break;
     2407#if 0
    4412408        case GIC_DIST_REG_IPRIORITYRn_OFF_START:
    4422409        case GIC_DIST_REG_IPRIORITYRn_OFF_START + 4: /* These are banked for the PEs and access the redistributor. */
     
    4682435            break;
    4692436        }
     2437#endif
    4702438        case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
    4712439            AssertReleaseFailed();
     
    4932461            break;
    4942462        case GIC_DIST_REG_PIDR2_OFF:
     2463#if 0
    4952464            Assert(pThis->uArchRev <= GIC_DIST_REG_PIDR2_ARCH_REV_GICV4);
    4962465            *puValue = GIC_DIST_REG_PIDR2_ARCH_REV_SET(pThis->uArchRev);
     2466#else
     2467            Assert(pGicDev->uArchRev <= GIC_DIST_REG_PIDR2_ARCH_REV_GICV4);
     2468            *puValue = GIC_DIST_REG_PIDR2_ARCH_REV_SET(pGicDev->uArchRev);
     2469#endif
    4972470            break;
    4982471        case GIC_DIST_REG_IIDR_OFF:
     2472            *puValue = 0x43b;   /* JEP106 code 0x43b is an ARM implementation. */
     2473            break;
    4992474        case GIC_DIST_REG_TYPER2_OFF:
    5002475            *puValue = 0;
    5012476            break;
     2477#if 0
    5022478        case GIC_DIST_REG_IROUTERn_OFF_START:
    5032479            AssertFailed();
    5042480            break;
     2481#endif
    5052482        default:
    5062483            *puValue = 0;
     
    5112488
    5122489/**
    513  * Writes a GIC distributor register.
     2490 * Writes a distributor register.
    5142491 *
    5152492 * @returns Strict VBox status code.
     
    5192496 * @param   uValue          The register value.
    5202497 */
    521 DECLINLINE(VBOXSTRICTRC) gicDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
    522 {
    523     VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
    524     PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
    525     PVMCC   pVM   = PDMDevHlpGetVM(pDevIns);
    526 
    527     if (offReg >= GIC_DIST_REG_IROUTERn_OFF_START && offReg <= GIC_DIST_REG_IROUTERn_OFF_LAST)
    528     {
    529         uint32_t idxReg = (offReg - GIC_DIST_REG_IROUTERn_OFF_START) / 4;
    530         LogFlowFunc(("GicDist: idxIRouter=%u uValue=%#x\n", idxReg, uValue));
    531         if (idxReg < RT_ELEMENTS(pThis->au32IntRouting))
    532             pThis->au32IntRouting[idxReg] = uValue;
    533         return VINF_SUCCESS;
     2498DECLINLINE(VBOXSTRICTRC) gicDistWriteRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
     2499{
     2500    VMCPU_ASSERT_EMT(pVCpu);
     2501    PGICDEV        pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
     2502    PVMCC          pVM     = PDMDevHlpGetVM(pDevIns);
     2503    uint16_t const cbReg   = sizeof(uint32_t);
     2504
     2505    /*
     2506     * GICD_IGROUPR<n> and GICD_IGROUPR<n>E.
     2507     */
     2508    {
     2509        if (offReg - GIC_DIST_REG_IGROUPRn_OFF_START < GIC_DIST_REG_IGROUPRn_RANGE_SIZE)
     2510        {
     2511            uint16_t const idxReg = (offReg - GIC_DIST_REG_IGROUPRn_OFF_START) / cbReg;
     2512            return gicDistWriteIntrGroupReg(pVM, pGicDev, idxReg, uValue);
     2513        }
     2514        if (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START < GIC_DIST_REG_IGROUPRnE_RANGE_SIZE)
     2515        {
     2516            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrGroup) / 2;
     2517            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START) / cbReg;
     2518            return gicDistWriteIntrGroupReg(pVM, pGicDev, idxReg, uValue);
     2519        }
     2520    }
     2521
     2522    /*
     2523     * GICD_IROUTER<n> and GICD_IROUTER<n>E.
     2524     */
     2525    {
     2526        if (offReg - GIC_DIST_REG_IROUTERn_OFF_START < GIC_DIST_REG_IROUTERn_RANGE_SIZE)
     2527        {
     2528            uint16_t const idxReg = (offReg - GIC_DIST_REG_IROUTERn_OFF_START) / cbReg;
     2529            return gicDistWriteIntrRoutingReg(pGicDev, offReg, idxReg, uValue);
     2530        }
     2531        if (offReg - GIC_DIST_REG_IROUTERnE_OFF_START < GIC_DIST_REG_IROUTERnE_RANGE_SIZE)
     2532        {
     2533            uint16_t const idxExt = RT_ELEMENTS(pGicDev->au32IntrRouting) / 2;
     2534            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IROUTERnE_OFF_START) / cbReg;
     2535            return gicDistWriteIntrRoutingReg(pGicDev, offReg, idxReg, uValue);
     2536        }
     2537    }
     2538
     2539    /*
     2540     * GICD_ISENABLER<n> and GICD_ISENABLER<n>E.
     2541     * GICD_ICENABLER<n> and GICD_ICENABLER<n>E.
     2542     */
     2543    {
     2544        if (offReg - GIC_DIST_REG_ISENABLERn_OFF_START  < GIC_DIST_REG_ISENABLERn_RANGE_SIZE)
     2545        {
     2546            uint16_t const idxReg = (offReg - GIC_DIST_REG_ISENABLERn_OFF_START) / cbReg;
     2547            return gicDistWriteIntrSetEnableReg(pVM, pGicDev, idxReg, uValue);
     2548        }
     2549        if (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START < GIC_DIST_REG_ISENABLERnE_RANGE_SIZE)
     2550        {
     2551            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrEnabled) / 2;
     2552            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START) / cbReg;
     2553            return gicDistWriteIntrSetEnableReg(pVM, pGicDev, idxReg, uValue);
     2554        }
     2555
     2556        if (offReg - GIC_DIST_REG_ICENABLERn_OFF_START  < GIC_DIST_REG_ICENABLERn_RANGE_SIZE)
     2557        {
     2558            uint16_t const idxReg = (offReg - GIC_DIST_REG_ICENABLERn_OFF_START) / cbReg;
     2559            return gicDistWriteIntrClearEnableReg(pVM, pGicDev, idxReg, uValue);
     2560        }
     2561        if (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START < GIC_DIST_REG_ICENABLERnE_RANGE_SIZE)
     2562        {
     2563            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrEnabled) / 2;
     2564            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START) / cbReg;
     2565            return gicDistWriteIntrClearEnableReg(pVM, pGicDev, idxReg, uValue);
     2566        }
     2567    }
     2568
     2569    /*
     2570     * GICD_ISACTIVER<n> and GICD_ISACTIVER<n>E.
     2571     * GICD_ICACTIVER<n> and GICD_ICACTIVER<n>E.
     2572     */
     2573    {
     2574        if (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START < GIC_DIST_REG_ISACTIVERn_RANGE_SIZE)
     2575        {
     2576            uint16_t const idxReg = (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START) / cbReg;
     2577            return gicDistWriteIntrSetActiveReg(pVM, pGicDev, idxReg, uValue);
     2578        }
     2579        if (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START < GIC_DIST_REG_ISACTIVERnE_RANGE_SIZE)
     2580        {
     2581            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrActive) / 2;
     2582            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START) / cbReg;
     2583            return gicDistWriteIntrSetActiveReg(pVM, pGicDev, idxReg, uValue);
     2584        }
     2585
     2586        if (offReg - GIC_DIST_REG_ICACTIVERn_OFF_START < GIC_DIST_REG_ICACTIVERn_RANGE_SIZE)
     2587        {
     2588            uint16_t const idxReg = (offReg - GIC_DIST_REG_ICACTIVERn_OFF_START) / cbReg;
     2589            return gicDistWriteIntrClearActiveReg(pVM, pGicDev, idxReg, uValue);
     2590        }
     2591        if (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START < GIC_DIST_REG_ICACTIVERnE_RANGE_SIZE)
     2592        {
     2593            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrActive) / 2;
     2594            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START) / cbReg;
     2595            return gicDistWriteIntrClearActiveReg(pVM, pGicDev, idxReg, uValue);
     2596        }
     2597    }
     2598
     2599    /*
     2600     * GICD_IPRIORITYR<n> and GICD_IPRIORITYR<n>E.
     2601     */
     2602    {
     2603        if (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START < GIC_DIST_REG_IPRIORITYRn_RANGE_SIZE)
     2604        {
     2605            uint16_t const idxReg = (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START) / cbReg;
     2606            return gicDistWriteIntrPriorityReg(pGicDev, idxReg, uValue);
     2607        }
     2608        if (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START < GIC_DIST_REG_IPRIORITYRnE_RANGE_SIZE)
     2609        {
     2610            uint16_t const idxExt = RT_ELEMENTS(pGicDev->abIntrPriority) / (2 * sizeof(uint32_t));
     2611            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START) / cbReg;
     2612            return gicDistWriteIntrPriorityReg(pGicDev, idxReg, uValue);
     2613        }
     2614    }
     2615
     2616    /*
     2617     * GICD_ISPENDR<n> and GICD_ISPENDR<n>E.
     2618     * GICD_ICPENDR<n> and GICD_ICPENDR<n>E.
     2619     */
     2620    {
     2621        if (offReg - GIC_DIST_REG_ISPENDRn_OFF_START < GIC_DIST_REG_ISPENDRn_RANGE_SIZE)
     2622        {
     2623            uint16_t const idxReg = (offReg - GIC_DIST_REG_ISPENDRn_OFF_START) / cbReg;
     2624            return gicDistWriteIntrSetPendingReg(pVM, pGicDev, idxReg, uValue);
     2625        }
     2626        if (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START < GIC_DIST_REG_ISPENDRnE_RANGE_SIZE)
     2627        {
     2628            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrPending) / 2;
     2629            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START) / cbReg;
     2630            return gicDistWriteIntrSetPendingReg(pVM, pGicDev, idxReg, uValue);
     2631        }
     2632
     2633        if (offReg - GIC_DIST_REG_ICPENDRn_OFF_START < GIC_DIST_REG_ICPENDRn_RANGE_SIZE)
     2634        {
     2635            uint16_t const idxReg = (offReg - GIC_DIST_REG_ICPENDRn_OFF_START) / cbReg;
     2636            return gicDistWriteIntrClearPendingReg(pVM, pGicDev, idxReg, uValue);
     2637        }
     2638        if (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START < GIC_DIST_REG_ICPENDRnE_RANGE_SIZE)
     2639        {
     2640            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrPending) / 2;
     2641            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START) / cbReg;
     2642            return gicDistWriteIntrClearPendingReg(pVM, pGicDev, idxReg, uValue);
     2643        }
     2644    }
     2645
     2646    /*
     2647     * GICD_ICFGR<n> and GICD_ICFGR<n>E.
     2648     */
     2649    {
     2650        if (offReg - GIC_DIST_REG_ICFGRn_OFF_START + cbReg < GIC_DIST_REG_ICFGRn_RANGE_SIZE)
     2651        {
     2652            uint16_t const idxReg = (offReg - GIC_DIST_REG_ICFGRn_OFF_START) / cbReg;
     2653            return gicDistWriteIntrConfigReg(pGicDev, idxReg, uValue);
     2654        }
     2655        if (offReg - GIC_DIST_REG_ICFGRnE_OFF_START < GIC_DIST_REG_ICFGRnE_RANGE_SIZE)
     2656        {
     2657            uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrConfig) / 2;
     2658            uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICFGRnE_OFF_START) / cbReg;
     2659            return gicDistWriteIntrConfigReg(pGicDev, idxReg, uValue);
     2660        }
    5342661    }
    5352662
     
    5382665    {
    5392666        case GIC_DIST_REG_CTLR_OFF:
     2667#if 0
    5402668            ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP0));
    5412669            ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP1_NS));
    5422670            Assert(!(uValue & GIC_DIST_REG_CTRL_ARE_NS));
    5432671            rcStrict = gicDistUpdateIrqState(pVM, pThis);
     2672#else
     2673            Assert(!(uValue & GIC_DIST_REG_CTRL_ARE_NS));
     2674            pGicDev->fIrqGrp0Enabled = RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP0);
     2675            pGicDev->fIrqGrp1Enabled = RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP1_NS);
     2676            rcStrict = gicDistUpdateIrqState(pVM, pGicDev);
     2677#endif
    5442678            break;
    5452679        case GIC_DIST_REG_STATUSR_OFF:
     
    5582692            AssertReleaseFailed();
    5592693            break;
     2694#if 0
    5602695        case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
    5612696            AssertReleaseFailed();
     
    6412776            break;
    6422777        }
     2778#endif
    6432779        case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
    6442780            AssertReleaseFailed();
    6452781            break;
     2782#if 0
    6462783        case GIC_DIST_REG_ICFGRn_OFF_START + 8: /* Only 32 lines for now. */
    6472784            ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
     
    6502787            ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
    6512788            break;
     2789#endif
    6522790        case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
    6532791            AssertReleaseFailed();
     
    6872825 * @param   puValue         Where to store the register value.
    6882826 */
    689 DECLINLINE(VBOXSTRICTRC) gicReDistRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint32_t idRedist, uint16_t offReg, uint32_t *puValue)
    690 {
    691     PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
    692 
     2827DECLINLINE(VBOXSTRICTRC) gicReDistReadRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint32_t idRedist, uint16_t offReg, uint32_t *puValue)
     2828{
     2829    PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
     2830    Assert(idRedist == pVCpu->idCpu);   /* Assert for now, maybe remove function parameter later. */
    6932831    switch (offReg)
    6942832    {
    6952833        case GIC_REDIST_REG_TYPER_OFF:
    6962834        {
    697             PVMCC pVM = PDMDevHlpGetVM(pDevIns);
    698             *puValue =   ((pVCpu->idCpu == pVM->cCpus - 1) ? GIC_REDIST_REG_TYPER_LAST : 0)
    699                        | GIC_REDIST_REG_TYPER_CPU_NUMBER_SET(idRedist)
    700                        | GIC_REDIST_REG_TYPER_CMN_LPI_AFF_SET(GIC_REDIST_REG_TYPER_CMN_LPI_AFF_ALL);
    701             break;
    702         }
     2835            PCVMCC pVM = PDMDevHlpGetVM(pDevIns);
     2836            *puValue = ((pVCpu->idCpu == pVM->cCpus - 1) ? GIC_REDIST_REG_TYPER_LAST : 0)
     2837                     | GIC_REDIST_REG_TYPER_CPU_NUMBER_SET(idRedist)
     2838                     | GIC_REDIST_REG_TYPER_CMN_LPI_AFF_SET(GIC_REDIST_REG_TYPER_CMN_LPI_AFF_ALL);
     2839            break;
     2840        }
     2841        case GIC_REDIST_REG_IIDR_OFF:
     2842            *puValue = 0x43b;    /* JEP106 code 0x43b is an ARM implementation. */
     2843            break;
    7032844        case GIC_REDIST_REG_TYPER_AFFINITY_OFF:
    7042845            *puValue = idRedist;
    7052846            break;
    7062847        case GIC_REDIST_REG_PIDR2_OFF:
    707             Assert(pThis->uArchRev <= GIC_DIST_REG_PIDR2_ARCH_REV_GICV4);
    708             *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(pThis->uArchRev);
     2848            Assert(pGicDev->uArchRev <= GIC_DIST_REG_PIDR2_ARCH_REV_GICV4);
     2849            *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(pGicDev->uArchRev);
    7092850            break;
    7102851        default:
    7112852            *puValue = 0;
    7122853    }
    713 
    7142854    return VINF_SUCCESS;
    7152855}
     
    7252865 * @param   puValue         Where to store the register value.
    7262866 */
    727 DECLINLINE(VBOXSTRICTRC) gicReDistSgiPpiRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
     2867DECLINLINE(VBOXSTRICTRC) gicReDistReadSgiPpiRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
    7282868{
    7292869    VMCPU_ASSERT_EMT(pVCpu);
    7302870    RT_NOREF(pDevIns);
    7312871
    732     PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
     2872    PGICCPU  pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     2873    PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
     2874    uint16_t const cbReg = sizeof(uint32_t);
     2875
     2876#if 1
     2877    /*
     2878     * GICR_IGROUPR0 and GICR_IGROUPR<n>E.
     2879     */
     2880    {
     2881        if (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF < GIC_REDIST_SGI_PPI_REG_IGROUPRnE_RANGE_SIZE)
     2882        {
     2883            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF) / cbReg;
     2884            return gicReDistReadIntrGroupReg(pGicDev, pGicCpu, idxReg, puValue);
     2885        }
     2886    }
     2887
     2888    /*
     2889     * GICR_ISENABLER0 and GICR_ISENABLER<n>E.
     2890     * GICR_ICENABLER0 and GICR_ICENABLER<n>E.
     2891     */
     2892    {
     2893        if (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ISENABLERnE_RANGE_SIZE)
     2894        {
     2895            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF) / cbReg;
     2896            return gicReDistReadIntrEnableReg(pGicDev, pGicCpu, idxReg, puValue);
     2897        }
     2898        if (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ICENABLERnE_RANGE_SIZE)
     2899        {
     2900            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLERnE_OFF_START) / cbReg;
     2901            return gicReDistReadIntrEnableReg(pGicDev, pGicCpu, idxReg, puValue);
     2902        }
     2903    }
     2904
     2905    /*
     2906     * GICR_ISACTIVER0 and GICR_ISACTIVER<n>E.
     2907     * GICR_ICACTIVER0 and GICR_ICACTIVER<n>E.
     2908     */
     2909    {
     2910        if (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ISACTIVERnE_RANGE_SIZE)
     2911        {
     2912            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF) / cbReg;
     2913            return gicReDistReadIntrActiveReg(pGicCpu, idxReg, puValue);
     2914        }
     2915        if (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ICACTIVERnE_RANGE_SIZE)
     2916        {
     2917            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF) / cbReg;
     2918            return gicReDistReadIntrActiveReg(pGicCpu, idxReg, puValue);
     2919        }
     2920    }
     2921
     2922    /*
     2923     * GICR_ISPENDR0 and GICR_ISPENDR<n>E.
     2924     * GICR_ICPENDR0 and GICR_ICPENDR<n>E.
     2925     */
     2926    {
     2927        if (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ISPENDRnE_RANGE_SIZE)
     2928        {
     2929            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF) / cbReg;
     2930            return gicReDistReadIntrPendingReg(pGicDev, pGicCpu, idxReg, puValue);
     2931        }
     2932        if (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ICPENDRnE_RANGE_SIZE)
     2933        {
     2934            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF) / cbReg;
     2935            return gicReDistReadIntrPendingReg(pGicDev, pGicCpu, idxReg, puValue);
     2936        }
     2937    }
     2938
     2939    /*
     2940     * GICR_IPRIORITYR<n> and GICR_IPRIORITYR<n>E.
     2941     */
     2942    {
     2943        if (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START < GIC_REDIST_SGI_PPI_REG_IPRIORITYRnE_RANGE_SIZE)
     2944        {
     2945            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START) / cbReg;
     2946            return gicReDistReadIntrPriorityReg(pGicDev, pGicCpu, idxReg, puValue);
     2947        }
     2948    }
     2949
     2950    /*
     2951     * GICR_ICFGR0, GICR_ICFGR1 and GICR_ICFGR<n>E.
     2952     */
     2953    {
     2954        if (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF < GIC_REDIST_SGI_PPI_REG_ICFGRnE_RANGE_SIZE)
     2955        {
     2956            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF) / cbReg;
     2957            return gicReDistReadIntrConfigReg(pGicDev, pGicCpu, idxReg, puValue);
     2958        }
     2959    }
     2960
     2961    AssertReleaseFailed();
     2962    *puValue = 0;
     2963    return VINF_SUCCESS;
     2964#else
    7332965    switch (offReg)
    7342966    {
     
    7773009
    7783010    return VINF_SUCCESS;
     3011#endif
    7793012}
    7803013
     
    7893022 * @param   uValue          The register value.
    7903023 */
    791 DECLINLINE(VBOXSTRICTRC) gicReDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
     3024DECLINLINE(VBOXSTRICTRC) gicReDistWriteRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
    7923025{
    7933026    VMCPU_ASSERT_EMT(pVCpu);
     
    8423075 * @param   uValue          The register value.
    8433076 */
    844 DECLINLINE(VBOXSTRICTRC) gicReDistSgiPpiRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
     3077DECLINLINE(VBOXSTRICTRC) gicReDistWriteSgiPpiRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
    8453078{
    8463079    VMCPU_ASSERT_EMT(pVCpu);
    847     RT_NOREF(pDevIns);
    848 
    849     PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
     3080
     3081#if 1
     3082    PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
     3083
     3084    /*
     3085     * GICR_IGROUPR0 and GICR_IGROUPR<n>E.
     3086     */
     3087    {
     3088        uint16_t const cbReg = sizeof(uint32_t);
     3089        if (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF < GIC_REDIST_SGI_PPI_REG_IGROUPRnE_RANGE_SIZE)
     3090        {
     3091            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF) / cbReg;
     3092            return gicReDistWriteIntrGroupReg(pGicDev, pVCpu, idxReg, uValue);
     3093        }
     3094    }
     3095
     3096    /*
     3097     * GICR_ISENABLER0 and GICR_ISENABLER<n>E.
     3098     * GICR_ICENABLER0 and GICR_ICENABLER<n>E.
     3099     */
     3100    {
     3101        uint16_t const cbReg = sizeof(uint32_t);
     3102        if (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ISENABLERnE_RANGE_SIZE)
     3103        {
     3104            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF) / cbReg;
     3105            return gicReDistWriteIntrSetEnableReg(pGicDev, pVCpu, idxReg, uValue);
     3106        }
     3107        if (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ICENABLERnE_RANGE_SIZE)
     3108        {
     3109            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF) / cbReg;
     3110            return gicReDistWriteIntrClearEnableReg(pGicDev, pVCpu, idxReg, uValue);
     3111        }
     3112    }
     3113
     3114    /*
     3115     * GICR_ISACTIVER0 and GICR_ISACTIVER<n>E.
     3116     * GICR_ICACTIVER0 and GICR_ICACTIVER<n>E.
     3117     */
     3118    {
     3119        uint16_t const cbReg = sizeof(uint32_t);
     3120        if (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ISACTIVERnE_RANGE_SIZE)
     3121        {
     3122            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF) / cbReg;
     3123            return gicReDistWriteIntrSetActiveReg(pGicDev, pVCpu, idxReg, uValue);
     3124        }
     3125        if (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ICACTIVERnE_RANGE_SIZE)
     3126        {
     3127            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF) / cbReg;
     3128            return gicReDistWriteIntrClearActiveReg(pGicDev, pVCpu, idxReg, uValue);
     3129        }
     3130    }
     3131
     3132    /*
     3133     * GICR_ISPENDR0 and GICR_ISPENDR<n>E.
     3134     * GICR_ICPENDR0 and GICR_ICPENDR<n>E.
     3135     */
     3136    {
     3137        uint16_t const cbReg = sizeof(uint32_t);
     3138        if (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ISPENDRnE_RANGE_SIZE)
     3139        {
     3140            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF) / cbReg;
     3141            return gicReDistWriteIntrSetPendingReg(pGicDev, pVCpu, idxReg, uValue);
     3142        }
     3143        if (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ICPENDRnE_RANGE_SIZE)
     3144        {
     3145            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF) / cbReg;
     3146            return gicReDistWriteIntrClearPendingReg(pGicDev, pVCpu, idxReg, uValue);
     3147        }
     3148    }
     3149
     3150    /*
     3151     * GICR_IPRIORITYR<n> and GICR_IPRIORITYR<n>E.
     3152     */
     3153    {
     3154        uint16_t const cbReg = sizeof(uint32_t);
     3155        if (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START < GIC_REDIST_SGI_PPI_REG_IPRIORITYRnE_RANGE_SIZE)
     3156        {
     3157            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START) / cbReg;
     3158            return gicReDistWriteIntrPriorityReg(pGicDev, pVCpu, idxReg, uValue);
     3159        }
     3160    }
     3161
     3162    /*
     3163     * GICR_ICFGR0, GIC_ICFGR1 and GICR_ICFGR<n>E.
     3164     */
     3165    {
     3166        uint16_t const cbReg = sizeof(uint32_t);
     3167        if (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF < GIC_REDIST_SGI_PPI_REG_ICFGRnE_RANGE_SIZE)
     3168        {
     3169            uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF) / cbReg;
     3170            return gicReDistWriteIntrConfigReg(pGicDev, pVCpu, idxReg, uValue);
     3171        }
     3172    }
     3173
     3174    AssertReleaseFailed();
     3175    return VERR_INTERNAL_ERROR_2;
     3176#else
    8503177    VBOXSTRICTRC rcStrict = VINF_SUCCESS;
    8513178    switch (offReg)
     
    9083235            break;
    9093236    }
    910 
    9113237    return rcStrict;
     3238#endif
    9123239}
    9133240
     
    9163243 * @interface_method_impl{PDMGICBACKEND,pfnSetSpi}
    9173244 */
    918 static DECLCALLBACK(int) gicSetSpi(PVMCC pVM, uint32_t uIntId, bool fAsserted)
    919 {
    920     LogFlowFunc(("pVM=%p uIntId=%u fAsserted=%RTbool\n",
    921                  pVM, uIntId, fAsserted));
    922 
    923     AssertReturn(uIntId < GIC_SPI_MAX, VERR_INVALID_PARAMETER);
     3245static DECLCALLBACK(int) gicSetSpi(PVMCC pVM, uint32_t uSpiIntId, bool fAsserted)
     3246{
     3247    LogFlowFunc(("pVM=%p uSpiIntId=%u fAsserted=%RTbool\n",
     3248                 pVM, uSpiIntId, fAsserted));
    9243249
    9253250    PGIC       pGic    = VM_TO_GIC(pVM);
    9263251    PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
    927     PGICDEV    pThis  = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
     3252    PGICDEV    pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
    9283253
    9293254    int const  rcLock  = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
    9303255    PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
    9313256
     3257#if 0
    9323258    /* Update the interrupts pending state. */
    9333259    if (fAsserted)
     
    9373263
    9383264    int rc = VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pThis));
     3265#else
     3266    uint16_t const uIntId  = GIC_INTID_RANGE_SPI_START + uSpiIntId;
     3267    uint16_t const idxIntr = gicDistGetIndexFromIntId(uIntId);
     3268
     3269    Assert(idxIntr >= GIC_INTID_RANGE_SPI_START);
     3270    AssertMsgReturnStmt(idxIntr < sizeof(pGicDev->bmIntrPending) * 8,
     3271                        ("out-of-range SPI interrupt ID %RU32 (%RU32)\n", uIntId, uSpiIntId),
     3272                        PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3),
     3273                        VERR_INVALID_PARAMETER);
     3274
     3275    /* Update the interrupt pending state. */
     3276    if (fAsserted)
     3277        ASMBitSet(&pGicDev->bmIntrPending[0], idxIntr);
     3278    else
     3279        ASMBitClear(&pGicDev->bmIntrPending[0], idxIntr);
     3280    int const rc = VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pGicDev));
     3281#endif
     3282
    9393283    PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
    9403284    return rc;
     
    9453289 * @interface_method_impl{PDMGICBACKEND,pfnSetPpi}
    9463290 */
    947 static DECLCALLBACK(int) gicSetPpi(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
    948 {
     3291static DECLCALLBACK(int) gicSetPpi(PVMCPUCC pVCpu, uint32_t uPpiIntId, bool fAsserted)
     3292{
     3293    LogFlowFunc(("pVCpu=%p{.idCpu=%u} uPpiIntId=%u fAsserted=%RTbool\n", pVCpu, pVCpu->idCpu, uPpiIntId, fAsserted));
     3294
     3295    PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
     3296    PCGICDEV   pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
     3297    PGICCPU    pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     3298    int const  rcLock  = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
     3299    PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
     3300
     3301#if 0
     3302    AssertReturn(uIntId <= (GIC_INTID_RANGE_PPI_LAST - GIC_INTID_RANGE_PPI_START), VERR_INVALID_PARAMETER);
     3303    int rc = gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_PPI_START, fAsserted);
     3304#else
     3305    uint32_t const uIntId  = GIC_INTID_RANGE_PPI_START + uPpiIntId;
     3306    uint16_t const idxIntr = gicReDistGetIndexFromIntId(uIntId);
     3307
     3308    Assert(idxIntr >= GIC_INTID_RANGE_PPI_START);
     3309    AssertMsgReturnStmt(idxIntr < sizeof(pGicCpu->bmIntrPending) * 8,
     3310                        ("out-of-range PPI interrupt ID %RU32 (%RU32)\n", uIntId, uPpiIntId),
     3311                        PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3),
     3312                        VERR_INVALID_PARAMETER);
     3313
     3314    /* Update the interrupt pending state. */
     3315    if (fAsserted)
     3316        ASMBitSet(&pGicCpu->bmIntrPending[0], idxIntr);
     3317    else
     3318        ASMBitClear(&pGicCpu->bmIntrPending[0], idxIntr);
     3319    int const rc = VBOXSTRICTRC_VAL(gicReDistUpdateIrqState(pGicDev, pVCpu));
     3320#endif
     3321
     3322    PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
     3323
     3324    return rc;
     3325}
     3326
     3327
     3328/**
     3329 * Sets the specified software generated interrupt (SGI).
     3330 *
     3331 * @returns VBox status code.
     3332 * @param   pVM             The cross context VM structure.
     3333 * @param   pVCpu           The cross context virtual CPU structure.
     3334 * @param   pDestCpuSet     Which CPUs to deliver the SGI to.
     3335 * @param   uIntId          The SGI interrupt ID.
     3336 */
     3337static int gicSetSgi(PCGICDEV pGicDev, PVMCPUCC pVCpu, PCVMCPUSET pDestCpuSet, uint8_t uIntId)
     3338{
     3339#if 0
    9493340    LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u fAsserted=%RTbool\n",
    9503341                 pVCpu, pVCpu->idCpu, uIntId, fAsserted));
     
    9543345    PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
    9553346
    956     AssertReturn(uIntId <= (GIC_INTID_RANGE_PPI_LAST - GIC_INTID_RANGE_PPI_START), VERR_INVALID_PARAMETER);
    957     int rc = gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_PPI_START, fAsserted);
    958     PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
    959 
    960     return rc;
    961 }
    962 
    963 
    964 /**
    965  * Sets the specified software generated interrupt starting.
    966  *
    967  * @returns VBox status code.
    968  * @param   pVCpu               The cross context virtual CPU structure.
    969  * @param   uIntId              The PPI ID (minus GIC_INTID_RANGE_SGI_START) to assert/de-assert.
    970  * @param   fAsserted           Flag whether to mark the interrupt as asserted/de-asserted.
    971  */
    972 static int gicSetSgi(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
    973 {
    974     LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u fAsserted=%RTbool\n",
    975                  pVCpu, pVCpu->idCpu, uIntId, fAsserted));
    976 
    977     PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
    978     int const  rcLock  = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
    979     PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
    980 
    9813347    AssertReturn(uIntId <= (GIC_INTID_RANGE_SGI_LAST - GIC_INTID_RANGE_SGI_START), VERR_INVALID_PARAMETER);
    9823348    int rc = gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_SGI_START, fAsserted);
    9833349    PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
    984 
     3350#else
     3351    LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u\n", pVCpu, pVCpu->idCpu, uIntId));
     3352
     3353    PPDMDEVINS     pDevIns = VMCPU_TO_DEVINS(pVCpu);
     3354    PCVMCC         pVM     = pVCpu->CTX_SUFF(pVM);
     3355    uint32_t const cCpus   = pVM->cCpus;
     3356    AssertReturn(uIntId <= GIC_INTID_RANGE_SGI_LAST, VERR_INVALID_PARAMETER);
     3357
     3358    int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
     3359    PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
     3360
     3361    for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
     3362        if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
     3363        {
     3364            PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVM->CTX_SUFF(apCpus)[idCpu]);
     3365            pGicCpu->bmIntrPending[0] |= RT_BIT_32(uIntId);
     3366        }
     3367
     3368    int const rc = VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pGicDev));
     3369    PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
     3370#endif
    9853371    return rc;
     3372}
     3373
     3374
     3375/**
     3376 * Writes to the redistributor's SGI group 1 register (ICC_SGI1R_EL1).
     3377 *
     3378 * @returns Strict VBox status code.
     3379 * @param   pGicDev     The GIC distributor state.
     3380 * @param   pVCpu       The cross context virtual CPU structure.
     3381 * @param   uValue      The value being written to the ICC_SGI1R_EL1 register.
     3382 */
     3383static VBOXSTRICTRC gicReDistWriteSgiReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint64_t uValue)
     3384{
     3385    PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
     3386    VMCPUSET DestCpuSet;
     3387    if (uValue & ARMV8_ICC_SGI1R_EL1_AARCH64_IRM)
     3388    {
     3389        /*
     3390         * Deliver to all VCPUs but this one.
     3391         */
     3392        VMCPUSET_FILL(&DestCpuSet);
     3393        VMCPUSET_DEL(&DestCpuSet, pVCpu->idCpu);
     3394    }
     3395    else
     3396    {
     3397        /*
     3398         * Target specific VCPUs.
     3399         * See ARM GICv3 and GICv4 Software Overview spec 3.3 "Affinity routing".
     3400         */
     3401        VMCPUSET_EMPTY(&DestCpuSet);
     3402        bool const     fRangeSelSupport = RT_BOOL(pGicCpu->uIccCtlr & ARMV8_ICC_CTLR_EL1_AARCH64_RSS);
     3403        uint8_t const  idRangeStart     = ARMV8_ICC_SGI1R_EL1_AARCH64_RS_GET(uValue) * 16;
     3404        uint16_t const bmCpuInterfaces  = ARMV8_ICC_SGI1R_EL1_AARCH64_TARGET_LIST_GET(uValue);
     3405        uint8_t const  uAff1            = ARMV8_ICC_SGI1R_EL1_AARCH64_AFF1_GET(uValue);
     3406        uint8_t const  uAff2            = ARMV8_ICC_SGI1R_EL1_AARCH64_AFF2_GET(uValue);
     3407        uint8_t const  uAff3            = ARMV8_ICC_SGI1R_EL1_AARCH64_AFF3_GET(uValue);
     3408        uint32_t const cCpus            = pVCpu->CTX_SUFF(pVM)->cCpus;
     3409        for (uint8_t idCpuInterface = 0; idCpuInterface < 16; idCpuInterface++)
     3410        {
     3411            if (bmCpuInterfaces & RT_BIT(idCpuInterface))
     3412            {
     3413                VMCPUID idCpuTarget;
     3414                if (fRangeSelSupport)
     3415                    idCpuTarget = RT_MAKE_U32_FROM_U8(idRangeStart + idCpuInterface, uAff1, uAff2, uAff3);
     3416                else
     3417                    idCpuTarget = gicGetCpuIdFromAffinity(idCpuInterface, uAff1, uAff2, uAff3);
     3418                if (RT_LIKELY(idCpuTarget < cCpus))
     3419                    VMCPUSET_ADD(&DestCpuSet, idCpuTarget);
     3420                else
     3421                    AssertReleaseFailed();
     3422            }
     3423        }
     3424    }
     3425
     3426    if (!VMCPUSET_IS_EMPTY(&DestCpuSet))
     3427    {
     3428        uint8_t const uSgiIntId = ARMV8_ICC_SGI1R_EL1_AARCH64_INTID_GET(uValue);
     3429        Assert(GIC_IS_INTR_SGI(uSgiIntId));
     3430#if 0
     3431        uint16_t const idxIdb = uSgiIntId;
     3432        gicPostInterrupt(pVCpu, &DestCpuSet, idxIdb);
     3433#else
     3434        gicSetSgi(pGicDev, pVCpu, &DestCpuSet, uSgiIntId);
     3435#endif
     3436    }
     3437    return VINF_SUCCESS;
    9863438}
    9873439
     
    9993451
    10003452    *pu64Value = 0;
    1001     PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
     3453    PGICCPU    pGicCpu = VMCPU_TO_GICCPU(pVCpu);
    10023454    PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
    1003     PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
     3455    PGICDEV    pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
    10043456
    10053457    int const  rcLock  = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
     
    10093461    {
    10103462        case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
    1011             *pu64Value = pThis->bInterruptPriority;
     3463            *pu64Value = pGicCpu->bInterruptPriority;
    10123464            break;
    10133465        case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
     
    10213473            break;
    10223474        case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
    1023             *pu64Value = pThis->bBinaryPointGrp0 & 0x7;
     3475            *pu64Value = ARMV8_ICC_BPR0_EL1_AARCH64_BINARYPOINT_SET(pGicCpu->bBinaryPointGrp0);
    10243476            break;
    10253477        case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
     
    10543506            break;
    10553507        case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
    1056             *pu64Value = pThis->abRunningPriorities[pThis->idxRunningPriority];
     3508            *pu64Value = pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority];
    10573509            break;
    10583510        case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
     
    10673519        case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
    10683520        {
     3521#if 0
    10693522            /** @todo Figure out the highest priority interrupt. */
    10703523            uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
     
    11233576                    *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
    11243577            }
     3578#else
     3579            *pu64Value = gicAckHighestPrioPendingIntr(pGicDev, pVCpu, false /*fGroup0*/, true /*fGroup1*/);
     3580#endif
    11253581            break;
    11263582        }
     
    11303586        case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
    11313587        {
     3588#if 0
    11323589            /** @todo Figure out the highest priority interrupt. */
    11333590            uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
     
    11493606                    *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
    11503607            }
     3608#else
     3609            AssertReleaseFailed();
     3610            *pu64Value = gicGetHighestPrioPendingIntr(pVCpu->pVMR3, pGicDev, false /*fGroup0*/, true /*fGroup1*/);
     3611#endif
    11513612            break;
    11523613        }
    11533614        case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
    1154             *pu64Value = ARMV8_ICC_BPR1_EL1_AARCH64_BINARYPOINT_SET(pThis->bBinaryPointGrp1);
     3615            *pu64Value = ARMV8_ICC_BPR1_EL1_AARCH64_BINARYPOINT_SET(pGicCpu->bBinaryPointGrp1);
    11553616            break;
    11563617        case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
    1157             *pu64Value =   ARMV8_ICC_CTLR_EL1_AARCH64_PMHE
    1158                          | ARMV8_ICC_CTLR_EL1_AARCH64_PRIBITS_SET(4)
    1159                          | ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_SET(ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_16BITS);
     3618            *pu64Value = pGicCpu->uIccCtlr;
    11603619            break;
    11613620        case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
     
    11633622            break;
    11643623        case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
    1165             *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled) ? ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE : 0;
     3624            *pu64Value = pGicCpu->fIrqGrp0Enabled ? ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE : 0;
    11663625            break;
    11673626        case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
    1168             *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled) ? ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE : 0;
     3627            *pu64Value = pGicCpu->fIrqGrp1Enabled ? ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE : 0;
    11693628            break;
    11703629        default:
     
    11753634    PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
    11763635
    1177     LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} pu64Value=%RX64\n", pVCpu, u32Reg, gicIccRegisterStringify(u32Reg), *pu64Value));
     3636    LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} pu64Value=%RX64\n", pVCpu, u32Reg, gicIccGetRegDescription(u32Reg), *pu64Value));
    11783637    return VINF_SUCCESS;
    11793638}
     
    11893648     */
    11903649    VMCPU_ASSERT_EMT(pVCpu);
    1191     LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} u64Value=%RX64\n", pVCpu, u32Reg, gicIccRegisterStringify(u32Reg), u64Value));
    1192 
    1193     PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
     3650    LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} u64Value=%RX64\n", pVCpu, u32Reg, gicIccGetRegDescription(u32Reg), u64Value));
     3651
    11943652    PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
    1195     PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
     3653    PGICDEV    pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
     3654    PGICCPU    pGicCpu = VMCPU_TO_GICCPU(pVCpu);
    11963655
    11973656    int const  rcLock  = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
    11983657    PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
    11993658
     3659    VBOXSTRICTRC rcStrict = VINF_SUCCESS;
    12003660    switch (u32Reg)
    12013661    {
    12023662        case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
    12033663            LogFlowFunc(("ICC_PMR_EL1: Interrupt priority now %u\n", (uint8_t)u64Value));
     3664#if 0
    12043665            ASMAtomicWriteU8(&pThis->bInterruptPriority, (uint8_t)u64Value);
    12053666            gicReDistUpdateIrqState(pThis, pVCpu);
     3667#else
     3668            pGicCpu->bInterruptPriority = (uint8_t)u64Value;
     3669            rcStrict = gicReDistUpdateIrqState(pGicDev, pVCpu);
     3670#endif
    12063671            break;
    12073672        case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
     
    12153680            break;
    12163681        case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
     3682#if 0
    12173683            pThis->bBinaryPointGrp0 = (uint8_t)ARMV8_ICC_BPR0_EL1_AARCH64_BINARYPOINT_GET(u64Value);
     3684#else
     3685            pGicCpu->bBinaryPointGrp0 = (uint8_t)ARMV8_ICC_BPR0_EL1_AARCH64_BINARYPOINT_GET(u64Value);
     3686#endif
    12183687            break;
    12193688        case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
     
    12523721        case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
    12533722        {
     3723#if 0
    12543724            uint32_t uIntId = ARMV8_ICC_SGI1R_EL1_AARCH64_INTID_GET(u64Value) - GIC_INTID_RANGE_SGI_START;
    12553725            if (u64Value & ARMV8_ICC_SGI1R_EL1_AARCH64_IRM)
     
    12893759                }
    12903760            }
     3761#else
     3762            gicReDistWriteSgiReg(pGicDev, pVCpu, u64Value);
     3763#endif
    12913764            break;
    12923765        }
     
    13023775        case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
    13033776        {
     3777#if 0
    13043778            /* Mark the interrupt as not active anymore, though it might still be pending. */
    13053779            if (u64Value < GIC_INTID_RANGE_SPI_START)
     
    13193793            }
    13203794            gicReDistUpdateIrqState(pThis, pVCpu);
     3795#else
     3796            /*
     3797             * We only support priority drop + interrupt deactivation with writes to this register.
     3798             * This avoids an extra access which would be required by software for deactivation.
     3799             */
     3800            Assert(!(pGicCpu->uIccCtlr & ARMV8_ICC_CTLR_EL1_AARCH64_EOIMODE));
     3801
     3802            /*
     3803             * Mark the interrupt as inactive, though it might still be pending.
     3804             * WARNING! The order of the 'if' checks below are crucial.
     3805             */
     3806            uint16_t const uIntId = (uint16_t)u64Value;
     3807            if (uIntId <= GIC_INTID_RANGE_PPI_LAST)
     3808            {
     3809                /* SGIs and PPIs. */
     3810                AssertCompile(GIC_INTID_RANGE_PPI_LAST < 8 * sizeof(pGicDev->bmIntrActive[0]));
     3811                Assert(pGicDev->fAffRoutingEnabled);
     3812                pGicCpu->bmIntrActive[0] &= ~RT_BIT_32(uIntId);
     3813            }
     3814            else if (uIntId <= GIC_INTID_RANGE_SPI_LAST)
     3815            {
     3816                /* SPIs. */
     3817                uint16_t const idxIntr = /*gicDistGetIndexFromIntId*/(uIntId);
     3818                AssertReturn(idxIntr < sizeof(pGicDev->bmIntrActive) * 8, VERR_BUFFER_OVERFLOW);
     3819                ASMBitClear(&pGicDev->bmIntrActive[0], idxIntr);
     3820            }
     3821            else if (uIntId <= GIC_INTID_RANGE_EXT_PPI_LAST)
     3822            {
     3823                /* Extended PPIs. */
     3824                uint16_t const idxIntr = gicReDistGetIndexFromIntId(uIntId);
     3825                AssertReturn(idxIntr < sizeof(pGicCpu->bmIntrActive) * 8, VERR_BUFFER_OVERFLOW);
     3826                ASMBitClear(&pGicCpu->bmIntrActive[0], idxIntr);
     3827            }
     3828            else if (uIntId <= GIC_INTID_RANGE_EXT_SPI_LAST)
     3829            {
     3830                /* Extended SPIs. */
     3831                uint16_t const idxIntr = gicDistGetIndexFromIntId(uIntId);
     3832                AssertReturn(idxIntr < sizeof(pGicDev->bmIntrActive) * 8, VERR_BUFFER_OVERFLOW);
     3833                ASMBitClear(&pGicDev->bmIntrActive[0], idxIntr);
     3834            }
     3835            else
     3836            {
     3837                AssertMsgFailed(("Invalid INTID %u\n", uIntId));
     3838                break;
     3839            }
     3840
     3841            /*
     3842             * Restore previous interrupt priority.
     3843             */
     3844            Assert(pGicCpu->idxRunningPriority > 0);
     3845            if (RT_LIKELY(pGicCpu->idxRunningPriority))
     3846            {
     3847                LogFlowFunc(("Restoring interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
     3848                             pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority],
     3849                             pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority - 1],
     3850                             pGicCpu->idxRunningPriority, pGicCpu->idxRunningPriority - 1));
     3851                pGicCpu->idxRunningPriority--;
     3852            }
     3853            rcStrict = gicReDistUpdateIrqState(pGicDev, pVCpu);
     3854#endif
    13213855            break;
    13223856        }
     
    13253859            break;
    13263860        case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
    1327             pThis->bBinaryPointGrp1 = (uint8_t)ARMV8_ICC_BPR1_EL1_AARCH64_BINARYPOINT_GET(u64Value);
     3861            pGicCpu->bBinaryPointGrp1 = (uint8_t)ARMV8_ICC_BPR1_EL1_AARCH64_BINARYPOINT_GET(u64Value);
    13283862            break;
    13293863        case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
    1330             u64Value &= ARMV8_ICC_CTLR_EL1_RW;
     3864            pGicCpu->uIccCtlr &= ARMV8_ICC_CTLR_EL1_RW;
    13313865            /** @todo */
    13323866            break;
     
    13353869            break;
    13363870        case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
    1337             ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE));
     3871            pGicCpu->fIrqGrp0Enabled = RT_BOOL(u64Value & ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE);
    13383872            break;
    13393873        case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
    1340             ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE));
     3874            pGicCpu->fIrqGrp1Enabled = RT_BOOL(u64Value & ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE);
    13413875            break;
    13423876        default:
     
    13463880
    13473881    PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
    1348     return VINF_SUCCESS;
     3882    return rcStrict;
     3883}
     3884
     3885
     3886/**
     3887 * Initializes the GIC distributor state.
     3888 *
     3889 * @param   pDevIns     The device instance.
     3890 */
     3891DECLHIDDEN(void) gicInit(PPDMDEVINS pDevIns)
     3892{
     3893    LogFlowFunc(("\n"));
     3894    PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
     3895    RT_ZERO(pGicDev->bmIntrGroup);
     3896    RT_ZERO(pGicDev->bmIntrConfig);
     3897    RT_ZERO(pGicDev->bmIntrEnabled);
     3898    RT_ZERO(pGicDev->bmIntrPending);
     3899    RT_ZERO(pGicDev->bmIntrActive);
     3900    RT_ZERO(pGicDev->abIntrPriority);
     3901    RT_ZERO(pGicDev->au32IntrRouting);
     3902    RT_ZERO(pGicDev->bmIntrRoutingMode);
     3903    pGicDev->fIrqGrp0Enabled    = false;
     3904    pGicDev->fIrqGrp1Enabled    = false;
     3905    pGicDev->fAffRoutingEnabled = true; /* GICv2 backwards compatibility is not implemented, so this is RA1/WI. */
     3906}
     3907
     3908
     3909/**
     3910 * Initialies the GIC redistributor and CPU interface state.
     3911 *
     3912 * @param   pDevIns     The device instance.
     3913 * @param   pVCpu       The cross context virtual CPU structure.
     3914 */
     3915DECLHIDDEN(void) gicInitCpu(PPDMDEVINS pDevIns, PVMCPUCC pVCpu)
     3916{
     3917    LogFlowFunc(("[%u]\n", pVCpu->idCpu));
     3918    PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
     3919    PGICCPU pGicCpu = &pVCpu->gic.s;
     3920    RT_ZERO(pGicCpu->bmIntrGroup);
     3921    RT_ZERO(pGicCpu->bmIntrConfig);
     3922    RT_ZERO(pGicCpu->bmIntrEnabled);
     3923    RT_ZERO(pGicCpu->bmIntrPending);
     3924    RT_ZERO(pGicCpu->bmIntrActive);
     3925    RT_ZERO(pGicCpu->abIntrPriority);
     3926    pGicCpu->fRegWritePending = false;
     3927
     3928    /* SGIs are always edge-triggered, writes to GICR_ICFGR0 are to be ignored. */
     3929    pGicCpu->bmIntrConfig[0] = 0xaaaaaaaa;
     3930
     3931    pGicCpu->uIccCtlr = ARMV8_ICC_CTLR_EL1_AARCH64_PMHE
     3932                      | ARMV8_ICC_CTLR_EL1_AARCH64_PRIBITS_SET(4)
     3933                      | ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_SET(ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_16BITS)
     3934                      | (pGicDev->fRangeSelSupport ? ARMV8_ICC_CTLR_EL1_AARCH64_RSS : 0);
     3935
     3936    memset((void *)&pGicCpu->abRunningPriorities[0], 0xff, sizeof(pGicCpu->abRunningPriorities));
     3937    pGicCpu->idxRunningPriority = 0;
     3938    pGicCpu->bInterruptPriority = 0; /* Means no interrupt gets through to the PE. */
     3939    pGicCpu->fIrqGrp0Enabled    = false;
     3940    pGicCpu->fIrqGrp1Enabled    = false;
     3941
     3942    /* The binary point register are undefined on reset, initialized
     3943       with arbitrarily chosen values in our implementation. */
     3944    pGicCpu->bBinaryPointGrp0 = 3;
     3945    pGicCpu->bBinaryPointGrp1 = 3;
     3946}
     3947
     3948
     3949/**
     3950 * Initializes per-VM GIC to the state following a power-up or hardware
     3951 * reset.
     3952 *
     3953 * @param   pVM     The cross context VM structure.
     3954 */
     3955DECLHIDDEN(void) gicReset(PPDMDEVINS pDevIns)
     3956{
     3957    LogFlowFunc(("\n"));
     3958    gicInit(pDevIns);
    13493959}
    13503960
     
    13563966 * @param   pVCpu               The cross context virtual CPU structure.
    13573967 */
    1358 DECLHIDDEN(void) gicResetCpu(PVMCPUCC pVCpu)
    1359 {
    1360     LogFlowFunc(("GIC%u\n", pVCpu->idCpu));
     3968DECLHIDDEN(void) gicResetCpu(PPDMDEVINS pDevIns, PVMCPUCC pVCpu)
     3969{
     3970    LogFlowFunc(("[%u]\n", pVCpu->idCpu));
    13613971    VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
    1362 
    1363     memset((void *)&pVCpu->gic.s.abRunningPriorities[0], 0xff, sizeof(pVCpu->gic.s.abRunningPriorities));
    1364     pVCpu->gic.s.idxRunningPriority = 0;
    1365     pVCpu->gic.s.bInterruptPriority = 0; /* Means no interrupt gets through to the PE. */
     3972    gicInitCpu(pDevIns, pVCpu);
    13663973}
    13673974
     
    13763983    Assert(cb == 4); RT_NOREF_PV(cb);
    13773984
    1378     PVMCPUCC pVCpu    = PDMDevHlpGetVMCPU(pDevIns);
    1379     uint16_t offReg   = off & 0xfffc;
    1380     uint32_t uValue   = 0;
     3985    PVMCPUCC pVCpu  = PDMDevHlpGetVMCPU(pDevIns);
     3986    uint16_t offReg = off & 0xfffc;
     3987    uint32_t uValue = 0;
    13813988
    13823989    STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
    13833990
    1384     VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(gicDistRegisterRead(pDevIns, pVCpu, offReg, &uValue));
     3991    VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(gicDistReadRegister(pDevIns, pVCpu, offReg, &uValue));
    13853992    *(uint32_t *)pv = uValue;
    13863993
    1387     Log2(("GIC%u: gicDistMmioRead: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
     3994    LogFlowFunc(("[%u]: offReg=%#RX16 (%s) uValue=%#RX32\n", pVCpu->idCpu, offReg, gicDistGetRegDescription(offReg), uValue));
    13883995    return rc;
    13893996}
     
    13994006    Assert(cb == 4); RT_NOREF_PV(cb);
    14004007
    1401     PVMCPUCC pVCpu    = PDMDevHlpGetVMCPU(pDevIns);
    1402     uint16_t offReg   = off & 0xfffc;
    1403     uint32_t uValue   = *(uint32_t *)pv;
     4008    PVMCPUCC pVCpu  = PDMDevHlpGetVMCPU(pDevIns);
     4009    uint16_t offReg = off & 0xfffc;
     4010    uint32_t uValue = *(uint32_t *)pv;
    14044011
    14054012    STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
    1406 
    1407     Log2(("GIC%u: gicDistMmioWrite: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
    1408     return gicDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
     4013    LogFlowFunc(("[%u]: offReg=%#RX16 (%s) uValue=%#RX32\n", pVCpu->idCpu, offReg, gicDistGetRegDescription(offReg), uValue));
     4014
     4015    return gicDistWriteRegister(pDevIns, pVCpu, offReg, uValue);
    14094016}
    14104017
     
    14244031     * and the redistributors are adjacent.
    14254032     */
    1426     uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
     4033    uint32_t const idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
    14274034    off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
    14284035
    14294036    PVMCC pVM = PDMDevHlpGetVM(pDevIns);
    14304037    Assert(idReDist < pVM->cCpus);
    1431     PVMCPUCC pVCpu = pVM->apCpusR3[idReDist];
     4038    PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[idReDist];
    14324039
    14334040    STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
    14344041
    14354042    /* Redistributor or SGI/PPI frame? */
    1436     uint16_t offReg = off & 0xfffc;
    1437     uint32_t uValue = 0;
     4043    uint16_t const offReg = off & 0xfffc;
     4044    uint32_t       uValue = 0;
    14384045    VBOXSTRICTRC rcStrict;
    14394046    if (off < GIC_REDIST_REG_FRAME_SIZE)
    1440         rcStrict = gicReDistRegisterRead(pDevIns, pVCpu, idReDist, offReg, &uValue);
     4047        rcStrict = gicReDistReadRegister(pDevIns, pVCpu, idReDist, offReg, &uValue);
    14414048    else
    1442         rcStrict = gicReDistSgiPpiRegisterRead(pDevIns, pVCpu, offReg, &uValue);
     4049        rcStrict = gicReDistReadSgiPpiRegister(pDevIns, pVCpu, offReg, &uValue);
    14434050
    14444051    *(uint32_t *)pv = uValue;
    1445     Log2(("GICReDist%u: gicReDistMmioRead: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",
    1446           pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));
     4052    LogFlowFunc(("[%u]: off=%RGp idReDist=%u offReg=%#RX16 (%s) uValue=%#RX32 -> %Rrc\n", pVCpu->idCpu, off, idReDist, offReg,
     4053                 gicReDistGetRegDescription(offReg), uValue, VBOXSTRICTRC_VAL(rcStrict)));
    14474054    return rcStrict;
    14484055}
     
    14654072     * and the redistributors are adjacent.
    14664073     */
    1467     uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
     4074    uint32_t const idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
    14684075    off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
    14694076
    1470     PVMCC pVM = PDMDevHlpGetVM(pDevIns);
     4077    PCVMCC pVM = PDMDevHlpGetVM(pDevIns);
    14714078    Assert(idReDist < pVM->cCpus);
    1472     PVMCPUCC pVCpu = pVM->apCpusR3[idReDist];
     4079    PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[idReDist];
    14734080
    14744081    STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
    14754082
    14764083    /* Redistributor or SGI/PPI frame? */
    1477     uint16_t offReg = off & 0xfffc;
     4084    uint16_t const offReg = off & 0xfffc;
    14784085    VBOXSTRICTRC rcStrict;
    14794086    if (off < GIC_REDIST_REG_FRAME_SIZE)
    1480         rcStrict = gicReDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
     4087        rcStrict = gicReDistWriteRegister(pDevIns, pVCpu, offReg, uValue);
    14814088    else
    1482         rcStrict = gicReDistSgiPpiRegisterWrite(pDevIns, pVCpu, offReg, uValue);
    1483 
    1484     Log2(("GICReDist%u: gicReDistMmioWrite: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",
    1485           pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));
     4089        rcStrict = gicReDistWriteSgiPpiRegister(pDevIns, pVCpu, offReg, uValue);
     4090
     4091    LogFlowFunc(("[%u]: off=%RGp idReDist=%u offReg=%#RX16 (%s) uValue=%#RX32 -> %Rrc\n", pVCpu->idCpu, off, idReDist, offReg,
     4092                 gicReDistGetRegDescription(offReg), uValue, VBOXSTRICTRC_VAL(rcStrict)));
    14864093    return rcStrict;
    14874094}
     
    14894096
    14904097#ifndef IN_RING3
    1491 
    14924098/**
    14934099 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
     
    15004106}
    15014107#endif /* !IN_RING3 */
     4108
    15024109
    15034110/**
     
    15744181};
    15754182
     4183
    15764184/**
    15774185 * The VirtualBox GIC backend.
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