Index: trunk/src/VBox/VMM/VMMAll/GICAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/GICAll.cpp	(revision 99725)
+++ trunk/src/VBox/VMM/VMMAll/GICAll.cpp	(revision 99734)
@@ -51,4 +51,146 @@
 *   Global Variables                                                                                                             *
 *********************************************************************************************************************************/
+
+/**
+ * Sets the interrupt pending force-flag and pokes the EMT if required.
+ *
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   enmType         The IRQ type.
+ */
+static void gicSetInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
+{
+    Assert(fIrq || fFiq);
+
+#ifdef IN_RING3
+    /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
+    Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
+#endif
+
+    if (fIrq)
+        VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_IRQ);
+    if (fFiq)
+        VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_FIQ);
+
+    /*
+     * We need to wake up the target CPU if we're not on EMT.
+     */
+    /** @todo We could just use RTThreadNativeSelf() here, couldn't we? */
+#if defined(IN_RING0)
+    PVMCC   pVM   = pVCpu->CTX_SUFF(pVM);
+    VMCPUID idCpu = pVCpu->idCpu;
+    if (VMMGetCpuId(pVM) != idCpu)
+    {
+        switch (VMCPU_GET_STATE(pVCpu))
+        {
+            case VMCPUSTATE_STARTED_EXEC:
+                Log7Func(("idCpu=%u VMCPUSTATE_STARTED_EXEC\n", idCpu));
+                GVMMR0SchedPokeNoGVMNoLock(pVM, idCpu);
+                break;
+
+            case VMCPUSTATE_STARTED_HALTED:
+                Log7Func(("idCpu=%u VMCPUSTATE_STARTED_HALTED\n", idCpu));
+                GVMMR0SchedWakeUpNoGVMNoLock(pVM, idCpu);
+                break;
+
+            default:
+                Log7Func(("idCpu=%u enmState=%d\n", idCpu, pVCpu->enmState));
+                break; /* nothing to do in other states. */
+        }
+    }
+#elif defined(IN_RING3)
+    PVMCC   pVM   = pVCpu->CTX_SUFF(pVM);
+    VMCPUID idCpu = pVCpu->idCpu;
+    if (VMMGetCpuId(pVM) != idCpu)
+    {
+        Log7Func(("idCpu=%u enmState=%d\n", idCpu, pVCpu->enmState));
+        VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_POKE);
+    }
+#endif
+}
+
+
+/**
+ * Clears the interrupt pending force-flag.
+ *
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   fIrq            Flag whether to clear the IRQ flag.
+ * @param   fFiq            Flag whether to clear the FIQ flag.
+ */
+DECLINLINE(void) gicClearInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
+{
+    Assert(fIrq || fFiq);
+
+#ifdef IN_RING3
+    /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
+    Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
+#endif
+
+    if (fIrq)
+        VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_IRQ);
+    if (fFiq)
+        VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_FIQ);
+}
+
+
+/**
+ * Updates the internal IRQ state and sets or clears the appropirate force action flags.
+ *
+ * @returns Strict VBox status code.
+ * @param   pThis           The GIC re-distributor state for the associated vCPU.
+ * @param   pVCpu           The cross context virtual CPU structure.
+ */
+static VBOXSTRICTRC gicReDistUpdateIrqState(PGICCPU pThis, PVMCPUCC pVCpu)
+{
+    /* Read the interrupt state. */
+    uint32_t u32RegIGrp0  = ASMAtomicReadU32(&pThis->u32RegIGrp0);
+    uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
+    uint32_t bmIntPending = ASMAtomicReadU32(&pThis->bmIntPending);
+    uint32_t bmIntActive  = ASMAtomicReadU32(&pThis->bmIntActive);
+    bool fIrqGrp0Enabled  = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled);
+    bool fIrqGrp1Enabled  = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled);
+
+    /* Is anything enabled at all? */
+    uint32_t bmIntForward = (bmIntPending & bmIntEnabled) & ~bmIntActive; /* Exclude the currently active interrupt. */
+    if (bmIntForward)
+    {
+        /* Determine whether we have to assert the IRQ or FIQ line. */
+        bool fIrq = RT_BOOL(bmIntForward & u32RegIGrp0) && fIrqGrp1Enabled;
+        bool fFiq = RT_BOOL(bmIntForward & ~u32RegIGrp0) && fIrqGrp0Enabled;
+
+        if (fIrq || fFiq)
+            gicSetInterruptFF(pVCpu, fIrq, fFiq);
+
+        if (!fIrq || !fFiq)
+            gicClearInterruptFF(pVCpu, !fIrq, !fFiq);
+    }
+    else
+        gicClearInterruptFF(pVCpu, true /*fIrq*/, true /*fFiq*/);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Sets the given SGI/PPI interrupt ID on the re-distributor of the given vCPU.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   uIntId          The SGI/PPI interrupt identifier.
+ * @param   fAsserted       Flag whether the SGI/PPI interrupt is asserted or not.
+ */
+static int gicReDistInterruptSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
+{
+    PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
+
+    /* Update the interrupts pending state. */
+    if (fAsserted)
+        ASMAtomicOrU32(&pThis->bmIntPending, RT_BIT_32(uIntId));
+    else
+        ASMAtomicAndU32(&pThis->bmIntPending, ~RT_BIT_32(uIntId));
+
+    return VBOXSTRICTRC_VAL(gicReDistUpdateIrqState(pThis, pVCpu));
+}
+
+
 /**
  * Reads a GIC distributor register.
@@ -68,5 +210,5 @@
     {
         case GIC_DIST_REG_TYPER_OFF:
-            *puValue =   GIC_DIST_REG_TYPER_NUM_ITLINES_SET(0)  /** @todo 32 SPIs for now. */
+            *puValue =   GIC_DIST_REG_TYPER_NUM_ITLINES_SET(1)  /** @todo 32 SPIs for now. */
                        | GIC_DIST_REG_TYPER_NUM_PES_SET(0)      /* 1 PE */
                        /*| GIC_DIST_REG_TYPER_ESPI*/            /** @todo */
