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 1508d999995SChristoffer Dall static void gic_set_irq_11mpcore(GICState *s, int irq, int level, 1518d999995SChristoffer Dall int cm, int target) 1528d999995SChristoffer Dall { 1538d999995SChristoffer Dall if (level) { 15467ce697aSLuc Michel GIC_DIST_SET_LEVEL(irq, cm); 15567ce697aSLuc Michel if (GIC_DIST_TEST_EDGE_TRIGGER(irq) || GIC_DIST_TEST_ENABLED(irq, cm)) { 1568d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 15767ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, target); 1588d999995SChristoffer Dall } 1598d999995SChristoffer Dall } else { 16067ce697aSLuc Michel GIC_DIST_CLEAR_LEVEL(irq, cm); 1618d999995SChristoffer Dall } 1628d999995SChristoffer Dall } 1638d999995SChristoffer Dall 1648d999995SChristoffer Dall static void gic_set_irq_generic(GICState *s, int irq, int level, 1658d999995SChristoffer Dall int cm, int target) 1668d999995SChristoffer Dall { 1678d999995SChristoffer Dall if (level) { 16867ce697aSLuc Michel GIC_DIST_SET_LEVEL(irq, cm); 1698d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 17067ce697aSLuc Michel if (GIC_DIST_TEST_EDGE_TRIGGER(irq)) { 17167ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, target); 1728d999995SChristoffer Dall } 1738d999995SChristoffer Dall } else { 17467ce697aSLuc Michel GIC_DIST_CLEAR_LEVEL(irq, cm); 1758d999995SChristoffer Dall } 1768d999995SChristoffer Dall } 1778d999995SChristoffer Dall 1789ee6e8bbSpbrook /* Process a change in an external IRQ input. */ 179e69954b9Spbrook static void gic_set_irq(void *opaque, int irq, int level) 180e69954b9Spbrook { 181544d1afaSPeter Maydell /* Meaning of the 'irq' parameter: 182544d1afaSPeter Maydell * [0..N-1] : external interrupts 183544d1afaSPeter Maydell * [N..N+31] : PPI (internal) interrupts for CPU 0 184544d1afaSPeter Maydell * [N+32..N+63] : PPI (internal interrupts for CPU 1 185544d1afaSPeter Maydell * ... 186544d1afaSPeter Maydell */ 187fae15286SPeter Maydell GICState *s = (GICState *)opaque; 188544d1afaSPeter Maydell int cm, target; 189544d1afaSPeter Maydell if (irq < (s->num_irq - GIC_INTERNAL)) { 190e69954b9Spbrook /* The first external input line is internal interrupt 32. */ 191544d1afaSPeter Maydell cm = ALL_CPU_MASK; 19269253800SRusty Russell irq += GIC_INTERNAL; 19367ce697aSLuc Michel target = GIC_DIST_TARGET(irq); 194544d1afaSPeter Maydell } else { 195544d1afaSPeter Maydell int cpu; 196544d1afaSPeter Maydell irq -= (s->num_irq - GIC_INTERNAL); 197544d1afaSPeter Maydell cpu = irq / GIC_INTERNAL; 198544d1afaSPeter Maydell irq %= GIC_INTERNAL; 199544d1afaSPeter Maydell cm = 1 << cpu; 200544d1afaSPeter Maydell target = cm; 201544d1afaSPeter Maydell } 202544d1afaSPeter Maydell 20340d22500SChristoffer Dall assert(irq >= GIC_NR_SGIS); 20440d22500SChristoffer Dall 20567ce697aSLuc Michel if (level == GIC_DIST_TEST_LEVEL(irq, cm)) { 206e69954b9Spbrook return; 207544d1afaSPeter Maydell } 208e69954b9Spbrook 2093bc4b52cSMarcin Krzeminski if (s->revision == REV_11MPCORE) { 2108d999995SChristoffer Dall gic_set_irq_11mpcore(s, irq, level, cm, target); 211e69954b9Spbrook } else { 2128d999995SChristoffer Dall gic_set_irq_generic(s, irq, level, cm, target); 213e69954b9Spbrook } 2142531088fSHollis Blanchard trace_gic_set_irq(irq, level, cm, target); 2158d999995SChristoffer Dall 216e69954b9Spbrook gic_update(s); 217e69954b9Spbrook } 218e69954b9Spbrook 2197c0fa108SFabian Aggeler static uint16_t gic_get_current_pending_irq(GICState *s, int cpu, 2207c0fa108SFabian Aggeler MemTxAttrs attrs) 2217c0fa108SFabian Aggeler { 2227c0fa108SFabian Aggeler uint16_t pending_irq = s->current_pending[cpu]; 2237c0fa108SFabian Aggeler 2247c0fa108SFabian Aggeler if (pending_irq < GIC_MAXIRQ && gic_has_groups(s)) { 22586b350f0SLuc Michel int group = gic_test_group(s, pending_irq, cpu); 22686b350f0SLuc Michel 2277c0fa108SFabian Aggeler /* On a GIC without the security extensions, reading this register 2287c0fa108SFabian Aggeler * behaves in the same way as a secure access to a GIC with them. 2297c0fa108SFabian Aggeler */ 2303dd0471bSLuc Michel bool secure = !gic_cpu_ns_access(s, cpu, attrs); 2317c0fa108SFabian Aggeler 2327c0fa108SFabian Aggeler if (group == 0 && !secure) { 2337c0fa108SFabian Aggeler /* Group0 interrupts hidden from Non-secure access */ 2347c0fa108SFabian Aggeler return 1023; 2357c0fa108SFabian Aggeler } 2367c0fa108SFabian Aggeler if (group == 1 && secure && !(s->cpu_ctlr[cpu] & GICC_CTLR_ACK_CTL)) { 2377c0fa108SFabian Aggeler /* Group1 interrupts only seen by Secure access if 2387c0fa108SFabian Aggeler * AckCtl bit set. 2397c0fa108SFabian Aggeler */ 2407c0fa108SFabian Aggeler return 1022; 2417c0fa108SFabian Aggeler } 2427c0fa108SFabian Aggeler } 2437c0fa108SFabian Aggeler return pending_irq; 2447c0fa108SFabian Aggeler } 2457c0fa108SFabian Aggeler 246df92cfa6SPeter Maydell static int gic_get_group_priority(GICState *s, int cpu, int irq) 247df92cfa6SPeter Maydell { 248df92cfa6SPeter Maydell /* Return the group priority of the specified interrupt 249df92cfa6SPeter Maydell * (which is the top bits of its priority, with the number 250df92cfa6SPeter Maydell * of bits masked determined by the applicable binary point register). 251df92cfa6SPeter Maydell */ 252df92cfa6SPeter Maydell int bpr; 253df92cfa6SPeter Maydell uint32_t mask; 254df92cfa6SPeter Maydell 255df92cfa6SPeter Maydell if (gic_has_groups(s) && 256df92cfa6SPeter Maydell !(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) && 25786b350f0SLuc Michel gic_test_group(s, irq, cpu)) { 258fc05a6f2SLuc MICHEL bpr = s->abpr[cpu] - 1; 259fc05a6f2SLuc MICHEL assert(bpr >= 0); 260df92cfa6SPeter Maydell } else { 261df92cfa6SPeter Maydell bpr = s->bpr[cpu]; 262df92cfa6SPeter Maydell } 263df92cfa6SPeter Maydell 264df92cfa6SPeter Maydell /* a BPR of 0 means the group priority bits are [7:1]; 265df92cfa6SPeter Maydell * a BPR of 1 means they are [7:2], and so on down to 266df92cfa6SPeter Maydell * a BPR of 7 meaning no group priority bits at all. 267df92cfa6SPeter Maydell */ 268df92cfa6SPeter Maydell mask = ~0U << ((bpr & 7) + 1); 269df92cfa6SPeter Maydell 27086b350f0SLuc Michel return gic_get_priority(s, irq, cpu) & mask; 271df92cfa6SPeter Maydell } 272df92cfa6SPeter Maydell 27372889c8aSPeter Maydell static void gic_activate_irq(GICState *s, int cpu, int irq) 274e69954b9Spbrook { 27572889c8aSPeter Maydell /* Set the appropriate Active Priority Register bit for this IRQ, 27672889c8aSPeter Maydell * and update the running priority. 27772889c8aSPeter Maydell */ 27872889c8aSPeter Maydell int prio = gic_get_group_priority(s, cpu, irq); 279a1d7b8d8SLuc Michel int min_bpr = gic_is_vcpu(cpu) ? GIC_VIRT_MIN_BPR : GIC_MIN_BPR; 280a1d7b8d8SLuc Michel int preemption_level = prio >> (min_bpr + 1); 28172889c8aSPeter Maydell int regno = preemption_level / 32; 28272889c8aSPeter Maydell int bitno = preemption_level % 32; 283a1d7b8d8SLuc Michel uint32_t *papr = NULL; 28472889c8aSPeter Maydell 285a1d7b8d8SLuc Michel if (gic_is_vcpu(cpu)) { 286a1d7b8d8SLuc Michel assert(regno == 0); 287a1d7b8d8SLuc Michel papr = &s->h_apr[gic_get_vcpu_real_id(cpu)]; 288a1d7b8d8SLuc Michel } else if (gic_has_groups(s) && gic_test_group(s, irq, cpu)) { 289a1d7b8d8SLuc Michel papr = &s->nsapr[regno][cpu]; 2909ee6e8bbSpbrook } else { 291a1d7b8d8SLuc Michel papr = &s->apr[regno][cpu]; 2929ee6e8bbSpbrook } 29372889c8aSPeter Maydell 294a1d7b8d8SLuc Michel *papr |= (1 << bitno); 295a1d7b8d8SLuc Michel 29672889c8aSPeter Maydell s->running_priority[cpu] = prio; 29786b350f0SLuc Michel gic_set_active(s, irq, cpu); 29872889c8aSPeter Maydell } 29972889c8aSPeter Maydell 30072889c8aSPeter Maydell static int gic_get_prio_from_apr_bits(GICState *s, int cpu) 30172889c8aSPeter Maydell { 30272889c8aSPeter Maydell /* Recalculate the current running priority for this CPU based 30372889c8aSPeter Maydell * on the set bits in the Active Priority Registers. 30472889c8aSPeter Maydell */ 30572889c8aSPeter Maydell int i; 306a1d7b8d8SLuc Michel 307a1d7b8d8SLuc Michel if (gic_is_vcpu(cpu)) { 308a1d7b8d8SLuc Michel uint32_t apr = s->h_apr[gic_get_vcpu_real_id(cpu)]; 309a1d7b8d8SLuc Michel if (apr) { 310a1d7b8d8SLuc Michel return ctz32(apr) << (GIC_VIRT_MIN_BPR + 1); 311a1d7b8d8SLuc Michel } else { 312a1d7b8d8SLuc Michel return 0x100; 313a1d7b8d8SLuc Michel } 314a1d7b8d8SLuc Michel } 315a1d7b8d8SLuc Michel 31672889c8aSPeter Maydell for (i = 0; i < GIC_NR_APRS; i++) { 31772889c8aSPeter Maydell uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu]; 31872889c8aSPeter Maydell if (!apr) { 31972889c8aSPeter Maydell continue; 32072889c8aSPeter Maydell } 32172889c8aSPeter Maydell return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1); 32272889c8aSPeter Maydell } 32372889c8aSPeter Maydell return 0x100; 32472889c8aSPeter Maydell } 32572889c8aSPeter Maydell 32672889c8aSPeter Maydell static void gic_drop_prio(GICState *s, int cpu, int group) 32772889c8aSPeter Maydell { 32872889c8aSPeter Maydell /* Drop the priority of the currently active interrupt in the 32972889c8aSPeter Maydell * specified group. 33072889c8aSPeter Maydell * 33172889c8aSPeter Maydell * Note that we can guarantee (because of the requirement to nest 33272889c8aSPeter Maydell * GICC_IAR reads [which activate an interrupt and raise priority] 33372889c8aSPeter Maydell * with GICC_EOIR writes [which drop the priority for the interrupt]) 33472889c8aSPeter Maydell * that the interrupt we're being called for is the highest priority 33572889c8aSPeter Maydell * active interrupt, meaning that it has the lowest set bit in the 33672889c8aSPeter Maydell * APR registers. 33772889c8aSPeter Maydell * 33872889c8aSPeter Maydell * If the guest does not honour the ordering constraints then the 33972889c8aSPeter Maydell * behaviour of the GIC is UNPREDICTABLE, which for us means that 34072889c8aSPeter Maydell * the values of the APR registers might become incorrect and the 34172889c8aSPeter Maydell * running priority will be wrong, so interrupts that should preempt 34272889c8aSPeter Maydell * might not do so, and interrupts that should not preempt might do so. 34372889c8aSPeter Maydell */ 344a1d7b8d8SLuc Michel if (gic_is_vcpu(cpu)) { 345a1d7b8d8SLuc Michel int rcpu = gic_get_vcpu_real_id(cpu); 346a1d7b8d8SLuc Michel 347a1d7b8d8SLuc Michel if (s->h_apr[rcpu]) { 348a1d7b8d8SLuc Michel /* Clear lowest set bit */ 349a1d7b8d8SLuc Michel s->h_apr[rcpu] &= s->h_apr[rcpu] - 1; 350a1d7b8d8SLuc Michel } 351a1d7b8d8SLuc Michel } else { 35272889c8aSPeter Maydell int i; 35372889c8aSPeter Maydell 35472889c8aSPeter Maydell for (i = 0; i < GIC_NR_APRS; i++) { 35572889c8aSPeter Maydell uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu]; 35672889c8aSPeter Maydell if (!*papr) { 35772889c8aSPeter Maydell continue; 35872889c8aSPeter Maydell } 35972889c8aSPeter Maydell /* Clear lowest set bit */ 36072889c8aSPeter Maydell *papr &= *papr - 1; 36172889c8aSPeter Maydell break; 36272889c8aSPeter Maydell } 363a1d7b8d8SLuc Michel } 36472889c8aSPeter Maydell 36572889c8aSPeter Maydell s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu); 366e69954b9Spbrook } 367e69954b9Spbrook 368439badd6SLuc Michel static inline uint32_t gic_clear_pending_sgi(GICState *s, int irq, int cpu) 369e69954b9Spbrook { 370439badd6SLuc Michel int src; 371439badd6SLuc Michel uint32_t ret; 372c5619bf9SFabian Aggeler 373439badd6SLuc Michel if (!gic_is_vcpu(cpu)) { 37440d22500SChristoffer Dall /* Lookup the source CPU for the SGI and clear this in the 37540d22500SChristoffer Dall * sgi_pending map. Return the src and clear the overall pending 37640d22500SChristoffer Dall * state on this CPU if the SGI is not pending from any CPUs. 37740d22500SChristoffer Dall */ 37840d22500SChristoffer Dall assert(s->sgi_pending[irq][cpu] != 0); 37940d22500SChristoffer Dall src = ctz32(s->sgi_pending[irq][cpu]); 38040d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~(1 << src); 38140d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 38286b350f0SLuc Michel gic_clear_pending(s, irq, cpu); 38340d22500SChristoffer Dall } 38440d22500SChristoffer Dall ret = irq | ((src & 0x7) << 10); 38540d22500SChristoffer Dall } else { 386439badd6SLuc Michel uint32_t *lr_entry = gic_get_lr_entry(s, irq, cpu); 387439badd6SLuc Michel src = GICH_LR_CPUID(*lr_entry); 388439badd6SLuc Michel 389439badd6SLuc Michel gic_clear_pending(s, irq, cpu); 390439badd6SLuc Michel ret = irq | (src << 10); 391439badd6SLuc Michel } 392439badd6SLuc Michel 393439badd6SLuc Michel return ret; 394439badd6SLuc Michel } 395439badd6SLuc Michel 396439badd6SLuc Michel uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) 397439badd6SLuc Michel { 398439badd6SLuc Michel int ret, irq; 399439badd6SLuc Michel 400439badd6SLuc Michel /* gic_get_current_pending_irq() will return 1022 or 1023 appropriately 401439badd6SLuc Michel * for the case where this GIC supports grouping and the pending interrupt 402439badd6SLuc Michel * is in the wrong group. 40340d22500SChristoffer Dall */ 404439badd6SLuc Michel irq = gic_get_current_pending_irq(s, cpu, attrs); 405439badd6SLuc Michel trace_gic_acknowledge_irq(gic_get_vcpu_real_id(cpu), irq); 406439badd6SLuc Michel 407439badd6SLuc Michel if (irq >= GIC_MAXIRQ) { 408439badd6SLuc Michel DPRINTF("ACK, no pending interrupt or it is hidden: %d\n", irq); 409439badd6SLuc Michel return irq; 410439badd6SLuc Michel } 411439badd6SLuc Michel 412439badd6SLuc Michel if (gic_get_priority(s, irq, cpu) >= s->running_priority[cpu]) { 413439badd6SLuc Michel DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq); 414439badd6SLuc Michel return 1023; 415439badd6SLuc Michel } 416439badd6SLuc Michel 417439badd6SLuc Michel gic_activate_irq(s, cpu, irq); 418439badd6SLuc Michel 419439badd6SLuc Michel if (s->revision == REV_11MPCORE) { 420439badd6SLuc Michel /* Clear pending flags for both level and edge triggered interrupts. 421439badd6SLuc Michel * Level triggered IRQs will be reasserted once they become inactive. 422439badd6SLuc Michel */ 423439badd6SLuc Michel gic_clear_pending(s, irq, cpu); 424439badd6SLuc Michel ret = irq; 425439badd6SLuc Michel } else { 426439badd6SLuc Michel if (irq < GIC_NR_SGIS) { 427439badd6SLuc Michel ret = gic_clear_pending_sgi(s, irq, cpu); 428439badd6SLuc Michel } else { 42986b350f0SLuc Michel gic_clear_pending(s, irq, cpu); 43040d22500SChristoffer Dall ret = irq; 43140d22500SChristoffer Dall } 43240d22500SChristoffer Dall } 43340d22500SChristoffer Dall 43472889c8aSPeter Maydell gic_update(s); 43540d22500SChristoffer Dall DPRINTF("ACK %d\n", irq); 43640d22500SChristoffer Dall return ret; 437e69954b9Spbrook } 438e69954b9Spbrook 43967ce697aSLuc Michel void gic_dist_set_priority(GICState *s, int cpu, int irq, uint8_t val, 44081508470SFabian Aggeler MemTxAttrs attrs) 4419df90ad0SChristoffer Dall { 44281508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 44367ce697aSLuc Michel if (!GIC_DIST_TEST_GROUP(irq, (1 << cpu))) { 44481508470SFabian Aggeler return; /* Ignore Non-secure access of Group0 IRQ */ 44581508470SFabian Aggeler } 44681508470SFabian Aggeler val = 0x80 | (val >> 1); /* Non-secure view */ 44781508470SFabian Aggeler } 44881508470SFabian Aggeler 4499df90ad0SChristoffer Dall if (irq < GIC_INTERNAL) { 4509df90ad0SChristoffer Dall s->priority1[irq][cpu] = val; 4519df90ad0SChristoffer Dall } else { 4529df90ad0SChristoffer Dall s->priority2[(irq) - GIC_INTERNAL] = val; 4539df90ad0SChristoffer Dall } 4549df90ad0SChristoffer Dall } 4559df90ad0SChristoffer Dall 45667ce697aSLuc Michel static uint32_t gic_dist_get_priority(GICState *s, int cpu, int irq, 45781508470SFabian Aggeler MemTxAttrs attrs) 45881508470SFabian Aggeler { 45967ce697aSLuc Michel uint32_t prio = GIC_DIST_GET_PRIORITY(irq, cpu); 46081508470SFabian Aggeler 46181508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 46267ce697aSLuc Michel if (!GIC_DIST_TEST_GROUP(irq, (1 << cpu))) { 46381508470SFabian Aggeler return 0; /* Non-secure access cannot read priority of Group0 IRQ */ 46481508470SFabian Aggeler } 46581508470SFabian Aggeler prio = (prio << 1) & 0xff; /* Non-secure view */ 46681508470SFabian Aggeler } 46781508470SFabian Aggeler return prio; 46881508470SFabian Aggeler } 46981508470SFabian Aggeler 47081508470SFabian Aggeler static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask, 47181508470SFabian Aggeler MemTxAttrs attrs) 47281508470SFabian Aggeler { 4733dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 47481508470SFabian Aggeler if (s->priority_mask[cpu] & 0x80) { 47581508470SFabian Aggeler /* Priority Mask in upper half */ 47681508470SFabian Aggeler pmask = 0x80 | (pmask >> 1); 47781508470SFabian Aggeler } else { 47881508470SFabian Aggeler /* Non-secure write ignored if priority mask is in lower half */ 47981508470SFabian Aggeler return; 48081508470SFabian Aggeler } 48181508470SFabian Aggeler } 48281508470SFabian Aggeler s->priority_mask[cpu] = pmask; 48381508470SFabian Aggeler } 48481508470SFabian Aggeler 48581508470SFabian Aggeler static uint32_t gic_get_priority_mask(GICState *s, int cpu, MemTxAttrs attrs) 48681508470SFabian Aggeler { 48781508470SFabian Aggeler uint32_t pmask = s->priority_mask[cpu]; 48881508470SFabian Aggeler 4893dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 49081508470SFabian Aggeler if (pmask & 0x80) { 49181508470SFabian Aggeler /* Priority Mask in upper half, return Non-secure view */ 49281508470SFabian Aggeler pmask = (pmask << 1) & 0xff; 49381508470SFabian Aggeler } else { 49481508470SFabian Aggeler /* Priority Mask in lower half, RAZ */ 49581508470SFabian Aggeler pmask = 0; 49681508470SFabian Aggeler } 49781508470SFabian Aggeler } 49881508470SFabian Aggeler return pmask; 49981508470SFabian Aggeler } 50081508470SFabian Aggeler 50132951860SFabian Aggeler static uint32_t gic_get_cpu_control(GICState *s, int cpu, MemTxAttrs attrs) 50232951860SFabian Aggeler { 50332951860SFabian Aggeler uint32_t ret = s->cpu_ctlr[cpu]; 50432951860SFabian Aggeler 5053dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 50632951860SFabian Aggeler /* Construct the NS banked view of GICC_CTLR from the correct 50732951860SFabian Aggeler * bits of the S banked view. We don't need to move the bypass 50832951860SFabian Aggeler * control bits because we don't implement that (IMPDEF) part 50932951860SFabian Aggeler * of the GIC architecture. 51032951860SFabian Aggeler */ 51132951860SFabian Aggeler ret = (ret & (GICC_CTLR_EN_GRP1 | GICC_CTLR_EOIMODE_NS)) >> 1; 51232951860SFabian Aggeler } 51332951860SFabian Aggeler return ret; 51432951860SFabian Aggeler } 51532951860SFabian Aggeler 51632951860SFabian Aggeler static void gic_set_cpu_control(GICState *s, int cpu, uint32_t value, 51732951860SFabian Aggeler MemTxAttrs attrs) 51832951860SFabian Aggeler { 51932951860SFabian Aggeler uint32_t mask; 52032951860SFabian Aggeler 5213dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 52232951860SFabian Aggeler /* The NS view can only write certain bits in the register; 52332951860SFabian Aggeler * the rest are unchanged 52432951860SFabian Aggeler */ 52532951860SFabian Aggeler mask = GICC_CTLR_EN_GRP1; 52632951860SFabian Aggeler if (s->revision == 2) { 52732951860SFabian Aggeler mask |= GICC_CTLR_EOIMODE_NS; 52832951860SFabian Aggeler } 52932951860SFabian Aggeler s->cpu_ctlr[cpu] &= ~mask; 53032951860SFabian Aggeler s->cpu_ctlr[cpu] |= (value << 1) & mask; 53132951860SFabian Aggeler } else { 53232951860SFabian Aggeler if (s->revision == 2) { 53332951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V2_S_MASK : GICC_CTLR_V2_MASK; 53432951860SFabian Aggeler } else { 53532951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V1_S_MASK : GICC_CTLR_V1_MASK; 53632951860SFabian Aggeler } 53732951860SFabian Aggeler s->cpu_ctlr[cpu] = value & mask; 53832951860SFabian Aggeler } 53932951860SFabian Aggeler DPRINTF("CPU Interface %d: Group0 Interrupts %sabled, " 54032951860SFabian Aggeler "Group1 Interrupts %sabled\n", cpu, 54132951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP0) ? "En" : "Dis", 54232951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP1) ? "En" : "Dis"); 54332951860SFabian Aggeler } 54432951860SFabian Aggeler 54508efa9f2SFabian Aggeler static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs) 54608efa9f2SFabian Aggeler { 54771aa735bSLuc MICHEL if ((s->revision != REV_11MPCORE) && (s->running_priority[cpu] > 0xff)) { 54871aa735bSLuc MICHEL /* Idle priority */ 54971aa735bSLuc MICHEL return 0xff; 55071aa735bSLuc MICHEL } 55171aa735bSLuc MICHEL 5523dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 55308efa9f2SFabian Aggeler if (s->running_priority[cpu] & 0x80) { 55408efa9f2SFabian Aggeler /* Running priority in upper half of range: return the Non-secure 55508efa9f2SFabian Aggeler * view of the priority. 55608efa9f2SFabian Aggeler */ 55708efa9f2SFabian Aggeler return s->running_priority[cpu] << 1; 55808efa9f2SFabian Aggeler } else { 55908efa9f2SFabian Aggeler /* Running priority in lower half of range: RAZ */ 56008efa9f2SFabian Aggeler return 0; 56108efa9f2SFabian Aggeler } 56208efa9f2SFabian Aggeler } else { 56308efa9f2SFabian Aggeler return s->running_priority[cpu]; 56408efa9f2SFabian Aggeler } 56508efa9f2SFabian Aggeler } 56608efa9f2SFabian Aggeler 567a55c910eSPeter Maydell /* Return true if we should split priority drop and interrupt deactivation, 568a55c910eSPeter Maydell * ie whether the relevant EOIMode bit is set. 569a55c910eSPeter Maydell */ 570a55c910eSPeter Maydell static bool gic_eoi_split(GICState *s, int cpu, MemTxAttrs attrs) 571a55c910eSPeter Maydell { 572a55c910eSPeter Maydell if (s->revision != 2) { 573a55c910eSPeter Maydell /* Before GICv2 prio-drop and deactivate are not separable */ 574a55c910eSPeter Maydell return false; 575a55c910eSPeter Maydell } 5763dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 577a55c910eSPeter Maydell return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE_NS; 578a55c910eSPeter Maydell } 579a55c910eSPeter Maydell return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE; 580a55c910eSPeter Maydell } 581a55c910eSPeter Maydell 582a55c910eSPeter Maydell static void gic_deactivate_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) 583a55c910eSPeter Maydell { 584ee03cca8SPeter Maydell int group; 585ee03cca8SPeter Maydell 586*02f2e22dSLuc Michel if (irq >= GIC_MAXIRQ || (!gic_is_vcpu(cpu) && irq >= s->num_irq)) { 587ee03cca8SPeter Maydell /* 588ee03cca8SPeter Maydell * This handles two cases: 589ee03cca8SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 590ee03cca8SPeter Maydell * to the GICC_DIR, the GIC ignores that write. 591ee03cca8SPeter Maydell * 2. If software writes the number of a non-existent interrupt 592ee03cca8SPeter Maydell * this must be a subcase of "value written is not an active interrupt" 593*02f2e22dSLuc Michel * and so this is UNPREDICTABLE. We choose to ignore it. For vCPUs, 594*02f2e22dSLuc Michel * all IRQs potentially exist, so this limit does not apply. 595ee03cca8SPeter Maydell */ 596ee03cca8SPeter Maydell return; 597ee03cca8SPeter Maydell } 598ee03cca8SPeter Maydell 599a55c910eSPeter Maydell if (!gic_eoi_split(s, cpu, attrs)) { 600a55c910eSPeter Maydell /* This is UNPREDICTABLE; we choose to ignore it */ 601a55c910eSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 602a55c910eSPeter Maydell "gic_deactivate_irq: GICC_DIR write when EOIMode clear"); 603a55c910eSPeter Maydell return; 604a55c910eSPeter Maydell } 605a55c910eSPeter Maydell 606*02f2e22dSLuc Michel if (gic_is_vcpu(cpu) && !gic_virq_is_valid(s, irq, cpu)) { 607*02f2e22dSLuc Michel /* This vIRQ does not have an LR entry which is either active or 608*02f2e22dSLuc Michel * pending and active. Increment EOICount and ignore the write. 609*02f2e22dSLuc Michel */ 610*02f2e22dSLuc Michel int rcpu = gic_get_vcpu_real_id(cpu); 611*02f2e22dSLuc Michel s->h_hcr[rcpu] += 1 << R_GICH_HCR_EOICount_SHIFT; 612*02f2e22dSLuc Michel return; 613*02f2e22dSLuc Michel } 614*02f2e22dSLuc Michel 615*02f2e22dSLuc Michel group = gic_has_groups(s) && gic_test_group(s, irq, cpu); 616*02f2e22dSLuc Michel 6173dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs) && !group) { 618a55c910eSPeter Maydell DPRINTF("Non-secure DI for Group0 interrupt %d ignored\n", irq); 619a55c910eSPeter Maydell return; 620a55c910eSPeter Maydell } 621a55c910eSPeter Maydell 62286b350f0SLuc Michel gic_clear_active(s, irq, cpu); 623a55c910eSPeter Maydell } 624a55c910eSPeter Maydell 62550491c56SLuc Michel static void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) 626e69954b9Spbrook { 6279ee6e8bbSpbrook int cm = 1 << cpu; 62872889c8aSPeter Maydell int group; 62972889c8aSPeter Maydell 630df628ff1Spbrook DPRINTF("EOI %d\n", irq); 631*02f2e22dSLuc Michel if (gic_is_vcpu(cpu)) { 632*02f2e22dSLuc Michel /* The call to gic_prio_drop() will clear a bit in GICH_APR iff the 633*02f2e22dSLuc Michel * running prio is < 0x100. 634*02f2e22dSLuc Michel */ 635*02f2e22dSLuc Michel bool prio_drop = s->running_priority[cpu] < 0x100; 636*02f2e22dSLuc Michel 637*02f2e22dSLuc Michel if (irq >= GIC_MAXIRQ) { 638*02f2e22dSLuc Michel /* Ignore spurious interrupt */ 639*02f2e22dSLuc Michel return; 640*02f2e22dSLuc Michel } 641*02f2e22dSLuc Michel 642*02f2e22dSLuc Michel gic_drop_prio(s, cpu, 0); 643*02f2e22dSLuc Michel 644*02f2e22dSLuc Michel if (!gic_eoi_split(s, cpu, attrs)) { 645*02f2e22dSLuc Michel bool valid = gic_virq_is_valid(s, irq, cpu); 646*02f2e22dSLuc Michel if (prio_drop && !valid) { 647*02f2e22dSLuc Michel /* We are in a situation where: 648*02f2e22dSLuc Michel * - V_CTRL.EOIMode is false (no EOI split), 649*02f2e22dSLuc Michel * - The call to gic_drop_prio() cleared a bit in GICH_APR, 650*02f2e22dSLuc Michel * - This vIRQ does not have an LR entry which is either 651*02f2e22dSLuc Michel * active or pending and active. 652*02f2e22dSLuc Michel * In that case, we must increment EOICount. 653*02f2e22dSLuc Michel */ 654*02f2e22dSLuc Michel int rcpu = gic_get_vcpu_real_id(cpu); 655*02f2e22dSLuc Michel s->h_hcr[rcpu] += 1 << R_GICH_HCR_EOICount_SHIFT; 656*02f2e22dSLuc Michel } else if (valid) { 657*02f2e22dSLuc Michel gic_clear_active(s, irq, cpu); 658*02f2e22dSLuc Michel } 659*02f2e22dSLuc Michel } 660*02f2e22dSLuc Michel 661*02f2e22dSLuc Michel return; 662*02f2e22dSLuc Michel } 663*02f2e22dSLuc Michel 664a32134aaSMark Langsdorf if (irq >= s->num_irq) { 665217bfb44SPeter Maydell /* This handles two cases: 666217bfb44SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 667217bfb44SPeter Maydell * to the GICC_EOIR, the GIC ignores that write. 668217bfb44SPeter Maydell * 2. If software writes the number of a non-existent interrupt 669217bfb44SPeter Maydell * this must be a subcase of "value written does not match the last 670217bfb44SPeter Maydell * valid interrupt value read from the Interrupt Acknowledge 671217bfb44SPeter Maydell * register" and so this is UNPREDICTABLE. We choose to ignore it. 672217bfb44SPeter Maydell */ 673217bfb44SPeter Maydell return; 674217bfb44SPeter Maydell } 67572889c8aSPeter Maydell if (s->running_priority[cpu] == 0x100) { 676e69954b9Spbrook return; /* No active IRQ. */ 67772889c8aSPeter Maydell } 6788d999995SChristoffer Dall 6793bc4b52cSMarcin Krzeminski if (s->revision == REV_11MPCORE) { 680e69954b9Spbrook /* Mark level triggered interrupts as pending if they are still 681e69954b9Spbrook raised. */ 68267ce697aSLuc Michel if (!GIC_DIST_TEST_EDGE_TRIGGER(irq) && GIC_DIST_TEST_ENABLED(irq, cm) 68367ce697aSLuc Michel && GIC_DIST_TEST_LEVEL(irq, cm) 68467ce697aSLuc Michel && (GIC_DIST_TARGET(irq) & cm) != 0) { 6859ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq, cm); 68667ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, cm); 687e69954b9Spbrook } 6888d999995SChristoffer Dall } 6898d999995SChristoffer Dall 69086b350f0SLuc Michel group = gic_has_groups(s) && gic_test_group(s, irq, cpu); 69172889c8aSPeter Maydell 6923dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs) && !group) { 693f9c6a7f1SFabian Aggeler DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq); 694f9c6a7f1SFabian Aggeler return; 695f9c6a7f1SFabian Aggeler } 696f9c6a7f1SFabian Aggeler 697f9c6a7f1SFabian Aggeler /* Secure EOI with GICC_CTLR.AckCtl == 0 when the IRQ is a Group 1 698f9c6a7f1SFabian Aggeler * interrupt is UNPREDICTABLE. We choose to handle it as if AckCtl == 1, 699f9c6a7f1SFabian Aggeler * i.e. go ahead and complete the irq anyway. 700f9c6a7f1SFabian Aggeler */ 701f9c6a7f1SFabian Aggeler 70272889c8aSPeter Maydell gic_drop_prio(s, cpu, group); 703a55c910eSPeter Maydell 704a55c910eSPeter Maydell /* In GICv2 the guest can choose to split priority-drop and deactivate */ 705a55c910eSPeter Maydell if (!gic_eoi_split(s, cpu, attrs)) { 70686b350f0SLuc Michel gic_clear_active(s, irq, cpu); 707a55c910eSPeter Maydell } 708e69954b9Spbrook gic_update(s); 709e69954b9Spbrook } 710e69954b9Spbrook 711a9d85353SPeter Maydell static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) 712e69954b9Spbrook { 713fae15286SPeter Maydell GICState *s = (GICState *)opaque; 714e69954b9Spbrook uint32_t res; 715e69954b9Spbrook int irq; 716e69954b9Spbrook int i; 7179ee6e8bbSpbrook int cpu; 7189ee6e8bbSpbrook int cm; 7199ee6e8bbSpbrook int mask; 720e69954b9Spbrook 721926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 7229ee6e8bbSpbrook cm = 1 << cpu; 723e69954b9Spbrook if (offset < 0x100) { 724679aa175SFabian Aggeler if (offset == 0) { /* GICD_CTLR */ 725679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 726679aa175SFabian Aggeler /* The NS bank of this register is just an alias of the 727679aa175SFabian Aggeler * EnableGrp1 bit in the S bank version. 728679aa175SFabian Aggeler */ 729679aa175SFabian Aggeler return extract32(s->ctlr, 1, 1); 730679aa175SFabian Aggeler } else { 731679aa175SFabian Aggeler return s->ctlr; 732679aa175SFabian Aggeler } 733679aa175SFabian Aggeler } 734e69954b9Spbrook if (offset == 4) 7355543d1abSFabian Aggeler /* Interrupt Controller Type Register */ 7365543d1abSFabian Aggeler return ((s->num_irq / 32) - 1) 737b95690c9SWei Huang | ((s->num_cpu - 1) << 5) 7385543d1abSFabian Aggeler | (s->security_extn << 10); 739e69954b9Spbrook if (offset < 0x08) 740e69954b9Spbrook return 0; 741b79f2265SRob Herring if (offset >= 0x80) { 742c27a5ba9SFabian Aggeler /* Interrupt Group Registers: these RAZ/WI if this is an NS 743c27a5ba9SFabian Aggeler * access to a GIC with the security extensions, or if the GIC 744c27a5ba9SFabian Aggeler * doesn't have groups at all. 745c27a5ba9SFabian Aggeler */ 746c27a5ba9SFabian Aggeler res = 0; 747c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 748c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 749c27a5ba9SFabian Aggeler irq = (offset - 0x080) * 8 + GIC_BASE_IRQ; 750c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 751c27a5ba9SFabian Aggeler goto bad_reg; 752c27a5ba9SFabian Aggeler } 753c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 75467ce697aSLuc Michel if (GIC_DIST_TEST_GROUP(irq + i, cm)) { 755c27a5ba9SFabian Aggeler res |= (1 << i); 756c27a5ba9SFabian Aggeler } 757c27a5ba9SFabian Aggeler } 758c27a5ba9SFabian Aggeler } 759c27a5ba9SFabian Aggeler return res; 760b79f2265SRob Herring } 761e69954b9Spbrook goto bad_reg; 762e69954b9Spbrook } else if (offset < 0x200) { 763e69954b9Spbrook /* Interrupt Set/Clear Enable. */ 764e69954b9Spbrook if (offset < 0x180) 765e69954b9Spbrook irq = (offset - 0x100) * 8; 766e69954b9Spbrook else 767e69954b9Spbrook irq = (offset - 0x180) * 8; 7689ee6e8bbSpbrook irq += GIC_BASE_IRQ; 769a32134aaSMark Langsdorf if (irq >= s->num_irq) 770e69954b9Spbrook goto bad_reg; 771e69954b9Spbrook res = 0; 772e69954b9Spbrook for (i = 0; i < 8; i++) { 773fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 77467ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 775fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 776fea8a08eSJens Wiklander } 777fea8a08eSJens Wiklander 77867ce697aSLuc Michel if (GIC_DIST_TEST_ENABLED(irq + i, cm)) { 779e69954b9Spbrook res |= (1 << i); 780e69954b9Spbrook } 781e69954b9Spbrook } 782e69954b9Spbrook } else if (offset < 0x300) { 783e69954b9Spbrook /* Interrupt Set/Clear Pending. */ 784e69954b9Spbrook if (offset < 0x280) 785e69954b9Spbrook irq = (offset - 0x200) * 8; 786e69954b9Spbrook else 787e69954b9Spbrook irq = (offset - 0x280) * 8; 7889ee6e8bbSpbrook irq += GIC_BASE_IRQ; 789a32134aaSMark Langsdorf if (irq >= s->num_irq) 790e69954b9Spbrook goto bad_reg; 791e69954b9Spbrook res = 0; 79269253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 793e69954b9Spbrook for (i = 0; i < 8; i++) { 794fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 79567ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 796fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 797fea8a08eSJens Wiklander } 798fea8a08eSJens Wiklander 7998d999995SChristoffer Dall if (gic_test_pending(s, irq + i, mask)) { 800e69954b9Spbrook res |= (1 << i); 801e69954b9Spbrook } 802e69954b9Spbrook } 803e69954b9Spbrook } else if (offset < 0x400) { 8043bb0b038SLuc Michel /* Interrupt Set/Clear Active. */ 8053bb0b038SLuc Michel if (offset < 0x380) { 8063bb0b038SLuc Michel irq = (offset - 0x300) * 8; 8073bb0b038SLuc Michel } else if (s->revision == 2) { 8083bb0b038SLuc Michel irq = (offset - 0x380) * 8; 8093bb0b038SLuc Michel } else { 8103bb0b038SLuc Michel goto bad_reg; 8113bb0b038SLuc Michel } 8123bb0b038SLuc Michel 8133bb0b038SLuc Michel irq += GIC_BASE_IRQ; 814a32134aaSMark Langsdorf if (irq >= s->num_irq) 815e69954b9Spbrook goto bad_reg; 816e69954b9Spbrook res = 0; 81769253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 818e69954b9Spbrook for (i = 0; i < 8; i++) { 819fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 82067ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 821fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 822fea8a08eSJens Wiklander } 823fea8a08eSJens Wiklander 82467ce697aSLuc Michel if (GIC_DIST_TEST_ACTIVE(irq + i, mask)) { 825e69954b9Spbrook res |= (1 << i); 826e69954b9Spbrook } 827e69954b9Spbrook } 828e69954b9Spbrook } else if (offset < 0x800) { 829e69954b9Spbrook /* Interrupt Priority. */ 8309ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 831a32134aaSMark Langsdorf if (irq >= s->num_irq) 832e69954b9Spbrook goto bad_reg; 83367ce697aSLuc Michel res = gic_dist_get_priority(s, cpu, irq, attrs); 834e69954b9Spbrook } else if (offset < 0xc00) { 835e69954b9Spbrook /* Interrupt CPU Target. */ 8366b9680bbSPeter Maydell if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { 8376b9680bbSPeter Maydell /* For uniprocessor GICs these RAZ/WI */ 8386b9680bbSPeter Maydell res = 0; 8396b9680bbSPeter Maydell } else { 8409ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 8416b9680bbSPeter Maydell if (irq >= s->num_irq) { 842e69954b9Spbrook goto bad_reg; 8436b9680bbSPeter Maydell } 8447995206dSPeter Maydell if (irq < 29 && s->revision == REV_11MPCORE) { 8457995206dSPeter Maydell res = 0; 8467995206dSPeter Maydell } else if (irq < GIC_INTERNAL) { 8479ee6e8bbSpbrook res = cm; 8489ee6e8bbSpbrook } else { 84967ce697aSLuc Michel res = GIC_DIST_TARGET(irq); 8509ee6e8bbSpbrook } 8516b9680bbSPeter Maydell } 852e69954b9Spbrook } else if (offset < 0xf00) { 853e69954b9Spbrook /* Interrupt Configuration. */ 85471a62046SAdam Lackorzynski irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 855a32134aaSMark Langsdorf if (irq >= s->num_irq) 856e69954b9Spbrook goto bad_reg; 857e69954b9Spbrook res = 0; 858e69954b9Spbrook for (i = 0; i < 4; i++) { 859fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 86067ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 861fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 862fea8a08eSJens Wiklander } 863fea8a08eSJens Wiklander 86467ce697aSLuc Michel if (GIC_DIST_TEST_MODEL(irq + i)) { 865e69954b9Spbrook res |= (1 << (i * 2)); 86667ce697aSLuc Michel } 86767ce697aSLuc Michel if (GIC_DIST_TEST_EDGE_TRIGGER(irq + i)) { 868e69954b9Spbrook res |= (2 << (i * 2)); 869e69954b9Spbrook } 87067ce697aSLuc Michel } 87140d22500SChristoffer Dall } else if (offset < 0xf10) { 87240d22500SChristoffer Dall goto bad_reg; 87340d22500SChristoffer Dall } else if (offset < 0xf30) { 8747c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 87540d22500SChristoffer Dall goto bad_reg; 87640d22500SChristoffer Dall } 87740d22500SChristoffer Dall 87840d22500SChristoffer Dall if (offset < 0xf20) { 87940d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 88040d22500SChristoffer Dall irq = (offset - 0xf10); 88140d22500SChristoffer Dall } else { 88240d22500SChristoffer Dall irq = (offset - 0xf20); 88340d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 88440d22500SChristoffer Dall } 88540d22500SChristoffer Dall 886fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 88767ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq, 1 << cpu)) { 888fea8a08eSJens Wiklander res = 0; /* Ignore Non-secure access of Group0 IRQ */ 889fea8a08eSJens Wiklander } else { 89040d22500SChristoffer Dall res = s->sgi_pending[irq][cpu]; 891fea8a08eSJens Wiklander } 8923355c360SAlistair Francis } else if (offset < 0xfd0) { 893e69954b9Spbrook goto bad_reg; 8943355c360SAlistair Francis } else if (offset < 0x1000) { 895e69954b9Spbrook if (offset & 3) { 896e69954b9Spbrook res = 0; 897e69954b9Spbrook } else { 8983355c360SAlistair Francis switch (s->revision) { 8993355c360SAlistair Francis case REV_11MPCORE: 9003355c360SAlistair Francis res = gic_id_11mpcore[(offset - 0xfd0) >> 2]; 9013355c360SAlistair Francis break; 9023355c360SAlistair Francis case 1: 9033355c360SAlistair Francis res = gic_id_gicv1[(offset - 0xfd0) >> 2]; 9043355c360SAlistair Francis break; 9053355c360SAlistair Francis case 2: 9063355c360SAlistair Francis res = gic_id_gicv2[(offset - 0xfd0) >> 2]; 9073355c360SAlistair Francis break; 9083355c360SAlistair Francis default: 9093355c360SAlistair Francis res = 0; 910e69954b9Spbrook } 911e69954b9Spbrook } 9123355c360SAlistair Francis } else { 9133355c360SAlistair Francis g_assert_not_reached(); 9143355c360SAlistair Francis } 915e69954b9Spbrook return res; 916e69954b9Spbrook bad_reg: 9178c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 9188c8dc39fSPeter Maydell "gic_dist_readb: Bad offset %x\n", (int)offset); 919e69954b9Spbrook return 0; 920e69954b9Spbrook } 921e69954b9Spbrook 922a9d85353SPeter Maydell static MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data, 923a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 924e69954b9Spbrook { 925a9d85353SPeter Maydell switch (size) { 926a9d85353SPeter Maydell case 1: 927a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 928a9d85353SPeter Maydell return MEMTX_OK; 929a9d85353SPeter Maydell case 2: 930a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 931a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 932a9d85353SPeter Maydell return MEMTX_OK; 933a9d85353SPeter Maydell case 4: 934a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 935a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 936a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 2, attrs) << 16; 937a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 3, attrs) << 24; 938a9d85353SPeter Maydell return MEMTX_OK; 939a9d85353SPeter Maydell default: 940a9d85353SPeter Maydell return MEMTX_ERROR; 941e69954b9Spbrook } 942e69954b9Spbrook } 943e69954b9Spbrook 944a8170e5eSAvi Kivity static void gic_dist_writeb(void *opaque, hwaddr offset, 945a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 946e69954b9Spbrook { 947fae15286SPeter Maydell GICState *s = (GICState *)opaque; 948e69954b9Spbrook int irq; 949e69954b9Spbrook int i; 9509ee6e8bbSpbrook int cpu; 951e69954b9Spbrook 952926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 953e69954b9Spbrook if (offset < 0x100) { 954e69954b9Spbrook if (offset == 0) { 955679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 956679aa175SFabian Aggeler /* NS version is just an alias of the S version's bit 1 */ 957679aa175SFabian Aggeler s->ctlr = deposit32(s->ctlr, 1, 1, value); 958679aa175SFabian Aggeler } else if (gic_has_groups(s)) { 959679aa175SFabian Aggeler s->ctlr = value & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1); 960679aa175SFabian Aggeler } else { 961679aa175SFabian Aggeler s->ctlr = value & GICD_CTLR_EN_GRP0; 962679aa175SFabian Aggeler } 963679aa175SFabian Aggeler DPRINTF("Distributor: Group0 %sabled; Group 1 %sabled\n", 964679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP0 ? "En" : "Dis", 965679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP1 ? "En" : "Dis"); 966e69954b9Spbrook } else if (offset < 4) { 967e69954b9Spbrook /* ignored. */ 968b79f2265SRob Herring } else if (offset >= 0x80) { 969c27a5ba9SFabian Aggeler /* Interrupt Group Registers: RAZ/WI for NS access to secure 970c27a5ba9SFabian Aggeler * GIC, or for GICs without groups. 971c27a5ba9SFabian Aggeler */ 972c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 973c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 974c27a5ba9SFabian Aggeler irq = (offset - 0x80) * 8 + GIC_BASE_IRQ; 975c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 976c27a5ba9SFabian Aggeler goto bad_reg; 977c27a5ba9SFabian Aggeler } 978c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 979c27a5ba9SFabian Aggeler /* Group bits are banked for private interrupts */ 980c27a5ba9SFabian Aggeler int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 981c27a5ba9SFabian Aggeler if (value & (1 << i)) { 982c27a5ba9SFabian Aggeler /* Group1 (Non-secure) */ 98367ce697aSLuc Michel GIC_DIST_SET_GROUP(irq + i, cm); 984c27a5ba9SFabian Aggeler } else { 985c27a5ba9SFabian Aggeler /* Group0 (Secure) */ 98667ce697aSLuc Michel GIC_DIST_CLEAR_GROUP(irq + i, cm); 987c27a5ba9SFabian Aggeler } 988c27a5ba9SFabian Aggeler } 989c27a5ba9SFabian Aggeler } 990e69954b9Spbrook } else { 991e69954b9Spbrook goto bad_reg; 992e69954b9Spbrook } 993e69954b9Spbrook } else if (offset < 0x180) { 994e69954b9Spbrook /* Interrupt Set Enable. */ 9959ee6e8bbSpbrook irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 996a32134aaSMark Langsdorf if (irq >= s->num_irq) 997e69954b9Spbrook goto bad_reg; 99841ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 9999ee6e8bbSpbrook value = 0xff; 100041ab7b55SChristoffer Dall } 100141ab7b55SChristoffer Dall 1002e69954b9Spbrook for (i = 0; i < 8; i++) { 1003e69954b9Spbrook if (value & (1 << i)) { 1004f47b48fbSDaniel Sangorrin int mask = 100567ce697aSLuc Michel (irq < GIC_INTERNAL) ? (1 << cpu) 100667ce697aSLuc Michel : GIC_DIST_TARGET(irq + i); 100769253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 100841bf234dSRabin Vincent 1009fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 101067ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1011fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 1012fea8a08eSJens Wiklander } 1013fea8a08eSJens Wiklander 101467ce697aSLuc Michel if (!GIC_DIST_TEST_ENABLED(irq + i, cm)) { 1015e69954b9Spbrook DPRINTF("Enabled IRQ %d\n", irq + i); 10162531088fSHollis Blanchard trace_gic_enable_irq(irq + i); 101741bf234dSRabin Vincent } 101867ce697aSLuc Michel GIC_DIST_SET_ENABLED(irq + i, cm); 1019e69954b9Spbrook /* If a raised level triggered IRQ enabled then mark 1020e69954b9Spbrook is as pending. */ 102167ce697aSLuc Michel if (GIC_DIST_TEST_LEVEL(irq + i, mask) 102267ce697aSLuc Michel && !GIC_DIST_TEST_EDGE_TRIGGER(irq + i)) { 10239ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq + i, mask); 102467ce697aSLuc Michel GIC_DIST_SET_PENDING(irq + i, mask); 10259ee6e8bbSpbrook } 1026e69954b9Spbrook } 1027e69954b9Spbrook } 1028e69954b9Spbrook } else if (offset < 0x200) { 1029e69954b9Spbrook /* Interrupt Clear Enable. */ 10309ee6e8bbSpbrook irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 1031a32134aaSMark Langsdorf if (irq >= s->num_irq) 1032e69954b9Spbrook goto bad_reg; 103341ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 10349ee6e8bbSpbrook value = 0; 103541ab7b55SChristoffer Dall } 103641ab7b55SChristoffer Dall 1037e69954b9Spbrook for (i = 0; i < 8; i++) { 1038e69954b9Spbrook if (value & (1 << i)) { 103969253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 104041bf234dSRabin Vincent 1041fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 104267ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1043fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 1044fea8a08eSJens Wiklander } 1045fea8a08eSJens Wiklander 104667ce697aSLuc Michel if (GIC_DIST_TEST_ENABLED(irq + i, cm)) { 1047e69954b9Spbrook DPRINTF("Disabled IRQ %d\n", irq + i); 10482531088fSHollis Blanchard trace_gic_disable_irq(irq + i); 104941bf234dSRabin Vincent } 105067ce697aSLuc Michel GIC_DIST_CLEAR_ENABLED(irq + i, cm); 1051e69954b9Spbrook } 1052e69954b9Spbrook } 1053e69954b9Spbrook } else if (offset < 0x280) { 1054e69954b9Spbrook /* Interrupt Set Pending. */ 10559ee6e8bbSpbrook irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 1056a32134aaSMark Langsdorf if (irq >= s->num_irq) 1057e69954b9Spbrook goto bad_reg; 105841ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 10595b0adce1SChristoffer Dall value = 0; 106041ab7b55SChristoffer Dall } 10619ee6e8bbSpbrook 1062e69954b9Spbrook for (i = 0; i < 8; i++) { 1063e69954b9Spbrook if (value & (1 << i)) { 1064fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 106567ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1066fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 1067fea8a08eSJens Wiklander } 1068fea8a08eSJens Wiklander 106967ce697aSLuc Michel GIC_DIST_SET_PENDING(irq + i, GIC_DIST_TARGET(irq + i)); 1070e69954b9Spbrook } 1071e69954b9Spbrook } 1072e69954b9Spbrook } else if (offset < 0x300) { 1073e69954b9Spbrook /* Interrupt Clear Pending. */ 10749ee6e8bbSpbrook irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 1075a32134aaSMark Langsdorf if (irq >= s->num_irq) 1076e69954b9Spbrook goto bad_reg; 10775b0adce1SChristoffer Dall if (irq < GIC_NR_SGIS) { 10785b0adce1SChristoffer Dall value = 0; 10795b0adce1SChristoffer Dall } 10805b0adce1SChristoffer Dall 1081e69954b9Spbrook for (i = 0; i < 8; 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 10879ee6e8bbSpbrook /* ??? This currently clears the pending bit for all CPUs, even 10889ee6e8bbSpbrook for per-CPU interrupts. It's unclear whether this is the 10899ee6e8bbSpbrook corect behavior. */ 1090e69954b9Spbrook if (value & (1 << i)) { 109167ce697aSLuc Michel GIC_DIST_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 1092e69954b9Spbrook } 1093e69954b9Spbrook } 10943bb0b038SLuc Michel } else if (offset < 0x380) { 10953bb0b038SLuc Michel /* Interrupt Set Active. */ 10963bb0b038SLuc Michel if (s->revision != 2) { 1097e69954b9Spbrook goto bad_reg; 10983bb0b038SLuc Michel } 10993bb0b038SLuc Michel 11003bb0b038SLuc Michel irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 11013bb0b038SLuc Michel if (irq >= s->num_irq) { 11023bb0b038SLuc Michel goto bad_reg; 11033bb0b038SLuc Michel } 11043bb0b038SLuc Michel 11053bb0b038SLuc Michel /* This register is banked per-cpu for PPIs */ 11063bb0b038SLuc Michel int cm = irq < GIC_INTERNAL ? (1 << cpu) : ALL_CPU_MASK; 11073bb0b038SLuc Michel 11083bb0b038SLuc Michel for (i = 0; i < 8; i++) { 11093bb0b038SLuc Michel if (s->security_extn && !attrs.secure && 11103bb0b038SLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 11113bb0b038SLuc Michel continue; /* Ignore Non-secure access of Group0 IRQ */ 11123bb0b038SLuc Michel } 11133bb0b038SLuc Michel 11143bb0b038SLuc Michel if (value & (1 << i)) { 11153bb0b038SLuc Michel GIC_DIST_SET_ACTIVE(irq + i, cm); 11163bb0b038SLuc Michel } 11173bb0b038SLuc Michel } 11183bb0b038SLuc Michel } else if (offset < 0x400) { 11193bb0b038SLuc Michel /* Interrupt Clear Active. */ 11203bb0b038SLuc Michel if (s->revision != 2) { 11213bb0b038SLuc Michel goto bad_reg; 11223bb0b038SLuc Michel } 11233bb0b038SLuc Michel 11243bb0b038SLuc Michel irq = (offset - 0x380) * 8 + GIC_BASE_IRQ; 11253bb0b038SLuc Michel if (irq >= s->num_irq) { 11263bb0b038SLuc Michel goto bad_reg; 11273bb0b038SLuc Michel } 11283bb0b038SLuc Michel 11293bb0b038SLuc Michel /* This register is banked per-cpu for PPIs */ 11303bb0b038SLuc Michel int cm = irq < GIC_INTERNAL ? (1 << cpu) : ALL_CPU_MASK; 11313bb0b038SLuc Michel 11323bb0b038SLuc Michel for (i = 0; i < 8; i++) { 11333bb0b038SLuc Michel if (s->security_extn && !attrs.secure && 11343bb0b038SLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 11353bb0b038SLuc Michel continue; /* Ignore Non-secure access of Group0 IRQ */ 11363bb0b038SLuc Michel } 11373bb0b038SLuc Michel 11383bb0b038SLuc Michel if (value & (1 << i)) { 11393bb0b038SLuc Michel GIC_DIST_CLEAR_ACTIVE(irq + i, cm); 11403bb0b038SLuc Michel } 11413bb0b038SLuc Michel } 1142e69954b9Spbrook } else if (offset < 0x800) { 1143e69954b9Spbrook /* Interrupt Priority. */ 11449ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 1145a32134aaSMark Langsdorf if (irq >= s->num_irq) 1146e69954b9Spbrook goto bad_reg; 114767ce697aSLuc Michel gic_dist_set_priority(s, cpu, irq, value, attrs); 1148e69954b9Spbrook } else if (offset < 0xc00) { 11496b9680bbSPeter Maydell /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the 11506b9680bbSPeter Maydell * annoying exception of the 11MPCore's GIC. 11516b9680bbSPeter Maydell */ 11526b9680bbSPeter Maydell if (s->num_cpu != 1 || s->revision == REV_11MPCORE) { 11539ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 11546b9680bbSPeter Maydell if (irq >= s->num_irq) { 1155e69954b9Spbrook goto bad_reg; 11566b9680bbSPeter Maydell } 11577995206dSPeter Maydell if (irq < 29 && s->revision == REV_11MPCORE) { 11589ee6e8bbSpbrook value = 0; 11596b9680bbSPeter Maydell } else if (irq < GIC_INTERNAL) { 11609ee6e8bbSpbrook value = ALL_CPU_MASK; 11616b9680bbSPeter Maydell } 11629ee6e8bbSpbrook s->irq_target[irq] = value & ALL_CPU_MASK; 11636b9680bbSPeter Maydell } 1164e69954b9Spbrook } else if (offset < 0xf00) { 1165e69954b9Spbrook /* Interrupt Configuration. */ 11669ee6e8bbSpbrook irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 1167a32134aaSMark Langsdorf if (irq >= s->num_irq) 1168e69954b9Spbrook goto bad_reg; 1169de7a900fSAdam Lackorzynski if (irq < GIC_NR_SGIS) 11709ee6e8bbSpbrook value |= 0xaa; 1171e69954b9Spbrook for (i = 0; i < 4; i++) { 1172fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 117367ce697aSLuc Michel !GIC_DIST_TEST_GROUP(irq + i, 1 << cpu)) { 1174fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 1175fea8a08eSJens Wiklander } 1176fea8a08eSJens Wiklander 11777c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 1178e69954b9Spbrook if (value & (1 << (i * 2))) { 117967ce697aSLuc Michel GIC_DIST_SET_MODEL(irq + i); 1180e69954b9Spbrook } else { 118167ce697aSLuc Michel GIC_DIST_CLEAR_MODEL(irq + i); 1182e69954b9Spbrook } 118324b790dfSAdam Lackorzynski } 1184e69954b9Spbrook if (value & (2 << (i * 2))) { 118567ce697aSLuc Michel GIC_DIST_SET_EDGE_TRIGGER(irq + i); 1186e69954b9Spbrook } else { 118767ce697aSLuc Michel GIC_DIST_CLEAR_EDGE_TRIGGER(irq + i); 1188e69954b9Spbrook } 1189e69954b9Spbrook } 119040d22500SChristoffer Dall } else if (offset < 0xf10) { 11919ee6e8bbSpbrook /* 0xf00 is only handled for 32-bit writes. */ 1192e69954b9Spbrook goto bad_reg; 119340d22500SChristoffer Dall } else if (offset < 0xf20) { 119440d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 11957c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 119640d22500SChristoffer Dall goto bad_reg; 119740d22500SChristoffer Dall } 119840d22500SChristoffer Dall irq = (offset - 0xf10); 119940d22500SChristoffer Dall 1200fea8a08eSJens Wiklander if (!s->security_extn || attrs.secure || 120167ce697aSLuc Michel GIC_DIST_TEST_GROUP(irq, 1 << cpu)) { 120240d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~value; 120340d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 120467ce697aSLuc Michel GIC_DIST_CLEAR_PENDING(irq, 1 << cpu); 120540d22500SChristoffer Dall } 1206fea8a08eSJens Wiklander } 120740d22500SChristoffer Dall } else if (offset < 0xf30) { 120840d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 12097c14b3acSMichael Davidsaver if (s->revision == REV_11MPCORE) { 121040d22500SChristoffer Dall goto bad_reg; 121140d22500SChristoffer Dall } 121240d22500SChristoffer Dall irq = (offset - 0xf20); 121340d22500SChristoffer Dall 1214fea8a08eSJens Wiklander if (!s->security_extn || attrs.secure || 121567ce697aSLuc Michel GIC_DIST_TEST_GROUP(irq, 1 << cpu)) { 121667ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, 1 << cpu); 121740d22500SChristoffer Dall s->sgi_pending[irq][cpu] |= value; 1218fea8a08eSJens Wiklander } 121940d22500SChristoffer Dall } else { 122040d22500SChristoffer Dall goto bad_reg; 1221e69954b9Spbrook } 1222e69954b9Spbrook gic_update(s); 1223e69954b9Spbrook return; 1224e69954b9Spbrook bad_reg: 12258c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 12268c8dc39fSPeter Maydell "gic_dist_writeb: Bad offset %x\n", (int)offset); 1227e69954b9Spbrook } 1228e69954b9Spbrook 1229a8170e5eSAvi Kivity static void gic_dist_writew(void *opaque, hwaddr offset, 1230a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1231e69954b9Spbrook { 1232a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, value & 0xff, attrs); 1233a9d85353SPeter Maydell gic_dist_writeb(opaque, offset + 1, value >> 8, attrs); 1234e69954b9Spbrook } 1235e69954b9Spbrook 1236a8170e5eSAvi Kivity static void gic_dist_writel(void *opaque, hwaddr offset, 1237a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1238e69954b9Spbrook { 1239fae15286SPeter Maydell GICState *s = (GICState *)opaque; 12408da3ff18Spbrook if (offset == 0xf00) { 12419ee6e8bbSpbrook int cpu; 12429ee6e8bbSpbrook int irq; 12439ee6e8bbSpbrook int mask; 124440d22500SChristoffer Dall int target_cpu; 12459ee6e8bbSpbrook 1246926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 12479ee6e8bbSpbrook irq = value & 0x3ff; 12489ee6e8bbSpbrook switch ((value >> 24) & 3) { 12499ee6e8bbSpbrook case 0: 12509ee6e8bbSpbrook mask = (value >> 16) & ALL_CPU_MASK; 12519ee6e8bbSpbrook break; 12529ee6e8bbSpbrook case 1: 1253fa250144SAdam Lackorzynski mask = ALL_CPU_MASK ^ (1 << cpu); 12549ee6e8bbSpbrook break; 12559ee6e8bbSpbrook case 2: 1256fa250144SAdam Lackorzynski mask = 1 << cpu; 12579ee6e8bbSpbrook break; 12589ee6e8bbSpbrook default: 12599ee6e8bbSpbrook DPRINTF("Bad Soft Int target filter\n"); 12609ee6e8bbSpbrook mask = ALL_CPU_MASK; 12619ee6e8bbSpbrook break; 12629ee6e8bbSpbrook } 126367ce697aSLuc Michel GIC_DIST_SET_PENDING(irq, mask); 126440d22500SChristoffer Dall target_cpu = ctz32(mask); 126540d22500SChristoffer Dall while (target_cpu < GIC_NCPU) { 126640d22500SChristoffer Dall s->sgi_pending[irq][target_cpu] |= (1 << cpu); 126740d22500SChristoffer Dall mask &= ~(1 << target_cpu); 126840d22500SChristoffer Dall target_cpu = ctz32(mask); 126940d22500SChristoffer Dall } 12709ee6e8bbSpbrook gic_update(s); 12719ee6e8bbSpbrook return; 12729ee6e8bbSpbrook } 1273a9d85353SPeter Maydell gic_dist_writew(opaque, offset, value & 0xffff, attrs); 1274a9d85353SPeter Maydell gic_dist_writew(opaque, offset + 2, value >> 16, attrs); 1275a9d85353SPeter Maydell } 1276a9d85353SPeter Maydell 1277a9d85353SPeter Maydell static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data, 1278a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1279a9d85353SPeter Maydell { 1280a9d85353SPeter Maydell switch (size) { 1281a9d85353SPeter Maydell case 1: 1282a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, data, attrs); 1283a9d85353SPeter Maydell return MEMTX_OK; 1284a9d85353SPeter Maydell case 2: 1285a9d85353SPeter Maydell gic_dist_writew(opaque, offset, data, attrs); 1286a9d85353SPeter Maydell return MEMTX_OK; 1287a9d85353SPeter Maydell case 4: 1288a9d85353SPeter Maydell gic_dist_writel(opaque, offset, data, attrs); 1289a9d85353SPeter Maydell return MEMTX_OK; 1290a9d85353SPeter Maydell default: 1291a9d85353SPeter Maydell return MEMTX_ERROR; 1292a9d85353SPeter Maydell } 1293e69954b9Spbrook } 1294e69954b9Spbrook 129551fd06e0SPeter Maydell static inline uint32_t gic_apr_ns_view(GICState *s, int cpu, int regno) 129651fd06e0SPeter Maydell { 129751fd06e0SPeter Maydell /* Return the Nonsecure view of GICC_APR<regno>. This is the 129851fd06e0SPeter Maydell * second half of GICC_NSAPR. 129951fd06e0SPeter Maydell */ 130051fd06e0SPeter Maydell switch (GIC_MIN_BPR) { 130151fd06e0SPeter Maydell case 0: 130251fd06e0SPeter Maydell if (regno < 2) { 130351fd06e0SPeter Maydell return s->nsapr[regno + 2][cpu]; 130451fd06e0SPeter Maydell } 130551fd06e0SPeter Maydell break; 130651fd06e0SPeter Maydell case 1: 130751fd06e0SPeter Maydell if (regno == 0) { 130851fd06e0SPeter Maydell return s->nsapr[regno + 1][cpu]; 130951fd06e0SPeter Maydell } 131051fd06e0SPeter Maydell break; 131151fd06e0SPeter Maydell case 2: 131251fd06e0SPeter Maydell if (regno == 0) { 131351fd06e0SPeter Maydell return extract32(s->nsapr[0][cpu], 16, 16); 131451fd06e0SPeter Maydell } 131551fd06e0SPeter Maydell break; 131651fd06e0SPeter Maydell case 3: 131751fd06e0SPeter Maydell if (regno == 0) { 131851fd06e0SPeter Maydell return extract32(s->nsapr[0][cpu], 8, 8); 131951fd06e0SPeter Maydell } 132051fd06e0SPeter Maydell break; 132151fd06e0SPeter Maydell default: 132251fd06e0SPeter Maydell g_assert_not_reached(); 132351fd06e0SPeter Maydell } 132451fd06e0SPeter Maydell return 0; 132551fd06e0SPeter Maydell } 132651fd06e0SPeter Maydell 132751fd06e0SPeter Maydell static inline void gic_apr_write_ns_view(GICState *s, int cpu, int regno, 132851fd06e0SPeter Maydell uint32_t value) 132951fd06e0SPeter Maydell { 133051fd06e0SPeter Maydell /* Write the Nonsecure view of GICC_APR<regno>. */ 133151fd06e0SPeter Maydell switch (GIC_MIN_BPR) { 133251fd06e0SPeter Maydell case 0: 133351fd06e0SPeter Maydell if (regno < 2) { 133451fd06e0SPeter Maydell s->nsapr[regno + 2][cpu] = value; 133551fd06e0SPeter Maydell } 133651fd06e0SPeter Maydell break; 133751fd06e0SPeter Maydell case 1: 133851fd06e0SPeter Maydell if (regno == 0) { 133951fd06e0SPeter Maydell s->nsapr[regno + 1][cpu] = value; 134051fd06e0SPeter Maydell } 134151fd06e0SPeter Maydell break; 134251fd06e0SPeter Maydell case 2: 134351fd06e0SPeter Maydell if (regno == 0) { 134451fd06e0SPeter Maydell s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 16, 16, value); 134551fd06e0SPeter Maydell } 134651fd06e0SPeter Maydell break; 134751fd06e0SPeter Maydell case 3: 134851fd06e0SPeter Maydell if (regno == 0) { 134951fd06e0SPeter Maydell s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 8, 8, value); 135051fd06e0SPeter Maydell } 135151fd06e0SPeter Maydell break; 135251fd06e0SPeter Maydell default: 135351fd06e0SPeter Maydell g_assert_not_reached(); 135451fd06e0SPeter Maydell } 135551fd06e0SPeter Maydell } 135651fd06e0SPeter Maydell 1357a9d85353SPeter Maydell static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, 1358a9d85353SPeter Maydell uint64_t *data, MemTxAttrs attrs) 1359e69954b9Spbrook { 1360e69954b9Spbrook switch (offset) { 1361e69954b9Spbrook case 0x00: /* Control */ 136232951860SFabian Aggeler *data = gic_get_cpu_control(s, cpu, attrs); 1363a9d85353SPeter Maydell break; 1364e69954b9Spbrook case 0x04: /* Priority mask */ 136581508470SFabian Aggeler *data = gic_get_priority_mask(s, cpu, attrs); 1366a9d85353SPeter Maydell break; 1367e69954b9Spbrook case 0x08: /* Binary Point */ 13683dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 1369421a3c22SLuc MICHEL if (s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) { 1370421a3c22SLuc MICHEL /* NS view of BPR when CBPR is 1 */ 1371421a3c22SLuc MICHEL *data = MIN(s->bpr[cpu] + 1, 7); 1372421a3c22SLuc MICHEL } else { 1373822e9cc3SFabian Aggeler /* BPR is banked. Non-secure copy stored in ABPR. */ 1374822e9cc3SFabian Aggeler *data = s->abpr[cpu]; 1375421a3c22SLuc MICHEL } 1376822e9cc3SFabian Aggeler } else { 1377a9d85353SPeter Maydell *data = s->bpr[cpu]; 1378822e9cc3SFabian Aggeler } 1379a9d85353SPeter Maydell break; 1380e69954b9Spbrook case 0x0c: /* Acknowledge */ 1381c5619bf9SFabian Aggeler *data = gic_acknowledge_irq(s, cpu, attrs); 1382a9d85353SPeter Maydell break; 138366a0a2cbSDong Xu Wang case 0x14: /* Running Priority */ 138408efa9f2SFabian Aggeler *data = gic_get_running_priority(s, cpu, attrs); 1385a9d85353SPeter Maydell break; 1386e69954b9Spbrook case 0x18: /* Highest Pending Interrupt */ 13877c0fa108SFabian Aggeler *data = gic_get_current_pending_irq(s, cpu, attrs); 1388a9d85353SPeter Maydell break; 1389aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 1390822e9cc3SFabian Aggeler /* GIC v2, no security: ABPR 1391822e9cc3SFabian Aggeler * GIC v1, no security: not implemented (RAZ/WI) 1392822e9cc3SFabian Aggeler * With security extensions, secure access: ABPR (alias of NS BPR) 1393822e9cc3SFabian Aggeler * With security extensions, nonsecure access: RAZ/WI 1394822e9cc3SFabian Aggeler */ 13953dd0471bSLuc Michel if (!gic_has_groups(s) || (gic_cpu_ns_access(s, cpu, attrs))) { 1396822e9cc3SFabian Aggeler *data = 0; 1397822e9cc3SFabian Aggeler } else { 1398a9d85353SPeter Maydell *data = s->abpr[cpu]; 1399822e9cc3SFabian Aggeler } 1400a9d85353SPeter Maydell break; 1401a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 140251fd06e0SPeter Maydell { 140351fd06e0SPeter Maydell int regno = (offset - 0xd0) / 4; 140451fd06e0SPeter Maydell 140551fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 140651fd06e0SPeter Maydell *data = 0; 14073dd0471bSLuc Michel } else if (gic_cpu_ns_access(s, cpu, attrs)) { 140851fd06e0SPeter Maydell /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ 140951fd06e0SPeter Maydell *data = gic_apr_ns_view(s, regno, cpu); 141051fd06e0SPeter Maydell } else { 141151fd06e0SPeter Maydell *data = s->apr[regno][cpu]; 141251fd06e0SPeter Maydell } 1413a9d85353SPeter Maydell break; 141451fd06e0SPeter Maydell } 141551fd06e0SPeter Maydell case 0xe0: case 0xe4: case 0xe8: case 0xec: 141651fd06e0SPeter Maydell { 141751fd06e0SPeter Maydell int regno = (offset - 0xe0) / 4; 141851fd06e0SPeter Maydell 141951fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2 || !gic_has_groups(s) || 14203dd0471bSLuc Michel gic_cpu_ns_access(s, cpu, attrs)) { 142151fd06e0SPeter Maydell *data = 0; 142251fd06e0SPeter Maydell } else { 142351fd06e0SPeter Maydell *data = s->nsapr[regno][cpu]; 142451fd06e0SPeter Maydell } 142551fd06e0SPeter Maydell break; 142651fd06e0SPeter Maydell } 1427e69954b9Spbrook default: 14288c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 14298c8dc39fSPeter Maydell "gic_cpu_read: Bad offset %x\n", (int)offset); 14300cf09852SPeter Maydell *data = 0; 14310cf09852SPeter Maydell break; 1432e69954b9Spbrook } 1433a9d85353SPeter Maydell return MEMTX_OK; 1434e69954b9Spbrook } 1435e69954b9Spbrook 1436a9d85353SPeter Maydell static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, 1437a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1438e69954b9Spbrook { 1439e69954b9Spbrook switch (offset) { 1440e69954b9Spbrook case 0x00: /* Control */ 144132951860SFabian Aggeler gic_set_cpu_control(s, cpu, value, attrs); 1442e69954b9Spbrook break; 1443e69954b9Spbrook case 0x04: /* Priority mask */ 144481508470SFabian Aggeler gic_set_priority_mask(s, cpu, value, attrs); 1445e69954b9Spbrook break; 1446e69954b9Spbrook case 0x08: /* Binary Point */ 14473dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 1448421a3c22SLuc MICHEL if (s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) { 1449421a3c22SLuc MICHEL /* WI when CBPR is 1 */ 1450421a3c22SLuc MICHEL return MEMTX_OK; 1451421a3c22SLuc MICHEL } else { 1452822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1453421a3c22SLuc MICHEL } 1454822e9cc3SFabian Aggeler } else { 1455822e9cc3SFabian Aggeler s->bpr[cpu] = MAX(value & 0x7, GIC_MIN_BPR); 1456822e9cc3SFabian Aggeler } 1457e69954b9Spbrook break; 1458e69954b9Spbrook case 0x10: /* End Of Interrupt */ 1459f9c6a7f1SFabian Aggeler gic_complete_irq(s, cpu, value & 0x3ff, attrs); 1460a9d85353SPeter Maydell return MEMTX_OK; 1461aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 14623dd0471bSLuc Michel if (!gic_has_groups(s) || (gic_cpu_ns_access(s, cpu, attrs))) { 1463822e9cc3SFabian Aggeler /* unimplemented, or NS access: RAZ/WI */ 1464822e9cc3SFabian Aggeler return MEMTX_OK; 1465822e9cc3SFabian Aggeler } else { 1466822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1467aa7d461aSChristoffer Dall } 1468aa7d461aSChristoffer Dall break; 1469a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 147051fd06e0SPeter Maydell { 147151fd06e0SPeter Maydell int regno = (offset - 0xd0) / 4; 147251fd06e0SPeter Maydell 147351fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 147451fd06e0SPeter Maydell return MEMTX_OK; 147551fd06e0SPeter Maydell } 14763dd0471bSLuc Michel if (gic_cpu_ns_access(s, cpu, attrs)) { 147751fd06e0SPeter Maydell /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ 147851fd06e0SPeter Maydell gic_apr_write_ns_view(s, regno, cpu, value); 147951fd06e0SPeter Maydell } else { 148051fd06e0SPeter Maydell s->apr[regno][cpu] = value; 148151fd06e0SPeter Maydell } 1482a9d477c4SChristoffer Dall break; 148351fd06e0SPeter Maydell } 148451fd06e0SPeter Maydell case 0xe0: case 0xe4: case 0xe8: case 0xec: 148551fd06e0SPeter Maydell { 148651fd06e0SPeter Maydell int regno = (offset - 0xe0) / 4; 148751fd06e0SPeter Maydell 148851fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 148951fd06e0SPeter Maydell return MEMTX_OK; 149051fd06e0SPeter Maydell } 14913dd0471bSLuc Michel if (!gic_has_groups(s) || (gic_cpu_ns_access(s, cpu, attrs))) { 149251fd06e0SPeter Maydell return MEMTX_OK; 149351fd06e0SPeter Maydell } 149451fd06e0SPeter Maydell s->nsapr[regno][cpu] = value; 149551fd06e0SPeter Maydell break; 149651fd06e0SPeter Maydell } 1497a55c910eSPeter Maydell case 0x1000: 1498a55c910eSPeter Maydell /* GICC_DIR */ 1499a55c910eSPeter Maydell gic_deactivate_irq(s, cpu, value & 0x3ff, attrs); 1500a55c910eSPeter Maydell break; 1501e69954b9Spbrook default: 15028c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 15038c8dc39fSPeter Maydell "gic_cpu_write: Bad offset %x\n", (int)offset); 15040cf09852SPeter Maydell return MEMTX_OK; 1505e69954b9Spbrook } 1506e69954b9Spbrook gic_update(s); 1507a9d85353SPeter Maydell return MEMTX_OK; 1508e69954b9Spbrook } 1509e2c56465SPeter Maydell 1510e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for the current CPU */ 1511a9d85353SPeter Maydell static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data, 1512a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1513e2c56465SPeter Maydell { 1514fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1515a9d85353SPeter Maydell return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs); 1516e2c56465SPeter Maydell } 1517e2c56465SPeter Maydell 1518a9d85353SPeter Maydell static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr, 1519a9d85353SPeter Maydell uint64_t value, unsigned size, 1520a9d85353SPeter Maydell MemTxAttrs attrs) 1521e2c56465SPeter Maydell { 1522fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1523a9d85353SPeter Maydell return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs); 1524e2c56465SPeter Maydell } 1525e2c56465SPeter Maydell 1526e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for a specific CPU. 1527fae15286SPeter Maydell * These just decode the opaque pointer into GICState* + cpu id. 1528e2c56465SPeter Maydell */ 1529a9d85353SPeter Maydell static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data, 1530a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1531e2c56465SPeter Maydell { 1532fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1533fae15286SPeter Maydell GICState *s = *backref; 1534e2c56465SPeter Maydell int id = (backref - s->backref); 1535a9d85353SPeter Maydell return gic_cpu_read(s, id, addr, data, attrs); 1536e2c56465SPeter Maydell } 1537e2c56465SPeter Maydell 1538a9d85353SPeter Maydell static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr, 1539a9d85353SPeter Maydell uint64_t value, unsigned size, 1540a9d85353SPeter Maydell MemTxAttrs attrs) 1541e2c56465SPeter Maydell { 1542fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1543fae15286SPeter Maydell GICState *s = *backref; 1544e2c56465SPeter Maydell int id = (backref - s->backref); 1545a9d85353SPeter Maydell return gic_cpu_write(s, id, addr, value, attrs); 1546e2c56465SPeter Maydell } 1547e2c56465SPeter Maydell 15487926c210SPavel Fedin static const MemoryRegionOps gic_ops[2] = { 15497926c210SPavel Fedin { 15507926c210SPavel Fedin .read_with_attrs = gic_dist_read, 15517926c210SPavel Fedin .write_with_attrs = gic_dist_write, 15527926c210SPavel Fedin .endianness = DEVICE_NATIVE_ENDIAN, 15537926c210SPavel Fedin }, 15547926c210SPavel Fedin { 1555a9d85353SPeter Maydell .read_with_attrs = gic_thiscpu_read, 1556a9d85353SPeter Maydell .write_with_attrs = gic_thiscpu_write, 1557e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 15587926c210SPavel Fedin } 1559e2c56465SPeter Maydell }; 1560e2c56465SPeter Maydell 1561e2c56465SPeter Maydell static const MemoryRegionOps gic_cpu_ops = { 1562a9d85353SPeter Maydell .read_with_attrs = gic_do_cpu_read, 1563a9d85353SPeter Maydell .write_with_attrs = gic_do_cpu_write, 1564e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 1565e2c56465SPeter Maydell }; 1566e69954b9Spbrook 156753111180SPeter Maydell static void arm_gic_realize(DeviceState *dev, Error **errp) 15682b518c56SPeter Maydell { 156953111180SPeter Maydell /* Device instance realize function for the GIC sysbus device */ 15702b518c56SPeter Maydell int i; 157153111180SPeter Maydell GICState *s = ARM_GIC(dev); 157253111180SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 15731e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_GET_CLASS(s); 15740175ba10SMarkus Armbruster Error *local_err = NULL; 15751e8cae4dSPeter Maydell 15760175ba10SMarkus Armbruster agc->parent_realize(dev, &local_err); 15770175ba10SMarkus Armbruster if (local_err) { 15780175ba10SMarkus Armbruster error_propagate(errp, local_err); 157953111180SPeter Maydell return; 158053111180SPeter Maydell } 15811e8cae4dSPeter Maydell 15825d721b78SAlexander Graf if (kvm_enabled() && !kvm_arm_supports_user_irq()) { 15835d721b78SAlexander Graf error_setg(errp, "KVM with user space irqchip only works when the " 15845d721b78SAlexander Graf "host kernel supports KVM_CAP_ARM_USER_IRQ"); 15855d721b78SAlexander Graf return; 15865d721b78SAlexander Graf } 15875d721b78SAlexander Graf 15887926c210SPavel Fedin /* This creates distributor and main CPU interface (s->cpuiomem[0]) */ 15895773c049SLuc Michel gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops, NULL); 15902b518c56SPeter Maydell 15917926c210SPavel Fedin /* Extra core-specific regions for the CPU interfaces. This is 15927926c210SPavel Fedin * necessary for "franken-GIC" implementations, for example on 15937926c210SPavel Fedin * Exynos 4. 1594e2c56465SPeter Maydell * NB that the memory region size of 0x100 applies for the 11MPCore 1595e2c56465SPeter Maydell * and also cores following the GIC v1 spec (ie A9). 1596e2c56465SPeter Maydell * GIC v2 defines a larger memory region (0x1000) so this will need 1597e2c56465SPeter Maydell * to be extended when we implement A15. 1598e2c56465SPeter Maydell */ 1599b95690c9SWei Huang for (i = 0; i < s->num_cpu; i++) { 1600e2c56465SPeter Maydell s->backref[i] = s; 16011437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, 16021437c94bSPaolo Bonzini &s->backref[i], "gic_cpu", 0x100); 16037926c210SPavel Fedin sysbus_init_mmio(sbd, &s->cpuiomem[i+1]); 1604496dbcd1SPeter Maydell } 1605496dbcd1SPeter Maydell } 1606496dbcd1SPeter Maydell 1607496dbcd1SPeter Maydell static void arm_gic_class_init(ObjectClass *klass, void *data) 1608496dbcd1SPeter Maydell { 1609496dbcd1SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 16101e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_CLASS(klass); 161153111180SPeter Maydell 1612bf853881SPhilippe Mathieu-Daudé device_class_set_parent_realize(dc, arm_gic_realize, &agc->parent_realize); 1613496dbcd1SPeter Maydell } 1614496dbcd1SPeter Maydell 16158c43a6f0SAndreas Färber static const TypeInfo arm_gic_info = { 16161e8cae4dSPeter Maydell .name = TYPE_ARM_GIC, 16171e8cae4dSPeter Maydell .parent = TYPE_ARM_GIC_COMMON, 1618fae15286SPeter Maydell .instance_size = sizeof(GICState), 1619496dbcd1SPeter Maydell .class_init = arm_gic_class_init, 1620998a74bcSPeter Maydell .class_size = sizeof(ARMGICClass), 1621496dbcd1SPeter Maydell }; 1622496dbcd1SPeter Maydell 1623496dbcd1SPeter Maydell static void arm_gic_register_types(void) 1624496dbcd1SPeter Maydell { 1625496dbcd1SPeter Maydell type_register_static(&arm_gic_info); 1626496dbcd1SPeter Maydell } 1627496dbcd1SPeter Maydell 1628496dbcd1SPeter Maydell type_init(arm_gic_register_types) 1629