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; 639ee6e8bbSpbrook int 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]); 73e69954b9Spbrook return; 74e69954b9Spbrook } 75e69954b9Spbrook best_prio = 0x100; 76e69954b9Spbrook best_irq = 1023; 77a32134aaSMark Langsdorf for (irq = 0; irq < s->num_irq; irq++) { 78b52b81e4SSergey Fedorov if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm) && 79b52b81e4SSergey Fedorov (irq < GIC_INTERNAL || GIC_TARGET(irq) & cm)) { 809ee6e8bbSpbrook if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { 819ee6e8bbSpbrook best_prio = GIC_GET_PRIORITY(irq, cpu); 82e69954b9Spbrook best_irq = irq; 83e69954b9Spbrook } 84e69954b9Spbrook } 85e69954b9Spbrook } 869ee6e8bbSpbrook level = 0; 87cad065f1SPeter Maydell if (best_prio < s->priority_mask[cpu]) { 889ee6e8bbSpbrook s->current_pending[cpu] = best_irq; 899ee6e8bbSpbrook if (best_prio < s->running_priority[cpu]) { 908c815fb3SPeter Crosthwaite DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu); 919ee6e8bbSpbrook level = 1; 92e69954b9Spbrook } 93e69954b9Spbrook } 949ee6e8bbSpbrook qemu_set_irq(s->parent_irq[cpu], level); 959ee6e8bbSpbrook } 96e69954b9Spbrook } 97e69954b9Spbrook 98fae15286SPeter Maydell void gic_set_pending_private(GICState *s, int cpu, int irq) 999ee6e8bbSpbrook { 1009ee6e8bbSpbrook int cm = 1 << cpu; 1019ee6e8bbSpbrook 1028d999995SChristoffer Dall if (gic_test_pending(s, irq, cm)) { 1039ee6e8bbSpbrook return; 1048d999995SChristoffer Dall } 1059ee6e8bbSpbrook 1069ee6e8bbSpbrook DPRINTF("Set %d pending cpu %d\n", irq, cpu); 1079ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 1089ee6e8bbSpbrook gic_update(s); 1099ee6e8bbSpbrook } 1109ee6e8bbSpbrook 1118d999995SChristoffer Dall static void gic_set_irq_11mpcore(GICState *s, int irq, int level, 1128d999995SChristoffer Dall int cm, int target) 1138d999995SChristoffer Dall { 1148d999995SChristoffer Dall if (level) { 1158d999995SChristoffer Dall GIC_SET_LEVEL(irq, cm); 1168d999995SChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) { 1178d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 1188d999995SChristoffer Dall GIC_SET_PENDING(irq, target); 1198d999995SChristoffer Dall } 1208d999995SChristoffer Dall } else { 1218d999995SChristoffer Dall GIC_CLEAR_LEVEL(irq, cm); 1228d999995SChristoffer Dall } 1238d999995SChristoffer Dall } 1248d999995SChristoffer Dall 1258d999995SChristoffer Dall static void gic_set_irq_generic(GICState *s, int irq, int level, 1268d999995SChristoffer Dall int cm, int target) 1278d999995SChristoffer Dall { 1288d999995SChristoffer Dall if (level) { 1298d999995SChristoffer Dall GIC_SET_LEVEL(irq, cm); 1308d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 1318d999995SChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq)) { 1328d999995SChristoffer Dall GIC_SET_PENDING(irq, target); 1338d999995SChristoffer Dall } 1348d999995SChristoffer Dall } else { 1358d999995SChristoffer Dall GIC_CLEAR_LEVEL(irq, cm); 1368d999995SChristoffer Dall } 1378d999995SChristoffer Dall } 1388d999995SChristoffer Dall 1399ee6e8bbSpbrook /* Process a change in an external IRQ input. */ 140e69954b9Spbrook static void gic_set_irq(void *opaque, int irq, int level) 141e69954b9Spbrook { 142544d1afaSPeter Maydell /* Meaning of the 'irq' parameter: 143544d1afaSPeter Maydell * [0..N-1] : external interrupts 144544d1afaSPeter Maydell * [N..N+31] : PPI (internal) interrupts for CPU 0 145544d1afaSPeter Maydell * [N+32..N+63] : PPI (internal interrupts for CPU 1 146544d1afaSPeter Maydell * ... 147544d1afaSPeter Maydell */ 148fae15286SPeter Maydell GICState *s = (GICState *)opaque; 149544d1afaSPeter Maydell int cm, target; 150544d1afaSPeter Maydell if (irq < (s->num_irq - GIC_INTERNAL)) { 151e69954b9Spbrook /* The first external input line is internal interrupt 32. */ 152544d1afaSPeter Maydell cm = ALL_CPU_MASK; 15369253800SRusty Russell irq += GIC_INTERNAL; 154544d1afaSPeter Maydell target = GIC_TARGET(irq); 155544d1afaSPeter Maydell } else { 156544d1afaSPeter Maydell int cpu; 157544d1afaSPeter Maydell irq -= (s->num_irq - GIC_INTERNAL); 158544d1afaSPeter Maydell cpu = irq / GIC_INTERNAL; 159544d1afaSPeter Maydell irq %= GIC_INTERNAL; 160544d1afaSPeter Maydell cm = 1 << cpu; 161544d1afaSPeter Maydell target = cm; 162544d1afaSPeter Maydell } 163544d1afaSPeter Maydell 16440d22500SChristoffer Dall assert(irq >= GIC_NR_SGIS); 16540d22500SChristoffer Dall 166544d1afaSPeter Maydell if (level == GIC_TEST_LEVEL(irq, cm)) { 167e69954b9Spbrook return; 168544d1afaSPeter Maydell } 169e69954b9Spbrook 1708d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 1718d999995SChristoffer Dall gic_set_irq_11mpcore(s, irq, level, cm, target); 172e69954b9Spbrook } else { 1738d999995SChristoffer Dall gic_set_irq_generic(s, irq, level, cm, target); 174e69954b9Spbrook } 1758d999995SChristoffer Dall 176e69954b9Spbrook gic_update(s); 177e69954b9Spbrook } 178e69954b9Spbrook 179fae15286SPeter Maydell static void gic_set_running_irq(GICState *s, int cpu, int irq) 180e69954b9Spbrook { 1819ee6e8bbSpbrook s->running_irq[cpu] = irq; 1829ee6e8bbSpbrook if (irq == 1023) { 1839ee6e8bbSpbrook s->running_priority[cpu] = 0x100; 1849ee6e8bbSpbrook } else { 1859ee6e8bbSpbrook s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu); 1869ee6e8bbSpbrook } 187e69954b9Spbrook gic_update(s); 188e69954b9Spbrook } 189e69954b9Spbrook 190fae15286SPeter Maydell uint32_t gic_acknowledge_irq(GICState *s, int cpu) 191e69954b9Spbrook { 19240d22500SChristoffer Dall int ret, irq, src; 1939ee6e8bbSpbrook int cm = 1 << cpu; 19440d22500SChristoffer Dall irq = s->current_pending[cpu]; 19540d22500SChristoffer Dall if (irq == 1023 19640d22500SChristoffer Dall || GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) { 197e69954b9Spbrook DPRINTF("ACK no pending IRQ\n"); 198e69954b9Spbrook return 1023; 199e69954b9Spbrook } 20040d22500SChristoffer Dall s->last_active[irq][cpu] = s->running_irq[cpu]; 20140d22500SChristoffer Dall 20287316902SPeter Maydell if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 2039ee6e8bbSpbrook /* Clear pending flags for both level and edge triggered interrupts. 20440d22500SChristoffer Dall * Level triggered IRQs will be reasserted once they become inactive. 20540d22500SChristoffer Dall */ 20640d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 20740d22500SChristoffer Dall ret = irq; 20840d22500SChristoffer Dall } else { 20940d22500SChristoffer Dall if (irq < GIC_NR_SGIS) { 21040d22500SChristoffer Dall /* Lookup the source CPU for the SGI and clear this in the 21140d22500SChristoffer Dall * sgi_pending map. Return the src and clear the overall pending 21240d22500SChristoffer Dall * state on this CPU if the SGI is not pending from any CPUs. 21340d22500SChristoffer Dall */ 21440d22500SChristoffer Dall assert(s->sgi_pending[irq][cpu] != 0); 21540d22500SChristoffer Dall src = ctz32(s->sgi_pending[irq][cpu]); 21640d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~(1 << src); 21740d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 21840d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 21940d22500SChristoffer Dall } 22040d22500SChristoffer Dall ret = irq | ((src & 0x7) << 10); 22140d22500SChristoffer Dall } else { 22240d22500SChristoffer Dall /* Clear pending state for both level and edge triggered 22340d22500SChristoffer Dall * interrupts. (level triggered interrupts with an active line 22440d22500SChristoffer Dall * remain pending, see gic_test_pending) 22540d22500SChristoffer Dall */ 22640d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 22740d22500SChristoffer Dall ret = irq; 22840d22500SChristoffer Dall } 22940d22500SChristoffer Dall } 23040d22500SChristoffer Dall 23140d22500SChristoffer Dall gic_set_running_irq(s, cpu, irq); 23240d22500SChristoffer Dall DPRINTF("ACK %d\n", irq); 23340d22500SChristoffer Dall return ret; 234e69954b9Spbrook } 235e69954b9Spbrook 2369df90ad0SChristoffer Dall void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val) 2379df90ad0SChristoffer Dall { 2389df90ad0SChristoffer Dall if (irq < GIC_INTERNAL) { 2399df90ad0SChristoffer Dall s->priority1[irq][cpu] = val; 2409df90ad0SChristoffer Dall } else { 2419df90ad0SChristoffer Dall s->priority2[(irq) - GIC_INTERNAL] = val; 2429df90ad0SChristoffer Dall } 2439df90ad0SChristoffer Dall } 2449df90ad0SChristoffer Dall 24532951860SFabian Aggeler static uint32_t gic_get_cpu_control(GICState *s, int cpu, MemTxAttrs attrs) 24632951860SFabian Aggeler { 24732951860SFabian Aggeler uint32_t ret = s->cpu_ctlr[cpu]; 24832951860SFabian Aggeler 24932951860SFabian Aggeler if (s->security_extn && !attrs.secure) { 25032951860SFabian Aggeler /* Construct the NS banked view of GICC_CTLR from the correct 25132951860SFabian Aggeler * bits of the S banked view. We don't need to move the bypass 25232951860SFabian Aggeler * control bits because we don't implement that (IMPDEF) part 25332951860SFabian Aggeler * of the GIC architecture. 25432951860SFabian Aggeler */ 25532951860SFabian Aggeler ret = (ret & (GICC_CTLR_EN_GRP1 | GICC_CTLR_EOIMODE_NS)) >> 1; 25632951860SFabian Aggeler } 25732951860SFabian Aggeler return ret; 25832951860SFabian Aggeler } 25932951860SFabian Aggeler 26032951860SFabian Aggeler static void gic_set_cpu_control(GICState *s, int cpu, uint32_t value, 26132951860SFabian Aggeler MemTxAttrs attrs) 26232951860SFabian Aggeler { 26332951860SFabian Aggeler uint32_t mask; 26432951860SFabian Aggeler 26532951860SFabian Aggeler if (s->security_extn && !attrs.secure) { 26632951860SFabian Aggeler /* The NS view can only write certain bits in the register; 26732951860SFabian Aggeler * the rest are unchanged 26832951860SFabian Aggeler */ 26932951860SFabian Aggeler mask = GICC_CTLR_EN_GRP1; 27032951860SFabian Aggeler if (s->revision == 2) { 27132951860SFabian Aggeler mask |= GICC_CTLR_EOIMODE_NS; 27232951860SFabian Aggeler } 27332951860SFabian Aggeler s->cpu_ctlr[cpu] &= ~mask; 27432951860SFabian Aggeler s->cpu_ctlr[cpu] |= (value << 1) & mask; 27532951860SFabian Aggeler } else { 27632951860SFabian Aggeler if (s->revision == 2) { 27732951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V2_S_MASK : GICC_CTLR_V2_MASK; 27832951860SFabian Aggeler } else { 27932951860SFabian Aggeler mask = s->security_extn ? GICC_CTLR_V1_S_MASK : GICC_CTLR_V1_MASK; 28032951860SFabian Aggeler } 28132951860SFabian Aggeler s->cpu_ctlr[cpu] = value & mask; 28232951860SFabian Aggeler } 28332951860SFabian Aggeler DPRINTF("CPU Interface %d: Group0 Interrupts %sabled, " 28432951860SFabian Aggeler "Group1 Interrupts %sabled\n", cpu, 28532951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP0) ? "En" : "Dis", 28632951860SFabian Aggeler (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP1) ? "En" : "Dis"); 28732951860SFabian Aggeler } 28832951860SFabian Aggeler 289*08efa9f2SFabian Aggeler static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs) 290*08efa9f2SFabian Aggeler { 291*08efa9f2SFabian Aggeler if (s->security_extn && !attrs.secure) { 292*08efa9f2SFabian Aggeler if (s->running_priority[cpu] & 0x80) { 293*08efa9f2SFabian Aggeler /* Running priority in upper half of range: return the Non-secure 294*08efa9f2SFabian Aggeler * view of the priority. 295*08efa9f2SFabian Aggeler */ 296*08efa9f2SFabian Aggeler return s->running_priority[cpu] << 1; 297*08efa9f2SFabian Aggeler } else { 298*08efa9f2SFabian Aggeler /* Running priority in lower half of range: RAZ */ 299*08efa9f2SFabian Aggeler return 0; 300*08efa9f2SFabian Aggeler } 301*08efa9f2SFabian Aggeler } else { 302*08efa9f2SFabian Aggeler return s->running_priority[cpu]; 303*08efa9f2SFabian Aggeler } 304*08efa9f2SFabian Aggeler } 305*08efa9f2SFabian Aggeler 306fae15286SPeter Maydell void gic_complete_irq(GICState *s, int cpu, int irq) 307e69954b9Spbrook { 308e69954b9Spbrook int update = 0; 3099ee6e8bbSpbrook int cm = 1 << cpu; 310df628ff1Spbrook DPRINTF("EOI %d\n", irq); 311a32134aaSMark Langsdorf if (irq >= s->num_irq) { 312217bfb44SPeter Maydell /* This handles two cases: 313217bfb44SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 314217bfb44SPeter Maydell * to the GICC_EOIR, the GIC ignores that write. 315217bfb44SPeter Maydell * 2. If software writes the number of a non-existent interrupt 316217bfb44SPeter Maydell * this must be a subcase of "value written does not match the last 317217bfb44SPeter Maydell * valid interrupt value read from the Interrupt Acknowledge 318217bfb44SPeter Maydell * register" and so this is UNPREDICTABLE. We choose to ignore it. 319217bfb44SPeter Maydell */ 320217bfb44SPeter Maydell return; 321217bfb44SPeter Maydell } 3229ee6e8bbSpbrook if (s->running_irq[cpu] == 1023) 323e69954b9Spbrook return; /* No active IRQ. */ 3248d999995SChristoffer Dall 3258d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 326e69954b9Spbrook /* Mark level triggered interrupts as pending if they are still 327e69954b9Spbrook raised. */ 32804050c5cSChristoffer Dall if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm) 3299ee6e8bbSpbrook && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) { 3309ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq, cm); 3319ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 332e69954b9Spbrook update = 1; 333e69954b9Spbrook } 3348d999995SChristoffer Dall } 3358d999995SChristoffer Dall 3369ee6e8bbSpbrook if (irq != s->running_irq[cpu]) { 337e69954b9Spbrook /* Complete an IRQ that is not currently running. */ 3389ee6e8bbSpbrook int tmp = s->running_irq[cpu]; 3399ee6e8bbSpbrook while (s->last_active[tmp][cpu] != 1023) { 3409ee6e8bbSpbrook if (s->last_active[tmp][cpu] == irq) { 3419ee6e8bbSpbrook s->last_active[tmp][cpu] = s->last_active[irq][cpu]; 342e69954b9Spbrook break; 343e69954b9Spbrook } 3449ee6e8bbSpbrook tmp = s->last_active[tmp][cpu]; 345e69954b9Spbrook } 346e69954b9Spbrook if (update) { 347e69954b9Spbrook gic_update(s); 348e69954b9Spbrook } 349e69954b9Spbrook } else { 350e69954b9Spbrook /* Complete the current running IRQ. */ 3519ee6e8bbSpbrook gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]); 352e69954b9Spbrook } 353e69954b9Spbrook } 354e69954b9Spbrook 355a9d85353SPeter Maydell static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) 356e69954b9Spbrook { 357fae15286SPeter Maydell GICState *s = (GICState *)opaque; 358e69954b9Spbrook uint32_t res; 359e69954b9Spbrook int irq; 360e69954b9Spbrook int i; 3619ee6e8bbSpbrook int cpu; 3629ee6e8bbSpbrook int cm; 3639ee6e8bbSpbrook int mask; 364e69954b9Spbrook 365926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 3669ee6e8bbSpbrook cm = 1 << cpu; 367e69954b9Spbrook if (offset < 0x100) { 368679aa175SFabian Aggeler if (offset == 0) { /* GICD_CTLR */ 369679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 370679aa175SFabian Aggeler /* The NS bank of this register is just an alias of the 371679aa175SFabian Aggeler * EnableGrp1 bit in the S bank version. 372679aa175SFabian Aggeler */ 373679aa175SFabian Aggeler return extract32(s->ctlr, 1, 1); 374679aa175SFabian Aggeler } else { 375679aa175SFabian Aggeler return s->ctlr; 376679aa175SFabian Aggeler } 377679aa175SFabian Aggeler } 378e69954b9Spbrook if (offset == 4) 3795543d1abSFabian Aggeler /* Interrupt Controller Type Register */ 3805543d1abSFabian Aggeler return ((s->num_irq / 32) - 1) 3815543d1abSFabian Aggeler | ((NUM_CPU(s) - 1) << 5) 3825543d1abSFabian Aggeler | (s->security_extn << 10); 383e69954b9Spbrook if (offset < 0x08) 384e69954b9Spbrook return 0; 385b79f2265SRob Herring if (offset >= 0x80) { 386c27a5ba9SFabian Aggeler /* Interrupt Group Registers: these RAZ/WI if this is an NS 387c27a5ba9SFabian Aggeler * access to a GIC with the security extensions, or if the GIC 388c27a5ba9SFabian Aggeler * doesn't have groups at all. 389c27a5ba9SFabian Aggeler */ 390c27a5ba9SFabian Aggeler res = 0; 391c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 392c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 393c27a5ba9SFabian Aggeler irq = (offset - 0x080) * 8 + GIC_BASE_IRQ; 394c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 395c27a5ba9SFabian Aggeler goto bad_reg; 396c27a5ba9SFabian Aggeler } 397c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 398c27a5ba9SFabian Aggeler if (GIC_TEST_GROUP(irq + i, cm)) { 399c27a5ba9SFabian Aggeler res |= (1 << i); 400c27a5ba9SFabian Aggeler } 401c27a5ba9SFabian Aggeler } 402c27a5ba9SFabian Aggeler } 403c27a5ba9SFabian Aggeler return res; 404b79f2265SRob Herring } 405e69954b9Spbrook goto bad_reg; 406e69954b9Spbrook } else if (offset < 0x200) { 407e69954b9Spbrook /* Interrupt Set/Clear Enable. */ 408e69954b9Spbrook if (offset < 0x180) 409e69954b9Spbrook irq = (offset - 0x100) * 8; 410e69954b9Spbrook else 411e69954b9Spbrook irq = (offset - 0x180) * 8; 4129ee6e8bbSpbrook irq += GIC_BASE_IRQ; 413a32134aaSMark Langsdorf if (irq >= s->num_irq) 414e69954b9Spbrook goto bad_reg; 415e69954b9Spbrook res = 0; 416e69954b9Spbrook for (i = 0; i < 8; i++) { 41741bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 418e69954b9Spbrook res |= (1 << i); 419e69954b9Spbrook } 420e69954b9Spbrook } 421e69954b9Spbrook } else if (offset < 0x300) { 422e69954b9Spbrook /* Interrupt Set/Clear Pending. */ 423e69954b9Spbrook if (offset < 0x280) 424e69954b9Spbrook irq = (offset - 0x200) * 8; 425e69954b9Spbrook else 426e69954b9Spbrook irq = (offset - 0x280) * 8; 4279ee6e8bbSpbrook irq += GIC_BASE_IRQ; 428a32134aaSMark Langsdorf if (irq >= s->num_irq) 429e69954b9Spbrook goto bad_reg; 430e69954b9Spbrook res = 0; 43169253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 432e69954b9Spbrook for (i = 0; i < 8; i++) { 4338d999995SChristoffer Dall if (gic_test_pending(s, irq + i, mask)) { 434e69954b9Spbrook res |= (1 << i); 435e69954b9Spbrook } 436e69954b9Spbrook } 437e69954b9Spbrook } else if (offset < 0x400) { 438e69954b9Spbrook /* Interrupt Active. */ 4399ee6e8bbSpbrook irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 440a32134aaSMark Langsdorf if (irq >= s->num_irq) 441e69954b9Spbrook goto bad_reg; 442e69954b9Spbrook res = 0; 44369253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 444e69954b9Spbrook for (i = 0; i < 8; i++) { 4459ee6e8bbSpbrook if (GIC_TEST_ACTIVE(irq + i, mask)) { 446e69954b9Spbrook res |= (1 << i); 447e69954b9Spbrook } 448e69954b9Spbrook } 449e69954b9Spbrook } else if (offset < 0x800) { 450e69954b9Spbrook /* Interrupt Priority. */ 4519ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 452a32134aaSMark Langsdorf if (irq >= s->num_irq) 453e69954b9Spbrook goto bad_reg; 4549ee6e8bbSpbrook res = GIC_GET_PRIORITY(irq, cpu); 455e69954b9Spbrook } else if (offset < 0xc00) { 456e69954b9Spbrook /* Interrupt CPU Target. */ 4576b9680bbSPeter Maydell if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { 4586b9680bbSPeter Maydell /* For uniprocessor GICs these RAZ/WI */ 4596b9680bbSPeter Maydell res = 0; 4606b9680bbSPeter Maydell } else { 4619ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 4626b9680bbSPeter Maydell if (irq >= s->num_irq) { 463e69954b9Spbrook goto bad_reg; 4646b9680bbSPeter Maydell } 4659ee6e8bbSpbrook if (irq >= 29 && irq <= 31) { 4669ee6e8bbSpbrook res = cm; 4679ee6e8bbSpbrook } else { 4689ee6e8bbSpbrook res = GIC_TARGET(irq); 4699ee6e8bbSpbrook } 4706b9680bbSPeter Maydell } 471e69954b9Spbrook } else if (offset < 0xf00) { 472e69954b9Spbrook /* Interrupt Configuration. */ 47371a62046SAdam Lackorzynski irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 474a32134aaSMark Langsdorf if (irq >= s->num_irq) 475e69954b9Spbrook goto bad_reg; 476e69954b9Spbrook res = 0; 477e69954b9Spbrook for (i = 0; i < 4; i++) { 478e69954b9Spbrook if (GIC_TEST_MODEL(irq + i)) 479e69954b9Spbrook res |= (1 << (i * 2)); 48004050c5cSChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq + i)) 481e69954b9Spbrook res |= (2 << (i * 2)); 482e69954b9Spbrook } 48340d22500SChristoffer Dall } else if (offset < 0xf10) { 48440d22500SChristoffer Dall goto bad_reg; 48540d22500SChristoffer Dall } else if (offset < 0xf30) { 48640d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 48740d22500SChristoffer Dall goto bad_reg; 48840d22500SChristoffer Dall } 48940d22500SChristoffer Dall 49040d22500SChristoffer Dall if (offset < 0xf20) { 49140d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 49240d22500SChristoffer Dall irq = (offset - 0xf10); 49340d22500SChristoffer Dall } else { 49440d22500SChristoffer Dall irq = (offset - 0xf20); 49540d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 49640d22500SChristoffer Dall } 49740d22500SChristoffer Dall 49840d22500SChristoffer Dall res = s->sgi_pending[irq][cpu]; 499e69954b9Spbrook } else if (offset < 0xfe0) { 500e69954b9Spbrook goto bad_reg; 501e69954b9Spbrook } else /* offset >= 0xfe0 */ { 502e69954b9Spbrook if (offset & 3) { 503e69954b9Spbrook res = 0; 504e69954b9Spbrook } else { 505e69954b9Spbrook res = gic_id[(offset - 0xfe0) >> 2]; 506e69954b9Spbrook } 507e69954b9Spbrook } 508e69954b9Spbrook return res; 509e69954b9Spbrook bad_reg: 5108c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 5118c8dc39fSPeter Maydell "gic_dist_readb: Bad offset %x\n", (int)offset); 512e69954b9Spbrook return 0; 513e69954b9Spbrook } 514e69954b9Spbrook 515a9d85353SPeter Maydell static MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data, 516a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 517e69954b9Spbrook { 518a9d85353SPeter Maydell switch (size) { 519a9d85353SPeter Maydell case 1: 520a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 521a9d85353SPeter Maydell return MEMTX_OK; 522a9d85353SPeter Maydell case 2: 523a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 524a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 525a9d85353SPeter Maydell return MEMTX_OK; 526a9d85353SPeter Maydell case 4: 527a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 528a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 529a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 2, attrs) << 16; 530a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 3, attrs) << 24; 531a9d85353SPeter Maydell return MEMTX_OK; 532a9d85353SPeter Maydell default: 533a9d85353SPeter Maydell return MEMTX_ERROR; 534e69954b9Spbrook } 535e69954b9Spbrook } 536e69954b9Spbrook 537a8170e5eSAvi Kivity static void gic_dist_writeb(void *opaque, hwaddr offset, 538a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 539e69954b9Spbrook { 540fae15286SPeter Maydell GICState *s = (GICState *)opaque; 541e69954b9Spbrook int irq; 542e69954b9Spbrook int i; 5439ee6e8bbSpbrook int cpu; 544e69954b9Spbrook 545926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 546e69954b9Spbrook if (offset < 0x100) { 547e69954b9Spbrook if (offset == 0) { 548679aa175SFabian Aggeler if (s->security_extn && !attrs.secure) { 549679aa175SFabian Aggeler /* NS version is just an alias of the S version's bit 1 */ 550679aa175SFabian Aggeler s->ctlr = deposit32(s->ctlr, 1, 1, value); 551679aa175SFabian Aggeler } else if (gic_has_groups(s)) { 552679aa175SFabian Aggeler s->ctlr = value & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1); 553679aa175SFabian Aggeler } else { 554679aa175SFabian Aggeler s->ctlr = value & GICD_CTLR_EN_GRP0; 555679aa175SFabian Aggeler } 556679aa175SFabian Aggeler DPRINTF("Distributor: Group0 %sabled; Group 1 %sabled\n", 557679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP0 ? "En" : "Dis", 558679aa175SFabian Aggeler s->ctlr & GICD_CTLR_EN_GRP1 ? "En" : "Dis"); 559e69954b9Spbrook } else if (offset < 4) { 560e69954b9Spbrook /* ignored. */ 561b79f2265SRob Herring } else if (offset >= 0x80) { 562c27a5ba9SFabian Aggeler /* Interrupt Group Registers: RAZ/WI for NS access to secure 563c27a5ba9SFabian Aggeler * GIC, or for GICs without groups. 564c27a5ba9SFabian Aggeler */ 565c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 566c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 567c27a5ba9SFabian Aggeler irq = (offset - 0x80) * 8 + GIC_BASE_IRQ; 568c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 569c27a5ba9SFabian Aggeler goto bad_reg; 570c27a5ba9SFabian Aggeler } 571c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 572c27a5ba9SFabian Aggeler /* Group bits are banked for private interrupts */ 573c27a5ba9SFabian Aggeler int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 574c27a5ba9SFabian Aggeler if (value & (1 << i)) { 575c27a5ba9SFabian Aggeler /* Group1 (Non-secure) */ 576c27a5ba9SFabian Aggeler GIC_SET_GROUP(irq + i, cm); 577c27a5ba9SFabian Aggeler } else { 578c27a5ba9SFabian Aggeler /* Group0 (Secure) */ 579c27a5ba9SFabian Aggeler GIC_CLEAR_GROUP(irq + i, cm); 580c27a5ba9SFabian Aggeler } 581c27a5ba9SFabian Aggeler } 582c27a5ba9SFabian Aggeler } 583e69954b9Spbrook } else { 584e69954b9Spbrook goto bad_reg; 585e69954b9Spbrook } 586e69954b9Spbrook } else if (offset < 0x180) { 587e69954b9Spbrook /* Interrupt Set Enable. */ 5889ee6e8bbSpbrook irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 589a32134aaSMark Langsdorf if (irq >= s->num_irq) 590e69954b9Spbrook goto bad_reg; 59141ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 5929ee6e8bbSpbrook value = 0xff; 59341ab7b55SChristoffer Dall } 59441ab7b55SChristoffer Dall 595e69954b9Spbrook for (i = 0; i < 8; i++) { 596e69954b9Spbrook if (value & (1 << i)) { 597f47b48fbSDaniel Sangorrin int mask = 598f47b48fbSDaniel Sangorrin (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i); 59969253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 60041bf234dSRabin Vincent 60141bf234dSRabin Vincent if (!GIC_TEST_ENABLED(irq + i, cm)) { 602e69954b9Spbrook DPRINTF("Enabled IRQ %d\n", irq + i); 60341bf234dSRabin Vincent } 60441bf234dSRabin Vincent GIC_SET_ENABLED(irq + i, cm); 605e69954b9Spbrook /* If a raised level triggered IRQ enabled then mark 606e69954b9Spbrook is as pending. */ 6079ee6e8bbSpbrook if (GIC_TEST_LEVEL(irq + i, mask) 60804050c5cSChristoffer Dall && !GIC_TEST_EDGE_TRIGGER(irq + i)) { 6099ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq + i, mask); 6109ee6e8bbSpbrook GIC_SET_PENDING(irq + i, mask); 6119ee6e8bbSpbrook } 612e69954b9Spbrook } 613e69954b9Spbrook } 614e69954b9Spbrook } else if (offset < 0x200) { 615e69954b9Spbrook /* Interrupt Clear Enable. */ 6169ee6e8bbSpbrook irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 617a32134aaSMark Langsdorf if (irq >= s->num_irq) 618e69954b9Spbrook goto bad_reg; 61941ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 6209ee6e8bbSpbrook value = 0; 62141ab7b55SChristoffer Dall } 62241ab7b55SChristoffer Dall 623e69954b9Spbrook for (i = 0; i < 8; i++) { 624e69954b9Spbrook if (value & (1 << i)) { 62569253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 62641bf234dSRabin Vincent 62741bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 628e69954b9Spbrook DPRINTF("Disabled IRQ %d\n", irq + i); 62941bf234dSRabin Vincent } 63041bf234dSRabin Vincent GIC_CLEAR_ENABLED(irq + i, cm); 631e69954b9Spbrook } 632e69954b9Spbrook } 633e69954b9Spbrook } else if (offset < 0x280) { 634e69954b9Spbrook /* Interrupt Set Pending. */ 6359ee6e8bbSpbrook irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 636a32134aaSMark Langsdorf if (irq >= s->num_irq) 637e69954b9Spbrook goto bad_reg; 63841ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 6395b0adce1SChristoffer Dall value = 0; 64041ab7b55SChristoffer Dall } 6419ee6e8bbSpbrook 642e69954b9Spbrook for (i = 0; i < 8; i++) { 643e69954b9Spbrook if (value & (1 << i)) { 644f47b48fbSDaniel Sangorrin GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); 645e69954b9Spbrook } 646e69954b9Spbrook } 647e69954b9Spbrook } else if (offset < 0x300) { 648e69954b9Spbrook /* Interrupt Clear Pending. */ 6499ee6e8bbSpbrook irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 650a32134aaSMark Langsdorf if (irq >= s->num_irq) 651e69954b9Spbrook goto bad_reg; 6525b0adce1SChristoffer Dall if (irq < GIC_NR_SGIS) { 6535b0adce1SChristoffer Dall value = 0; 6545b0adce1SChristoffer Dall } 6555b0adce1SChristoffer Dall 656e69954b9Spbrook for (i = 0; i < 8; i++) { 6579ee6e8bbSpbrook /* ??? This currently clears the pending bit for all CPUs, even 6589ee6e8bbSpbrook for per-CPU interrupts. It's unclear whether this is the 6599ee6e8bbSpbrook corect behavior. */ 660e69954b9Spbrook if (value & (1 << i)) { 6619ee6e8bbSpbrook GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 662e69954b9Spbrook } 663e69954b9Spbrook } 664e69954b9Spbrook } else if (offset < 0x400) { 665e69954b9Spbrook /* Interrupt Active. */ 666e69954b9Spbrook goto bad_reg; 667e69954b9Spbrook } else if (offset < 0x800) { 668e69954b9Spbrook /* Interrupt Priority. */ 6699ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 670a32134aaSMark Langsdorf if (irq >= s->num_irq) 671e69954b9Spbrook goto bad_reg; 6729df90ad0SChristoffer Dall gic_set_priority(s, cpu, irq, value); 673e69954b9Spbrook } else if (offset < 0xc00) { 6746b9680bbSPeter Maydell /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the 6756b9680bbSPeter Maydell * annoying exception of the 11MPCore's GIC. 6766b9680bbSPeter Maydell */ 6776b9680bbSPeter Maydell if (s->num_cpu != 1 || s->revision == REV_11MPCORE) { 6789ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 6796b9680bbSPeter Maydell if (irq >= s->num_irq) { 680e69954b9Spbrook goto bad_reg; 6816b9680bbSPeter Maydell } 6826b9680bbSPeter Maydell if (irq < 29) { 6839ee6e8bbSpbrook value = 0; 6846b9680bbSPeter Maydell } else if (irq < GIC_INTERNAL) { 6859ee6e8bbSpbrook value = ALL_CPU_MASK; 6866b9680bbSPeter Maydell } 6879ee6e8bbSpbrook s->irq_target[irq] = value & ALL_CPU_MASK; 6886b9680bbSPeter Maydell } 689e69954b9Spbrook } else if (offset < 0xf00) { 690e69954b9Spbrook /* Interrupt Configuration. */ 6919ee6e8bbSpbrook irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 692a32134aaSMark Langsdorf if (irq >= s->num_irq) 693e69954b9Spbrook goto bad_reg; 694de7a900fSAdam Lackorzynski if (irq < GIC_NR_SGIS) 6959ee6e8bbSpbrook value |= 0xaa; 696e69954b9Spbrook for (i = 0; i < 4; i++) { 69724b790dfSAdam Lackorzynski if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 698e69954b9Spbrook if (value & (1 << (i * 2))) { 699e69954b9Spbrook GIC_SET_MODEL(irq + i); 700e69954b9Spbrook } else { 701e69954b9Spbrook GIC_CLEAR_MODEL(irq + i); 702e69954b9Spbrook } 70324b790dfSAdam Lackorzynski } 704e69954b9Spbrook if (value & (2 << (i * 2))) { 70504050c5cSChristoffer Dall GIC_SET_EDGE_TRIGGER(irq + i); 706e69954b9Spbrook } else { 70704050c5cSChristoffer Dall GIC_CLEAR_EDGE_TRIGGER(irq + i); 708e69954b9Spbrook } 709e69954b9Spbrook } 71040d22500SChristoffer Dall } else if (offset < 0xf10) { 7119ee6e8bbSpbrook /* 0xf00 is only handled for 32-bit writes. */ 712e69954b9Spbrook goto bad_reg; 71340d22500SChristoffer Dall } else if (offset < 0xf20) { 71440d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 71540d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 71640d22500SChristoffer Dall goto bad_reg; 71740d22500SChristoffer Dall } 71840d22500SChristoffer Dall irq = (offset - 0xf10); 71940d22500SChristoffer Dall 72040d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~value; 72140d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 72240d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, 1 << cpu); 72340d22500SChristoffer Dall } 72440d22500SChristoffer Dall } else if (offset < 0xf30) { 72540d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 72640d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 72740d22500SChristoffer Dall goto bad_reg; 72840d22500SChristoffer Dall } 72940d22500SChristoffer Dall irq = (offset - 0xf20); 73040d22500SChristoffer Dall 73140d22500SChristoffer Dall GIC_SET_PENDING(irq, 1 << cpu); 73240d22500SChristoffer Dall s->sgi_pending[irq][cpu] |= value; 73340d22500SChristoffer Dall } else { 73440d22500SChristoffer Dall goto bad_reg; 735e69954b9Spbrook } 736e69954b9Spbrook gic_update(s); 737e69954b9Spbrook return; 738e69954b9Spbrook bad_reg: 7398c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 7408c8dc39fSPeter Maydell "gic_dist_writeb: Bad offset %x\n", (int)offset); 741e69954b9Spbrook } 742e69954b9Spbrook 743a8170e5eSAvi Kivity static void gic_dist_writew(void *opaque, hwaddr offset, 744a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 745e69954b9Spbrook { 746a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, value & 0xff, attrs); 747a9d85353SPeter Maydell gic_dist_writeb(opaque, offset + 1, value >> 8, attrs); 748e69954b9Spbrook } 749e69954b9Spbrook 750a8170e5eSAvi Kivity static void gic_dist_writel(void *opaque, hwaddr offset, 751a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 752e69954b9Spbrook { 753fae15286SPeter Maydell GICState *s = (GICState *)opaque; 7548da3ff18Spbrook if (offset == 0xf00) { 7559ee6e8bbSpbrook int cpu; 7569ee6e8bbSpbrook int irq; 7579ee6e8bbSpbrook int mask; 75840d22500SChristoffer Dall int target_cpu; 7599ee6e8bbSpbrook 760926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 7619ee6e8bbSpbrook irq = value & 0x3ff; 7629ee6e8bbSpbrook switch ((value >> 24) & 3) { 7639ee6e8bbSpbrook case 0: 7649ee6e8bbSpbrook mask = (value >> 16) & ALL_CPU_MASK; 7659ee6e8bbSpbrook break; 7669ee6e8bbSpbrook case 1: 767fa250144SAdam Lackorzynski mask = ALL_CPU_MASK ^ (1 << cpu); 7689ee6e8bbSpbrook break; 7699ee6e8bbSpbrook case 2: 770fa250144SAdam Lackorzynski mask = 1 << cpu; 7719ee6e8bbSpbrook break; 7729ee6e8bbSpbrook default: 7739ee6e8bbSpbrook DPRINTF("Bad Soft Int target filter\n"); 7749ee6e8bbSpbrook mask = ALL_CPU_MASK; 7759ee6e8bbSpbrook break; 7769ee6e8bbSpbrook } 7779ee6e8bbSpbrook GIC_SET_PENDING(irq, mask); 77840d22500SChristoffer Dall target_cpu = ctz32(mask); 77940d22500SChristoffer Dall while (target_cpu < GIC_NCPU) { 78040d22500SChristoffer Dall s->sgi_pending[irq][target_cpu] |= (1 << cpu); 78140d22500SChristoffer Dall mask &= ~(1 << target_cpu); 78240d22500SChristoffer Dall target_cpu = ctz32(mask); 78340d22500SChristoffer Dall } 7849ee6e8bbSpbrook gic_update(s); 7859ee6e8bbSpbrook return; 7869ee6e8bbSpbrook } 787a9d85353SPeter Maydell gic_dist_writew(opaque, offset, value & 0xffff, attrs); 788a9d85353SPeter Maydell gic_dist_writew(opaque, offset + 2, value >> 16, attrs); 789a9d85353SPeter Maydell } 790a9d85353SPeter Maydell 791a9d85353SPeter Maydell static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data, 792a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 793a9d85353SPeter Maydell { 794a9d85353SPeter Maydell switch (size) { 795a9d85353SPeter Maydell case 1: 796a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, data, attrs); 797a9d85353SPeter Maydell return MEMTX_OK; 798a9d85353SPeter Maydell case 2: 799a9d85353SPeter Maydell gic_dist_writew(opaque, offset, data, attrs); 800a9d85353SPeter Maydell return MEMTX_OK; 801a9d85353SPeter Maydell case 4: 802a9d85353SPeter Maydell gic_dist_writel(opaque, offset, data, attrs); 803a9d85353SPeter Maydell return MEMTX_OK; 804a9d85353SPeter Maydell default: 805a9d85353SPeter Maydell return MEMTX_ERROR; 806a9d85353SPeter Maydell } 807e69954b9Spbrook } 808e69954b9Spbrook 809755c0802SAvi Kivity static const MemoryRegionOps gic_dist_ops = { 810a9d85353SPeter Maydell .read_with_attrs = gic_dist_read, 811a9d85353SPeter Maydell .write_with_attrs = gic_dist_write, 812755c0802SAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 813e69954b9Spbrook }; 814e69954b9Spbrook 815a9d85353SPeter Maydell static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, 816a9d85353SPeter Maydell uint64_t *data, MemTxAttrs attrs) 817e69954b9Spbrook { 818e69954b9Spbrook switch (offset) { 819e69954b9Spbrook case 0x00: /* Control */ 82032951860SFabian Aggeler *data = gic_get_cpu_control(s, cpu, attrs); 821a9d85353SPeter Maydell break; 822e69954b9Spbrook case 0x04: /* Priority mask */ 823a9d85353SPeter Maydell *data = s->priority_mask[cpu]; 824a9d85353SPeter Maydell break; 825e69954b9Spbrook case 0x08: /* Binary Point */ 826822e9cc3SFabian Aggeler if (s->security_extn && !attrs.secure) { 827822e9cc3SFabian Aggeler /* BPR is banked. Non-secure copy stored in ABPR. */ 828822e9cc3SFabian Aggeler *data = s->abpr[cpu]; 829822e9cc3SFabian Aggeler } else { 830a9d85353SPeter Maydell *data = s->bpr[cpu]; 831822e9cc3SFabian Aggeler } 832a9d85353SPeter Maydell break; 833e69954b9Spbrook case 0x0c: /* Acknowledge */ 834a9d85353SPeter Maydell *data = gic_acknowledge_irq(s, cpu); 835a9d85353SPeter Maydell break; 83666a0a2cbSDong Xu Wang case 0x14: /* Running Priority */ 837*08efa9f2SFabian Aggeler *data = gic_get_running_priority(s, cpu, attrs); 838a9d85353SPeter Maydell break; 839e69954b9Spbrook case 0x18: /* Highest Pending Interrupt */ 840a9d85353SPeter Maydell *data = s->current_pending[cpu]; 841a9d85353SPeter Maydell break; 842aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 843822e9cc3SFabian Aggeler /* GIC v2, no security: ABPR 844822e9cc3SFabian Aggeler * GIC v1, no security: not implemented (RAZ/WI) 845822e9cc3SFabian Aggeler * With security extensions, secure access: ABPR (alias of NS BPR) 846822e9cc3SFabian Aggeler * With security extensions, nonsecure access: RAZ/WI 847822e9cc3SFabian Aggeler */ 848822e9cc3SFabian Aggeler if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 849822e9cc3SFabian Aggeler *data = 0; 850822e9cc3SFabian Aggeler } else { 851a9d85353SPeter Maydell *data = s->abpr[cpu]; 852822e9cc3SFabian Aggeler } 853a9d85353SPeter Maydell break; 854a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 855a9d85353SPeter Maydell *data = s->apr[(offset - 0xd0) / 4][cpu]; 856a9d85353SPeter Maydell break; 857e69954b9Spbrook default: 8588c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 8598c8dc39fSPeter Maydell "gic_cpu_read: Bad offset %x\n", (int)offset); 860a9d85353SPeter Maydell return MEMTX_ERROR; 861e69954b9Spbrook } 862a9d85353SPeter Maydell return MEMTX_OK; 863e69954b9Spbrook } 864e69954b9Spbrook 865a9d85353SPeter Maydell static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, 866a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 867e69954b9Spbrook { 868e69954b9Spbrook switch (offset) { 869e69954b9Spbrook case 0x00: /* Control */ 87032951860SFabian Aggeler gic_set_cpu_control(s, cpu, value, attrs); 871e69954b9Spbrook break; 872e69954b9Spbrook case 0x04: /* Priority mask */ 8739ee6e8bbSpbrook s->priority_mask[cpu] = (value & 0xff); 874e69954b9Spbrook break; 875e69954b9Spbrook case 0x08: /* Binary Point */ 876822e9cc3SFabian Aggeler if (s->security_extn && !attrs.secure) { 877822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 878822e9cc3SFabian Aggeler } else { 879822e9cc3SFabian Aggeler s->bpr[cpu] = MAX(value & 0x7, GIC_MIN_BPR); 880822e9cc3SFabian Aggeler } 881e69954b9Spbrook break; 882e69954b9Spbrook case 0x10: /* End Of Interrupt */ 883e7ae771fSStefan Weil gic_complete_irq(s, cpu, value & 0x3ff); 884a9d85353SPeter Maydell return MEMTX_OK; 885aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 886822e9cc3SFabian Aggeler if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { 887822e9cc3SFabian Aggeler /* unimplemented, or NS access: RAZ/WI */ 888822e9cc3SFabian Aggeler return MEMTX_OK; 889822e9cc3SFabian Aggeler } else { 890822e9cc3SFabian Aggeler s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); 891aa7d461aSChristoffer Dall } 892aa7d461aSChristoffer Dall break; 893a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 894a9d477c4SChristoffer Dall qemu_log_mask(LOG_UNIMP, "Writing APR not implemented\n"); 895a9d477c4SChristoffer Dall break; 896e69954b9Spbrook default: 8978c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 8988c8dc39fSPeter Maydell "gic_cpu_write: Bad offset %x\n", (int)offset); 899a9d85353SPeter Maydell return MEMTX_ERROR; 900e69954b9Spbrook } 901e69954b9Spbrook gic_update(s); 902a9d85353SPeter Maydell return MEMTX_OK; 903e69954b9Spbrook } 904e2c56465SPeter Maydell 905e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for the current CPU */ 906a9d85353SPeter Maydell static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data, 907a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 908e2c56465SPeter Maydell { 909fae15286SPeter Maydell GICState *s = (GICState *)opaque; 910a9d85353SPeter Maydell return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs); 911e2c56465SPeter Maydell } 912e2c56465SPeter Maydell 913a9d85353SPeter Maydell static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr, 914a9d85353SPeter Maydell uint64_t value, unsigned size, 915a9d85353SPeter Maydell MemTxAttrs attrs) 916e2c56465SPeter Maydell { 917fae15286SPeter Maydell GICState *s = (GICState *)opaque; 918a9d85353SPeter Maydell return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs); 919e2c56465SPeter Maydell } 920e2c56465SPeter Maydell 921e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for a specific CPU. 922fae15286SPeter Maydell * These just decode the opaque pointer into GICState* + cpu id. 923e2c56465SPeter Maydell */ 924a9d85353SPeter Maydell static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data, 925a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 926e2c56465SPeter Maydell { 927fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 928fae15286SPeter Maydell GICState *s = *backref; 929e2c56465SPeter Maydell int id = (backref - s->backref); 930a9d85353SPeter Maydell return gic_cpu_read(s, id, addr, data, attrs); 931e2c56465SPeter Maydell } 932e2c56465SPeter Maydell 933a9d85353SPeter Maydell static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr, 934a9d85353SPeter Maydell uint64_t value, unsigned size, 935a9d85353SPeter Maydell MemTxAttrs attrs) 936e2c56465SPeter Maydell { 937fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 938fae15286SPeter Maydell GICState *s = *backref; 939e2c56465SPeter Maydell int id = (backref - s->backref); 940a9d85353SPeter Maydell return gic_cpu_write(s, id, addr, value, attrs); 941e2c56465SPeter Maydell } 942e2c56465SPeter Maydell 943e2c56465SPeter Maydell static const MemoryRegionOps gic_thiscpu_ops = { 944a9d85353SPeter Maydell .read_with_attrs = gic_thiscpu_read, 945a9d85353SPeter Maydell .write_with_attrs = gic_thiscpu_write, 946e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 947e2c56465SPeter Maydell }; 948e2c56465SPeter Maydell 949e2c56465SPeter Maydell static const MemoryRegionOps gic_cpu_ops = { 950a9d85353SPeter Maydell .read_with_attrs = gic_do_cpu_read, 951a9d85353SPeter Maydell .write_with_attrs = gic_do_cpu_write, 952e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 953e2c56465SPeter Maydell }; 954e69954b9Spbrook 9557b95a508SKONRAD Frederic void gic_init_irqs_and_distributor(GICState *s) 956e69954b9Spbrook { 957285b4432SAndreas Färber SysBusDevice *sbd = SYS_BUS_DEVICE(s); 9589ee6e8bbSpbrook int i; 959e69954b9Spbrook 960544d1afaSPeter Maydell i = s->num_irq - GIC_INTERNAL; 961544d1afaSPeter Maydell /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU. 962544d1afaSPeter Maydell * GPIO array layout is thus: 963544d1afaSPeter Maydell * [0..N-1] SPIs 964544d1afaSPeter Maydell * [N..N+31] PPIs for CPU 0 965544d1afaSPeter Maydell * [N+32..N+63] PPIs for CPU 1 966544d1afaSPeter Maydell * ... 967544d1afaSPeter Maydell */ 96884e4fccbSPeter Maydell if (s->revision != REV_NVIC) { 969c48c6522SPeter Maydell i += (GIC_INTERNAL * s->num_cpu); 97084e4fccbSPeter Maydell } 971285b4432SAndreas Färber qdev_init_gpio_in(DEVICE(s), gic_set_irq, i); 972c988bfadSPaul Brook for (i = 0; i < NUM_CPU(s); i++) { 973285b4432SAndreas Färber sysbus_init_irq(sbd, &s->parent_irq[i]); 9749ee6e8bbSpbrook } 97544f55296SFabian Aggeler for (i = 0; i < NUM_CPU(s); i++) { 97644f55296SFabian Aggeler sysbus_init_irq(sbd, &s->parent_fiq[i]); 97744f55296SFabian Aggeler } 9781437c94bSPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s, 9791437c94bSPaolo Bonzini "gic_dist", 0x1000); 9802b518c56SPeter Maydell } 9812b518c56SPeter Maydell 98253111180SPeter Maydell static void arm_gic_realize(DeviceState *dev, Error **errp) 9832b518c56SPeter Maydell { 98453111180SPeter Maydell /* Device instance realize function for the GIC sysbus device */ 9852b518c56SPeter Maydell int i; 98653111180SPeter Maydell GICState *s = ARM_GIC(dev); 98753111180SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 9881e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_GET_CLASS(s); 9890175ba10SMarkus Armbruster Error *local_err = NULL; 9901e8cae4dSPeter Maydell 9910175ba10SMarkus Armbruster agc->parent_realize(dev, &local_err); 9920175ba10SMarkus Armbruster if (local_err) { 9930175ba10SMarkus Armbruster error_propagate(errp, local_err); 99453111180SPeter Maydell return; 99553111180SPeter Maydell } 9961e8cae4dSPeter Maydell 9977b95a508SKONRAD Frederic gic_init_irqs_and_distributor(s); 9982b518c56SPeter Maydell 999e2c56465SPeter Maydell /* Memory regions for the CPU interfaces (NVIC doesn't have these): 1000e2c56465SPeter Maydell * a region for "CPU interface for this core", then a region for 1001e2c56465SPeter Maydell * "CPU interface for core 0", "for core 1", ... 1002e2c56465SPeter Maydell * NB that the memory region size of 0x100 applies for the 11MPCore 1003e2c56465SPeter Maydell * and also cores following the GIC v1 spec (ie A9). 1004e2c56465SPeter Maydell * GIC v2 defines a larger memory region (0x1000) so this will need 1005e2c56465SPeter Maydell * to be extended when we implement A15. 1006e2c56465SPeter Maydell */ 10071437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s, 1008e2c56465SPeter Maydell "gic_cpu", 0x100); 1009e2c56465SPeter Maydell for (i = 0; i < NUM_CPU(s); i++) { 1010e2c56465SPeter Maydell s->backref[i] = s; 10111437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, 10121437c94bSPaolo Bonzini &s->backref[i], "gic_cpu", 0x100); 1013e2c56465SPeter Maydell } 1014496dbcd1SPeter Maydell /* Distributor */ 101553111180SPeter Maydell sysbus_init_mmio(sbd, &s->iomem); 1016496dbcd1SPeter Maydell /* cpu interfaces (one for "current cpu" plus one per cpu) */ 1017496dbcd1SPeter Maydell for (i = 0; i <= NUM_CPU(s); i++) { 101853111180SPeter Maydell sysbus_init_mmio(sbd, &s->cpuiomem[i]); 1019496dbcd1SPeter Maydell } 1020496dbcd1SPeter Maydell } 1021496dbcd1SPeter Maydell 1022496dbcd1SPeter Maydell static void arm_gic_class_init(ObjectClass *klass, void *data) 1023496dbcd1SPeter Maydell { 1024496dbcd1SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 10251e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_CLASS(klass); 102653111180SPeter Maydell 102753111180SPeter Maydell agc->parent_realize = dc->realize; 102853111180SPeter Maydell dc->realize = arm_gic_realize; 1029496dbcd1SPeter Maydell } 1030496dbcd1SPeter Maydell 10318c43a6f0SAndreas Färber static const TypeInfo arm_gic_info = { 10321e8cae4dSPeter Maydell .name = TYPE_ARM_GIC, 10331e8cae4dSPeter Maydell .parent = TYPE_ARM_GIC_COMMON, 1034fae15286SPeter Maydell .instance_size = sizeof(GICState), 1035496dbcd1SPeter Maydell .class_init = arm_gic_class_init, 1036998a74bcSPeter Maydell .class_size = sizeof(ARMGICClass), 1037496dbcd1SPeter Maydell }; 1038496dbcd1SPeter Maydell 1039496dbcd1SPeter Maydell static void arm_gic_register_types(void) 1040496dbcd1SPeter Maydell { 1041496dbcd1SPeter Maydell type_register_static(&arm_gic_info); 1042496dbcd1SPeter Maydell } 1043496dbcd1SPeter Maydell 1044496dbcd1SPeter Maydell type_init(arm_gic_register_types) 1045