@@ -136,5 +278,69 @@
 
 /**
- * Writes a GIC redistributor register.
+ * Reads a GIC redistributor SGI/PPI frame register.
+ *
+ * @returns VBox status code.
+ * @param   pDevIns         The device instance.
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   offReg          The offset of the register being read.
+ * @param   puValue         Where to store the register value.
+ */
+DECLINLINE(VBOXSTRICTRC) gicReDistSgiPpiRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
+{
+    VMCPU_ASSERT_EMT(pVCpu);
+    RT_NOREF(pDevIns);
+
+    PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
+    switch (offReg)
+    {
+        case GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF:
+        case GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF:
+            *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
+            break;
+        case GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF:
+        case GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF:
+            *puValue = ASMAtomicReadU32(&pThis->bmIntPending);
+            break;
+        case GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF:
+        case GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF:
+            *puValue = ASMAtomicReadU32(&pThis->bmIntActive);
+            break;
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START +  4:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START +  8:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 12:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 16:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 20:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 24:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 28:
+        {
+            /* Figure out the register whch is written. */
+            uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START;
+            Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
+
+            uint32_t u32Value = 0;
+            for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
+                u32Value |= pThis->abIntPriority[i] << ((i - idxPrio) * 8);
+
+            *puValue = u32Value;
+            break;
+        }
+        case GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF:
+            *puValue = ASMAtomicReadU32(&pThis->u32RegICfg0);
+            break;
+        case GIC_REDIST_SGI_PPI_REG_ICFGR1_OFF:
+            *puValue = ASMAtomicReadU32(&pThis->u32RegICfg1);
+            break;
+        default:
+            AssertReleaseFailed();
+            *puValue = 0;
+    }
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Writes a GIC redistributor frame register.
  *
  * @returns Strict VBox status code.
@@ -150,4 +356,83 @@
 
     VBOXSTRICTRC rcStrict = VINF_SUCCESS;
+    return rcStrict;
+}
+
+
+/**
+ * Writes a GIC redistributor SGI/PPI frame register.
+ *
+ * @returns Strict VBox status code.
+ * @param   pDevIns         The device instance.
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   offReg          The offset of the register being written.
+ * @param   uValue          The register value.
+ */
+DECLINLINE(VBOXSTRICTRC) gicReDistSgiPpiRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
+{
+    VMCPU_ASSERT_EMT(pVCpu);
+    RT_NOREF(pDevIns);
+
+    PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
+    VBOXSTRICTRC rcStrict = VINF_SUCCESS;
+    switch (offReg)
+    {
+        case GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF:
+            ASMAtomicOrU32(&pThis->u32RegIGrp0, uValue);
+            rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
+            break;
+        case GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF:
+            ASMAtomicOrU32(&pThis->bmIntEnabled, uValue);
+            rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
+            break;
+        case GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF:
+            ASMAtomicAndU32(&pThis->bmIntEnabled, ~uValue);
+            rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
+            break;
+        case GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF:
+            ASMAtomicOrU32(&pThis->bmIntPending, uValue);
+            rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
+            break;
+        case GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF:
+            ASMAtomicAndU32(&pThis->bmIntPending, ~uValue);
+            rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
+            break;
+        case GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF:
+            ASMAtomicOrU32(&pThis->bmIntActive, uValue);
+            rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
+            break;
+        case GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF:
+            ASMAtomicAndU32(&pThis->bmIntActive, ~uValue);
+            rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
+            break;
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START +  4:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START +  8:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 12:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 16:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 20:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 24:
+        case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 28:
+        {
+            /* Figure out the register whch is written. */
+            uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START;
+            Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
+            for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
+            {
+                pThis->abIntPriority[i] = (uint8_t)(uValue & 0xff);
+                uValue >>= 8;
+            }
+            break;
+        }
+        case GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF:
+            ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
+            break;
+        case GIC_REDIST_SGI_PPI_REG_ICFGR1_OFF:
+            ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
+            break;
+        default:
+            AssertReleaseFailed();
+    }
+
     return rcStrict;
 }
