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 64c27a5ba9SFabian Aggeler /* Return true if this GIC config has interrupt groups, which is 65c27a5ba9SFabian Aggeler * true if we're a GICv2, or a GICv1 with the security extensions. 66c27a5ba9SFabian Aggeler */ 67c27a5ba9SFabian Aggeler static inline bool gic_has_groups(GICState *s) 68c27a5ba9SFabian Aggeler { 69c27a5ba9SFabian Aggeler return s->revision == 2 || s->security_extn; 70c27a5ba9SFabian Aggeler } 71c27a5ba9SFabian Aggeler 72e69954b9Spbrook /* TODO: Many places that call this routine could be optimized. */ 73e69954b9Spbrook /* Update interrupt status after enabled or pending bits have been changed. */ 74fae15286SPeter Maydell void gic_update(GICState *s) 75e69954b9Spbrook { 76e69954b9Spbrook int best_irq; 77e69954b9Spbrook int best_prio; 78e69954b9Spbrook int irq; 79dadbb58fSPeter Maydell int irq_level, fiq_level; 809ee6e8bbSpbrook int cpu; 819ee6e8bbSpbrook int cm; 82e69954b9Spbrook 83b95690c9SWei Huang for (cpu = 0; cpu < s->num_cpu; cpu++) { 849ee6e8bbSpbrook cm = 1 << cpu; 859ee6e8bbSpbrook s->current_pending[cpu] = 1023; 86679aa175SFabian Aggeler if (!(s->ctlr & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1)) 8732951860SFabian Aggeler || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) { 889ee6e8bbSpbrook qemu_irq_lower(s->parent_irq[cpu]); 89dadbb58fSPeter Maydell qemu_irq_lower(s->parent_fiq[cpu]); 90235069a3SJohan Karlsson continue; 91e69954b9Spbrook } 92e69954b9Spbrook best_prio = 0x100; 93e69954b9Spbrook best_irq = 1023; 94a32134aaSMark Langsdorf for (irq = 0; irq < s->num_irq; irq++) { 9567ce697aSLuc Michel if (GIC_DIST_TEST_ENABLED(irq, cm) && 9667ce697aSLuc Michel gic_test_pending(s, irq, cm) && 9767ce697aSLuc Michel (!GIC_DIST_TEST_ACTIVE(irq, cm)) && 9867ce697aSLuc Michel (irq < GIC_INTERNAL || GIC_DIST_TARGET(irq) & cm)) { 9967ce697aSLuc Michel if (GIC_DIST_GET_PRIORITY(irq, cpu) < best_prio) { 10067ce697aSLuc Michel best_prio = GIC_DIST_GET_PRIORITY(irq, cpu); 101e69954b9Spbrook best_irq = irq; 102e69954b9Spbrook } 103e69954b9Spbrook } 104e69954b9Spbrook } 105dadbb58fSPeter Maydell 1062531088fSHollis Blanchard if (best_irq != 1023) { 1072531088fSHollis Blanchard trace_gic_update_bestirq(cpu, best_irq, best_prio, 1082531088fSHollis Blanchard s->priority_mask[cpu], s->running_priority[cpu]); 1092531088fSHollis Blanchard } 1102531088fSHollis Blanchard 111dadbb58fSPeter Maydell irq_level = fiq_level = 0; 112dadbb58fSPeter Maydell 113cad065f1SPeter Maydell if (best_prio < s->priority_mask[cpu]) { 1149ee6e8bbSpbrook s->current_pending[cpu] = best_irq; 1159ee6e8bbSpbrook if (best_prio < s->running_priority[cpu]) { 11667ce697aSLuc Michel int group = GIC_DIST_TEST_GROUP(best_irq, cm); 117dadbb58fSPeter Maydell 118dadbb58fSPeter Maydell if (extract32(s->ctlr, group, 1) && 119dadbb58fSPeter Maydell extract32(s->cpu_ctlr[cpu], group, 1)) { 120dadbb58fSPeter Maydell if (group == 0 && s->cpu_ctlr[cpu] & GICC_CTLR_FIQ_EN) { 121dadbb58fSPeter Maydell DPRINTF("Raised pending FIQ %d (cpu %d)\n", 122dadbb58fSPeter Maydell best_irq, cpu); 123dadbb58fSPeter Maydell fiq_level = 1; 1242531088fSHollis Blanchard trace_gic_update_set_irq(cpu, "fiq", fiq_level); 125dadbb58fSPeter Maydell } else { 126dadbb58fSPeter Maydell DPRINTF("Raised pending IRQ %d (cpu %d)\n", 127dadbb58fSPeter Maydell best_irq, cpu); 128dadbb58fSPeter Maydell irq_level = 1; 1292531088fSHollis Blanchard trace_gic_update_set_irq(cpu, "irq", irq_level); 130e69954b9Spbrook } 131e69954b9Spbrook } 132dadbb58fSPeter Maydell } 133dadbb58fSPeter Maydell } 134dadbb58fSPeter Maydell 135dadbb58fSPeter Maydell qemu_set_irq(s->parent_irq[cpu], irq_level); 136dadbb58fSPeter Maydell qemu_set_irq(s->parent_fiq[cpu], fiq_level); 1379ee6e8bbSpbrook } 138e69954b9Spbrook } 139e69954b9Spbrook 140fae15286SPeter Maydell void gic_set_pending_private(GICState *s, int cpu, int irq) 1419ee6e8bbSpbrook { 1429ee6e8bbSpbrook int cm = 1 << cpu; 1439ee6e8bbSpbrook 1448d999995SChristoffer Dall if (gic_test_pending(s, irq, cm)) { 1459ee6e8bbSpbrook return; 1468d999995SChristoffer Dall } 1479ee6e8bbSpbrook 1489ee6e8bbSpbrook DPRINTF("Set %d pending cpu %d\n", irq, cpu); 14967ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, cm); 1509ee6e8bbSpbrook gic_update(s); 1519ee6e8bbSpbrook } 1529ee6e8bbSpbrook 1538d999995SChristoffer Dall static void gic_set_irq_11mpcore(GICState *s, int irq, int level, 1548d999995SChristoffer Dall int cm, int target) 1558d999995SChristoffer Dall { 1568d999995SChristoffer Dall if (level) { 15767ce697aSLuc Michel GIC_DIST_SET_LEVEL(irq, cm); 15867ce697aSLuc Michel if (GIC_DIST_TEST_EDGE_TRIGGER(irq) || GIC_DIST_TEST_ENABLED(irq, cm)) { 1598d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 16067ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, target); 1618d999995SChristoffer Dall } 1628d999995SChristoffer Dall } else { 16367ce697aSLuc Michel GIC_DIST_CLEAR_LEVEL(irq, cm); 1648d999995SChristoffer Dall } 1658d999995SChristoffer Dall } 1668d999995SChristoffer Dall 1678d999995SChristoffer Dall static void gic_set_irq_generic(GICState *s, int irq, int level, 1688d999995SChristoffer Dall int cm, int target) 1698d999995SChristoffer Dall { 1708d999995SChristoffer Dall if (level) { 17167ce697aSLuc Michel GIC_DIST_SET_LEVEL(irq, cm); 1728d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 17367ce697aSLuc Michel if (GIC_DIST_TEST_EDGE_TRIGGER(irq)) { 17467ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, target); 1758d999995SChristoffer Dall } 1768d999995SChristoffer Dall } else { 17767ce697aSLuc Michel GIC_DIST_CLEAR_LEVEL(irq, cm); 1788d999995SChristoffer Dall } 1798d999995SChristoffer Dall } 1808d999995SChristoffer Dall 1819ee6e8bbSpbrook /* Process a change in an external IRQ input. */ 182e69954b9Spbrook static void gic_set_irq(void *opaque, int irq, int level) 183e69954b9Spbrook { 184544d1afaSPeter Maydell /* Meaning of the 'irq' parameter: 185544d1afaSPeter Maydell * [0..N-1] : external interrupts 186544d1afaSPeter Maydell * [N..N+31] : PPI (internal) interrupts for CPU 0 187544d1afaSPeter Maydell * [N+32..N+63] : PPI (internal interrupts for CPU 1 188544d1afaSPeter Maydell * ... 189544d1afaSPeter Maydell */ 190fae15286SPeter Maydell GICState *s = (GICState *)opaque; 191544d1afaSPeter Maydell int cm, target; 192544d1afaSPeter Maydell if (irq < (s->num_irq - GIC_INTERNAL)) { 193e69954b9Spbrook /* The first external input line is internal interrupt 32. */ 194544d1afaSPeter Maydell cm = ALL_CPU_MASK; 19569253800SRusty Russell irq += GIC_INTERNAL; 19667ce697aSLuc Michel target = GIC_DIST_TARGET(irq); 197544d1afaSPeter Maydell } else { 198544d1afaSPeter Maydell int cpu; 199544d1afaSPeter Maydell irq -= (s->num_irq - GIC_INTERNAL); 200544d1afaSPeter Maydell cpu = irq / GIC_INTERNAL; 201544d1afaSPeter Maydell irq %= GIC_INTERNAL; 202544d1afaSPeter Maydell cm = 1 << cpu; 203544d1afaSPeter Maydell target = cm; 204544d1afaSPeter Maydell } 205544d1afaSPeter Maydell 20640d22500SChristoffer Dall assert(irq >= GIC_NR_SGIS); 20740d22500SChristoffer Dall 20867ce697aSLuc Michel if (level == GIC_DIST_TEST_LEVEL(irq, cm)) { 209e69954b9Spbrook return; 210544d1afaSPeter Maydell } 211e69954b9Spbrook 2123bc4b52cSMarcin Krzeminski if (s->revision == REV_11MPCORE) { 2138d999995SChristoffer Dall gic_set_irq_11mpcore(s, irq, level, cm, target); 214e69954b9Spbrook } else { 2158d999995SChristoffer Dall gic_set_irq_generic(s, irq, level, cm, target); 216e69954b9Spbrook } 2172531088fSHollis Blanchard trace_gic_set_irq(irq, level, cm, target); 2188d999995SChristoffer Dall 219e69954b9Spbrook gic_update(s); 220e69954b9Spbrook } 221e69954b9Spbrook 2227c0fa108SFabian Aggeler static uint16_t gic_get_current_pending_irq(GICState *s, int cpu, 2237c0fa108SFabian Aggeler MemTxAttrs attrs) 2247c0fa108SFabian Aggeler { 2257c0fa108SFabian Aggeler uint16_t pending_irq = s->current_pending[cpu]; 2267c0fa108SFabian Aggeler 2277c0fa108SFabian Aggeler if (pending_irq < GIC_MAXIRQ && gic_has_groups(s)) { 22867ce697aSLuc Michel int group = GIC_DIST_TEST_GROUP(pending_irq, (1 << cpu)); 2297c0fa108SFabian Aggeler /* On a GIC without the security extensions, reading this register 2307c0fa108SFabian Aggeler * behaves in the same way as a secure access to a GIC with them. 2317c0fa108SFabian Aggeler */ 2327c0fa108SFabian Aggeler bool secure = !s->security_extn || attrs.secure; 2337c0fa108SFabian Aggeler 2347c0fa108SFabian Aggeler if (group == 0 && !secure) { 2357c0fa108SFabian Aggeler /* Group0 interrupts hidden from Non-secure access */ 2367c0fa108SFabian Aggeler return 1023; 2377c0fa108SFabian Aggeler } 2387c0fa108SFabian Aggeler if (group == 1 && secure && !(s->cpu_ctlr[cpu] & GICC_CTLR_ACK_CTL)) { 2397c0fa108SFabian Aggeler /* Group1 interrupts only seen by Secure access if 2407c0fa108SFabian Aggeler * AckCtl bit set. 2417c0fa108SFabian Aggeler */ 2427c0fa108SFabian Aggeler return 1022; 2437c0fa108SFabian Aggeler } 2447c0fa108SFabian Aggeler } 2457c0fa108SFabian Aggeler return pending_irq; 2467c0fa108SFabian Aggeler } 2477c0fa108SFabian Aggeler 248df92cfa6SPeter Maydell static int gic_get_group_priority(GICState *s, int cpu, int irq) 249df92cfa6SPeter Maydell { 250df92cfa6SPeter Maydell /* Return the group priority of the specified interrupt 251df92cfa6SPeter Maydell * (which is the top bits of its priority, with the number 252df92cfa6SPeter Maydell * of bits masked determined by the applicable binary point register). 253df92cfa6SPeter Maydell */ 254df92cfa6SPeter Maydell int bpr; 255df92cfa6SPeter Maydell uint32_t mask; 256df92cfa6SPeter Maydell 257df92cfa6SPeter Maydell if (gic_has_groups(s) && 258df92cfa6SPeter Maydell !(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) && 25967ce697aSLuc Michel GIC_DIST_TEST_GROUP(irq, (1 << cpu))) { 260fc05a6f2SLuc MICHEL bpr = s->abpr[cpu] - 1; 261fc05a6f2SLuc MICHEL assert(bpr >= 0); 262df92cfa6SPeter Maydell } else { 263df92cfa6SPeter Maydell bpr = s->bpr[cpu]; 264df92cfa6SPeter Maydell } 265df92cfa6SPeter Maydell 266df92cfa6SPeter Maydell /* a BPR of 0 means the group priority bits are [7:1]; 267df92cfa6SPeter Maydell * a BPR of 1 means they are [7:2], and so on down to 268df92cfa6SPeter Maydell * a BPR of 7 meaning no group priority bits at all. 269df92cfa6SPeter Maydell */ 270df92cfa6SPeter Maydell mask = ~0U << ((bpr & 7) + 1); 271df92cfa6SPeter Maydell 27267ce697aSLuc Michel return GIC_DIST_GET_PRIORITY(irq, cpu) & mask; 273df92cfa6SPeter Maydell } 274df92cfa6SPeter Maydell 27572889c8aSPeter Maydell static void gic_activate_irq(GICState *s, int cpu, int irq) 276e69954b9Spbrook { 27772889c8aSPeter Maydell /* Set the appropriate Active Priority Register bit for this IRQ, 27872889c8aSPeter Maydell * and update the running priority. 27972889c8aSPeter Maydell */ 28072889c8aSPeter Maydell int prio = gic_get_group_priority(s, cpu, irq); 28172889c8aSPeter Maydell int preemption_level = prio >> (GIC_MIN_BPR + 1); 28272889c8aSPeter Maydell int regno = preemption_level / 32; 28372889c8aSPeter Maydell int bitno = preemption_level % 32; 28472889c8aSPeter Maydell 28567ce697aSLuc Michel if (gic_has_groups(s) && GIC_DIST_TEST_GROUP(irq, (1 << cpu))) { 286a8595957SFrançois Baldassari s->nsapr[regno][cpu] |= (1 << bitno); 2879ee6e8bbSpbrook } else { 288a8595957SFrançois Baldassari s->apr[regno][cpu] |= (1 << bitno); 2899ee6e8bbSpbrook } 29072889c8aSPeter Maydell 29172889c8aSPeter Maydell s->running_priority[cpu] = prio; 29267ce697aSLuc Michel GIC_DIST_SET_ACTIVE(irq, 1 << cpu); 29372889c8aSPeter Maydell } 29472889c8aSPeter Maydell 29572889c8aSPeter Maydell static int gic_get_prio_from_apr_bits(GICState *s, int cpu) 29672889c8aSPeter Maydell { 29772889c8aSPeter Maydell /* Recalculate the current running priority for this CPU based 29872889c8aSPeter Maydell * on the set bits in the Active Priority Registers. 29972889c8aSPeter Maydell */ 30072889c8aSPeter Maydell int i; 30172889c8aSPeter Maydell for (i = 0; i < GIC_NR_APRS; i++) { 30272889c8aSPeter Maydell uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu]; 30372889c8aSPeter Maydell if (!apr) { 30472889c8aSPeter Maydell continue; 30572889c8aSPeter Maydell } 30672889c8aSPeter Maydell return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1); 30772889c8aSPeter Maydell } 30872889c8aSPeter Maydell return 0x100; 30972889c8aSPeter Maydell } 31072889c8aSPeter Maydell 31172889c8aSPeter Maydell static void gic_drop_prio(GICState *s, int cpu, int group) 31272889c8aSPeter Maydell { 31372889c8aSPeter Maydell /* Drop the priority of the currently active interrupt in the 31472889c8aSPeter Maydell * specified group. 31572889c8aSPeter Maydell * 31672889c8aSPeter Maydell * Note that we can guarantee (because of the requirement to nest 31772889c8aSPeter Maydell * GICC_IAR reads [which activate an interrupt and raise priority] 31872889c8aSPeter Maydell * with GICC_EOIR writes [which drop the priority for the interrupt]) 31972889c8aSPeter Maydell * that the interrupt we're being called for is the highest priority 32072889c8aSPeter Maydell * active interrupt, meaning that it has the lowest set bit in the 32172889c8aSPeter Maydell * APR registers. 32272889c8aSPeter Maydell * 32372889c8aSPeter Maydell * If the guest does not honour the ordering constraints then the 32472889c8aSPeter Maydell * behaviour of the GIC is UNPREDICTABLE, which for us means that 32572889c8aSPeter Maydell * the values of the APR registers might become incorrect and the 32672889c8aSPeter Maydell * running priority will be wrong, so interrupts that should preempt 32772889c8aSPeter Maydell * might not do so, and interrupts that should not preempt might do so. 32872889c8aSPeter Maydell */ 32972889c8aSPeter Maydell int i; 33072889c8aSPeter Maydell 33172889c8aSPeter Maydell for (i = 0; i < GIC_NR_APRS; i++) { 33272889c8aSPeter Maydell uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu]; 33372889c8aSPeter Maydell if (!*papr) { 33472889c8aSPeter Maydell continue; 33572889c8aSPeter Maydell } 33672889c8aSPeter Maydell /* Clear lowest set bit */ 33772889c8aSPeter Maydell *papr &= *papr - 1; 33872889c8aSPeter Maydell break; 33972889c8aSPeter Maydell } 34072889c8aSPeter Maydell 34172889c8aSPeter Maydell s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu); 342e69954b9Spbrook } 343e69954b9Spbrook 344c5619bf9SFabian Aggeler uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) 345e69954b9Spbrook { 34640d22500SChristoffer Dall int ret, irq, src; 3479ee6e8bbSpbrook int cm = 1 << cpu; 348c5619bf9SFabian Aggeler 349c5619bf9SFabian Aggeler /* gic_get_current_pending_irq() will return 1022 or 1023 appropriately 350c5619bf9SFabian Aggeler * for the case where this GIC supports grouping and the pending interrupt 351c5619bf9SFabian Aggeler * is in the wrong group. 352c5619bf9SFabian Aggeler */ 353a8f15a27SDaniel P. Berrange irq = gic_get_current_pending_irq(s, cpu, attrs); 3542531088fSHollis Blanchard trace_gic_acknowledge_irq(cpu, irq); 355c5619bf9SFabian Aggeler 356c5619bf9SFabian Aggeler if (irq >= GIC_MAXIRQ) { 357c5619bf9SFabian Aggeler DPRINTF("ACK, no pending interrupt or it is hidden: %d\n", irq); 358c5619bf9SFabian Aggeler return irq; 359c5619bf9SFabian Aggeler } 360c5619bf9SFabian Aggeler 36167ce697aSLuc Michel if (GIC_DIST_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) { 362c5619bf9SFabian Aggeler DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq); 363e69954b9Spbrook return 1023; 364e69954b9Spbrook } 36540d22500SChristoffer Dall 3667c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 3679ee6e8bbSpbrook /* Clear pending flags for both level and edge triggered interrupts. 36840d22500SChristoffer Dall * Level triggered IRQs will be reasserted once they become inactive. 36940d22500SChristoffer Dall */ 37067ce697aSLuc Michel GIC_DIST_CLEAR_PENDING(irq, GIC_DIST_TEST_MODEL(irq) ? ALL_CPU_MASK 37167ce697aSLuc Michel : cm); 37240d22500SChristoffer Dall ret = irq; 37340d22500SChristoffer Dall } else { 37440d22500SChristoffer Dall if (irq < GIC_NR_SGIS) { 37540d22500SChristoffer Dall /* Lookup the source CPU for the SGI and clear this in the 37640d22500SChristoffer Dall * sgi_pending map. Return the src and clear the overall pending 37740d22500SChristoffer Dall * state on this CPU if the SGI is not pending from any CPUs. 37840d22500SChristoffer Dall */ 37940d22500SChristoffer Dall assert(s->sgi_pending[irq][cpu] != 0); 38040d22500SChristoffer Dall src = ctz32(s->sgi_pending[irq][cpu]); 38140d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~(1 << src); 38240d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 38367ce697aSLuc Michel GIC_DIST_CLEAR_PENDING(irq, 38467ce697aSLuc Michel GIC_DIST_TEST_MODEL(irq) ? ALL_CPU_MASK 38567ce697aSLuc Michel : cm); 38640d22500SChristoffer Dall } 38740d22500SChristoffer Dall ret = irq | ((src & 0x7) << 10); 38840d22500SChristoffer Dall } else { 38940d22500SChristoffer Dall /* Clear pending state for both level and edge triggered 39040d22500SChristoffer Dall * interrupts. (level triggered interrupts with an active line 39140d22500SChristoffer Dall * remain pending, see gic_test_pending) 39240d22500SChristoffer Dall */ 39367ce697aSLuc Michel GIC_DIST_CLEAR_PENDING(irq, GIC_DIST_TEST_MODEL(irq) ? ALL_CPU_MASK 39467ce697aSLuc Michel : cm); 39540d22500SChristoffer Dall ret = irq; 39640d22500SChristoffer Dall } 39740d22500SChristoffer Dall } 39840d22500SChristoffer Dall 39972889c8aSPeter Maydell gic_activate_irq(s, cpu, irq); 40072889c8aSPeter Maydell gic_update(s); 40140d22500SChristoffer Dall DPRINTF("ACK %d\n", irq); 40240d22500SChristoffer Dall return ret; 403e69954b9Spbrook } 404e69954b9Spbrook 40567ce697aSLuc Michel void gic_dist_set_priority(GICState *s, int cpu, int irq, uint8_t val, 40681508470SFabian Aggeler MemTxAttrs attrs) 4079df90ad0SChristoffer Dall { 40881508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 40967ce697aSLuc Michel if (!GIC_DIST_TEST_GROUP(irq, (1 << cpu))) { 41081508470SFabian Aggeler return; /* Ignore Non-secure access of Group0 IRQ */ 41181508470SFabian Aggeler } 41281508470SFabian Aggeler val = 0x80 | (val >> 1); /* Non-secure view */ 41381508470SFabian Aggeler } 41481508470SFabian Aggeler 4159df90ad0SChristoffer Dall if (irq < GIC_INTERNAL) { 4169df90ad0SChristoffer Dall s->priority1[irq][cpu] = val; 4179df90ad0SChristoffer Dall } else { 4189df90ad0SChristoffer Dall s->priority2[(irq) - GIC_INTERNAL] = val; 4199df90ad0SChristoffer Dall } 4209df90ad0SChristoffer Dall } 4219df90ad0SChristoffer Dall 42267ce697aSLuc Michel static uint32_t gic_dist_get_priority(GICState *s, int cpu, int irq, 42381508470SFabian Aggeler MemTxAttrs attrs) 42481508470SFabian Aggeler { 42567ce697aSLuc Michel uint32_t prio = GIC_DIST_GET_PRIORITY(irq, cpu); 42681508470SFabian Aggeler 42781508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 42867ce697aSLuc Michel if (!GIC_DIST_TEST_GROUP(irq, (1 << cpu))) { 42981508470SFabian Aggeler return 0; /* Non-secure access cannot read priority of Group0 IRQ */ 43081508470SFabian Aggeler } 43181508470SFabian Aggeler prio = (prio << 1) & 0xff; /* Non-secure view */ 43281508470SFabian Aggeler } 43381508470SFabian Aggeler return prio; 43481508470SFabian Aggeler } 43581508470SFabian Aggeler 43681508470SFabian Aggeler static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask, 43781508470SFabian Aggeler MemTxAttrs attrs) 43881508470SFabian Aggeler { 43981508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 44081508470SFabian Aggeler if (s->priority_mask[cpu] & 0x80) { 44181508470SFabian Aggeler /* Priority Mask in upper half */ 44281508470SFabian Aggeler pmask = 0x80 | (pmask >> 1); 44381508470SFabian Aggeler } else { 44481508470SFabian Aggeler /* Non-secure write ignored if priority mask is in lower half */ 44581508470SFabian Aggeler return; 44681508470SFabian Aggeler } 44781508470SFabian Aggeler } 44881508470SFabian Aggeler s->priority_mask[cpu] = pmask; 44981508470SFabian Aggeler } 45081508470SFabian Aggeler 45181508470SFabian Aggeler static uint32_t gic_get_priority_mask(GICState *s, int cpu, MemTxAttrs attrs) 45281508470SFabian Aggeler { 45381508470SFabian Aggeler uint32_t pmask = s->priority_mask[cpu]; 45481508470SFabian Aggeler 45581508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 45681508470SFabian Aggeler if (pmask & 0x80) { 45781508470SFabian Aggeler /* Priority Mask in upper half, return Non-secure view */ 45881508470SFabian Aggeler pmask = (pmask << 1) & 0xff; 45981508470SFabian Aggeler } else { 46081508470SFabian Aggeler /* Priority Mask in lower half, RAZ */ 46181508470SFabian Aggeler pmask = 0; 46281508470SFabian Aggeler } 46381508470SFabian Aggeler } 46481508470SFabian Aggeler return pmask; 46581508470SFabian Aggeler } 46681508470SFabian Aggeler 46732951860SFabian Aggeler static uint32_t gic_get_cpu_control(GICState *s, int cpu, MemTxAttrs attrs) 46832951860SFabian Aggeler { 46932951860SFabian Aggeler uint32_t ret = s->cpu_ctlr[cpu]; 47032951860SFabian Aggeler 47132951860SFabian Aggeler if (s->security_extn && !attrs.secure) { 47232951860SFabian Aggeler /* Construct the NS banked view of GICC_CTLR from the correct 47332951860SFabian Aggeler * bits of the S banked view. We don't need to move the bypass 47432951860SFabian Aggeler * control bits because we don't implement that (IMPDEF) part 47532951860SFabian Aggeler * of the GIC architecture. 47632951860SFabian Aggeler */ 47732951860SFabian Aggeler ret = (ret & (GICC_CTLR_EN_GRP1 | GICC_CTLR_EOIMODE_NS)) >> 1; 47832951860SFabian Aggeler } 47932951860SFabian Aggeler return ret; 48032951860SFabian Aggeler } 48132951860SFabian Aggeler 48232951860SFabian Aggeler static void gic_set_cpu_control(GICState *s, int cpu, uint32_t value, 48332951860SFabian Aggeler MemTxAttrs attrs) 48432951860SFabian Aggeler { 48532951860SFabian Aggeler uint32_t mask; 48632951860SFabian Aggeler 48732951860SFabian Aggeler if (s->security_extn && !attrs.secure) { 48832951860SFabian Aggeler /* The NS view can only write certain bits in the register; 48932951860SFabian Aggeler * the rest are unchanged 49032951860SFabian Aggeler */ 49132951860SFabian Aggeler mask = GICC_CTLR_EN_GRP1; 49232951860SFabian Aggeler if (s->revision == 2) { 49332951860SFabian Aggeler mask |= GICC_CTLR_EOIMODE_NS; 49432951860SFabian Aggeler } 49532951860SFabian Aggeler s->cpu_ctlr[cpu] &= ~mask; 49632951860SFabian Aggeler s->cpu_ctlr[cpu] |= (value << 1) & mask; 49732951860SFabian Aggeler } else { 49832951860SFabian Aggeler if (s->revision == 2) { 49932951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V2_S_MASK : GICC_CTLR_V2_MASK; 50032951860SFabian Aggeler } else { 50132951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V1_S_MASK : GICC_CTLR_V1_MASK; 50232951860SFabian Aggeler } 50332951860SFabian Aggeler s->cpu_ctlr[cpu] = value & mask; 50432951860SFabian Aggeler } 50532951860SFabian Aggeler DPRINTF("CPU Interface %d: Group0 Interrupts %sabled, " 50632951860SFabian Aggeler "Group1 Interrupts %sabled\n", cpu, 50732951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP0) ? "En" : "Dis", 50832951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP1) ? "En" : "Dis"); 50932951860SFabian Aggeler } 51032951860SFabian Aggeler 51108efa9f2SFabian Aggeler static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs) 51208efa9f2SFabian Aggeler { 51371aa735bSLuc MICHEL if ((s->revision != REV_11MPCORE) && (s->running_priority[cpu] > 0xff)) { 51471aa735bSLuc MICHEL /* Idle priority */ 51571aa735bSLuc MICHEL return 0xff; 51671aa735bSLuc MICHEL } 51771aa735bSLuc MICHEL 51808efa9f2SFabian Aggeler if (s->security_extn && !attrs.secure) { 51908efa9f2SFabian Aggeler if (s->running_priority[cpu] & 0x80) { 52008efa9f2SFabian Aggeler /* Running priority in upper half of range: return the Non-secure 52108efa9f2SFabian Aggeler * view of the priority. 52208efa9f2SFabian Aggeler */ 52308efa9f2SFabian Aggeler return s->running_priority[cpu] << 1; 52408efa9f2SFabian Aggeler } else { 52508efa9f2SFabian Aggeler /* Running priority in lower half of range: RAZ */ 52608efa9f2SFabian Aggeler return 0; 52708efa9f2SFabian Aggeler } 52808efa9f2SFabian Aggeler } else { 52908efa9f2SFabian Aggeler return s->running_priority[cpu]; 53008efa9f2SFabian Aggeler } 53108efa9f2SFabian Aggeler } 53208efa9f2SFabian Aggeler 533a55c910eSPeter Maydell /* Return true if we should split priority drop and interrupt deactivation, 534a55c910eSPeter Maydell * ie whether the relevant EOIMode bit is set. 535a55c910eSPeter Maydell */ 536a55c910eSPeter Maydell static bool gic_eoi_split(GICState *s, int cpu, MemTxAttrs attrs) 537a55c910eSPeter Maydell { 538a55c910eSPeter Maydell if (s->revision != 2) { 539a55c910eSPeter Maydell /* Before GICv2 prio-drop and deactivate are not separable */ 540a55c910eSPeter Maydell return false; 541a55c910eSPeter Maydell } 542a55c910eSPeter Maydell if (s->security_extn && !attrs.secure) { 543a55c910eSPeter Maydell return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE_NS; 544a55c910eSPeter Maydell } 545a55c910eSPeter Maydell return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE; 546a55c910eSPeter Maydell } 547a55c910eSPeter Maydell 548a55c910eSPeter Maydell static void gic_deactivate_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) 549a55c910eSPeter Maydell { 550a55c910eSPeter Maydell int cm = 1 << cpu; 551ee03cca8SPeter Maydell int group; 552ee03cca8SPeter Maydell 553ee03cca8SPeter Maydell if (irq >= s->num_irq) { 554ee03cca8SPeter Maydell /* 555ee03cca8SPeter Maydell * This handles two cases: 556ee03cca8SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 557ee03cca8SPeter Maydell * to the GICC_DIR, the GIC ignores that write. 558ee03cca8SPeter Maydell * 2. If software writes the number of a non-existent interrupt 559ee03cca8SPeter Maydell * this must be a subcase of "value written is not an active interrupt" 560ee03cca8SPeter Maydell * and so this is UNPREDICTABLE. We choose to ignore it. 561ee03cca8SPeter Maydell */ 562ee03cca8SPeter Maydell return; 563ee03cca8SPeter Maydell } 564ee03cca8SPeter Maydell 56567ce697aSLuc Michel group = gic_has_groups(s) && GIC_DIST_TEST_GROUP(irq, cm); 566a55c910eSPeter Maydell 567a55c910eSPeter Maydell if (!gic_eoi_split(s, cpu, attrs)) { 568a55c910eSPeter Maydell /* This is UNPREDICTABLE; we choose to ignore it */ 569a55c910eSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 570a55c910eSPeter Maydell "gic_deactivate_irq: GICC_DIR write when EOIMode clear"); 571a55c910eSPeter Maydell return; 572a55c910eSPeter Maydell } 573a55c910eSPeter Maydell 574a55c910eSPeter Maydell if (s->security_extn && !attrs.secure && !group) { 575a55c910eSPeter Maydell DPRINTF("Non-secure DI for Group0 interrupt %d ignored\n", irq); 576a55c910eSPeter Maydell return; 577a55c910eSPeter Maydell } 578a55c910eSPeter Maydell 57967ce697aSLuc Michel GIC_DIST_CLEAR_ACTIVE(irq, cm); 580a55c910eSPeter Maydell } 581a55c910eSPeter Maydell 582f9c6a7f1SFabian Aggeler void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) 583e69954b9Spbrook { 5849ee6e8bbSpbrook int cm = 1 << cpu; 58572889c8aSPeter Maydell int group; 58672889c8aSPeter Maydell 587df628ff1Spbrook DPRINTF("EOI %d\n", irq); 588a32134aaSMark Langsdorf if (irq >= s->num_irq) { 589217bfb44SPeter Maydell /* This handles two cases: 590217bfb44SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 591217bfb44SPeter Maydell * to the GICC_EOIR, the GIC ignores that write. 592217bfb44SPeter Maydell * 2. If software writes the number of a non-existent interrupt 593217bfb44SPeter Maydell * this must be a subcase of "value written does not match the last 594217bfb44SPeter Maydell * valid interrupt value read from the Interrupt Acknowledge 595217bfb44SPeter Maydell * register" and so this is UNPREDICTABLE. We choose to ignore it. 596217bfb44SPeter Maydell */ 597217bfb44SPeter Maydell return; 598217bfb44SPeter Maydell } 59972889c8aSPeter Maydell if (s->running_priority[cpu] == 0x100) { 600e69954b9Spbrook return; /* No active IRQ. */ 60172889c8aSPeter Maydell } 6028d999995SChristoffer Dall 6033bc4b52cSMarcin Krzeminski if (s->revision == REV_11MPCORE) { 604e69954b9Spbrook /* Mark level triggered interrupts as pending if they are still 605e69954b9Spbrook raised. */ 60667ce697aSLuc Michel if (!GIC_DIST_TEST_EDGE_TRIGGER(irq) && GIC_DIST_TEST_ENABLED(irq, cm) 60767ce697aSLuc Michel && GIC_DIST_TEST_LEVEL(irq, cm) 60867ce697aSLuc Michel && (GIC_DIST_TARGET(irq) & cm) != 0) { 6099ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq, cm); 61067ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, cm); 611e69954b9Spbrook } 6128d999995SChristoffer Dall } 6138d999995SChristoffer Dall 61467ce697aSLuc Michel group = gic_has_groups(s) && GIC_DIST_TEST_GROUP(irq, cm); 61572889c8aSPeter Maydell 61672889c8aSPeter Maydell if (s->security_extn && !attrs.secure && !group) { 617f9c6a7f1SFabian Aggeler DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq); 618f9c6a7f1SFabian Aggeler return; 619f9c6a7f1SFabian Aggeler } 620f9c6a7f1SFabian Aggeler 621f9c6a7f1SFabian Aggeler /* Secure EOI with GICC_CTLR.AckCtl == 0 when the IRQ is a Group 1 622f9c6a7f1SFabian Aggeler * interrupt is UNPREDICTABLE. We choose to handle it as if AckCtl == 1, 623f9c6a7f1SFabian Aggeler * i.e. go ahead and complete the irq anyway. 624f9c6a7f1SFabian Aggeler */ 625f9c6a7f1SFabian Aggeler 62672889c8aSPeter Maydell gic_drop_prio(s, cpu, group); 627a55c910eSPeter Maydell 628a55c910eSPeter Maydell /* In GICv2 the guest can choose to split priority-drop and deactivate */ 629a55c910eSPeter Maydell if (!gic_eoi_split(s, cpu, attrs)) { 63067ce697aSLuc Michel GIC_DIST_CLEAR_ACTIVE(irq, cm); 631a55c910eSPeter Maydell } 632e69954b9Spbrook gic_update(s); 633e69954b9Spbrook } 634e69954b9Spbrook 635a9d85353SPeter Maydell static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) 636e69954b9Spbrook { 637fae15286SPeter Maydell GICState *s = (GICState *)opaque; 638e69954b9Spbrook uint32_t res; 639e69954b9Spbrook int irq; 640e69954b9Spbrook int i; 6419ee6e8bbSpbrook int cpu; 6429ee6e8bbSpbrook int cm; 6439ee6e8bbSpbrook int mask; 644e69954b9Spbrook 645926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 6469ee6e8bbSpbrook cm = 1 << cpu; 647e69954b9Spbrook if (offset < 0x100) { 648679aa175SFabian Aggeler if (offset == 0) { /* GICD_CTLR */ 649679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 650679aa175SFabian Aggeler /* The NS bank of this register is just an alias of the 651679aa175SFabian Aggeler * EnableGrp1 bit in the S bank version. 652679aa175SFabian Aggeler */ 653679aa175SFabian Aggeler return extract32(s->ctlr, 1, 1); 654679aa175SFabian Aggeler } else { 655679aa175SFabian Aggeler return s->ctlr; 656679aa175SFabian Aggeler } 657679aa175SFabian Aggeler } 658e69954b9Spbrook if (offset == 4) 6595543d1abSFabian Aggeler /* Interrupt Controller Type Register */ 6605543d1abSFabian Aggeler return ((s->num_irq / 32) - 1) 661b95690c9SWei Huang | ((s->num_cpu - 1) << 5) 6625543d1abSFabian Aggeler | (s->security_extn << 10); 663e69954b9Spbrook if (offset < 0x08) 664e69954b9Spbrook return 0; 665b79f2265SRob Herring if (offset >= 0x80) { 666c27a5ba9SFabian Aggeler /* Interrupt Group Registers: these RAZ/WI if this is an NS 667c27a5ba9SFabian Aggeler * access to a GIC with the security extensions, or if the GIC 668c27a5ba9SFabian Aggeler * doesn't have groups at all. 669c27a5ba9SFabian Aggeler */ 670c27a5ba9SFabian Aggeler res = 0; 671c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 672c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 673c27a5ba9SFabian Aggeler irq = (offset - 0x080) * 8 + GIC_BASE_IRQ; 674c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 675c27a5ba9SFabian Aggeler goto bad_reg; 676c27a5ba9SFabian Aggeler } 677c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 67867ce697aSLuc Michel if (GIC_DIST_TEST_GROUP(irq + i, cm)) { 679c27a5ba9SFabian Aggeler res |= (1 << i); 680c27a5ba9SFabian Aggeler } 681c27a5ba9SFabian Aggeler } 682c27a5ba9SFabian Aggeler } 683c27a5ba9SFabian Aggeler return res; 684b79f2265SRob Herring } 685e69954b9Spbrook goto bad_reg; 686e69954b9Spbrook } else if (offset < 0x200) { 687e69954b9Spbrook /* Interrupt Set/Clear Enable. */ 688e69954b9Spbrook if (offset < 0x180) 689e69954b9Spbrook irq = (offset - 0x100) * 8; 690e69954b9Spbrook else 691e69954b9Spbrook irq = (offset - 0x180) * 8; 6929ee6e8bbSpbrook irq += GIC_BASE_IRQ; 693a32134aaSMark Langsdorf if (irq >= s->num_irq) 694e69954b9Spbrook goto bad_reg; 695e69954b9Spbrook res = 0; 696e69954b9Spbrook for (i = 0; i < 8; i++) { 697fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 69867ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 699fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 700fea8a08eSJens Wiklander } 701fea8a08eSJens Wiklander 70267ce697aSLuc Michel if (GIC_DIST_TEST_ENABLED(irq + i, cm)) { 703e69954b9Spbrook res |= (1 << i); 704e69954b9Spbrook } 705e69954b9Spbrook } 706e69954b9Spbrook } else if (offset < 0x300) { 707e69954b9Spbrook /* Interrupt Set/Clear Pending. */ 708e69954b9Spbrook if (offset < 0x280) 709e69954b9Spbrook irq = (offset - 0x200) * 8; 710e69954b9Spbrook else 711e69954b9Spbrook irq = (offset - 0x280) * 8; 7129ee6e8bbSpbrook irq += GIC_BASE_IRQ; 713a32134aaSMark Langsdorf if (irq >= s->num_irq) 714e69954b9Spbrook goto bad_reg; 715e69954b9Spbrook res = 0; 71669253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 717e69954b9Spbrook for (i = 0; i < 8; i++) { 718fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 71967ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 720fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 721fea8a08eSJens Wiklander } 722fea8a08eSJens Wiklander 7238d999995SChristoffer Dall if (gic_test_pending(s, irq + i, mask)) { 724e69954b9Spbrook res |= (1 << i); 725e69954b9Spbrook } 726e69954b9Spbrook } 727e69954b9Spbrook } else if (offset < 0x400) { 728*3bb0b038SLuc Michel /* Interrupt Set/Clear Active. */ 729*3bb0b038SLuc Michel if (offset < 0x380) { 730*3bb0b038SLuc Michel irq = (offset - 0x300) * 8; 731*3bb0b038SLuc Michel } else if (s->revision == 2) { 732*3bb0b038SLuc Michel irq = (offset - 0x380) * 8; 733*3bb0b038SLuc Michel } else { 734*3bb0b038SLuc Michel goto bad_reg; 735*3bb0b038SLuc Michel } 736*3bb0b038SLuc Michel 737*3bb0b038SLuc Michel irq += GIC_BASE_IRQ; 738a32134aaSMark Langsdorf if (irq >= s->num_irq) 739e69954b9Spbrook goto bad_reg; 740e69954b9Spbrook res = 0; 74169253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 742e69954b9Spbrook for (i = 0; i < 8; i++) { 743fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 74467ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 745fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 746fea8a08eSJens Wiklander } 747fea8a08eSJens Wiklander 74867ce697aSLuc Michel if (GIC_DIST_TEST_ACTIVE(irq + i, mask)) { 749e69954b9Spbrook res |= (1 << i); 750e69954b9Spbrook } 751e69954b9Spbrook } 752e69954b9Spbrook } else if (offset < 0x800) { 753e69954b9Spbrook /* Interrupt Priority. */ 7549ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 755a32134aaSMark Langsdorf if (irq >= s->num_irq) 756e69954b9Spbrook goto bad_reg; 75767ce697aSLuc Michel res = gic_dist_get_priority(s, cpu, irq, attrs); 758e69954b9Spbrook } else if (offset < 0xc00) { 759e69954b9Spbrook /* Interrupt CPU Target. */ 7606b9680bbSPeter Maydell if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { 7616b9680bbSPeter Maydell /* For uniprocessor GICs these RAZ/WI */ 7626b9680bbSPeter Maydell res = 0; 7636b9680bbSPeter Maydell } else { 7649ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 7656b9680bbSPeter Maydell if (irq >= s->num_irq) { 766e69954b9Spbrook goto bad_reg; 7676b9680bbSPeter Maydell } 7687995206dSPeter Maydell if (irq < 29 && s->revision == REV_11MPCORE) { 7697995206dSPeter Maydell res = 0; 7707995206dSPeter Maydell } else if (irq < GIC_INTERNAL) { 7719ee6e8bbSpbrook res = cm; 7729ee6e8bbSpbrook } else { 77367ce697aSLuc Michel res = GIC_DIST_TARGET(irq); 7749ee6e8bbSpbrook } 7756b9680bbSPeter Maydell } 776e69954b9Spbrook } else if (offset < 0xf00) { 777e69954b9Spbrook /* Interrupt Configuration. */ 77871a62046SAdam Lackorzynski irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 779a32134aaSMark Langsdorf if (irq >= s->num_irq) 780e69954b9Spbrook goto bad_reg; 781e69954b9Spbrook res = 0; 782e69954b9Spbrook for (i = 0; i < 4; i++) { 783fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 78467ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 785fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 786fea8a08eSJens Wiklander } 787fea8a08eSJens Wiklander 78867ce697aSLuc Michel if (GIC_DIST_TEST_MODEL(irq + i)) { 789e69954b9Spbrook res |= (1 << (i * 2)); 79067ce697aSLuc Michel } 79167ce697aSLuc Michel if (GIC_DIST_TEST_EDGE_TRIGGER(irq + i)) { 792e69954b9Spbrook res |= (2 << (i * 2)); 793e69954b9Spbrook } 79467ce697aSLuc Michel } 79540d22500SChristoffer Dall } else if (offset < 0xf10) { 79640d22500SChristoffer Dall goto bad_reg; 79740d22500SChristoffer Dall } else if (offset < 0xf30) { 7987c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 79940d22500SChristoffer Dall goto bad_reg; 80040d22500SChristoffer Dall } 80140d22500SChristoffer Dall 80240d22500SChristoffer Dall if (offset < 0xf20) { 80340d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 80440d22500SChristoffer Dall irq = (offset - 0xf10); 80540d22500SChristoffer Dall } else { 80640d22500SChristoffer Dall irq = (offset - 0xf20); 80740d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 80840d22500SChristoffer Dall } 80940d22500SChristoffer Dall 810fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 81167ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq, 1 << cpu)) { 812fea8a08eSJens Wiklander res = 0; /* Ignore Non-secure access of Group0 IRQ */ 813fea8a08eSJens Wiklander } else { 81440d22500SChristoffer Dall res = s->sgi_pending[irq][cpu]; 815fea8a08eSJens Wiklander } 8163355c360SAlistair Francis } else if (offset < 0xfd0) { 817e69954b9Spbrook goto bad_reg; 8183355c360SAlistair Francis } else if (offset < 0x1000) { 819e69954b9Spbrook if (offset & 3) { 820e69954b9Spbrook res = 0; 821e69954b9Spbrook } else { 8223355c360SAlistair Francis switch (s->revision) { 8233355c360SAlistair Francis case REV_11MPCORE: 8243355c360SAlistair Francis res = gic_id_11mpcore[(offset - 0xfd0) >> 2]; 8253355c360SAlistair Francis break; 8263355c360SAlistair Francis case 1: 8273355c360SAlistair Francis res = gic_id_gicv1[(offset - 0xfd0) >> 2]; 8283355c360SAlistair Francis break; 8293355c360SAlistair Francis case 2: 8303355c360SAlistair Francis res = gic_id_gicv2[(offset - 0xfd0) >> 2]; 8313355c360SAlistair Francis break; 8323355c360SAlistair Francis default: 8333355c360SAlistair Francis res = 0; 834e69954b9Spbrook } 835e69954b9Spbrook } 8363355c360SAlistair Francis } else { 8373355c360SAlistair Francis g_assert_not_reached(); 8383355c360SAlistair Francis } 839e69954b9Spbrook return res; 840e69954b9Spbrook bad_reg: 8418c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 8428c8dc39fSPeter Maydell "gic_dist_readb: Bad offset %x\n", (int)offset); 843e69954b9Spbrook return 0; 844e69954b9Spbrook } 845e69954b9Spbrook 846a9d85353SPeter Maydell static MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data, 847a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 848e69954b9Spbrook { 849a9d85353SPeter Maydell switch (size) { 850a9d85353SPeter Maydell case 1: 851a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 852a9d85353SPeter Maydell return MEMTX_OK; 853a9d85353SPeter Maydell case 2: 854a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 855a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 856a9d85353SPeter Maydell return MEMTX_OK; 857a9d85353SPeter Maydell case 4: 858a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 859a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 860a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 2, attrs) << 16; 861a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 3, attrs) << 24; 862a9d85353SPeter Maydell return MEMTX_OK; 863a9d85353SPeter Maydell default: 864a9d85353SPeter Maydell return MEMTX_ERROR; 865e69954b9Spbrook } 866e69954b9Spbrook } 867e69954b9Spbrook 868a8170e5eSAvi Kivity static void gic_dist_writeb(void *opaque, hwaddr offset, 869a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 870e69954b9Spbrook { 871fae15286SPeter Maydell GICState *s = (GICState *)opaque; 872e69954b9Spbrook int irq; 873e69954b9Spbrook int i; 8749ee6e8bbSpbrook int cpu; 875e69954b9Spbrook 876926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 877e69954b9Spbrook if (offset < 0x100) { 878e69954b9Spbrook if (offset == 0) { 879679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 880679aa175SFabian Aggeler /* NS version is just an alias of the S version's bit 1 */ 881679aa175SFabian Aggeler s->ctlr = deposit32(s->ctlr, 1, 1, value); 882679aa175SFabian Aggeler } else if (gic_has_groups(s)) { 883679aa175SFabian Aggeler s->ctlr = value & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1); 884679aa175SFabian Aggeler } else { 885679aa175SFabian Aggeler s->ctlr = value & GICD_CTLR_EN_GRP0; 886679aa175SFabian Aggeler } 887679aa175SFabian Aggeler DPRINTF("Distributor: Group0 %sabled; Group 1 %sabled\n", 888679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP0 ? "En" : "Dis", 889679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP1 ? "En" : "Dis"); 890e69954b9Spbrook } else if (offset < 4) { 891e69954b9Spbrook /* ignored. */ 892b79f2265SRob Herring } else if (offset >= 0x80) { 893c27a5ba9SFabian Aggeler /* Interrupt Group Registers: RAZ/WI for NS access to secure 894c27a5ba9SFabian Aggeler * GIC, or for GICs without groups. 895c27a5ba9SFabian Aggeler */ 896c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 897c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 898c27a5ba9SFabian Aggeler irq = (offset - 0x80) * 8 + GIC_BASE_IRQ; 899c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 900c27a5ba9SFabian Aggeler goto bad_reg; 901c27a5ba9SFabian Aggeler } 902c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 903c27a5ba9SFabian Aggeler /* Group bits are banked for private interrupts */ 904c27a5ba9SFabian Aggeler int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 905c27a5ba9SFabian Aggeler if (value & (1 << i)) { 906c27a5ba9SFabian Aggeler /* Group1 (Non-secure) */ 90767ce697aSLuc Michel GIC_DIST_SET_GROUP(irq + i, cm); 908c27a5ba9SFabian Aggeler } else { 909c27a5ba9SFabian Aggeler /* Group0 (Secure) */ 91067ce697aSLuc Michel GIC_DIST_CLEAR_GROUP(irq + i, cm); 911c27a5ba9SFabian Aggeler } 912c27a5ba9SFabian Aggeler } 913c27a5ba9SFabian Aggeler } 914e69954b9Spbrook } else { 915e69954b9Spbrook goto bad_reg; 916e69954b9Spbrook } 917e69954b9Spbrook } else if (offset < 0x180) { 918e69954b9Spbrook /* Interrupt Set Enable. */ 9199ee6e8bbSpbrook irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 920a32134aaSMark Langsdorf if (irq >= s->num_irq) 921e69954b9Spbrook goto bad_reg; 92241ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 9239ee6e8bbSpbrook value = 0xff; 92441ab7b55SChristoffer Dall } 92541ab7b55SChristoffer Dall 926e69954b9Spbrook for (i = 0; i < 8; i++) { 927e69954b9Spbrook if (value & (1 << i)) { 928f47b48fbSDaniel Sangorrin int mask = 92967ce697aSLuc Michel (irq < GIC_INTERNAL) ? (1 << cpu) 93067ce697aSLuc Michel : GIC_DIST_TARGET(irq + i); 93169253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 93241bf234dSRabin Vincent 933fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 93467ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 935fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 936fea8a08eSJens Wiklander } 937fea8a08eSJens Wiklander 93867ce697aSLuc Michel if (!GIC_DIST_TEST_ENABLED(irq + i, cm)) { 939e69954b9Spbrook DPRINTF("Enabled IRQ %d\n", irq + i); 9402531088fSHollis Blanchard trace_gic_enable_irq(irq + i); 94141bf234dSRabin Vincent } 94267ce697aSLuc Michel GIC_DIST_SET_ENABLED(irq + i, cm); 943e69954b9Spbrook /* If a raised level triggered IRQ enabled then mark 944e69954b9Spbrook is as pending. */ 94567ce697aSLuc Michel if (GIC_DIST_TEST_LEVEL(irq + i, mask) 94667ce697aSLuc Michel && !GIC_DIST_TEST_EDGE_TRIGGER(irq + i)) { 9479ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq + i, mask); 94867ce697aSLuc Michel GIC_DIST_SET_PENDING(irq + i, mask); 9499ee6e8bbSpbrook } 950e69954b9Spbrook } 951e69954b9Spbrook } 952e69954b9Spbrook } else if (offset < 0x200) { 953e69954b9Spbrook /* Interrupt Clear Enable. */ 9549ee6e8bbSpbrook irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 955a32134aaSMark Langsdorf if (irq >= s->num_irq) 956e69954b9Spbrook goto bad_reg; 95741ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 9589ee6e8bbSpbrook value = 0; 95941ab7b55SChristoffer Dall } 96041ab7b55SChristoffer Dall 961e69954b9Spbrook for (i = 0; i < 8; i++) { 962e69954b9Spbrook if (value & (1 << i)) { 96369253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 96441bf234dSRabin Vincent 965fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 96667ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 967fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 968fea8a08eSJens Wiklander } 969fea8a08eSJens Wiklander 97067ce697aSLuc Michel if (GIC_DIST_TEST_ENABLED(irq + i, cm)) { 971e69954b9Spbrook DPRINTF("Disabled IRQ %d\n", irq + i); 9722531088fSHollis Blanchard trace_gic_disable_irq(irq + i); 97341bf234dSRabin Vincent } 97467ce697aSLuc Michel GIC_DIST_CLEAR_ENABLED(irq + i, cm); 975e69954b9Spbrook } 976e69954b9Spbrook } 977e69954b9Spbrook } else if (offset < 0x280) { 978e69954b9Spbrook /* Interrupt Set Pending. */ 9799ee6e8bbSpbrook irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 980a32134aaSMark Langsdorf if (irq >= s->num_irq) 981e69954b9Spbrook goto bad_reg; 98241ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 9835b0adce1SChristoffer Dall value = 0; 98441ab7b55SChristoffer Dall } 9859ee6e8bbSpbrook 986e69954b9Spbrook for (i = 0; i < 8; i++) { 987e69954b9Spbrook if (value & (1 << i)) { 988fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 98967ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 990fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 991fea8a08eSJens Wiklander } 992fea8a08eSJens Wiklander 99367ce697aSLuc Michel GIC_DIST_SET_PENDING(irq + i, GIC_DIST_TARGET(irq + i)); 994e69954b9Spbrook } 995e69954b9Spbrook } 996e69954b9Spbrook } else if (offset < 0x300) { 997e69954b9Spbrook /* Interrupt Clear Pending. */ 9989ee6e8bbSpbrook irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 999a32134aaSMark Langsdorf if (irq >= s->num_irq) 1000e69954b9Spbrook goto bad_reg; 10015b0adce1SChristoffer Dall if (irq < GIC_NR_SGIS) { 10025b0adce1SChristoffer Dall value = 0; 10035b0adce1SChristoffer Dall } 10045b0adce1SChristoffer Dall 1005e69954b9Spbrook for (i = 0; i < 8; i++) { 1006fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 100767ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1008fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 1009fea8a08eSJens Wiklander } 1010fea8a08eSJens Wiklander 10119ee6e8bbSpbrook /* ??? This currently clears the pending bit for all CPUs, even 10129ee6e8bbSpbrook for per-CPU interrupts. It's unclear whether this is the 10139ee6e8bbSpbrook corect behavior. */ 1014e69954b9Spbrook if (value & (1 << i)) { 101567ce697aSLuc Michel GIC_DIST_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 1016e69954b9Spbrook } 1017e69954b9Spbrook } 1018*3bb0b038SLuc Michel } else if (offset < 0x380) { 1019*3bb0b038SLuc Michel /* Interrupt Set Active. */ 1020*3bb0b038SLuc Michel if (s->revision != 2) { 1021e69954b9Spbrook goto bad_reg; 1022*3bb0b038SLuc Michel } 1023*3bb0b038SLuc Michel 1024*3bb0b038SLuc Michel irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 1025*3bb0b038SLuc Michel if (irq >= s->num_irq) { 1026*3bb0b038SLuc Michel goto bad_reg; 1027*3bb0b038SLuc Michel } 1028*3bb0b038SLuc Michel 1029*3bb0b038SLuc Michel /* This register is banked per-cpu for PPIs */ 1030*3bb0b038SLuc Michel int cm = irq < GIC_INTERNAL ? (1 << cpu) : ALL_CPU_MASK; 1031*3bb0b038SLuc Michel 1032*3bb0b038SLuc Michel for (i = 0; i < 8; i++) { 1033*3bb0b038SLuc Michel if (s->security_extn && !attrs.secure && 1034*3bb0b038SLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1035*3bb0b038SLuc Michel continue; /* Ignore Non-secure access of Group0 IRQ */ 1036*3bb0b038SLuc Michel } 1037*3bb0b038SLuc Michel 1038*3bb0b038SLuc Michel if (value & (1 << i)) { 1039*3bb0b038SLuc Michel GIC_DIST_SET_ACTIVE(irq + i, cm); 1040*3bb0b038SLuc Michel } 1041*3bb0b038SLuc Michel } 1042*3bb0b038SLuc Michel } else if (offset < 0x400) { 1043*3bb0b038SLuc Michel /* Interrupt Clear Active. */ 1044*3bb0b038SLuc Michel if (s->revision != 2) { 1045*3bb0b038SLuc Michel goto bad_reg; 1046*3bb0b038SLuc Michel } 1047*3bb0b038SLuc Michel 1048*3bb0b038SLuc Michel irq = (offset - 0x380) * 8 + GIC_BASE_IRQ; 1049*3bb0b038SLuc Michel if (irq >= s->num_irq) { 1050*3bb0b038SLuc Michel goto bad_reg; 1051*3bb0b038SLuc Michel } 1052*3bb0b038SLuc Michel 1053*3bb0b038SLuc Michel /* This register is banked per-cpu for PPIs */ 1054*3bb0b038SLuc Michel int cm = irq < GIC_INTERNAL ? (1 << cpu) : ALL_CPU_MASK; 1055*3bb0b038SLuc Michel 1056*3bb0b038SLuc Michel for (i = 0; i < 8; i++) { 1057*3bb0b038SLuc Michel if (s->security_extn && !attrs.secure && 1058*3bb0b038SLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1059*3bb0b038SLuc Michel continue; /* Ignore Non-secure access of Group0 IRQ */ 1060*3bb0b038SLuc Michel } 1061*3bb0b038SLuc Michel 1062*3bb0b038SLuc Michel if (value & (1 << i)) { 1063*3bb0b038SLuc Michel GIC_DIST_CLEAR_ACTIVE(irq + i, cm); 1064*3bb0b038SLuc Michel } 1065*3bb0b038SLuc Michel } 1066e69954b9Spbrook } else if (offset < 0x800) { 1067e69954b9Spbrook /* Interrupt Priority. */ 10689ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 1069a32134aaSMark Langsdorf if (irq >= s->num_irq) 1070e69954b9Spbrook goto bad_reg; 107167ce697aSLuc Michel gic_dist_set_priority(s, cpu, irq, value, attrs); 1072e69954b9Spbrook } else if (offset < 0xc00) { 10736b9680bbSPeter Maydell /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the 10746b9680bbSPeter Maydell * annoying exception of the 11MPCore's GIC. 10756b9680bbSPeter Maydell */ 10766b9680bbSPeter Maydell if (s->num_cpu != 1 || s->revision == REV_11MPCORE) { 10779ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 10786b9680bbSPeter Maydell if (irq >= s->num_irq) { 1079e69954b9Spbrook goto bad_reg; 10806b9680bbSPeter Maydell } 10817995206dSPeter Maydell if (irq < 29 && s->revision == REV_11MPCORE) { 10829ee6e8bbSpbrook value = 0; 10836b9680bbSPeter Maydell } else if (irq < GIC_INTERNAL) { 10849ee6e8bbSpbrook value = ALL_CPU_MASK; 10856b9680bbSPeter Maydell } 10869ee6e8bbSpbrook s->irq_target[irq] = value & ALL_CPU_MASK; 10876b9680bbSPeter Maydell } 1088e69954b9Spbrook } else if (offset < 0xf00) { 1089e69954b9Spbrook /* Interrupt Configuration. */ 10909ee6e8bbSpbrook irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 1091a32134aaSMark Langsdorf if (irq >= s->num_irq) 1092e69954b9Spbrook goto bad_reg; 1093de7a900fSAdam Lackorzynski if (irq < GIC_NR_SGIS) 10949ee6e8bbSpbrook value |= 0xaa; 1095e69954b9Spbrook for (i = 0; i < 4; i++) { 1096fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 109767ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1098fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 1099fea8a08eSJens Wiklander } 1100fea8a08eSJens Wiklander 11017c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 1102e69954b9Spbrook if (value & (1 << (i * 2))) { 110367ce697aSLuc Michel GIC_DIST_SET_MODEL(irq + i); 1104e69954b9Spbrook } else { 110567ce697aSLuc Michel GIC_DIST_CLEAR_MODEL(irq + i); 1106e69954b9Spbrook } 110724b790dfSAdam Lackorzynski } 1108e69954b9Spbrook if (value & (2 << (i * 2))) { 110967ce697aSLuc Michel GIC_DIST_SET_EDGE_TRIGGER(irq + i); 1110e69954b9Spbrook } else { 111167ce697aSLuc Michel GIC_DIST_CLEAR_EDGE_TRIGGER(irq + i); 1112e69954b9Spbrook } 1113e69954b9Spbrook } 111440d22500SChristoffer Dall } else if (offset < 0xf10) { 11159ee6e8bbSpbrook /* 0xf00 is only handled for 32-bit writes. */ 1116e69954b9Spbrook goto bad_reg; 111740d22500SChristoffer Dall } else if (offset < 0xf20) { 111840d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 11197c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 112040d22500SChristoffer Dall goto bad_reg; 112140d22500SChristoffer Dall } 112240d22500SChristoffer Dall irq = (offset - 0xf10); 112340d22500SChristoffer Dall 1124fea8a08eSJens Wiklander if (!s->security_extn || attrs.secure || 112567ce697aSLuc Michel GIC_DIST_TEST_GROUP(irq, 1 << cpu)) { 112640d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~value; 112740d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 112867ce697aSLuc Michel GIC_DIST_CLEAR_PENDING(irq, 1 << cpu); 112940d22500SChristoffer Dall } 1130fea8a08eSJens Wiklander } 113140d22500SChristoffer Dall } else if (offset < 0xf30) { 113240d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 11337c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 113440d22500SChristoffer Dall goto bad_reg; 113540d22500SChristoffer Dall } 113640d22500SChristoffer Dall irq = (offset - 0xf20); 113740d22500SChristoffer Dall 1138fea8a08eSJens Wiklander if (!s->security_extn || attrs.secure || 113967ce697aSLuc Michel GIC_DIST_TEST_GROUP(irq, 1 << cpu)) { 114067ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, 1 << cpu); 114140d22500SChristoffer Dall s->sgi_pending[irq][cpu] |= value; 1142fea8a08eSJens Wiklander } 114340d22500SChristoffer Dall } else { 114440d22500SChristoffer Dall goto bad_reg; 1145e69954b9Spbrook } 1146e69954b9Spbrook gic_update(s); 1147e69954b9Spbrook return; 1148e69954b9Spbrook bad_reg: 11498c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 11508c8dc39fSPeter Maydell "gic_dist_writeb: Bad offset %x\n", (int)offset); 1151e69954b9Spbrook } 1152e69954b9Spbrook 1153a8170e5eSAvi Kivity static void gic_dist_writew(void *opaque, hwaddr offset, 1154a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1155e69954b9Spbrook { 1156a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, value & 0xff, attrs); 1157a9d85353SPeter Maydell gic_dist_writeb(opaque, offset + 1, value >> 8, attrs); 1158e69954b9Spbrook } 1159e69954b9Spbrook 1160a8170e5eSAvi Kivity static void gic_dist_writel(void *opaque, hwaddr offset, 1161a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1162e69954b9Spbrook { 1163fae15286SPeter Maydell GICState *s = (GICState *)opaque; 11648da3ff18Spbrook if (offset == 0xf00) { 11659ee6e8bbSpbrook int cpu; 11669ee6e8bbSpbrook int irq; 11679ee6e8bbSpbrook int mask; 116840d22500SChristoffer Dall int target_cpu; 11699ee6e8bbSpbrook 1170926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 11719ee6e8bbSpbrook irq = value & 0x3ff; 11729ee6e8bbSpbrook switch ((value >> 24) & 3) { 11739ee6e8bbSpbrook case 0: 11749ee6e8bbSpbrook mask = (value >> 16) & ALL_CPU_MASK; 11759ee6e8bbSpbrook break; 11769ee6e8bbSpbrook case 1: 1177fa250144SAdam Lackorzynski mask = ALL_CPU_MASK ^ (1 << cpu); 11789ee6e8bbSpbrook break; 11799ee6e8bbSpbrook case 2: 1180fa250144SAdam Lackorzynski mask = 1 << cpu; 11819ee6e8bbSpbrook break; 11829ee6e8bbSpbrook default: 11839ee6e8bbSpbrook DPRINTF("Bad Soft Int target filter\n"); 11849ee6e8bbSpbrook mask = ALL_CPU_MASK; 11859ee6e8bbSpbrook break; 11869ee6e8bbSpbrook } 118767ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, mask); 118840d22500SChristoffer Dall target_cpu = ctz32(mask); 118940d22500SChristoffer Dall while (target_cpu < GIC_NCPU) { 119040d22500SChristoffer Dall s->sgi_pending[irq][target_cpu] |= (1 << cpu); 119140d22500SChristoffer Dall mask &= ~(1 << target_cpu); 119240d22500SChristoffer Dall target_cpu = ctz32(mask); 119340d22500SChristoffer Dall } 11949ee6e8bbSpbrook gic_update(s); 11959ee6e8bbSpbrook return; 11969ee6e8bbSpbrook } 1197a9d85353SPeter Maydell gic_dist_writew(opaque, offset, value & 0xffff, attrs); 1198a9d85353SPeter Maydell gic_dist_writew(opaque, offset + 2, value >> 16, attrs); 1199a9d85353SPeter Maydell } 1200a9d85353SPeter Maydell 1201a9d85353SPeter Maydell static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data, 1202a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1203a9d85353SPeter Maydell { 1204a9d85353SPeter Maydell switch (size) { 1205a9d85353SPeter Maydell case 1: 1206a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, data, attrs); 1207a9d85353SPeter Maydell return MEMTX_OK; 1208a9d85353SPeter Maydell case 2: 1209a9d85353SPeter Maydell gic_dist_writew(opaque, offset, data, attrs); 1210a9d85353SPeter Maydell return MEMTX_OK; 1211a9d85353SPeter Maydell case 4: 1212a9d85353SPeter Maydell gic_dist_writel(opaque, offset, data, attrs); 1213a9d85353SPeter Maydell return MEMTX_OK; 1214a9d85353SPeter Maydell default: 1215a9d85353SPeter Maydell return MEMTX_ERROR; 1216a9d85353SPeter Maydell } 1217e69954b9Spbrook } 1218e69954b9Spbrook 121951fd06e0SPeter Maydell static inline uint32_t gic_apr_ns_view(GICState *s, int cpu, int regno) 122051fd06e0SPeter Maydell { 122151fd06e0SPeter Maydell /* Return the Nonsecure view of GICC_APR<regno>. This is the 122251fd06e0SPeter Maydell * second half of GICC_NSAPR. 122351fd06e0SPeter Maydell */ 122451fd06e0SPeter Maydell switch (GIC_MIN_BPR) { 122551fd06e0SPeter Maydell case 0: 122651fd06e0SPeter Maydell if (regno < 2) { 122751fd06e0SPeter Maydell return s->nsapr[regno + 2][cpu]; 122851fd06e0SPeter Maydell } 122951fd06e0SPeter Maydell break; 123051fd06e0SPeter Maydell case 1: 123151fd06e0SPeter Maydell if (regno == 0) { 123251fd06e0SPeter Maydell return s->nsapr[regno + 1][cpu]; 123351fd06e0SPeter Maydell } 123451fd06e0SPeter Maydell break; 123551fd06e0SPeter Maydell case 2: 123651fd06e0SPeter Maydell if (regno == 0) { 123751fd06e0SPeter Maydell return extract32(s->nsapr[0][cpu], 16, 16); 123851fd06e0SPeter Maydell } 123951fd06e0SPeter Maydell break; 124051fd06e0SPeter Maydell case 3: 124151fd06e0SPeter Maydell if (regno == 0) { 124251fd06e0SPeter Maydell return extract32(s->nsapr[0][cpu], 8, 8); 124351fd06e0SPeter Maydell } 124451fd06e0SPeter Maydell break; 124551fd06e0SPeter Maydell default: 124651fd06e0SPeter Maydell g_assert_not_reached(); 124751fd06e0SPeter Maydell } 124851fd06e0SPeter Maydell return 0; 124951fd06e0SPeter Maydell } 125051fd06e0SPeter Maydell 125151fd06e0SPeter Maydell static inline void gic_apr_write_ns_view(GICState *s, int cpu, int regno, 125251fd06e0SPeter Maydell uint32_t value) 125351fd06e0SPeter Maydell { 125451fd06e0SPeter Maydell /* Write the Nonsecure view of GICC_APR<regno>. */ 125551fd06e0SPeter Maydell switch (GIC_MIN_BPR) { 125651fd06e0SPeter Maydell case 0: 125751fd06e0SPeter Maydell if (regno < 2) { 125851fd06e0SPeter Maydell s->nsapr[regno + 2][cpu] = value; 125951fd06e0SPeter Maydell } 126051fd06e0SPeter Maydell break; 126151fd06e0SPeter Maydell case 1: 126251fd06e0SPeter Maydell if (regno == 0) { 126351fd06e0SPeter Maydell s->nsapr[regno + 1][cpu] = value; 126451fd06e0SPeter Maydell } 126551fd06e0SPeter Maydell break; 126651fd06e0SPeter Maydell case 2: 126751fd06e0SPeter Maydell if (regno == 0) { 126851fd06e0SPeter Maydell s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 16, 16, value); 126951fd06e0SPeter Maydell } 127051fd06e0SPeter Maydell break; 127151fd06e0SPeter Maydell case 3: 127251fd06e0SPeter Maydell if (regno == 0) { 127351fd06e0SPeter Maydell s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 8, 8, value); 127451fd06e0SPeter Maydell } 127551fd06e0SPeter Maydell break; 127651fd06e0SPeter Maydell default: 127751fd06e0SPeter Maydell g_assert_not_reached(); 127851fd06e0SPeter Maydell } 127951fd06e0SPeter Maydell } 128051fd06e0SPeter Maydell 1281a9d85353SPeter Maydell static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, 1282a9d85353SPeter Maydell uint64_t *data, MemTxAttrs attrs) 1283e69954b9Spbrook { 1284e69954b9Spbrook switch (offset) { 1285e69954b9Spbrook case 0x00: /* Control */ 128632951860SFabian Aggeler *data = gic_get_cpu_control(s, cpu, attrs); 1287a9d85353SPeter Maydell break; 1288e69954b9Spbrook case 0x04: /* Priority mask */ 128981508470SFabian Aggeler *data = gic_get_priority_mask(s, cpu, attrs); 1290a9d85353SPeter Maydell break; 1291e69954b9Spbrook case 0x08: /* Binary Point */ 1292822e9cc3SFabian Aggeler if (s->security_extn && !attrs.secure) { 1293421a3c22SLuc MICHEL if (s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) { 1294421a3c22SLuc MICHEL /* NS view of BPR when CBPR is 1 */ 1295421a3c22SLuc MICHEL *data = MIN(s->bpr[cpu] + 1, 7); 1296421a3c22SLuc MICHEL } else { 1297822e9cc3SFabian Aggeler /* BPR is banked. Non-secure copy stored in ABPR. */ 1298822e9cc3SFabian Aggeler *data = s->abpr[cpu]; 1299421a3c22SLuc MICHEL } 1300822e9cc3SFabian Aggeler } else { 1301a9d85353SPeter Maydell *data = s->bpr[cpu]; 1302822e9cc3SFabian Aggeler } 1303a9d85353SPeter Maydell break; 1304e69954b9Spbrook case 0x0c: /* Acknowledge */ 1305c5619bf9SFabian Aggeler *data = gic_acknowledge_irq(s, cpu, attrs); 1306a9d85353SPeter Maydell break; 130766a0a2cbSDong Xu Wang case 0x14: /* Running Priority */ 130808efa9f2SFabian Aggeler *data = gic_get_running_priority(s, cpu, attrs); 1309a9d85353SPeter Maydell break; 1310e69954b9Spbrook case 0x18: /* Highest Pending Interrupt */ 13117c0fa108SFabian Aggeler *data = gic_get_current_pending_irq(s, cpu, attrs); 1312a9d85353SPeter Maydell break; 1313aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 1314822e9cc3SFabian Aggeler /* GIC v2, no security: ABPR 1315822e9cc3SFabian Aggeler * GIC v1, no security: not implemented (RAZ/WI) 1316822e9cc3SFabian Aggeler * With security extensions, secure access: ABPR (alias of NS BPR) 1317822e9cc3SFabian Aggeler * With security extensions, nonsecure access: RAZ/WI 1318822e9cc3SFabian Aggeler */ 1319822e9cc3SFabian Aggeler if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 1320822e9cc3SFabian Aggeler *data = 0; 1321822e9cc3SFabian Aggeler } else { 1322a9d85353SPeter Maydell *data = s->abpr[cpu]; 1323822e9cc3SFabian Aggeler } 1324a9d85353SPeter Maydell break; 1325a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 132651fd06e0SPeter Maydell { 132751fd06e0SPeter Maydell int regno = (offset - 0xd0) / 4; 132851fd06e0SPeter Maydell 132951fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 133051fd06e0SPeter Maydell *data = 0; 133151fd06e0SPeter Maydell } else if (s->security_extn && !attrs.secure) { 133251fd06e0SPeter Maydell /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ 133351fd06e0SPeter Maydell *data = gic_apr_ns_view(s, regno, cpu); 133451fd06e0SPeter Maydell } else { 133551fd06e0SPeter Maydell *data = s->apr[regno][cpu]; 133651fd06e0SPeter Maydell } 1337a9d85353SPeter Maydell break; 133851fd06e0SPeter Maydell } 133951fd06e0SPeter Maydell case 0xe0: case 0xe4: case 0xe8: case 0xec: 134051fd06e0SPeter Maydell { 134151fd06e0SPeter Maydell int regno = (offset - 0xe0) / 4; 134251fd06e0SPeter Maydell 134351fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2 || !gic_has_groups(s) || 134451fd06e0SPeter Maydell (s->security_extn && !attrs.secure)) { 134551fd06e0SPeter Maydell *data = 0; 134651fd06e0SPeter Maydell } else { 134751fd06e0SPeter Maydell *data = s->nsapr[regno][cpu]; 134851fd06e0SPeter Maydell } 134951fd06e0SPeter Maydell break; 135051fd06e0SPeter Maydell } 1351e69954b9Spbrook default: 13528c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 13538c8dc39fSPeter Maydell "gic_cpu_read: Bad offset %x\n", (int)offset); 13540cf09852SPeter Maydell *data = 0; 13550cf09852SPeter Maydell break; 1356e69954b9Spbrook } 1357a9d85353SPeter Maydell return MEMTX_OK; 1358e69954b9Spbrook } 1359e69954b9Spbrook 1360a9d85353SPeter Maydell static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, 1361a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1362e69954b9Spbrook { 1363e69954b9Spbrook switch (offset) { 1364e69954b9Spbrook case 0x00: /* Control */ 136532951860SFabian Aggeler gic_set_cpu_control(s, cpu, value, attrs); 1366e69954b9Spbrook break; 1367e69954b9Spbrook case 0x04: /* Priority mask */ 136881508470SFabian Aggeler gic_set_priority_mask(s, cpu, value, attrs); 1369e69954b9Spbrook break; 1370e69954b9Spbrook case 0x08: /* Binary Point */ 1371822e9cc3SFabian Aggeler if (s->security_extn && !attrs.secure) { 1372421a3c22SLuc MICHEL if (s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) { 1373421a3c22SLuc MICHEL /* WI when CBPR is 1 */ 1374421a3c22SLuc MICHEL return MEMTX_OK; 1375421a3c22SLuc MICHEL } else { 1376822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1377421a3c22SLuc MICHEL } 1378822e9cc3SFabian Aggeler } else { 1379822e9cc3SFabian Aggeler s->bpr[cpu] = MAX(value & 0x7, GIC_MIN_BPR); 1380822e9cc3SFabian Aggeler } 1381e69954b9Spbrook break; 1382e69954b9Spbrook case 0x10: /* End Of Interrupt */ 1383f9c6a7f1SFabian Aggeler gic_complete_irq(s, cpu, value & 0x3ff, attrs); 1384a9d85353SPeter Maydell return MEMTX_OK; 1385aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 1386822e9cc3SFabian Aggeler if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 1387822e9cc3SFabian Aggeler /* unimplemented, or NS access: RAZ/WI */ 1388822e9cc3SFabian Aggeler return MEMTX_OK; 1389822e9cc3SFabian Aggeler } else { 1390822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1391aa7d461aSChristoffer Dall } 1392aa7d461aSChristoffer Dall break; 1393a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 139451fd06e0SPeter Maydell { 139551fd06e0SPeter Maydell int regno = (offset - 0xd0) / 4; 139651fd06e0SPeter Maydell 139751fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 139851fd06e0SPeter Maydell return MEMTX_OK; 139951fd06e0SPeter Maydell } 140051fd06e0SPeter Maydell if (s->security_extn && !attrs.secure) { 140151fd06e0SPeter Maydell /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ 140251fd06e0SPeter Maydell gic_apr_write_ns_view(s, regno, cpu, value); 140351fd06e0SPeter Maydell } else { 140451fd06e0SPeter Maydell s->apr[regno][cpu] = value; 140551fd06e0SPeter Maydell } 1406a9d477c4SChristoffer Dall break; 140751fd06e0SPeter Maydell } 140851fd06e0SPeter Maydell case 0xe0: case 0xe4: case 0xe8: case 0xec: 140951fd06e0SPeter Maydell { 141051fd06e0SPeter Maydell int regno = (offset - 0xe0) / 4; 141151fd06e0SPeter Maydell 141251fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 141351fd06e0SPeter Maydell return MEMTX_OK; 141451fd06e0SPeter Maydell } 141551fd06e0SPeter Maydell if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 141651fd06e0SPeter Maydell return MEMTX_OK; 141751fd06e0SPeter Maydell } 141851fd06e0SPeter Maydell s->nsapr[regno][cpu] = value; 141951fd06e0SPeter Maydell break; 142051fd06e0SPeter Maydell } 1421a55c910eSPeter Maydell case 0x1000: 1422a55c910eSPeter Maydell /* GICC_DIR */ 1423a55c910eSPeter Maydell gic_deactivate_irq(s, cpu, value & 0x3ff, attrs); 1424a55c910eSPeter Maydell break; 1425e69954b9Spbrook default: 14268c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 14278c8dc39fSPeter Maydell "gic_cpu_write: Bad offset %x\n", (int)offset); 14280cf09852SPeter Maydell return MEMTX_OK; 1429e69954b9Spbrook } 1430e69954b9Spbrook gic_update(s); 1431a9d85353SPeter Maydell return MEMTX_OK; 1432e69954b9Spbrook } 1433e2c56465SPeter Maydell 1434e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for the current CPU */ 1435a9d85353SPeter Maydell static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data, 1436a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1437e2c56465SPeter Maydell { 1438fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1439a9d85353SPeter Maydell return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs); 1440e2c56465SPeter Maydell } 1441e2c56465SPeter Maydell 1442a9d85353SPeter Maydell static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr, 1443a9d85353SPeter Maydell uint64_t value, unsigned size, 1444a9d85353SPeter Maydell MemTxAttrs attrs) 1445e2c56465SPeter Maydell { 1446fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1447a9d85353SPeter Maydell return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs); 1448e2c56465SPeter Maydell } 1449e2c56465SPeter Maydell 1450e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for a specific CPU. 1451fae15286SPeter Maydell * These just decode the opaque pointer into GICState* + cpu id. 1452e2c56465SPeter Maydell */ 1453a9d85353SPeter Maydell static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data, 1454a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1455e2c56465SPeter Maydell { 1456fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1457fae15286SPeter Maydell GICState *s = *backref; 1458e2c56465SPeter Maydell int id = (backref - s->backref); 1459a9d85353SPeter Maydell return gic_cpu_read(s, id, addr, data, attrs); 1460e2c56465SPeter Maydell } 1461e2c56465SPeter Maydell 1462a9d85353SPeter Maydell static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr, 1463a9d85353SPeter Maydell uint64_t value, unsigned size, 1464a9d85353SPeter Maydell MemTxAttrs attrs) 1465e2c56465SPeter Maydell { 1466fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1467fae15286SPeter Maydell GICState *s = *backref; 1468e2c56465SPeter Maydell int id = (backref - s->backref); 1469a9d85353SPeter Maydell return gic_cpu_write(s, id, addr, value, attrs); 1470e2c56465SPeter Maydell } 1471e2c56465SPeter Maydell 14727926c210SPavel Fedin static const MemoryRegionOps gic_ops[2] = { 14737926c210SPavel Fedin { 14747926c210SPavel Fedin .read_with_attrs = gic_dist_read, 14757926c210SPavel Fedin .write_with_attrs = gic_dist_write, 14767926c210SPavel Fedin .endianness = DEVICE_NATIVE_ENDIAN, 14777926c210SPavel Fedin }, 14787926c210SPavel Fedin { 1479a9d85353SPeter Maydell .read_with_attrs = gic_thiscpu_read, 1480a9d85353SPeter Maydell .write_with_attrs = gic_thiscpu_write, 1481e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 14827926c210SPavel Fedin } 1483e2c56465SPeter Maydell }; 1484e2c56465SPeter Maydell 1485e2c56465SPeter Maydell static const MemoryRegionOps gic_cpu_ops = { 1486a9d85353SPeter Maydell .read_with_attrs = gic_do_cpu_read, 1487a9d85353SPeter Maydell .write_with_attrs = gic_do_cpu_write, 1488e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 1489e2c56465SPeter Maydell }; 1490e69954b9Spbrook 14917926c210SPavel Fedin /* This function is used by nvic model */ 14927b95a508SKONRAD Frederic void gic_init_irqs_and_distributor(GICState *s) 1493e69954b9Spbrook { 14947926c210SPavel Fedin gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); 14952b518c56SPeter Maydell } 14962b518c56SPeter Maydell 149753111180SPeter Maydell static void arm_gic_realize(DeviceState *dev, Error **errp) 14982b518c56SPeter Maydell { 149953111180SPeter Maydell /* Device instance realize function for the GIC sysbus device */ 15002b518c56SPeter Maydell int i; 150153111180SPeter Maydell GICState *s = ARM_GIC(dev); 150253111180SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 15031e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_GET_CLASS(s); 15040175ba10SMarkus Armbruster Error *local_err = NULL; 15051e8cae4dSPeter Maydell 15060175ba10SMarkus Armbruster agc->parent_realize(dev, &local_err); 15070175ba10SMarkus Armbruster if (local_err) { 15080175ba10SMarkus Armbruster error_propagate(errp, local_err); 150953111180SPeter Maydell return; 151053111180SPeter Maydell } 15111e8cae4dSPeter Maydell 15125d721b78SAlexander Graf if (kvm_enabled() && !kvm_arm_supports_user_irq()) { 15135d721b78SAlexander Graf error_setg(errp, "KVM with user space irqchip only works when the " 15145d721b78SAlexander Graf "host kernel supports KVM_CAP_ARM_USER_IRQ"); 15155d721b78SAlexander Graf return; 15165d721b78SAlexander Graf } 15175d721b78SAlexander Graf 15187926c210SPavel Fedin /* This creates distributor and main CPU interface (s->cpuiomem[0]) */ 15197926c210SPavel Fedin gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); 15202b518c56SPeter Maydell 15217926c210SPavel Fedin /* Extra core-specific regions for the CPU interfaces. This is 15227926c210SPavel Fedin * necessary for "franken-GIC" implementations, for example on 15237926c210SPavel Fedin * Exynos 4. 1524e2c56465SPeter Maydell * NB that the memory region size of 0x100 applies for the 11MPCore 1525e2c56465SPeter Maydell * and also cores following the GIC v1 spec (ie A9). 1526e2c56465SPeter Maydell * GIC v2 defines a larger memory region (0x1000) so this will need 1527e2c56465SPeter Maydell * to be extended when we implement A15. 1528e2c56465SPeter Maydell */ 1529b95690c9SWei Huang for (i = 0; i < s->num_cpu; i++) { 1530e2c56465SPeter Maydell s->backref[i] = s; 15311437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, 15321437c94bSPaolo Bonzini &s->backref[i], "gic_cpu", 0x100); 15337926c210SPavel Fedin sysbus_init_mmio(sbd, &s->cpuiomem[i+1]); 1534496dbcd1SPeter Maydell } 1535496dbcd1SPeter Maydell } 1536496dbcd1SPeter Maydell 1537496dbcd1SPeter Maydell static void arm_gic_class_init(ObjectClass *klass, void *data) 1538496dbcd1SPeter Maydell { 1539496dbcd1SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 15401e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_CLASS(klass); 154153111180SPeter Maydell 1542bf853881SPhilippe Mathieu-Daudé device_class_set_parent_realize(dc, arm_gic_realize, &agc->parent_realize); 1543496dbcd1SPeter Maydell } 1544496dbcd1SPeter Maydell 15458c43a6f0SAndreas Färber static const TypeInfo arm_gic_info = { 15461e8cae4dSPeter Maydell .name = TYPE_ARM_GIC, 15471e8cae4dSPeter Maydell .parent = TYPE_ARM_GIC_COMMON, 1548fae15286SPeter Maydell .instance_size = sizeof(GICState), 1549496dbcd1SPeter Maydell .class_init = arm_gic_class_init, 1550998a74bcSPeter Maydell .class_size = sizeof(ARMGICClass), 1551496dbcd1SPeter Maydell }; 1552496dbcd1SPeter Maydell 1553496dbcd1SPeter Maydell static void arm_gic_register_types(void) 1554496dbcd1SPeter Maydell { 1555496dbcd1SPeter Maydell type_register_static(&arm_gic_info); 1556496dbcd1SPeter Maydell } 1557496dbcd1SPeter Maydell 1558496dbcd1SPeter Maydell type_init(arm_gic_register_types) 1559