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" 28386e2955SPeter Maydell 29e69954b9Spbrook //#define DEBUG_GIC 30e69954b9Spbrook 31e69954b9Spbrook #ifdef DEBUG_GIC 32001faf32SBlue Swirl #define DPRINTF(fmt, ...) \ 335eb98401SPeter A. G. Crosthwaite do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0) 34e69954b9Spbrook #else 35001faf32SBlue Swirl #define DPRINTF(fmt, ...) do {} while(0) 36e69954b9Spbrook #endif 37e69954b9Spbrook 383355c360SAlistair Francis static const uint8_t gic_id_11mpcore[] = { 393355c360SAlistair Francis 0x00, 0x00, 0x00, 0x00, 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 403355c360SAlistair Francis }; 413355c360SAlistair Francis 423355c360SAlistair Francis static const uint8_t gic_id_gicv1[] = { 433355c360SAlistair Francis 0x04, 0x00, 0x00, 0x00, 0x90, 0xb3, 0x1b, 0x00, 0x0d, 0xf0, 0x05, 0xb1 443355c360SAlistair Francis }; 453355c360SAlistair Francis 463355c360SAlistair Francis static const uint8_t gic_id_gicv2[] = { 473355c360SAlistair Francis 0x04, 0x00, 0x00, 0x00, 0x90, 0xb4, 0x2b, 0x00, 0x0d, 0xf0, 0x05, 0xb1 482a29ddeeSPeter Maydell }; 492a29ddeeSPeter Maydell 50fae15286SPeter Maydell static inline int gic_get_current_cpu(GICState *s) 51926c4affSPeter Maydell { 52926c4affSPeter Maydell if (s->num_cpu > 1) { 534917cf44SAndreas Färber return current_cpu->cpu_index; 54926c4affSPeter Maydell } 55926c4affSPeter Maydell return 0; 56926c4affSPeter Maydell } 57926c4affSPeter Maydell 58c27a5ba9SFabian Aggeler /* Return true if this GIC config has interrupt groups, which is 59c27a5ba9SFabian Aggeler * true if we're a GICv2, or a GICv1 with the security extensions. 60c27a5ba9SFabian Aggeler */ 61c27a5ba9SFabian Aggeler static inline bool gic_has_groups(GICState *s) 62c27a5ba9SFabian Aggeler { 63c27a5ba9SFabian Aggeler return s->revision == 2 || s->security_extn; 64c27a5ba9SFabian Aggeler } 65c27a5ba9SFabian Aggeler 66e69954b9Spbrook /* TODO: Many places that call this routine could be optimized. */ 67e69954b9Spbrook /* Update interrupt status after enabled or pending bits have been changed. */ 68fae15286SPeter Maydell void gic_update(GICState *s) 69e69954b9Spbrook { 70e69954b9Spbrook int best_irq; 71e69954b9Spbrook int best_prio; 72e69954b9Spbrook int irq; 73dadbb58fSPeter Maydell int irq_level, fiq_level; 749ee6e8bbSpbrook int cpu; 759ee6e8bbSpbrook int cm; 76e69954b9Spbrook 77b95690c9SWei Huang for (cpu = 0; cpu < s->num_cpu; cpu++) { 789ee6e8bbSpbrook cm = 1 << cpu; 799ee6e8bbSpbrook s->current_pending[cpu] = 1023; 80679aa175SFabian Aggeler if (!(s->ctlr & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1)) 8132951860SFabian Aggeler || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) { 829ee6e8bbSpbrook qemu_irq_lower(s->parent_irq[cpu]); 83dadbb58fSPeter Maydell qemu_irq_lower(s->parent_fiq[cpu]); 84235069a3SJohan Karlsson continue; 85e69954b9Spbrook } 86e69954b9Spbrook best_prio = 0x100; 87e69954b9Spbrook best_irq = 1023; 88a32134aaSMark Langsdorf for (irq = 0; irq < s->num_irq; irq++) { 89b52b81e4SSergey Fedorov if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm) && 90b52b81e4SSergey Fedorov (irq < GIC_INTERNAL || GIC_TARGET(irq) & cm)) { 919ee6e8bbSpbrook if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { 929ee6e8bbSpbrook best_prio = GIC_GET_PRIORITY(irq, cpu); 93e69954b9Spbrook best_irq = irq; 94e69954b9Spbrook } 95e69954b9Spbrook } 96e69954b9Spbrook } 97dadbb58fSPeter Maydell 982531088fSHollis Blanchard if (best_irq != 1023) { 992531088fSHollis Blanchard trace_gic_update_bestirq(cpu, best_irq, best_prio, 1002531088fSHollis Blanchard s->priority_mask[cpu], s->running_priority[cpu]); 1012531088fSHollis Blanchard } 1022531088fSHollis Blanchard 103dadbb58fSPeter Maydell irq_level = fiq_level = 0; 104dadbb58fSPeter Maydell 105cad065f1SPeter Maydell if (best_prio < s->priority_mask[cpu]) { 1069ee6e8bbSpbrook s->current_pending[cpu] = best_irq; 1079ee6e8bbSpbrook if (best_prio < s->running_priority[cpu]) { 108dadbb58fSPeter Maydell int group = GIC_TEST_GROUP(best_irq, cm); 109dadbb58fSPeter Maydell 110dadbb58fSPeter Maydell if (extract32(s->ctlr, group, 1) && 111dadbb58fSPeter Maydell extract32(s->cpu_ctlr[cpu], group, 1)) { 112dadbb58fSPeter Maydell if (group == 0 && s->cpu_ctlr[cpu] & GICC_CTLR_FIQ_EN) { 113dadbb58fSPeter Maydell DPRINTF("Raised pending FIQ %d (cpu %d)\n", 114dadbb58fSPeter Maydell best_irq, cpu); 115dadbb58fSPeter Maydell fiq_level = 1; 1162531088fSHollis Blanchard trace_gic_update_set_irq(cpu, "fiq", fiq_level); 117dadbb58fSPeter Maydell } else { 118dadbb58fSPeter Maydell DPRINTF("Raised pending IRQ %d (cpu %d)\n", 119dadbb58fSPeter Maydell best_irq, cpu); 120dadbb58fSPeter Maydell irq_level = 1; 1212531088fSHollis Blanchard trace_gic_update_set_irq(cpu, "irq", irq_level); 122e69954b9Spbrook } 123e69954b9Spbrook } 124dadbb58fSPeter Maydell } 125dadbb58fSPeter Maydell } 126dadbb58fSPeter Maydell 127dadbb58fSPeter Maydell qemu_set_irq(s->parent_irq[cpu], irq_level); 128dadbb58fSPeter Maydell qemu_set_irq(s->parent_fiq[cpu], fiq_level); 1299ee6e8bbSpbrook } 130e69954b9Spbrook } 131e69954b9Spbrook 132fae15286SPeter Maydell void gic_set_pending_private(GICState *s, int cpu, int irq) 1339ee6e8bbSpbrook { 1349ee6e8bbSpbrook int cm = 1 << cpu; 1359ee6e8bbSpbrook 1368d999995SChristoffer Dall if (gic_test_pending(s, irq, cm)) { 1379ee6e8bbSpbrook return; 1388d999995SChristoffer Dall } 1399ee6e8bbSpbrook 1409ee6e8bbSpbrook DPRINTF("Set %d pending cpu %d\n", irq, cpu); 1419ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 1429ee6e8bbSpbrook gic_update(s); 1439ee6e8bbSpbrook } 1449ee6e8bbSpbrook 1458d999995SChristoffer Dall static void gic_set_irq_11mpcore(GICState *s, int irq, int level, 1468d999995SChristoffer Dall int cm, int target) 1478d999995SChristoffer Dall { 1488d999995SChristoffer Dall if (level) { 1498d999995SChristoffer Dall GIC_SET_LEVEL(irq, cm); 1508d999995SChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) { 1518d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 1528d999995SChristoffer Dall GIC_SET_PENDING(irq, target); 1538d999995SChristoffer Dall } 1548d999995SChristoffer Dall } else { 1558d999995SChristoffer Dall GIC_CLEAR_LEVEL(irq, cm); 1568d999995SChristoffer Dall } 1578d999995SChristoffer Dall } 1588d999995SChristoffer Dall 1598d999995SChristoffer Dall static void gic_set_irq_generic(GICState *s, int irq, int level, 1608d999995SChristoffer Dall int cm, int target) 1618d999995SChristoffer Dall { 1628d999995SChristoffer Dall if (level) { 1638d999995SChristoffer Dall GIC_SET_LEVEL(irq, cm); 1648d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 1658d999995SChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq)) { 1668d999995SChristoffer Dall GIC_SET_PENDING(irq, target); 1678d999995SChristoffer Dall } 1688d999995SChristoffer Dall } else { 1698d999995SChristoffer Dall GIC_CLEAR_LEVEL(irq, cm); 1708d999995SChristoffer Dall } 1718d999995SChristoffer Dall } 1728d999995SChristoffer Dall 1739ee6e8bbSpbrook /* Process a change in an external IRQ input. */ 174e69954b9Spbrook static void gic_set_irq(void *opaque, int irq, int level) 175e69954b9Spbrook { 176544d1afaSPeter Maydell /* Meaning of the 'irq' parameter: 177544d1afaSPeter Maydell * [0..N-1] : external interrupts 178544d1afaSPeter Maydell * [N..N+31] : PPI (internal) interrupts for CPU 0 179544d1afaSPeter Maydell * [N+32..N+63] : PPI (internal interrupts for CPU 1 180544d1afaSPeter Maydell * ... 181544d1afaSPeter Maydell */ 182fae15286SPeter Maydell GICState *s = (GICState *)opaque; 183544d1afaSPeter Maydell int cm, target; 184544d1afaSPeter Maydell if (irq < (s->num_irq - GIC_INTERNAL)) { 185e69954b9Spbrook /* The first external input line is internal interrupt 32. */ 186544d1afaSPeter Maydell cm = ALL_CPU_MASK; 18769253800SRusty Russell irq += GIC_INTERNAL; 188544d1afaSPeter Maydell target = GIC_TARGET(irq); 189544d1afaSPeter Maydell } else { 190544d1afaSPeter Maydell int cpu; 191544d1afaSPeter Maydell irq -= (s->num_irq - GIC_INTERNAL); 192544d1afaSPeter Maydell cpu = irq / GIC_INTERNAL; 193544d1afaSPeter Maydell irq %= GIC_INTERNAL; 194544d1afaSPeter Maydell cm = 1 << cpu; 195544d1afaSPeter Maydell target = cm; 196544d1afaSPeter Maydell } 197544d1afaSPeter Maydell 19840d22500SChristoffer Dall assert(irq >= GIC_NR_SGIS); 19940d22500SChristoffer Dall 200544d1afaSPeter Maydell if (level == GIC_TEST_LEVEL(irq, cm)) { 201e69954b9Spbrook return; 202544d1afaSPeter Maydell } 203e69954b9Spbrook 2048d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 2058d999995SChristoffer Dall gic_set_irq_11mpcore(s, irq, level, cm, target); 206e69954b9Spbrook } else { 2078d999995SChristoffer Dall gic_set_irq_generic(s, irq, level, cm, target); 208e69954b9Spbrook } 2092531088fSHollis Blanchard trace_gic_set_irq(irq, level, cm, target); 2108d999995SChristoffer Dall 211e69954b9Spbrook gic_update(s); 212e69954b9Spbrook } 213e69954b9Spbrook 2147c0fa108SFabian Aggeler static uint16_t gic_get_current_pending_irq(GICState *s, int cpu, 2157c0fa108SFabian Aggeler MemTxAttrs attrs) 2167c0fa108SFabian Aggeler { 2177c0fa108SFabian Aggeler uint16_t pending_irq = s->current_pending[cpu]; 2187c0fa108SFabian Aggeler 2197c0fa108SFabian Aggeler if (pending_irq < GIC_MAXIRQ && gic_has_groups(s)) { 2207c0fa108SFabian Aggeler int group = GIC_TEST_GROUP(pending_irq, (1 << cpu)); 2217c0fa108SFabian Aggeler /* On a GIC without the security extensions, reading this register 2227c0fa108SFabian Aggeler * behaves in the same way as a secure access to a GIC with them. 2237c0fa108SFabian Aggeler */ 2247c0fa108SFabian Aggeler bool secure = !s->security_extn || attrs.secure; 2257c0fa108SFabian Aggeler 2267c0fa108SFabian Aggeler if (group == 0 && !secure) { 2277c0fa108SFabian Aggeler /* Group0 interrupts hidden from Non-secure access */ 2287c0fa108SFabian Aggeler return 1023; 2297c0fa108SFabian Aggeler } 2307c0fa108SFabian Aggeler if (group == 1 && secure && !(s->cpu_ctlr[cpu] & GICC_CTLR_ACK_CTL)) { 2317c0fa108SFabian Aggeler /* Group1 interrupts only seen by Secure access if 2327c0fa108SFabian Aggeler * AckCtl bit set. 2337c0fa108SFabian Aggeler */ 2347c0fa108SFabian Aggeler return 1022; 2357c0fa108SFabian Aggeler } 2367c0fa108SFabian Aggeler } 2377c0fa108SFabian Aggeler return pending_irq; 2387c0fa108SFabian Aggeler } 2397c0fa108SFabian Aggeler 240df92cfa6SPeter Maydell static int gic_get_group_priority(GICState *s, int cpu, int irq) 241df92cfa6SPeter Maydell { 242df92cfa6SPeter Maydell /* Return the group priority of the specified interrupt 243df92cfa6SPeter Maydell * (which is the top bits of its priority, with the number 244df92cfa6SPeter Maydell * of bits masked determined by the applicable binary point register). 245df92cfa6SPeter Maydell */ 246df92cfa6SPeter Maydell int bpr; 247df92cfa6SPeter Maydell uint32_t mask; 248df92cfa6SPeter Maydell 249df92cfa6SPeter Maydell if (gic_has_groups(s) && 250df92cfa6SPeter Maydell !(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) && 251df92cfa6SPeter Maydell GIC_TEST_GROUP(irq, (1 << cpu))) { 252df92cfa6SPeter Maydell bpr = s->abpr[cpu]; 253df92cfa6SPeter Maydell } else { 254df92cfa6SPeter Maydell bpr = s->bpr[cpu]; 255df92cfa6SPeter Maydell } 256df92cfa6SPeter Maydell 257df92cfa6SPeter Maydell /* a BPR of 0 means the group priority bits are [7:1]; 258df92cfa6SPeter Maydell * a BPR of 1 means they are [7:2], and so on down to 259df92cfa6SPeter Maydell * a BPR of 7 meaning no group priority bits at all. 260df92cfa6SPeter Maydell */ 261df92cfa6SPeter Maydell mask = ~0U << ((bpr & 7) + 1); 262df92cfa6SPeter Maydell 263df92cfa6SPeter Maydell return GIC_GET_PRIORITY(irq, cpu) & mask; 264df92cfa6SPeter Maydell } 265df92cfa6SPeter Maydell 26672889c8aSPeter Maydell static void gic_activate_irq(GICState *s, int cpu, int irq) 267e69954b9Spbrook { 26872889c8aSPeter Maydell /* Set the appropriate Active Priority Register bit for this IRQ, 26972889c8aSPeter Maydell * and update the running priority. 27072889c8aSPeter Maydell */ 27172889c8aSPeter Maydell int prio = gic_get_group_priority(s, cpu, irq); 27272889c8aSPeter Maydell int preemption_level = prio >> (GIC_MIN_BPR + 1); 27372889c8aSPeter Maydell int regno = preemption_level / 32; 27472889c8aSPeter Maydell int bitno = preemption_level % 32; 27572889c8aSPeter Maydell 27672889c8aSPeter Maydell if (gic_has_groups(s) && GIC_TEST_GROUP(irq, (1 << cpu))) { 277a8595957SFrançois Baldassari s->nsapr[regno][cpu] |= (1 << bitno); 2789ee6e8bbSpbrook } else { 279a8595957SFrançois Baldassari s->apr[regno][cpu] |= (1 << bitno); 2809ee6e8bbSpbrook } 28172889c8aSPeter Maydell 28272889c8aSPeter Maydell s->running_priority[cpu] = prio; 283d5523a13SPeter Maydell GIC_SET_ACTIVE(irq, 1 << cpu); 28472889c8aSPeter Maydell } 28572889c8aSPeter Maydell 28672889c8aSPeter Maydell static int gic_get_prio_from_apr_bits(GICState *s, int cpu) 28772889c8aSPeter Maydell { 28872889c8aSPeter Maydell /* Recalculate the current running priority for this CPU based 28972889c8aSPeter Maydell * on the set bits in the Active Priority Registers. 29072889c8aSPeter Maydell */ 29172889c8aSPeter Maydell int i; 29272889c8aSPeter Maydell for (i = 0; i < GIC_NR_APRS; i++) { 29372889c8aSPeter Maydell uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu]; 29472889c8aSPeter Maydell if (!apr) { 29572889c8aSPeter Maydell continue; 29672889c8aSPeter Maydell } 29772889c8aSPeter Maydell return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1); 29872889c8aSPeter Maydell } 29972889c8aSPeter Maydell return 0x100; 30072889c8aSPeter Maydell } 30172889c8aSPeter Maydell 30272889c8aSPeter Maydell static void gic_drop_prio(GICState *s, int cpu, int group) 30372889c8aSPeter Maydell { 30472889c8aSPeter Maydell /* Drop the priority of the currently active interrupt in the 30572889c8aSPeter Maydell * specified group. 30672889c8aSPeter Maydell * 30772889c8aSPeter Maydell * Note that we can guarantee (because of the requirement to nest 30872889c8aSPeter Maydell * GICC_IAR reads [which activate an interrupt and raise priority] 30972889c8aSPeter Maydell * with GICC_EOIR writes [which drop the priority for the interrupt]) 31072889c8aSPeter Maydell * that the interrupt we're being called for is the highest priority 31172889c8aSPeter Maydell * active interrupt, meaning that it has the lowest set bit in the 31272889c8aSPeter Maydell * APR registers. 31372889c8aSPeter Maydell * 31472889c8aSPeter Maydell * If the guest does not honour the ordering constraints then the 31572889c8aSPeter Maydell * behaviour of the GIC is UNPREDICTABLE, which for us means that 31672889c8aSPeter Maydell * the values of the APR registers might become incorrect and the 31772889c8aSPeter Maydell * running priority will be wrong, so interrupts that should preempt 31872889c8aSPeter Maydell * might not do so, and interrupts that should not preempt might do so. 31972889c8aSPeter Maydell */ 32072889c8aSPeter Maydell int i; 32172889c8aSPeter Maydell 32272889c8aSPeter Maydell for (i = 0; i < GIC_NR_APRS; i++) { 32372889c8aSPeter Maydell uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu]; 32472889c8aSPeter Maydell if (!*papr) { 32572889c8aSPeter Maydell continue; 32672889c8aSPeter Maydell } 32772889c8aSPeter Maydell /* Clear lowest set bit */ 32872889c8aSPeter Maydell *papr &= *papr - 1; 32972889c8aSPeter Maydell break; 33072889c8aSPeter Maydell } 33172889c8aSPeter Maydell 33272889c8aSPeter Maydell s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu); 333e69954b9Spbrook } 334e69954b9Spbrook 335c5619bf9SFabian Aggeler uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) 336e69954b9Spbrook { 33740d22500SChristoffer Dall int ret, irq, src; 3389ee6e8bbSpbrook int cm = 1 << cpu; 339c5619bf9SFabian Aggeler 340c5619bf9SFabian Aggeler /* gic_get_current_pending_irq() will return 1022 or 1023 appropriately 341c5619bf9SFabian Aggeler * for the case where this GIC supports grouping and the pending interrupt 342c5619bf9SFabian Aggeler * is in the wrong group. 343c5619bf9SFabian Aggeler */ 344a8f15a27SDaniel P. Berrange irq = gic_get_current_pending_irq(s, cpu, attrs); 3452531088fSHollis Blanchard trace_gic_acknowledge_irq(cpu, irq); 346c5619bf9SFabian Aggeler 347c5619bf9SFabian Aggeler if (irq >= GIC_MAXIRQ) { 348c5619bf9SFabian Aggeler DPRINTF("ACK, no pending interrupt or it is hidden: %d\n", irq); 349c5619bf9SFabian Aggeler return irq; 350c5619bf9SFabian Aggeler } 351c5619bf9SFabian Aggeler 352c5619bf9SFabian Aggeler if (GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) { 353c5619bf9SFabian Aggeler DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq); 354e69954b9Spbrook return 1023; 355e69954b9Spbrook } 35640d22500SChristoffer Dall 35787316902SPeter Maydell if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 3589ee6e8bbSpbrook /* Clear pending flags for both level and edge triggered interrupts. 35940d22500SChristoffer Dall * Level triggered IRQs will be reasserted once they become inactive. 36040d22500SChristoffer Dall */ 36140d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 36240d22500SChristoffer Dall ret = irq; 36340d22500SChristoffer Dall } else { 36440d22500SChristoffer Dall if (irq < GIC_NR_SGIS) { 36540d22500SChristoffer Dall /* Lookup the source CPU for the SGI and clear this in the 36640d22500SChristoffer Dall * sgi_pending map. Return the src and clear the overall pending 36740d22500SChristoffer Dall * state on this CPU if the SGI is not pending from any CPUs. 36840d22500SChristoffer Dall */ 36940d22500SChristoffer Dall assert(s->sgi_pending[irq][cpu] != 0); 37040d22500SChristoffer Dall src = ctz32(s->sgi_pending[irq][cpu]); 37140d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~(1 << src); 37240d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 37340d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 37440d22500SChristoffer Dall } 37540d22500SChristoffer Dall ret = irq | ((src & 0x7) << 10); 37640d22500SChristoffer Dall } else { 37740d22500SChristoffer Dall /* Clear pending state for both level and edge triggered 37840d22500SChristoffer Dall * interrupts. (level triggered interrupts with an active line 37940d22500SChristoffer Dall * remain pending, see gic_test_pending) 38040d22500SChristoffer Dall */ 38140d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 38240d22500SChristoffer Dall ret = irq; 38340d22500SChristoffer Dall } 38440d22500SChristoffer Dall } 38540d22500SChristoffer Dall 38672889c8aSPeter Maydell gic_activate_irq(s, cpu, irq); 38772889c8aSPeter Maydell gic_update(s); 38840d22500SChristoffer Dall DPRINTF("ACK %d\n", irq); 38940d22500SChristoffer Dall return ret; 390e69954b9Spbrook } 391e69954b9Spbrook 39281508470SFabian Aggeler void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val, 39381508470SFabian Aggeler MemTxAttrs attrs) 3949df90ad0SChristoffer Dall { 39581508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 39681508470SFabian Aggeler if (!GIC_TEST_GROUP(irq, (1 << cpu))) { 39781508470SFabian Aggeler return; /* Ignore Non-secure access of Group0 IRQ */ 39881508470SFabian Aggeler } 39981508470SFabian Aggeler val = 0x80 | (val >> 1); /* Non-secure view */ 40081508470SFabian Aggeler } 40181508470SFabian Aggeler 4029df90ad0SChristoffer Dall if (irq < GIC_INTERNAL) { 4039df90ad0SChristoffer Dall s->priority1[irq][cpu] = val; 4049df90ad0SChristoffer Dall } else { 4059df90ad0SChristoffer Dall s->priority2[(irq) - GIC_INTERNAL] = val; 4069df90ad0SChristoffer Dall } 4079df90ad0SChristoffer Dall } 4089df90ad0SChristoffer Dall 40981508470SFabian Aggeler static uint32_t gic_get_priority(GICState *s, int cpu, int irq, 41081508470SFabian Aggeler MemTxAttrs attrs) 41181508470SFabian Aggeler { 41281508470SFabian Aggeler uint32_t prio = GIC_GET_PRIORITY(irq, cpu); 41381508470SFabian Aggeler 41481508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 41581508470SFabian Aggeler if (!GIC_TEST_GROUP(irq, (1 << cpu))) { 41681508470SFabian Aggeler return 0; /* Non-secure access cannot read priority of Group0 IRQ */ 41781508470SFabian Aggeler } 41881508470SFabian Aggeler prio = (prio << 1) & 0xff; /* Non-secure view */ 41981508470SFabian Aggeler } 42081508470SFabian Aggeler return prio; 42181508470SFabian Aggeler } 42281508470SFabian Aggeler 42381508470SFabian Aggeler static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask, 42481508470SFabian Aggeler MemTxAttrs attrs) 42581508470SFabian Aggeler { 42681508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 42781508470SFabian Aggeler if (s->priority_mask[cpu] & 0x80) { 42881508470SFabian Aggeler /* Priority Mask in upper half */ 42981508470SFabian Aggeler pmask = 0x80 | (pmask >> 1); 43081508470SFabian Aggeler } else { 43181508470SFabian Aggeler /* Non-secure write ignored if priority mask is in lower half */ 43281508470SFabian Aggeler return; 43381508470SFabian Aggeler } 43481508470SFabian Aggeler } 43581508470SFabian Aggeler s->priority_mask[cpu] = pmask; 43681508470SFabian Aggeler } 43781508470SFabian Aggeler 43881508470SFabian Aggeler static uint32_t gic_get_priority_mask(GICState *s, int cpu, MemTxAttrs attrs) 43981508470SFabian Aggeler { 44081508470SFabian Aggeler uint32_t pmask = s->priority_mask[cpu]; 44181508470SFabian Aggeler 44281508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 44381508470SFabian Aggeler if (pmask & 0x80) { 44481508470SFabian Aggeler /* Priority Mask in upper half, return Non-secure view */ 44581508470SFabian Aggeler pmask = (pmask << 1) & 0xff; 44681508470SFabian Aggeler } else { 44781508470SFabian Aggeler /* Priority Mask in lower half, RAZ */ 44881508470SFabian Aggeler pmask = 0; 44981508470SFabian Aggeler } 45081508470SFabian Aggeler } 45181508470SFabian Aggeler return pmask; 45281508470SFabian Aggeler } 45381508470SFabian Aggeler 45432951860SFabian Aggeler static uint32_t gic_get_cpu_control(GICState *s, int cpu, MemTxAttrs attrs) 45532951860SFabian Aggeler { 45632951860SFabian Aggeler uint32_t ret = s->cpu_ctlr[cpu]; 45732951860SFabian Aggeler 45832951860SFabian Aggeler if (s->security_extn && !attrs.secure) { 45932951860SFabian Aggeler /* Construct the NS banked view of GICC_CTLR from the correct 46032951860SFabian Aggeler * bits of the S banked view. We don't need to move the bypass 46132951860SFabian Aggeler * control bits because we don't implement that (IMPDEF) part 46232951860SFabian Aggeler * of the GIC architecture. 46332951860SFabian Aggeler */ 46432951860SFabian Aggeler ret = (ret & (GICC_CTLR_EN_GRP1 | GICC_CTLR_EOIMODE_NS)) >> 1; 46532951860SFabian Aggeler } 46632951860SFabian Aggeler return ret; 46732951860SFabian Aggeler } 46832951860SFabian Aggeler 46932951860SFabian Aggeler static void gic_set_cpu_control(GICState *s, int cpu, uint32_t value, 47032951860SFabian Aggeler MemTxAttrs attrs) 47132951860SFabian Aggeler { 47232951860SFabian Aggeler uint32_t mask; 47332951860SFabian Aggeler 47432951860SFabian Aggeler if (s->security_extn && !attrs.secure) { 47532951860SFabian Aggeler /* The NS view can only write certain bits in the register; 47632951860SFabian Aggeler * the rest are unchanged 47732951860SFabian Aggeler */ 47832951860SFabian Aggeler mask = GICC_CTLR_EN_GRP1; 47932951860SFabian Aggeler if (s->revision == 2) { 48032951860SFabian Aggeler mask |= GICC_CTLR_EOIMODE_NS; 48132951860SFabian Aggeler } 48232951860SFabian Aggeler s->cpu_ctlr[cpu] &= ~mask; 48332951860SFabian Aggeler s->cpu_ctlr[cpu] |= (value << 1) & mask; 48432951860SFabian Aggeler } else { 48532951860SFabian Aggeler if (s->revision == 2) { 48632951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V2_S_MASK : GICC_CTLR_V2_MASK; 48732951860SFabian Aggeler } else { 48832951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V1_S_MASK : GICC_CTLR_V1_MASK; 48932951860SFabian Aggeler } 49032951860SFabian Aggeler s->cpu_ctlr[cpu] = value & mask; 49132951860SFabian Aggeler } 49232951860SFabian Aggeler DPRINTF("CPU Interface %d: Group0 Interrupts %sabled, " 49332951860SFabian Aggeler "Group1 Interrupts %sabled\n", cpu, 49432951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP0) ? "En" : "Dis", 49532951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP1) ? "En" : "Dis"); 49632951860SFabian Aggeler } 49732951860SFabian Aggeler 49808efa9f2SFabian Aggeler static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs) 49908efa9f2SFabian Aggeler { 50008efa9f2SFabian Aggeler if (s->security_extn && !attrs.secure) { 50108efa9f2SFabian Aggeler if (s->running_priority[cpu] & 0x80) { 50208efa9f2SFabian Aggeler /* Running priority in upper half of range: return the Non-secure 50308efa9f2SFabian Aggeler * view of the priority. 50408efa9f2SFabian Aggeler */ 50508efa9f2SFabian Aggeler return s->running_priority[cpu] << 1; 50608efa9f2SFabian Aggeler } else { 50708efa9f2SFabian Aggeler /* Running priority in lower half of range: RAZ */ 50808efa9f2SFabian Aggeler return 0; 50908efa9f2SFabian Aggeler } 51008efa9f2SFabian Aggeler } else { 51108efa9f2SFabian Aggeler return s->running_priority[cpu]; 51208efa9f2SFabian Aggeler } 51308efa9f2SFabian Aggeler } 51408efa9f2SFabian Aggeler 515a55c910eSPeter Maydell /* Return true if we should split priority drop and interrupt deactivation, 516a55c910eSPeter Maydell * ie whether the relevant EOIMode bit is set. 517a55c910eSPeter Maydell */ 518a55c910eSPeter Maydell static bool gic_eoi_split(GICState *s, int cpu, MemTxAttrs attrs) 519a55c910eSPeter Maydell { 520a55c910eSPeter Maydell if (s->revision != 2) { 521a55c910eSPeter Maydell /* Before GICv2 prio-drop and deactivate are not separable */ 522a55c910eSPeter Maydell return false; 523a55c910eSPeter Maydell } 524a55c910eSPeter Maydell if (s->security_extn && !attrs.secure) { 525a55c910eSPeter Maydell return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE_NS; 526a55c910eSPeter Maydell } 527a55c910eSPeter Maydell return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE; 528a55c910eSPeter Maydell } 529a55c910eSPeter Maydell 530a55c910eSPeter Maydell static void gic_deactivate_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) 531a55c910eSPeter Maydell { 532a55c910eSPeter Maydell int cm = 1 << cpu; 533a55c910eSPeter Maydell int group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm); 534a55c910eSPeter Maydell 535a55c910eSPeter Maydell if (!gic_eoi_split(s, cpu, attrs)) { 536a55c910eSPeter Maydell /* This is UNPREDICTABLE; we choose to ignore it */ 537a55c910eSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 538a55c910eSPeter Maydell "gic_deactivate_irq: GICC_DIR write when EOIMode clear"); 539a55c910eSPeter Maydell return; 540a55c910eSPeter Maydell } 541a55c910eSPeter Maydell 542a55c910eSPeter Maydell if (s->security_extn && !attrs.secure && !group) { 543a55c910eSPeter Maydell DPRINTF("Non-secure DI for Group0 interrupt %d ignored\n", irq); 544a55c910eSPeter Maydell return; 545a55c910eSPeter Maydell } 546a55c910eSPeter Maydell 547a55c910eSPeter Maydell GIC_CLEAR_ACTIVE(irq, cm); 548a55c910eSPeter Maydell } 549a55c910eSPeter Maydell 550f9c6a7f1SFabian Aggeler void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) 551e69954b9Spbrook { 5529ee6e8bbSpbrook int cm = 1 << cpu; 55372889c8aSPeter Maydell int group; 55472889c8aSPeter Maydell 555df628ff1Spbrook DPRINTF("EOI %d\n", irq); 556a32134aaSMark Langsdorf if (irq >= s->num_irq) { 557217bfb44SPeter Maydell /* This handles two cases: 558217bfb44SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 559217bfb44SPeter Maydell * to the GICC_EOIR, the GIC ignores that write. 560217bfb44SPeter Maydell * 2. If software writes the number of a non-existent interrupt 561217bfb44SPeter Maydell * this must be a subcase of "value written does not match the last 562217bfb44SPeter Maydell * valid interrupt value read from the Interrupt Acknowledge 563217bfb44SPeter Maydell * register" and so this is UNPREDICTABLE. We choose to ignore it. 564217bfb44SPeter Maydell */ 565217bfb44SPeter Maydell return; 566217bfb44SPeter Maydell } 56772889c8aSPeter Maydell if (s->running_priority[cpu] == 0x100) { 568e69954b9Spbrook return; /* No active IRQ. */ 56972889c8aSPeter Maydell } 5708d999995SChristoffer Dall 5718d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 572e69954b9Spbrook /* Mark level triggered interrupts as pending if they are still 573e69954b9Spbrook raised. */ 57404050c5cSChristoffer Dall if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm) 5759ee6e8bbSpbrook && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) { 5769ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq, cm); 5779ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 578e69954b9Spbrook } 5798d999995SChristoffer Dall } 5808d999995SChristoffer Dall 58172889c8aSPeter Maydell group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm); 58272889c8aSPeter Maydell 58372889c8aSPeter Maydell if (s->security_extn && !attrs.secure && !group) { 584f9c6a7f1SFabian Aggeler DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq); 585f9c6a7f1SFabian Aggeler return; 586f9c6a7f1SFabian Aggeler } 587f9c6a7f1SFabian Aggeler 588f9c6a7f1SFabian Aggeler /* Secure EOI with GICC_CTLR.AckCtl == 0 when the IRQ is a Group 1 589f9c6a7f1SFabian Aggeler * interrupt is UNPREDICTABLE. We choose to handle it as if AckCtl == 1, 590f9c6a7f1SFabian Aggeler * i.e. go ahead and complete the irq anyway. 591f9c6a7f1SFabian Aggeler */ 592f9c6a7f1SFabian Aggeler 59372889c8aSPeter Maydell gic_drop_prio(s, cpu, group); 594a55c910eSPeter Maydell 595a55c910eSPeter Maydell /* In GICv2 the guest can choose to split priority-drop and deactivate */ 596a55c910eSPeter Maydell if (!gic_eoi_split(s, cpu, attrs)) { 597d5523a13SPeter Maydell GIC_CLEAR_ACTIVE(irq, cm); 598a55c910eSPeter Maydell } 599e69954b9Spbrook gic_update(s); 600e69954b9Spbrook } 601e69954b9Spbrook 602a9d85353SPeter Maydell static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) 603e69954b9Spbrook { 604fae15286SPeter Maydell GICState *s = (GICState *)opaque; 605e69954b9Spbrook uint32_t res; 606e69954b9Spbrook int irq; 607e69954b9Spbrook int i; 6089ee6e8bbSpbrook int cpu; 6099ee6e8bbSpbrook int cm; 6109ee6e8bbSpbrook int mask; 611e69954b9Spbrook 612926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 6139ee6e8bbSpbrook cm = 1 << cpu; 614e69954b9Spbrook if (offset < 0x100) { 615679aa175SFabian Aggeler if (offset == 0) { /* GICD_CTLR */ 616679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 617679aa175SFabian Aggeler /* The NS bank of this register is just an alias of the 618679aa175SFabian Aggeler * EnableGrp1 bit in the S bank version. 619679aa175SFabian Aggeler */ 620679aa175SFabian Aggeler return extract32(s->ctlr, 1, 1); 621679aa175SFabian Aggeler } else { 622679aa175SFabian Aggeler return s->ctlr; 623679aa175SFabian Aggeler } 624679aa175SFabian Aggeler } 625e69954b9Spbrook if (offset == 4) 6265543d1abSFabian Aggeler /* Interrupt Controller Type Register */ 6275543d1abSFabian Aggeler return ((s->num_irq / 32) - 1) 628b95690c9SWei Huang | ((s->num_cpu - 1) << 5) 6295543d1abSFabian Aggeler | (s->security_extn << 10); 630e69954b9Spbrook if (offset < 0x08) 631e69954b9Spbrook return 0; 632b79f2265SRob Herring if (offset >= 0x80) { 633c27a5ba9SFabian Aggeler /* Interrupt Group Registers: these RAZ/WI if this is an NS 634c27a5ba9SFabian Aggeler * access to a GIC with the security extensions, or if the GIC 635c27a5ba9SFabian Aggeler * doesn't have groups at all. 636c27a5ba9SFabian Aggeler */ 637c27a5ba9SFabian Aggeler res = 0; 638c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 639c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 640c27a5ba9SFabian Aggeler irq = (offset - 0x080) * 8 + GIC_BASE_IRQ; 641c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 642c27a5ba9SFabian Aggeler goto bad_reg; 643c27a5ba9SFabian Aggeler } 644c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 645c27a5ba9SFabian Aggeler if (GIC_TEST_GROUP(irq + i, cm)) { 646c27a5ba9SFabian Aggeler res |= (1 << i); 647c27a5ba9SFabian Aggeler } 648c27a5ba9SFabian Aggeler } 649c27a5ba9SFabian Aggeler } 650c27a5ba9SFabian Aggeler return res; 651b79f2265SRob Herring } 652e69954b9Spbrook goto bad_reg; 653e69954b9Spbrook } else if (offset < 0x200) { 654e69954b9Spbrook /* Interrupt Set/Clear Enable. */ 655e69954b9Spbrook if (offset < 0x180) 656e69954b9Spbrook irq = (offset - 0x100) * 8; 657e69954b9Spbrook else 658e69954b9Spbrook irq = (offset - 0x180) * 8; 6599ee6e8bbSpbrook irq += GIC_BASE_IRQ; 660a32134aaSMark Langsdorf if (irq >= s->num_irq) 661e69954b9Spbrook goto bad_reg; 662e69954b9Spbrook res = 0; 663e69954b9Spbrook for (i = 0; i < 8; i++) { 664*fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 665*fea8a08eSJens Wiklander !GIC_TEST_GROUP(irq + i, 1 << cpu)) { 666*fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 667*fea8a08eSJens Wiklander } 668*fea8a08eSJens Wiklander 66941bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 670e69954b9Spbrook res |= (1 << i); 671e69954b9Spbrook } 672e69954b9Spbrook } 673e69954b9Spbrook } else if (offset < 0x300) { 674e69954b9Spbrook /* Interrupt Set/Clear Pending. */ 675e69954b9Spbrook if (offset < 0x280) 676e69954b9Spbrook irq = (offset - 0x200) * 8; 677e69954b9Spbrook else 678e69954b9Spbrook irq = (offset - 0x280) * 8; 6799ee6e8bbSpbrook irq += GIC_BASE_IRQ; 680a32134aaSMark Langsdorf if (irq >= s->num_irq) 681e69954b9Spbrook goto bad_reg; 682e69954b9Spbrook res = 0; 68369253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 684e69954b9Spbrook for (i = 0; i < 8; i++) { 685*fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 686*fea8a08eSJens Wiklander !GIC_TEST_GROUP(irq + i, 1 << cpu)) { 687*fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 688*fea8a08eSJens Wiklander } 689*fea8a08eSJens Wiklander 6908d999995SChristoffer Dall if (gic_test_pending(s, irq + i, mask)) { 691e69954b9Spbrook res |= (1 << i); 692e69954b9Spbrook } 693e69954b9Spbrook } 694e69954b9Spbrook } else if (offset < 0x400) { 695e69954b9Spbrook /* Interrupt Active. */ 6969ee6e8bbSpbrook irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 697a32134aaSMark Langsdorf if (irq >= s->num_irq) 698e69954b9Spbrook goto bad_reg; 699e69954b9Spbrook res = 0; 70069253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 701e69954b9Spbrook for (i = 0; i < 8; i++) { 702*fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 703*fea8a08eSJens Wiklander !GIC_TEST_GROUP(irq + i, 1 << cpu)) { 704*fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 705*fea8a08eSJens Wiklander } 706*fea8a08eSJens Wiklander 7079ee6e8bbSpbrook if (GIC_TEST_ACTIVE(irq + i, mask)) { 708e69954b9Spbrook res |= (1 << i); 709e69954b9Spbrook } 710e69954b9Spbrook } 711e69954b9Spbrook } else if (offset < 0x800) { 712e69954b9Spbrook /* Interrupt Priority. */ 7139ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 714a32134aaSMark Langsdorf if (irq >= s->num_irq) 715e69954b9Spbrook goto bad_reg; 71681508470SFabian Aggeler res = gic_get_priority(s, cpu, irq, attrs); 717e69954b9Spbrook } else if (offset < 0xc00) { 718e69954b9Spbrook /* Interrupt CPU Target. */ 7196b9680bbSPeter Maydell if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { 7206b9680bbSPeter Maydell /* For uniprocessor GICs these RAZ/WI */ 7216b9680bbSPeter Maydell res = 0; 7226b9680bbSPeter Maydell } else { 7239ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 7246b9680bbSPeter Maydell if (irq >= s->num_irq) { 725e69954b9Spbrook goto bad_reg; 7266b9680bbSPeter Maydell } 7279ee6e8bbSpbrook if (irq >= 29 && irq <= 31) { 7289ee6e8bbSpbrook res = cm; 7299ee6e8bbSpbrook } else { 7309ee6e8bbSpbrook res = GIC_TARGET(irq); 7319ee6e8bbSpbrook } 7326b9680bbSPeter Maydell } 733e69954b9Spbrook } else if (offset < 0xf00) { 734e69954b9Spbrook /* Interrupt Configuration. */ 73571a62046SAdam Lackorzynski irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 736a32134aaSMark Langsdorf if (irq >= s->num_irq) 737e69954b9Spbrook goto bad_reg; 738e69954b9Spbrook res = 0; 739e69954b9Spbrook for (i = 0; i < 4; i++) { 740*fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 741*fea8a08eSJens Wiklander !GIC_TEST_GROUP(irq + i, 1 << cpu)) { 742*fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 743*fea8a08eSJens Wiklander } 744*fea8a08eSJens Wiklander 745e69954b9Spbrook if (GIC_TEST_MODEL(irq + i)) 746e69954b9Spbrook res |= (1 << (i * 2)); 74704050c5cSChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq + i)) 748e69954b9Spbrook res |= (2 << (i * 2)); 749e69954b9Spbrook } 75040d22500SChristoffer Dall } else if (offset < 0xf10) { 75140d22500SChristoffer Dall goto bad_reg; 75240d22500SChristoffer Dall } else if (offset < 0xf30) { 75340d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 75440d22500SChristoffer Dall goto bad_reg; 75540d22500SChristoffer Dall } 75640d22500SChristoffer Dall 75740d22500SChristoffer Dall if (offset < 0xf20) { 75840d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 75940d22500SChristoffer Dall irq = (offset - 0xf10); 76040d22500SChristoffer Dall } else { 76140d22500SChristoffer Dall irq = (offset - 0xf20); 76240d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 76340d22500SChristoffer Dall } 76440d22500SChristoffer Dall 765*fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 766*fea8a08eSJens Wiklander !GIC_TEST_GROUP(irq, 1 << cpu)) { 767*fea8a08eSJens Wiklander res = 0; /* Ignore Non-secure access of Group0 IRQ */ 768*fea8a08eSJens Wiklander } else { 76940d22500SChristoffer Dall res = s->sgi_pending[irq][cpu]; 770*fea8a08eSJens Wiklander } 7713355c360SAlistair Francis } else if (offset < 0xfd0) { 772e69954b9Spbrook goto bad_reg; 7733355c360SAlistair Francis } else if (offset < 0x1000) { 774e69954b9Spbrook if (offset & 3) { 775e69954b9Spbrook res = 0; 776e69954b9Spbrook } else { 7773355c360SAlistair Francis switch (s->revision) { 7783355c360SAlistair Francis case REV_11MPCORE: 7793355c360SAlistair Francis res = gic_id_11mpcore[(offset - 0xfd0) >> 2]; 7803355c360SAlistair Francis break; 7813355c360SAlistair Francis case 1: 7823355c360SAlistair Francis res = gic_id_gicv1[(offset - 0xfd0) >> 2]; 7833355c360SAlistair Francis break; 7843355c360SAlistair Francis case 2: 7853355c360SAlistair Francis res = gic_id_gicv2[(offset - 0xfd0) >> 2]; 7863355c360SAlistair Francis break; 7873355c360SAlistair Francis case REV_NVIC: 7883355c360SAlistair Francis /* Shouldn't be able to get here */ 7893355c360SAlistair Francis abort(); 7903355c360SAlistair Francis default: 7913355c360SAlistair Francis res = 0; 792e69954b9Spbrook } 793e69954b9Spbrook } 7943355c360SAlistair Francis } else { 7953355c360SAlistair Francis g_assert_not_reached(); 7963355c360SAlistair Francis } 797e69954b9Spbrook return res; 798e69954b9Spbrook bad_reg: 7998c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 8008c8dc39fSPeter Maydell "gic_dist_readb: Bad offset %x\n", (int)offset); 801e69954b9Spbrook return 0; 802e69954b9Spbrook } 803e69954b9Spbrook 804a9d85353SPeter Maydell static MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data, 805a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 806e69954b9Spbrook { 807a9d85353SPeter Maydell switch (size) { 808a9d85353SPeter Maydell case 1: 809a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 810a9d85353SPeter Maydell return MEMTX_OK; 811a9d85353SPeter Maydell case 2: 812a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 813a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 814a9d85353SPeter Maydell return MEMTX_OK; 815a9d85353SPeter Maydell case 4: 816a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 817a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 818a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 2, attrs) << 16; 819a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 3, attrs) << 24; 820a9d85353SPeter Maydell return MEMTX_OK; 821a9d85353SPeter Maydell default: 822a9d85353SPeter Maydell return MEMTX_ERROR; 823e69954b9Spbrook } 824e69954b9Spbrook } 825e69954b9Spbrook 826a8170e5eSAvi Kivity static void gic_dist_writeb(void *opaque, hwaddr offset, 827a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 828e69954b9Spbrook { 829fae15286SPeter Maydell GICState *s = (GICState *)opaque; 830e69954b9Spbrook int irq; 831e69954b9Spbrook int i; 8329ee6e8bbSpbrook int cpu; 833e69954b9Spbrook 834926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 835e69954b9Spbrook if (offset < 0x100) { 836e69954b9Spbrook if (offset == 0) { 837679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 838679aa175SFabian Aggeler /* NS version is just an alias of the S version's bit 1 */ 839679aa175SFabian Aggeler s->ctlr = deposit32(s->ctlr, 1, 1, value); 840679aa175SFabian Aggeler } else if (gic_has_groups(s)) { 841679aa175SFabian Aggeler s->ctlr = value & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1); 842679aa175SFabian Aggeler } else { 843679aa175SFabian Aggeler s->ctlr = value & GICD_CTLR_EN_GRP0; 844679aa175SFabian Aggeler } 845679aa175SFabian Aggeler DPRINTF("Distributor: Group0 %sabled; Group 1 %sabled\n", 846679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP0 ? "En" : "Dis", 847679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP1 ? "En" : "Dis"); 848e69954b9Spbrook } else if (offset < 4) { 849e69954b9Spbrook /* ignored. */ 850b79f2265SRob Herring } else if (offset >= 0x80) { 851c27a5ba9SFabian Aggeler /* Interrupt Group Registers: RAZ/WI for NS access to secure 852c27a5ba9SFabian Aggeler * GIC, or for GICs without groups. 853c27a5ba9SFabian Aggeler */ 854c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 855c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 856c27a5ba9SFabian Aggeler irq = (offset - 0x80) * 8 + GIC_BASE_IRQ; 857c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 858c27a5ba9SFabian Aggeler goto bad_reg; 859c27a5ba9SFabian Aggeler } 860c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 861c27a5ba9SFabian Aggeler /* Group bits are banked for private interrupts */ 862c27a5ba9SFabian Aggeler int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 863c27a5ba9SFabian Aggeler if (value & (1 << i)) { 864c27a5ba9SFabian Aggeler /* Group1 (Non-secure) */ 865c27a5ba9SFabian Aggeler GIC_SET_GROUP(irq + i, cm); 866c27a5ba9SFabian Aggeler } else { 867c27a5ba9SFabian Aggeler /* Group0 (Secure) */ 868c27a5ba9SFabian Aggeler GIC_CLEAR_GROUP(irq + i, cm); 869c27a5ba9SFabian Aggeler } 870c27a5ba9SFabian Aggeler } 871c27a5ba9SFabian Aggeler } 872e69954b9Spbrook } else { 873e69954b9Spbrook goto bad_reg; 874e69954b9Spbrook } 875e69954b9Spbrook } else if (offset < 0x180) { 876e69954b9Spbrook /* Interrupt Set Enable. */ 8779ee6e8bbSpbrook irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 878a32134aaSMark Langsdorf if (irq >= s->num_irq) 879e69954b9Spbrook goto bad_reg; 88041ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 8819ee6e8bbSpbrook value = 0xff; 88241ab7b55SChristoffer Dall } 88341ab7b55SChristoffer Dall 884e69954b9Spbrook for (i = 0; i < 8; i++) { 885e69954b9Spbrook if (value & (1 << i)) { 886f47b48fbSDaniel Sangorrin int mask = 887f47b48fbSDaniel Sangorrin (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i); 88869253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 88941bf234dSRabin Vincent 890*fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 891*fea8a08eSJens Wiklander !GIC_TEST_GROUP(irq + i, 1 << cpu)) { 892*fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 893*fea8a08eSJens Wiklander } 894*fea8a08eSJens Wiklander 89541bf234dSRabin Vincent if (!GIC_TEST_ENABLED(irq + i, cm)) { 896e69954b9Spbrook DPRINTF("Enabled IRQ %d\n", irq + i); 8972531088fSHollis Blanchard trace_gic_enable_irq(irq + i); 89841bf234dSRabin Vincent } 89941bf234dSRabin Vincent GIC_SET_ENABLED(irq + i, cm); 900e69954b9Spbrook /* If a raised level triggered IRQ enabled then mark 901e69954b9Spbrook is as pending. */ 9029ee6e8bbSpbrook if (GIC_TEST_LEVEL(irq + i, mask) 90304050c5cSChristoffer Dall && !GIC_TEST_EDGE_TRIGGER(irq + i)) { 9049ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq + i, mask); 9059ee6e8bbSpbrook GIC_SET_PENDING(irq + i, mask); 9069ee6e8bbSpbrook } 907e69954b9Spbrook } 908e69954b9Spbrook } 909e69954b9Spbrook } else if (offset < 0x200) { 910e69954b9Spbrook /* Interrupt Clear Enable. */ 9119ee6e8bbSpbrook irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 912a32134aaSMark Langsdorf if (irq >= s->num_irq) 913e69954b9Spbrook goto bad_reg; 91441ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 9159ee6e8bbSpbrook value = 0; 91641ab7b55SChristoffer Dall } 91741ab7b55SChristoffer Dall 918e69954b9Spbrook for (i = 0; i < 8; i++) { 919e69954b9Spbrook if (value & (1 << i)) { 92069253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 92141bf234dSRabin Vincent 922*fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 923*fea8a08eSJens Wiklander !GIC_TEST_GROUP(irq + i, 1 << cpu)) { 924*fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 925*fea8a08eSJens Wiklander } 926*fea8a08eSJens Wiklander 92741bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 928e69954b9Spbrook DPRINTF("Disabled IRQ %d\n", irq + i); 9292531088fSHollis Blanchard trace_gic_disable_irq(irq + i); 93041bf234dSRabin Vincent } 93141bf234dSRabin Vincent GIC_CLEAR_ENABLED(irq + i, cm); 932e69954b9Spbrook } 933e69954b9Spbrook } 934e69954b9Spbrook } else if (offset < 0x280) { 935e69954b9Spbrook /* Interrupt Set Pending. */ 9369ee6e8bbSpbrook irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 937a32134aaSMark Langsdorf if (irq >= s->num_irq) 938e69954b9Spbrook goto bad_reg; 93941ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 9405b0adce1SChristoffer Dall value = 0; 94141ab7b55SChristoffer Dall } 9429ee6e8bbSpbrook 943e69954b9Spbrook for (i = 0; i < 8; i++) { 944e69954b9Spbrook if (value & (1 << i)) { 945*fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 946*fea8a08eSJens Wiklander !GIC_TEST_GROUP(irq + i, 1 << cpu)) { 947*fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 948*fea8a08eSJens Wiklander } 949*fea8a08eSJens Wiklander 950f47b48fbSDaniel Sangorrin GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); 951e69954b9Spbrook } 952e69954b9Spbrook } 953e69954b9Spbrook } else if (offset < 0x300) { 954e69954b9Spbrook /* Interrupt Clear Pending. */ 9559ee6e8bbSpbrook irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 956a32134aaSMark Langsdorf if (irq >= s->num_irq) 957e69954b9Spbrook goto bad_reg; 9585b0adce1SChristoffer Dall if (irq < GIC_NR_SGIS) { 9595b0adce1SChristoffer Dall value = 0; 9605b0adce1SChristoffer Dall } 9615b0adce1SChristoffer Dall 962e69954b9Spbrook for (i = 0; i < 8; i++) { 963*fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 964*fea8a08eSJens Wiklander !GIC_TEST_GROUP(irq + i, 1 << cpu)) { 965*fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 966*fea8a08eSJens Wiklander } 967*fea8a08eSJens Wiklander 9689ee6e8bbSpbrook /* ??? This currently clears the pending bit for all CPUs, even 9699ee6e8bbSpbrook for per-CPU interrupts. It's unclear whether this is the 9709ee6e8bbSpbrook corect behavior. */ 971e69954b9Spbrook if (value & (1 << i)) { 9729ee6e8bbSpbrook GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 973e69954b9Spbrook } 974e69954b9Spbrook } 975e69954b9Spbrook } else if (offset < 0x400) { 976e69954b9Spbrook /* Interrupt Active. */ 977e69954b9Spbrook goto bad_reg; 978e69954b9Spbrook } else if (offset < 0x800) { 979e69954b9Spbrook /* Interrupt Priority. */ 9809ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 981a32134aaSMark Langsdorf if (irq >= s->num_irq) 982e69954b9Spbrook goto bad_reg; 98381508470SFabian Aggeler gic_set_priority(s, cpu, irq, value, attrs); 984e69954b9Spbrook } else if (offset < 0xc00) { 9856b9680bbSPeter Maydell /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the 9866b9680bbSPeter Maydell * annoying exception of the 11MPCore's GIC. 9876b9680bbSPeter Maydell */ 9886b9680bbSPeter Maydell if (s->num_cpu != 1 || s->revision == REV_11MPCORE) { 9899ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 9906b9680bbSPeter Maydell if (irq >= s->num_irq) { 991e69954b9Spbrook goto bad_reg; 9926b9680bbSPeter Maydell } 9936b9680bbSPeter Maydell if (irq < 29) { 9949ee6e8bbSpbrook value = 0; 9956b9680bbSPeter Maydell } else if (irq < GIC_INTERNAL) { 9969ee6e8bbSpbrook value = ALL_CPU_MASK; 9976b9680bbSPeter Maydell } 9989ee6e8bbSpbrook s->irq_target[irq] = value & ALL_CPU_MASK; 9996b9680bbSPeter Maydell } 1000e69954b9Spbrook } else if (offset < 0xf00) { 1001e69954b9Spbrook /* Interrupt Configuration. */ 10029ee6e8bbSpbrook irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 1003a32134aaSMark Langsdorf if (irq >= s->num_irq) 1004e69954b9Spbrook goto bad_reg; 1005de7a900fSAdam Lackorzynski if (irq < GIC_NR_SGIS) 10069ee6e8bbSpbrook value |= 0xaa; 1007e69954b9Spbrook for (i = 0; i < 4; i++) { 1008*fea8a08eSJens Wiklander if (s->security_extn && !attrs.secure && 1009*fea8a08eSJens Wiklander !GIC_TEST_GROUP(irq + i, 1 << cpu)) { 1010*fea8a08eSJens Wiklander continue; /* Ignore Non-secure access of Group0 IRQ */ 1011*fea8a08eSJens Wiklander } 1012*fea8a08eSJens Wiklander 101324b790dfSAdam Lackorzynski if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 1014e69954b9Spbrook if (value & (1 << (i * 2))) { 1015e69954b9Spbrook GIC_SET_MODEL(irq + i); 1016e69954b9Spbrook } else { 1017e69954b9Spbrook GIC_CLEAR_MODEL(irq + i); 1018e69954b9Spbrook } 101924b790dfSAdam Lackorzynski } 1020e69954b9Spbrook if (value & (2 << (i * 2))) { 102104050c5cSChristoffer Dall GIC_SET_EDGE_TRIGGER(irq + i); 1022e69954b9Spbrook } else { 102304050c5cSChristoffer Dall GIC_CLEAR_EDGE_TRIGGER(irq + i); 1024e69954b9Spbrook } 1025e69954b9Spbrook } 102640d22500SChristoffer Dall } else if (offset < 0xf10) { 10279ee6e8bbSpbrook /* 0xf00 is only handled for 32-bit writes. */ 1028e69954b9Spbrook goto bad_reg; 102940d22500SChristoffer Dall } else if (offset < 0xf20) { 103040d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 103140d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 103240d22500SChristoffer Dall goto bad_reg; 103340d22500SChristoffer Dall } 103440d22500SChristoffer Dall irq = (offset - 0xf10); 103540d22500SChristoffer Dall 1036*fea8a08eSJens Wiklander if (!s->security_extn || attrs.secure || 1037*fea8a08eSJens Wiklander GIC_TEST_GROUP(irq, 1 << cpu)) { 103840d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~value; 103940d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 104040d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, 1 << cpu); 104140d22500SChristoffer Dall } 1042*fea8a08eSJens Wiklander } 104340d22500SChristoffer Dall } else if (offset < 0xf30) { 104440d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 104540d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 104640d22500SChristoffer Dall goto bad_reg; 104740d22500SChristoffer Dall } 104840d22500SChristoffer Dall irq = (offset - 0xf20); 104940d22500SChristoffer Dall 1050*fea8a08eSJens Wiklander if (!s->security_extn || attrs.secure || 1051*fea8a08eSJens Wiklander GIC_TEST_GROUP(irq, 1 << cpu)) { 105240d22500SChristoffer Dall GIC_SET_PENDING(irq, 1 << cpu); 105340d22500SChristoffer Dall s->sgi_pending[irq][cpu] |= value; 1054*fea8a08eSJens Wiklander } 105540d22500SChristoffer Dall } else { 105640d22500SChristoffer Dall goto bad_reg; 1057e69954b9Spbrook } 1058e69954b9Spbrook gic_update(s); 1059e69954b9Spbrook return; 1060e69954b9Spbrook bad_reg: 10618c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 10628c8dc39fSPeter Maydell "gic_dist_writeb: Bad offset %x\n", (int)offset); 1063e69954b9Spbrook } 1064e69954b9Spbrook 1065a8170e5eSAvi Kivity static void gic_dist_writew(void *opaque, hwaddr offset, 1066a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1067e69954b9Spbrook { 1068a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, value & 0xff, attrs); 1069a9d85353SPeter Maydell gic_dist_writeb(opaque, offset + 1, value >> 8, attrs); 1070e69954b9Spbrook } 1071e69954b9Spbrook 1072a8170e5eSAvi Kivity static void gic_dist_writel(void *opaque, hwaddr offset, 1073a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1074e69954b9Spbrook { 1075fae15286SPeter Maydell GICState *s = (GICState *)opaque; 10768da3ff18Spbrook if (offset == 0xf00) { 10779ee6e8bbSpbrook int cpu; 10789ee6e8bbSpbrook int irq; 10799ee6e8bbSpbrook int mask; 108040d22500SChristoffer Dall int target_cpu; 10819ee6e8bbSpbrook 1082926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 10839ee6e8bbSpbrook irq = value & 0x3ff; 10849ee6e8bbSpbrook switch ((value >> 24) & 3) { 10859ee6e8bbSpbrook case 0: 10869ee6e8bbSpbrook mask = (value >> 16) & ALL_CPU_MASK; 10879ee6e8bbSpbrook break; 10889ee6e8bbSpbrook case 1: 1089fa250144SAdam Lackorzynski mask = ALL_CPU_MASK ^ (1 << cpu); 10909ee6e8bbSpbrook break; 10919ee6e8bbSpbrook case 2: 1092fa250144SAdam Lackorzynski mask = 1 << cpu; 10939ee6e8bbSpbrook break; 10949ee6e8bbSpbrook default: 10959ee6e8bbSpbrook DPRINTF("Bad Soft Int target filter\n"); 10969ee6e8bbSpbrook mask = ALL_CPU_MASK; 10979ee6e8bbSpbrook break; 10989ee6e8bbSpbrook } 10999ee6e8bbSpbrook GIC_SET_PENDING(irq, mask); 110040d22500SChristoffer Dall target_cpu = ctz32(mask); 110140d22500SChristoffer Dall while (target_cpu < GIC_NCPU) { 110240d22500SChristoffer Dall s->sgi_pending[irq][target_cpu] |= (1 << cpu); 110340d22500SChristoffer Dall mask &= ~(1 << target_cpu); 110440d22500SChristoffer Dall target_cpu = ctz32(mask); 110540d22500SChristoffer Dall } 11069ee6e8bbSpbrook gic_update(s); 11079ee6e8bbSpbrook return; 11089ee6e8bbSpbrook } 1109a9d85353SPeter Maydell gic_dist_writew(opaque, offset, value & 0xffff, attrs); 1110a9d85353SPeter Maydell gic_dist_writew(opaque, offset + 2, value >> 16, attrs); 1111a9d85353SPeter Maydell } 1112a9d85353SPeter Maydell 1113a9d85353SPeter Maydell static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data, 1114a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1115a9d85353SPeter Maydell { 1116a9d85353SPeter Maydell switch (size) { 1117a9d85353SPeter Maydell case 1: 1118a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, data, attrs); 1119a9d85353SPeter Maydell return MEMTX_OK; 1120a9d85353SPeter Maydell case 2: 1121a9d85353SPeter Maydell gic_dist_writew(opaque, offset, data, attrs); 1122a9d85353SPeter Maydell return MEMTX_OK; 1123a9d85353SPeter Maydell case 4: 1124a9d85353SPeter Maydell gic_dist_writel(opaque, offset, data, attrs); 1125a9d85353SPeter Maydell return MEMTX_OK; 1126a9d85353SPeter Maydell default: 1127a9d85353SPeter Maydell return MEMTX_ERROR; 1128a9d85353SPeter Maydell } 1129e69954b9Spbrook } 1130e69954b9Spbrook 113151fd06e0SPeter Maydell static inline uint32_t gic_apr_ns_view(GICState *s, int cpu, int regno) 113251fd06e0SPeter Maydell { 113351fd06e0SPeter Maydell /* Return the Nonsecure view of GICC_APR<regno>. This is the 113451fd06e0SPeter Maydell * second half of GICC_NSAPR. 113551fd06e0SPeter Maydell */ 113651fd06e0SPeter Maydell switch (GIC_MIN_BPR) { 113751fd06e0SPeter Maydell case 0: 113851fd06e0SPeter Maydell if (regno < 2) { 113951fd06e0SPeter Maydell return s->nsapr[regno + 2][cpu]; 114051fd06e0SPeter Maydell } 114151fd06e0SPeter Maydell break; 114251fd06e0SPeter Maydell case 1: 114351fd06e0SPeter Maydell if (regno == 0) { 114451fd06e0SPeter Maydell return s->nsapr[regno + 1][cpu]; 114551fd06e0SPeter Maydell } 114651fd06e0SPeter Maydell break; 114751fd06e0SPeter Maydell case 2: 114851fd06e0SPeter Maydell if (regno == 0) { 114951fd06e0SPeter Maydell return extract32(s->nsapr[0][cpu], 16, 16); 115051fd06e0SPeter Maydell } 115151fd06e0SPeter Maydell break; 115251fd06e0SPeter Maydell case 3: 115351fd06e0SPeter Maydell if (regno == 0) { 115451fd06e0SPeter Maydell return extract32(s->nsapr[0][cpu], 8, 8); 115551fd06e0SPeter Maydell } 115651fd06e0SPeter Maydell break; 115751fd06e0SPeter Maydell default: 115851fd06e0SPeter Maydell g_assert_not_reached(); 115951fd06e0SPeter Maydell } 116051fd06e0SPeter Maydell return 0; 116151fd06e0SPeter Maydell } 116251fd06e0SPeter Maydell 116351fd06e0SPeter Maydell static inline void gic_apr_write_ns_view(GICState *s, int cpu, int regno, 116451fd06e0SPeter Maydell uint32_t value) 116551fd06e0SPeter Maydell { 116651fd06e0SPeter Maydell /* Write the Nonsecure view of GICC_APR<regno>. */ 116751fd06e0SPeter Maydell switch (GIC_MIN_BPR) { 116851fd06e0SPeter Maydell case 0: 116951fd06e0SPeter Maydell if (regno < 2) { 117051fd06e0SPeter Maydell s->nsapr[regno + 2][cpu] = value; 117151fd06e0SPeter Maydell } 117251fd06e0SPeter Maydell break; 117351fd06e0SPeter Maydell case 1: 117451fd06e0SPeter Maydell if (regno == 0) { 117551fd06e0SPeter Maydell s->nsapr[regno + 1][cpu] = value; 117651fd06e0SPeter Maydell } 117751fd06e0SPeter Maydell break; 117851fd06e0SPeter Maydell case 2: 117951fd06e0SPeter Maydell if (regno == 0) { 118051fd06e0SPeter Maydell s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 16, 16, value); 118151fd06e0SPeter Maydell } 118251fd06e0SPeter Maydell break; 118351fd06e0SPeter Maydell case 3: 118451fd06e0SPeter Maydell if (regno == 0) { 118551fd06e0SPeter Maydell s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 8, 8, value); 118651fd06e0SPeter Maydell } 118751fd06e0SPeter Maydell break; 118851fd06e0SPeter Maydell default: 118951fd06e0SPeter Maydell g_assert_not_reached(); 119051fd06e0SPeter Maydell } 119151fd06e0SPeter Maydell } 119251fd06e0SPeter Maydell 1193a9d85353SPeter Maydell static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, 1194a9d85353SPeter Maydell uint64_t *data, MemTxAttrs attrs) 1195e69954b9Spbrook { 1196e69954b9Spbrook switch (offset) { 1197e69954b9Spbrook case 0x00: /* Control */ 119832951860SFabian Aggeler *data = gic_get_cpu_control(s, cpu, attrs); 1199a9d85353SPeter Maydell break; 1200e69954b9Spbrook case 0x04: /* Priority mask */ 120181508470SFabian Aggeler *data = gic_get_priority_mask(s, cpu, attrs); 1202a9d85353SPeter Maydell break; 1203e69954b9Spbrook case 0x08: /* Binary Point */ 1204822e9cc3SFabian Aggeler if (s->security_extn && !attrs.secure) { 1205822e9cc3SFabian Aggeler /* BPR is banked. Non-secure copy stored in ABPR. */ 1206822e9cc3SFabian Aggeler *data = s->abpr[cpu]; 1207822e9cc3SFabian Aggeler } else { 1208a9d85353SPeter Maydell *data = s->bpr[cpu]; 1209822e9cc3SFabian Aggeler } 1210a9d85353SPeter Maydell break; 1211e69954b9Spbrook case 0x0c: /* Acknowledge */ 1212c5619bf9SFabian Aggeler *data = gic_acknowledge_irq(s, cpu, attrs); 1213a9d85353SPeter Maydell break; 121466a0a2cbSDong Xu Wang case 0x14: /* Running Priority */ 121508efa9f2SFabian Aggeler *data = gic_get_running_priority(s, cpu, attrs); 1216a9d85353SPeter Maydell break; 1217e69954b9Spbrook case 0x18: /* Highest Pending Interrupt */ 12187c0fa108SFabian Aggeler *data = gic_get_current_pending_irq(s, cpu, attrs); 1219a9d85353SPeter Maydell break; 1220aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 1221822e9cc3SFabian Aggeler /* GIC v2, no security: ABPR 1222822e9cc3SFabian Aggeler * GIC v1, no security: not implemented (RAZ/WI) 1223822e9cc3SFabian Aggeler * With security extensions, secure access: ABPR (alias of NS BPR) 1224822e9cc3SFabian Aggeler * With security extensions, nonsecure access: RAZ/WI 1225822e9cc3SFabian Aggeler */ 1226822e9cc3SFabian Aggeler if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 1227822e9cc3SFabian Aggeler *data = 0; 1228822e9cc3SFabian Aggeler } else { 1229a9d85353SPeter Maydell *data = s->abpr[cpu]; 1230822e9cc3SFabian Aggeler } 1231a9d85353SPeter Maydell break; 1232a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 123351fd06e0SPeter Maydell { 123451fd06e0SPeter Maydell int regno = (offset - 0xd0) / 4; 123551fd06e0SPeter Maydell 123651fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 123751fd06e0SPeter Maydell *data = 0; 123851fd06e0SPeter Maydell } else if (s->security_extn && !attrs.secure) { 123951fd06e0SPeter Maydell /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ 124051fd06e0SPeter Maydell *data = gic_apr_ns_view(s, regno, cpu); 124151fd06e0SPeter Maydell } else { 124251fd06e0SPeter Maydell *data = s->apr[regno][cpu]; 124351fd06e0SPeter Maydell } 1244a9d85353SPeter Maydell break; 124551fd06e0SPeter Maydell } 124651fd06e0SPeter Maydell case 0xe0: case 0xe4: case 0xe8: case 0xec: 124751fd06e0SPeter Maydell { 124851fd06e0SPeter Maydell int regno = (offset - 0xe0) / 4; 124951fd06e0SPeter Maydell 125051fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2 || !gic_has_groups(s) || 125151fd06e0SPeter Maydell (s->security_extn && !attrs.secure)) { 125251fd06e0SPeter Maydell *data = 0; 125351fd06e0SPeter Maydell } else { 125451fd06e0SPeter Maydell *data = s->nsapr[regno][cpu]; 125551fd06e0SPeter Maydell } 125651fd06e0SPeter Maydell break; 125751fd06e0SPeter Maydell } 1258e69954b9Spbrook default: 12598c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 12608c8dc39fSPeter Maydell "gic_cpu_read: Bad offset %x\n", (int)offset); 1261a9d85353SPeter Maydell return MEMTX_ERROR; 1262e69954b9Spbrook } 1263a9d85353SPeter Maydell return MEMTX_OK; 1264e69954b9Spbrook } 1265e69954b9Spbrook 1266a9d85353SPeter Maydell static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, 1267a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1268e69954b9Spbrook { 1269e69954b9Spbrook switch (offset) { 1270e69954b9Spbrook case 0x00: /* Control */ 127132951860SFabian Aggeler gic_set_cpu_control(s, cpu, value, attrs); 1272e69954b9Spbrook break; 1273e69954b9Spbrook case 0x04: /* Priority mask */ 127481508470SFabian Aggeler gic_set_priority_mask(s, cpu, value, attrs); 1275e69954b9Spbrook break; 1276e69954b9Spbrook case 0x08: /* Binary Point */ 1277822e9cc3SFabian Aggeler if (s->security_extn && !attrs.secure) { 1278822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1279822e9cc3SFabian Aggeler } else { 1280822e9cc3SFabian Aggeler s->bpr[cpu] = MAX(value & 0x7, GIC_MIN_BPR); 1281822e9cc3SFabian Aggeler } 1282e69954b9Spbrook break; 1283e69954b9Spbrook case 0x10: /* End Of Interrupt */ 1284f9c6a7f1SFabian Aggeler gic_complete_irq(s, cpu, value & 0x3ff, attrs); 1285a9d85353SPeter Maydell return MEMTX_OK; 1286aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 1287822e9cc3SFabian Aggeler if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 1288822e9cc3SFabian Aggeler /* unimplemented, or NS access: RAZ/WI */ 1289822e9cc3SFabian Aggeler return MEMTX_OK; 1290822e9cc3SFabian Aggeler } else { 1291822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1292aa7d461aSChristoffer Dall } 1293aa7d461aSChristoffer Dall break; 1294a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 129551fd06e0SPeter Maydell { 129651fd06e0SPeter Maydell int regno = (offset - 0xd0) / 4; 129751fd06e0SPeter Maydell 129851fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 129951fd06e0SPeter Maydell return MEMTX_OK; 130051fd06e0SPeter Maydell } 130151fd06e0SPeter Maydell if (s->security_extn && !attrs.secure) { 130251fd06e0SPeter Maydell /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ 130351fd06e0SPeter Maydell gic_apr_write_ns_view(s, regno, cpu, value); 130451fd06e0SPeter Maydell } else { 130551fd06e0SPeter Maydell s->apr[regno][cpu] = value; 130651fd06e0SPeter Maydell } 1307a9d477c4SChristoffer Dall break; 130851fd06e0SPeter Maydell } 130951fd06e0SPeter Maydell case 0xe0: case 0xe4: case 0xe8: case 0xec: 131051fd06e0SPeter Maydell { 131151fd06e0SPeter Maydell int regno = (offset - 0xe0) / 4; 131251fd06e0SPeter Maydell 131351fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 131451fd06e0SPeter Maydell return MEMTX_OK; 131551fd06e0SPeter Maydell } 131651fd06e0SPeter Maydell if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 131751fd06e0SPeter Maydell return MEMTX_OK; 131851fd06e0SPeter Maydell } 131951fd06e0SPeter Maydell s->nsapr[regno][cpu] = value; 132051fd06e0SPeter Maydell break; 132151fd06e0SPeter Maydell } 1322a55c910eSPeter Maydell case 0x1000: 1323a55c910eSPeter Maydell /* GICC_DIR */ 1324a55c910eSPeter Maydell gic_deactivate_irq(s, cpu, value & 0x3ff, attrs); 1325a55c910eSPeter Maydell break; 1326e69954b9Spbrook default: 13278c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 13288c8dc39fSPeter Maydell "gic_cpu_write: Bad offset %x\n", (int)offset); 1329a9d85353SPeter Maydell return MEMTX_ERROR; 1330e69954b9Spbrook } 1331e69954b9Spbrook gic_update(s); 1332a9d85353SPeter Maydell return MEMTX_OK; 1333e69954b9Spbrook } 1334e2c56465SPeter Maydell 1335e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for the current CPU */ 1336a9d85353SPeter Maydell static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data, 1337a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1338e2c56465SPeter Maydell { 1339fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1340a9d85353SPeter Maydell return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs); 1341e2c56465SPeter Maydell } 1342e2c56465SPeter Maydell 1343a9d85353SPeter Maydell static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr, 1344a9d85353SPeter Maydell uint64_t value, unsigned size, 1345a9d85353SPeter Maydell MemTxAttrs attrs) 1346e2c56465SPeter Maydell { 1347fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1348a9d85353SPeter Maydell return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs); 1349e2c56465SPeter Maydell } 1350e2c56465SPeter Maydell 1351e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for a specific CPU. 1352fae15286SPeter Maydell * These just decode the opaque pointer into GICState* + cpu id. 1353e2c56465SPeter Maydell */ 1354a9d85353SPeter Maydell static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data, 1355a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1356e2c56465SPeter Maydell { 1357fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1358fae15286SPeter Maydell GICState *s = *backref; 1359e2c56465SPeter Maydell int id = (backref - s->backref); 1360a9d85353SPeter Maydell return gic_cpu_read(s, id, addr, data, attrs); 1361e2c56465SPeter Maydell } 1362e2c56465SPeter Maydell 1363a9d85353SPeter Maydell static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr, 1364a9d85353SPeter Maydell uint64_t value, unsigned size, 1365a9d85353SPeter Maydell MemTxAttrs attrs) 1366e2c56465SPeter Maydell { 1367fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1368fae15286SPeter Maydell GICState *s = *backref; 1369e2c56465SPeter Maydell int id = (backref - s->backref); 1370a9d85353SPeter Maydell return gic_cpu_write(s, id, addr, value, attrs); 1371e2c56465SPeter Maydell } 1372e2c56465SPeter Maydell 13737926c210SPavel Fedin static const MemoryRegionOps gic_ops[2] = { 13747926c210SPavel Fedin { 13757926c210SPavel Fedin .read_with_attrs = gic_dist_read, 13767926c210SPavel Fedin .write_with_attrs = gic_dist_write, 13777926c210SPavel Fedin .endianness = DEVICE_NATIVE_ENDIAN, 13787926c210SPavel Fedin }, 13797926c210SPavel Fedin { 1380a9d85353SPeter Maydell .read_with_attrs = gic_thiscpu_read, 1381a9d85353SPeter Maydell .write_with_attrs = gic_thiscpu_write, 1382e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 13837926c210SPavel Fedin } 1384e2c56465SPeter Maydell }; 1385e2c56465SPeter Maydell 1386e2c56465SPeter Maydell static const MemoryRegionOps gic_cpu_ops = { 1387a9d85353SPeter Maydell .read_with_attrs = gic_do_cpu_read, 1388a9d85353SPeter Maydell .write_with_attrs = gic_do_cpu_write, 1389e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 1390e2c56465SPeter Maydell }; 1391e69954b9Spbrook 13927926c210SPavel Fedin /* This function is used by nvic model */ 13937b95a508SKONRAD Frederic void gic_init_irqs_and_distributor(GICState *s) 1394e69954b9Spbrook { 13957926c210SPavel Fedin gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); 13962b518c56SPeter Maydell } 13972b518c56SPeter Maydell 139853111180SPeter Maydell static void arm_gic_realize(DeviceState *dev, Error **errp) 13992b518c56SPeter Maydell { 140053111180SPeter Maydell /* Device instance realize function for the GIC sysbus device */ 14012b518c56SPeter Maydell int i; 140253111180SPeter Maydell GICState *s = ARM_GIC(dev); 140353111180SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 14041e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_GET_CLASS(s); 14050175ba10SMarkus Armbruster Error *local_err = NULL; 14061e8cae4dSPeter Maydell 14070175ba10SMarkus Armbruster agc->parent_realize(dev, &local_err); 14080175ba10SMarkus Armbruster if (local_err) { 14090175ba10SMarkus Armbruster error_propagate(errp, local_err); 141053111180SPeter Maydell return; 141153111180SPeter Maydell } 14121e8cae4dSPeter Maydell 14137926c210SPavel Fedin /* This creates distributor and main CPU interface (s->cpuiomem[0]) */ 14147926c210SPavel Fedin gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); 14152b518c56SPeter Maydell 14167926c210SPavel Fedin /* Extra core-specific regions for the CPU interfaces. This is 14177926c210SPavel Fedin * necessary for "franken-GIC" implementations, for example on 14187926c210SPavel Fedin * Exynos 4. 1419e2c56465SPeter Maydell * NB that the memory region size of 0x100 applies for the 11MPCore 1420e2c56465SPeter Maydell * and also cores following the GIC v1 spec (ie A9). 1421e2c56465SPeter Maydell * GIC v2 defines a larger memory region (0x1000) so this will need 1422e2c56465SPeter Maydell * to be extended when we implement A15. 1423e2c56465SPeter Maydell */ 1424b95690c9SWei Huang for (i = 0; i < s->num_cpu; i++) { 1425e2c56465SPeter Maydell s->backref[i] = s; 14261437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, 14271437c94bSPaolo Bonzini &s->backref[i], "gic_cpu", 0x100); 14287926c210SPavel Fedin sysbus_init_mmio(sbd, &s->cpuiomem[i+1]); 1429496dbcd1SPeter Maydell } 1430496dbcd1SPeter Maydell } 1431496dbcd1SPeter Maydell 1432496dbcd1SPeter Maydell static void arm_gic_class_init(ObjectClass *klass, void *data) 1433496dbcd1SPeter Maydell { 1434496dbcd1SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 14351e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_CLASS(klass); 143653111180SPeter Maydell 143753111180SPeter Maydell agc->parent_realize = dc->realize; 143853111180SPeter Maydell dc->realize = arm_gic_realize; 1439496dbcd1SPeter Maydell } 1440496dbcd1SPeter Maydell 14418c43a6f0SAndreas Färber static const TypeInfo arm_gic_info = { 14421e8cae4dSPeter Maydell .name = TYPE_ARM_GIC, 14431e8cae4dSPeter Maydell .parent = TYPE_ARM_GIC_COMMON, 1444fae15286SPeter Maydell .instance_size = sizeof(GICState), 1445496dbcd1SPeter Maydell .class_init = arm_gic_class_init, 1446998a74bcSPeter Maydell .class_size = sizeof(ARMGICClass), 1447496dbcd1SPeter Maydell }; 1448496dbcd1SPeter Maydell 1449496dbcd1SPeter Maydell static void arm_gic_register_types(void) 1450496dbcd1SPeter Maydell { 1451496dbcd1SPeter Maydell type_register_static(&arm_gic_info); 1452496dbcd1SPeter Maydell } 1453496dbcd1SPeter Maydell 1454496dbcd1SPeter Maydell type_init(arm_gic_register_types) 1455