@@ -171,4 +456,107 @@
 
     *pu64Value = 0;
+    PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
+    switch (u32Reg)
+    {
+        case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
+            *pu64Value = pThis->bInterruptPriority;
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_EOIR0_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_HPPIR0_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
+            *pu64Value = pThis->bBinaryPointGrp0 & 0x7;
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP0R1_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP0R2_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP1R1_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP1R2_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP1R3_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_DIR_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_ASGI1R_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
+        {
+            /** @todo Figure out the highest priority interrupt. */
+            uint32_t bmPending = ASMAtomicReadU32(&pThis->bmIntPending);
+            int32_t idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
+            if (idxIntPending > -1)
+            {
+                /* Mark the interrupt as active. */
+                ASMAtomicOrU32(&pThis->bmIntActive, idxIntPending);
+                *pu64Value = idxIntPending;
+            }
+            else
+                *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
+            break;
+        }
+        case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
+            *pu64Value = pThis->bBinaryPointGrp1 & 0x7;
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
+            *pu64Value =   ARMV8_ICC_CTLR_EL1_AARCH64_PMHE
+                         | ARMV8_ICC_CTLR_EL1_AARCH64_PRIBITS_SET(4)
+                         | ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_SET(ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_16BITS);
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
+            *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled) ? ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE : 0;
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
+            *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled) ? ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE : 0;
+            break;
+        default:
+            AssertReleaseFailed();
+            break;
+    }
+
     LogFlowFunc(("pVCpu=%p u32Reg=%#x pu64Value=%RX64\n", pVCpu, u32Reg, *pu64Value));
     return VINF_SUCCESS;
@@ -193,5 +581,145 @@
     LogFlowFunc(("pVCpu=%p u32Reg=%#x u64Value=%RX64\n", pVCpu, u32Reg, u64Value));
 
+    PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
+    switch (u32Reg)
+    {
+        case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
+            ASMAtomicWriteU8(&pThis->bInterruptPriority, (uint8_t)u64Value);
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_EOIR0_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_HPPIR0_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
+            pThis->bBinaryPointGrp0 = (uint8_t)(u64Value & 0x7);
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
+            /** @todo */
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP0R1_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP0R2_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1:
+            /** @todo */
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP1R1_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP1R2_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_AP1R3_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_DIR_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_ASGI1R_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
+        {
+            /* Mark the interrupt as not active anymore, though it might still be pending. */
+            Assert(u64Value < GIC_INTID_RANGE_SPI_START);
+            ASMAtomicAndU32(&pThis->bmIntActive, (uint32_t)u64Value);
+            break;
+        }
+        case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
+            pThis->bBinaryPointGrp0 = (uint8_t)(u64Value & 0x7);
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
+            u64Value &= ARMV8_ICC_CTLR_EL1_RW;
+            /** @todo */
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
+            AssertReleaseFailed();
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
+            ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE));
+            break;
+        case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
+            ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE));
+            break;
+        default:
+            AssertReleaseFailed();
+            break;
+    }
+
     return VINF_SUCCESS;
