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 2183c9f4caSPaolo Bonzini #include "hw/sysbus.h" 2247b43a1fSPaolo Bonzini #include "gic_internal.h" 23dfc08079SAndreas Färber #include "qom/cpu.h" 24386e2955SPeter Maydell 25e69954b9Spbrook //#define DEBUG_GIC 26e69954b9Spbrook 27e69954b9Spbrook #ifdef DEBUG_GIC 28001faf32SBlue Swirl #define DPRINTF(fmt, ...) \ 295eb98401SPeter A. G. Crosthwaite do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0) 30e69954b9Spbrook #else 31001faf32SBlue Swirl #define DPRINTF(fmt, ...) do {} while(0) 32e69954b9Spbrook #endif 33e69954b9Spbrook 342a29ddeeSPeter Maydell static const uint8_t gic_id[] = { 352a29ddeeSPeter Maydell 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 362a29ddeeSPeter Maydell }; 372a29ddeeSPeter Maydell 38c988bfadSPaul Brook #define NUM_CPU(s) ((s)->num_cpu) 399ee6e8bbSpbrook 40fae15286SPeter Maydell static inline int gic_get_current_cpu(GICState *s) 41926c4affSPeter Maydell { 42926c4affSPeter Maydell if (s->num_cpu > 1) { 434917cf44SAndreas Färber return current_cpu->cpu_index; 44926c4affSPeter Maydell } 45926c4affSPeter Maydell return 0; 46926c4affSPeter Maydell } 47926c4affSPeter Maydell 48c27a5ba9SFabian Aggeler /* Return true if this GIC config has interrupt groups, which is 49c27a5ba9SFabian Aggeler * true if we're a GICv2, or a GICv1 with the security extensions. 50c27a5ba9SFabian Aggeler */ 51c27a5ba9SFabian Aggeler static inline bool gic_has_groups(GICState *s) 52c27a5ba9SFabian Aggeler { 53c27a5ba9SFabian Aggeler return s->revision == 2 || s->security_extn; 54c27a5ba9SFabian Aggeler } 55c27a5ba9SFabian Aggeler 56e69954b9Spbrook /* TODO: Many places that call this routine could be optimized. */ 57e69954b9Spbrook /* Update interrupt status after enabled or pending bits have been changed. */ 58fae15286SPeter Maydell void gic_update(GICState *s) 59e69954b9Spbrook { 60e69954b9Spbrook int best_irq; 61e69954b9Spbrook int best_prio; 62e69954b9Spbrook int irq; 63dadbb58fSPeter Maydell int irq_level, fiq_level; 649ee6e8bbSpbrook int cpu; 659ee6e8bbSpbrook int cm; 66e69954b9Spbrook 67c988bfadSPaul Brook for (cpu = 0; cpu < NUM_CPU(s); cpu++) { 689ee6e8bbSpbrook cm = 1 << cpu; 699ee6e8bbSpbrook s->current_pending[cpu] = 1023; 70679aa175SFabian Aggeler if (!(s->ctlr & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1)) 7132951860SFabian Aggeler || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) { 729ee6e8bbSpbrook qemu_irq_lower(s->parent_irq[cpu]); 73dadbb58fSPeter Maydell qemu_irq_lower(s->parent_fiq[cpu]); 74235069a3SJohan Karlsson continue; 75e69954b9Spbrook } 76e69954b9Spbrook best_prio = 0x100; 77e69954b9Spbrook best_irq = 1023; 78a32134aaSMark Langsdorf for (irq = 0; irq < s->num_irq; irq++) { 79b52b81e4SSergey Fedorov if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm) && 80b52b81e4SSergey Fedorov (irq < GIC_INTERNAL || GIC_TARGET(irq) & cm)) { 819ee6e8bbSpbrook if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { 829ee6e8bbSpbrook best_prio = GIC_GET_PRIORITY(irq, cpu); 83e69954b9Spbrook best_irq = irq; 84e69954b9Spbrook } 85e69954b9Spbrook } 86e69954b9Spbrook } 87dadbb58fSPeter Maydell 88dadbb58fSPeter Maydell irq_level = fiq_level = 0; 89dadbb58fSPeter Maydell 90cad065f1SPeter Maydell if (best_prio < s->priority_mask[cpu]) { 919ee6e8bbSpbrook s->current_pending[cpu] = best_irq; 929ee6e8bbSpbrook if (best_prio < s->running_priority[cpu]) { 93dadbb58fSPeter Maydell int group = GIC_TEST_GROUP(best_irq, cm); 94dadbb58fSPeter Maydell 95dadbb58fSPeter Maydell if (extract32(s->ctlr, group, 1) && 96dadbb58fSPeter Maydell extract32(s->cpu_ctlr[cpu], group, 1)) { 97dadbb58fSPeter Maydell if (group == 0 && s->cpu_ctlr[cpu] & GICC_CTLR_FIQ_EN) { 98dadbb58fSPeter Maydell DPRINTF("Raised pending FIQ %d (cpu %d)\n", 99dadbb58fSPeter Maydell best_irq, cpu); 100dadbb58fSPeter Maydell fiq_level = 1; 101dadbb58fSPeter Maydell } else { 102dadbb58fSPeter Maydell DPRINTF("Raised pending IRQ %d (cpu %d)\n", 103dadbb58fSPeter Maydell best_irq, cpu); 104dadbb58fSPeter Maydell irq_level = 1; 105e69954b9Spbrook } 106e69954b9Spbrook } 107dadbb58fSPeter Maydell } 108dadbb58fSPeter Maydell } 109dadbb58fSPeter Maydell 110dadbb58fSPeter Maydell qemu_set_irq(s->parent_irq[cpu], irq_level); 111dadbb58fSPeter Maydell qemu_set_irq(s->parent_fiq[cpu], fiq_level); 1129ee6e8bbSpbrook } 113e69954b9Spbrook } 114e69954b9Spbrook 115fae15286SPeter Maydell void gic_set_pending_private(GICState *s, int cpu, int irq) 1169ee6e8bbSpbrook { 1179ee6e8bbSpbrook int cm = 1 << cpu; 1189ee6e8bbSpbrook 1198d999995SChristoffer Dall if (gic_test_pending(s, irq, cm)) { 1209ee6e8bbSpbrook return; 1218d999995SChristoffer Dall } 1229ee6e8bbSpbrook 1239ee6e8bbSpbrook DPRINTF("Set %d pending cpu %d\n", irq, cpu); 1249ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 1259ee6e8bbSpbrook gic_update(s); 1269ee6e8bbSpbrook } 1279ee6e8bbSpbrook 1288d999995SChristoffer Dall static void gic_set_irq_11mpcore(GICState *s, int irq, int level, 1298d999995SChristoffer Dall int cm, int target) 1308d999995SChristoffer Dall { 1318d999995SChristoffer Dall if (level) { 1328d999995SChristoffer Dall GIC_SET_LEVEL(irq, cm); 1338d999995SChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) { 1348d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 1358d999995SChristoffer Dall GIC_SET_PENDING(irq, target); 1368d999995SChristoffer Dall } 1378d999995SChristoffer Dall } else { 1388d999995SChristoffer Dall GIC_CLEAR_LEVEL(irq, cm); 1398d999995SChristoffer Dall } 1408d999995SChristoffer Dall } 1418d999995SChristoffer Dall 1428d999995SChristoffer Dall static void gic_set_irq_generic(GICState *s, int irq, int level, 1438d999995SChristoffer Dall int cm, int target) 1448d999995SChristoffer Dall { 1458d999995SChristoffer Dall if (level) { 1468d999995SChristoffer Dall GIC_SET_LEVEL(irq, cm); 1478d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 1488d999995SChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq)) { 1498d999995SChristoffer Dall GIC_SET_PENDING(irq, target); 1508d999995SChristoffer Dall } 1518d999995SChristoffer Dall } else { 1528d999995SChristoffer Dall GIC_CLEAR_LEVEL(irq, cm); 1538d999995SChristoffer Dall } 1548d999995SChristoffer Dall } 1558d999995SChristoffer Dall 1569ee6e8bbSpbrook /* Process a change in an external IRQ input. */ 157e69954b9Spbrook static void gic_set_irq(void *opaque, int irq, int level) 158e69954b9Spbrook { 159544d1afaSPeter Maydell /* Meaning of the 'irq' parameter: 160544d1afaSPeter Maydell * [0..N-1] : external interrupts 161544d1afaSPeter Maydell * [N..N+31] : PPI (internal) interrupts for CPU 0 162544d1afaSPeter Maydell * [N+32..N+63] : PPI (internal interrupts for CPU 1 163544d1afaSPeter Maydell * ... 164544d1afaSPeter Maydell */ 165fae15286SPeter Maydell GICState *s = (GICState *)opaque; 166544d1afaSPeter Maydell int cm, target; 167544d1afaSPeter Maydell if (irq < (s->num_irq - GIC_INTERNAL)) { 168e69954b9Spbrook /* The first external input line is internal interrupt 32. */ 169544d1afaSPeter Maydell cm = ALL_CPU_MASK; 17069253800SRusty Russell irq += GIC_INTERNAL; 171544d1afaSPeter Maydell target = GIC_TARGET(irq); 172544d1afaSPeter Maydell } else { 173544d1afaSPeter Maydell int cpu; 174544d1afaSPeter Maydell irq -= (s->num_irq - GIC_INTERNAL); 175544d1afaSPeter Maydell cpu = irq / GIC_INTERNAL; 176544d1afaSPeter Maydell irq %= GIC_INTERNAL; 177544d1afaSPeter Maydell cm = 1 << cpu; 178544d1afaSPeter Maydell target = cm; 179544d1afaSPeter Maydell } 180544d1afaSPeter Maydell 18140d22500SChristoffer Dall assert(irq >= GIC_NR_SGIS); 18240d22500SChristoffer Dall 183544d1afaSPeter Maydell if (level == GIC_TEST_LEVEL(irq, cm)) { 184e69954b9Spbrook return; 185544d1afaSPeter Maydell } 186e69954b9Spbrook 1878d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 1888d999995SChristoffer Dall gic_set_irq_11mpcore(s, irq, level, cm, target); 189e69954b9Spbrook } else { 1908d999995SChristoffer Dall gic_set_irq_generic(s, irq, level, cm, target); 191e69954b9Spbrook } 1928d999995SChristoffer Dall 193e69954b9Spbrook gic_update(s); 194e69954b9Spbrook } 195e69954b9Spbrook 1967c0fa108SFabian Aggeler static uint16_t gic_get_current_pending_irq(GICState *s, int cpu, 1977c0fa108SFabian Aggeler MemTxAttrs attrs) 1987c0fa108SFabian Aggeler { 1997c0fa108SFabian Aggeler uint16_t pending_irq = s->current_pending[cpu]; 2007c0fa108SFabian Aggeler 2017c0fa108SFabian Aggeler if (pending_irq < GIC_MAXIRQ && gic_has_groups(s)) { 2027c0fa108SFabian Aggeler int group = GIC_TEST_GROUP(pending_irq, (1 << cpu)); 2037c0fa108SFabian Aggeler /* On a GIC without the security extensions, reading this register 2047c0fa108SFabian Aggeler * behaves in the same way as a secure access to a GIC with them. 2057c0fa108SFabian Aggeler */ 2067c0fa108SFabian Aggeler bool secure = !s->security_extn || attrs.secure; 2077c0fa108SFabian Aggeler 2087c0fa108SFabian Aggeler if (group == 0 && !secure) { 2097c0fa108SFabian Aggeler /* Group0 interrupts hidden from Non-secure access */ 2107c0fa108SFabian Aggeler return 1023; 2117c0fa108SFabian Aggeler } 2127c0fa108SFabian Aggeler if (group == 1 && secure && !(s->cpu_ctlr[cpu] & GICC_CTLR_ACK_CTL)) { 2137c0fa108SFabian Aggeler /* Group1 interrupts only seen by Secure access if 2147c0fa108SFabian Aggeler * AckCtl bit set. 2157c0fa108SFabian Aggeler */ 2167c0fa108SFabian Aggeler return 1022; 2177c0fa108SFabian Aggeler } 2187c0fa108SFabian Aggeler } 2197c0fa108SFabian Aggeler return pending_irq; 2207c0fa108SFabian Aggeler } 2217c0fa108SFabian Aggeler 222df92cfa6SPeter Maydell static int gic_get_group_priority(GICState *s, int cpu, int irq) 223df92cfa6SPeter Maydell { 224df92cfa6SPeter Maydell /* Return the group priority of the specified interrupt 225df92cfa6SPeter Maydell * (which is the top bits of its priority, with the number 226df92cfa6SPeter Maydell * of bits masked determined by the applicable binary point register). 227df92cfa6SPeter Maydell */ 228df92cfa6SPeter Maydell int bpr; 229df92cfa6SPeter Maydell uint32_t mask; 230df92cfa6SPeter Maydell 231df92cfa6SPeter Maydell if (gic_has_groups(s) && 232df92cfa6SPeter Maydell !(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) && 233df92cfa6SPeter Maydell GIC_TEST_GROUP(irq, (1 << cpu))) { 234df92cfa6SPeter Maydell bpr = s->abpr[cpu]; 235df92cfa6SPeter Maydell } else { 236df92cfa6SPeter Maydell bpr = s->bpr[cpu]; 237df92cfa6SPeter Maydell } 238df92cfa6SPeter Maydell 239df92cfa6SPeter Maydell /* a BPR of 0 means the group priority bits are [7:1]; 240df92cfa6SPeter Maydell * a BPR of 1 means they are [7:2], and so on down to 241df92cfa6SPeter Maydell * a BPR of 7 meaning no group priority bits at all. 242df92cfa6SPeter Maydell */ 243df92cfa6SPeter Maydell mask = ~0U << ((bpr & 7) + 1); 244df92cfa6SPeter Maydell 245df92cfa6SPeter Maydell return GIC_GET_PRIORITY(irq, cpu) & mask; 246df92cfa6SPeter Maydell } 247df92cfa6SPeter Maydell 24872889c8aSPeter Maydell static void gic_activate_irq(GICState *s, int cpu, int irq) 249e69954b9Spbrook { 25072889c8aSPeter Maydell /* Set the appropriate Active Priority Register bit for this IRQ, 25172889c8aSPeter Maydell * and update the running priority. 25272889c8aSPeter Maydell */ 25372889c8aSPeter Maydell int prio = gic_get_group_priority(s, cpu, irq); 25472889c8aSPeter Maydell int preemption_level = prio >> (GIC_MIN_BPR + 1); 25572889c8aSPeter Maydell int regno = preemption_level / 32; 25672889c8aSPeter Maydell int bitno = preemption_level % 32; 25772889c8aSPeter Maydell 25872889c8aSPeter Maydell if (gic_has_groups(s) && GIC_TEST_GROUP(irq, (1 << cpu))) { 25972889c8aSPeter Maydell s->nsapr[regno][cpu] &= (1 << bitno); 2609ee6e8bbSpbrook } else { 26172889c8aSPeter Maydell s->apr[regno][cpu] &= (1 << bitno); 2629ee6e8bbSpbrook } 26372889c8aSPeter Maydell 26472889c8aSPeter Maydell s->running_priority[cpu] = prio; 265*d5523a13SPeter Maydell GIC_SET_ACTIVE(irq, 1 << cpu); 26672889c8aSPeter Maydell } 26772889c8aSPeter Maydell 26872889c8aSPeter Maydell static int gic_get_prio_from_apr_bits(GICState *s, int cpu) 26972889c8aSPeter Maydell { 27072889c8aSPeter Maydell /* Recalculate the current running priority for this CPU based 27172889c8aSPeter Maydell * on the set bits in the Active Priority Registers. 27272889c8aSPeter Maydell */ 27372889c8aSPeter Maydell int i; 27472889c8aSPeter Maydell for (i = 0; i < GIC_NR_APRS; i++) { 27572889c8aSPeter Maydell uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu]; 27672889c8aSPeter Maydell if (!apr) { 27772889c8aSPeter Maydell continue; 27872889c8aSPeter Maydell } 27972889c8aSPeter Maydell return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1); 28072889c8aSPeter Maydell } 28172889c8aSPeter Maydell return 0x100; 28272889c8aSPeter Maydell } 28372889c8aSPeter Maydell 28472889c8aSPeter Maydell static void gic_drop_prio(GICState *s, int cpu, int group) 28572889c8aSPeter Maydell { 28672889c8aSPeter Maydell /* Drop the priority of the currently active interrupt in the 28772889c8aSPeter Maydell * specified group. 28872889c8aSPeter Maydell * 28972889c8aSPeter Maydell * Note that we can guarantee (because of the requirement to nest 29072889c8aSPeter Maydell * GICC_IAR reads [which activate an interrupt and raise priority] 29172889c8aSPeter Maydell * with GICC_EOIR writes [which drop the priority for the interrupt]) 29272889c8aSPeter Maydell * that the interrupt we're being called for is the highest priority 29372889c8aSPeter Maydell * active interrupt, meaning that it has the lowest set bit in the 29472889c8aSPeter Maydell * APR registers. 29572889c8aSPeter Maydell * 29672889c8aSPeter Maydell * If the guest does not honour the ordering constraints then the 29772889c8aSPeter Maydell * behaviour of the GIC is UNPREDICTABLE, which for us means that 29872889c8aSPeter Maydell * the values of the APR registers might become incorrect and the 29972889c8aSPeter Maydell * running priority will be wrong, so interrupts that should preempt 30072889c8aSPeter Maydell * might not do so, and interrupts that should not preempt might do so. 30172889c8aSPeter Maydell */ 30272889c8aSPeter Maydell int i; 30372889c8aSPeter Maydell 30472889c8aSPeter Maydell for (i = 0; i < GIC_NR_APRS; i++) { 30572889c8aSPeter Maydell uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu]; 30672889c8aSPeter Maydell if (!*papr) { 30772889c8aSPeter Maydell continue; 30872889c8aSPeter Maydell } 30972889c8aSPeter Maydell /* Clear lowest set bit */ 31072889c8aSPeter Maydell *papr &= *papr - 1; 31172889c8aSPeter Maydell break; 31272889c8aSPeter Maydell } 31372889c8aSPeter Maydell 31472889c8aSPeter Maydell s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu); 315e69954b9Spbrook } 316e69954b9Spbrook 317c5619bf9SFabian Aggeler uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) 318e69954b9Spbrook { 31940d22500SChristoffer Dall int ret, irq, src; 3209ee6e8bbSpbrook int cm = 1 << cpu; 321c5619bf9SFabian Aggeler 322c5619bf9SFabian Aggeler /* gic_get_current_pending_irq() will return 1022 or 1023 appropriately 323c5619bf9SFabian Aggeler * for the case where this GIC supports grouping and the pending interrupt 324c5619bf9SFabian Aggeler * is in the wrong group. 325c5619bf9SFabian Aggeler */ 326c5619bf9SFabian Aggeler irq = gic_get_current_pending_irq(s, cpu, attrs);; 327c5619bf9SFabian Aggeler 328c5619bf9SFabian Aggeler if (irq >= GIC_MAXIRQ) { 329c5619bf9SFabian Aggeler DPRINTF("ACK, no pending interrupt or it is hidden: %d\n", irq); 330c5619bf9SFabian Aggeler return irq; 331c5619bf9SFabian Aggeler } 332c5619bf9SFabian Aggeler 333c5619bf9SFabian Aggeler if (GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) { 334c5619bf9SFabian Aggeler DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq); 335e69954b9Spbrook return 1023; 336e69954b9Spbrook } 33740d22500SChristoffer Dall 33887316902SPeter Maydell if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 3399ee6e8bbSpbrook /* Clear pending flags for both level and edge triggered interrupts. 34040d22500SChristoffer Dall * Level triggered IRQs will be reasserted once they become inactive. 34140d22500SChristoffer Dall */ 34240d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 34340d22500SChristoffer Dall ret = irq; 34440d22500SChristoffer Dall } else { 34540d22500SChristoffer Dall if (irq < GIC_NR_SGIS) { 34640d22500SChristoffer Dall /* Lookup the source CPU for the SGI and clear this in the 34740d22500SChristoffer Dall * sgi_pending map. Return the src and clear the overall pending 34840d22500SChristoffer Dall * state on this CPU if the SGI is not pending from any CPUs. 34940d22500SChristoffer Dall */ 35040d22500SChristoffer Dall assert(s->sgi_pending[irq][cpu] != 0); 35140d22500SChristoffer Dall src = ctz32(s->sgi_pending[irq][cpu]); 35240d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~(1 << src); 35340d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 35440d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 35540d22500SChristoffer Dall } 35640d22500SChristoffer Dall ret = irq | ((src & 0x7) << 10); 35740d22500SChristoffer Dall } else { 35840d22500SChristoffer Dall /* Clear pending state for both level and edge triggered 35940d22500SChristoffer Dall * interrupts. (level triggered interrupts with an active line 36040d22500SChristoffer Dall * remain pending, see gic_test_pending) 36140d22500SChristoffer Dall */ 36240d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 36340d22500SChristoffer Dall ret = irq; 36440d22500SChristoffer Dall } 36540d22500SChristoffer Dall } 36640d22500SChristoffer Dall 36772889c8aSPeter Maydell gic_activate_irq(s, cpu, irq); 36872889c8aSPeter Maydell gic_update(s); 36940d22500SChristoffer Dall DPRINTF("ACK %d\n", irq); 37040d22500SChristoffer Dall return ret; 371e69954b9Spbrook } 372e69954b9Spbrook 37381508470SFabian Aggeler void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val, 37481508470SFabian Aggeler MemTxAttrs attrs) 3759df90ad0SChristoffer Dall { 37681508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 37781508470SFabian Aggeler if (!GIC_TEST_GROUP(irq, (1 << cpu))) { 37881508470SFabian Aggeler return; /* Ignore Non-secure access of Group0 IRQ */ 37981508470SFabian Aggeler } 38081508470SFabian Aggeler val = 0x80 | (val >> 1); /* Non-secure view */ 38181508470SFabian Aggeler } 38281508470SFabian Aggeler 3839df90ad0SChristoffer Dall if (irq < GIC_INTERNAL) { 3849df90ad0SChristoffer Dall s->priority1[irq][cpu] = val; 3859df90ad0SChristoffer Dall } else { 3869df90ad0SChristoffer Dall s->priority2[(irq) - GIC_INTERNAL] = val; 3879df90ad0SChristoffer Dall } 3889df90ad0SChristoffer Dall } 3899df90ad0SChristoffer Dall 39081508470SFabian Aggeler static uint32_t gic_get_priority(GICState *s, int cpu, int irq, 39181508470SFabian Aggeler MemTxAttrs attrs) 39281508470SFabian Aggeler { 39381508470SFabian Aggeler uint32_t prio = GIC_GET_PRIORITY(irq, cpu); 39481508470SFabian Aggeler 39581508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 39681508470SFabian Aggeler if (!GIC_TEST_GROUP(irq, (1 << cpu))) { 39781508470SFabian Aggeler return 0; /* Non-secure access cannot read priority of Group0 IRQ */ 39881508470SFabian Aggeler } 39981508470SFabian Aggeler prio = (prio << 1) & 0xff; /* Non-secure view */ 40081508470SFabian Aggeler } 40181508470SFabian Aggeler return prio; 40281508470SFabian Aggeler } 40381508470SFabian Aggeler 40481508470SFabian Aggeler static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask, 40581508470SFabian Aggeler MemTxAttrs attrs) 40681508470SFabian Aggeler { 40781508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 40881508470SFabian Aggeler if (s->priority_mask[cpu] & 0x80) { 40981508470SFabian Aggeler /* Priority Mask in upper half */ 41081508470SFabian Aggeler pmask = 0x80 | (pmask >> 1); 41181508470SFabian Aggeler } else { 41281508470SFabian Aggeler /* Non-secure write ignored if priority mask is in lower half */ 41381508470SFabian Aggeler return; 41481508470SFabian Aggeler } 41581508470SFabian Aggeler } 41681508470SFabian Aggeler s->priority_mask[cpu] = pmask; 41781508470SFabian Aggeler } 41881508470SFabian Aggeler 41981508470SFabian Aggeler static uint32_t gic_get_priority_mask(GICState *s, int cpu, MemTxAttrs attrs) 42081508470SFabian Aggeler { 42181508470SFabian Aggeler uint32_t pmask = s->priority_mask[cpu]; 42281508470SFabian Aggeler 42381508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 42481508470SFabian Aggeler if (pmask & 0x80) { 42581508470SFabian Aggeler /* Priority Mask in upper half, return Non-secure view */ 42681508470SFabian Aggeler pmask = (pmask << 1) & 0xff; 42781508470SFabian Aggeler } else { 42881508470SFabian Aggeler /* Priority Mask in lower half, RAZ */ 42981508470SFabian Aggeler pmask = 0; 43081508470SFabian Aggeler } 43181508470SFabian Aggeler } 43281508470SFabian Aggeler return pmask; 43381508470SFabian Aggeler } 43481508470SFabian Aggeler 43532951860SFabian Aggeler static uint32_t gic_get_cpu_control(GICState *s, int cpu, MemTxAttrs attrs) 43632951860SFabian Aggeler { 43732951860SFabian Aggeler uint32_t ret = s->cpu_ctlr[cpu]; 43832951860SFabian Aggeler 43932951860SFabian Aggeler if (s->security_extn && !attrs.secure) { 44032951860SFabian Aggeler /* Construct the NS banked view of GICC_CTLR from the correct 44132951860SFabian Aggeler * bits of the S banked view. We don't need to move the bypass 44232951860SFabian Aggeler * control bits because we don't implement that (IMPDEF) part 44332951860SFabian Aggeler * of the GIC architecture. 44432951860SFabian Aggeler */ 44532951860SFabian Aggeler ret = (ret & (GICC_CTLR_EN_GRP1 | GICC_CTLR_EOIMODE_NS)) >> 1; 44632951860SFabian Aggeler } 44732951860SFabian Aggeler return ret; 44832951860SFabian Aggeler } 44932951860SFabian Aggeler 45032951860SFabian Aggeler static void gic_set_cpu_control(GICState *s, int cpu, uint32_t value, 45132951860SFabian Aggeler MemTxAttrs attrs) 45232951860SFabian Aggeler { 45332951860SFabian Aggeler uint32_t mask; 45432951860SFabian Aggeler 45532951860SFabian Aggeler if (s->security_extn && !attrs.secure) { 45632951860SFabian Aggeler /* The NS view can only write certain bits in the register; 45732951860SFabian Aggeler * the rest are unchanged 45832951860SFabian Aggeler */ 45932951860SFabian Aggeler mask = GICC_CTLR_EN_GRP1; 46032951860SFabian Aggeler if (s->revision == 2) { 46132951860SFabian Aggeler mask |= GICC_CTLR_EOIMODE_NS; 46232951860SFabian Aggeler } 46332951860SFabian Aggeler s->cpu_ctlr[cpu] &= ~mask; 46432951860SFabian Aggeler s->cpu_ctlr[cpu] |= (value << 1) & mask; 46532951860SFabian Aggeler } else { 46632951860SFabian Aggeler if (s->revision == 2) { 46732951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V2_S_MASK : GICC_CTLR_V2_MASK; 46832951860SFabian Aggeler } else { 46932951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V1_S_MASK : GICC_CTLR_V1_MASK; 47032951860SFabian Aggeler } 47132951860SFabian Aggeler s->cpu_ctlr[cpu] = value & mask; 47232951860SFabian Aggeler } 47332951860SFabian Aggeler DPRINTF("CPU Interface %d: Group0 Interrupts %sabled, " 47432951860SFabian Aggeler "Group1 Interrupts %sabled\n", cpu, 47532951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP0) ? "En" : "Dis", 47632951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP1) ? "En" : "Dis"); 47732951860SFabian Aggeler } 47832951860SFabian Aggeler 47908efa9f2SFabian Aggeler static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs) 48008efa9f2SFabian Aggeler { 48108efa9f2SFabian Aggeler if (s->security_extn && !attrs.secure) { 48208efa9f2SFabian Aggeler if (s->running_priority[cpu] & 0x80) { 48308efa9f2SFabian Aggeler /* Running priority in upper half of range: return the Non-secure 48408efa9f2SFabian Aggeler * view of the priority. 48508efa9f2SFabian Aggeler */ 48608efa9f2SFabian Aggeler return s->running_priority[cpu] << 1; 48708efa9f2SFabian Aggeler } else { 48808efa9f2SFabian Aggeler /* Running priority in lower half of range: RAZ */ 48908efa9f2SFabian Aggeler return 0; 49008efa9f2SFabian Aggeler } 49108efa9f2SFabian Aggeler } else { 49208efa9f2SFabian Aggeler return s->running_priority[cpu]; 49308efa9f2SFabian Aggeler } 49408efa9f2SFabian Aggeler } 49508efa9f2SFabian Aggeler 496f9c6a7f1SFabian Aggeler void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) 497e69954b9Spbrook { 4989ee6e8bbSpbrook int cm = 1 << cpu; 49972889c8aSPeter Maydell int group; 50072889c8aSPeter Maydell 501df628ff1Spbrook DPRINTF("EOI %d\n", irq); 502a32134aaSMark Langsdorf if (irq >= s->num_irq) { 503217bfb44SPeter Maydell /* This handles two cases: 504217bfb44SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 505217bfb44SPeter Maydell * to the GICC_EOIR, the GIC ignores that write. 506217bfb44SPeter Maydell * 2. If software writes the number of a non-existent interrupt 507217bfb44SPeter Maydell * this must be a subcase of "value written does not match the last 508217bfb44SPeter Maydell * valid interrupt value read from the Interrupt Acknowledge 509217bfb44SPeter Maydell * register" and so this is UNPREDICTABLE. We choose to ignore it. 510217bfb44SPeter Maydell */ 511217bfb44SPeter Maydell return; 512217bfb44SPeter Maydell } 51372889c8aSPeter Maydell if (s->running_priority[cpu] == 0x100) { 514e69954b9Spbrook return; /* No active IRQ. */ 51572889c8aSPeter Maydell } 5168d999995SChristoffer Dall 5178d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 518e69954b9Spbrook /* Mark level triggered interrupts as pending if they are still 519e69954b9Spbrook raised. */ 52004050c5cSChristoffer Dall if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm) 5219ee6e8bbSpbrook && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) { 5229ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq, cm); 5239ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 524e69954b9Spbrook } 5258d999995SChristoffer Dall } 5268d999995SChristoffer Dall 52772889c8aSPeter Maydell group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm); 52872889c8aSPeter Maydell 52972889c8aSPeter Maydell if (s->security_extn && !attrs.secure && !group) { 530f9c6a7f1SFabian Aggeler DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq); 531f9c6a7f1SFabian Aggeler return; 532f9c6a7f1SFabian Aggeler } 533f9c6a7f1SFabian Aggeler 534f9c6a7f1SFabian Aggeler /* Secure EOI with GICC_CTLR.AckCtl == 0 when the IRQ is a Group 1 535f9c6a7f1SFabian Aggeler * interrupt is UNPREDICTABLE. We choose to handle it as if AckCtl == 1, 536f9c6a7f1SFabian Aggeler * i.e. go ahead and complete the irq anyway. 537f9c6a7f1SFabian Aggeler */ 538f9c6a7f1SFabian Aggeler 53972889c8aSPeter Maydell gic_drop_prio(s, cpu, group); 540*d5523a13SPeter Maydell GIC_CLEAR_ACTIVE(irq, cm); 541e69954b9Spbrook gic_update(s); 542e69954b9Spbrook } 543e69954b9Spbrook 544a9d85353SPeter Maydell static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) 545e69954b9Spbrook { 546fae15286SPeter Maydell GICState *s = (GICState *)opaque; 547e69954b9Spbrook uint32_t res; 548e69954b9Spbrook int irq; 549e69954b9Spbrook int i; 5509ee6e8bbSpbrook int cpu; 5519ee6e8bbSpbrook int cm; 5529ee6e8bbSpbrook int mask; 553e69954b9Spbrook 554926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 5559ee6e8bbSpbrook cm = 1 << cpu; 556e69954b9Spbrook if (offset < 0x100) { 557679aa175SFabian Aggeler if (offset == 0) { /* GICD_CTLR */ 558679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 559679aa175SFabian Aggeler /* The NS bank of this register is just an alias of the 560679aa175SFabian Aggeler * EnableGrp1 bit in the S bank version. 561679aa175SFabian Aggeler */ 562679aa175SFabian Aggeler return extract32(s->ctlr, 1, 1); 563679aa175SFabian Aggeler } else { 564679aa175SFabian Aggeler return s->ctlr; 565679aa175SFabian Aggeler } 566679aa175SFabian Aggeler } 567e69954b9Spbrook if (offset == 4) 5685543d1abSFabian Aggeler /* Interrupt Controller Type Register */ 5695543d1abSFabian Aggeler return ((s->num_irq / 32) - 1) 5705543d1abSFabian Aggeler | ((NUM_CPU(s) - 1) << 5) 5715543d1abSFabian Aggeler | (s->security_extn << 10); 572e69954b9Spbrook if (offset < 0x08) 573e69954b9Spbrook return 0; 574b79f2265SRob Herring if (offset >= 0x80) { 575c27a5ba9SFabian Aggeler /* Interrupt Group Registers: these RAZ/WI if this is an NS 576c27a5ba9SFabian Aggeler * access to a GIC with the security extensions, or if the GIC 577c27a5ba9SFabian Aggeler * doesn't have groups at all. 578c27a5ba9SFabian Aggeler */ 579c27a5ba9SFabian Aggeler res = 0; 580c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 581c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 582c27a5ba9SFabian Aggeler irq = (offset - 0x080) * 8 + GIC_BASE_IRQ; 583c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 584c27a5ba9SFabian Aggeler goto bad_reg; 585c27a5ba9SFabian Aggeler } 586c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 587c27a5ba9SFabian Aggeler if (GIC_TEST_GROUP(irq + i, cm)) { 588c27a5ba9SFabian Aggeler res |= (1 << i); 589c27a5ba9SFabian Aggeler } 590c27a5ba9SFabian Aggeler } 591c27a5ba9SFabian Aggeler } 592c27a5ba9SFabian Aggeler return res; 593b79f2265SRob Herring } 594e69954b9Spbrook goto bad_reg; 595e69954b9Spbrook } else if (offset < 0x200) { 596e69954b9Spbrook /* Interrupt Set/Clear Enable. */ 597e69954b9Spbrook if (offset < 0x180) 598e69954b9Spbrook irq = (offset - 0x100) * 8; 599e69954b9Spbrook else 600e69954b9Spbrook irq = (offset - 0x180) * 8; 6019ee6e8bbSpbrook irq += GIC_BASE_IRQ; 602a32134aaSMark Langsdorf if (irq >= s->num_irq) 603e69954b9Spbrook goto bad_reg; 604e69954b9Spbrook res = 0; 605e69954b9Spbrook for (i = 0; i < 8; i++) { 60641bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 607e69954b9Spbrook res |= (1 << i); 608e69954b9Spbrook } 609e69954b9Spbrook } 610e69954b9Spbrook } else if (offset < 0x300) { 611e69954b9Spbrook /* Interrupt Set/Clear Pending. */ 612e69954b9Spbrook if (offset < 0x280) 613e69954b9Spbrook irq = (offset - 0x200) * 8; 614e69954b9Spbrook else 615e69954b9Spbrook irq = (offset - 0x280) * 8; 6169ee6e8bbSpbrook irq += GIC_BASE_IRQ; 617a32134aaSMark Langsdorf if (irq >= s->num_irq) 618e69954b9Spbrook goto bad_reg; 619e69954b9Spbrook res = 0; 62069253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 621e69954b9Spbrook for (i = 0; i < 8; i++) { 6228d999995SChristoffer Dall if (gic_test_pending(s, irq + i, mask)) { 623e69954b9Spbrook res |= (1 << i); 624e69954b9Spbrook } 625e69954b9Spbrook } 626e69954b9Spbrook } else if (offset < 0x400) { 627e69954b9Spbrook /* Interrupt Active. */ 6289ee6e8bbSpbrook irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 629a32134aaSMark Langsdorf if (irq >= s->num_irq) 630e69954b9Spbrook goto bad_reg; 631e69954b9Spbrook res = 0; 63269253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 633e69954b9Spbrook for (i = 0; i < 8; i++) { 6349ee6e8bbSpbrook if (GIC_TEST_ACTIVE(irq + i, mask)) { 635e69954b9Spbrook res |= (1 << i); 636e69954b9Spbrook } 637e69954b9Spbrook } 638e69954b9Spbrook } else if (offset < 0x800) { 639e69954b9Spbrook /* Interrupt Priority. */ 6409ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 641a32134aaSMark Langsdorf if (irq >= s->num_irq) 642e69954b9Spbrook goto bad_reg; 64381508470SFabian Aggeler res = gic_get_priority(s, cpu, irq, attrs); 644e69954b9Spbrook } else if (offset < 0xc00) { 645e69954b9Spbrook /* Interrupt CPU Target. */ 6466b9680bbSPeter Maydell if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { 6476b9680bbSPeter Maydell /* For uniprocessor GICs these RAZ/WI */ 6486b9680bbSPeter Maydell res = 0; 6496b9680bbSPeter Maydell } else { 6509ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 6516b9680bbSPeter Maydell if (irq >= s->num_irq) { 652e69954b9Spbrook goto bad_reg; 6536b9680bbSPeter Maydell } 6549ee6e8bbSpbrook if (irq >= 29 && irq <= 31) { 6559ee6e8bbSpbrook res = cm; 6569ee6e8bbSpbrook } else { 6579ee6e8bbSpbrook res = GIC_TARGET(irq); 6589ee6e8bbSpbrook } 6596b9680bbSPeter Maydell } 660e69954b9Spbrook } else if (offset < 0xf00) { 661e69954b9Spbrook /* Interrupt Configuration. */ 66271a62046SAdam Lackorzynski irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 663a32134aaSMark Langsdorf if (irq >= s->num_irq) 664e69954b9Spbrook goto bad_reg; 665e69954b9Spbrook res = 0; 666e69954b9Spbrook for (i = 0; i < 4; i++) { 667e69954b9Spbrook if (GIC_TEST_MODEL(irq + i)) 668e69954b9Spbrook res |= (1 << (i * 2)); 66904050c5cSChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq + i)) 670e69954b9Spbrook res |= (2 << (i * 2)); 671e69954b9Spbrook } 67240d22500SChristoffer Dall } else if (offset < 0xf10) { 67340d22500SChristoffer Dall goto bad_reg; 67440d22500SChristoffer Dall } else if (offset < 0xf30) { 67540d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 67640d22500SChristoffer Dall goto bad_reg; 67740d22500SChristoffer Dall } 67840d22500SChristoffer Dall 67940d22500SChristoffer Dall if (offset < 0xf20) { 68040d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 68140d22500SChristoffer Dall irq = (offset - 0xf10); 68240d22500SChristoffer Dall } else { 68340d22500SChristoffer Dall irq = (offset - 0xf20); 68440d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 68540d22500SChristoffer Dall } 68640d22500SChristoffer Dall 68740d22500SChristoffer Dall res = s->sgi_pending[irq][cpu]; 688e69954b9Spbrook } else if (offset < 0xfe0) { 689e69954b9Spbrook goto bad_reg; 690e69954b9Spbrook } else /* offset >= 0xfe0 */ { 691e69954b9Spbrook if (offset & 3) { 692e69954b9Spbrook res = 0; 693e69954b9Spbrook } else { 694e69954b9Spbrook res = gic_id[(offset - 0xfe0) >> 2]; 695e69954b9Spbrook } 696e69954b9Spbrook } 697e69954b9Spbrook return res; 698e69954b9Spbrook bad_reg: 6998c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 7008c8dc39fSPeter Maydell "gic_dist_readb: Bad offset %x\n", (int)offset); 701e69954b9Spbrook return 0; 702e69954b9Spbrook } 703e69954b9Spbrook 704a9d85353SPeter Maydell static MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data, 705a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 706e69954b9Spbrook { 707a9d85353SPeter Maydell switch (size) { 708a9d85353SPeter Maydell case 1: 709a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 710a9d85353SPeter Maydell return MEMTX_OK; 711a9d85353SPeter Maydell case 2: 712a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 713a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 714a9d85353SPeter Maydell return MEMTX_OK; 715a9d85353SPeter Maydell case 4: 716a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 717a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 718a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 2, attrs) << 16; 719a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 3, attrs) << 24; 720a9d85353SPeter Maydell return MEMTX_OK; 721a9d85353SPeter Maydell default: 722a9d85353SPeter Maydell return MEMTX_ERROR; 723e69954b9Spbrook } 724e69954b9Spbrook } 725e69954b9Spbrook 726a8170e5eSAvi Kivity static void gic_dist_writeb(void *opaque, hwaddr offset, 727a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 728e69954b9Spbrook { 729fae15286SPeter Maydell GICState *s = (GICState *)opaque; 730e69954b9Spbrook int irq; 731e69954b9Spbrook int i; 7329ee6e8bbSpbrook int cpu; 733e69954b9Spbrook 734926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 735e69954b9Spbrook if (offset < 0x100) { 736e69954b9Spbrook if (offset == 0) { 737679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 738679aa175SFabian Aggeler /* NS version is just an alias of the S version's bit 1 */ 739679aa175SFabian Aggeler s->ctlr = deposit32(s->ctlr, 1, 1, value); 740679aa175SFabian Aggeler } else if (gic_has_groups(s)) { 741679aa175SFabian Aggeler s->ctlr = value & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1); 742679aa175SFabian Aggeler } else { 743679aa175SFabian Aggeler s->ctlr = value & GICD_CTLR_EN_GRP0; 744679aa175SFabian Aggeler } 745679aa175SFabian Aggeler DPRINTF("Distributor: Group0 %sabled; Group 1 %sabled\n", 746679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP0 ? "En" : "Dis", 747679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP1 ? "En" : "Dis"); 748e69954b9Spbrook } else if (offset < 4) { 749e69954b9Spbrook /* ignored. */ 750b79f2265SRob Herring } else if (offset >= 0x80) { 751c27a5ba9SFabian Aggeler /* Interrupt Group Registers: RAZ/WI for NS access to secure 752c27a5ba9SFabian Aggeler * GIC, or for GICs without groups. 753c27a5ba9SFabian Aggeler */ 754c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 755c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 756c27a5ba9SFabian Aggeler irq = (offset - 0x80) * 8 + GIC_BASE_IRQ; 757c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 758c27a5ba9SFabian Aggeler goto bad_reg; 759c27a5ba9SFabian Aggeler } 760c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 761c27a5ba9SFabian Aggeler /* Group bits are banked for private interrupts */ 762c27a5ba9SFabian Aggeler int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 763c27a5ba9SFabian Aggeler if (value & (1 << i)) { 764c27a5ba9SFabian Aggeler /* Group1 (Non-secure) */ 765c27a5ba9SFabian Aggeler GIC_SET_GROUP(irq + i, cm); 766c27a5ba9SFabian Aggeler } else { 767c27a5ba9SFabian Aggeler /* Group0 (Secure) */ 768c27a5ba9SFabian Aggeler GIC_CLEAR_GROUP(irq + i, cm); 769c27a5ba9SFabian Aggeler } 770c27a5ba9SFabian Aggeler } 771c27a5ba9SFabian Aggeler } 772e69954b9Spbrook } else { 773e69954b9Spbrook goto bad_reg; 774e69954b9Spbrook } 775e69954b9Spbrook } else if (offset < 0x180) { 776e69954b9Spbrook /* Interrupt Set Enable. */ 7779ee6e8bbSpbrook irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 778a32134aaSMark Langsdorf if (irq >= s->num_irq) 779e69954b9Spbrook goto bad_reg; 78041ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 7819ee6e8bbSpbrook value = 0xff; 78241ab7b55SChristoffer Dall } 78341ab7b55SChristoffer Dall 784e69954b9Spbrook for (i = 0; i < 8; i++) { 785e69954b9Spbrook if (value & (1 << i)) { 786f47b48fbSDaniel Sangorrin int mask = 787f47b48fbSDaniel Sangorrin (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i); 78869253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 78941bf234dSRabin Vincent 79041bf234dSRabin Vincent if (!GIC_TEST_ENABLED(irq + i, cm)) { 791e69954b9Spbrook DPRINTF("Enabled IRQ %d\n", irq + i); 79241bf234dSRabin Vincent } 79341bf234dSRabin Vincent GIC_SET_ENABLED(irq + i, cm); 794e69954b9Spbrook /* If a raised level triggered IRQ enabled then mark 795e69954b9Spbrook is as pending. */ 7969ee6e8bbSpbrook if (GIC_TEST_LEVEL(irq + i, mask) 79704050c5cSChristoffer Dall && !GIC_TEST_EDGE_TRIGGER(irq + i)) { 7989ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq + i, mask); 7999ee6e8bbSpbrook GIC_SET_PENDING(irq + i, mask); 8009ee6e8bbSpbrook } 801e69954b9Spbrook } 802e69954b9Spbrook } 803e69954b9Spbrook } else if (offset < 0x200) { 804e69954b9Spbrook /* Interrupt Clear Enable. */ 8059ee6e8bbSpbrook irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 806a32134aaSMark Langsdorf if (irq >= s->num_irq) 807e69954b9Spbrook goto bad_reg; 80841ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 8099ee6e8bbSpbrook value = 0; 81041ab7b55SChristoffer Dall } 81141ab7b55SChristoffer Dall 812e69954b9Spbrook for (i = 0; i < 8; i++) { 813e69954b9Spbrook if (value & (1 << i)) { 81469253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 81541bf234dSRabin Vincent 81641bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 817e69954b9Spbrook DPRINTF("Disabled IRQ %d\n", irq + i); 81841bf234dSRabin Vincent } 81941bf234dSRabin Vincent GIC_CLEAR_ENABLED(irq + i, cm); 820e69954b9Spbrook } 821e69954b9Spbrook } 822e69954b9Spbrook } else if (offset < 0x280) { 823e69954b9Spbrook /* Interrupt Set Pending. */ 8249ee6e8bbSpbrook irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 825a32134aaSMark Langsdorf if (irq >= s->num_irq) 826e69954b9Spbrook goto bad_reg; 82741ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 8285b0adce1SChristoffer Dall value = 0; 82941ab7b55SChristoffer Dall } 8309ee6e8bbSpbrook 831e69954b9Spbrook for (i = 0; i < 8; i++) { 832e69954b9Spbrook if (value & (1 << i)) { 833f47b48fbSDaniel Sangorrin GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); 834e69954b9Spbrook } 835e69954b9Spbrook } 836e69954b9Spbrook } else if (offset < 0x300) { 837e69954b9Spbrook /* Interrupt Clear Pending. */ 8389ee6e8bbSpbrook irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 839a32134aaSMark Langsdorf if (irq >= s->num_irq) 840e69954b9Spbrook goto bad_reg; 8415b0adce1SChristoffer Dall if (irq < GIC_NR_SGIS) { 8425b0adce1SChristoffer Dall value = 0; 8435b0adce1SChristoffer Dall } 8445b0adce1SChristoffer Dall 845e69954b9Spbrook for (i = 0; i < 8; i++) { 8469ee6e8bbSpbrook /* ??? This currently clears the pending bit for all CPUs, even 8479ee6e8bbSpbrook for per-CPU interrupts. It's unclear whether this is the 8489ee6e8bbSpbrook corect behavior. */ 849e69954b9Spbrook if (value & (1 << i)) { 8509ee6e8bbSpbrook GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 851e69954b9Spbrook } 852e69954b9Spbrook } 853e69954b9Spbrook } else if (offset < 0x400) { 854e69954b9Spbrook /* Interrupt Active. */ 855e69954b9Spbrook goto bad_reg; 856e69954b9Spbrook } else if (offset < 0x800) { 857e69954b9Spbrook /* Interrupt Priority. */ 8589ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 859a32134aaSMark Langsdorf if (irq >= s->num_irq) 860e69954b9Spbrook goto bad_reg; 86181508470SFabian Aggeler gic_set_priority(s, cpu, irq, value, attrs); 862e69954b9Spbrook } else if (offset < 0xc00) { 8636b9680bbSPeter Maydell /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the 8646b9680bbSPeter Maydell * annoying exception of the 11MPCore's GIC. 8656b9680bbSPeter Maydell */ 8666b9680bbSPeter Maydell if (s->num_cpu != 1 || s->revision == REV_11MPCORE) { 8679ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 8686b9680bbSPeter Maydell if (irq >= s->num_irq) { 869e69954b9Spbrook goto bad_reg; 8706b9680bbSPeter Maydell } 8716b9680bbSPeter Maydell if (irq < 29) { 8729ee6e8bbSpbrook value = 0; 8736b9680bbSPeter Maydell } else if (irq < GIC_INTERNAL) { 8749ee6e8bbSpbrook value = ALL_CPU_MASK; 8756b9680bbSPeter Maydell } 8769ee6e8bbSpbrook s->irq_target[irq] = value & ALL_CPU_MASK; 8776b9680bbSPeter Maydell } 878e69954b9Spbrook } else if (offset < 0xf00) { 879e69954b9Spbrook /* Interrupt Configuration. */ 8809ee6e8bbSpbrook irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 881a32134aaSMark Langsdorf if (irq >= s->num_irq) 882e69954b9Spbrook goto bad_reg; 883de7a900fSAdam Lackorzynski if (irq < GIC_NR_SGIS) 8849ee6e8bbSpbrook value |= 0xaa; 885e69954b9Spbrook for (i = 0; i < 4; i++) { 88624b790dfSAdam Lackorzynski if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 887e69954b9Spbrook if (value & (1 << (i * 2))) { 888e69954b9Spbrook GIC_SET_MODEL(irq + i); 889e69954b9Spbrook } else { 890e69954b9Spbrook GIC_CLEAR_MODEL(irq + i); 891e69954b9Spbrook } 89224b790dfSAdam Lackorzynski } 893e69954b9Spbrook if (value & (2 << (i * 2))) { 89404050c5cSChristoffer Dall GIC_SET_EDGE_TRIGGER(irq + i); 895e69954b9Spbrook } else { 89604050c5cSChristoffer Dall GIC_CLEAR_EDGE_TRIGGER(irq + i); 897e69954b9Spbrook } 898e69954b9Spbrook } 89940d22500SChristoffer Dall } else if (offset < 0xf10) { 9009ee6e8bbSpbrook /* 0xf00 is only handled for 32-bit writes. */ 901e69954b9Spbrook goto bad_reg; 90240d22500SChristoffer Dall } else if (offset < 0xf20) { 90340d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 90440d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 90540d22500SChristoffer Dall goto bad_reg; 90640d22500SChristoffer Dall } 90740d22500SChristoffer Dall irq = (offset - 0xf10); 90840d22500SChristoffer Dall 90940d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~value; 91040d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 91140d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, 1 << cpu); 91240d22500SChristoffer Dall } 91340d22500SChristoffer Dall } else if (offset < 0xf30) { 91440d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 91540d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 91640d22500SChristoffer Dall goto bad_reg; 91740d22500SChristoffer Dall } 91840d22500SChristoffer Dall irq = (offset - 0xf20); 91940d22500SChristoffer Dall 92040d22500SChristoffer Dall GIC_SET_PENDING(irq, 1 << cpu); 92140d22500SChristoffer Dall s->sgi_pending[irq][cpu] |= value; 92240d22500SChristoffer Dall } else { 92340d22500SChristoffer Dall goto bad_reg; 924e69954b9Spbrook } 925e69954b9Spbrook gic_update(s); 926e69954b9Spbrook return; 927e69954b9Spbrook bad_reg: 9288c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 9298c8dc39fSPeter Maydell "gic_dist_writeb: Bad offset %x\n", (int)offset); 930e69954b9Spbrook } 931e69954b9Spbrook 932a8170e5eSAvi Kivity static void gic_dist_writew(void *opaque, hwaddr offset, 933a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 934e69954b9Spbrook { 935a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, value & 0xff, attrs); 936a9d85353SPeter Maydell gic_dist_writeb(opaque, offset + 1, value >> 8, attrs); 937e69954b9Spbrook } 938e69954b9Spbrook 939a8170e5eSAvi Kivity static void gic_dist_writel(void *opaque, hwaddr offset, 940a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 941e69954b9Spbrook { 942fae15286SPeter Maydell GICState *s = (GICState *)opaque; 9438da3ff18Spbrook if (offset == 0xf00) { 9449ee6e8bbSpbrook int cpu; 9459ee6e8bbSpbrook int irq; 9469ee6e8bbSpbrook int mask; 94740d22500SChristoffer Dall int target_cpu; 9489ee6e8bbSpbrook 949926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 9509ee6e8bbSpbrook irq = value & 0x3ff; 9519ee6e8bbSpbrook switch ((value >> 24) & 3) { 9529ee6e8bbSpbrook case 0: 9539ee6e8bbSpbrook mask = (value >> 16) & ALL_CPU_MASK; 9549ee6e8bbSpbrook break; 9559ee6e8bbSpbrook case 1: 956fa250144SAdam Lackorzynski mask = ALL_CPU_MASK ^ (1 << cpu); 9579ee6e8bbSpbrook break; 9589ee6e8bbSpbrook case 2: 959fa250144SAdam Lackorzynski mask = 1 << cpu; 9609ee6e8bbSpbrook break; 9619ee6e8bbSpbrook default: 9629ee6e8bbSpbrook DPRINTF("Bad Soft Int target filter\n"); 9639ee6e8bbSpbrook mask = ALL_CPU_MASK; 9649ee6e8bbSpbrook break; 9659ee6e8bbSpbrook } 9669ee6e8bbSpbrook GIC_SET_PENDING(irq, mask); 96740d22500SChristoffer Dall target_cpu = ctz32(mask); 96840d22500SChristoffer Dall while (target_cpu < GIC_NCPU) { 96940d22500SChristoffer Dall s->sgi_pending[irq][target_cpu] |= (1 << cpu); 97040d22500SChristoffer Dall mask &= ~(1 << target_cpu); 97140d22500SChristoffer Dall target_cpu = ctz32(mask); 97240d22500SChristoffer Dall } 9739ee6e8bbSpbrook gic_update(s); 9749ee6e8bbSpbrook return; 9759ee6e8bbSpbrook } 976a9d85353SPeter Maydell gic_dist_writew(opaque, offset, value & 0xffff, attrs); 977a9d85353SPeter Maydell gic_dist_writew(opaque, offset + 2, value >> 16, attrs); 978a9d85353SPeter Maydell } 979a9d85353SPeter Maydell 980a9d85353SPeter Maydell static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data, 981a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 982a9d85353SPeter Maydell { 983a9d85353SPeter Maydell switch (size) { 984a9d85353SPeter Maydell case 1: 985a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, data, attrs); 986a9d85353SPeter Maydell return MEMTX_OK; 987a9d85353SPeter Maydell case 2: 988a9d85353SPeter Maydell gic_dist_writew(opaque, offset, data, attrs); 989a9d85353SPeter Maydell return MEMTX_OK; 990a9d85353SPeter Maydell case 4: 991a9d85353SPeter Maydell gic_dist_writel(opaque, offset, data, attrs); 992a9d85353SPeter Maydell return MEMTX_OK; 993a9d85353SPeter Maydell default: 994a9d85353SPeter Maydell return MEMTX_ERROR; 995a9d85353SPeter Maydell } 996e69954b9Spbrook } 997e69954b9Spbrook 99851fd06e0SPeter Maydell static inline uint32_t gic_apr_ns_view(GICState *s, int cpu, int regno) 99951fd06e0SPeter Maydell { 100051fd06e0SPeter Maydell /* Return the Nonsecure view of GICC_APR<regno>. This is the 100151fd06e0SPeter Maydell * second half of GICC_NSAPR. 100251fd06e0SPeter Maydell */ 100351fd06e0SPeter Maydell switch (GIC_MIN_BPR) { 100451fd06e0SPeter Maydell case 0: 100551fd06e0SPeter Maydell if (regno < 2) { 100651fd06e0SPeter Maydell return s->nsapr[regno + 2][cpu]; 100751fd06e0SPeter Maydell } 100851fd06e0SPeter Maydell break; 100951fd06e0SPeter Maydell case 1: 101051fd06e0SPeter Maydell if (regno == 0) { 101151fd06e0SPeter Maydell return s->nsapr[regno + 1][cpu]; 101251fd06e0SPeter Maydell } 101351fd06e0SPeter Maydell break; 101451fd06e0SPeter Maydell case 2: 101551fd06e0SPeter Maydell if (regno == 0) { 101651fd06e0SPeter Maydell return extract32(s->nsapr[0][cpu], 16, 16); 101751fd06e0SPeter Maydell } 101851fd06e0SPeter Maydell break; 101951fd06e0SPeter Maydell case 3: 102051fd06e0SPeter Maydell if (regno == 0) { 102151fd06e0SPeter Maydell return extract32(s->nsapr[0][cpu], 8, 8); 102251fd06e0SPeter Maydell } 102351fd06e0SPeter Maydell break; 102451fd06e0SPeter Maydell default: 102551fd06e0SPeter Maydell g_assert_not_reached(); 102651fd06e0SPeter Maydell } 102751fd06e0SPeter Maydell return 0; 102851fd06e0SPeter Maydell } 102951fd06e0SPeter Maydell 103051fd06e0SPeter Maydell static inline void gic_apr_write_ns_view(GICState *s, int cpu, int regno, 103151fd06e0SPeter Maydell uint32_t value) 103251fd06e0SPeter Maydell { 103351fd06e0SPeter Maydell /* Write the Nonsecure view of GICC_APR<regno>. */ 103451fd06e0SPeter Maydell switch (GIC_MIN_BPR) { 103551fd06e0SPeter Maydell case 0: 103651fd06e0SPeter Maydell if (regno < 2) { 103751fd06e0SPeter Maydell s->nsapr[regno + 2][cpu] = value; 103851fd06e0SPeter Maydell } 103951fd06e0SPeter Maydell break; 104051fd06e0SPeter Maydell case 1: 104151fd06e0SPeter Maydell if (regno == 0) { 104251fd06e0SPeter Maydell s->nsapr[regno + 1][cpu] = value; 104351fd06e0SPeter Maydell } 104451fd06e0SPeter Maydell break; 104551fd06e0SPeter Maydell case 2: 104651fd06e0SPeter Maydell if (regno == 0) { 104751fd06e0SPeter Maydell s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 16, 16, value); 104851fd06e0SPeter Maydell } 104951fd06e0SPeter Maydell break; 105051fd06e0SPeter Maydell case 3: 105151fd06e0SPeter Maydell if (regno == 0) { 105251fd06e0SPeter Maydell s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 8, 8, value); 105351fd06e0SPeter Maydell } 105451fd06e0SPeter Maydell break; 105551fd06e0SPeter Maydell default: 105651fd06e0SPeter Maydell g_assert_not_reached(); 105751fd06e0SPeter Maydell } 105851fd06e0SPeter Maydell } 105951fd06e0SPeter Maydell 1060a9d85353SPeter Maydell static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, 1061a9d85353SPeter Maydell uint64_t *data, MemTxAttrs attrs) 1062e69954b9Spbrook { 1063e69954b9Spbrook switch (offset) { 1064e69954b9Spbrook case 0x00: /* Control */ 106532951860SFabian Aggeler *data = gic_get_cpu_control(s, cpu, attrs); 1066a9d85353SPeter Maydell break; 1067e69954b9Spbrook case 0x04: /* Priority mask */ 106881508470SFabian Aggeler *data = gic_get_priority_mask(s, cpu, attrs); 1069a9d85353SPeter Maydell break; 1070e69954b9Spbrook case 0x08: /* Binary Point */ 1071822e9cc3SFabian Aggeler if (s->security_extn && !attrs.secure) { 1072822e9cc3SFabian Aggeler /* BPR is banked. Non-secure copy stored in ABPR. */ 1073822e9cc3SFabian Aggeler *data = s->abpr[cpu]; 1074822e9cc3SFabian Aggeler } else { 1075a9d85353SPeter Maydell *data = s->bpr[cpu]; 1076822e9cc3SFabian Aggeler } 1077a9d85353SPeter Maydell break; 1078e69954b9Spbrook case 0x0c: /* Acknowledge */ 1079c5619bf9SFabian Aggeler *data = gic_acknowledge_irq(s, cpu, attrs); 1080a9d85353SPeter Maydell break; 108166a0a2cbSDong Xu Wang case 0x14: /* Running Priority */ 108208efa9f2SFabian Aggeler *data = gic_get_running_priority(s, cpu, attrs); 1083a9d85353SPeter Maydell break; 1084e69954b9Spbrook case 0x18: /* Highest Pending Interrupt */ 10857c0fa108SFabian Aggeler *data = gic_get_current_pending_irq(s, cpu, attrs); 1086a9d85353SPeter Maydell break; 1087aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 1088822e9cc3SFabian Aggeler /* GIC v2, no security: ABPR 1089822e9cc3SFabian Aggeler * GIC v1, no security: not implemented (RAZ/WI) 1090822e9cc3SFabian Aggeler * With security extensions, secure access: ABPR (alias of NS BPR) 1091822e9cc3SFabian Aggeler * With security extensions, nonsecure access: RAZ/WI 1092822e9cc3SFabian Aggeler */ 1093822e9cc3SFabian Aggeler if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 1094822e9cc3SFabian Aggeler *data = 0; 1095822e9cc3SFabian Aggeler } else { 1096a9d85353SPeter Maydell *data = s->abpr[cpu]; 1097822e9cc3SFabian Aggeler } 1098a9d85353SPeter Maydell break; 1099a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 110051fd06e0SPeter Maydell { 110151fd06e0SPeter Maydell int regno = (offset - 0xd0) / 4; 110251fd06e0SPeter Maydell 110351fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 110451fd06e0SPeter Maydell *data = 0; 110551fd06e0SPeter Maydell } else if (s->security_extn && !attrs.secure) { 110651fd06e0SPeter Maydell /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ 110751fd06e0SPeter Maydell *data = gic_apr_ns_view(s, regno, cpu); 110851fd06e0SPeter Maydell } else { 110951fd06e0SPeter Maydell *data = s->apr[regno][cpu]; 111051fd06e0SPeter Maydell } 1111a9d85353SPeter Maydell break; 111251fd06e0SPeter Maydell } 111351fd06e0SPeter Maydell case 0xe0: case 0xe4: case 0xe8: case 0xec: 111451fd06e0SPeter Maydell { 111551fd06e0SPeter Maydell int regno = (offset - 0xe0) / 4; 111651fd06e0SPeter Maydell 111751fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2 || !gic_has_groups(s) || 111851fd06e0SPeter Maydell (s->security_extn && !attrs.secure)) { 111951fd06e0SPeter Maydell *data = 0; 112051fd06e0SPeter Maydell } else { 112151fd06e0SPeter Maydell *data = s->nsapr[regno][cpu]; 112251fd06e0SPeter Maydell } 112351fd06e0SPeter Maydell break; 112451fd06e0SPeter Maydell } 1125e69954b9Spbrook default: 11268c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 11278c8dc39fSPeter Maydell "gic_cpu_read: Bad offset %x\n", (int)offset); 1128a9d85353SPeter Maydell return MEMTX_ERROR; 1129e69954b9Spbrook } 1130a9d85353SPeter Maydell return MEMTX_OK; 1131e69954b9Spbrook } 1132e69954b9Spbrook 1133a9d85353SPeter Maydell static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, 1134a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 1135e69954b9Spbrook { 1136e69954b9Spbrook switch (offset) { 1137e69954b9Spbrook case 0x00: /* Control */ 113832951860SFabian Aggeler gic_set_cpu_control(s, cpu, value, attrs); 1139e69954b9Spbrook break; 1140e69954b9Spbrook case 0x04: /* Priority mask */ 114181508470SFabian Aggeler gic_set_priority_mask(s, cpu, value, attrs); 1142e69954b9Spbrook break; 1143e69954b9Spbrook case 0x08: /* Binary Point */ 1144822e9cc3SFabian Aggeler if (s->security_extn && !attrs.secure) { 1145822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1146822e9cc3SFabian Aggeler } else { 1147822e9cc3SFabian Aggeler s->bpr[cpu] = MAX(value & 0x7, GIC_MIN_BPR); 1148822e9cc3SFabian Aggeler } 1149e69954b9Spbrook break; 1150e69954b9Spbrook case 0x10: /* End Of Interrupt */ 1151f9c6a7f1SFabian Aggeler gic_complete_irq(s, cpu, value & 0x3ff, attrs); 1152a9d85353SPeter Maydell return MEMTX_OK; 1153aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 1154822e9cc3SFabian Aggeler if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 1155822e9cc3SFabian Aggeler /* unimplemented, or NS access: RAZ/WI */ 1156822e9cc3SFabian Aggeler return MEMTX_OK; 1157822e9cc3SFabian Aggeler } else { 1158822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1159aa7d461aSChristoffer Dall } 1160aa7d461aSChristoffer Dall break; 1161a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 116251fd06e0SPeter Maydell { 116351fd06e0SPeter Maydell int regno = (offset - 0xd0) / 4; 116451fd06e0SPeter Maydell 116551fd06e0SPeter Maydell if (regno >= GIC_NR_APRS || s->revision != 2) { 116651fd06e0SPeter Maydell return MEMTX_OK; 116751fd06e0SPeter Maydell } 116851fd06e0SPeter Maydell if (s->security_extn && !attrs.secure) { 116951fd06e0SPeter Maydell /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ 117051fd06e0SPeter Maydell gic_apr_write_ns_view(s, regno, cpu, value); 117151fd06e0SPeter Maydell } else { 117251fd06e0SPeter Maydell s->apr[regno][cpu] = value; 117351fd06e0SPeter Maydell } 1174a9d477c4SChristoffer Dall 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) { 118151fd06e0SPeter Maydell return MEMTX_OK; 118251fd06e0SPeter Maydell } 118351fd06e0SPeter Maydell if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 118451fd06e0SPeter Maydell return MEMTX_OK; 118551fd06e0SPeter Maydell } 118651fd06e0SPeter Maydell s->nsapr[regno][cpu] = value; 118751fd06e0SPeter Maydell break; 118851fd06e0SPeter Maydell } 1189e69954b9Spbrook default: 11908c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 11918c8dc39fSPeter Maydell "gic_cpu_write: Bad offset %x\n", (int)offset); 1192a9d85353SPeter Maydell return MEMTX_ERROR; 1193e69954b9Spbrook } 1194e69954b9Spbrook gic_update(s); 1195a9d85353SPeter Maydell return MEMTX_OK; 1196e69954b9Spbrook } 1197e2c56465SPeter Maydell 1198e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for the current CPU */ 1199a9d85353SPeter Maydell static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data, 1200a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1201e2c56465SPeter Maydell { 1202fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1203a9d85353SPeter Maydell return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs); 1204e2c56465SPeter Maydell } 1205e2c56465SPeter Maydell 1206a9d85353SPeter Maydell static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr, 1207a9d85353SPeter Maydell uint64_t value, unsigned size, 1208a9d85353SPeter Maydell MemTxAttrs attrs) 1209e2c56465SPeter Maydell { 1210fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1211a9d85353SPeter Maydell return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs); 1212e2c56465SPeter Maydell } 1213e2c56465SPeter Maydell 1214e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for a specific CPU. 1215fae15286SPeter Maydell * These just decode the opaque pointer into GICState* + cpu id. 1216e2c56465SPeter Maydell */ 1217a9d85353SPeter Maydell static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data, 1218a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1219e2c56465SPeter Maydell { 1220fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1221fae15286SPeter Maydell GICState *s = *backref; 1222e2c56465SPeter Maydell int id = (backref - s->backref); 1223a9d85353SPeter Maydell return gic_cpu_read(s, id, addr, data, attrs); 1224e2c56465SPeter Maydell } 1225e2c56465SPeter Maydell 1226a9d85353SPeter Maydell static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr, 1227a9d85353SPeter Maydell uint64_t value, unsigned size, 1228a9d85353SPeter Maydell MemTxAttrs attrs) 1229e2c56465SPeter Maydell { 1230fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1231fae15286SPeter Maydell GICState *s = *backref; 1232e2c56465SPeter Maydell int id = (backref - s->backref); 1233a9d85353SPeter Maydell return gic_cpu_write(s, id, addr, value, attrs); 1234e2c56465SPeter Maydell } 1235e2c56465SPeter Maydell 12367926c210SPavel Fedin static const MemoryRegionOps gic_ops[2] = { 12377926c210SPavel Fedin { 12387926c210SPavel Fedin .read_with_attrs = gic_dist_read, 12397926c210SPavel Fedin .write_with_attrs = gic_dist_write, 12407926c210SPavel Fedin .endianness = DEVICE_NATIVE_ENDIAN, 12417926c210SPavel Fedin }, 12427926c210SPavel Fedin { 1243a9d85353SPeter Maydell .read_with_attrs = gic_thiscpu_read, 1244a9d85353SPeter Maydell .write_with_attrs = gic_thiscpu_write, 1245e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 12467926c210SPavel Fedin } 1247e2c56465SPeter Maydell }; 1248e2c56465SPeter Maydell 1249e2c56465SPeter Maydell static const MemoryRegionOps gic_cpu_ops = { 1250a9d85353SPeter Maydell .read_with_attrs = gic_do_cpu_read, 1251a9d85353SPeter Maydell .write_with_attrs = gic_do_cpu_write, 1252e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 1253e2c56465SPeter Maydell }; 1254e69954b9Spbrook 12557926c210SPavel Fedin /* This function is used by nvic model */ 12567b95a508SKONRAD Frederic void gic_init_irqs_and_distributor(GICState *s) 1257e69954b9Spbrook { 12587926c210SPavel Fedin gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); 12592b518c56SPeter Maydell } 12602b518c56SPeter Maydell 126153111180SPeter Maydell static void arm_gic_realize(DeviceState *dev, Error **errp) 12622b518c56SPeter Maydell { 126353111180SPeter Maydell /* Device instance realize function for the GIC sysbus device */ 12642b518c56SPeter Maydell int i; 126553111180SPeter Maydell GICState *s = ARM_GIC(dev); 126653111180SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 12671e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_GET_CLASS(s); 12680175ba10SMarkus Armbruster Error *local_err = NULL; 12691e8cae4dSPeter Maydell 12700175ba10SMarkus Armbruster agc->parent_realize(dev, &local_err); 12710175ba10SMarkus Armbruster if (local_err) { 12720175ba10SMarkus Armbruster error_propagate(errp, local_err); 127353111180SPeter Maydell return; 127453111180SPeter Maydell } 12751e8cae4dSPeter Maydell 12767926c210SPavel Fedin /* This creates distributor and main CPU interface (s->cpuiomem[0]) */ 12777926c210SPavel Fedin gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); 12782b518c56SPeter Maydell 12797926c210SPavel Fedin /* Extra core-specific regions for the CPU interfaces. This is 12807926c210SPavel Fedin * necessary for "franken-GIC" implementations, for example on 12817926c210SPavel Fedin * Exynos 4. 1282e2c56465SPeter Maydell * NB that the memory region size of 0x100 applies for the 11MPCore 1283e2c56465SPeter Maydell * and also cores following the GIC v1 spec (ie A9). 1284e2c56465SPeter Maydell * GIC v2 defines a larger memory region (0x1000) so this will need 1285e2c56465SPeter Maydell * to be extended when we implement A15. 1286e2c56465SPeter Maydell */ 1287e2c56465SPeter Maydell for (i = 0; i < NUM_CPU(s); i++) { 1288e2c56465SPeter Maydell s->backref[i] = s; 12891437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, 12901437c94bSPaolo Bonzini &s->backref[i], "gic_cpu", 0x100); 12917926c210SPavel Fedin sysbus_init_mmio(sbd, &s->cpuiomem[i+1]); 1292496dbcd1SPeter Maydell } 1293496dbcd1SPeter Maydell } 1294496dbcd1SPeter Maydell 1295496dbcd1SPeter Maydell static void arm_gic_class_init(ObjectClass *klass, void *data) 1296496dbcd1SPeter Maydell { 1297496dbcd1SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 12981e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_CLASS(klass); 129953111180SPeter Maydell 130053111180SPeter Maydell agc->parent_realize = dc->realize; 130153111180SPeter Maydell dc->realize = arm_gic_realize; 1302496dbcd1SPeter Maydell } 1303496dbcd1SPeter Maydell 13048c43a6f0SAndreas Färber static const TypeInfo arm_gic_info = { 13051e8cae4dSPeter Maydell .name = TYPE_ARM_GIC, 13061e8cae4dSPeter Maydell .parent = TYPE_ARM_GIC_COMMON, 1307fae15286SPeter Maydell .instance_size = sizeof(GICState), 1308496dbcd1SPeter Maydell .class_init = arm_gic_class_init, 1309998a74bcSPeter Maydell .class_size = sizeof(ARMGICClass), 1310496dbcd1SPeter Maydell }; 1311496dbcd1SPeter Maydell 1312496dbcd1SPeter Maydell static void arm_gic_register_types(void) 1313496dbcd1SPeter Maydell { 1314496dbcd1SPeter Maydell type_register_static(&arm_gic_info); 1315496dbcd1SPeter Maydell } 1316496dbcd1SPeter Maydell 1317496dbcd1SPeter Maydell type_init(arm_gic_register_types) 1318