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" 24dfc08079SAndreas Färber #include "qom/cpu.h" 25386e2955SPeter Maydell 26e69954b9Spbrook //#define DEBUG_GIC 27e69954b9Spbrook 28e69954b9Spbrook #ifdef DEBUG_GIC 29001faf32SBlue Swirl #define DPRINTF(fmt, ...) \ 305eb98401SPeter A. G. Crosthwaite do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0) 31e69954b9Spbrook #else 32001faf32SBlue Swirl #define DPRINTF(fmt, ...) do {} while(0) 33e69954b9Spbrook #endif 34e69954b9Spbrook 353355c360SAlistair Francis static const uint8_t gic_id_11mpcore[] = { 363355c360SAlistair Francis 0x00, 0x00, 0x00, 0x00, 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 373355c360SAlistair Francis }; 383355c360SAlistair Francis 393355c360SAlistair Francis static const uint8_t gic_id_gicv1[] = { 403355c360SAlistair Francis 0x04, 0x00, 0x00, 0x00, 0x90, 0xb3, 0x1b, 0x00, 0x0d, 0xf0, 0x05, 0xb1 413355c360SAlistair Francis }; 423355c360SAlistair Francis 433355c360SAlistair Francis static const uint8_t gic_id_gicv2[] = { 443355c360SAlistair Francis 0x04, 0x00, 0x00, 0x00, 0x90, 0xb4, 0x2b, 0x00, 0x0d, 0xf0, 0x05, 0xb1 452a29ddeeSPeter Maydell }; 462a29ddeeSPeter Maydell 47fae15286SPeter Maydell static inline int gic_get_current_cpu(GICState *s) 48926c4affSPeter Maydell { 49926c4affSPeter Maydell if (s->num_cpu > 1) { 504917cf44SAndreas Färber return current_cpu->cpu_index; 51926c4affSPeter Maydell } 52926c4affSPeter Maydell return 0; 53926c4affSPeter Maydell } 54926c4affSPeter Maydell 55c27a5ba9SFabian Aggeler /* Return true if this GIC config has interrupt groups, which is 56c27a5ba9SFabian Aggeler * true if we're a GICv2, or a GICv1 with the security extensions. 57c27a5ba9SFabian Aggeler */ 58c27a5ba9SFabian Aggeler static inline bool gic_has_groups(GICState *s) 59c27a5ba9SFabian Aggeler { 60c27a5ba9SFabian Aggeler return s->revision == 2 || s->security_extn; 61c27a5ba9SFabian Aggeler } 62c27a5ba9SFabian Aggeler 63e69954b9Spbrook /* TODO: Many places that call this routine could be optimized. */ 64e69954b9Spbrook /* Update interrupt status after enabled or pending bits have been changed. */ 65fae15286SPeter Maydell void gic_update(GICState *s) 66e69954b9Spbrook { 67e69954b9Spbrook int best_irq; 68e69954b9Spbrook int best_prio; 69e69954b9Spbrook int irq; 70dadbb58fSPeter Maydell int irq_level, fiq_level; 719ee6e8bbSpbrook int cpu; 729ee6e8bbSpbrook int cm; 73e69954b9Spbrook 74b95690c9SWei Huang for (cpu = 0; cpu < s->num_cpu; cpu++) { 759ee6e8bbSpbrook cm = 1 << cpu; 769ee6e8bbSpbrook s->current_pending[cpu] = 1023; 77679aa175SFabian Aggeler if (!(s->ctlr & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1)) 7832951860SFabian Aggeler || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) { 799ee6e8bbSpbrook qemu_irq_lower(s->parent_irq[cpu]); 80dadbb58fSPeter Maydell qemu_irq_lower(s->parent_fiq[cpu]); 81235069a3SJohan Karlsson continue; 82e69954b9Spbrook } 83e69954b9Spbrook best_prio = 0x100; 84e69954b9Spbrook best_irq = 1023; 85a32134aaSMark Langsdorf for (irq = 0; irq < s->num_irq; irq++) { 86b52b81e4SSergey Fedorov if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm) && 87b52b81e4SSergey Fedorov (irq < GIC_INTERNAL || GIC_TARGET(irq) & cm)) { 889ee6e8bbSpbrook if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { 899ee6e8bbSpbrook best_prio = GIC_GET_PRIORITY(irq, cpu); 90e69954b9Spbrook best_irq = irq; 91e69954b9Spbrook } 92e69954b9Spbrook } 93e69954b9Spbrook } 94dadbb58fSPeter Maydell 95dadbb58fSPeter Maydell irq_level = fiq_level = 0; 96dadbb58fSPeter Maydell 97cad065f1SPeter Maydell if (best_prio < s->priority_mask[cpu]) { 989ee6e8bbSpbrook s->current_pending[cpu] = best_irq; 999ee6e8bbSpbrook if (best_prio < s->running_priority[cpu]) { 100dadbb58fSPeter Maydell int group = GIC_TEST_GROUP(best_irq, cm); 101dadbb58fSPeter Maydell 102dadbb58fSPeter Maydell if (extract32(s->ctlr, group, 1) && 103dadbb58fSPeter Maydell extract32(s->cpu_ctlr[cpu], group, 1)) { 104dadbb58fSPeter Maydell if (group == 0 && s->cpu_ctlr[cpu] & GICC_CTLR_FIQ_EN) { 105dadbb58fSPeter Maydell DPRINTF("Raised pending FIQ %d (cpu %d)\n", 106dadbb58fSPeter Maydell best_irq, cpu); 107dadbb58fSPeter Maydell fiq_level = 1; 108dadbb58fSPeter Maydell } else { 109dadbb58fSPeter Maydell DPRINTF("Raised pending IRQ %d (cpu %d)\n", 110dadbb58fSPeter Maydell best_irq, cpu); 111dadbb58fSPeter Maydell irq_level = 1; 112e69954b9Spbrook } 113e69954b9Spbrook } 114dadbb58fSPeter Maydell } 115dadbb58fSPeter Maydell } 116dadbb58fSPeter Maydell 117dadbb58fSPeter Maydell qemu_set_irq(s->parent_irq[cpu], irq_level); 118dadbb58fSPeter Maydell qemu_set_irq(s->parent_fiq[cpu], fiq_level); 1199ee6e8bbSpbrook } 120e69954b9Spbrook } 121e69954b9Spbrook 122fae15286SPeter Maydell void gic_set_pending_private(GICState *s, int cpu, int irq) 1239ee6e8bbSpbrook { 1249ee6e8bbSpbrook int cm = 1 << cpu; 1259ee6e8bbSpbrook 1268d999995SChristoffer Dall if (gic_test_pending(s, irq, cm)) { 1279ee6e8bbSpbrook return; 1288d999995SChristoffer Dall } 1299ee6e8bbSpbrook 1309ee6e8bbSpbrook DPRINTF("Set %d pending cpu %d\n", irq, cpu); 1319ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 1329ee6e8bbSpbrook gic_update(s); 1339ee6e8bbSpbrook } 1349ee6e8bbSpbrook 1358d999995SChristoffer Dall static void gic_set_irq_11mpcore(GICState *s, int irq, int level, 1368d999995SChristoffer Dall int cm, int target) 1378d999995SChristoffer Dall { 1388d999995SChristoffer Dall if (level) { 1398d999995SChristoffer Dall GIC_SET_LEVEL(irq, cm); 1408d999995SChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) { 1418d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 1428d999995SChristoffer Dall GIC_SET_PENDING(irq, target); 1438d999995SChristoffer Dall } 1448d999995SChristoffer Dall } else { 1458d999995SChristoffer Dall GIC_CLEAR_LEVEL(irq, cm); 1468d999995SChristoffer Dall } 1478d999995SChristoffer Dall } 1488d999995SChristoffer Dall 1498d999995SChristoffer Dall static void gic_set_irq_generic(GICState *s, int irq, int level, 1508d999995SChristoffer Dall int cm, int target) 1518d999995SChristoffer Dall { 1528d999995SChristoffer Dall if (level) { 1538d999995SChristoffer Dall GIC_SET_LEVEL(irq, cm); 1548d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 1558d999995SChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq)) { 1568d999995SChristoffer Dall GIC_SET_PENDING(irq, target); 1578d999995SChristoffer Dall } 1588d999995SChristoffer Dall } else { 1598d999995SChristoffer Dall GIC_CLEAR_LEVEL(irq, cm); 1608d999995SChristoffer Dall } 1618d999995SChristoffer Dall } 1628d999995SChristoffer Dall 1639ee6e8bbSpbrook /* Process a change in an external IRQ input. */ 164e69954b9Spbrook static void gic_set_irq(void *opaque, int irq, int level) 165e69954b9Spbrook { 166544d1afaSPeter Maydell /* Meaning of the 'irq' parameter: 167544d1afaSPeter Maydell * [0..N-1] : external interrupts 168544d1afaSPeter Maydell * [N..N+31] : PPI (internal) interrupts for CPU 0 169544d1afaSPeter Maydell * [N+32..N+63] : PPI (internal interrupts for CPU 1 170544d1afaSPeter Maydell * ... 171544d1afaSPeter Maydell */ 172fae15286SPeter Maydell GICState *s = (GICState *)opaque; 173544d1afaSPeter Maydell int cm, target; 174544d1afaSPeter Maydell if (irq < (s->num_irq - GIC_INTERNAL)) { 175e69954b9Spbrook /* The first external input line is internal interrupt 32. */ 176544d1afaSPeter Maydell cm = ALL_CPU_MASK; 17769253800SRusty Russell irq += GIC_INTERNAL; 178544d1afaSPeter Maydell target = GIC_TARGET(irq); 179544d1afaSPeter Maydell } else { 180544d1afaSPeter Maydell int cpu; 181544d1afaSPeter Maydell irq -= (s->num_irq - GIC_INTERNAL); 182544d1afaSPeter Maydell cpu = irq / GIC_INTERNAL; 183544d1afaSPeter Maydell irq %= GIC_INTERNAL; 184544d1afaSPeter Maydell cm = 1 << cpu; 185544d1afaSPeter Maydell target = cm; 186544d1afaSPeter Maydell } 187544d1afaSPeter Maydell 18840d22500SChristoffer Dall assert(irq >= GIC_NR_SGIS); 18940d22500SChristoffer Dall 190544d1afaSPeter Maydell if (level == GIC_TEST_LEVEL(irq, cm)) { 191e69954b9Spbrook return; 192544d1afaSPeter Maydell } 193e69954b9Spbrook 1948d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 1958d999995SChristoffer Dall gic_set_irq_11mpcore(s, irq, level, cm, target); 196e69954b9Spbrook } else { 1978d999995SChristoffer Dall gic_set_irq_generic(s, irq, level, cm, target); 198e69954b9Spbrook } 1998d999995SChristoffer Dall 200e69954b9Spbrook gic_update(s); 201e69954b9Spbrook } 202e69954b9Spbrook 2037c0fa108SFabian Aggeler static uint16_t gic_get_current_pending_irq(GICState *s, int cpu, 2047c0fa108SFabian Aggeler MemTxAttrs attrs) 2057c0fa108SFabian Aggeler { 2067c0fa108SFabian Aggeler uint16_t pending_irq = s->current_pending[cpu]; 2077c0fa108SFabian Aggeler 2087c0fa108SFabian Aggeler if (pending_irq < GIC_MAXIRQ && gic_has_groups(s)) { 2097c0fa108SFabian Aggeler int group = GIC_TEST_GROUP(pending_irq, (1 << cpu)); 2107c0fa108SFabian Aggeler /* On a GIC without the security extensions, reading this register 2117c0fa108SFabian Aggeler * behaves in the same way as a secure access to a GIC with them. 2127c0fa108SFabian Aggeler */ 2137c0fa108SFabian Aggeler bool secure = !s->security_extn || attrs.secure; 2147c0fa108SFabian Aggeler 2157c0fa108SFabian Aggeler if (group == 0 && !secure) { 2167c0fa108SFabian Aggeler /* Group0 interrupts hidden from Non-secure access */ 2177c0fa108SFabian Aggeler return 1023; 2187c0fa108SFabian Aggeler } 2197c0fa108SFabian Aggeler if (group == 1 && secure && !(s->cpu_ctlr[cpu] & GICC_CTLR_ACK_CTL)) { 2207c0fa108SFabian Aggeler /* Group1 interrupts only seen by Secure access if 2217c0fa108SFabian Aggeler * AckCtl bit set. 2227c0fa108SFabian Aggeler */ 2237c0fa108SFabian Aggeler return 1022; 2247c0fa108SFabian Aggeler } 2257c0fa108SFabian Aggeler } 2267c0fa108SFabian Aggeler return pending_irq; 2277c0fa108SFabian Aggeler } 2287c0fa108SFabian Aggeler 229df92cfa6SPeter Maydell static int gic_get_group_priority(GICState *s, int cpu, int irq) 230df92cfa6SPeter Maydell { 231df92cfa6SPeter Maydell /* Return the group priority of the specified interrupt 232df92cfa6SPeter Maydell * (which is the top bits of its priority, with the number 233df92cfa6SPeter Maydell * of bits masked determined by the applicable binary point register). 234df92cfa6SPeter Maydell */ 235df92cfa6SPeter Maydell int bpr; 236df92cfa6SPeter Maydell uint32_t mask; 237df92cfa6SPeter Maydell 238df92cfa6SPeter Maydell if (gic_has_groups(s) && 239df92cfa6SPeter Maydell !(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) && 240df92cfa6SPeter Maydell GIC_TEST_GROUP(irq, (1 << cpu))) { 241df92cfa6SPeter Maydell bpr = s->abpr[cpu]; 242df92cfa6SPeter Maydell } else { 243df92cfa6SPeter Maydell bpr = s->bpr[cpu]; 244df92cfa6SPeter Maydell } 245df92cfa6SPeter Maydell 246df92cfa6SPeter Maydell /* a BPR of 0 means the group priority bits are [7:1]; 247df92cfa6SPeter Maydell * a BPR of 1 means they are [7:2], and so on down to 248df92cfa6SPeter Maydell * a BPR of 7 meaning no group priority bits at all. 249df92cfa6SPeter Maydell */ 250df92cfa6SPeter Maydell mask = ~0U << ((bpr & 7) + 1); 251df92cfa6SPeter Maydell 252df92cfa6SPeter Maydell return GIC_GET_PRIORITY(irq, cpu) & mask; 253df92cfa6SPeter Maydell } 254df92cfa6SPeter Maydell 25572889c8aSPeter Maydell static void gic_activate_irq(GICState *s, int cpu, int irq) 256e69954b9Spbrook { 25772889c8aSPeter Maydell /* Set the appropriate Active Priority Register bit for this IRQ, 25872889c8aSPeter Maydell * and update the running priority. 25972889c8aSPeter Maydell */ 26072889c8aSPeter Maydell int prio = gic_get_group_priority(s, cpu, irq); 26172889c8aSPeter Maydell int preemption_level = prio >> (GIC_MIN_BPR + 1); 26272889c8aSPeter Maydell int regno = preemption_level / 32; 26372889c8aSPeter Maydell int bitno = preemption_level % 32; 26472889c8aSPeter Maydell 26572889c8aSPeter Maydell if (gic_has_groups(s) && GIC_TEST_GROUP(irq, (1 << cpu))) { 266a8595957SFrançois Baldassari s->nsapr[regno][cpu] |= (1 << bitno); 2679ee6e8bbSpbrook } else { 268a8595957SFrançois Baldassari s->apr[regno][cpu] |= (1 << bitno); 2699ee6e8bbSpbrook } 27072889c8aSPeter Maydell 27172889c8aSPeter Maydell s->running_priority[cpu] = prio; 272d5523a13SPeter Maydell GIC_SET_ACTIVE(irq, 1 << cpu); 27372889c8aSPeter Maydell } 27472889c8aSPeter Maydell 27572889c8aSPeter Maydell static int gic_get_prio_from_apr_bits(GICState *s, int cpu) 27672889c8aSPeter Maydell { 27772889c8aSPeter Maydell /* Recalculate the current running priority for this CPU based 27872889c8aSPeter Maydell * on the set bits in the Active Priority Registers. 27972889c8aSPeter Maydell */ 28072889c8aSPeter Maydell int i; 28172889c8aSPeter Maydell for (i = 0; i < GIC_NR_APRS; i++) { 28272889c8aSPeter Maydell uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu]; 28372889c8aSPeter Maydell if (!apr) { 28472889c8aSPeter Maydell continue; 28572889c8aSPeter Maydell } 28672889c8aSPeter Maydell return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1); 28772889c8aSPeter Maydell } 28872889c8aSPeter Maydell return 0x100; 28972889c8aSPeter Maydell } 29072889c8aSPeter Maydell 29172889c8aSPeter Maydell static void gic_drop_prio(GICState *s, int cpu, int group) 29272889c8aSPeter Maydell { 29372889c8aSPeter Maydell /* Drop the priority of the currently active interrupt in the 29472889c8aSPeter Maydell * specified group. 29572889c8aSPeter Maydell * 29672889c8aSPeter Maydell * Note that we can guarantee (because of the requirement to nest 29772889c8aSPeter Maydell * GICC_IAR reads [which activate an interrupt and raise priority] 29872889c8aSPeter Maydell * with GICC_EOIR writes [which drop the priority for the interrupt]) 29972889c8aSPeter Maydell * that the interrupt we're being called for is the highest priority 30072889c8aSPeter Maydell * active interrupt, meaning that it has the lowest set bit in the 30172889c8aSPeter Maydell * APR registers. 30272889c8aSPeter Maydell * 30372889c8aSPeter Maydell * If the guest does not honour the ordering constraints then the 30472889c8aSPeter Maydell * behaviour of the GIC is UNPREDICTABLE, which for us means that 30572889c8aSPeter Maydell * the values of the APR registers might become incorrect and the 30672889c8aSPeter Maydell * running priority will be wrong, so interrupts that should preempt 30772889c8aSPeter Maydell * might not do so, and interrupts that should not preempt might do so. 30872889c8aSPeter Maydell */ 30972889c8aSPeter Maydell int i; 31072889c8aSPeter Maydell 31172889c8aSPeter Maydell for (i = 0; i < GIC_NR_APRS; i++) { 31272889c8aSPeter Maydell uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu]; 31372889c8aSPeter Maydell if (!*papr) { 31472889c8aSPeter Maydell continue; 31572889c8aSPeter Maydell } 31672889c8aSPeter Maydell /* Clear lowest set bit */ 31772889c8aSPeter Maydell *papr &= *papr - 1; 31872889c8aSPeter Maydell break; 31972889c8aSPeter Maydell } 32072889c8aSPeter Maydell 32172889c8aSPeter Maydell s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu); 322e69954b9Spbrook } 323e69954b9Spbrook 324c5619bf9SFabian Aggeler uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) 325e69954b9Spbrook { 32640d22500SChristoffer Dall int ret, irq, src; 3279ee6e8bbSpbrook int cm = 1 << cpu; 328c5619bf9SFabian Aggeler 329c5619bf9SFabian Aggeler /* gic_get_current_pending_irq() will return 1022 or 1023 appropriately 330c5619bf9SFabian Aggeler * for the case where this GIC supports grouping and the pending interrupt 331c5619bf9SFabian Aggeler * is in the wrong group. 332c5619bf9SFabian Aggeler */ 333a8f15a27SDaniel P. Berrange irq = gic_get_current_pending_irq(s, cpu, attrs); 334c5619bf9SFabian Aggeler 335c5619bf9SFabian Aggeler if (irq >= GIC_MAXIRQ) { 336c5619bf9SFabian Aggeler DPRINTF("ACK, no pending interrupt or it is hidden: %d\n", irq); 337c5619bf9SFabian Aggeler return irq; 338c5619bf9SFabian Aggeler } 339c5619bf9SFabian Aggeler 340c5619bf9SFabian Aggeler if (GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) { 341c5619bf9SFabian Aggeler DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq); 342e69954b9Spbrook return 1023; 343e69954b9Spbrook } 34440d22500SChristoffer Dall 34587316902SPeter Maydell if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 3469ee6e8bbSpbrook /* Clear pending flags for both level and edge triggered interrupts. 34740d22500SChristoffer Dall * Level triggered IRQs will be reasserted once they become inactive. 34840d22500SChristoffer Dall */ 34940d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 35040d22500SChristoffer Dall ret = irq; 35140d22500SChristoffer Dall } else { 35240d22500SChristoffer Dall if (irq < GIC_NR_SGIS) { 35340d22500SChristoffer Dall /* Lookup the source CPU for the SGI and clear this in the 35440d22500SChristoffer Dall * sgi_pending map. Return the src and clear the overall pending 35540d22500SChristoffer Dall * state on this CPU if the SGI is not pending from any CPUs. 35640d22500SChristoffer Dall */ 35740d22500SChristoffer Dall assert(s->sgi_pending[irq][cpu] != 0); 35840d22500SChristoffer Dall src = ctz32(s->sgi_pending[irq][cpu]); 35940d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~(1 << src); 36040d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 36140d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 36240d22500SChristoffer Dall } 36340d22500SChristoffer Dall ret = irq | ((src & 0x7) << 10); 36440d22500SChristoffer Dall } else { 36540d22500SChristoffer Dall /* Clear pending state for both level and edge triggered 36640d22500SChristoffer Dall * interrupts. (level triggered interrupts with an active line 36740d22500SChristoffer Dall * remain pending, see gic_test_pending) 36840d22500SChristoffer Dall */ 36940d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 37040d22500SChristoffer Dall ret = irq; 37140d22500SChristoffer Dall } 37240d22500SChristoffer Dall } 37340d22500SChristoffer Dall 37472889c8aSPeter Maydell gic_activate_irq(s, cpu, irq); 37572889c8aSPeter Maydell gic_update(s); 37640d22500SChristoffer Dall DPRINTF("ACK %d\n", irq); 37740d22500SChristoffer Dall return ret; 378e69954b9Spbrook } 379e69954b9Spbrook 38081508470SFabian Aggeler void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val, 38181508470SFabian Aggeler MemTxAttrs attrs) 3829df90ad0SChristoffer Dall { 38381508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 38481508470SFabian Aggeler if (!GIC_TEST_GROUP(irq, (1 << cpu))) { 38581508470SFabian Aggeler return; /* Ignore Non-secure access of Group0 IRQ */ 38681508470SFabian Aggeler } 38781508470SFabian Aggeler val = 0x80 | (val >> 1); /* Non-secure view */ 38881508470SFabian Aggeler } 38981508470SFabian Aggeler 3909df90ad0SChristoffer Dall if (irq < GIC_INTERNAL) { 3919df90ad0SChristoffer Dall s->priority1[irq][cpu] = val; 3929df90ad0SChristoffer Dall } else { 3939df90ad0SChristoffer Dall s->priority2[(irq) - GIC_INTERNAL] = val; 3949df90ad0SChristoffer Dall } 3959df90ad0SChristoffer Dall } 3969df90ad0SChristoffer Dall 39781508470SFabian Aggeler static uint32_t gic_get_priority(GICState *s, int cpu, int irq, 39881508470SFabian Aggeler MemTxAttrs attrs) 39981508470SFabian Aggeler { 40081508470SFabian Aggeler uint32_t prio = GIC_GET_PRIORITY(irq, cpu); 40181508470SFabian Aggeler 40281508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 40381508470SFabian Aggeler if (!GIC_TEST_GROUP(irq, (1 << cpu))) { 40481508470SFabian Aggeler return 0; /* Non-secure access cannot read priority of Group0 IRQ */ 40581508470SFabian Aggeler } 40681508470SFabian Aggeler prio = (prio << 1) & 0xff; /* Non-secure view */ 40781508470SFabian Aggeler } 40881508470SFabian Aggeler return prio; 40981508470SFabian Aggeler } 41081508470SFabian Aggeler 41181508470SFabian Aggeler static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask, 41281508470SFabian Aggeler MemTxAttrs attrs) 41381508470SFabian Aggeler { 41481508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 41581508470SFabian Aggeler if (s->priority_mask[cpu] & 0x80) { 41681508470SFabian Aggeler /* Priority Mask in upper half */ 41781508470SFabian Aggeler pmask = 0x80 | (pmask >> 1); 41881508470SFabian Aggeler } else { 41981508470SFabian Aggeler /* Non-secure write ignored if priority mask is in lower half */ 42081508470SFabian Aggeler return; 42181508470SFabian Aggeler } 42281508470SFabian Aggeler } 42381508470SFabian Aggeler s->priority_mask[cpu] = pmask; 42481508470SFabian Aggeler } 42581508470SFabian Aggeler 42681508470SFabian Aggeler static uint32_t gic_get_priority_mask(GICState *s, int cpu, MemTxAttrs attrs) 42781508470SFabian Aggeler { 42881508470SFabian Aggeler uint32_t pmask = s->priority_mask[cpu]; 42981508470SFabian Aggeler 43081508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 43181508470SFabian Aggeler if (pmask & 0x80) { 43281508470SFabian Aggeler /* Priority Mask in upper half, return Non-secure view */ 43381508470SFabian Aggeler pmask = (pmask << 1) & 0xff; 43481508470SFabian Aggeler } else { 43581508470SFabian Aggeler /* Priority Mask in lower half, RAZ */ 43681508470SFabian Aggeler pmask = 0; 43781508470SFabian Aggeler } 43881508470SFabian Aggeler } 43981508470SFabian Aggeler return pmask; 44081508470SFabian Aggeler } 44181508470SFabian Aggeler 44232951860SFabian Aggeler static uint32_t gic_get_cpu_control(GICState *s, int cpu, MemTxAttrs attrs) 44332951860SFabian Aggeler { 44432951860SFabian Aggeler uint32_t ret = s->cpu_ctlr[cpu]; 44532951860SFabian Aggeler 44632951860SFabian Aggeler if (s->security_extn && !attrs.secure) { 44732951860SFabian Aggeler /* Construct the NS banked view of GICC_CTLR from the correct 44832951860SFabian Aggeler * bits of the S banked view. We don't need to move the bypass 44932951860SFabian Aggeler * control bits because we don't implement that (IMPDEF) part 45032951860SFabian Aggeler * of the GIC architecture. 45132951860SFabian Aggeler */ 45232951860SFabian Aggeler ret = (ret & (GICC_CTLR_EN_GRP1 | GICC_CTLR_EOIMODE_NS)) >> 1; 45332951860SFabian Aggeler } 45432951860SFabian Aggeler return ret; 45532951860SFabian Aggeler } 45632951860SFabian Aggeler 45732951860SFabian Aggeler static void gic_set_cpu_control(GICState *s, int cpu, uint32_t value, 45832951860SFabian Aggeler MemTxAttrs attrs) 45932951860SFabian Aggeler { 46032951860SFabian Aggeler uint32_t mask; 46132951860SFabian Aggeler 46232951860SFabian Aggeler if (s->security_extn && !attrs.secure) { 46332951860SFabian Aggeler /* The NS view can only write certain bits in the register; 46432951860SFabian Aggeler * the rest are unchanged 46532951860SFabian Aggeler */ 46632951860SFabian Aggeler mask = GICC_CTLR_EN_GRP1; 46732951860SFabian Aggeler if (s->revision == 2) { 46832951860SFabian Aggeler mask |= GICC_CTLR_EOIMODE_NS; 46932951860SFabian Aggeler } 47032951860SFabian Aggeler s->cpu_ctlr[cpu] &= ~mask; 47132951860SFabian Aggeler s->cpu_ctlr[cpu] |= (value << 1) & mask; 47232951860SFabian Aggeler } else { 47332951860SFabian Aggeler if (s->revision == 2) { 47432951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V2_S_MASK : GICC_CTLR_V2_MASK; 47532951860SFabian Aggeler } else { 47632951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V1_S_MASK : GICC_CTLR_V1_MASK; 47732951860SFabian Aggeler } 47832951860SFabian Aggeler s->cpu_ctlr[cpu] = value & mask; 47932951860SFabian Aggeler } 48032951860SFabian Aggeler DPRINTF("CPU Interface %d: Group0 Interrupts %sabled, " 48132951860SFabian Aggeler "Group1 Interrupts %sabled\n", cpu, 48232951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP0) ? "En" : "Dis", 48332951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP1) ? "En" : "Dis"); 48432951860SFabian Aggeler } 48532951860SFabian Aggeler 48608efa9f2SFabian Aggeler static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs) 48708efa9f2SFabian Aggeler { 48808efa9f2SFabian Aggeler if (s->security_extn && !attrs.secure) { 48908efa9f2SFabian Aggeler if (s->running_priority[cpu] & 0x80) { 49008efa9f2SFabian Aggeler /* Running priority in upper half of range: return the Non-secure 49108efa9f2SFabian Aggeler * view of the priority. 49208efa9f2SFabian Aggeler */ 49308efa9f2SFabian Aggeler return s->running_priority[cpu] << 1; 49408efa9f2SFabian Aggeler } else { 49508efa9f2SFabian Aggeler /* Running priority in lower half of range: RAZ */ 49608efa9f2SFabian Aggeler return 0; 49708efa9f2SFabian Aggeler } 49808efa9f2SFabian Aggeler } else { 49908efa9f2SFabian Aggeler return s->running_priority[cpu]; 50008efa9f2SFabian Aggeler } 50108efa9f2SFabian Aggeler } 50208efa9f2SFabian Aggeler 503*a55c910eSPeter Maydell /* Return true if we should split priority drop and interrupt deactivation, 504*a55c910eSPeter Maydell * ie whether the relevant EOIMode bit is set. 505*a55c910eSPeter Maydell */ 506*a55c910eSPeter Maydell static bool gic_eoi_split(GICState *s, int cpu, MemTxAttrs attrs) 507*a55c910eSPeter Maydell { 508*a55c910eSPeter Maydell if (s->revision != 2) { 509*a55c910eSPeter Maydell /* Before GICv2 prio-drop and deactivate are not separable */ 510*a55c910eSPeter Maydell return false; 511*a55c910eSPeter Maydell } 512*a55c910eSPeter Maydell if (s->security_extn && !attrs.secure) { 513*a55c910eSPeter Maydell return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE_NS; 514*a55c910eSPeter Maydell } 515*a55c910eSPeter Maydell return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE; 516*a55c910eSPeter Maydell } 517*a55c910eSPeter Maydell 518*a55c910eSPeter Maydell static void gic_deactivate_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) 519*a55c910eSPeter Maydell { 520*a55c910eSPeter Maydell int cm = 1 << cpu; 521*a55c910eSPeter Maydell int group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm); 522*a55c910eSPeter Maydell 523*a55c910eSPeter Maydell if (!gic_eoi_split(s, cpu, attrs)) { 524*a55c910eSPeter Maydell /* This is UNPREDICTABLE; we choose to ignore it */ 525*a55c910eSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 526*a55c910eSPeter Maydell "gic_deactivate_irq: GICC_DIR write when EOIMode clear"); 527*a55c910eSPeter Maydell return; 528*a55c910eSPeter Maydell } 529*a55c910eSPeter Maydell 530*a55c910eSPeter Maydell if (s->security_extn && !attrs.secure && !group) { 531*a55c910eSPeter Maydell DPRINTF("Non-secure DI for Group0 interrupt %d ignored\n", irq); 532*a55c910eSPeter Maydell return; 533*a55c910eSPeter Maydell } 534*a55c910eSPeter Maydell 535*a55c910eSPeter Maydell GIC_CLEAR_ACTIVE(irq, cm); 536*a55c910eSPeter Maydell } 537*a55c910eSPeter Maydell 538f9c6a7f1SFabian Aggeler void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) 539e69954b9Spbrook { 5409ee6e8bbSpbrook int cm = 1 << cpu; 54172889c8aSPeter Maydell int group; 54272889c8aSPeter Maydell 543df628ff1Spbrook DPRINTF("EOI %d\n", irq); 544a32134aaSMark Langsdorf if (irq >= s->num_irq) { 545217bfb44SPeter Maydell /* This handles two cases: 546217bfb44SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 547217bfb44SPeter Maydell * to the GICC_EOIR, the GIC ignores that write. 548217bfb44SPeter Maydell * 2. If software writes the number of a non-existent interrupt 549217bfb44SPeter Maydell * this must be a subcase of "value written does not match the last 550217bfb44SPeter Maydell * valid interrupt value read from the Interrupt Acknowledge 551217bfb44SPeter Maydell * register" and so this is UNPREDICTABLE. We choose to ignore it. 552217bfb44SPeter Maydell */ 553217bfb44SPeter Maydell return; 554217bfb44SPeter Maydell } 55572889c8aSPeter Maydell if (s->running_priority[cpu] == 0x100) { 556e69954b9Spbrook return; /* No active IRQ. */ 55772889c8aSPeter Maydell } 5588d999995SChristoffer Dall 5598d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 560e69954b9Spbrook /* Mark level triggered interrupts as pending if they are still 561e69954b9Spbrook raised. */ 56204050c5cSChristoffer Dall if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm) 5639ee6e8bbSpbrook && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) { 5649ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq, cm); 5659ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 566e69954b9Spbrook } 5678d999995SChristoffer Dall } 5688d999995SChristoffer Dall 56972889c8aSPeter Maydell group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm); 57072889c8aSPeter Maydell 57172889c8aSPeter Maydell if (s->security_extn && !attrs.secure && !group) { 572f9c6a7f1SFabian Aggeler DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq); 573f9c6a7f1SFabian Aggeler return; 574f9c6a7f1SFabian Aggeler } 575f9c6a7f1SFabian Aggeler 576f9c6a7f1SFabian Aggeler /* Secure EOI with GICC_CTLR.AckCtl == 0 when the IRQ is a Group 1 577f9c6a7f1SFabian Aggeler * interrupt is UNPREDICTABLE. We choose to handle it as if AckCtl == 1, 578f9c6a7f1SFabian Aggeler * i.e. go ahead and complete the irq anyway. 579f9c6a7f1SFabian Aggeler */ 580f9c6a7f1SFabian Aggeler 58172889c8aSPeter Maydell gic_drop_prio(s, cpu, group); 582*a55c910eSPeter Maydell 583*a55c910eSPeter Maydell /* In GICv2 the guest can choose to split priority-drop and deactivate */ 584*a55c910eSPeter Maydell if (!gic_eoi_split(s, cpu, attrs)) { 585d5523a13SPeter Maydell GIC_CLEAR_ACTIVE(irq, cm); 586*a55c910eSPeter Maydell } 587e69954b9Spbrook gic_update(s); 588e69954b9Spbrook } 589e69954b9Spbrook 590a9d85353SPeter Maydell static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) 591e69954b9Spbrook { 592fae15286SPeter Maydell GICState *s = (GICState *)opaque; 593e69954b9Spbrook uint32_t res; 594e69954b9Spbrook int irq; 595e69954b9Spbrook int i; 5969ee6e8bbSpbrook int cpu; 5979ee6e8bbSpbrook int cm; 5989ee6e8bbSpbrook int mask; 599e69954b9Spbrook 600926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 6019ee6e8bbSpbrook cm = 1 << cpu; 602e69954b9Spbrook if (offset < 0x100) { 603679aa175SFabian Aggeler if (offset == 0) { /* GICD_CTLR */ 604679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 605679aa175SFabian Aggeler /* The NS bank of this register is just an alias of the 606679aa175SFabian Aggeler * EnableGrp1 bit in the S bank version. 607679aa175SFabian Aggeler */ 608679aa175SFabian Aggeler return extract32(s->ctlr, 1, 1); 609679aa175SFabian Aggeler } else { 610679aa175SFabian Aggeler return s->ctlr; 611679aa175SFabian Aggeler } 612679aa175SFabian Aggeler } 613e69954b9Spbrook if (offset == 4) 6145543d1abSFabian Aggeler /* Interrupt Controller Type Register */ 6155543d1abSFabian Aggeler return ((s->num_irq / 32) - 1) 616b95690c9SWei Huang | ((s->num_cpu - 1) << 5) 6175543d1abSFabian Aggeler | (s->security_extn << 10); 618e69954b9Spbrook if (offset < 0x08) 619e69954b9Spbrook return 0; 620b79f2265SRob Herring if (offset >= 0x80) { 621c27a5ba9SFabian Aggeler /* Interrupt Group Registers: these RAZ/WI if this is an NS 622c27a5ba9SFabian Aggeler * access to a GIC with the security extensions, or if the GIC 623c27a5ba9SFabian Aggeler * doesn't have groups at all. 624c27a5ba9SFabian Aggeler */ 625c27a5ba9SFabian Aggeler res = 0; 626c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 627c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 628c27a5ba9SFabian Aggeler irq = (offset - 0x080) * 8 + GIC_BASE_IRQ; 629c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 630c27a5ba9SFabian Aggeler goto bad_reg; 631c27a5ba9SFabian Aggeler } 632c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 633c27a5ba9SFabian Aggeler if (GIC_TEST_GROUP(irq + i, cm)) { 634c27a5ba9SFabian Aggeler res |= (1 << i); 635c27a5ba9SFabian Aggeler } 636c27a5ba9SFabian Aggeler } 637c27a5ba9SFabian Aggeler } 638c27a5ba9SFabian Aggeler return res; 639b79f2265SRob Herring } 640e69954b9Spbrook goto bad_reg; 641e69954b9Spbrook } else if (offset < 0x200) { 642e69954b9Spbrook /* Interrupt Set/Clear Enable. */ 643e69954b9Spbrook if (offset < 0x180) 644e69954b9Spbrook irq = (offset - 0x100) * 8; 645e69954b9Spbrook else 646e69954b9Spbrook irq = (offset - 0x180) * 8; 6479ee6e8bbSpbrook irq += GIC_BASE_IRQ; 648a32134aaSMark Langsdorf if (irq >= s->num_irq) 649e69954b9Spbrook goto bad_reg; 650e69954b9Spbrook res = 0; 651e69954b9Spbrook for (i = 0; i < 8; i++) { 65241bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 653e69954b9Spbrook res |= (1 << i); 654e69954b9Spbrook } 655e69954b9Spbrook } 656e69954b9Spbrook } else if (offset < 0x300) { 657e69954b9Spbrook /* Interrupt Set/Clear Pending. */ 658e69954b9Spbrook if (offset < 0x280) 659e69954b9Spbrook irq = (offset - 0x200) * 8; 660e69954b9Spbrook else 661e69954b9Spbrook irq = (offset - 0x280) * 8; 6629ee6e8bbSpbrook irq += GIC_BASE_IRQ; 663a32134aaSMark Langsdorf if (irq >= s->num_irq) 664e69954b9Spbrook goto bad_reg; 665e69954b9Spbrook res = 0; 66669253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 667e69954b9Spbrook for (i = 0; i < 8; i++) { 6688d999995SChristoffer Dall if (gic_test_pending(s, irq + i, mask)) { 669e69954b9Spbrook res |= (1 << i); 670e69954b9Spbrook } 671e69954b9Spbrook } 672e69954b9Spbrook } else if (offset < 0x400) { 673e69954b9Spbrook /* Interrupt Active. */ 6749ee6e8bbSpbrook irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 675a32134aaSMark Langsdorf if (irq >= s->num_irq) 676e69954b9Spbrook goto bad_reg; 677e69954b9Spbrook res = 0; 67869253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 679e69954b9Spbrook for (i = 0; i < 8; i++) { 6809ee6e8bbSpbrook if (GIC_TEST_ACTIVE(irq + i, mask)) { 681e69954b9Spbrook res |= (1 << i); 682e69954b9Spbrook } 683e69954b9Spbrook } 684e69954b9Spbrook } else if (offset < 0x800) { 685e69954b9Spbrook /* Interrupt Priority. */ 6869ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 687a32134aaSMark Langsdorf if (irq >= s->num_irq) 688e69954b9Spbrook goto bad_reg; 68981508470SFabian Aggeler res = gic_get_priority(s, cpu, irq, attrs); 690e69954b9Spbrook } else if (offset < 0xc00) { 691e69954b9Spbrook /* Interrupt CPU Target. */ 6926b9680bbSPeter Maydell if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { 6936b9680bbSPeter Maydell /* For uniprocessor GICs these RAZ/WI */ 6946b9680bbSPeter Maydell res = 0; 6956b9680bbSPeter Maydell } else { 6969ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 6976b9680bbSPeter Maydell if (irq >= s->num_irq) { 698e69954b9Spbrook goto bad_reg; 6996b9680bbSPeter Maydell } 7009ee6e8bbSpbrook if (irq >= 29 && irq <= 31) { 7019ee6e8bbSpbrook res = cm; 7029ee6e8bbSpbrook } else { 7039ee6e8bbSpbrook res = GIC_TARGET(irq); 7049ee6e8bbSpbrook } 7056b9680bbSPeter Maydell } 706e69954b9Spbrook } else if (offset < 0xf00) { 707e69954b9Spbrook /* Interrupt Configuration. */ 70871a62046SAdam Lackorzynski irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 709a32134aaSMark Langsdorf if (irq >= s->num_irq) 710e69954b9Spbrook goto bad_reg; 711e69954b9Spbrook res = 0; 712e69954b9Spbrook for (i = 0; i < 4; i++) { 713e69954b9Spbrook if (GIC_TEST_MODEL(irq + i)) 714e69954b9Spbrook res |= (1 << (i * 2)); 71504050c5cSChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq + i)) 716e69954b9Spbrook res |= (2 << (i * 2)); 717e69954b9Spbrook } 71840d22500SChristoffer Dall } else if (offset < 0xf10) { 71940d22500SChristoffer Dall goto bad_reg; 72040d22500SChristoffer Dall } else if (offset < 0xf30) { 72140d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 72240d22500SChristoffer Dall goto bad_reg; 72340d22500SChristoffer Dall } 72440d22500SChristoffer Dall 72540d22500SChristoffer Dall if (offset < 0xf20) { 72640d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 72740d22500SChristoffer Dall irq = (offset - 0xf10); 72840d22500SChristoffer Dall } else { 72940d22500SChristoffer Dall irq = (offset - 0xf20); 73040d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 73140d22500SChristoffer Dall } 73240d22500SChristoffer Dall 73340d22500SChristoffer Dall res = s->sgi_pending[irq][cpu]; 7343355c360SAlistair Francis } else if (offset < 0xfd0) { 735e69954b9Spbrook goto bad_reg; 7363355c360SAlistair Francis } else if (offset < 0x1000) { 737e69954b9Spbrook if (offset & 3) { 738e69954b9Spbrook res = 0; 739e69954b9Spbrook } else { 7403355c360SAlistair Francis switch (s->revision) { 7413355c360SAlistair Francis case REV_11MPCORE: 7423355c360SAlistair Francis res = gic_id_11mpcore[(offset - 0xfd0) >> 2]; 7433355c360SAlistair Francis break; 7443355c360SAlistair Francis case 1: 7453355c360SAlistair Francis res = gic_id_gicv1[(offset - 0xfd0) >> 2]; 7463355c360SAlistair Francis break; 7473355c360SAlistair Francis case 2: 7483355c360SAlistair Francis res = gic_id_gicv2[(offset - 0xfd0) >> 2]; 7493355c360SAlistair Francis break; 7503355c360SAlistair Francis case REV_NVIC: 7513355c360SAlistair Francis /* Shouldn't be able to get here */ 7523355c360SAlistair Francis abort(); 7533355c360SAlistair Francis default: 7543355c360SAlistair Francis res = 0; 755e69954b9Spbrook } 756e69954b9Spbrook } 7573355c360SAlistair Francis } else { 7583355c360SAlistair Francis g_assert_not_reached(); 7593355c360SAlistair Francis } 760e69954b9Spbrook return res; 761e69954b9Spbrook bad_reg: 7628c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 7638c8dc39fSPeter Maydell "gic_dist_readb: Bad offset %x\n", (int)offset); 764e69954b9Spbrook return 0; 765e69954b9Spbrook } 766e69954b9Spbrook 767a9d85353SPeter Maydell static MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data, 768a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 769e69954b9Spbrook { 770a9d85353SPeter Maydell switch (size) { 771a9d85353SPeter Maydell case 1: 772a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 773a9d85353SPeter Maydell return MEMTX_OK; 774a9d85353SPeter Maydell case 2: 775a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 776a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 777a9d85353SPeter Maydell return MEMTX_OK; 778a9d85353SPeter Maydell case 4: 779a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 780a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 781a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 2, attrs) << 16; 782a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 3, attrs) << 24; 783a9d85353SPeter Maydell return MEMTX_OK; 784a9d85353SPeter Maydell default: 785a9d85353SPeter Maydell return MEMTX_ERROR; 786e69954b9Spbrook } 787e69954b9Spbrook } 788e69954b9Spbrook 789a8170e5eSAvi Kivity static void gic_dist_writeb(void *opaque, hwaddr offset, 790a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 791e69954b9Spbrook { 792fae15286SPeter Maydell GICState *s = (GICState *)opaque; 793e69954b9Spbrook int irq; 794e69954b9Spbrook int i; 7959ee6e8bbSpbrook int cpu; 796e69954b9Spbrook 797926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 798e69954b9Spbrook if (offset < 0x100) { 799e69954b9Spbrook if (offset == 0) { 800679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 801679aa175SFabian Aggeler /* NS version is just an alias of the S version's bit 1 */ 802679aa175SFabian Aggeler s->ctlr = deposit32(s->ctlr, 1, 1, value); 803679aa175SFabian Aggeler } else if (gic_has_groups(s)) { 804679aa175SFabian Aggeler s->ctlr = value & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1); 805679aa175SFabian Aggeler } else { 806679aa175SFabian Aggeler s->ctlr = value & GICD_CTLR_EN_GRP0; 807679aa175SFabian Aggeler } 808679aa175SFabian Aggeler DPRINTF("Distributor: Group0 %sabled; Group 1 %sabled\n", 809679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP0 ? "En" : "Dis", 810679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP1 ? "En" : "Dis"); 811e69954b9Spbrook } else if (offset < 4) { 812e69954b9Spbrook /* ignored. */ 813b79f2265SRob Herring } else if (offset >= 0x80) { 814c27a5ba9SFabian Aggeler /* Interrupt Group Registers: RAZ/WI for NS access to secure 815c27a5ba9SFabian Aggeler * GIC, or for GICs without groups. 816c27a5ba9SFabian Aggeler */ 817c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 818c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 819c27a5ba9SFabian Aggeler irq = (offset - 0x80) * 8 + GIC_BASE_IRQ; 820c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 821c27a5ba9SFabian Aggeler goto bad_reg; 822c27a5ba9SFabian Aggeler } 823c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 824c27a5ba9SFabian Aggeler /* Group bits are banked for private interrupts */ 825c27a5ba9SFabian Aggeler int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 826c27a5ba9SFabian Aggeler if (value & (1 << i)) { 827c27a5ba9SFabian Aggeler /* Group1 (Non-secure) */ 828c27a5ba9SFabian Aggeler GIC_SET_GROUP(irq + i, cm); 829c27a5ba9SFabian Aggeler } else { 830c27a5ba9SFabian Aggeler /* Group0 (Secure) */ 831c27a5ba9SFabian Aggeler GIC_CLEAR_GROUP(irq + i, cm); 832c27a5ba9SFabian Aggeler } 833c27a5ba9SFabian Aggeler } 834c27a5ba9SFabian Aggeler } 835e69954b9Spbrook } else { 836e69954b9Spbrook goto bad_reg; 837e69954b9Spbrook } 838e69954b9Spbrook } else if (offset < 0x180) { 839e69954b9Spbrook /* Interrupt Set Enable. */ 8409ee6e8bbSpbrook irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 841a32134aaSMark Langsdorf if (irq >= s->num_irq) 842e69954b9Spbrook goto bad_reg; 84341ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 8449ee6e8bbSpbrook value = 0xff; 84541ab7b55SChristoffer Dall } 84641ab7b55SChristoffer Dall 847e69954b9Spbrook for (i = 0; i < 8; i++) { 848e69954b9Spbrook if (value & (1 << i)) { 849f47b48fbSDaniel Sangorrin int mask = 850f47b48fbSDaniel Sangorrin (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i); 85169253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 85241bf234dSRabin Vincent 85341bf234dSRabin Vincent if (!GIC_TEST_ENABLED(irq + i, cm)) { 854e69954b9Spbrook DPRINTF("Enabled IRQ %d\n", irq + i); 85541bf234dSRabin Vincent } 85641bf234dSRabin Vincent GIC_SET_ENABLED(irq + i, cm); 857e69954b9Spbrook /* If a raised level triggered IRQ enabled then mark 858e69954b9Spbrook is as pending. */ 8599ee6e8bbSpbrook if (GIC_TEST_LEVEL(irq + i, mask) 86004050c5cSChristoffer Dall && !GIC_TEST_EDGE_TRIGGER(irq + i)) { 8619ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq + i, mask); 8629ee6e8bbSpbrook GIC_SET_PENDING(irq + i, mask); 8639ee6e8bbSpbrook } 864e69954b9Spbrook } 865e69954b9Spbrook } 866e69954b9Spbrook } else if (offset < 0x200) { 867e69954b9Spbrook /* Interrupt Clear Enable. */ 8689ee6e8bbSpbrook irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 869a32134aaSMark Langsdorf if (irq >= s->num_irq) 870e69954b9Spbrook goto bad_reg; 87141ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 8729ee6e8bbSpbrook value = 0; 87341ab7b55SChristoffer Dall } 87441ab7b55SChristoffer Dall 875e69954b9Spbrook for (i = 0; i < 8; i++) { 876e69954b9Spbrook if (value & (1 << i)) { 87769253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 87841bf234dSRabin Vincent 87941bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 880e69954b9Spbrook DPRINTF("Disabled IRQ %d\n", irq + i); 88141bf234dSRabin Vincent } 88241bf234dSRabin Vincent GIC_CLEAR_ENABLED(irq + i, cm); 883e69954b9Spbrook } 884e69954b9Spbrook } 885e69954b9Spbrook } else if (offset < 0x280) { 886e69954b9Spbrook /* Interrupt Set Pending. */ 8879ee6e8bbSpbrook irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 888a32134aaSMark Langsdorf if (irq >= s->num_irq) 889e69954b9Spbrook goto bad_reg; 89041ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 8915b0adce1SChristoffer Dall value = 0; 89241ab7b55SChristoffer Dall } 8939ee6e8bbSpbrook 894e69954b9Spbrook for (i = 0; i < 8; i++) { 895e69954b9Spbrook if (value & (1 << i)) { 896f47b48fbSDaniel Sangorrin GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); 897e69954b9Spbrook } 898e69954b9Spbrook } 899e69954b9Spbrook } else if (offset < 0x300) { 900e69954b9Spbrook /* Interrupt Clear Pending. */ 9019ee6e8bbSpbrook irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 902a32134aaSMark Langsdorf if (irq >= s->num_irq) 903e69954b9Spbrook goto bad_reg; 9045b0adce1SChristoffer Dall if (irq < GIC_NR_SGIS) { 9055b0adce1SChristoffer Dall value = 0; 9065b0adce1SChristoffer Dall } 9075b0adce1SChristoffer Dall 908e69954b9Spbrook for (i = 0; i < 8; i++) { 9099ee6e8bbSpbrook /* ??? This currently clears the pending bit for all CPUs, even 9109ee6e8bbSpbrook for per-CPU interrupts. It's unclear whether this is the 9119ee6e8bbSpbrook corect behavior. */ 912e69954b9Spbrook if (value & (1 << i)) { 9139ee6e8bbSpbrook GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 914e69954b9Spbrook } 915e69954b9Spbrook } 916e69954b9Spbrook } else if (offset < 0x400) { 917e69954b9Spbrook /* Interrupt Active. */ 918e69954b9Spbrook goto bad_reg; 919e69954b9Spbrook } else if (offset < 0x800) { 920e69954b9Spbrook /* Interrupt Priority. */ 9219ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 922a32134aaSMark Langsdorf if (irq >= s->num_irq) 923e69954b9Spbrook goto bad_reg; 92481508470SFabian Aggeler gic_set_priority(s, cpu, irq, value, attrs); 925e69954b9Spbrook } else if (offset < 0xc00) { 9266b9680bbSPeter Maydell /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the 9276b9680bbSPeter Maydell * annoying exception of the 11MPCore's GIC. 9286b9680bbSPeter Maydell */ 9296b9680bbSPeter Maydell if (s->num_cpu != 1 || s->revision == REV_11MPCORE) { 9309ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 9316b9680bbSPeter Maydell if (irq >= s->num_irq) { 932e69954b9Spbrook goto bad_reg; 9336b9680bbSPeter Maydell } 9346b9680bbSPeter Maydell if (irq < 29) { 9359ee6e8bbSpbrook value = 0; 9366b9680bbSPeter Maydell } else if (irq < GIC_INTERNAL) { 9379ee6e8bbSpbrook value = ALL_CPU_MASK; 9386b9680bbSPeter Maydell } 9399ee6e8bbSpbrook s->irq_target[irq] = value & ALL_CPU_MASK; 9406b9680bbSPeter Maydell } 941e69954b9Spbrook } else if (offset < 0xf00) { 942e69954b9Spbrook /* Interrupt Configuration. */ 9439ee6e8bbSpbrook irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 944a32134aaSMark Langsdorf if (irq >= s->num_irq) 945e69954b9Spbrook goto bad_reg; 946de7a900fSAdam Lackorzynski if (irq < GIC_NR_SGIS) 9479ee6e8bbSpbrook value |= 0xaa; 948e69954b9Spbrook for (i = 0; i < 4; i++) { 94924b790dfSAdam Lackorzynski if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 950e69954b9Spbrook if (value & (1 << (i * 2))) { 951e69954b9Spbrook GIC_SET_MODEL(irq + i); 952e69954b9Spbrook } else { 953e69954b9Spbrook GIC_CLEAR_MODEL(irq + i); 954e69954b9Spbrook } 95524b790dfSAdam Lackorzynski } 956e69954b9Spbrook if (value & (2 << (i * 2))) { 95704050c5cSChristoffer Dall GIC_SET_EDGE_TRIGGER(irq + i); 958e69954b9Spbrook } else { 95904050c5cSChristoffer Dall GIC_CLEAR_EDGE_TRIGGER(irq + i); 960e69954b9Spbrook } 961e69954b9Spbrook } 96240d22500SChristoffer Dall } else if (offset < 0xf10) { 9639ee6e8bbSpbrook /* 0xf00 is only handled for 32-bit writes. */ 964e69954b9Spbrook goto bad_reg; 96540d22500SChristoffer Dall } else if (offset < 0xf20) { 96640d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 96740d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 96840d22500SChristoffer Dall goto bad_reg; 96940d22500SChristoffer Dall } 97040d22500SChristoffer Dall irq = (offset - 0xf10); 97140d22500SChristoffer Dall 97240d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~value; 97340d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 97440d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, 1 << cpu); 97540d22500SChristoffer Dall } 97640d22500SChristoffer Dall } else if (offset < 0xf30) { 97740d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 97840d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 97940d22500SChristoffer Dall goto bad_reg; 98040d22500SChristoffer Dall } 98140d22500SChristoffer Dall irq = (offset - 0xf20); 98240d22500SChristoffer Dall 98340d22500SChristoffer Dall GIC_SET_PENDING(irq, 1 << cpu); 98440d22500SChristoffer Dall s->sgi_pending[irq][cpu] |= value; 98540d22500SChristoffer Dall } else { 98640d22500SChristoffer Dall goto bad_reg; 987e69954b9Spbrook } 988e69954b9Spbrook gic_update(s); 989e69954b9Spbrook return; 990e69954b9Spbrook bad_reg: 9918c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 9928c8dc39fSPeter Maydell "gic_dist_writeb: Bad offset %x\n", (int)offset); 993e69954b9Spbrook } 994e69954b9Spbrook 995a8170e5eSAvi Kivity static void gic_dist_writew(void *opaque, hwaddr offset, 996a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 997e69954b9Spbrook { 998a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, value & 0xff, attrs); 999a9d85353SPeter Maydell gic_dist_writeb(opaque, offset + 1, value >> 8, attrs); 1000e69954b9Spbrook } 1001e69954b9Spbrook 1002a8170e5eSAvi Kivity static void gic_dist_writel(void *opaque, hwaddr offset, 1003a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1004e69954b9Spbrook { 1005fae15286SPeter Maydell GICState *s = (GICState *)opaque; 10068da3ff18Spbrook if (offset == 0xf00) { 10079ee6e8bbSpbrook int cpu; 10089ee6e8bbSpbrook int irq; 10099ee6e8bbSpbrook int mask; 101040d22500SChristoffer Dall int target_cpu; 10119ee6e8bbSpbrook 1012926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 10139ee6e8bbSpbrook irq = value & 0x3ff; 10149ee6e8bbSpbrook switch ((value >> 24) & 3) { 10159ee6e8bbSpbrook case 0: 10169ee6e8bbSpbrook mask = (value >> 16) & ALL_CPU_MASK; 10179ee6e8bbSpbrook break; 10189ee6e8bbSpbrook case 1: 1019fa250144SAdam Lackorzynski mask = ALL_CPU_MASK ^ (1 << cpu); 10209ee6e8bbSpbrook break; 10219ee6e8bbSpbrook case 2: 1022fa250144SAdam Lackorzynski mask = 1 << cpu; 10239ee6e8bbSpbrook break; 10249ee6e8bbSpbrook default: 10259ee6e8bbSpbrook DPRINTF("Bad Soft Int target filter\n"); 10269ee6e8bbSpbrook mask = ALL_CPU_MASK; 10279ee6e8bbSpbrook break; 10289ee6e8bbSpbrook } 10299ee6e8bbSpbrook GIC_SET_PENDING(irq, mask); 103040d22500SChristoffer Dall target_cpu = ctz32(mask); 103140d22500SChristoffer Dall while (target_cpu < GIC_NCPU) { 103240d22500SChristoffer Dall s->sgi_pending[irq][target_cpu] |= (1 << cpu); 103340d22500SChristoffer Dall mask &= ~(1 << target_cpu); 103440d22500SChristoffer Dall target_cpu = ctz32(mask); 103540d22500SChristoffer Dall } 10369ee6e8bbSpbrook gic_update(s); 10379ee6e8bbSpbrook return; 10389ee6e8bbSpbrook } 1039a9d85353SPeter Maydell gic_dist_writew(opaque, offset, value & 0xffff, attrs); 1040a9d85353SPeter Maydell gic_dist_writew(opaque, offset + 2, value >> 16, attrs); 1041a9d85353SPeter Maydell } 1042a9d85353SPeter Maydell 1043a9d85353SPeter Maydell static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data, 1044a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1045a9d85353SPeter Maydell { 1046a9d85353SPeter Maydell switch (size) { 1047a9d85353SPeter Maydell case 1: 1048a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, data, attrs); 1049a9d85353SPeter Maydell return MEMTX_OK; 1050a9d85353SPeter Maydell case 2: 1051a9d85353SPeter Maydell gic_dist_writew(opaque, offset, data, attrs); 1052a9d85353SPeter Maydell return MEMTX_OK; 1053a9d85353SPeter Maydell case 4: 1054a9d85353SPeter Maydell gic_dist_writel(opaque, offset, data, attrs); 1055a9d85353SPeter Maydell return MEMTX_OK; 1056a9d85353SPeter Maydell default: 1057a9d85353SPeter Maydell return MEMTX_ERROR; 1058a9d85353SPeter Maydell } 1059e69954b9Spbrook } 1060e69954b9Spbrook 106151fd06e0SPeter Maydell static inline uint32_t gic_apr_ns_view(GICState *s, int cpu, int regno) 106251fd06e0SPeter Maydell { 106351fd06e0SPeter Maydell /* Return the Nonsecure view of GICC_APR<regno>. This is the 106451fd06e0SPeter Maydell * second half of GICC_NSAPR. 106551fd06e0SPeter Maydell */ 106651fd06e0SPeter Maydell switch (GIC_MIN_BPR) { 106751fd06e0SPeter Maydell case 0: 106851fd06e0SPeter Maydell if (regno < 2) { 106951fd06e0SPeter Maydell return s->nsapr[regno + 2][cpu]; 107051fd06e0SPeter Maydell } 107151fd06e0SPeter Maydell break; 107251fd06e0SPeter Maydell case 1: 107351fd06e0SPeter Maydell if (regno == 0) { 107451fd06e0SPeter Maydell return s->nsapr[regno + 1][cpu]; 107551fd06e0SPeter Maydell } 107651fd06e0SPeter Maydell break; 107751fd06e0SPeter Maydell case 2: 107851fd06e0SPeter Maydell if (regno == 0) { 107951fd06e0SPeter Maydell return extract32(s->nsapr[0][cpu], 16, 16); 108051fd06e0SPeter Maydell } 108151fd06e0SPeter Maydell break; 108251fd06e0SPeter Maydell case 3: 108351fd06e0SPeter Maydell if (regno == 0) { 108451fd06e0SPeter Maydell return extract32(s->nsapr[0][cpu], 8, 8); 108551fd06e0SPeter Maydell } 108651fd06e0SPeter Maydell break; 108751fd06e0SPeter Maydell default: 108851fd06e0SPeter Maydell g_assert_not_reached(); 108951fd06e0SPeter Maydell } 109051fd06e0SPeter Maydell return 0; 109151fd06e0SPeter Maydell } 109251fd06e0SPeter Maydell 109351fd06e0SPeter Maydell static inline void gic_apr_write_ns_view(GICState *s, int cpu, int regno, 109451fd06e0SPeter Maydell uint32_t value) 109551fd06e0SPeter Maydell { 109651fd06e0SPeter Maydell /* Write the Nonsecure view of GICC_APR<regno>. */ 109751fd06e0SPeter Maydell switch (GIC_MIN_BPR) { 109851fd06e0SPeter Maydell case 0: 109951fd06e0SPeter Maydell if (regno < 2) { 110051fd06e0SPeter Maydell s->nsapr[regno + 2][cpu] = value; 110151fd06e0SPeter Maydell } 110251fd06e0SPeter Maydell break; 110351fd06e0SPeter Maydell case 1: 110451fd06e0SPeter Maydell if (regno == 0) { 110551fd06e0SPeter Maydell s->nsapr[regno + 1][cpu] = value; 110651fd06e0SPeter Maydell } 110751fd06e0SPeter Maydell break; 110851fd06e0SPeter Maydell case 2: 110951fd06e0SPeter Maydell if (regno == 0) { 111051fd06e0SPeter Maydell s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 16, 16, value); 111151fd06e0SPeter Maydell } 111251fd06e0SPeter Maydell break; 111351fd06e0SPeter Maydell case 3: 111451fd06e0SPeter Maydell if (regno == 0) { 111551fd06e0SPeter Maydell s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 8, 8, value); 111651fd06e0SPeter Maydell } 111751fd06e0SPeter Maydell break; 111851fd06e0SPeter Maydell default: 111951fd06e0SPeter Maydell g_assert_not_reached(); 112051fd06e0SPeter Maydell } 112151fd06e0SPeter Maydell } 112251fd06e0SPeter Maydell 1123a9d85353SPeter Maydell static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, 1124a9d85353SPeter Maydell uint64_t *data, MemTxAttrs attrs) 1125e69954b9Spbrook { 1126e69954b9Spbrook switch (offset) { 1127e69954b9Spbrook case 0x00: /* Control */ 112832951860SFabian Aggeler *data = gic_get_cpu_control(s, cpu, attrs); 1129a9d85353SPeter Maydell break; 1130e69954b9Spbrook case 0x04: /* Priority mask */ 113181508470SFabian Aggeler *data = gic_get_priority_mask(s, cpu, attrs); 1132a9d85353SPeter Maydell break; 1133e69954b9Spbrook case 0x08: /* Binary Point */ 1134822e9cc3SFabian Aggeler if (s->security_extn && !attrs.secure) { 1135822e9cc3SFabian Aggeler /* BPR is banked. Non-secure copy stored in ABPR. */ 1136822e9cc3SFabian Aggeler *data = s->abpr[cpu]; 1137822e9cc3SFabian Aggeler } else { 1138a9d85353SPeter Maydell *data = s->bpr[cpu]; 1139822e9cc3SFabian Aggeler } 1140a9d85353SPeter Maydell break; 1141e69954b9Spbrook case 0x0c: /* Acknowledge */ 1142c5619bf9SFabian Aggeler *data = gic_acknowledge_irq(s, cpu, attrs); 1143a9d85353SPeter Maydell break; 114466a0a2cbSDong Xu Wang case 0x14: /* Running Priority */ 114508efa9f2SFabian Aggeler *data = gic_get_running_priority(s, cpu, attrs); 1146a9d85353SPeter Maydell break; 1147e69954b9Spbrook case 0x18: /* Highest Pending Interrupt */ 11487c0fa108SFabian Aggeler *data = gic_get_current_pending_irq(s, cpu, attrs); 1149a9d85353SPeter Maydell break; 1150aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 1151822e9cc3SFabian Aggeler /* GIC v2, no security: ABPR 1152822e9cc3SFabian Aggeler * GIC v1, no security: not implemented (RAZ/WI) 1153822e9cc3SFabian Aggeler * With security extensions, secure access: ABPR (alias of NS BPR) 1154822e9cc3SFabian Aggeler * With security extensions, nonsecure access: RAZ/WI 1155822e9cc3SFabian Aggeler */ 1156822e9cc3SFabian Aggeler if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 1157822e9cc3SFabian Aggeler *data = 0; 1158822e9cc3SFabian Aggeler } else { 1159a9d85353SPeter Maydell *data = s->abpr[cpu]; 1160822e9cc3SFabian Aggeler } 1161a9d85353SPeter Maydell break; 1162a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 116351fd06e0SPeter Maydell { 116451fd06e0SPeter Maydell int regno = (offset - 0xd0) / 4; 116551fd06e0SPeter Maydell 116651fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 116751fd06e0SPeter Maydell *data = 0; 116851fd06e0SPeter Maydell } else if (s->security_extn && !attrs.secure) { 116951fd06e0SPeter Maydell /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ 117051fd06e0SPeter Maydell *data = gic_apr_ns_view(s, regno, cpu); 117151fd06e0SPeter Maydell } else { 117251fd06e0SPeter Maydell *data = s->apr[regno][cpu]; 117351fd06e0SPeter Maydell } 1174a9d85353SPeter Maydell break; 117551fd06e0SPeter Maydell } 117651fd06e0SPeter Maydell case 0xe0: case 0xe4: case 0xe8: case 0xec: 117751fd06e0SPeter Maydell { 117851fd06e0SPeter Maydell int regno = (offset - 0xe0) / 4; 117951fd06e0SPeter Maydell 118051fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2 || !gic_has_groups(s) || 118151fd06e0SPeter Maydell (s->security_extn && !attrs.secure)) { 118251fd06e0SPeter Maydell *data = 0; 118351fd06e0SPeter Maydell } else { 118451fd06e0SPeter Maydell *data = s->nsapr[regno][cpu]; 118551fd06e0SPeter Maydell } 118651fd06e0SPeter Maydell break; 118751fd06e0SPeter Maydell } 1188e69954b9Spbrook default: 11898c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 11908c8dc39fSPeter Maydell "gic_cpu_read: Bad offset %x\n", (int)offset); 1191a9d85353SPeter Maydell return MEMTX_ERROR; 1192e69954b9Spbrook } 1193a9d85353SPeter Maydell return MEMTX_OK; 1194e69954b9Spbrook } 1195e69954b9Spbrook 1196a9d85353SPeter Maydell static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, 1197a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1198e69954b9Spbrook { 1199e69954b9Spbrook switch (offset) { 1200e69954b9Spbrook case 0x00: /* Control */ 120132951860SFabian Aggeler gic_set_cpu_control(s, cpu, value, attrs); 1202e69954b9Spbrook break; 1203e69954b9Spbrook case 0x04: /* Priority mask */ 120481508470SFabian Aggeler gic_set_priority_mask(s, cpu, value, attrs); 1205e69954b9Spbrook break; 1206e69954b9Spbrook case 0x08: /* Binary Point */ 1207822e9cc3SFabian Aggeler if (s->security_extn && !attrs.secure) { 1208822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1209822e9cc3SFabian Aggeler } else { 1210822e9cc3SFabian Aggeler s->bpr[cpu] = MAX(value & 0x7, GIC_MIN_BPR); 1211822e9cc3SFabian Aggeler } 1212e69954b9Spbrook break; 1213e69954b9Spbrook case 0x10: /* End Of Interrupt */ 1214f9c6a7f1SFabian Aggeler gic_complete_irq(s, cpu, value & 0x3ff, attrs); 1215a9d85353SPeter Maydell return MEMTX_OK; 1216aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 1217822e9cc3SFabian Aggeler if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 1218822e9cc3SFabian Aggeler /* unimplemented, or NS access: RAZ/WI */ 1219822e9cc3SFabian Aggeler return MEMTX_OK; 1220822e9cc3SFabian Aggeler } else { 1221822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1222aa7d461aSChristoffer Dall } 1223aa7d461aSChristoffer Dall break; 1224a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 122551fd06e0SPeter Maydell { 122651fd06e0SPeter Maydell int regno = (offset - 0xd0) / 4; 122751fd06e0SPeter Maydell 122851fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 122951fd06e0SPeter Maydell return MEMTX_OK; 123051fd06e0SPeter Maydell } 123151fd06e0SPeter Maydell if (s->security_extn && !attrs.secure) { 123251fd06e0SPeter Maydell /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ 123351fd06e0SPeter Maydell gic_apr_write_ns_view(s, regno, cpu, value); 123451fd06e0SPeter Maydell } else { 123551fd06e0SPeter Maydell s->apr[regno][cpu] = value; 123651fd06e0SPeter Maydell } 1237a9d477c4SChristoffer Dall break; 123851fd06e0SPeter Maydell } 123951fd06e0SPeter Maydell case 0xe0: case 0xe4: case 0xe8: case 0xec: 124051fd06e0SPeter Maydell { 124151fd06e0SPeter Maydell int regno = (offset - 0xe0) / 4; 124251fd06e0SPeter Maydell 124351fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 124451fd06e0SPeter Maydell return MEMTX_OK; 124551fd06e0SPeter Maydell } 124651fd06e0SPeter Maydell if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 124751fd06e0SPeter Maydell return MEMTX_OK; 124851fd06e0SPeter Maydell } 124951fd06e0SPeter Maydell s->nsapr[regno][cpu] = value; 125051fd06e0SPeter Maydell break; 125151fd06e0SPeter Maydell } 1252*a55c910eSPeter Maydell case 0x1000: 1253*a55c910eSPeter Maydell /* GICC_DIR */ 1254*a55c910eSPeter Maydell gic_deactivate_irq(s, cpu, value & 0x3ff, attrs); 1255*a55c910eSPeter Maydell break; 1256e69954b9Spbrook default: 12578c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 12588c8dc39fSPeter Maydell "gic_cpu_write: Bad offset %x\n", (int)offset); 1259a9d85353SPeter Maydell return MEMTX_ERROR; 1260e69954b9Spbrook } 1261e69954b9Spbrook gic_update(s); 1262a9d85353SPeter Maydell return MEMTX_OK; 1263e69954b9Spbrook } 1264e2c56465SPeter Maydell 1265e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for the current CPU */ 1266a9d85353SPeter Maydell static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data, 1267a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1268e2c56465SPeter Maydell { 1269fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1270a9d85353SPeter Maydell return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs); 1271e2c56465SPeter Maydell } 1272e2c56465SPeter Maydell 1273a9d85353SPeter Maydell static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr, 1274a9d85353SPeter Maydell uint64_t value, unsigned size, 1275a9d85353SPeter Maydell MemTxAttrs attrs) 1276e2c56465SPeter Maydell { 1277fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1278a9d85353SPeter Maydell return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs); 1279e2c56465SPeter Maydell } 1280e2c56465SPeter Maydell 1281e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for a specific CPU. 1282fae15286SPeter Maydell * These just decode the opaque pointer into GICState* + cpu id. 1283e2c56465SPeter Maydell */ 1284a9d85353SPeter Maydell static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data, 1285a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1286e2c56465SPeter Maydell { 1287fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1288fae15286SPeter Maydell GICState *s = *backref; 1289e2c56465SPeter Maydell int id = (backref - s->backref); 1290a9d85353SPeter Maydell return gic_cpu_read(s, id, addr, data, attrs); 1291e2c56465SPeter Maydell } 1292e2c56465SPeter Maydell 1293a9d85353SPeter Maydell static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr, 1294a9d85353SPeter Maydell uint64_t value, unsigned size, 1295a9d85353SPeter Maydell MemTxAttrs attrs) 1296e2c56465SPeter Maydell { 1297fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1298fae15286SPeter Maydell GICState *s = *backref; 1299e2c56465SPeter Maydell int id = (backref - s->backref); 1300a9d85353SPeter Maydell return gic_cpu_write(s, id, addr, value, attrs); 1301e2c56465SPeter Maydell } 1302e2c56465SPeter Maydell 13037926c210SPavel Fedin static const MemoryRegionOps gic_ops[2] = { 13047926c210SPavel Fedin { 13057926c210SPavel Fedin .read_with_attrs = gic_dist_read, 13067926c210SPavel Fedin .write_with_attrs = gic_dist_write, 13077926c210SPavel Fedin .endianness = DEVICE_NATIVE_ENDIAN, 13087926c210SPavel Fedin }, 13097926c210SPavel Fedin { 1310a9d85353SPeter Maydell .read_with_attrs = gic_thiscpu_read, 1311a9d85353SPeter Maydell .write_with_attrs = gic_thiscpu_write, 1312e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 13137926c210SPavel Fedin } 1314e2c56465SPeter Maydell }; 1315e2c56465SPeter Maydell 1316e2c56465SPeter Maydell static const MemoryRegionOps gic_cpu_ops = { 1317a9d85353SPeter Maydell .read_with_attrs = gic_do_cpu_read, 1318a9d85353SPeter Maydell .write_with_attrs = gic_do_cpu_write, 1319e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 1320e2c56465SPeter Maydell }; 1321e69954b9Spbrook 13227926c210SPavel Fedin /* This function is used by nvic model */ 13237b95a508SKONRAD Frederic void gic_init_irqs_and_distributor(GICState *s) 1324e69954b9Spbrook { 13257926c210SPavel Fedin gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); 13262b518c56SPeter Maydell } 13272b518c56SPeter Maydell 132853111180SPeter Maydell static void arm_gic_realize(DeviceState *dev, Error **errp) 13292b518c56SPeter Maydell { 133053111180SPeter Maydell /* Device instance realize function for the GIC sysbus device */ 13312b518c56SPeter Maydell int i; 133253111180SPeter Maydell GICState *s = ARM_GIC(dev); 133353111180SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 13341e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_GET_CLASS(s); 13350175ba10SMarkus Armbruster Error *local_err = NULL; 13361e8cae4dSPeter Maydell 13370175ba10SMarkus Armbruster agc->parent_realize(dev, &local_err); 13380175ba10SMarkus Armbruster if (local_err) { 13390175ba10SMarkus Armbruster error_propagate(errp, local_err); 134053111180SPeter Maydell return; 134153111180SPeter Maydell } 13421e8cae4dSPeter Maydell 13437926c210SPavel Fedin /* This creates distributor and main CPU interface (s->cpuiomem[0]) */ 13447926c210SPavel Fedin gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); 13452b518c56SPeter Maydell 13467926c210SPavel Fedin /* Extra core-specific regions for the CPU interfaces. This is 13477926c210SPavel Fedin * necessary for "franken-GIC" implementations, for example on 13487926c210SPavel Fedin * Exynos 4. 1349e2c56465SPeter Maydell * NB that the memory region size of 0x100 applies for the 11MPCore 1350e2c56465SPeter Maydell * and also cores following the GIC v1 spec (ie A9). 1351e2c56465SPeter Maydell * GIC v2 defines a larger memory region (0x1000) so this will need 1352e2c56465SPeter Maydell * to be extended when we implement A15. 1353e2c56465SPeter Maydell */ 1354b95690c9SWei Huang for (i = 0; i < s->num_cpu; i++) { 1355e2c56465SPeter Maydell s->backref[i] = s; 13561437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, 13571437c94bSPaolo Bonzini &s->backref[i], "gic_cpu", 0x100); 13587926c210SPavel Fedin sysbus_init_mmio(sbd, &s->cpuiomem[i+1]); 1359496dbcd1SPeter Maydell } 1360496dbcd1SPeter Maydell } 1361496dbcd1SPeter Maydell 1362496dbcd1SPeter Maydell static void arm_gic_class_init(ObjectClass *klass, void *data) 1363496dbcd1SPeter Maydell { 1364496dbcd1SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 13651e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_CLASS(klass); 136653111180SPeter Maydell 136753111180SPeter Maydell agc->parent_realize = dc->realize; 136853111180SPeter Maydell dc->realize = arm_gic_realize; 1369496dbcd1SPeter Maydell } 1370496dbcd1SPeter Maydell 13718c43a6f0SAndreas Färber static const TypeInfo arm_gic_info = { 13721e8cae4dSPeter Maydell .name = TYPE_ARM_GIC, 13731e8cae4dSPeter Maydell .parent = TYPE_ARM_GIC_COMMON, 1374fae15286SPeter Maydell .instance_size = sizeof(GICState), 1375496dbcd1SPeter Maydell .class_init = arm_gic_class_init, 1376998a74bcSPeter Maydell .class_size = sizeof(ARMGICClass), 1377496dbcd1SPeter Maydell }; 1378496dbcd1SPeter Maydell 1379496dbcd1SPeter Maydell static void arm_gic_register_types(void) 1380496dbcd1SPeter Maydell { 1381496dbcd1SPeter Maydell type_register_static(&arm_gic_info); 1382496dbcd1SPeter Maydell } 1383496dbcd1SPeter Maydell 1384496dbcd1SPeter Maydell type_init(arm_gic_register_types) 1385