+}
+
+
+/**
+ * Sets the specified shared peripheral interrupt starting.
+ *
+ * @returns VBox status code.
+ * @param   pVM                 The cross context virtual machine structure.
+ * @param   uIntId              The SPI ID (minus GIC_INTID_RANGE_SPI_START) to assert/de-assert.
+ * @param   fAsserted           Flag whether to mark the interrupt as asserted/de-asserted.
+ */
+VMM_INT_DECL(int) GICSpiSet(PVMCC pVM, uint32_t uIntId, bool fAsserted)
+{
+    RT_NOREF(pVM, uIntId, fAsserted);
+    AssertReleaseFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * Sets the specified private peripheral interrupt starting.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu               The cross context virtual CPU structure.
+ * @param   uIntId              The PPI ID (minus GIC_INTID_RANGE_PPI_START) to assert/de-assert.
+ * @param   fAsserted           Flag whether to mark the interrupt as asserted/de-asserted.
+ */
+VMM_INT_DECL(int) GICPpiSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
+{
+    AssertReturn(uIntId >= 0 && uIntId <= (GIC_INTID_RANGE_PPI_LAST - GIC_INTID_RANGE_PPI_START), VERR_INVALID_PARAMETER);
+    return gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_PPI_START, fAsserted);
+}
+
+
+/**
+ * Sets the specified software generated interrupt starting.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu               The cross context virtual CPU structure.
+ * @param   uIntId              The PPI ID (minus GIC_INTID_RANGE_SGI_START) to assert/de-assert.
+ * @param   fAsserted           Flag whether to mark the interrupt as asserted/de-asserted.
+ */
+VMM_INT_DECL(int) GICSgiSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
+{
+    AssertReturn(uIntId >= 0 && uIntId <= (GIC_INTID_RANGE_SGI_LAST - GIC_INTID_RANGE_SGI_START), VERR_INVALID_PARAMETER);
+    return gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_SGI_START, fAsserted);
 }
 
