1e69954b9Spbrook /* 29ee6e8bbSpbrook * ARM Generic/Distributed Interrupt Controller 3e69954b9Spbrook * 49ee6e8bbSpbrook * Copyright (c) 2006-2007 CodeSourcery. 5e69954b9Spbrook * Written by Paul Brook 6e69954b9Spbrook * 78e31bf38SMatthew Fernandez * This code is licensed under the GPL. 8e69954b9Spbrook */ 9e69954b9Spbrook 109ee6e8bbSpbrook /* This file contains implementation code for the RealView EB interrupt 110d256bdcSPeter Maydell * controller, MPCore distributed interrupt controller and ARMv7-M 120d256bdcSPeter Maydell * Nested Vectored Interrupt Controller. 130d256bdcSPeter Maydell * It is compiled in two ways: 140d256bdcSPeter Maydell * (1) as a standalone file to produce a sysbus device which is a GIC 150d256bdcSPeter Maydell * that can be used on the realview board and as one of the builtin 160d256bdcSPeter Maydell * private peripherals for the ARM MP CPUs (11MPCore, A9, etc) 170d256bdcSPeter Maydell * (2) by being directly #included into armv7m_nvic.c to produce the 180d256bdcSPeter Maydell * armv7m_nvic device. 190d256bdcSPeter Maydell */ 20e69954b9Spbrook 218ef94f0bSPeter Maydell #include "qemu/osdep.h" 2283c9f4caSPaolo Bonzini #include "hw/sysbus.h" 2347b43a1fSPaolo Bonzini #include "gic_internal.h" 24da34e65cSMarkus Armbruster #include "qapi/error.h" 25dfc08079SAndreas Färber #include "qom/cpu.h" 2603dd024fSPaolo Bonzini #include "qemu/log.h" 272531088fSHollis Blanchard #include "trace.h" 285d721b78SAlexander Graf #include "sysemu/kvm.h" 29386e2955SPeter Maydell 3068bf93ceSAlex Bennée /* #define DEBUG_GIC */ 31e69954b9Spbrook 32e69954b9Spbrook #ifdef DEBUG_GIC 3368bf93ceSAlex Bennée #define DEBUG_GIC_GATE 1 34e69954b9Spbrook #else 3568bf93ceSAlex Bennée #define DEBUG_GIC_GATE 0 36e69954b9Spbrook #endif 37e69954b9Spbrook 3868bf93ceSAlex Bennée #define DPRINTF(fmt, ...) do { \ 3968bf93ceSAlex Bennée if (DEBUG_GIC_GATE) { \ 4068bf93ceSAlex Bennée fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \ 4168bf93ceSAlex Bennée } \ 4268bf93ceSAlex Bennée } while (0) 4368bf93ceSAlex Bennée 443355c360SAlistair Francis static const uint8_t gic_id_11mpcore[] = { 453355c360SAlistair Francis 0x00, 0x00, 0x00, 0x00, 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 463355c360SAlistair Francis }; 473355c360SAlistair Francis 483355c360SAlistair Francis static const uint8_t gic_id_gicv1[] = { 493355c360SAlistair Francis 0x04, 0x00, 0x00, 0x00, 0x90, 0xb3, 0x1b, 0x00, 0x0d, 0xf0, 0x05, 0xb1 503355c360SAlistair Francis }; 513355c360SAlistair Francis 523355c360SAlistair Francis static const uint8_t gic_id_gicv2[] = { 533355c360SAlistair Francis 0x04, 0x00, 0x00, 0x00, 0x90, 0xb4, 0x2b, 0x00, 0x0d, 0xf0, 0x05, 0xb1 542a29ddeeSPeter Maydell }; 552a29ddeeSPeter Maydell 56fae15286SPeter Maydell static inline int gic_get_current_cpu(GICState *s) 57926c4affSPeter Maydell { 58926c4affSPeter Maydell if (s->num_cpu > 1) { 594917cf44SAndreas Färber return current_cpu->cpu_index; 60926c4affSPeter Maydell } 61926c4affSPeter Maydell return 0; 62926c4affSPeter Maydell } 63926c4affSPeter Maydell 644a37e0e4SLuc Michel static inline int gic_get_current_vcpu(GICState *s) 654a37e0e4SLuc Michel { 664a37e0e4SLuc Michel return gic_get_current_cpu(s) + GIC_NCPU; 674a37e0e4SLuc Michel } 684a37e0e4SLuc Michel 69c27a5ba9SFabian Aggeler /* Return true if this GIC config has interrupt groups, which is 70c27a5ba9SFabian Aggeler * true if we're a GICv2, or a GICv1 with the security extensions. 71c27a5ba9SFabian Aggeler */ 72c27a5ba9SFabian Aggeler static inline bool gic_has_groups(GICState *s) 73c27a5ba9SFabian Aggeler { 74c27a5ba9SFabian Aggeler return s->revision == 2 || s->security_extn; 75c27a5ba9SFabian Aggeler } 76c27a5ba9SFabian Aggeler 773dd0471bSLuc Michel static inline bool gic_cpu_ns_access(GICState *s, int cpu, MemTxAttrs attrs) 783dd0471bSLuc Michel { 793dd0471bSLuc Michel return !gic_is_vcpu(cpu) && s->security_extn && !attrs.secure; 803dd0471bSLuc Michel } 813dd0471bSLuc Michel 82e69954b9Spbrook /* TODO: Many places that call this routine could be optimized. */ 83e69954b9Spbrook /* Update interrupt status after enabled or pending bits have been changed. */ 8450491c56SLuc Michel static void gic_update(GICState *s) 85e69954b9Spbrook { 86e69954b9Spbrook int best_irq; 87e69954b9Spbrook int best_prio; 88e69954b9Spbrook int irq; 89dadbb58fSPeter Maydell int irq_level, fiq_level; 909ee6e8bbSpbrook int cpu; 919ee6e8bbSpbrook int cm; 92e69954b9Spbrook 93b95690c9SWei Huang for (cpu = 0; cpu < s->num_cpu; cpu++) { 949ee6e8bbSpbrook cm = 1 << cpu; 959ee6e8bbSpbrook s->current_pending[cpu] = 1023; 96679aa175SFabian Aggeler if (!(s->ctlr & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1)) 9732951860SFabian Aggeler || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) { 989ee6e8bbSpbrook qemu_irq_lower(s->parent_irq[cpu]); 99dadbb58fSPeter Maydell qemu_irq_lower(s->parent_fiq[cpu]); 100235069a3SJohan Karlsson continue; 101e69954b9Spbrook } 102e69954b9Spbrook best_prio = 0x100; 103e69954b9Spbrook best_irq = 1023; 104a32134aaSMark Langsdorf for (irq = 0; irq < s->num_irq; irq++) { 10567ce697aSLuc Michel if (GIC_DIST_TEST_ENABLED(irq, cm) && 10667ce697aSLuc Michel gic_test_pending(s, irq, cm) && 10767ce697aSLuc Michel (!GIC_DIST_TEST_ACTIVE(irq, cm)) && 10867ce697aSLuc Michel (irq < GIC_INTERNAL || GIC_DIST_TARGET(irq) & cm)) { 10967ce697aSLuc Michel if (GIC_DIST_GET_PRIORITY(irq, cpu) < best_prio) { 11067ce697aSLuc Michel best_prio = GIC_DIST_GET_PRIORITY(irq, cpu); 111e69954b9Spbrook best_irq = irq; 112e69954b9Spbrook } 113e69954b9Spbrook } 114e69954b9Spbrook } 115dadbb58fSPeter Maydell 1162531088fSHollis Blanchard if (best_irq != 1023) { 1172531088fSHollis Blanchard trace_gic_update_bestirq(cpu, best_irq, best_prio, 1182531088fSHollis Blanchard s->priority_mask[cpu], s->running_priority[cpu]); 1192531088fSHollis Blanchard } 1202531088fSHollis Blanchard 121dadbb58fSPeter Maydell irq_level = fiq_level = 0; 122dadbb58fSPeter Maydell 123cad065f1SPeter Maydell if (best_prio < s->priority_mask[cpu]) { 1249ee6e8bbSpbrook s->current_pending[cpu] = best_irq; 1259ee6e8bbSpbrook if (best_prio < s->running_priority[cpu]) { 12667ce697aSLuc Michel int group = GIC_DIST_TEST_GROUP(best_irq, cm); 127dadbb58fSPeter Maydell 128dadbb58fSPeter Maydell if (extract32(s->ctlr, group, 1) && 129dadbb58fSPeter Maydell extract32(s->cpu_ctlr[cpu], group, 1)) { 130dadbb58fSPeter Maydell if (group == 0 && s->cpu_ctlr[cpu] & GICC_CTLR_FIQ_EN) { 131dadbb58fSPeter Maydell DPRINTF("Raised pending FIQ %d (cpu %d)\n", 132dadbb58fSPeter Maydell best_irq, cpu); 133dadbb58fSPeter Maydell fiq_level = 1; 1342531088fSHollis Blanchard trace_gic_update_set_irq(cpu, "fiq", fiq_level); 135dadbb58fSPeter Maydell } else { 136dadbb58fSPeter Maydell DPRINTF("Raised pending IRQ %d (cpu %d)\n", 137dadbb58fSPeter Maydell best_irq, cpu); 138dadbb58fSPeter Maydell irq_level = 1; 1392531088fSHollis Blanchard trace_gic_update_set_irq(cpu, "irq", irq_level); 140e69954b9Spbrook } 141e69954b9Spbrook } 142dadbb58fSPeter Maydell } 143dadbb58fSPeter Maydell } 144dadbb58fSPeter Maydell 145dadbb58fSPeter Maydell qemu_set_irq(s->parent_irq[cpu], irq_level); 146dadbb58fSPeter Maydell qemu_set_irq(s->parent_fiq[cpu], fiq_level); 1479ee6e8bbSpbrook } 148e69954b9Spbrook } 149e69954b9Spbrook 150*527d296fSLuc Michel /* Return true if this LR is empty, i.e. the corresponding bit 151*527d296fSLuc Michel * in ELRSR is set. 152*527d296fSLuc Michel */ 153*527d296fSLuc Michel static inline bool gic_lr_entry_is_free(uint32_t entry) 154*527d296fSLuc Michel { 155*527d296fSLuc Michel return (GICH_LR_STATE(entry) == GICH_LR_STATE_INVALID) 156*527d296fSLuc Michel && (GICH_LR_HW(entry) || !GICH_LR_EOI(entry)); 157*527d296fSLuc Michel } 158*527d296fSLuc Michel 159*527d296fSLuc Michel /* Return true if this LR should trigger an EOI maintenance interrupt, i.e. the 160*527d296fSLuc Michel * corrsponding bit in EISR is set. 161*527d296fSLuc Michel */ 162*527d296fSLuc Michel static inline bool gic_lr_entry_is_eoi(uint32_t entry) 163*527d296fSLuc Michel { 164*527d296fSLuc Michel return (GICH_LR_STATE(entry) == GICH_LR_STATE_INVALID) 165*527d296fSLuc Michel && !GICH_LR_HW(entry) && GICH_LR_EOI(entry); 166*527d296fSLuc Michel } 167*527d296fSLuc Michel 1688d999995SChristoffer Dall static void gic_set_irq_11mpcore(GICState *s, int irq, int level, 1698d999995SChristoffer Dall int cm, int target) 1708d999995SChristoffer Dall { 1718d999995SChristoffer Dall if (level) { 17267ce697aSLuc Michel GIC_DIST_SET_LEVEL(irq, cm); 17367ce697aSLuc Michel if (GIC_DIST_TEST_EDGE_TRIGGER(irq) || GIC_DIST_TEST_ENABLED(irq, cm)) { 1748d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 17567ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, target); 1768d999995SChristoffer Dall } 1778d999995SChristoffer Dall } else { 17867ce697aSLuc Michel GIC_DIST_CLEAR_LEVEL(irq, cm); 1798d999995SChristoffer Dall } 1808d999995SChristoffer Dall } 1818d999995SChristoffer Dall 1828d999995SChristoffer Dall static void gic_set_irq_generic(GICState *s, int irq, int level, 1838d999995SChristoffer Dall int cm, int target) 1848d999995SChristoffer Dall { 1858d999995SChristoffer Dall if (level) { 18667ce697aSLuc Michel GIC_DIST_SET_LEVEL(irq, cm); 1878d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 18867ce697aSLuc Michel if (GIC_DIST_TEST_EDGE_TRIGGER(irq)) { 18967ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, target); 1908d999995SChristoffer Dall } 1918d999995SChristoffer Dall } else { 19267ce697aSLuc Michel GIC_DIST_CLEAR_LEVEL(irq, cm); 1938d999995SChristoffer Dall } 1948d999995SChristoffer Dall } 1958d999995SChristoffer Dall 1969ee6e8bbSpbrook /* Process a change in an external IRQ input. */ 197e69954b9Spbrook static void gic_set_irq(void *opaque, int irq, int level) 198e69954b9Spbrook { 199544d1afaSPeter Maydell /* Meaning of the 'irq' parameter: 200544d1afaSPeter Maydell * [0..N-1] : external interrupts 201544d1afaSPeter Maydell * [N..N+31] : PPI (internal) interrupts for CPU 0 202544d1afaSPeter Maydell * [N+32..N+63] : PPI (internal interrupts for CPU 1 203544d1afaSPeter Maydell * ... 204544d1afaSPeter Maydell */ 205fae15286SPeter Maydell GICState *s = (GICState *)opaque; 206544d1afaSPeter Maydell int cm, target; 207544d1afaSPeter Maydell if (irq < (s->num_irq - GIC_INTERNAL)) { 208e69954b9Spbrook /* The first external input line is internal interrupt 32. */ 209544d1afaSPeter Maydell cm = ALL_CPU_MASK; 21069253800SRusty Russell irq += GIC_INTERNAL; 21167ce697aSLuc Michel target = GIC_DIST_TARGET(irq); 212544d1afaSPeter Maydell } else { 213544d1afaSPeter Maydell int cpu; 214544d1afaSPeter Maydell irq -= (s->num_irq - GIC_INTERNAL); 215544d1afaSPeter Maydell cpu = irq / GIC_INTERNAL; 216544d1afaSPeter Maydell irq %= GIC_INTERNAL; 217544d1afaSPeter Maydell cm = 1 << cpu; 218544d1afaSPeter Maydell target = cm; 219544d1afaSPeter Maydell } 220544d1afaSPeter Maydell 22140d22500SChristoffer Dall assert(irq >= GIC_NR_SGIS); 22240d22500SChristoffer Dall 22367ce697aSLuc Michel if (level == GIC_DIST_TEST_LEVEL(irq, cm)) { 224e69954b9Spbrook return; 225544d1afaSPeter Maydell } 226e69954b9Spbrook 2273bc4b52cSMarcin Krzeminski if (s->revision == REV_11MPCORE) { 2288d999995SChristoffer Dall gic_set_irq_11mpcore(s, irq, level, cm, target); 229e69954b9Spbrook } else { 2308d999995SChristoffer Dall gic_set_irq_generic(s, irq, level, cm, target); 231e69954b9Spbrook } 2322531088fSHollis Blanchard trace_gic_set_irq(irq, level, cm, target); 2338d999995SChristoffer Dall 234e69954b9Spbrook gic_update(s); 235e69954b9Spbrook } 236e69954b9Spbrook 2377c0fa108SFabian Aggeler static uint16_t gic_get_current_pending_irq(GICState *s, int cpu, 2387c0fa108SFabian Aggeler MemTxAttrs attrs) 2397c0fa108SFabian Aggeler { 2407c0fa108SFabian Aggeler uint16_t pending_irq = s->current_pending[cpu]; 2417c0fa108SFabian Aggeler 2427c0fa108SFabian Aggeler if (pending_irq < GIC_MAXIRQ && gic_has_groups(s)) { 24386b350f0SLuc Michel int group = gic_test_group(s, pending_irq, cpu); 24486b350f0SLuc Michel 2457c0fa108SFabian Aggeler /* On a GIC without the security extensions, reading this register 2467c0fa108SFabian Aggeler * behaves in the same way as a secure access to a GIC with them. 2477c0fa108SFabian Aggeler */ 2483dd0471bSLuc Michel bool secure = !gic_cpu_ns_access(s, cpu, attrs); 2497c0fa108SFabian Aggeler 2507c0fa108SFabian Aggeler if (group == 0 && !secure) { 2517c0fa108SFabian Aggeler /* Group0 interrupts hidden from Non-secure access */ 2527c0fa108SFabian Aggeler return 1023; 2537c0fa108SFabian Aggeler } 2547c0fa108SFabian Aggeler if (group == 1 && secure && !(s->cpu_ctlr[cpu] & GICC_CTLR_ACK_CTL)) { 2557c0fa108SFabian Aggeler /* Group1 interrupts only seen by Secure access if 2567c0fa108SFabian Aggeler * AckCtl bit set. 2577c0fa108SFabian Aggeler */ 2587c0fa108SFabian Aggeler return 1022; 2597c0fa108SFabian Aggeler } 2607c0fa108SFabian Aggeler } 2617c0fa108SFabian Aggeler return pending_irq; 2627c0fa108SFabian Aggeler } 2637c0fa108SFabian Aggeler 264df92cfa6SPeter Maydell static int gic_get_group_priority(GICState *s, int cpu, int irq) 265df92cfa6SPeter Maydell { 266df92cfa6SPeter Maydell /* Return the group priority of the specified interrupt 267df92cfa6SPeter Maydell * (which is the top bits of its priority, with the number 268df92cfa6SPeter Maydell * of bits masked determined by the applicable binary point register). 269df92cfa6SPeter Maydell */ 270df92cfa6SPeter Maydell int bpr; 271df92cfa6SPeter Maydell uint32_t mask; 272df92cfa6SPeter Maydell 273df92cfa6SPeter Maydell if (gic_has_groups(s) && 274df92cfa6SPeter Maydell !(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) && 27586b350f0SLuc Michel gic_test_group(s, irq, cpu)) { 276fc05a6f2SLuc MICHEL bpr = s->abpr[cpu] - 1; 277fc05a6f2SLuc MICHEL assert(bpr >= 0); 278df92cfa6SPeter Maydell } else { 279df92cfa6SPeter Maydell bpr = s->bpr[cpu]; 280df92cfa6SPeter Maydell } 281df92cfa6SPeter Maydell 282df92cfa6SPeter Maydell /* a BPR of 0 means the group priority bits are [7:1]; 283df92cfa6SPeter Maydell * a BPR of 1 means they are [7:2], and so on down to 284df92cfa6SPeter Maydell * a BPR of 7 meaning no group priority bits at all. 285df92cfa6SPeter Maydell */ 286df92cfa6SPeter Maydell mask = ~0U << ((bpr & 7) + 1); 287df92cfa6SPeter Maydell 28886b350f0SLuc Michel return gic_get_priority(s, irq, cpu) & mask; 289df92cfa6SPeter Maydell } 290df92cfa6SPeter Maydell 29172889c8aSPeter Maydell static void gic_activate_irq(GICState *s, int cpu, int irq) 292e69954b9Spbrook { 29372889c8aSPeter Maydell /* Set the appropriate Active Priority Register bit for this IRQ, 29472889c8aSPeter Maydell * and update the running priority. 29572889c8aSPeter Maydell */ 29672889c8aSPeter Maydell int prio = gic_get_group_priority(s, cpu, irq); 297a1d7b8d8SLuc Michel int min_bpr = gic_is_vcpu(cpu) ? GIC_VIRT_MIN_BPR : GIC_MIN_BPR; 298a1d7b8d8SLuc Michel int preemption_level = prio >> (min_bpr + 1); 29972889c8aSPeter Maydell int regno = preemption_level / 32; 30072889c8aSPeter Maydell int bitno = preemption_level % 32; 301a1d7b8d8SLuc Michel uint32_t *papr = NULL; 30272889c8aSPeter Maydell 303a1d7b8d8SLuc Michel if (gic_is_vcpu(cpu)) { 304a1d7b8d8SLuc Michel assert(regno == 0); 305a1d7b8d8SLuc Michel papr = &s->h_apr[gic_get_vcpu_real_id(cpu)]; 306a1d7b8d8SLuc Michel } else if (gic_has_groups(s) && gic_test_group(s, irq, cpu)) { 307a1d7b8d8SLuc Michel papr = &s->nsapr[regno][cpu]; 3089ee6e8bbSpbrook } else { 309a1d7b8d8SLuc Michel papr = &s->apr[regno][cpu]; 3109ee6e8bbSpbrook } 31172889c8aSPeter Maydell 312a1d7b8d8SLuc Michel *papr |= (1 << bitno); 313a1d7b8d8SLuc Michel 31472889c8aSPeter Maydell s->running_priority[cpu] = prio; 31586b350f0SLuc Michel gic_set_active(s, irq, cpu); 31672889c8aSPeter Maydell } 31772889c8aSPeter Maydell 31872889c8aSPeter Maydell static int gic_get_prio_from_apr_bits(GICState *s, int cpu) 31972889c8aSPeter Maydell { 32072889c8aSPeter Maydell /* Recalculate the current running priority for this CPU based 32172889c8aSPeter Maydell * on the set bits in the Active Priority Registers. 32272889c8aSPeter Maydell */ 32372889c8aSPeter Maydell int i; 324a1d7b8d8SLuc Michel 325a1d7b8d8SLuc Michel if (gic_is_vcpu(cpu)) { 326a1d7b8d8SLuc Michel uint32_t apr = s->h_apr[gic_get_vcpu_real_id(cpu)]; 327a1d7b8d8SLuc Michel if (apr) { 328a1d7b8d8SLuc Michel return ctz32(apr) << (GIC_VIRT_MIN_BPR + 1); 329a1d7b8d8SLuc Michel } else { 330a1d7b8d8SLuc Michel return 0x100; 331a1d7b8d8SLuc Michel } 332a1d7b8d8SLuc Michel } 333a1d7b8d8SLuc Michel 33472889c8aSPeter Maydell for (i = 0; i < GIC_NR_APRS; i++) { 33572889c8aSPeter Maydell uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu]; 33672889c8aSPeter Maydell if (!apr) { 33772889c8aSPeter Maydell continue; 33872889c8aSPeter Maydell } 33972889c8aSPeter Maydell return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1); 34072889c8aSPeter Maydell } 34172889c8aSPeter Maydell return 0x100; 34272889c8aSPeter Maydell } 34372889c8aSPeter Maydell 34472889c8aSPeter Maydell static void gic_drop_prio(GICState *s, int cpu, int group) 34572889c8aSPeter Maydell { 34672889c8aSPeter Maydell /* Drop the priority of the currently active interrupt in the 34772889c8aSPeter Maydell * specified group. 34872889c8aSPeter Maydell * 34972889c8aSPeter Maydell * Note that we can guarantee (because of the requirement to nest 35072889c8aSPeter Maydell * GICC_IAR reads [which activate an interrupt and raise priority] 35172889c8aSPeter Maydell * with GICC_EOIR writes [which drop the priority for the interrupt]) 35272889c8aSPeter Maydell * that the interrupt we're being called for is the highest priority 35372889c8aSPeter Maydell * active interrupt, meaning that it has the lowest set bit in the 35472889c8aSPeter Maydell * APR registers. 35572889c8aSPeter Maydell * 35672889c8aSPeter Maydell * If the guest does not honour the ordering constraints then the 35772889c8aSPeter Maydell * behaviour of the GIC is UNPREDICTABLE, which for us means that 35872889c8aSPeter Maydell * the values of the APR registers might become incorrect and the 35972889c8aSPeter Maydell * running priority will be wrong, so interrupts that should preempt 36072889c8aSPeter Maydell * might not do so, and interrupts that should not preempt might do so. 36172889c8aSPeter Maydell */ 362a1d7b8d8SLuc Michel if (gic_is_vcpu(cpu)) { 363a1d7b8d8SLuc Michel int rcpu = gic_get_vcpu_real_id(cpu); 364a1d7b8d8SLuc Michel 365a1d7b8d8SLuc Michel if (s->h_apr[rcpu]) { 366a1d7b8d8SLuc Michel /* Clear lowest set bit */ 367a1d7b8d8SLuc Michel s->h_apr[rcpu] &= s->h_apr[rcpu] - 1; 368a1d7b8d8SLuc Michel } 369a1d7b8d8SLuc Michel } else { 37072889c8aSPeter Maydell int i; 37172889c8aSPeter Maydell 37272889c8aSPeter Maydell for (i = 0; i < GIC_NR_APRS; i++) { 37372889c8aSPeter Maydell uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu]; 37472889c8aSPeter Maydell if (!*papr) { 37572889c8aSPeter Maydell continue; 37672889c8aSPeter Maydell } 37772889c8aSPeter Maydell /* Clear lowest set bit */ 37872889c8aSPeter Maydell *papr &= *papr - 1; 37972889c8aSPeter Maydell break; 38072889c8aSPeter Maydell } 381a1d7b8d8SLuc Michel } 38272889c8aSPeter Maydell 38372889c8aSPeter Maydell s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu); 384e69954b9Spbrook } 385e69954b9Spbrook 386439badd6SLuc Michel static inline uint32_t gic_clear_pending_sgi(GICState *s, int irq, int cpu) 387e69954b9Spbrook { 388439badd6SLuc Michel int src; 389439badd6SLuc Michel uint32_t ret; 390c5619bf9SFabian Aggeler 391439badd6SLuc Michel if (!gic_is_vcpu(cpu)) { 39240d22500SChristoffer Dall /* Lookup the source CPU for the SGI and clear this in the 39340d22500SChristoffer Dall * sgi_pending map. Return the src and clear the overall pending 39440d22500SChristoffer Dall * state on this CPU if the SGI is not pending from any CPUs. 39540d22500SChristoffer Dall */ 39640d22500SChristoffer Dall assert(s->sgi_pending[irq][cpu] != 0); 39740d22500SChristoffer Dall src = ctz32(s->sgi_pending[irq][cpu]); 39840d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~(1 << src); 39940d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 40086b350f0SLuc Michel gic_clear_pending(s, irq, cpu); 40140d22500SChristoffer Dall } 40240d22500SChristoffer Dall ret = irq | ((src & 0x7) << 10); 40340d22500SChristoffer Dall } else { 404439badd6SLuc Michel uint32_t *lr_entry = gic_get_lr_entry(s, irq, cpu); 405439badd6SLuc Michel src = GICH_LR_CPUID(*lr_entry); 406439badd6SLuc Michel 407439badd6SLuc Michel gic_clear_pending(s, irq, cpu); 408439badd6SLuc Michel ret = irq | (src << 10); 409439badd6SLuc Michel } 410439badd6SLuc Michel 411439badd6SLuc Michel return ret; 412439badd6SLuc Michel } 413439badd6SLuc Michel 414439badd6SLuc Michel uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) 415439badd6SLuc Michel { 416439badd6SLuc Michel int ret, irq; 417439badd6SLuc Michel 418439badd6SLuc Michel /* gic_get_current_pending_irq() will return 1022 or 1023 appropriately 419439badd6SLuc Michel * for the case where this GIC supports grouping and the pending interrupt 420439badd6SLuc Michel * is in the wrong group. 42140d22500SChristoffer Dall */ 422439badd6SLuc Michel irq = gic_get_current_pending_irq(s, cpu, attrs); 423439badd6SLuc Michel trace_gic_acknowledge_irq(gic_get_vcpu_real_id(cpu), irq); 424439badd6SLuc Michel 425439badd6SLuc Michel if (irq >= GIC_MAXIRQ) { 426439badd6SLuc Michel DPRINTF("ACK, no pending interrupt or it is hidden: %d\n", irq); 427439badd6SLuc Michel return irq; 428439badd6SLuc Michel } 429439badd6SLuc Michel 430439badd6SLuc Michel if (gic_get_priority(s, irq, cpu) >= s->running_priority[cpu]) { 431439badd6SLuc Michel DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq); 432439badd6SLuc Michel return 1023; 433439badd6SLuc Michel } 434439badd6SLuc Michel 435439badd6SLuc Michel gic_activate_irq(s, cpu, irq); 436439badd6SLuc Michel 437439badd6SLuc Michel if (s->revision == REV_11MPCORE) { 438439badd6SLuc Michel /* Clear pending flags for both level and edge triggered interrupts. 439439badd6SLuc Michel * Level triggered IRQs will be reasserted once they become inactive. 440439badd6SLuc Michel */ 441439badd6SLuc Michel gic_clear_pending(s, irq, cpu); 442439badd6SLuc Michel ret = irq; 443439badd6SLuc Michel } else { 444439badd6SLuc Michel if (irq < GIC_NR_SGIS) { 445439badd6SLuc Michel ret = gic_clear_pending_sgi(s, irq, cpu); 446439badd6SLuc Michel } else { 44786b350f0SLuc Michel gic_clear_pending(s, irq, cpu); 44840d22500SChristoffer Dall ret = irq; 44940d22500SChristoffer Dall } 45040d22500SChristoffer Dall } 45140d22500SChristoffer Dall 45272889c8aSPeter Maydell gic_update(s); 45340d22500SChristoffer Dall DPRINTF("ACK %d\n", irq); 45440d22500SChristoffer Dall return ret; 455e69954b9Spbrook } 456e69954b9Spbrook 45767ce697aSLuc Michel void gic_dist_set_priority(GICState *s, int cpu, int irq, uint8_t val, 45881508470SFabian Aggeler MemTxAttrs attrs) 4599df90ad0SChristoffer Dall { 46081508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 46167ce697aSLuc Michel if (!GIC_DIST_TEST_GROUP(irq, (1 << cpu))) { 46281508470SFabian Aggeler return; /* Ignore Non-secure access of Group0 IRQ */ 46381508470SFabian Aggeler } 46481508470SFabian Aggeler val = 0x80 | (val >> 1); /* Non-secure view */ 46581508470SFabian Aggeler } 46681508470SFabian Aggeler 4679df90ad0SChristoffer Dall if (irq < GIC_INTERNAL) { 4689df90ad0SChristoffer Dall s->priority1[irq][cpu] = val; 4699df90ad0SChristoffer Dall } else { 4709df90ad0SChristoffer Dall s->priority2[(irq) - GIC_INTERNAL] = val; 4719df90ad0SChristoffer Dall } 4729df90ad0SChristoffer Dall } 4739df90ad0SChristoffer Dall 47467ce697aSLuc Michel static uint32_t gic_dist_get_priority(GICState *s, int cpu, int irq, 47581508470SFabian Aggeler MemTxAttrs attrs) 47681508470SFabian Aggeler { 47767ce697aSLuc Michel uint32_t prio = GIC_DIST_GET_PRIORITY(irq, cpu); 47881508470SFabian Aggeler 47981508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 48067ce697aSLuc Michel if (!GIC_DIST_TEST_GROUP(irq, (1 << cpu))) { 48181508470SFabian Aggeler return 0; /* Non-secure access cannot read priority of Group0 IRQ */ 48281508470SFabian Aggeler } 48381508470SFabian Aggeler prio = (prio << 1) & 0xff; /* Non-secure view */ 48481508470SFabian Aggeler } 48581508470SFabian Aggeler return prio; 48681508470SFabian Aggeler } 48781508470SFabian Aggeler 48881508470SFabian Aggeler static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask, 48981508470SFabian Aggeler MemTxAttrs attrs) 49081508470SFabian Aggeler { 4913dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 49281508470SFabian Aggeler if (s->priority_mask[cpu] & 0x80) { 49381508470SFabian Aggeler /* Priority Mask in upper half */ 49481508470SFabian Aggeler pmask = 0x80 | (pmask >> 1); 49581508470SFabian Aggeler } else { 49681508470SFabian Aggeler /* Non-secure write ignored if priority mask is in lower half */ 49781508470SFabian Aggeler return; 49881508470SFabian Aggeler } 49981508470SFabian Aggeler } 50081508470SFabian Aggeler s->priority_mask[cpu] = pmask; 50181508470SFabian Aggeler } 50281508470SFabian Aggeler 50381508470SFabian Aggeler static uint32_t gic_get_priority_mask(GICState *s, int cpu, MemTxAttrs attrs) 50481508470SFabian Aggeler { 50581508470SFabian Aggeler uint32_t pmask = s->priority_mask[cpu]; 50681508470SFabian Aggeler 5073dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 50881508470SFabian Aggeler if (pmask & 0x80) { 50981508470SFabian Aggeler /* Priority Mask in upper half, return Non-secure view */ 51081508470SFabian Aggeler pmask = (pmask << 1) & 0xff; 51181508470SFabian Aggeler } else { 51281508470SFabian Aggeler /* Priority Mask in lower half, RAZ */ 51381508470SFabian Aggeler pmask = 0; 51481508470SFabian Aggeler } 51581508470SFabian Aggeler } 51681508470SFabian Aggeler return pmask; 51781508470SFabian Aggeler } 51881508470SFabian Aggeler 51932951860SFabian Aggeler static uint32_t gic_get_cpu_control(GICState *s, int cpu, MemTxAttrs attrs) 52032951860SFabian Aggeler { 52132951860SFabian Aggeler uint32_t ret = s->cpu_ctlr[cpu]; 52232951860SFabian Aggeler 5233dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 52432951860SFabian Aggeler /* Construct the NS banked view of GICC_CTLR from the correct 52532951860SFabian Aggeler * bits of the S banked view. We don't need to move the bypass 52632951860SFabian Aggeler * control bits because we don't implement that (IMPDEF) part 52732951860SFabian Aggeler * of the GIC architecture. 52832951860SFabian Aggeler */ 52932951860SFabian Aggeler ret = (ret & (GICC_CTLR_EN_GRP1 | GICC_CTLR_EOIMODE_NS)) >> 1; 53032951860SFabian Aggeler } 53132951860SFabian Aggeler return ret; 53232951860SFabian Aggeler } 53332951860SFabian Aggeler 53432951860SFabian Aggeler static void gic_set_cpu_control(GICState *s, int cpu, uint32_t value, 53532951860SFabian Aggeler MemTxAttrs attrs) 53632951860SFabian Aggeler { 53732951860SFabian Aggeler uint32_t mask; 53832951860SFabian Aggeler 5393dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 54032951860SFabian Aggeler /* The NS view can only write certain bits in the register; 54132951860SFabian Aggeler * the rest are unchanged 54232951860SFabian Aggeler */ 54332951860SFabian Aggeler mask = GICC_CTLR_EN_GRP1; 54432951860SFabian Aggeler if (s->revision == 2) { 54532951860SFabian Aggeler mask |= GICC_CTLR_EOIMODE_NS; 54632951860SFabian Aggeler } 54732951860SFabian Aggeler s->cpu_ctlr[cpu] &= ~mask; 54832951860SFabian Aggeler s->cpu_ctlr[cpu] |= (value << 1) & mask; 54932951860SFabian Aggeler } else { 55032951860SFabian Aggeler if (s->revision == 2) { 55132951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V2_S_MASK : GICC_CTLR_V2_MASK; 55232951860SFabian Aggeler } else { 55332951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V1_S_MASK : GICC_CTLR_V1_MASK; 55432951860SFabian Aggeler } 55532951860SFabian Aggeler s->cpu_ctlr[cpu] = value & mask; 55632951860SFabian Aggeler } 55732951860SFabian Aggeler DPRINTF("CPU Interface %d: Group0 Interrupts %sabled, " 55832951860SFabian Aggeler "Group1 Interrupts %sabled\n", cpu, 55932951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP0) ? "En" : "Dis", 56032951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP1) ? "En" : "Dis"); 56132951860SFabian Aggeler } 56232951860SFabian Aggeler 56308efa9f2SFabian Aggeler static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs) 56408efa9f2SFabian Aggeler { 56571aa735bSLuc MICHEL if ((s->revision != REV_11MPCORE) && (s->running_priority[cpu] > 0xff)) { 56671aa735bSLuc MICHEL /* Idle priority */ 56771aa735bSLuc MICHEL return 0xff; 56871aa735bSLuc MICHEL } 56971aa735bSLuc MICHEL 5703dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 57108efa9f2SFabian Aggeler if (s->running_priority[cpu] & 0x80) { 57208efa9f2SFabian Aggeler /* Running priority in upper half of range: return the Non-secure 57308efa9f2SFabian Aggeler * view of the priority. 57408efa9f2SFabian Aggeler */ 57508efa9f2SFabian Aggeler return s->running_priority[cpu] << 1; 57608efa9f2SFabian Aggeler } else { 57708efa9f2SFabian Aggeler /* Running priority in lower half of range: RAZ */ 57808efa9f2SFabian Aggeler return 0; 57908efa9f2SFabian Aggeler } 58008efa9f2SFabian Aggeler } else { 58108efa9f2SFabian Aggeler return s->running_priority[cpu]; 58208efa9f2SFabian Aggeler } 58308efa9f2SFabian Aggeler } 58408efa9f2SFabian Aggeler 585a55c910eSPeter Maydell /* Return true if we should split priority drop and interrupt deactivation, 586a55c910eSPeter Maydell * ie whether the relevant EOIMode bit is set. 587a55c910eSPeter Maydell */ 588a55c910eSPeter Maydell static bool gic_eoi_split(GICState *s, int cpu, MemTxAttrs attrs) 589a55c910eSPeter Maydell { 590a55c910eSPeter Maydell if (s->revision != 2) { 591a55c910eSPeter Maydell /* Before GICv2 prio-drop and deactivate are not separable */ 592a55c910eSPeter Maydell return false; 593a55c910eSPeter Maydell } 5943dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 595a55c910eSPeter Maydell return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE_NS; 596a55c910eSPeter Maydell } 597a55c910eSPeter Maydell return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE; 598a55c910eSPeter Maydell } 599a55c910eSPeter Maydell 600a55c910eSPeter Maydell static void gic_deactivate_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) 601a55c910eSPeter Maydell { 602ee03cca8SPeter Maydell int group; 603ee03cca8SPeter Maydell 60402f2e22dSLuc Michel if (irq >= GIC_MAXIRQ || (!gic_is_vcpu(cpu) && irq >= s->num_irq)) { 605ee03cca8SPeter Maydell /* 606ee03cca8SPeter Maydell * This handles two cases: 607ee03cca8SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 608ee03cca8SPeter Maydell * to the GICC_DIR, the GIC ignores that write. 609ee03cca8SPeter Maydell * 2. If software writes the number of a non-existent interrupt 610ee03cca8SPeter Maydell * this must be a subcase of "value written is not an active interrupt" 61102f2e22dSLuc Michel * and so this is UNPREDICTABLE. We choose to ignore it. For vCPUs, 61202f2e22dSLuc Michel * all IRQs potentially exist, so this limit does not apply. 613ee03cca8SPeter Maydell */ 614ee03cca8SPeter Maydell return; 615ee03cca8SPeter Maydell } 616ee03cca8SPeter Maydell 617a55c910eSPeter Maydell if (!gic_eoi_split(s, cpu, attrs)) { 618a55c910eSPeter Maydell /* This is UNPREDICTABLE; we choose to ignore it */ 619a55c910eSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 620a55c910eSPeter Maydell "gic_deactivate_irq: GICC_DIR write when EOIMode clear"); 621a55c910eSPeter Maydell return; 622a55c910eSPeter Maydell } 623a55c910eSPeter Maydell 62402f2e22dSLuc Michel if (gic_is_vcpu(cpu) && !gic_virq_is_valid(s, irq, cpu)) { 62502f2e22dSLuc Michel /* This vIRQ does not have an LR entry which is either active or 62602f2e22dSLuc Michel * pending and active. Increment EOICount and ignore the write. 62702f2e22dSLuc Michel */ 62802f2e22dSLuc Michel int rcpu = gic_get_vcpu_real_id(cpu); 62902f2e22dSLuc Michel s->h_hcr[rcpu] += 1 << R_GICH_HCR_EOICount_SHIFT; 63002f2e22dSLuc Michel return; 63102f2e22dSLuc Michel } 63202f2e22dSLuc Michel 63302f2e22dSLuc Michel group = gic_has_groups(s) && gic_test_group(s, irq, cpu); 63402f2e22dSLuc Michel 6353dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs) && !group) { 636a55c910eSPeter Maydell DPRINTF("Non-secure DI for Group0 interrupt %d ignored\n", irq); 637a55c910eSPeter Maydell return; 638a55c910eSPeter Maydell } 639a55c910eSPeter Maydell 64086b350f0SLuc Michel gic_clear_active(s, irq, cpu); 641a55c910eSPeter Maydell } 642a55c910eSPeter Maydell 64350491c56SLuc Michel static void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) 644e69954b9Spbrook { 6459ee6e8bbSpbrook int cm = 1 << cpu; 64672889c8aSPeter Maydell int group; 64772889c8aSPeter Maydell 648df628ff1Spbrook DPRINTF("EOI %d\n", irq); 64902f2e22dSLuc Michel if (gic_is_vcpu(cpu)) { 65002f2e22dSLuc Michel /* The call to gic_prio_drop() will clear a bit in GICH_APR iff the 65102f2e22dSLuc Michel * running prio is < 0x100. 65202f2e22dSLuc Michel */ 65302f2e22dSLuc Michel bool prio_drop = s->running_priority[cpu] < 0x100; 65402f2e22dSLuc Michel 65502f2e22dSLuc Michel if (irq >= GIC_MAXIRQ) { 65602f2e22dSLuc Michel /* Ignore spurious interrupt */ 65702f2e22dSLuc Michel return; 65802f2e22dSLuc Michel } 65902f2e22dSLuc Michel 66002f2e22dSLuc Michel gic_drop_prio(s, cpu, 0); 66102f2e22dSLuc Michel 66202f2e22dSLuc Michel if (!gic_eoi_split(s, cpu, attrs)) { 66302f2e22dSLuc Michel bool valid = gic_virq_is_valid(s, irq, cpu); 66402f2e22dSLuc Michel if (prio_drop && !valid) { 66502f2e22dSLuc Michel /* We are in a situation where: 66602f2e22dSLuc Michel * - V_CTRL.EOIMode is false (no EOI split), 66702f2e22dSLuc Michel * - The call to gic_drop_prio() cleared a bit in GICH_APR, 66802f2e22dSLuc Michel * - This vIRQ does not have an LR entry which is either 66902f2e22dSLuc Michel * active or pending and active. 67002f2e22dSLuc Michel * In that case, we must increment EOICount. 67102f2e22dSLuc Michel */ 67202f2e22dSLuc Michel int rcpu = gic_get_vcpu_real_id(cpu); 67302f2e22dSLuc Michel s->h_hcr[rcpu] += 1 << R_GICH_HCR_EOICount_SHIFT; 67402f2e22dSLuc Michel } else if (valid) { 67502f2e22dSLuc Michel gic_clear_active(s, irq, cpu); 67602f2e22dSLuc Michel } 67702f2e22dSLuc Michel } 67802f2e22dSLuc Michel 67902f2e22dSLuc Michel return; 68002f2e22dSLuc Michel } 68102f2e22dSLuc Michel 682a32134aaSMark Langsdorf if (irq >= s->num_irq) { 683217bfb44SPeter Maydell /* This handles two cases: 684217bfb44SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 685217bfb44SPeter Maydell * to the GICC_EOIR, the GIC ignores that write. 686217bfb44SPeter Maydell * 2. If software writes the number of a non-existent interrupt 687217bfb44SPeter Maydell * this must be a subcase of "value written does not match the last 688217bfb44SPeter Maydell * valid interrupt value read from the Interrupt Acknowledge 689217bfb44SPeter Maydell * register" and so this is UNPREDICTABLE. We choose to ignore it. 690217bfb44SPeter Maydell */ 691217bfb44SPeter Maydell return; 692217bfb44SPeter Maydell } 69372889c8aSPeter Maydell if (s->running_priority[cpu] == 0x100) { 694e69954b9Spbrook return; /* No active IRQ. */ 69572889c8aSPeter Maydell } 6968d999995SChristoffer Dall 6973bc4b52cSMarcin Krzeminski if (s->revision == REV_11MPCORE) { 698e69954b9Spbrook /* Mark level triggered interrupts as pending if they are still 699e69954b9Spbrook raised. */ 70067ce697aSLuc Michel if (!GIC_DIST_TEST_EDGE_TRIGGER(irq) && GIC_DIST_TEST_ENABLED(irq, cm) 70167ce697aSLuc Michel && GIC_DIST_TEST_LEVEL(irq, cm) 70267ce697aSLuc Michel && (GIC_DIST_TARGET(irq) & cm) != 0) { 7039ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq, cm); 70467ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, cm); 705e69954b9Spbrook } 7068d999995SChristoffer Dall } 7078d999995SChristoffer Dall 70886b350f0SLuc Michel group = gic_has_groups(s) && gic_test_group(s, irq, cpu); 70972889c8aSPeter Maydell 7103dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs) && !group) { 711f9c6a7f1SFabian Aggeler DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq); 712f9c6a7f1SFabian Aggeler return; 713f9c6a7f1SFabian Aggeler } 714f9c6a7f1SFabian Aggeler 715f9c6a7f1SFabian Aggeler /* Secure EOI with GICC_CTLR.AckCtl == 0 when the IRQ is a Group 1 716f9c6a7f1SFabian Aggeler * interrupt is UNPREDICTABLE. We choose to handle it as if AckCtl == 1, 717f9c6a7f1SFabian Aggeler * i.e. go ahead and complete the irq anyway. 718f9c6a7f1SFabian Aggeler */ 719f9c6a7f1SFabian Aggeler 72072889c8aSPeter Maydell gic_drop_prio(s, cpu, group); 721a55c910eSPeter Maydell 722a55c910eSPeter Maydell /* In GICv2 the guest can choose to split priority-drop and deactivate */ 723a55c910eSPeter Maydell if (!gic_eoi_split(s, cpu, attrs)) { 72486b350f0SLuc Michel gic_clear_active(s, irq, cpu); 725a55c910eSPeter Maydell } 726e69954b9Spbrook gic_update(s); 727e69954b9Spbrook } 728e69954b9Spbrook 729a9d85353SPeter Maydell static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) 730e69954b9Spbrook { 731fae15286SPeter Maydell GICState *s = (GICState *)opaque; 732e69954b9Spbrook uint32_t res; 733e69954b9Spbrook int irq; 734e69954b9Spbrook int i; 7359ee6e8bbSpbrook int cpu; 7369ee6e8bbSpbrook int cm; 7379ee6e8bbSpbrook int mask; 738e69954b9Spbrook 739926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 7409ee6e8bbSpbrook cm = 1 << cpu; 741e69954b9Spbrook if (offset < 0x100) { 742679aa175SFabian Aggeler if (offset == 0) { /* GICD_CTLR */ 743679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 744679aa175SFabian Aggeler /* The NS bank of this register is just an alias of the 745679aa175SFabian Aggeler * EnableGrp1 bit in the S bank version. 746679aa175SFabian Aggeler */ 747679aa175SFabian Aggeler return extract32(s->ctlr, 1, 1); 748679aa175SFabian Aggeler } else { 749679aa175SFabian Aggeler return s->ctlr; 750679aa175SFabian Aggeler } 751679aa175SFabian Aggeler } 752e69954b9Spbrook if (offset == 4) 7535543d1abSFabian Aggeler /* Interrupt Controller Type Register */ 7545543d1abSFabian Aggeler return ((s->num_irq / 32) - 1) 755b95690c9SWei Huang | ((s->num_cpu - 1) << 5) 7565543d1abSFabian Aggeler | (s->security_extn << 10); 757e69954b9Spbrook if (offset < 0x08) 758e69954b9Spbrook return 0; 759b79f2265SRob Herring if (offset >= 0x80) { 760c27a5ba9SFabian Aggeler /* Interrupt Group Registers: these RAZ/WI if this is an NS 761c27a5ba9SFabian Aggeler * access to a GIC with the security extensions, or if the GIC 762c27a5ba9SFabian Aggeler * doesn't have groups at all. 763c27a5ba9SFabian Aggeler */ 764c27a5ba9SFabian Aggeler res = 0; 765c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 766c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 767c27a5ba9SFabian Aggeler irq = (offset - 0x080) * 8 + GIC_BASE_IRQ; 768c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 769c27a5ba9SFabian Aggeler goto bad_reg; 770c27a5ba9SFabian Aggeler } 771c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 77267ce697aSLuc Michel if (GIC_DIST_TEST_GROUP(irq + i, cm)) { 773c27a5ba9SFabian Aggeler res |= (1 << i); 774c27a5ba9SFabian Aggeler } 775c27a5ba9SFabian Aggeler } 776c27a5ba9SFabian Aggeler } 777c27a5ba9SFabian Aggeler return res; 778b79f2265SRob Herring } 779e69954b9Spbrook goto bad_reg; 780e69954b9Spbrook } else if (offset < 0x200) { 781e69954b9Spbrook /* Interrupt Set/Clear Enable. */ 782e69954b9Spbrook if (offset < 0x180) 783e69954b9Spbrook irq = (offset - 0x100) * 8; 784e69954b9Spbrook else 785e69954b9Spbrook irq = (offset - 0x180) * 8; 7869ee6e8bbSpbrook irq += GIC_BASE_IRQ; 787a32134aaSMark Langsdorf if (irq >= s->num_irq) 788e69954b9Spbrook goto bad_reg; 789e69954b9Spbrook res = 0; 790e69954b9Spbrook for (i = 0; i < 8; i++) { 791fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 79267ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 793fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 794fea8a08eSJens Wiklander } 795fea8a08eSJens Wiklander 79667ce697aSLuc Michel if (GIC_DIST_TEST_ENABLED(irq + i, cm)) { 797e69954b9Spbrook res |= (1 << i); 798e69954b9Spbrook } 799e69954b9Spbrook } 800e69954b9Spbrook } else if (offset < 0x300) { 801e69954b9Spbrook /* Interrupt Set/Clear Pending. */ 802e69954b9Spbrook if (offset < 0x280) 803e69954b9Spbrook irq = (offset - 0x200) * 8; 804e69954b9Spbrook else 805e69954b9Spbrook irq = (offset - 0x280) * 8; 8069ee6e8bbSpbrook irq += GIC_BASE_IRQ; 807a32134aaSMark Langsdorf if (irq >= s->num_irq) 808e69954b9Spbrook goto bad_reg; 809e69954b9Spbrook res = 0; 81069253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 811e69954b9Spbrook for (i = 0; i < 8; i++) { 812fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 81367ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 814fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 815fea8a08eSJens Wiklander } 816fea8a08eSJens Wiklander 8178d999995SChristoffer Dall if (gic_test_pending(s, irq + i, mask)) { 818e69954b9Spbrook res |= (1 << i); 819e69954b9Spbrook } 820e69954b9Spbrook } 821e69954b9Spbrook } else if (offset < 0x400) { 8223bb0b038SLuc Michel /* Interrupt Set/Clear Active. */ 8233bb0b038SLuc Michel if (offset < 0x380) { 8243bb0b038SLuc Michel irq = (offset - 0x300) * 8; 8253bb0b038SLuc Michel } else if (s->revision == 2) { 8263bb0b038SLuc Michel irq = (offset - 0x380) * 8; 8273bb0b038SLuc Michel } else { 8283bb0b038SLuc Michel goto bad_reg; 8293bb0b038SLuc Michel } 8303bb0b038SLuc Michel 8313bb0b038SLuc Michel irq += GIC_BASE_IRQ; 832a32134aaSMark Langsdorf if (irq >= s->num_irq) 833e69954b9Spbrook goto bad_reg; 834e69954b9Spbrook res = 0; 83569253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 836e69954b9Spbrook for (i = 0; i < 8; i++) { 837fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 83867ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 839fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 840fea8a08eSJens Wiklander } 841fea8a08eSJens Wiklander 84267ce697aSLuc Michel if (GIC_DIST_TEST_ACTIVE(irq + i, mask)) { 843e69954b9Spbrook res |= (1 << i); 844e69954b9Spbrook } 845e69954b9Spbrook } 846e69954b9Spbrook } else if (offset < 0x800) { 847e69954b9Spbrook /* Interrupt Priority. */ 8489ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 849a32134aaSMark Langsdorf if (irq >= s->num_irq) 850e69954b9Spbrook goto bad_reg; 85167ce697aSLuc Michel res = gic_dist_get_priority(s, cpu, irq, attrs); 852e69954b9Spbrook } else if (offset < 0xc00) { 853e69954b9Spbrook /* Interrupt CPU Target. */ 8546b9680bbSPeter Maydell if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { 8556b9680bbSPeter Maydell /* For uniprocessor GICs these RAZ/WI */ 8566b9680bbSPeter Maydell res = 0; 8576b9680bbSPeter Maydell } else { 8589ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 8596b9680bbSPeter Maydell if (irq >= s->num_irq) { 860e69954b9Spbrook goto bad_reg; 8616b9680bbSPeter Maydell } 8627995206dSPeter Maydell if (irq < 29 && s->revision == REV_11MPCORE) { 8637995206dSPeter Maydell res = 0; 8647995206dSPeter Maydell } else if (irq < GIC_INTERNAL) { 8659ee6e8bbSpbrook res = cm; 8669ee6e8bbSpbrook } else { 86767ce697aSLuc Michel res = GIC_DIST_TARGET(irq); 8689ee6e8bbSpbrook } 8696b9680bbSPeter Maydell } 870e69954b9Spbrook } else if (offset < 0xf00) { 871e69954b9Spbrook /* Interrupt Configuration. */ 87271a62046SAdam Lackorzynski irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 873a32134aaSMark Langsdorf if (irq >= s->num_irq) 874e69954b9Spbrook goto bad_reg; 875e69954b9Spbrook res = 0; 876e69954b9Spbrook for (i = 0; i < 4; i++) { 877fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 87867ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 879fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 880fea8a08eSJens Wiklander } 881fea8a08eSJens Wiklander 88267ce697aSLuc Michel if (GIC_DIST_TEST_MODEL(irq + i)) { 883e69954b9Spbrook res |= (1 << (i * 2)); 88467ce697aSLuc Michel } 88567ce697aSLuc Michel if (GIC_DIST_TEST_EDGE_TRIGGER(irq + i)) { 886e69954b9Spbrook res |= (2 << (i * 2)); 887e69954b9Spbrook } 88867ce697aSLuc Michel } 88940d22500SChristoffer Dall } else if (offset < 0xf10) { 89040d22500SChristoffer Dall goto bad_reg; 89140d22500SChristoffer Dall } else if (offset < 0xf30) { 8927c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 89340d22500SChristoffer Dall goto bad_reg; 89440d22500SChristoffer Dall } 89540d22500SChristoffer Dall 89640d22500SChristoffer Dall if (offset < 0xf20) { 89740d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 89840d22500SChristoffer Dall irq = (offset - 0xf10); 89940d22500SChristoffer Dall } else { 90040d22500SChristoffer Dall irq = (offset - 0xf20); 90140d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 90240d22500SChristoffer Dall } 90340d22500SChristoffer Dall 904fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 90567ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq, 1 << cpu)) { 906fea8a08eSJens Wiklander res = 0; /* Ignore Non-secure access of Group0 IRQ */ 907fea8a08eSJens Wiklander } else { 90840d22500SChristoffer Dall res = s->sgi_pending[irq][cpu]; 909fea8a08eSJens Wiklander } 9103355c360SAlistair Francis } else if (offset < 0xfd0) { 911e69954b9Spbrook goto bad_reg; 9123355c360SAlistair Francis } else if (offset < 0x1000) { 913e69954b9Spbrook if (offset & 3) { 914e69954b9Spbrook res = 0; 915e69954b9Spbrook } else { 9163355c360SAlistair Francis switch (s->revision) { 9173355c360SAlistair Francis case REV_11MPCORE: 9183355c360SAlistair Francis res = gic_id_11mpcore[(offset - 0xfd0) >> 2]; 9193355c360SAlistair Francis break; 9203355c360SAlistair Francis case 1: 9213355c360SAlistair Francis res = gic_id_gicv1[(offset - 0xfd0) >> 2]; 9223355c360SAlistair Francis break; 9233355c360SAlistair Francis case 2: 9243355c360SAlistair Francis res = gic_id_gicv2[(offset - 0xfd0) >> 2]; 9253355c360SAlistair Francis break; 9263355c360SAlistair Francis default: 9273355c360SAlistair Francis res = 0; 928e69954b9Spbrook } 929e69954b9Spbrook } 9303355c360SAlistair Francis } else { 9313355c360SAlistair Francis g_assert_not_reached(); 9323355c360SAlistair Francis } 933e69954b9Spbrook return res; 934e69954b9Spbrook bad_reg: 9358c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 9368c8dc39fSPeter Maydell "gic_dist_readb: Bad offset %x\n", (int)offset); 937e69954b9Spbrook return 0; 938e69954b9Spbrook } 939e69954b9Spbrook 940a9d85353SPeter Maydell static MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data, 941a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 942e69954b9Spbrook { 943a9d85353SPeter Maydell switch (size) { 944a9d85353SPeter Maydell case 1: 945a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 946a9d85353SPeter Maydell return MEMTX_OK; 947a9d85353SPeter Maydell case 2: 948a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 949a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 950a9d85353SPeter Maydell return MEMTX_OK; 951a9d85353SPeter Maydell case 4: 952a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 953a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 954a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 2, attrs) << 16; 955a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 3, attrs) << 24; 956a9d85353SPeter Maydell return MEMTX_OK; 957a9d85353SPeter Maydell default: 958a9d85353SPeter Maydell return MEMTX_ERROR; 959e69954b9Spbrook } 960e69954b9Spbrook } 961e69954b9Spbrook 962a8170e5eSAvi Kivity static void gic_dist_writeb(void *opaque, hwaddr offset, 963a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 964e69954b9Spbrook { 965fae15286SPeter Maydell GICState *s = (GICState *)opaque; 966e69954b9Spbrook int irq; 967e69954b9Spbrook int i; 9689ee6e8bbSpbrook int cpu; 969e69954b9Spbrook 970926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 971e69954b9Spbrook if (offset < 0x100) { 972e69954b9Spbrook if (offset == 0) { 973679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 974679aa175SFabian Aggeler /* NS version is just an alias of the S version's bit 1 */ 975679aa175SFabian Aggeler s->ctlr = deposit32(s->ctlr, 1, 1, value); 976679aa175SFabian Aggeler } else if (gic_has_groups(s)) { 977679aa175SFabian Aggeler s->ctlr = value & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1); 978679aa175SFabian Aggeler } else { 979679aa175SFabian Aggeler s->ctlr = value & GICD_CTLR_EN_GRP0; 980679aa175SFabian Aggeler } 981679aa175SFabian Aggeler DPRINTF("Distributor: Group0 %sabled; Group 1 %sabled\n", 982679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP0 ? "En" : "Dis", 983679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP1 ? "En" : "Dis"); 984e69954b9Spbrook } else if (offset < 4) { 985e69954b9Spbrook /* ignored. */ 986b79f2265SRob Herring } else if (offset >= 0x80) { 987c27a5ba9SFabian Aggeler /* Interrupt Group Registers: RAZ/WI for NS access to secure 988c27a5ba9SFabian Aggeler * GIC, or for GICs without groups. 989c27a5ba9SFabian Aggeler */ 990c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 991c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 992c27a5ba9SFabian Aggeler irq = (offset - 0x80) * 8 + GIC_BASE_IRQ; 993c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 994c27a5ba9SFabian Aggeler goto bad_reg; 995c27a5ba9SFabian Aggeler } 996c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 997c27a5ba9SFabian Aggeler /* Group bits are banked for private interrupts */ 998c27a5ba9SFabian Aggeler int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 999c27a5ba9SFabian Aggeler if (value & (1 << i)) { 1000c27a5ba9SFabian Aggeler /* Group1 (Non-secure) */ 100167ce697aSLuc Michel GIC_DIST_SET_GROUP(irq + i, cm); 1002c27a5ba9SFabian Aggeler } else { 1003c27a5ba9SFabian Aggeler /* Group0 (Secure) */ 100467ce697aSLuc Michel GIC_DIST_CLEAR_GROUP(irq + i, cm); 1005c27a5ba9SFabian Aggeler } 1006c27a5ba9SFabian Aggeler } 1007c27a5ba9SFabian Aggeler } 1008e69954b9Spbrook } else { 1009e69954b9Spbrook goto bad_reg; 1010e69954b9Spbrook } 1011e69954b9Spbrook } else if (offset < 0x180) { 1012e69954b9Spbrook /* Interrupt Set Enable. */ 10139ee6e8bbSpbrook irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 1014a32134aaSMark Langsdorf if (irq >= s->num_irq) 1015e69954b9Spbrook goto bad_reg; 101641ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 10179ee6e8bbSpbrook value = 0xff; 101841ab7b55SChristoffer Dall } 101941ab7b55SChristoffer Dall 1020e69954b9Spbrook for (i = 0; i < 8; i++) { 1021e69954b9Spbrook if (value & (1 << i)) { 1022f47b48fbSDaniel Sangorrin int mask = 102367ce697aSLuc Michel (irq < GIC_INTERNAL) ? (1 << cpu) 102467ce697aSLuc Michel : GIC_DIST_TARGET(irq + i); 102569253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 102641bf234dSRabin Vincent 1027fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 102867ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1029fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 1030fea8a08eSJens Wiklander } 1031fea8a08eSJens Wiklander 103267ce697aSLuc Michel if (!GIC_DIST_TEST_ENABLED(irq + i, cm)) { 1033e69954b9Spbrook DPRINTF("Enabled IRQ %d\n", irq + i); 10342531088fSHollis Blanchard trace_gic_enable_irq(irq + i); 103541bf234dSRabin Vincent } 103667ce697aSLuc Michel GIC_DIST_SET_ENABLED(irq + i, cm); 1037e69954b9Spbrook /* If a raised level triggered IRQ enabled then mark 1038e69954b9Spbrook is as pending. */ 103967ce697aSLuc Michel if (GIC_DIST_TEST_LEVEL(irq + i, mask) 104067ce697aSLuc Michel && !GIC_DIST_TEST_EDGE_TRIGGER(irq + i)) { 10419ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq + i, mask); 104267ce697aSLuc Michel GIC_DIST_SET_PENDING(irq + i, mask); 10439ee6e8bbSpbrook } 1044e69954b9Spbrook } 1045e69954b9Spbrook } 1046e69954b9Spbrook } else if (offset < 0x200) { 1047e69954b9Spbrook /* Interrupt Clear Enable. */ 10489ee6e8bbSpbrook irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 1049a32134aaSMark Langsdorf if (irq >= s->num_irq) 1050e69954b9Spbrook goto bad_reg; 105141ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 10529ee6e8bbSpbrook value = 0; 105341ab7b55SChristoffer Dall } 105441ab7b55SChristoffer Dall 1055e69954b9Spbrook for (i = 0; i < 8; i++) { 1056e69954b9Spbrook if (value & (1 << i)) { 105769253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 105841bf234dSRabin Vincent 1059fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 106067ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1061fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 1062fea8a08eSJens Wiklander } 1063fea8a08eSJens Wiklander 106467ce697aSLuc Michel if (GIC_DIST_TEST_ENABLED(irq + i, cm)) { 1065e69954b9Spbrook DPRINTF("Disabled IRQ %d\n", irq + i); 10662531088fSHollis Blanchard trace_gic_disable_irq(irq + i); 106741bf234dSRabin Vincent } 106867ce697aSLuc Michel GIC_DIST_CLEAR_ENABLED(irq + i, cm); 1069e69954b9Spbrook } 1070e69954b9Spbrook } 1071e69954b9Spbrook } else if (offset < 0x280) { 1072e69954b9Spbrook /* Interrupt Set Pending. */ 10739ee6e8bbSpbrook irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 1074a32134aaSMark Langsdorf if (irq >= s->num_irq) 1075e69954b9Spbrook goto bad_reg; 107641ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 10775b0adce1SChristoffer Dall value = 0; 107841ab7b55SChristoffer Dall } 10799ee6e8bbSpbrook 1080e69954b9Spbrook for (i = 0; i < 8; i++) { 1081e69954b9Spbrook if (value & (1 << i)) { 1082fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 108367ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1084fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 1085fea8a08eSJens Wiklander } 1086fea8a08eSJens Wiklander 108767ce697aSLuc Michel GIC_DIST_SET_PENDING(irq + i, GIC_DIST_TARGET(irq + i)); 1088e69954b9Spbrook } 1089e69954b9Spbrook } 1090e69954b9Spbrook } else if (offset < 0x300) { 1091e69954b9Spbrook /* Interrupt Clear Pending. */ 10929ee6e8bbSpbrook irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 1093a32134aaSMark Langsdorf if (irq >= s->num_irq) 1094e69954b9Spbrook goto bad_reg; 10955b0adce1SChristoffer Dall if (irq < GIC_NR_SGIS) { 10965b0adce1SChristoffer Dall value = 0; 10975b0adce1SChristoffer Dall } 10985b0adce1SChristoffer Dall 1099e69954b9Spbrook for (i = 0; i < 8; i++) { 1100fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 110167ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1102fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 1103fea8a08eSJens Wiklander } 1104fea8a08eSJens Wiklander 11059ee6e8bbSpbrook /* ??? This currently clears the pending bit for all CPUs, even 11069ee6e8bbSpbrook for per-CPU interrupts. It's unclear whether this is the 11079ee6e8bbSpbrook corect behavior. */ 1108e69954b9Spbrook if (value & (1 << i)) { 110967ce697aSLuc Michel GIC_DIST_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 1110e69954b9Spbrook } 1111e69954b9Spbrook } 11123bb0b038SLuc Michel } else if (offset < 0x380) { 11133bb0b038SLuc Michel /* Interrupt Set Active. */ 11143bb0b038SLuc Michel if (s->revision != 2) { 1115e69954b9Spbrook goto bad_reg; 11163bb0b038SLuc Michel } 11173bb0b038SLuc Michel 11183bb0b038SLuc Michel irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 11193bb0b038SLuc Michel if (irq >= s->num_irq) { 11203bb0b038SLuc Michel goto bad_reg; 11213bb0b038SLuc Michel } 11223bb0b038SLuc Michel 11233bb0b038SLuc Michel /* This register is banked per-cpu for PPIs */ 11243bb0b038SLuc Michel int cm = irq < GIC_INTERNAL ? (1 << cpu) : ALL_CPU_MASK; 11253bb0b038SLuc Michel 11263bb0b038SLuc Michel for (i = 0; i < 8; i++) { 11273bb0b038SLuc Michel if (s->security_extn && !attrs.secure && 11283bb0b038SLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 11293bb0b038SLuc Michel continue; /* Ignore Non-secure access of Group0 IRQ */ 11303bb0b038SLuc Michel } 11313bb0b038SLuc Michel 11323bb0b038SLuc Michel if (value & (1 << i)) { 11333bb0b038SLuc Michel GIC_DIST_SET_ACTIVE(irq + i, cm); 11343bb0b038SLuc Michel } 11353bb0b038SLuc Michel } 11363bb0b038SLuc Michel } else if (offset < 0x400) { 11373bb0b038SLuc Michel /* Interrupt Clear Active. */ 11383bb0b038SLuc Michel if (s->revision != 2) { 11393bb0b038SLuc Michel goto bad_reg; 11403bb0b038SLuc Michel } 11413bb0b038SLuc Michel 11423bb0b038SLuc Michel irq = (offset - 0x380) * 8 + GIC_BASE_IRQ; 11433bb0b038SLuc Michel if (irq >= s->num_irq) { 11443bb0b038SLuc Michel goto bad_reg; 11453bb0b038SLuc Michel } 11463bb0b038SLuc Michel 11473bb0b038SLuc Michel /* This register is banked per-cpu for PPIs */ 11483bb0b038SLuc Michel int cm = irq < GIC_INTERNAL ? (1 << cpu) : ALL_CPU_MASK; 11493bb0b038SLuc Michel 11503bb0b038SLuc Michel for (i = 0; i < 8; i++) { 11513bb0b038SLuc Michel if (s->security_extn && !attrs.secure && 11523bb0b038SLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 11533bb0b038SLuc Michel continue; /* Ignore Non-secure access of Group0 IRQ */ 11543bb0b038SLuc Michel } 11553bb0b038SLuc Michel 11563bb0b038SLuc Michel if (value & (1 << i)) { 11573bb0b038SLuc Michel GIC_DIST_CLEAR_ACTIVE(irq + i, cm); 11583bb0b038SLuc Michel } 11593bb0b038SLuc Michel } 1160e69954b9Spbrook } else if (offset < 0x800) { 1161e69954b9Spbrook /* Interrupt Priority. */ 11629ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 1163a32134aaSMark Langsdorf if (irq >= s->num_irq) 1164e69954b9Spbrook goto bad_reg; 116567ce697aSLuc Michel gic_dist_set_priority(s, cpu, irq, value, attrs); 1166e69954b9Spbrook } else if (offset < 0xc00) { 11676b9680bbSPeter Maydell /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the 11686b9680bbSPeter Maydell * annoying exception of the 11MPCore's GIC. 11696b9680bbSPeter Maydell */ 11706b9680bbSPeter Maydell if (s->num_cpu != 1 || s->revision == REV_11MPCORE) { 11719ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 11726b9680bbSPeter Maydell if (irq >= s->num_irq) { 1173e69954b9Spbrook goto bad_reg; 11746b9680bbSPeter Maydell } 11757995206dSPeter Maydell if (irq < 29 && s->revision == REV_11MPCORE) { 11769ee6e8bbSpbrook value = 0; 11776b9680bbSPeter Maydell } else if (irq < GIC_INTERNAL) { 11789ee6e8bbSpbrook value = ALL_CPU_MASK; 11796b9680bbSPeter Maydell } 11809ee6e8bbSpbrook s->irq_target[irq] = value & ALL_CPU_MASK; 11816b9680bbSPeter Maydell } 1182e69954b9Spbrook } else if (offset < 0xf00) { 1183e69954b9Spbrook /* Interrupt Configuration. */ 11849ee6e8bbSpbrook irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 1185a32134aaSMark Langsdorf if (irq >= s->num_irq) 1186e69954b9Spbrook goto bad_reg; 1187de7a900fSAdam Lackorzynski if (irq < GIC_NR_SGIS) 11889ee6e8bbSpbrook value |= 0xaa; 1189e69954b9Spbrook for (i = 0; i < 4; i++) { 1190fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 119167ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1192fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 1193fea8a08eSJens Wiklander } 1194fea8a08eSJens Wiklander 11957c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 1196e69954b9Spbrook if (value & (1 << (i * 2))) { 119767ce697aSLuc Michel GIC_DIST_SET_MODEL(irq + i); 1198e69954b9Spbrook } else { 119967ce697aSLuc Michel GIC_DIST_CLEAR_MODEL(irq + i); 1200e69954b9Spbrook } 120124b790dfSAdam Lackorzynski } 1202e69954b9Spbrook if (value & (2 << (i * 2))) { 120367ce697aSLuc Michel GIC_DIST_SET_EDGE_TRIGGER(irq + i); 1204e69954b9Spbrook } else { 120567ce697aSLuc Michel GIC_DIST_CLEAR_EDGE_TRIGGER(irq + i); 1206e69954b9Spbrook } 1207e69954b9Spbrook } 120840d22500SChristoffer Dall } else if (offset < 0xf10) { 12099ee6e8bbSpbrook /* 0xf00 is only handled for 32-bit writes. */ 1210e69954b9Spbrook goto bad_reg; 121140d22500SChristoffer Dall } else if (offset < 0xf20) { 121240d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 12137c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 121440d22500SChristoffer Dall goto bad_reg; 121540d22500SChristoffer Dall } 121640d22500SChristoffer Dall irq = (offset - 0xf10); 121740d22500SChristoffer Dall 1218fea8a08eSJens Wiklander if (!s->security_extn || attrs.secure || 121967ce697aSLuc Michel GIC_DIST_TEST_GROUP(irq, 1 << cpu)) { 122040d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~value; 122140d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 122267ce697aSLuc Michel GIC_DIST_CLEAR_PENDING(irq, 1 << cpu); 122340d22500SChristoffer Dall } 1224fea8a08eSJens Wiklander } 122540d22500SChristoffer Dall } else if (offset < 0xf30) { 122640d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 12277c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 122840d22500SChristoffer Dall goto bad_reg; 122940d22500SChristoffer Dall } 123040d22500SChristoffer Dall irq = (offset - 0xf20); 123140d22500SChristoffer Dall 1232fea8a08eSJens Wiklander if (!s->security_extn || attrs.secure || 123367ce697aSLuc Michel GIC_DIST_TEST_GROUP(irq, 1 << cpu)) { 123467ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, 1 << cpu); 123540d22500SChristoffer Dall s->sgi_pending[irq][cpu] |= value; 1236fea8a08eSJens Wiklander } 123740d22500SChristoffer Dall } else { 123840d22500SChristoffer Dall goto bad_reg; 1239e69954b9Spbrook } 1240e69954b9Spbrook gic_update(s); 1241e69954b9Spbrook return; 1242e69954b9Spbrook bad_reg: 12438c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 12448c8dc39fSPeter Maydell "gic_dist_writeb: Bad offset %x\n", (int)offset); 1245e69954b9Spbrook } 1246e69954b9Spbrook 1247a8170e5eSAvi Kivity static void gic_dist_writew(void *opaque, hwaddr offset, 1248a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1249e69954b9Spbrook { 1250a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, value & 0xff, attrs); 1251a9d85353SPeter Maydell gic_dist_writeb(opaque, offset + 1, value >> 8, attrs); 1252e69954b9Spbrook } 1253e69954b9Spbrook 1254a8170e5eSAvi Kivity static void gic_dist_writel(void *opaque, hwaddr offset, 1255a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1256e69954b9Spbrook { 1257fae15286SPeter Maydell GICState *s = (GICState *)opaque; 12588da3ff18Spbrook if (offset == 0xf00) { 12599ee6e8bbSpbrook int cpu; 12609ee6e8bbSpbrook int irq; 12619ee6e8bbSpbrook int mask; 126240d22500SChristoffer Dall int target_cpu; 12639ee6e8bbSpbrook 1264926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 12659ee6e8bbSpbrook irq = value & 0x3ff; 12669ee6e8bbSpbrook switch ((value >> 24) & 3) { 12679ee6e8bbSpbrook case 0: 12689ee6e8bbSpbrook mask = (value >> 16) & ALL_CPU_MASK; 12699ee6e8bbSpbrook break; 12709ee6e8bbSpbrook case 1: 1271fa250144SAdam Lackorzynski mask = ALL_CPU_MASK ^ (1 << cpu); 12729ee6e8bbSpbrook break; 12739ee6e8bbSpbrook case 2: 1274fa250144SAdam Lackorzynski mask = 1 << cpu; 12759ee6e8bbSpbrook break; 12769ee6e8bbSpbrook default: 12779ee6e8bbSpbrook DPRINTF("Bad Soft Int target filter\n"); 12789ee6e8bbSpbrook mask = ALL_CPU_MASK; 12799ee6e8bbSpbrook break; 12809ee6e8bbSpbrook } 128167ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, mask); 128240d22500SChristoffer Dall target_cpu = ctz32(mask); 128340d22500SChristoffer Dall while (target_cpu < GIC_NCPU) { 128440d22500SChristoffer Dall s->sgi_pending[irq][target_cpu] |= (1 << cpu); 128540d22500SChristoffer Dall mask &= ~(1 << target_cpu); 128640d22500SChristoffer Dall target_cpu = ctz32(mask); 128740d22500SChristoffer Dall } 12889ee6e8bbSpbrook gic_update(s); 12899ee6e8bbSpbrook return; 12909ee6e8bbSpbrook } 1291a9d85353SPeter Maydell gic_dist_writew(opaque, offset, value & 0xffff, attrs); 1292a9d85353SPeter Maydell gic_dist_writew(opaque, offset + 2, value >> 16, attrs); 1293a9d85353SPeter Maydell } 1294a9d85353SPeter Maydell 1295a9d85353SPeter Maydell static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data, 1296a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1297a9d85353SPeter Maydell { 1298a9d85353SPeter Maydell switch (size) { 1299a9d85353SPeter Maydell case 1: 1300a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, data, attrs); 1301a9d85353SPeter Maydell return MEMTX_OK; 1302a9d85353SPeter Maydell case 2: 1303a9d85353SPeter Maydell gic_dist_writew(opaque, offset, data, attrs); 1304a9d85353SPeter Maydell return MEMTX_OK; 1305a9d85353SPeter Maydell case 4: 1306a9d85353SPeter Maydell gic_dist_writel(opaque, offset, data, attrs); 1307a9d85353SPeter Maydell return MEMTX_OK; 1308a9d85353SPeter Maydell default: 1309a9d85353SPeter Maydell return MEMTX_ERROR; 1310a9d85353SPeter Maydell } 1311e69954b9Spbrook } 1312e69954b9Spbrook 131351fd06e0SPeter Maydell static inline uint32_t gic_apr_ns_view(GICState *s, int cpu, int regno) 131451fd06e0SPeter Maydell { 131551fd06e0SPeter Maydell /* Return the Nonsecure view of GICC_APR<regno>. This is the 131651fd06e0SPeter Maydell * second half of GICC_NSAPR. 131751fd06e0SPeter Maydell */ 131851fd06e0SPeter Maydell switch (GIC_MIN_BPR) { 131951fd06e0SPeter Maydell case 0: 132051fd06e0SPeter Maydell if (regno < 2) { 132151fd06e0SPeter Maydell return s->nsapr[regno + 2][cpu]; 132251fd06e0SPeter Maydell } 132351fd06e0SPeter Maydell break; 132451fd06e0SPeter Maydell case 1: 132551fd06e0SPeter Maydell if (regno == 0) { 132651fd06e0SPeter Maydell return s->nsapr[regno + 1][cpu]; 132751fd06e0SPeter Maydell } 132851fd06e0SPeter Maydell break; 132951fd06e0SPeter Maydell case 2: 133051fd06e0SPeter Maydell if (regno == 0) { 133151fd06e0SPeter Maydell return extract32(s->nsapr[0][cpu], 16, 16); 133251fd06e0SPeter Maydell } 133351fd06e0SPeter Maydell break; 133451fd06e0SPeter Maydell case 3: 133551fd06e0SPeter Maydell if (regno == 0) { 133651fd06e0SPeter Maydell return extract32(s->nsapr[0][cpu], 8, 8); 133751fd06e0SPeter Maydell } 133851fd06e0SPeter Maydell break; 133951fd06e0SPeter Maydell default: 134051fd06e0SPeter Maydell g_assert_not_reached(); 134151fd06e0SPeter Maydell } 134251fd06e0SPeter Maydell return 0; 134351fd06e0SPeter Maydell } 134451fd06e0SPeter Maydell 134551fd06e0SPeter Maydell static inline void gic_apr_write_ns_view(GICState *s, int cpu, int regno, 134651fd06e0SPeter Maydell uint32_t value) 134751fd06e0SPeter Maydell { 134851fd06e0SPeter Maydell /* Write the Nonsecure view of GICC_APR<regno>. */ 134951fd06e0SPeter Maydell switch (GIC_MIN_BPR) { 135051fd06e0SPeter Maydell case 0: 135151fd06e0SPeter Maydell if (regno < 2) { 135251fd06e0SPeter Maydell s->nsapr[regno + 2][cpu] = value; 135351fd06e0SPeter Maydell } 135451fd06e0SPeter Maydell break; 135551fd06e0SPeter Maydell case 1: 135651fd06e0SPeter Maydell if (regno == 0) { 135751fd06e0SPeter Maydell s->nsapr[regno + 1][cpu] = value; 135851fd06e0SPeter Maydell } 135951fd06e0SPeter Maydell break; 136051fd06e0SPeter Maydell case 2: 136151fd06e0SPeter Maydell if (regno == 0) { 136251fd06e0SPeter Maydell s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 16, 16, value); 136351fd06e0SPeter Maydell } 136451fd06e0SPeter Maydell break; 136551fd06e0SPeter Maydell case 3: 136651fd06e0SPeter Maydell if (regno == 0) { 136751fd06e0SPeter Maydell s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 8, 8, value); 136851fd06e0SPeter Maydell } 136951fd06e0SPeter Maydell break; 137051fd06e0SPeter Maydell default: 137151fd06e0SPeter Maydell g_assert_not_reached(); 137251fd06e0SPeter Maydell } 137351fd06e0SPeter Maydell } 137451fd06e0SPeter Maydell 1375a9d85353SPeter Maydell static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, 1376a9d85353SPeter Maydell uint64_t *data, MemTxAttrs attrs) 1377e69954b9Spbrook { 1378e69954b9Spbrook switch (offset) { 1379e69954b9Spbrook case 0x00: /* Control */ 138032951860SFabian Aggeler *data = gic_get_cpu_control(s, cpu, attrs); 1381a9d85353SPeter Maydell break; 1382e69954b9Spbrook case 0x04: /* Priority mask */ 138381508470SFabian Aggeler *data = gic_get_priority_mask(s, cpu, attrs); 1384a9d85353SPeter Maydell break; 1385e69954b9Spbrook case 0x08: /* Binary Point */ 13863dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 1387421a3c22SLuc MICHEL if (s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) { 1388421a3c22SLuc MICHEL /* NS view of BPR when CBPR is 1 */ 1389421a3c22SLuc MICHEL *data = MIN(s->bpr[cpu] + 1, 7); 1390421a3c22SLuc MICHEL } else { 1391822e9cc3SFabian Aggeler /* BPR is banked. Non-secure copy stored in ABPR. */ 1392822e9cc3SFabian Aggeler *data = s->abpr[cpu]; 1393421a3c22SLuc MICHEL } 1394822e9cc3SFabian Aggeler } else { 1395a9d85353SPeter Maydell *data = s->bpr[cpu]; 1396822e9cc3SFabian Aggeler } 1397a9d85353SPeter Maydell break; 1398e69954b9Spbrook case 0x0c: /* Acknowledge */ 1399c5619bf9SFabian Aggeler *data = gic_acknowledge_irq(s, cpu, attrs); 1400a9d85353SPeter Maydell break; 140166a0a2cbSDong Xu Wang case 0x14: /* Running Priority */ 140208efa9f2SFabian Aggeler *data = gic_get_running_priority(s, cpu, attrs); 1403a9d85353SPeter Maydell break; 1404e69954b9Spbrook case 0x18: /* Highest Pending Interrupt */ 14057c0fa108SFabian Aggeler *data = gic_get_current_pending_irq(s, cpu, attrs); 1406a9d85353SPeter Maydell break; 1407aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 1408822e9cc3SFabian Aggeler /* GIC v2, no security: ABPR 1409822e9cc3SFabian Aggeler * GIC v1, no security: not implemented (RAZ/WI) 1410822e9cc3SFabian Aggeler * With security extensions, secure access: ABPR (alias of NS BPR) 1411822e9cc3SFabian Aggeler * With security extensions, nonsecure access: RAZ/WI 1412822e9cc3SFabian Aggeler */ 14133dd0471bSLuc Michel if (!gic_has_groups(s) || (gic_cpu_ns_access(s, cpu, attrs))) { 1414822e9cc3SFabian Aggeler *data = 0; 1415822e9cc3SFabian Aggeler } else { 1416a9d85353SPeter Maydell *data = s->abpr[cpu]; 1417822e9cc3SFabian Aggeler } 1418a9d85353SPeter Maydell break; 1419a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 142051fd06e0SPeter Maydell { 142151fd06e0SPeter Maydell int regno = (offset - 0xd0) / 4; 14227eb079ecSLuc Michel int nr_aprs = gic_is_vcpu(cpu) ? GIC_VIRT_NR_APRS : GIC_NR_APRS; 142351fd06e0SPeter Maydell 14247eb079ecSLuc Michel if (regno >= nr_aprs || s->revision != 2) { 142551fd06e0SPeter Maydell *data = 0; 14267eb079ecSLuc Michel } else if (gic_is_vcpu(cpu)) { 14277eb079ecSLuc Michel *data = s->h_apr[gic_get_vcpu_real_id(cpu)]; 14283dd0471bSLuc Michel } else if (gic_cpu_ns_access(s, cpu, attrs)) { 142951fd06e0SPeter Maydell /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ 143051fd06e0SPeter Maydell *data = gic_apr_ns_view(s, regno, cpu); 143151fd06e0SPeter Maydell } else { 143251fd06e0SPeter Maydell *data = s->apr[regno][cpu]; 143351fd06e0SPeter Maydell } 1434a9d85353SPeter Maydell break; 143551fd06e0SPeter Maydell } 143651fd06e0SPeter Maydell case 0xe0: case 0xe4: case 0xe8: case 0xec: 143751fd06e0SPeter Maydell { 143851fd06e0SPeter Maydell int regno = (offset - 0xe0) / 4; 143951fd06e0SPeter Maydell 144051fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2 || !gic_has_groups(s) || 14417eb079ecSLuc Michel gic_cpu_ns_access(s, cpu, attrs) || gic_is_vcpu(cpu)) { 144251fd06e0SPeter Maydell *data = 0; 144351fd06e0SPeter Maydell } else { 144451fd06e0SPeter Maydell *data = s->nsapr[regno][cpu]; 144551fd06e0SPeter Maydell } 144651fd06e0SPeter Maydell break; 144751fd06e0SPeter Maydell } 1448e69954b9Spbrook default: 14498c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 14508c8dc39fSPeter Maydell "gic_cpu_read: Bad offset %x\n", (int)offset); 14510cf09852SPeter Maydell *data = 0; 14520cf09852SPeter Maydell break; 1453e69954b9Spbrook } 1454a9d85353SPeter Maydell return MEMTX_OK; 1455e69954b9Spbrook } 1456e69954b9Spbrook 1457a9d85353SPeter Maydell static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, 1458a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1459e69954b9Spbrook { 1460e69954b9Spbrook switch (offset) { 1461e69954b9Spbrook case 0x00: /* Control */ 146232951860SFabian Aggeler gic_set_cpu_control(s, cpu, value, attrs); 1463e69954b9Spbrook break; 1464e69954b9Spbrook case 0x04: /* Priority mask */ 146581508470SFabian Aggeler gic_set_priority_mask(s, cpu, value, attrs); 1466e69954b9Spbrook break; 1467e69954b9Spbrook case 0x08: /* Binary Point */ 14683dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 1469421a3c22SLuc MICHEL if (s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) { 1470421a3c22SLuc MICHEL /* WI when CBPR is 1 */ 1471421a3c22SLuc MICHEL return MEMTX_OK; 1472421a3c22SLuc MICHEL } else { 1473822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1474421a3c22SLuc MICHEL } 1475822e9cc3SFabian Aggeler } else { 14767eb079ecSLuc Michel int min_bpr = gic_is_vcpu(cpu) ? GIC_VIRT_MIN_BPR : GIC_MIN_BPR; 14777eb079ecSLuc Michel s->bpr[cpu] = MAX(value & 0x7, min_bpr); 1478822e9cc3SFabian Aggeler } 1479e69954b9Spbrook break; 1480e69954b9Spbrook case 0x10: /* End Of Interrupt */ 1481f9c6a7f1SFabian Aggeler gic_complete_irq(s, cpu, value & 0x3ff, attrs); 1482a9d85353SPeter Maydell return MEMTX_OK; 1483aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 14843dd0471bSLuc Michel if (!gic_has_groups(s) || (gic_cpu_ns_access(s, cpu, attrs))) { 1485822e9cc3SFabian Aggeler /* unimplemented, or NS access: RAZ/WI */ 1486822e9cc3SFabian Aggeler return MEMTX_OK; 1487822e9cc3SFabian Aggeler } else { 1488822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1489aa7d461aSChristoffer Dall } 1490aa7d461aSChristoffer Dall break; 1491a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 149251fd06e0SPeter Maydell { 149351fd06e0SPeter Maydell int regno = (offset - 0xd0) / 4; 14947eb079ecSLuc Michel int nr_aprs = gic_is_vcpu(cpu) ? GIC_VIRT_NR_APRS : GIC_NR_APRS; 149551fd06e0SPeter Maydell 14967eb079ecSLuc Michel if (regno >= nr_aprs || s->revision != 2) { 149751fd06e0SPeter Maydell return MEMTX_OK; 149851fd06e0SPeter Maydell } 14997eb079ecSLuc Michel if (gic_is_vcpu(cpu)) { 15007eb079ecSLuc Michel s->h_apr[gic_get_vcpu_real_id(cpu)] = value; 15017eb079ecSLuc Michel } else if (gic_cpu_ns_access(s, cpu, attrs)) { 150251fd06e0SPeter Maydell /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ 150351fd06e0SPeter Maydell gic_apr_write_ns_view(s, regno, cpu, value); 150451fd06e0SPeter Maydell } else { 150551fd06e0SPeter Maydell s->apr[regno][cpu] = value; 150651fd06e0SPeter Maydell } 1507a9d477c4SChristoffer Dall break; 150851fd06e0SPeter Maydell } 150951fd06e0SPeter Maydell case 0xe0: case 0xe4: case 0xe8: case 0xec: 151051fd06e0SPeter Maydell { 151151fd06e0SPeter Maydell int regno = (offset - 0xe0) / 4; 151251fd06e0SPeter Maydell 151351fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 151451fd06e0SPeter Maydell return MEMTX_OK; 151551fd06e0SPeter Maydell } 15167eb079ecSLuc Michel if (gic_is_vcpu(cpu)) { 15177eb079ecSLuc Michel return MEMTX_OK; 15187eb079ecSLuc Michel } 15193dd0471bSLuc Michel if (!gic_has_groups(s) || (gic_cpu_ns_access(s, cpu, attrs))) { 152051fd06e0SPeter Maydell return MEMTX_OK; 152151fd06e0SPeter Maydell } 152251fd06e0SPeter Maydell s->nsapr[regno][cpu] = value; 152351fd06e0SPeter Maydell break; 152451fd06e0SPeter Maydell } 1525a55c910eSPeter Maydell case 0x1000: 1526a55c910eSPeter Maydell /* GICC_DIR */ 1527a55c910eSPeter Maydell gic_deactivate_irq(s, cpu, value & 0x3ff, attrs); 1528a55c910eSPeter Maydell break; 1529e69954b9Spbrook default: 15308c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 15318c8dc39fSPeter Maydell "gic_cpu_write: Bad offset %x\n", (int)offset); 15320cf09852SPeter Maydell return MEMTX_OK; 1533e69954b9Spbrook } 1534e69954b9Spbrook gic_update(s); 1535a9d85353SPeter Maydell return MEMTX_OK; 1536e69954b9Spbrook } 1537e2c56465SPeter Maydell 1538e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for the current CPU */ 1539a9d85353SPeter Maydell static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data, 1540a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1541e2c56465SPeter Maydell { 1542fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1543a9d85353SPeter Maydell return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs); 1544e2c56465SPeter Maydell } 1545e2c56465SPeter Maydell 1546a9d85353SPeter Maydell static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr, 1547a9d85353SPeter Maydell uint64_t value, unsigned size, 1548a9d85353SPeter Maydell MemTxAttrs attrs) 1549e2c56465SPeter Maydell { 1550fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1551a9d85353SPeter Maydell return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs); 1552e2c56465SPeter Maydell } 1553e2c56465SPeter Maydell 1554e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for a specific CPU. 1555fae15286SPeter Maydell * These just decode the opaque pointer into GICState* + cpu id. 1556e2c56465SPeter Maydell */ 1557a9d85353SPeter Maydell static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data, 1558a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1559e2c56465SPeter Maydell { 1560fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1561fae15286SPeter Maydell GICState *s = *backref; 1562e2c56465SPeter Maydell int id = (backref - s->backref); 1563a9d85353SPeter Maydell return gic_cpu_read(s, id, addr, data, attrs); 1564e2c56465SPeter Maydell } 1565e2c56465SPeter Maydell 1566a9d85353SPeter Maydell static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr, 1567a9d85353SPeter Maydell uint64_t value, unsigned size, 1568a9d85353SPeter Maydell MemTxAttrs attrs) 1569e2c56465SPeter Maydell { 1570fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1571fae15286SPeter Maydell GICState *s = *backref; 1572e2c56465SPeter Maydell int id = (backref - s->backref); 1573a9d85353SPeter Maydell return gic_cpu_write(s, id, addr, value, attrs); 1574e2c56465SPeter Maydell } 1575e2c56465SPeter Maydell 15762c679ac7SLuc Michel static MemTxResult gic_thisvcpu_read(void *opaque, hwaddr addr, uint64_t *data, 15772c679ac7SLuc Michel unsigned size, MemTxAttrs attrs) 15782c679ac7SLuc Michel { 15792c679ac7SLuc Michel GICState *s = (GICState *)opaque; 15802c679ac7SLuc Michel 15812c679ac7SLuc Michel return gic_cpu_read(s, gic_get_current_vcpu(s), addr, data, attrs); 15822c679ac7SLuc Michel } 15832c679ac7SLuc Michel 15842c679ac7SLuc Michel static MemTxResult gic_thisvcpu_write(void *opaque, hwaddr addr, 15852c679ac7SLuc Michel uint64_t value, unsigned size, 15862c679ac7SLuc Michel MemTxAttrs attrs) 15872c679ac7SLuc Michel { 15882c679ac7SLuc Michel GICState *s = (GICState *)opaque; 15892c679ac7SLuc Michel 15902c679ac7SLuc Michel return gic_cpu_write(s, gic_get_current_vcpu(s), addr, value, attrs); 15912c679ac7SLuc Michel } 15922c679ac7SLuc Michel 1593*527d296fSLuc Michel static uint32_t gic_compute_eisr(GICState *s, int cpu, int lr_start) 1594*527d296fSLuc Michel { 1595*527d296fSLuc Michel int lr_idx; 1596*527d296fSLuc Michel uint32_t ret = 0; 1597*527d296fSLuc Michel 1598*527d296fSLuc Michel for (lr_idx = lr_start; lr_idx < s->num_lrs; lr_idx++) { 1599*527d296fSLuc Michel uint32_t *entry = &s->h_lr[lr_idx][cpu]; 1600*527d296fSLuc Michel ret = deposit32(ret, lr_idx - lr_start, 1, 1601*527d296fSLuc Michel gic_lr_entry_is_eoi(*entry)); 1602*527d296fSLuc Michel } 1603*527d296fSLuc Michel 1604*527d296fSLuc Michel return ret; 1605*527d296fSLuc Michel } 1606*527d296fSLuc Michel 1607*527d296fSLuc Michel static uint32_t gic_compute_elrsr(GICState *s, int cpu, int lr_start) 1608*527d296fSLuc Michel { 1609*527d296fSLuc Michel int lr_idx; 1610*527d296fSLuc Michel uint32_t ret = 0; 1611*527d296fSLuc Michel 1612*527d296fSLuc Michel for (lr_idx = lr_start; lr_idx < s->num_lrs; lr_idx++) { 1613*527d296fSLuc Michel uint32_t *entry = &s->h_lr[lr_idx][cpu]; 1614*527d296fSLuc Michel ret = deposit32(ret, lr_idx - lr_start, 1, 1615*527d296fSLuc Michel gic_lr_entry_is_free(*entry)); 1616*527d296fSLuc Michel } 1617*527d296fSLuc Michel 1618*527d296fSLuc Michel return ret; 1619*527d296fSLuc Michel } 1620*527d296fSLuc Michel 1621*527d296fSLuc Michel static void gic_vmcr_write(GICState *s, uint32_t value, MemTxAttrs attrs) 1622*527d296fSLuc Michel { 1623*527d296fSLuc Michel int vcpu = gic_get_current_vcpu(s); 1624*527d296fSLuc Michel uint32_t ctlr; 1625*527d296fSLuc Michel uint32_t abpr; 1626*527d296fSLuc Michel uint32_t bpr; 1627*527d296fSLuc Michel uint32_t prio_mask; 1628*527d296fSLuc Michel 1629*527d296fSLuc Michel ctlr = FIELD_EX32(value, GICH_VMCR, VMCCtlr); 1630*527d296fSLuc Michel abpr = FIELD_EX32(value, GICH_VMCR, VMABP); 1631*527d296fSLuc Michel bpr = FIELD_EX32(value, GICH_VMCR, VMBP); 1632*527d296fSLuc Michel prio_mask = FIELD_EX32(value, GICH_VMCR, VMPriMask) << 3; 1633*527d296fSLuc Michel 1634*527d296fSLuc Michel gic_set_cpu_control(s, vcpu, ctlr, attrs); 1635*527d296fSLuc Michel s->abpr[vcpu] = MAX(abpr, GIC_VIRT_MIN_ABPR); 1636*527d296fSLuc Michel s->bpr[vcpu] = MAX(bpr, GIC_VIRT_MIN_BPR); 1637*527d296fSLuc Michel gic_set_priority_mask(s, vcpu, prio_mask, attrs); 1638*527d296fSLuc Michel } 1639*527d296fSLuc Michel 1640*527d296fSLuc Michel static MemTxResult gic_hyp_read(void *opaque, int cpu, hwaddr addr, 1641*527d296fSLuc Michel uint64_t *data, MemTxAttrs attrs) 1642*527d296fSLuc Michel { 1643*527d296fSLuc Michel GICState *s = ARM_GIC(opaque); 1644*527d296fSLuc Michel int vcpu = cpu + GIC_NCPU; 1645*527d296fSLuc Michel 1646*527d296fSLuc Michel switch (addr) { 1647*527d296fSLuc Michel case A_GICH_HCR: /* Hypervisor Control */ 1648*527d296fSLuc Michel *data = s->h_hcr[cpu]; 1649*527d296fSLuc Michel break; 1650*527d296fSLuc Michel 1651*527d296fSLuc Michel case A_GICH_VTR: /* VGIC Type */ 1652*527d296fSLuc Michel *data = FIELD_DP32(0, GICH_VTR, ListRegs, s->num_lrs - 1); 1653*527d296fSLuc Michel *data = FIELD_DP32(*data, GICH_VTR, PREbits, 1654*527d296fSLuc Michel GIC_VIRT_MAX_GROUP_PRIO_BITS - 1); 1655*527d296fSLuc Michel *data = FIELD_DP32(*data, GICH_VTR, PRIbits, 1656*527d296fSLuc Michel (7 - GIC_VIRT_MIN_BPR) - 1); 1657*527d296fSLuc Michel break; 1658*527d296fSLuc Michel 1659*527d296fSLuc Michel case A_GICH_VMCR: /* Virtual Machine Control */ 1660*527d296fSLuc Michel *data = FIELD_DP32(0, GICH_VMCR, VMCCtlr, 1661*527d296fSLuc Michel extract32(s->cpu_ctlr[vcpu], 0, 10)); 1662*527d296fSLuc Michel *data = FIELD_DP32(*data, GICH_VMCR, VMABP, s->abpr[vcpu]); 1663*527d296fSLuc Michel *data = FIELD_DP32(*data, GICH_VMCR, VMBP, s->bpr[vcpu]); 1664*527d296fSLuc Michel *data = FIELD_DP32(*data, GICH_VMCR, VMPriMask, 1665*527d296fSLuc Michel extract32(s->priority_mask[vcpu], 3, 5)); 1666*527d296fSLuc Michel break; 1667*527d296fSLuc Michel 1668*527d296fSLuc Michel case A_GICH_MISR: /* Maintenance Interrupt Status */ 1669*527d296fSLuc Michel *data = s->h_misr[cpu]; 1670*527d296fSLuc Michel break; 1671*527d296fSLuc Michel 1672*527d296fSLuc Michel case A_GICH_EISR0: /* End of Interrupt Status 0 and 1 */ 1673*527d296fSLuc Michel case A_GICH_EISR1: 1674*527d296fSLuc Michel *data = gic_compute_eisr(s, cpu, (addr - A_GICH_EISR0) * 8); 1675*527d296fSLuc Michel break; 1676*527d296fSLuc Michel 1677*527d296fSLuc Michel case A_GICH_ELRSR0: /* Empty List Status 0 and 1 */ 1678*527d296fSLuc Michel case A_GICH_ELRSR1: 1679*527d296fSLuc Michel *data = gic_compute_elrsr(s, cpu, (addr - A_GICH_ELRSR0) * 8); 1680*527d296fSLuc Michel break; 1681*527d296fSLuc Michel 1682*527d296fSLuc Michel case A_GICH_APR: /* Active Priorities */ 1683*527d296fSLuc Michel *data = s->h_apr[cpu]; 1684*527d296fSLuc Michel break; 1685*527d296fSLuc Michel 1686*527d296fSLuc Michel case A_GICH_LR0 ... A_GICH_LR63: /* List Registers */ 1687*527d296fSLuc Michel { 1688*527d296fSLuc Michel int lr_idx = (addr - A_GICH_LR0) / 4; 1689*527d296fSLuc Michel 1690*527d296fSLuc Michel if (lr_idx > s->num_lrs) { 1691*527d296fSLuc Michel *data = 0; 1692*527d296fSLuc Michel } else { 1693*527d296fSLuc Michel *data = s->h_lr[lr_idx][cpu]; 1694*527d296fSLuc Michel } 1695*527d296fSLuc Michel break; 1696*527d296fSLuc Michel } 1697*527d296fSLuc Michel 1698*527d296fSLuc Michel default: 1699*527d296fSLuc Michel qemu_log_mask(LOG_GUEST_ERROR, 1700*527d296fSLuc Michel "gic_hyp_read: Bad offset %" HWADDR_PRIx "\n", addr); 1701*527d296fSLuc Michel return MEMTX_OK; 1702*527d296fSLuc Michel } 1703*527d296fSLuc Michel 1704*527d296fSLuc Michel return MEMTX_OK; 1705*527d296fSLuc Michel } 1706*527d296fSLuc Michel 1707*527d296fSLuc Michel static MemTxResult gic_hyp_write(void *opaque, int cpu, hwaddr addr, 1708*527d296fSLuc Michel uint64_t value, MemTxAttrs attrs) 1709*527d296fSLuc Michel { 1710*527d296fSLuc Michel GICState *s = ARM_GIC(opaque); 1711*527d296fSLuc Michel int vcpu = cpu + GIC_NCPU; 1712*527d296fSLuc Michel 1713*527d296fSLuc Michel switch (addr) { 1714*527d296fSLuc Michel case A_GICH_HCR: /* Hypervisor Control */ 1715*527d296fSLuc Michel s->h_hcr[cpu] = value & GICH_HCR_MASK; 1716*527d296fSLuc Michel break; 1717*527d296fSLuc Michel 1718*527d296fSLuc Michel case A_GICH_VMCR: /* Virtual Machine Control */ 1719*527d296fSLuc Michel gic_vmcr_write(s, value, attrs); 1720*527d296fSLuc Michel break; 1721*527d296fSLuc Michel 1722*527d296fSLuc Michel case A_GICH_APR: /* Active Priorities */ 1723*527d296fSLuc Michel s->h_apr[cpu] = value; 1724*527d296fSLuc Michel s->running_priority[vcpu] = gic_get_prio_from_apr_bits(s, vcpu); 1725*527d296fSLuc Michel break; 1726*527d296fSLuc Michel 1727*527d296fSLuc Michel case A_GICH_LR0 ... A_GICH_LR63: /* List Registers */ 1728*527d296fSLuc Michel { 1729*527d296fSLuc Michel int lr_idx = (addr - A_GICH_LR0) / 4; 1730*527d296fSLuc Michel 1731*527d296fSLuc Michel if (lr_idx > s->num_lrs) { 1732*527d296fSLuc Michel return MEMTX_OK; 1733*527d296fSLuc Michel } 1734*527d296fSLuc Michel 1735*527d296fSLuc Michel s->h_lr[lr_idx][cpu] = value & GICH_LR_MASK; 1736*527d296fSLuc Michel break; 1737*527d296fSLuc Michel } 1738*527d296fSLuc Michel 1739*527d296fSLuc Michel default: 1740*527d296fSLuc Michel qemu_log_mask(LOG_GUEST_ERROR, 1741*527d296fSLuc Michel "gic_hyp_write: Bad offset %" HWADDR_PRIx "\n", addr); 1742*527d296fSLuc Michel return MEMTX_OK; 1743*527d296fSLuc Michel } 1744*527d296fSLuc Michel 1745*527d296fSLuc Michel return MEMTX_OK; 1746*527d296fSLuc Michel } 1747*527d296fSLuc Michel 1748*527d296fSLuc Michel static MemTxResult gic_thiscpu_hyp_read(void *opaque, hwaddr addr, uint64_t *data, 1749*527d296fSLuc Michel unsigned size, MemTxAttrs attrs) 1750*527d296fSLuc Michel { 1751*527d296fSLuc Michel GICState *s = (GICState *)opaque; 1752*527d296fSLuc Michel 1753*527d296fSLuc Michel return gic_hyp_read(s, gic_get_current_cpu(s), addr, data, attrs); 1754*527d296fSLuc Michel } 1755*527d296fSLuc Michel 1756*527d296fSLuc Michel static MemTxResult gic_thiscpu_hyp_write(void *opaque, hwaddr addr, 1757*527d296fSLuc Michel uint64_t value, unsigned size, 1758*527d296fSLuc Michel MemTxAttrs attrs) 1759*527d296fSLuc Michel { 1760*527d296fSLuc Michel GICState *s = (GICState *)opaque; 1761*527d296fSLuc Michel 1762*527d296fSLuc Michel return gic_hyp_write(s, gic_get_current_cpu(s), addr, value, attrs); 1763*527d296fSLuc Michel } 1764*527d296fSLuc Michel 1765*527d296fSLuc Michel static MemTxResult gic_do_hyp_read(void *opaque, hwaddr addr, uint64_t *data, 1766*527d296fSLuc Michel unsigned size, MemTxAttrs attrs) 1767*527d296fSLuc Michel { 1768*527d296fSLuc Michel GICState **backref = (GICState **)opaque; 1769*527d296fSLuc Michel GICState *s = *backref; 1770*527d296fSLuc Michel int id = (backref - s->backref); 1771*527d296fSLuc Michel 1772*527d296fSLuc Michel return gic_hyp_read(s, id, addr, data, attrs); 1773*527d296fSLuc Michel } 1774*527d296fSLuc Michel 1775*527d296fSLuc Michel static MemTxResult gic_do_hyp_write(void *opaque, hwaddr addr, 1776*527d296fSLuc Michel uint64_t value, unsigned size, 1777*527d296fSLuc Michel MemTxAttrs attrs) 1778*527d296fSLuc Michel { 1779*527d296fSLuc Michel GICState **backref = (GICState **)opaque; 1780*527d296fSLuc Michel GICState *s = *backref; 1781*527d296fSLuc Michel int id = (backref - s->backref); 1782*527d296fSLuc Michel 1783*527d296fSLuc Michel return gic_hyp_write(s, id + GIC_NCPU, addr, value, attrs); 1784*527d296fSLuc Michel 1785*527d296fSLuc Michel } 1786*527d296fSLuc Michel 17877926c210SPavel Fedin static const MemoryRegionOps gic_ops[2] = { 17887926c210SPavel Fedin { 17897926c210SPavel Fedin .read_with_attrs = gic_dist_read, 17907926c210SPavel Fedin .write_with_attrs = gic_dist_write, 17917926c210SPavel Fedin .endianness = DEVICE_NATIVE_ENDIAN, 17927926c210SPavel Fedin }, 17937926c210SPavel Fedin { 1794a9d85353SPeter Maydell .read_with_attrs = gic_thiscpu_read, 1795a9d85353SPeter Maydell .write_with_attrs = gic_thiscpu_write, 1796e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 17977926c210SPavel Fedin } 1798e2c56465SPeter Maydell }; 1799e2c56465SPeter Maydell 1800e2c56465SPeter Maydell static const MemoryRegionOps gic_cpu_ops = { 1801a9d85353SPeter Maydell .read_with_attrs = gic_do_cpu_read, 1802a9d85353SPeter Maydell .write_with_attrs = gic_do_cpu_write, 1803e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 1804e2c56465SPeter Maydell }; 1805e69954b9Spbrook 18062c679ac7SLuc Michel static const MemoryRegionOps gic_virt_ops[2] = { 18072c679ac7SLuc Michel { 1808*527d296fSLuc Michel .read_with_attrs = gic_thiscpu_hyp_read, 1809*527d296fSLuc Michel .write_with_attrs = gic_thiscpu_hyp_write, 18102c679ac7SLuc Michel .endianness = DEVICE_NATIVE_ENDIAN, 18112c679ac7SLuc Michel }, 18122c679ac7SLuc Michel { 18132c679ac7SLuc Michel .read_with_attrs = gic_thisvcpu_read, 18142c679ac7SLuc Michel .write_with_attrs = gic_thisvcpu_write, 18152c679ac7SLuc Michel .endianness = DEVICE_NATIVE_ENDIAN, 18162c679ac7SLuc Michel } 18172c679ac7SLuc Michel }; 18182c679ac7SLuc Michel 1819*527d296fSLuc Michel static const MemoryRegionOps gic_viface_ops = { 1820*527d296fSLuc Michel .read_with_attrs = gic_do_hyp_read, 1821*527d296fSLuc Michel .write_with_attrs = gic_do_hyp_write, 1822*527d296fSLuc Michel .endianness = DEVICE_NATIVE_ENDIAN, 1823*527d296fSLuc Michel }; 1824*527d296fSLuc Michel 182553111180SPeter Maydell static void arm_gic_realize(DeviceState *dev, Error **errp) 18262b518c56SPeter Maydell { 182753111180SPeter Maydell /* Device instance realize function for the GIC sysbus device */ 18282b518c56SPeter Maydell int i; 182953111180SPeter Maydell GICState *s = ARM_GIC(dev); 183053111180SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 18311e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_GET_CLASS(s); 18320175ba10SMarkus Armbruster Error *local_err = NULL; 18331e8cae4dSPeter Maydell 18340175ba10SMarkus Armbruster agc->parent_realize(dev, &local_err); 18350175ba10SMarkus Armbruster if (local_err) { 18360175ba10SMarkus Armbruster error_propagate(errp, local_err); 183753111180SPeter Maydell return; 183853111180SPeter Maydell } 18391e8cae4dSPeter Maydell 18405d721b78SAlexander Graf if (kvm_enabled() && !kvm_arm_supports_user_irq()) { 18415d721b78SAlexander Graf error_setg(errp, "KVM with user space irqchip only works when the " 18425d721b78SAlexander Graf "host kernel supports KVM_CAP_ARM_USER_IRQ"); 18435d721b78SAlexander Graf return; 18445d721b78SAlexander Graf } 18455d721b78SAlexander Graf 18462c679ac7SLuc Michel /* This creates distributor, main CPU interface (s->cpuiomem[0]) and if 18472c679ac7SLuc Michel * enabled, virtualization extensions related interfaces (main virtual 18482c679ac7SLuc Michel * interface (s->vifaceiomem[0]) and virtual CPU interface). 18492c679ac7SLuc Michel */ 18502c679ac7SLuc Michel gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops, gic_virt_ops); 18512b518c56SPeter Maydell 18527926c210SPavel Fedin /* Extra core-specific regions for the CPU interfaces. This is 18537926c210SPavel Fedin * necessary for "franken-GIC" implementations, for example on 18547926c210SPavel Fedin * Exynos 4. 1855e2c56465SPeter Maydell * NB that the memory region size of 0x100 applies for the 11MPCore 1856e2c56465SPeter Maydell * and also cores following the GIC v1 spec (ie A9). 1857e2c56465SPeter Maydell * GIC v2 defines a larger memory region (0x1000) so this will need 1858e2c56465SPeter Maydell * to be extended when we implement A15. 1859e2c56465SPeter Maydell */ 1860b95690c9SWei Huang for (i = 0; i < s->num_cpu; i++) { 1861e2c56465SPeter Maydell s->backref[i] = s; 18621437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, 18631437c94bSPaolo Bonzini &s->backref[i], "gic_cpu", 0x100); 18647926c210SPavel Fedin sysbus_init_mmio(sbd, &s->cpuiomem[i+1]); 1865496dbcd1SPeter Maydell } 1866*527d296fSLuc Michel 1867*527d296fSLuc Michel /* Extra core-specific regions for virtual interfaces. This is required by 1868*527d296fSLuc Michel * the GICv2 specification. 1869*527d296fSLuc Michel */ 1870*527d296fSLuc Michel if (s->virt_extn) { 1871*527d296fSLuc Michel for (i = 0; i < s->num_cpu; i++) { 1872*527d296fSLuc Michel memory_region_init_io(&s->vifaceiomem[i + 1], OBJECT(s), 1873*527d296fSLuc Michel &gic_viface_ops, &s->backref[i], 1874*527d296fSLuc Michel "gic_viface", 0x1000); 1875*527d296fSLuc Michel sysbus_init_mmio(sbd, &s->vifaceiomem[i + 1]); 1876*527d296fSLuc Michel } 1877*527d296fSLuc Michel } 1878*527d296fSLuc Michel 1879496dbcd1SPeter Maydell } 1880496dbcd1SPeter Maydell 1881496dbcd1SPeter Maydell static void arm_gic_class_init(ObjectClass *klass, void *data) 1882496dbcd1SPeter Maydell { 1883496dbcd1SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 18841e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_CLASS(klass); 188553111180SPeter Maydell 1886bf853881SPhilippe Mathieu-Daudé device_class_set_parent_realize(dc, arm_gic_realize, &agc->parent_realize); 1887496dbcd1SPeter Maydell } 1888496dbcd1SPeter Maydell 18898c43a6f0SAndreas Färber static const TypeInfo arm_gic_info = { 18901e8cae4dSPeter Maydell .name = TYPE_ARM_GIC, 18911e8cae4dSPeter Maydell .parent = TYPE_ARM_GIC_COMMON, 1892fae15286SPeter Maydell .instance_size = sizeof(GICState), 1893496dbcd1SPeter Maydell .class_init = arm_gic_class_init, 1894998a74bcSPeter Maydell .class_size = sizeof(ARMGICClass), 1895496dbcd1SPeter Maydell }; 1896496dbcd1SPeter Maydell 1897496dbcd1SPeter Maydell static void arm_gic_register_types(void) 1898496dbcd1SPeter Maydell { 1899496dbcd1SPeter Maydell type_register_static(&arm_gic_info); 1900496dbcd1SPeter Maydell } 1901496dbcd1SPeter Maydell 1902496dbcd1SPeter Maydell type_init(arm_gic_register_types) 1903