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; 63*dadbb58fSPeter 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]); 73*dadbb58fSPeter Maydell qemu_irq_lower(s->parent_fiq[cpu]); 74e69954b9Spbrook return; 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 } 87*dadbb58fSPeter Maydell 88*dadbb58fSPeter Maydell irq_level = fiq_level = 0; 89*dadbb58fSPeter 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]) { 93*dadbb58fSPeter Maydell int group = GIC_TEST_GROUP(best_irq, cm); 94*dadbb58fSPeter Maydell 95*dadbb58fSPeter Maydell if (extract32(s->ctlr, group, 1) && 96*dadbb58fSPeter Maydell extract32(s->cpu_ctlr[cpu], group, 1)) { 97*dadbb58fSPeter Maydell if (group == 0 && s->cpu_ctlr[cpu] & GICC_CTLR_FIQ_EN) { 98*dadbb58fSPeter Maydell DPRINTF("Raised pending FIQ %d (cpu %d)\n", 99*dadbb58fSPeter Maydell best_irq, cpu); 100*dadbb58fSPeter Maydell fiq_level = 1; 101*dadbb58fSPeter Maydell } else { 102*dadbb58fSPeter Maydell DPRINTF("Raised pending IRQ %d (cpu %d)\n", 103*dadbb58fSPeter Maydell best_irq, cpu); 104*dadbb58fSPeter Maydell irq_level = 1; 105e69954b9Spbrook } 106e69954b9Spbrook } 107*dadbb58fSPeter Maydell } 108*dadbb58fSPeter Maydell } 109*dadbb58fSPeter Maydell 110*dadbb58fSPeter Maydell qemu_set_irq(s->parent_irq[cpu], irq_level); 111*dadbb58fSPeter 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 222fae15286SPeter Maydell static void gic_set_running_irq(GICState *s, int cpu, int irq) 223e69954b9Spbrook { 2249ee6e8bbSpbrook s->running_irq[cpu] = irq; 2259ee6e8bbSpbrook if (irq == 1023) { 2269ee6e8bbSpbrook s->running_priority[cpu] = 0x100; 2279ee6e8bbSpbrook } else { 2289ee6e8bbSpbrook s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu); 2299ee6e8bbSpbrook } 230e69954b9Spbrook gic_update(s); 231e69954b9Spbrook } 232e69954b9Spbrook 233c5619bf9SFabian Aggeler uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) 234e69954b9Spbrook { 23540d22500SChristoffer Dall int ret, irq, src; 2369ee6e8bbSpbrook int cm = 1 << cpu; 237c5619bf9SFabian Aggeler 238c5619bf9SFabian Aggeler /* gic_get_current_pending_irq() will return 1022 or 1023 appropriately 239c5619bf9SFabian Aggeler * for the case where this GIC supports grouping and the pending interrupt 240c5619bf9SFabian Aggeler * is in the wrong group. 241c5619bf9SFabian Aggeler */ 242c5619bf9SFabian Aggeler irq = gic_get_current_pending_irq(s, cpu, attrs);; 243c5619bf9SFabian Aggeler 244c5619bf9SFabian Aggeler if (irq >= GIC_MAXIRQ) { 245c5619bf9SFabian Aggeler DPRINTF("ACK, no pending interrupt or it is hidden: %d\n", irq); 246c5619bf9SFabian Aggeler return irq; 247c5619bf9SFabian Aggeler } 248c5619bf9SFabian Aggeler 249c5619bf9SFabian Aggeler if (GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) { 250c5619bf9SFabian Aggeler DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq); 251e69954b9Spbrook return 1023; 252e69954b9Spbrook } 25340d22500SChristoffer Dall s->last_active[irq][cpu] = s->running_irq[cpu]; 25440d22500SChristoffer Dall 25587316902SPeter Maydell if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 2569ee6e8bbSpbrook /* Clear pending flags for both level and edge triggered interrupts. 25740d22500SChristoffer Dall * Level triggered IRQs will be reasserted once they become inactive. 25840d22500SChristoffer Dall */ 25940d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 26040d22500SChristoffer Dall ret = irq; 26140d22500SChristoffer Dall } else { 26240d22500SChristoffer Dall if (irq < GIC_NR_SGIS) { 26340d22500SChristoffer Dall /* Lookup the source CPU for the SGI and clear this in the 26440d22500SChristoffer Dall * sgi_pending map. Return the src and clear the overall pending 26540d22500SChristoffer Dall * state on this CPU if the SGI is not pending from any CPUs. 26640d22500SChristoffer Dall */ 26740d22500SChristoffer Dall assert(s->sgi_pending[irq][cpu] != 0); 26840d22500SChristoffer Dall src = ctz32(s->sgi_pending[irq][cpu]); 26940d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~(1 << src); 27040d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 27140d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 27240d22500SChristoffer Dall } 27340d22500SChristoffer Dall ret = irq | ((src & 0x7) << 10); 27440d22500SChristoffer Dall } else { 27540d22500SChristoffer Dall /* Clear pending state for both level and edge triggered 27640d22500SChristoffer Dall * interrupts. (level triggered interrupts with an active line 27740d22500SChristoffer Dall * remain pending, see gic_test_pending) 27840d22500SChristoffer Dall */ 27940d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 28040d22500SChristoffer Dall ret = irq; 28140d22500SChristoffer Dall } 28240d22500SChristoffer Dall } 28340d22500SChristoffer Dall 28440d22500SChristoffer Dall gic_set_running_irq(s, cpu, irq); 28540d22500SChristoffer Dall DPRINTF("ACK %d\n", irq); 28640d22500SChristoffer Dall return ret; 287e69954b9Spbrook } 288e69954b9Spbrook 28981508470SFabian Aggeler void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val, 29081508470SFabian Aggeler MemTxAttrs attrs) 2919df90ad0SChristoffer Dall { 29281508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 29381508470SFabian Aggeler if (!GIC_TEST_GROUP(irq, (1 << cpu))) { 29481508470SFabian Aggeler return; /* Ignore Non-secure access of Group0 IRQ */ 29581508470SFabian Aggeler } 29681508470SFabian Aggeler val = 0x80 | (val >> 1); /* Non-secure view */ 29781508470SFabian Aggeler } 29881508470SFabian Aggeler 2999df90ad0SChristoffer Dall if (irq < GIC_INTERNAL) { 3009df90ad0SChristoffer Dall s->priority1[irq][cpu] = val; 3019df90ad0SChristoffer Dall } else { 3029df90ad0SChristoffer Dall s->priority2[(irq) - GIC_INTERNAL] = val; 3039df90ad0SChristoffer Dall } 3049df90ad0SChristoffer Dall } 3059df90ad0SChristoffer Dall 30681508470SFabian Aggeler static uint32_t gic_get_priority(GICState *s, int cpu, int irq, 30781508470SFabian Aggeler MemTxAttrs attrs) 30881508470SFabian Aggeler { 30981508470SFabian Aggeler uint32_t prio = GIC_GET_PRIORITY(irq, cpu); 31081508470SFabian Aggeler 31181508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 31281508470SFabian Aggeler if (!GIC_TEST_GROUP(irq, (1 << cpu))) { 31381508470SFabian Aggeler return 0; /* Non-secure access cannot read priority of Group0 IRQ */ 31481508470SFabian Aggeler } 31581508470SFabian Aggeler prio = (prio << 1) & 0xff; /* Non-secure view */ 31681508470SFabian Aggeler } 31781508470SFabian Aggeler return prio; 31881508470SFabian Aggeler } 31981508470SFabian Aggeler 32081508470SFabian Aggeler static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask, 32181508470SFabian Aggeler MemTxAttrs attrs) 32281508470SFabian Aggeler { 32381508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 32481508470SFabian Aggeler if (s->priority_mask[cpu] & 0x80) { 32581508470SFabian Aggeler /* Priority Mask in upper half */ 32681508470SFabian Aggeler pmask = 0x80 | (pmask >> 1); 32781508470SFabian Aggeler } else { 32881508470SFabian Aggeler /* Non-secure write ignored if priority mask is in lower half */ 32981508470SFabian Aggeler return; 33081508470SFabian Aggeler } 33181508470SFabian Aggeler } 33281508470SFabian Aggeler s->priority_mask[cpu] = pmask; 33381508470SFabian Aggeler } 33481508470SFabian Aggeler 33581508470SFabian Aggeler static uint32_t gic_get_priority_mask(GICState *s, int cpu, MemTxAttrs attrs) 33681508470SFabian Aggeler { 33781508470SFabian Aggeler uint32_t pmask = s->priority_mask[cpu]; 33881508470SFabian Aggeler 33981508470SFabian Aggeler if (s->security_extn && !attrs.secure) { 34081508470SFabian Aggeler if (pmask & 0x80) { 34181508470SFabian Aggeler /* Priority Mask in upper half, return Non-secure view */ 34281508470SFabian Aggeler pmask = (pmask << 1) & 0xff; 34381508470SFabian Aggeler } else { 34481508470SFabian Aggeler /* Priority Mask in lower half, RAZ */ 34581508470SFabian Aggeler pmask = 0; 34681508470SFabian Aggeler } 34781508470SFabian Aggeler } 34881508470SFabian Aggeler return pmask; 34981508470SFabian Aggeler } 35081508470SFabian Aggeler 35132951860SFabian Aggeler static uint32_t gic_get_cpu_control(GICState *s, int cpu, MemTxAttrs attrs) 35232951860SFabian Aggeler { 35332951860SFabian Aggeler uint32_t ret = s->cpu_ctlr[cpu]; 35432951860SFabian Aggeler 35532951860SFabian Aggeler if (s->security_extn && !attrs.secure) { 35632951860SFabian Aggeler /* Construct the NS banked view of GICC_CTLR from the correct 35732951860SFabian Aggeler * bits of the S banked view. We don't need to move the bypass 35832951860SFabian Aggeler * control bits because we don't implement that (IMPDEF) part 35932951860SFabian Aggeler * of the GIC architecture. 36032951860SFabian Aggeler */ 36132951860SFabian Aggeler ret = (ret & (GICC_CTLR_EN_GRP1 | GICC_CTLR_EOIMODE_NS)) >> 1; 36232951860SFabian Aggeler } 36332951860SFabian Aggeler return ret; 36432951860SFabian Aggeler } 36532951860SFabian Aggeler 36632951860SFabian Aggeler static void gic_set_cpu_control(GICState *s, int cpu, uint32_t value, 36732951860SFabian Aggeler MemTxAttrs attrs) 36832951860SFabian Aggeler { 36932951860SFabian Aggeler uint32_t mask; 37032951860SFabian Aggeler 37132951860SFabian Aggeler if (s->security_extn && !attrs.secure) { 37232951860SFabian Aggeler /* The NS view can only write certain bits in the register; 37332951860SFabian Aggeler * the rest are unchanged 37432951860SFabian Aggeler */ 37532951860SFabian Aggeler mask = GICC_CTLR_EN_GRP1; 37632951860SFabian Aggeler if (s->revision == 2) { 37732951860SFabian Aggeler mask |= GICC_CTLR_EOIMODE_NS; 37832951860SFabian Aggeler } 37932951860SFabian Aggeler s->cpu_ctlr[cpu] &= ~mask; 38032951860SFabian Aggeler s->cpu_ctlr[cpu] |= (value << 1) & mask; 38132951860SFabian Aggeler } else { 38232951860SFabian Aggeler if (s->revision == 2) { 38332951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V2_S_MASK : GICC_CTLR_V2_MASK; 38432951860SFabian Aggeler } else { 38532951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V1_S_MASK : GICC_CTLR_V1_MASK; 38632951860SFabian Aggeler } 38732951860SFabian Aggeler s->cpu_ctlr[cpu] = value & mask; 38832951860SFabian Aggeler } 38932951860SFabian Aggeler DPRINTF("CPU Interface %d: Group0 Interrupts %sabled, " 39032951860SFabian Aggeler "Group1 Interrupts %sabled\n", cpu, 39132951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP0) ? "En" : "Dis", 39232951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP1) ? "En" : "Dis"); 39332951860SFabian Aggeler } 39432951860SFabian Aggeler 39508efa9f2SFabian Aggeler static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs) 39608efa9f2SFabian Aggeler { 39708efa9f2SFabian Aggeler if (s->security_extn && !attrs.secure) { 39808efa9f2SFabian Aggeler if (s->running_priority[cpu] & 0x80) { 39908efa9f2SFabian Aggeler /* Running priority in upper half of range: return the Non-secure 40008efa9f2SFabian Aggeler * view of the priority. 40108efa9f2SFabian Aggeler */ 40208efa9f2SFabian Aggeler return s->running_priority[cpu] << 1; 40308efa9f2SFabian Aggeler } else { 40408efa9f2SFabian Aggeler /* Running priority in lower half of range: RAZ */ 40508efa9f2SFabian Aggeler return 0; 40608efa9f2SFabian Aggeler } 40708efa9f2SFabian Aggeler } else { 40808efa9f2SFabian Aggeler return s->running_priority[cpu]; 40908efa9f2SFabian Aggeler } 41008efa9f2SFabian Aggeler } 41108efa9f2SFabian Aggeler 412f9c6a7f1SFabian Aggeler void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) 413e69954b9Spbrook { 414e69954b9Spbrook int update = 0; 4159ee6e8bbSpbrook int cm = 1 << cpu; 416df628ff1Spbrook DPRINTF("EOI %d\n", irq); 417a32134aaSMark Langsdorf if (irq >= s->num_irq) { 418217bfb44SPeter Maydell /* This handles two cases: 419217bfb44SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 420217bfb44SPeter Maydell * to the GICC_EOIR, the GIC ignores that write. 421217bfb44SPeter Maydell * 2. If software writes the number of a non-existent interrupt 422217bfb44SPeter Maydell * this must be a subcase of "value written does not match the last 423217bfb44SPeter Maydell * valid interrupt value read from the Interrupt Acknowledge 424217bfb44SPeter Maydell * register" and so this is UNPREDICTABLE. We choose to ignore it. 425217bfb44SPeter Maydell */ 426217bfb44SPeter Maydell return; 427217bfb44SPeter Maydell } 4289ee6e8bbSpbrook if (s->running_irq[cpu] == 1023) 429e69954b9Spbrook return; /* No active IRQ. */ 4308d999995SChristoffer Dall 4318d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 432e69954b9Spbrook /* Mark level triggered interrupts as pending if they are still 433e69954b9Spbrook raised. */ 43404050c5cSChristoffer Dall if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm) 4359ee6e8bbSpbrook && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) { 4369ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq, cm); 4379ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 438e69954b9Spbrook update = 1; 439e69954b9Spbrook } 4408d999995SChristoffer Dall } 4418d999995SChristoffer Dall 442f9c6a7f1SFabian Aggeler if (s->security_extn && !attrs.secure && !GIC_TEST_GROUP(irq, cm)) { 443f9c6a7f1SFabian Aggeler DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq); 444f9c6a7f1SFabian Aggeler return; 445f9c6a7f1SFabian Aggeler } 446f9c6a7f1SFabian Aggeler 447f9c6a7f1SFabian Aggeler /* Secure EOI with GICC_CTLR.AckCtl == 0 when the IRQ is a Group 1 448f9c6a7f1SFabian Aggeler * interrupt is UNPREDICTABLE. We choose to handle it as if AckCtl == 1, 449f9c6a7f1SFabian Aggeler * i.e. go ahead and complete the irq anyway. 450f9c6a7f1SFabian Aggeler */ 451f9c6a7f1SFabian Aggeler 4529ee6e8bbSpbrook if (irq != s->running_irq[cpu]) { 453e69954b9Spbrook /* Complete an IRQ that is not currently running. */ 4549ee6e8bbSpbrook int tmp = s->running_irq[cpu]; 4559ee6e8bbSpbrook while (s->last_active[tmp][cpu] != 1023) { 4569ee6e8bbSpbrook if (s->last_active[tmp][cpu] == irq) { 4579ee6e8bbSpbrook s->last_active[tmp][cpu] = s->last_active[irq][cpu]; 458e69954b9Spbrook break; 459e69954b9Spbrook } 4609ee6e8bbSpbrook tmp = s->last_active[tmp][cpu]; 461e69954b9Spbrook } 462e69954b9Spbrook if (update) { 463e69954b9Spbrook gic_update(s); 464e69954b9Spbrook } 465e69954b9Spbrook } else { 466e69954b9Spbrook /* Complete the current running IRQ. */ 4679ee6e8bbSpbrook gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]); 468e69954b9Spbrook } 469e69954b9Spbrook } 470e69954b9Spbrook 471a9d85353SPeter Maydell static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) 472e69954b9Spbrook { 473fae15286SPeter Maydell GICState *s = (GICState *)opaque; 474e69954b9Spbrook uint32_t res; 475e69954b9Spbrook int irq; 476e69954b9Spbrook int i; 4779ee6e8bbSpbrook int cpu; 4789ee6e8bbSpbrook int cm; 4799ee6e8bbSpbrook int mask; 480e69954b9Spbrook 481926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 4829ee6e8bbSpbrook cm = 1 << cpu; 483e69954b9Spbrook if (offset < 0x100) { 484679aa175SFabian Aggeler if (offset == 0) { /* GICD_CTLR */ 485679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 486679aa175SFabian Aggeler /* The NS bank of this register is just an alias of the 487679aa175SFabian Aggeler * EnableGrp1 bit in the S bank version. 488679aa175SFabian Aggeler */ 489679aa175SFabian Aggeler return extract32(s->ctlr, 1, 1); 490679aa175SFabian Aggeler } else { 491679aa175SFabian Aggeler return s->ctlr; 492679aa175SFabian Aggeler } 493679aa175SFabian Aggeler } 494e69954b9Spbrook if (offset == 4) 4955543d1abSFabian Aggeler /* Interrupt Controller Type Register */ 4965543d1abSFabian Aggeler return ((s->num_irq / 32) - 1) 4975543d1abSFabian Aggeler | ((NUM_CPU(s) - 1) << 5) 4985543d1abSFabian Aggeler | (s->security_extn << 10); 499e69954b9Spbrook if (offset < 0x08) 500e69954b9Spbrook return 0; 501b79f2265SRob Herring if (offset >= 0x80) { 502c27a5ba9SFabian Aggeler /* Interrupt Group Registers: these RAZ/WI if this is an NS 503c27a5ba9SFabian Aggeler * access to a GIC with the security extensions, or if the GIC 504c27a5ba9SFabian Aggeler * doesn't have groups at all. 505c27a5ba9SFabian Aggeler */ 506c27a5ba9SFabian Aggeler res = 0; 507c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 508c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 509c27a5ba9SFabian Aggeler irq = (offset - 0x080) * 8 + GIC_BASE_IRQ; 510c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 511c27a5ba9SFabian Aggeler goto bad_reg; 512c27a5ba9SFabian Aggeler } 513c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 514c27a5ba9SFabian Aggeler if (GIC_TEST_GROUP(irq + i, cm)) { 515c27a5ba9SFabian Aggeler res |= (1 << i); 516c27a5ba9SFabian Aggeler } 517c27a5ba9SFabian Aggeler } 518c27a5ba9SFabian Aggeler } 519c27a5ba9SFabian Aggeler return res; 520b79f2265SRob Herring } 521e69954b9Spbrook goto bad_reg; 522e69954b9Spbrook } else if (offset < 0x200) { 523e69954b9Spbrook /* Interrupt Set/Clear Enable. */ 524e69954b9Spbrook if (offset < 0x180) 525e69954b9Spbrook irq = (offset - 0x100) * 8; 526e69954b9Spbrook else 527e69954b9Spbrook irq = (offset - 0x180) * 8; 5289ee6e8bbSpbrook irq += GIC_BASE_IRQ; 529a32134aaSMark Langsdorf if (irq >= s->num_irq) 530e69954b9Spbrook goto bad_reg; 531e69954b9Spbrook res = 0; 532e69954b9Spbrook for (i = 0; i < 8; i++) { 53341bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 534e69954b9Spbrook res |= (1 << i); 535e69954b9Spbrook } 536e69954b9Spbrook } 537e69954b9Spbrook } else if (offset < 0x300) { 538e69954b9Spbrook /* Interrupt Set/Clear Pending. */ 539e69954b9Spbrook if (offset < 0x280) 540e69954b9Spbrook irq = (offset - 0x200) * 8; 541e69954b9Spbrook else 542e69954b9Spbrook irq = (offset - 0x280) * 8; 5439ee6e8bbSpbrook irq += GIC_BASE_IRQ; 544a32134aaSMark Langsdorf if (irq >= s->num_irq) 545e69954b9Spbrook goto bad_reg; 546e69954b9Spbrook res = 0; 54769253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 548e69954b9Spbrook for (i = 0; i < 8; i++) { 5498d999995SChristoffer Dall if (gic_test_pending(s, irq + i, mask)) { 550e69954b9Spbrook res |= (1 << i); 551e69954b9Spbrook } 552e69954b9Spbrook } 553e69954b9Spbrook } else if (offset < 0x400) { 554e69954b9Spbrook /* Interrupt Active. */ 5559ee6e8bbSpbrook irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 556a32134aaSMark Langsdorf if (irq >= s->num_irq) 557e69954b9Spbrook goto bad_reg; 558e69954b9Spbrook res = 0; 55969253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 560e69954b9Spbrook for (i = 0; i < 8; i++) { 5619ee6e8bbSpbrook if (GIC_TEST_ACTIVE(irq + i, mask)) { 562e69954b9Spbrook res |= (1 << i); 563e69954b9Spbrook } 564e69954b9Spbrook } 565e69954b9Spbrook } else if (offset < 0x800) { 566e69954b9Spbrook /* Interrupt Priority. */ 5679ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 568a32134aaSMark Langsdorf if (irq >= s->num_irq) 569e69954b9Spbrook goto bad_reg; 57081508470SFabian Aggeler res = gic_get_priority(s, cpu, irq, attrs); 571e69954b9Spbrook } else if (offset < 0xc00) { 572e69954b9Spbrook /* Interrupt CPU Target. */ 5736b9680bbSPeter Maydell if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { 5746b9680bbSPeter Maydell /* For uniprocessor GICs these RAZ/WI */ 5756b9680bbSPeter Maydell res = 0; 5766b9680bbSPeter Maydell } else { 5779ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 5786b9680bbSPeter Maydell if (irq >= s->num_irq) { 579e69954b9Spbrook goto bad_reg; 5806b9680bbSPeter Maydell } 5819ee6e8bbSpbrook if (irq >= 29 && irq <= 31) { 5829ee6e8bbSpbrook res = cm; 5839ee6e8bbSpbrook } else { 5849ee6e8bbSpbrook res = GIC_TARGET(irq); 5859ee6e8bbSpbrook } 5866b9680bbSPeter Maydell } 587e69954b9Spbrook } else if (offset < 0xf00) { 588e69954b9Spbrook /* Interrupt Configuration. */ 58971a62046SAdam Lackorzynski irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 590a32134aaSMark Langsdorf if (irq >= s->num_irq) 591e69954b9Spbrook goto bad_reg; 592e69954b9Spbrook res = 0; 593e69954b9Spbrook for (i = 0; i < 4; i++) { 594e69954b9Spbrook if (GIC_TEST_MODEL(irq + i)) 595e69954b9Spbrook res |= (1 << (i * 2)); 59604050c5cSChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq + i)) 597e69954b9Spbrook res |= (2 << (i * 2)); 598e69954b9Spbrook } 59940d22500SChristoffer Dall } else if (offset < 0xf10) { 60040d22500SChristoffer Dall goto bad_reg; 60140d22500SChristoffer Dall } else if (offset < 0xf30) { 60240d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 60340d22500SChristoffer Dall goto bad_reg; 60440d22500SChristoffer Dall } 60540d22500SChristoffer Dall 60640d22500SChristoffer Dall if (offset < 0xf20) { 60740d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 60840d22500SChristoffer Dall irq = (offset - 0xf10); 60940d22500SChristoffer Dall } else { 61040d22500SChristoffer Dall irq = (offset - 0xf20); 61140d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 61240d22500SChristoffer Dall } 61340d22500SChristoffer Dall 61440d22500SChristoffer Dall res = s->sgi_pending[irq][cpu]; 615e69954b9Spbrook } else if (offset < 0xfe0) { 616e69954b9Spbrook goto bad_reg; 617e69954b9Spbrook } else /* offset >= 0xfe0 */ { 618e69954b9Spbrook if (offset & 3) { 619e69954b9Spbrook res = 0; 620e69954b9Spbrook } else { 621e69954b9Spbrook res = gic_id[(offset - 0xfe0) >> 2]; 622e69954b9Spbrook } 623e69954b9Spbrook } 624e69954b9Spbrook return res; 625e69954b9Spbrook bad_reg: 6268c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 6278c8dc39fSPeter Maydell "gic_dist_readb: Bad offset %x\n", (int)offset); 628e69954b9Spbrook return 0; 629e69954b9Spbrook } 630e69954b9Spbrook 631a9d85353SPeter Maydell static MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data, 632a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 633e69954b9Spbrook { 634a9d85353SPeter Maydell switch (size) { 635a9d85353SPeter Maydell case 1: 636a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 637a9d85353SPeter Maydell return MEMTX_OK; 638a9d85353SPeter Maydell case 2: 639a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 640a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 641a9d85353SPeter Maydell return MEMTX_OK; 642a9d85353SPeter Maydell case 4: 643a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 644a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 645a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 2, attrs) << 16; 646a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 3, attrs) << 24; 647a9d85353SPeter Maydell return MEMTX_OK; 648a9d85353SPeter Maydell default: 649a9d85353SPeter Maydell return MEMTX_ERROR; 650e69954b9Spbrook } 651e69954b9Spbrook } 652e69954b9Spbrook 653a8170e5eSAvi Kivity static void gic_dist_writeb(void *opaque, hwaddr offset, 654a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 655e69954b9Spbrook { 656fae15286SPeter Maydell GICState *s = (GICState *)opaque; 657e69954b9Spbrook int irq; 658e69954b9Spbrook int i; 6599ee6e8bbSpbrook int cpu; 660e69954b9Spbrook 661926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 662e69954b9Spbrook if (offset < 0x100) { 663e69954b9Spbrook if (offset == 0) { 664679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 665679aa175SFabian Aggeler /* NS version is just an alias of the S version's bit 1 */ 666679aa175SFabian Aggeler s->ctlr = deposit32(s->ctlr, 1, 1, value); 667679aa175SFabian Aggeler } else if (gic_has_groups(s)) { 668679aa175SFabian Aggeler s->ctlr = value & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1); 669679aa175SFabian Aggeler } else { 670679aa175SFabian Aggeler s->ctlr = value & GICD_CTLR_EN_GRP0; 671679aa175SFabian Aggeler } 672679aa175SFabian Aggeler DPRINTF("Distributor: Group0 %sabled; Group 1 %sabled\n", 673679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP0 ? "En" : "Dis", 674679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP1 ? "En" : "Dis"); 675e69954b9Spbrook } else if (offset < 4) { 676e69954b9Spbrook /* ignored. */ 677b79f2265SRob Herring } else if (offset >= 0x80) { 678c27a5ba9SFabian Aggeler /* Interrupt Group Registers: RAZ/WI for NS access to secure 679c27a5ba9SFabian Aggeler * GIC, or for GICs without groups. 680c27a5ba9SFabian Aggeler */ 681c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 682c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 683c27a5ba9SFabian Aggeler irq = (offset - 0x80) * 8 + GIC_BASE_IRQ; 684c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 685c27a5ba9SFabian Aggeler goto bad_reg; 686c27a5ba9SFabian Aggeler } 687c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 688c27a5ba9SFabian Aggeler /* Group bits are banked for private interrupts */ 689c27a5ba9SFabian Aggeler int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 690c27a5ba9SFabian Aggeler if (value & (1 << i)) { 691c27a5ba9SFabian Aggeler /* Group1 (Non-secure) */ 692c27a5ba9SFabian Aggeler GIC_SET_GROUP(irq + i, cm); 693c27a5ba9SFabian Aggeler } else { 694c27a5ba9SFabian Aggeler /* Group0 (Secure) */ 695c27a5ba9SFabian Aggeler GIC_CLEAR_GROUP(irq + i, cm); 696c27a5ba9SFabian Aggeler } 697c27a5ba9SFabian Aggeler } 698c27a5ba9SFabian Aggeler } 699e69954b9Spbrook } else { 700e69954b9Spbrook goto bad_reg; 701e69954b9Spbrook } 702e69954b9Spbrook } else if (offset < 0x180) { 703e69954b9Spbrook /* Interrupt Set Enable. */ 7049ee6e8bbSpbrook irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 705a32134aaSMark Langsdorf if (irq >= s->num_irq) 706e69954b9Spbrook goto bad_reg; 70741ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 7089ee6e8bbSpbrook value = 0xff; 70941ab7b55SChristoffer Dall } 71041ab7b55SChristoffer Dall 711e69954b9Spbrook for (i = 0; i < 8; i++) { 712e69954b9Spbrook if (value & (1 << i)) { 713f47b48fbSDaniel Sangorrin int mask = 714f47b48fbSDaniel Sangorrin (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i); 71569253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 71641bf234dSRabin Vincent 71741bf234dSRabin Vincent if (!GIC_TEST_ENABLED(irq + i, cm)) { 718e69954b9Spbrook DPRINTF("Enabled IRQ %d\n", irq + i); 71941bf234dSRabin Vincent } 72041bf234dSRabin Vincent GIC_SET_ENABLED(irq + i, cm); 721e69954b9Spbrook /* If a raised level triggered IRQ enabled then mark 722e69954b9Spbrook is as pending. */ 7239ee6e8bbSpbrook if (GIC_TEST_LEVEL(irq + i, mask) 72404050c5cSChristoffer Dall && !GIC_TEST_EDGE_TRIGGER(irq + i)) { 7259ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq + i, mask); 7269ee6e8bbSpbrook GIC_SET_PENDING(irq + i, mask); 7279ee6e8bbSpbrook } 728e69954b9Spbrook } 729e69954b9Spbrook } 730e69954b9Spbrook } else if (offset < 0x200) { 731e69954b9Spbrook /* Interrupt Clear Enable. */ 7329ee6e8bbSpbrook irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 733a32134aaSMark Langsdorf if (irq >= s->num_irq) 734e69954b9Spbrook goto bad_reg; 73541ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 7369ee6e8bbSpbrook value = 0; 73741ab7b55SChristoffer Dall } 73841ab7b55SChristoffer Dall 739e69954b9Spbrook for (i = 0; i < 8; i++) { 740e69954b9Spbrook if (value & (1 << i)) { 74169253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 74241bf234dSRabin Vincent 74341bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 744e69954b9Spbrook DPRINTF("Disabled IRQ %d\n", irq + i); 74541bf234dSRabin Vincent } 74641bf234dSRabin Vincent GIC_CLEAR_ENABLED(irq + i, cm); 747e69954b9Spbrook } 748e69954b9Spbrook } 749e69954b9Spbrook } else if (offset < 0x280) { 750e69954b9Spbrook /* Interrupt Set Pending. */ 7519ee6e8bbSpbrook irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 752a32134aaSMark Langsdorf if (irq >= s->num_irq) 753e69954b9Spbrook goto bad_reg; 75441ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 7555b0adce1SChristoffer Dall value = 0; 75641ab7b55SChristoffer Dall } 7579ee6e8bbSpbrook 758e69954b9Spbrook for (i = 0; i < 8; i++) { 759e69954b9Spbrook if (value & (1 << i)) { 760f47b48fbSDaniel Sangorrin GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); 761e69954b9Spbrook } 762e69954b9Spbrook } 763e69954b9Spbrook } else if (offset < 0x300) { 764e69954b9Spbrook /* Interrupt Clear Pending. */ 7659ee6e8bbSpbrook irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 766a32134aaSMark Langsdorf if (irq >= s->num_irq) 767e69954b9Spbrook goto bad_reg; 7685b0adce1SChristoffer Dall if (irq < GIC_NR_SGIS) { 7695b0adce1SChristoffer Dall value = 0; 7705b0adce1SChristoffer Dall } 7715b0adce1SChristoffer Dall 772e69954b9Spbrook for (i = 0; i < 8; i++) { 7739ee6e8bbSpbrook /* ??? This currently clears the pending bit for all CPUs, even 7749ee6e8bbSpbrook for per-CPU interrupts. It's unclear whether this is the 7759ee6e8bbSpbrook corect behavior. */ 776e69954b9Spbrook if (value & (1 << i)) { 7779ee6e8bbSpbrook GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 778e69954b9Spbrook } 779e69954b9Spbrook } 780e69954b9Spbrook } else if (offset < 0x400) { 781e69954b9Spbrook /* Interrupt Active. */ 782e69954b9Spbrook goto bad_reg; 783e69954b9Spbrook } else if (offset < 0x800) { 784e69954b9Spbrook /* Interrupt Priority. */ 7859ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 786a32134aaSMark Langsdorf if (irq >= s->num_irq) 787e69954b9Spbrook goto bad_reg; 78881508470SFabian Aggeler gic_set_priority(s, cpu, irq, value, attrs); 789e69954b9Spbrook } else if (offset < 0xc00) { 7906b9680bbSPeter Maydell /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the 7916b9680bbSPeter Maydell * annoying exception of the 11MPCore's GIC. 7926b9680bbSPeter Maydell */ 7936b9680bbSPeter Maydell if (s->num_cpu != 1 || s->revision == REV_11MPCORE) { 7949ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 7956b9680bbSPeter Maydell if (irq >= s->num_irq) { 796e69954b9Spbrook goto bad_reg; 7976b9680bbSPeter Maydell } 7986b9680bbSPeter Maydell if (irq < 29) { 7999ee6e8bbSpbrook value = 0; 8006b9680bbSPeter Maydell } else if (irq < GIC_INTERNAL) { 8019ee6e8bbSpbrook value = ALL_CPU_MASK; 8026b9680bbSPeter Maydell } 8039ee6e8bbSpbrook s->irq_target[irq] = value & ALL_CPU_MASK; 8046b9680bbSPeter Maydell } 805e69954b9Spbrook } else if (offset < 0xf00) { 806e69954b9Spbrook /* Interrupt Configuration. */ 8079ee6e8bbSpbrook irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 808a32134aaSMark Langsdorf if (irq >= s->num_irq) 809e69954b9Spbrook goto bad_reg; 810de7a900fSAdam Lackorzynski if (irq < GIC_NR_SGIS) 8119ee6e8bbSpbrook value |= 0xaa; 812e69954b9Spbrook for (i = 0; i < 4; i++) { 81324b790dfSAdam Lackorzynski if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 814e69954b9Spbrook if (value & (1 << (i * 2))) { 815e69954b9Spbrook GIC_SET_MODEL(irq + i); 816e69954b9Spbrook } else { 817e69954b9Spbrook GIC_CLEAR_MODEL(irq + i); 818e69954b9Spbrook } 81924b790dfSAdam Lackorzynski } 820e69954b9Spbrook if (value & (2 << (i * 2))) { 82104050c5cSChristoffer Dall GIC_SET_EDGE_TRIGGER(irq + i); 822e69954b9Spbrook } else { 82304050c5cSChristoffer Dall GIC_CLEAR_EDGE_TRIGGER(irq + i); 824e69954b9Spbrook } 825e69954b9Spbrook } 82640d22500SChristoffer Dall } else if (offset < 0xf10) { 8279ee6e8bbSpbrook /* 0xf00 is only handled for 32-bit writes. */ 828e69954b9Spbrook goto bad_reg; 82940d22500SChristoffer Dall } else if (offset < 0xf20) { 83040d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 83140d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 83240d22500SChristoffer Dall goto bad_reg; 83340d22500SChristoffer Dall } 83440d22500SChristoffer Dall irq = (offset - 0xf10); 83540d22500SChristoffer Dall 83640d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~value; 83740d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 83840d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, 1 << cpu); 83940d22500SChristoffer Dall } 84040d22500SChristoffer Dall } else if (offset < 0xf30) { 84140d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 84240d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 84340d22500SChristoffer Dall goto bad_reg; 84440d22500SChristoffer Dall } 84540d22500SChristoffer Dall irq = (offset - 0xf20); 84640d22500SChristoffer Dall 84740d22500SChristoffer Dall GIC_SET_PENDING(irq, 1 << cpu); 84840d22500SChristoffer Dall s->sgi_pending[irq][cpu] |= value; 84940d22500SChristoffer Dall } else { 85040d22500SChristoffer Dall goto bad_reg; 851e69954b9Spbrook } 852e69954b9Spbrook gic_update(s); 853e69954b9Spbrook return; 854e69954b9Spbrook bad_reg: 8558c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 8568c8dc39fSPeter Maydell "gic_dist_writeb: Bad offset %x\n", (int)offset); 857e69954b9Spbrook } 858e69954b9Spbrook 859a8170e5eSAvi Kivity static void gic_dist_writew(void *opaque, hwaddr offset, 860a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 861e69954b9Spbrook { 862a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, value & 0xff, attrs); 863a9d85353SPeter Maydell gic_dist_writeb(opaque, offset + 1, value >> 8, attrs); 864e69954b9Spbrook } 865e69954b9Spbrook 866a8170e5eSAvi Kivity static void gic_dist_writel(void *opaque, hwaddr offset, 867a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 868e69954b9Spbrook { 869fae15286SPeter Maydell GICState *s = (GICState *)opaque; 8708da3ff18Spbrook if (offset == 0xf00) { 8719ee6e8bbSpbrook int cpu; 8729ee6e8bbSpbrook int irq; 8739ee6e8bbSpbrook int mask; 87440d22500SChristoffer Dall int target_cpu; 8759ee6e8bbSpbrook 876926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 8779ee6e8bbSpbrook irq = value & 0x3ff; 8789ee6e8bbSpbrook switch ((value >> 24) & 3) { 8799ee6e8bbSpbrook case 0: 8809ee6e8bbSpbrook mask = (value >> 16) & ALL_CPU_MASK; 8819ee6e8bbSpbrook break; 8829ee6e8bbSpbrook case 1: 883fa250144SAdam Lackorzynski mask = ALL_CPU_MASK ^ (1 << cpu); 8849ee6e8bbSpbrook break; 8859ee6e8bbSpbrook case 2: 886fa250144SAdam Lackorzynski mask = 1 << cpu; 8879ee6e8bbSpbrook break; 8889ee6e8bbSpbrook default: 8899ee6e8bbSpbrook DPRINTF("Bad Soft Int target filter\n"); 8909ee6e8bbSpbrook mask = ALL_CPU_MASK; 8919ee6e8bbSpbrook break; 8929ee6e8bbSpbrook } 8939ee6e8bbSpbrook GIC_SET_PENDING(irq, mask); 89440d22500SChristoffer Dall target_cpu = ctz32(mask); 89540d22500SChristoffer Dall while (target_cpu < GIC_NCPU) { 89640d22500SChristoffer Dall s->sgi_pending[irq][target_cpu] |= (1 << cpu); 89740d22500SChristoffer Dall mask &= ~(1 << target_cpu); 89840d22500SChristoffer Dall target_cpu = ctz32(mask); 89940d22500SChristoffer Dall } 9009ee6e8bbSpbrook gic_update(s); 9019ee6e8bbSpbrook return; 9029ee6e8bbSpbrook } 903a9d85353SPeter Maydell gic_dist_writew(opaque, offset, value & 0xffff, attrs); 904a9d85353SPeter Maydell gic_dist_writew(opaque, offset + 2, value >> 16, attrs); 905a9d85353SPeter Maydell } 906a9d85353SPeter Maydell 907a9d85353SPeter Maydell static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data, 908a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 909a9d85353SPeter Maydell { 910a9d85353SPeter Maydell switch (size) { 911a9d85353SPeter Maydell case 1: 912a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, data, attrs); 913a9d85353SPeter Maydell return MEMTX_OK; 914a9d85353SPeter Maydell case 2: 915a9d85353SPeter Maydell gic_dist_writew(opaque, offset, data, attrs); 916a9d85353SPeter Maydell return MEMTX_OK; 917a9d85353SPeter Maydell case 4: 918a9d85353SPeter Maydell gic_dist_writel(opaque, offset, data, attrs); 919a9d85353SPeter Maydell return MEMTX_OK; 920a9d85353SPeter Maydell default: 921a9d85353SPeter Maydell return MEMTX_ERROR; 922a9d85353SPeter Maydell } 923e69954b9Spbrook } 924e69954b9Spbrook 925755c0802SAvi Kivity static const MemoryRegionOps gic_dist_ops = { 926a9d85353SPeter Maydell .read_with_attrs = gic_dist_read, 927a9d85353SPeter Maydell .write_with_attrs = gic_dist_write, 928755c0802SAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 929e69954b9Spbrook }; 930e69954b9Spbrook 931a9d85353SPeter Maydell static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, 932a9d85353SPeter Maydell uint64_t *data, MemTxAttrs attrs) 933e69954b9Spbrook { 934e69954b9Spbrook switch (offset) { 935e69954b9Spbrook case 0x00: /* Control */ 93632951860SFabian Aggeler *data = gic_get_cpu_control(s, cpu, attrs); 937a9d85353SPeter Maydell break; 938e69954b9Spbrook case 0x04: /* Priority mask */ 93981508470SFabian Aggeler *data = gic_get_priority_mask(s, cpu, attrs); 940a9d85353SPeter Maydell break; 941e69954b9Spbrook case 0x08: /* Binary Point */ 942822e9cc3SFabian Aggeler if (s->security_extn && !attrs.secure) { 943822e9cc3SFabian Aggeler /* BPR is banked. Non-secure copy stored in ABPR. */ 944822e9cc3SFabian Aggeler *data = s->abpr[cpu]; 945822e9cc3SFabian Aggeler } else { 946a9d85353SPeter Maydell *data = s->bpr[cpu]; 947822e9cc3SFabian Aggeler } 948a9d85353SPeter Maydell break; 949e69954b9Spbrook case 0x0c: /* Acknowledge */ 950c5619bf9SFabian Aggeler *data = gic_acknowledge_irq(s, cpu, attrs); 951a9d85353SPeter Maydell break; 95266a0a2cbSDong Xu Wang case 0x14: /* Running Priority */ 95308efa9f2SFabian Aggeler *data = gic_get_running_priority(s, cpu, attrs); 954a9d85353SPeter Maydell break; 955e69954b9Spbrook case 0x18: /* Highest Pending Interrupt */ 9567c0fa108SFabian Aggeler *data = gic_get_current_pending_irq(s, cpu, attrs); 957a9d85353SPeter Maydell break; 958aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 959822e9cc3SFabian Aggeler /* GIC v2, no security: ABPR 960822e9cc3SFabian Aggeler * GIC v1, no security: not implemented (RAZ/WI) 961822e9cc3SFabian Aggeler * With security extensions, secure access: ABPR (alias of NS BPR) 962822e9cc3SFabian Aggeler * With security extensions, nonsecure access: RAZ/WI 963822e9cc3SFabian Aggeler */ 964822e9cc3SFabian Aggeler if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 965822e9cc3SFabian Aggeler *data = 0; 966822e9cc3SFabian Aggeler } else { 967a9d85353SPeter Maydell *data = s->abpr[cpu]; 968822e9cc3SFabian Aggeler } 969a9d85353SPeter Maydell break; 970a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 971a9d85353SPeter Maydell *data = s->apr[(offset - 0xd0) / 4][cpu]; 972a9d85353SPeter Maydell break; 973e69954b9Spbrook default: 9748c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 9758c8dc39fSPeter Maydell "gic_cpu_read: Bad offset %x\n", (int)offset); 976a9d85353SPeter Maydell return MEMTX_ERROR; 977e69954b9Spbrook } 978a9d85353SPeter Maydell return MEMTX_OK; 979e69954b9Spbrook } 980e69954b9Spbrook 981a9d85353SPeter Maydell static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, 982a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 983e69954b9Spbrook { 984e69954b9Spbrook switch (offset) { 985e69954b9Spbrook case 0x00: /* Control */ 98632951860SFabian Aggeler gic_set_cpu_control(s, cpu, value, attrs); 987e69954b9Spbrook break; 988e69954b9Spbrook case 0x04: /* Priority mask */ 98981508470SFabian Aggeler gic_set_priority_mask(s, cpu, value, attrs); 990e69954b9Spbrook break; 991e69954b9Spbrook case 0x08: /* Binary Point */ 992822e9cc3SFabian Aggeler if (s->security_extn && !attrs.secure) { 993822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 994822e9cc3SFabian Aggeler } else { 995822e9cc3SFabian Aggeler s->bpr[cpu] = MAX(value & 0x7, GIC_MIN_BPR); 996822e9cc3SFabian Aggeler } 997e69954b9Spbrook break; 998e69954b9Spbrook case 0x10: /* End Of Interrupt */ 999f9c6a7f1SFabian Aggeler gic_complete_irq(s, cpu, value & 0x3ff, attrs); 1000a9d85353SPeter Maydell return MEMTX_OK; 1001aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 1002822e9cc3SFabian Aggeler if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 1003822e9cc3SFabian Aggeler /* unimplemented, or NS access: RAZ/WI */ 1004822e9cc3SFabian Aggeler return MEMTX_OK; 1005822e9cc3SFabian Aggeler } else { 1006822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 1007aa7d461aSChristoffer Dall } 1008aa7d461aSChristoffer Dall break; 1009a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 1010a9d477c4SChristoffer Dall qemu_log_mask(LOG_UNIMP, "Writing APR not implemented\n"); 1011a9d477c4SChristoffer Dall break; 1012e69954b9Spbrook default: 10138c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 10148c8dc39fSPeter Maydell "gic_cpu_write: Bad offset %x\n", (int)offset); 1015a9d85353SPeter Maydell return MEMTX_ERROR; 1016e69954b9Spbrook } 1017e69954b9Spbrook gic_update(s); 1018a9d85353SPeter Maydell return MEMTX_OK; 1019e69954b9Spbrook } 1020e2c56465SPeter Maydell 1021e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for the current CPU */ 1022a9d85353SPeter Maydell static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data, 1023a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1024e2c56465SPeter Maydell { 1025fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1026a9d85353SPeter Maydell return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs); 1027e2c56465SPeter Maydell } 1028e2c56465SPeter Maydell 1029a9d85353SPeter Maydell static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr, 1030a9d85353SPeter Maydell uint64_t value, unsigned size, 1031a9d85353SPeter Maydell MemTxAttrs attrs) 1032e2c56465SPeter Maydell { 1033fae15286SPeter Maydell GICState *s = (GICState *)opaque; 1034a9d85353SPeter Maydell return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs); 1035e2c56465SPeter Maydell } 1036e2c56465SPeter Maydell 1037e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for a specific CPU. 1038fae15286SPeter Maydell * These just decode the opaque pointer into GICState* + cpu id. 1039e2c56465SPeter Maydell */ 1040a9d85353SPeter Maydell static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data, 1041a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 1042e2c56465SPeter Maydell { 1043fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1044fae15286SPeter Maydell GICState *s = *backref; 1045e2c56465SPeter Maydell int id = (backref - s->backref); 1046a9d85353SPeter Maydell return gic_cpu_read(s, id, addr, data, attrs); 1047e2c56465SPeter Maydell } 1048e2c56465SPeter Maydell 1049a9d85353SPeter Maydell static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr, 1050a9d85353SPeter Maydell uint64_t value, unsigned size, 1051a9d85353SPeter Maydell MemTxAttrs attrs) 1052e2c56465SPeter Maydell { 1053fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 1054fae15286SPeter Maydell GICState *s = *backref; 1055e2c56465SPeter Maydell int id = (backref - s->backref); 1056a9d85353SPeter Maydell return gic_cpu_write(s, id, addr, value, attrs); 1057e2c56465SPeter Maydell } 1058e2c56465SPeter Maydell 1059e2c56465SPeter Maydell static const MemoryRegionOps gic_thiscpu_ops = { 1060a9d85353SPeter Maydell .read_with_attrs = gic_thiscpu_read, 1061a9d85353SPeter Maydell .write_with_attrs = gic_thiscpu_write, 1062e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 1063e2c56465SPeter Maydell }; 1064e2c56465SPeter Maydell 1065e2c56465SPeter Maydell static const MemoryRegionOps gic_cpu_ops = { 1066a9d85353SPeter Maydell .read_with_attrs = gic_do_cpu_read, 1067a9d85353SPeter Maydell .write_with_attrs = gic_do_cpu_write, 1068e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 1069e2c56465SPeter Maydell }; 1070e69954b9Spbrook 10717b95a508SKONRAD Frederic void gic_init_irqs_and_distributor(GICState *s) 1072e69954b9Spbrook { 1073285b4432SAndreas Färber SysBusDevice *sbd = SYS_BUS_DEVICE(s); 10749ee6e8bbSpbrook int i; 1075e69954b9Spbrook 1076544d1afaSPeter Maydell i = s->num_irq - GIC_INTERNAL; 1077544d1afaSPeter Maydell /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU. 1078544d1afaSPeter Maydell * GPIO array layout is thus: 1079544d1afaSPeter Maydell * [0..N-1] SPIs 1080544d1afaSPeter Maydell * [N..N+31] PPIs for CPU 0 1081544d1afaSPeter Maydell * [N+32..N+63] PPIs for CPU 1 1082544d1afaSPeter Maydell * ... 1083544d1afaSPeter Maydell */ 108484e4fccbSPeter Maydell if (s->revision != REV_NVIC) { 1085c48c6522SPeter Maydell i += (GIC_INTERNAL * s->num_cpu); 108684e4fccbSPeter Maydell } 1087285b4432SAndreas Färber qdev_init_gpio_in(DEVICE(s), gic_set_irq, i); 1088c988bfadSPaul Brook for (i = 0; i < NUM_CPU(s); i++) { 1089285b4432SAndreas Färber sysbus_init_irq(sbd, &s->parent_irq[i]); 10909ee6e8bbSpbrook } 109144f55296SFabian Aggeler for (i = 0; i < NUM_CPU(s); i++) { 109244f55296SFabian Aggeler sysbus_init_irq(sbd, &s->parent_fiq[i]); 109344f55296SFabian Aggeler } 10941437c94bSPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s, 10951437c94bSPaolo Bonzini "gic_dist", 0x1000); 10962b518c56SPeter Maydell } 10972b518c56SPeter Maydell 109853111180SPeter Maydell static void arm_gic_realize(DeviceState *dev, Error **errp) 10992b518c56SPeter Maydell { 110053111180SPeter Maydell /* Device instance realize function for the GIC sysbus device */ 11012b518c56SPeter Maydell int i; 110253111180SPeter Maydell GICState *s = ARM_GIC(dev); 110353111180SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 11041e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_GET_CLASS(s); 11050175ba10SMarkus Armbruster Error *local_err = NULL; 11061e8cae4dSPeter Maydell 11070175ba10SMarkus Armbruster agc->parent_realize(dev, &local_err); 11080175ba10SMarkus Armbruster if (local_err) { 11090175ba10SMarkus Armbruster error_propagate(errp, local_err); 111053111180SPeter Maydell return; 111153111180SPeter Maydell } 11121e8cae4dSPeter Maydell 11137b95a508SKONRAD Frederic gic_init_irqs_and_distributor(s); 11142b518c56SPeter Maydell 1115e2c56465SPeter Maydell /* Memory regions for the CPU interfaces (NVIC doesn't have these): 1116e2c56465SPeter Maydell * a region for "CPU interface for this core", then a region for 1117e2c56465SPeter Maydell * "CPU interface for core 0", "for core 1", ... 1118e2c56465SPeter Maydell * NB that the memory region size of 0x100 applies for the 11MPCore 1119e2c56465SPeter Maydell * and also cores following the GIC v1 spec (ie A9). 1120e2c56465SPeter Maydell * GIC v2 defines a larger memory region (0x1000) so this will need 1121e2c56465SPeter Maydell * to be extended when we implement A15. 1122e2c56465SPeter Maydell */ 11231437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s, 1124e2c56465SPeter Maydell "gic_cpu", 0x100); 1125e2c56465SPeter Maydell for (i = 0; i < NUM_CPU(s); i++) { 1126e2c56465SPeter Maydell s->backref[i] = s; 11271437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, 11281437c94bSPaolo Bonzini &s->backref[i], "gic_cpu", 0x100); 1129e2c56465SPeter Maydell } 1130496dbcd1SPeter Maydell /* Distributor */ 113153111180SPeter Maydell sysbus_init_mmio(sbd, &s->iomem); 1132496dbcd1SPeter Maydell /* cpu interfaces (one for "current cpu" plus one per cpu) */ 1133496dbcd1SPeter Maydell for (i = 0; i <= NUM_CPU(s); i++) { 113453111180SPeter Maydell sysbus_init_mmio(sbd, &s->cpuiomem[i]); 1135496dbcd1SPeter Maydell } 1136496dbcd1SPeter Maydell } 1137496dbcd1SPeter Maydell 1138496dbcd1SPeter Maydell static void arm_gic_class_init(ObjectClass *klass, void *data) 1139496dbcd1SPeter Maydell { 1140496dbcd1SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 11411e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_CLASS(klass); 114253111180SPeter Maydell 114353111180SPeter Maydell agc->parent_realize = dc->realize; 114453111180SPeter Maydell dc->realize = arm_gic_realize; 1145496dbcd1SPeter Maydell } 1146496dbcd1SPeter Maydell 11478c43a6f0SAndreas Färber static const TypeInfo arm_gic_info = { 11481e8cae4dSPeter Maydell .name = TYPE_ARM_GIC, 11491e8cae4dSPeter Maydell .parent = TYPE_ARM_GIC_COMMON, 1150fae15286SPeter Maydell .instance_size = sizeof(GICState), 1151496dbcd1SPeter Maydell .class_init = arm_gic_class_init, 1152998a74bcSPeter Maydell .class_size = sizeof(ARMGICClass), 1153496dbcd1SPeter Maydell }; 1154496dbcd1SPeter Maydell 1155496dbcd1SPeter Maydell static void arm_gic_register_types(void) 1156496dbcd1SPeter Maydell { 1157496dbcd1SPeter Maydell type_register_static(&arm_gic_info); 1158496dbcd1SPeter Maydell } 1159496dbcd1SPeter Maydell 1160496dbcd1SPeter Maydell type_init(arm_gic_register_types) 1161