@@ -216,6 +744,6 @@
 {
     NOREF(pvUser);
-    //Assert(!(off & 0xf));
-    //Assert(cb == 4); RT_NOREF_PV(cb);
+    Assert(!(off & 0x3));
+    Assert(cb == 4); RT_NOREF_PV(cb);
 
     PVMCPUCC pVCpu    = PDMDevHlpGetVMCPU(pDevIns);
@@ -239,6 +767,6 @@
 {
     NOREF(pvUser);
-    //Assert(!(off & 0xf));
-    //Assert(cb == 4); RT_NOREF_PV(cb);
+    Assert(!(off & 0x3));
+    Assert(cb == 4); RT_NOREF_PV(cb);
 
     PVMCPUCC pVCpu    = PDMDevHlpGetVMCPU(pDevIns);
@@ -259,18 +787,31 @@
 {
     NOREF(pvUser);
-    //Assert(!(off & 0xf));
-    //Assert(cb == 4); RT_NOREF_PV(cb);
+    Assert(!(off & 0x3));
+    Assert(cb == 4); RT_NOREF_PV(cb);
 
     PVMCPUCC pVCpu    = PDMDevHlpGetVMCPU(pDevIns);
-    uint16_t offReg   = off & 0xfffc;
-    uint32_t uValue   = 0;
 
     STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
 
-    VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(gicReDistRegisterRead(pDevIns, pVCpu, offReg, &uValue));
+    /*
+     * Determine the redistributor being targeted. Each redistributor takes GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE bytes
+     * and the redistributors are adjacent.
+     */
+    uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
+    off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
+
+    /* Redistributor or SGI/PPI frame? */
+    uint16_t offReg = off & 0xfffc;
+    uint32_t uValue = 0;
+    VBOXSTRICTRC rcStrict;
+    if (off < GIC_REDIST_REG_FRAME_SIZE)
+        rcStrict = gicReDistRegisterRead(pDevIns, pVCpu, offReg, &uValue);
+    else
+        rcStrict = gicReDistSgiPpiRegisterRead(pDevIns, pVCpu, offReg, &uValue);
+
     *(uint32_t *)pv = uValue;
-
-    Log2(("GIC%u: gicReDistMmioRead: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
-    return rc;
+    Log2(("GICReDist%u: gicReDistMmioRead: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",
+          pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));
+    return rcStrict;
 }
 
@@ -282,15 +823,30 @@
 {
     NOREF(pvUser);
-    //Assert(!(off & 0xf));
-    //Assert(cb == 4); RT_NOREF_PV(cb);
-
-    PVMCPUCC pVCpu    = PDMDevHlpGetVMCPU(pDevIns);
-    uint16_t offReg   = off & 0xfffc;
-    uint32_t uValue   = *(uint32_t *)pv;
+    Assert(!(off & 0x3));
+    Assert(cb == 4); RT_NOREF_PV(cb);
+
+    PVMCPUCC pVCpu  = PDMDevHlpGetVMCPU(pDevIns);
+    uint32_t uValue = *(uint32_t *)pv;
 
     STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
 
-    Log2(("GIC%u: gicReDistMmioWrite: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
-    return gicReDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
+    /*
+     * Determine the redistributor being targeted. Each redistributor takes GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE bytes
+     * and the redistributors are adjacent.
+     */
+    uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
+    off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
+
+    /* Redistributor or SGI/PPI frame? */
+    uint16_t offReg = off & 0xfffc;
+    VBOXSTRICTRC rcStrict;
+    if (off < GIC_REDIST_REG_FRAME_SIZE)
+        rcStrict = gicReDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
+    else
+        rcStrict = gicReDistSgiPpiRegisterWrite(pDevIns, pVCpu, offReg, uValue);
+
+    Log2(("GICReDist%u: gicReDistMmioWrite: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",
+          pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));
+    return rcStrict;
 }
 
Index: trunk/src/VBox/VMM/include/GICInternal.h
===================================================================
--- trunk/src/VBox/VMM/include/GICInternal.h	(revision 99725)
+++ trunk/src/VBox/VMM/include/GICInternal.h	(revision 99734)
@@ -86,4 +86,43 @@
 typedef struct GICCPU
 {
+    /** @name The per vCPU redistributor data is kept here.
+     * @{ */
+
+    /** @name Physical LPI register state.
+     * @{ */
+    /** @} */
+
+    /** @name SGI and PPI redistributor register state.
+     * @{ */
+    /** Interrupt Group 0 Register. */
+    volatile uint32_t           u32RegIGrp0;
+    /** Interrupt Configuration Register 0. */
+    volatile uint32_t           u32RegICfg0;
+    /** Interrupt Configuration Register 1. */
+    volatile uint32_t           u32RegICfg1;
+    /** Interrupt enabled bitmap. */
+    volatile uint32_t           bmIntEnabled;
+    /** Current interrupt pending state. */
+    volatile uint32_t           bmIntPending;
+    /** The current interrupt active state. */
+    volatile uint32_t           bmIntActive;
+    /** The interrupt priority for each of the SGI/PPIs */
+    volatile uint8_t            abIntPriority[GIC_INTID_RANGE_PPI_LAST + 1];
+    /** @} */
+
+    /** @name ICC system register state.
+     * @{ */
+    /** Flag whether group 0 interrupts are currently enabled. */
+    volatile bool               fIrqGrp0Enabled;
+    /** Flag whether group 1 interrupts are currently enabled. */
+    volatile bool               fIrqGrp1Enabled;
+    /** The current interrupt priority, only interrupts with a higher priority get signalled. */
+    volatile uint8_t            bInterruptPriority;
+    /** The interrupt controller Binary Point Register for Group 0 interrupts. */
+    uint8_t                     bBinaryPointGrp0;
+    /** The interrupt controller Binary Point Register for Group 1 interrupts. */
+    uint8_t                     bBinaryPointGrp1;
+    /** @} */
+
     /** @name Log Max counters
      * @{ */
