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 48*c27a5ba9SFabian Aggeler /* Return true if this GIC config has interrupt groups, which is 49*c27a5ba9SFabian Aggeler * true if we're a GICv2, or a GICv1 with the security extensions. 50*c27a5ba9SFabian Aggeler */ 51*c27a5ba9SFabian Aggeler static inline bool gic_has_groups(GICState *s) 52*c27a5ba9SFabian Aggeler { 53*c27a5ba9SFabian Aggeler return s->revision == 2 || s->security_extn; 54*c27a5ba9SFabian Aggeler } 55*c27a5ba9SFabian 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; 709ee6e8bbSpbrook if (!s->enabled || !s->cpu_enabled[cpu]) { 719ee6e8bbSpbrook qemu_irq_lower(s->parent_irq[cpu]); 72e69954b9Spbrook return; 73e69954b9Spbrook } 74e69954b9Spbrook best_prio = 0x100; 75e69954b9Spbrook best_irq = 1023; 76a32134aaSMark Langsdorf for (irq = 0; irq < s->num_irq; irq++) { 77b52b81e4SSergey Fedorov if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm) && 78b52b81e4SSergey Fedorov (irq < GIC_INTERNAL || GIC_TARGET(irq) & cm)) { 799ee6e8bbSpbrook if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { 809ee6e8bbSpbrook best_prio = GIC_GET_PRIORITY(irq, cpu); 81e69954b9Spbrook best_irq = irq; 82e69954b9Spbrook } 83e69954b9Spbrook } 84e69954b9Spbrook } 859ee6e8bbSpbrook level = 0; 86cad065f1SPeter Maydell if (best_prio < s->priority_mask[cpu]) { 879ee6e8bbSpbrook s->current_pending[cpu] = best_irq; 889ee6e8bbSpbrook if (best_prio < s->running_priority[cpu]) { 898c815fb3SPeter Crosthwaite DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu); 909ee6e8bbSpbrook level = 1; 91e69954b9Spbrook } 92e69954b9Spbrook } 939ee6e8bbSpbrook qemu_set_irq(s->parent_irq[cpu], level); 949ee6e8bbSpbrook } 95e69954b9Spbrook } 96e69954b9Spbrook 97fae15286SPeter Maydell void gic_set_pending_private(GICState *s, int cpu, int irq) 989ee6e8bbSpbrook { 999ee6e8bbSpbrook int cm = 1 << cpu; 1009ee6e8bbSpbrook 1018d999995SChristoffer Dall if (gic_test_pending(s, irq, cm)) { 1029ee6e8bbSpbrook return; 1038d999995SChristoffer Dall } 1049ee6e8bbSpbrook 1059ee6e8bbSpbrook DPRINTF("Set %d pending cpu %d\n", irq, cpu); 1069ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 1079ee6e8bbSpbrook gic_update(s); 1089ee6e8bbSpbrook } 1099ee6e8bbSpbrook 1108d999995SChristoffer Dall static void gic_set_irq_11mpcore(GICState *s, int irq, int level, 1118d999995SChristoffer Dall int cm, int target) 1128d999995SChristoffer Dall { 1138d999995SChristoffer Dall if (level) { 1148d999995SChristoffer Dall GIC_SET_LEVEL(irq, cm); 1158d999995SChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) { 1168d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 1178d999995SChristoffer Dall GIC_SET_PENDING(irq, target); 1188d999995SChristoffer Dall } 1198d999995SChristoffer Dall } else { 1208d999995SChristoffer Dall GIC_CLEAR_LEVEL(irq, cm); 1218d999995SChristoffer Dall } 1228d999995SChristoffer Dall } 1238d999995SChristoffer Dall 1248d999995SChristoffer Dall static void gic_set_irq_generic(GICState *s, int irq, int level, 1258d999995SChristoffer Dall int cm, int target) 1268d999995SChristoffer Dall { 1278d999995SChristoffer Dall if (level) { 1288d999995SChristoffer Dall GIC_SET_LEVEL(irq, cm); 1298d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 1308d999995SChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq)) { 1318d999995SChristoffer Dall GIC_SET_PENDING(irq, target); 1328d999995SChristoffer Dall } 1338d999995SChristoffer Dall } else { 1348d999995SChristoffer Dall GIC_CLEAR_LEVEL(irq, cm); 1358d999995SChristoffer Dall } 1368d999995SChristoffer Dall } 1378d999995SChristoffer Dall 1389ee6e8bbSpbrook /* Process a change in an external IRQ input. */ 139e69954b9Spbrook static void gic_set_irq(void *opaque, int irq, int level) 140e69954b9Spbrook { 141544d1afaSPeter Maydell /* Meaning of the 'irq' parameter: 142544d1afaSPeter Maydell * [0..N-1] : external interrupts 143544d1afaSPeter Maydell * [N..N+31] : PPI (internal) interrupts for CPU 0 144544d1afaSPeter Maydell * [N+32..N+63] : PPI (internal interrupts for CPU 1 145544d1afaSPeter Maydell * ... 146544d1afaSPeter Maydell */ 147fae15286SPeter Maydell GICState *s = (GICState *)opaque; 148544d1afaSPeter Maydell int cm, target; 149544d1afaSPeter Maydell if (irq < (s->num_irq - GIC_INTERNAL)) { 150e69954b9Spbrook /* The first external input line is internal interrupt 32. */ 151544d1afaSPeter Maydell cm = ALL_CPU_MASK; 15269253800SRusty Russell irq += GIC_INTERNAL; 153544d1afaSPeter Maydell target = GIC_TARGET(irq); 154544d1afaSPeter Maydell } else { 155544d1afaSPeter Maydell int cpu; 156544d1afaSPeter Maydell irq -= (s->num_irq - GIC_INTERNAL); 157544d1afaSPeter Maydell cpu = irq / GIC_INTERNAL; 158544d1afaSPeter Maydell irq %= GIC_INTERNAL; 159544d1afaSPeter Maydell cm = 1 << cpu; 160544d1afaSPeter Maydell target = cm; 161544d1afaSPeter Maydell } 162544d1afaSPeter Maydell 16340d22500SChristoffer Dall assert(irq >= GIC_NR_SGIS); 16440d22500SChristoffer Dall 165544d1afaSPeter Maydell if (level == GIC_TEST_LEVEL(irq, cm)) { 166e69954b9Spbrook return; 167544d1afaSPeter Maydell } 168e69954b9Spbrook 1698d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 1708d999995SChristoffer Dall gic_set_irq_11mpcore(s, irq, level, cm, target); 171e69954b9Spbrook } else { 1728d999995SChristoffer Dall gic_set_irq_generic(s, irq, level, cm, target); 173e69954b9Spbrook } 1748d999995SChristoffer Dall 175e69954b9Spbrook gic_update(s); 176e69954b9Spbrook } 177e69954b9Spbrook 178fae15286SPeter Maydell static void gic_set_running_irq(GICState *s, int cpu, int irq) 179e69954b9Spbrook { 1809ee6e8bbSpbrook s->running_irq[cpu] = irq; 1819ee6e8bbSpbrook if (irq == 1023) { 1829ee6e8bbSpbrook s->running_priority[cpu] = 0x100; 1839ee6e8bbSpbrook } else { 1849ee6e8bbSpbrook s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu); 1859ee6e8bbSpbrook } 186e69954b9Spbrook gic_update(s); 187e69954b9Spbrook } 188e69954b9Spbrook 189fae15286SPeter Maydell uint32_t gic_acknowledge_irq(GICState *s, int cpu) 190e69954b9Spbrook { 19140d22500SChristoffer Dall int ret, irq, src; 1929ee6e8bbSpbrook int cm = 1 << cpu; 19340d22500SChristoffer Dall irq = s->current_pending[cpu]; 19440d22500SChristoffer Dall if (irq == 1023 19540d22500SChristoffer Dall || GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) { 196e69954b9Spbrook DPRINTF("ACK no pending IRQ\n"); 197e69954b9Spbrook return 1023; 198e69954b9Spbrook } 19940d22500SChristoffer Dall s->last_active[irq][cpu] = s->running_irq[cpu]; 20040d22500SChristoffer Dall 20187316902SPeter Maydell if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 2029ee6e8bbSpbrook /* Clear pending flags for both level and edge triggered interrupts. 20340d22500SChristoffer Dall * Level triggered IRQs will be reasserted once they become inactive. 20440d22500SChristoffer Dall */ 20540d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 20640d22500SChristoffer Dall ret = irq; 20740d22500SChristoffer Dall } else { 20840d22500SChristoffer Dall if (irq < GIC_NR_SGIS) { 20940d22500SChristoffer Dall /* Lookup the source CPU for the SGI and clear this in the 21040d22500SChristoffer Dall * sgi_pending map. Return the src and clear the overall pending 21140d22500SChristoffer Dall * state on this CPU if the SGI is not pending from any CPUs. 21240d22500SChristoffer Dall */ 21340d22500SChristoffer Dall assert(s->sgi_pending[irq][cpu] != 0); 21440d22500SChristoffer Dall src = ctz32(s->sgi_pending[irq][cpu]); 21540d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~(1 << src); 21640d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 21740d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 21840d22500SChristoffer Dall } 21940d22500SChristoffer Dall ret = irq | ((src & 0x7) << 10); 22040d22500SChristoffer Dall } else { 22140d22500SChristoffer Dall /* Clear pending state for both level and edge triggered 22240d22500SChristoffer Dall * interrupts. (level triggered interrupts with an active line 22340d22500SChristoffer Dall * remain pending, see gic_test_pending) 22440d22500SChristoffer Dall */ 22540d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 22640d22500SChristoffer Dall ret = irq; 22740d22500SChristoffer Dall } 22840d22500SChristoffer Dall } 22940d22500SChristoffer Dall 23040d22500SChristoffer Dall gic_set_running_irq(s, cpu, irq); 23140d22500SChristoffer Dall DPRINTF("ACK %d\n", irq); 23240d22500SChristoffer Dall return ret; 233e69954b9Spbrook } 234e69954b9Spbrook 2359df90ad0SChristoffer Dall void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val) 2369df90ad0SChristoffer Dall { 2379df90ad0SChristoffer Dall if (irq < GIC_INTERNAL) { 2389df90ad0SChristoffer Dall s->priority1[irq][cpu] = val; 2399df90ad0SChristoffer Dall } else { 2409df90ad0SChristoffer Dall s->priority2[(irq) - GIC_INTERNAL] = val; 2419df90ad0SChristoffer Dall } 2429df90ad0SChristoffer Dall } 2439df90ad0SChristoffer Dall 244fae15286SPeter Maydell void gic_complete_irq(GICState *s, int cpu, int irq) 245e69954b9Spbrook { 246e69954b9Spbrook int update = 0; 2479ee6e8bbSpbrook int cm = 1 << cpu; 248df628ff1Spbrook DPRINTF("EOI %d\n", irq); 249a32134aaSMark Langsdorf if (irq >= s->num_irq) { 250217bfb44SPeter Maydell /* This handles two cases: 251217bfb44SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 252217bfb44SPeter Maydell * to the GICC_EOIR, the GIC ignores that write. 253217bfb44SPeter Maydell * 2. If software writes the number of a non-existent interrupt 254217bfb44SPeter Maydell * this must be a subcase of "value written does not match the last 255217bfb44SPeter Maydell * valid interrupt value read from the Interrupt Acknowledge 256217bfb44SPeter Maydell * register" and so this is UNPREDICTABLE. We choose to ignore it. 257217bfb44SPeter Maydell */ 258217bfb44SPeter Maydell return; 259217bfb44SPeter Maydell } 2609ee6e8bbSpbrook if (s->running_irq[cpu] == 1023) 261e69954b9Spbrook return; /* No active IRQ. */ 2628d999995SChristoffer Dall 2638d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 264e69954b9Spbrook /* Mark level triggered interrupts as pending if they are still 265e69954b9Spbrook raised. */ 26604050c5cSChristoffer Dall if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm) 2679ee6e8bbSpbrook && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) { 2689ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq, cm); 2699ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 270e69954b9Spbrook update = 1; 271e69954b9Spbrook } 2728d999995SChristoffer Dall } 2738d999995SChristoffer Dall 2749ee6e8bbSpbrook if (irq != s->running_irq[cpu]) { 275e69954b9Spbrook /* Complete an IRQ that is not currently running. */ 2769ee6e8bbSpbrook int tmp = s->running_irq[cpu]; 2779ee6e8bbSpbrook while (s->last_active[tmp][cpu] != 1023) { 2789ee6e8bbSpbrook if (s->last_active[tmp][cpu] == irq) { 2799ee6e8bbSpbrook s->last_active[tmp][cpu] = s->last_active[irq][cpu]; 280e69954b9Spbrook break; 281e69954b9Spbrook } 2829ee6e8bbSpbrook tmp = s->last_active[tmp][cpu]; 283e69954b9Spbrook } 284e69954b9Spbrook if (update) { 285e69954b9Spbrook gic_update(s); 286e69954b9Spbrook } 287e69954b9Spbrook } else { 288e69954b9Spbrook /* Complete the current running IRQ. */ 2899ee6e8bbSpbrook gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]); 290e69954b9Spbrook } 291e69954b9Spbrook } 292e69954b9Spbrook 293a9d85353SPeter Maydell static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) 294e69954b9Spbrook { 295fae15286SPeter Maydell GICState *s = (GICState *)opaque; 296e69954b9Spbrook uint32_t res; 297e69954b9Spbrook int irq; 298e69954b9Spbrook int i; 2999ee6e8bbSpbrook int cpu; 3009ee6e8bbSpbrook int cm; 3019ee6e8bbSpbrook int mask; 302e69954b9Spbrook 303926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 3049ee6e8bbSpbrook cm = 1 << cpu; 305e69954b9Spbrook if (offset < 0x100) { 306e69954b9Spbrook if (offset == 0) 307e69954b9Spbrook return s->enabled; 308e69954b9Spbrook if (offset == 4) 3095543d1abSFabian Aggeler /* Interrupt Controller Type Register */ 3105543d1abSFabian Aggeler return ((s->num_irq / 32) - 1) 3115543d1abSFabian Aggeler | ((NUM_CPU(s) - 1) << 5) 3125543d1abSFabian Aggeler | (s->security_extn << 10); 313e69954b9Spbrook if (offset < 0x08) 314e69954b9Spbrook return 0; 315b79f2265SRob Herring if (offset >= 0x80) { 316*c27a5ba9SFabian Aggeler /* Interrupt Group Registers: these RAZ/WI if this is an NS 317*c27a5ba9SFabian Aggeler * access to a GIC with the security extensions, or if the GIC 318*c27a5ba9SFabian Aggeler * doesn't have groups at all. 319*c27a5ba9SFabian Aggeler */ 320*c27a5ba9SFabian Aggeler res = 0; 321*c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 322*c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 323*c27a5ba9SFabian Aggeler irq = (offset - 0x080) * 8 + GIC_BASE_IRQ; 324*c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 325*c27a5ba9SFabian Aggeler goto bad_reg; 326*c27a5ba9SFabian Aggeler } 327*c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 328*c27a5ba9SFabian Aggeler if (GIC_TEST_GROUP(irq + i, cm)) { 329*c27a5ba9SFabian Aggeler res |= (1 << i); 330*c27a5ba9SFabian Aggeler } 331*c27a5ba9SFabian Aggeler } 332*c27a5ba9SFabian Aggeler } 333*c27a5ba9SFabian Aggeler return res; 334b79f2265SRob Herring } 335e69954b9Spbrook goto bad_reg; 336e69954b9Spbrook } else if (offset < 0x200) { 337e69954b9Spbrook /* Interrupt Set/Clear Enable. */ 338e69954b9Spbrook if (offset < 0x180) 339e69954b9Spbrook irq = (offset - 0x100) * 8; 340e69954b9Spbrook else 341e69954b9Spbrook irq = (offset - 0x180) * 8; 3429ee6e8bbSpbrook irq += GIC_BASE_IRQ; 343a32134aaSMark Langsdorf if (irq >= s->num_irq) 344e69954b9Spbrook goto bad_reg; 345e69954b9Spbrook res = 0; 346e69954b9Spbrook for (i = 0; i < 8; i++) { 34741bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 348e69954b9Spbrook res |= (1 << i); 349e69954b9Spbrook } 350e69954b9Spbrook } 351e69954b9Spbrook } else if (offset < 0x300) { 352e69954b9Spbrook /* Interrupt Set/Clear Pending. */ 353e69954b9Spbrook if (offset < 0x280) 354e69954b9Spbrook irq = (offset - 0x200) * 8; 355e69954b9Spbrook else 356e69954b9Spbrook irq = (offset - 0x280) * 8; 3579ee6e8bbSpbrook irq += GIC_BASE_IRQ; 358a32134aaSMark Langsdorf if (irq >= s->num_irq) 359e69954b9Spbrook goto bad_reg; 360e69954b9Spbrook res = 0; 36169253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 362e69954b9Spbrook for (i = 0; i < 8; i++) { 3638d999995SChristoffer Dall if (gic_test_pending(s, irq + i, mask)) { 364e69954b9Spbrook res |= (1 << i); 365e69954b9Spbrook } 366e69954b9Spbrook } 367e69954b9Spbrook } else if (offset < 0x400) { 368e69954b9Spbrook /* Interrupt Active. */ 3699ee6e8bbSpbrook irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 370a32134aaSMark Langsdorf if (irq >= s->num_irq) 371e69954b9Spbrook goto bad_reg; 372e69954b9Spbrook res = 0; 37369253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 374e69954b9Spbrook for (i = 0; i < 8; i++) { 3759ee6e8bbSpbrook if (GIC_TEST_ACTIVE(irq + i, mask)) { 376e69954b9Spbrook res |= (1 << i); 377e69954b9Spbrook } 378e69954b9Spbrook } 379e69954b9Spbrook } else if (offset < 0x800) { 380e69954b9Spbrook /* Interrupt Priority. */ 3819ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 382a32134aaSMark Langsdorf if (irq >= s->num_irq) 383e69954b9Spbrook goto bad_reg; 3849ee6e8bbSpbrook res = GIC_GET_PRIORITY(irq, cpu); 385e69954b9Spbrook } else if (offset < 0xc00) { 386e69954b9Spbrook /* Interrupt CPU Target. */ 3876b9680bbSPeter Maydell if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { 3886b9680bbSPeter Maydell /* For uniprocessor GICs these RAZ/WI */ 3896b9680bbSPeter Maydell res = 0; 3906b9680bbSPeter Maydell } else { 3919ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 3926b9680bbSPeter Maydell if (irq >= s->num_irq) { 393e69954b9Spbrook goto bad_reg; 3946b9680bbSPeter Maydell } 3959ee6e8bbSpbrook if (irq >= 29 && irq <= 31) { 3969ee6e8bbSpbrook res = cm; 3979ee6e8bbSpbrook } else { 3989ee6e8bbSpbrook res = GIC_TARGET(irq); 3999ee6e8bbSpbrook } 4006b9680bbSPeter Maydell } 401e69954b9Spbrook } else if (offset < 0xf00) { 402e69954b9Spbrook /* Interrupt Configuration. */ 40371a62046SAdam Lackorzynski irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 404a32134aaSMark Langsdorf if (irq >= s->num_irq) 405e69954b9Spbrook goto bad_reg; 406e69954b9Spbrook res = 0; 407e69954b9Spbrook for (i = 0; i < 4; i++) { 408e69954b9Spbrook if (GIC_TEST_MODEL(irq + i)) 409e69954b9Spbrook res |= (1 << (i * 2)); 41004050c5cSChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq + i)) 411e69954b9Spbrook res |= (2 << (i * 2)); 412e69954b9Spbrook } 41340d22500SChristoffer Dall } else if (offset < 0xf10) { 41440d22500SChristoffer Dall goto bad_reg; 41540d22500SChristoffer Dall } else if (offset < 0xf30) { 41640d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 41740d22500SChristoffer Dall goto bad_reg; 41840d22500SChristoffer Dall } 41940d22500SChristoffer Dall 42040d22500SChristoffer Dall if (offset < 0xf20) { 42140d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 42240d22500SChristoffer Dall irq = (offset - 0xf10); 42340d22500SChristoffer Dall } else { 42440d22500SChristoffer Dall irq = (offset - 0xf20); 42540d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 42640d22500SChristoffer Dall } 42740d22500SChristoffer Dall 42840d22500SChristoffer Dall res = s->sgi_pending[irq][cpu]; 429e69954b9Spbrook } else if (offset < 0xfe0) { 430e69954b9Spbrook goto bad_reg; 431e69954b9Spbrook } else /* offset >= 0xfe0 */ { 432e69954b9Spbrook if (offset & 3) { 433e69954b9Spbrook res = 0; 434e69954b9Spbrook } else { 435e69954b9Spbrook res = gic_id[(offset - 0xfe0) >> 2]; 436e69954b9Spbrook } 437e69954b9Spbrook } 438e69954b9Spbrook return res; 439e69954b9Spbrook bad_reg: 4408c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 4418c8dc39fSPeter Maydell "gic_dist_readb: Bad offset %x\n", (int)offset); 442e69954b9Spbrook return 0; 443e69954b9Spbrook } 444e69954b9Spbrook 445a9d85353SPeter Maydell static MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data, 446a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 447e69954b9Spbrook { 448a9d85353SPeter Maydell switch (size) { 449a9d85353SPeter Maydell case 1: 450a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 451a9d85353SPeter Maydell return MEMTX_OK; 452a9d85353SPeter Maydell case 2: 453a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 454a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 455a9d85353SPeter Maydell return MEMTX_OK; 456a9d85353SPeter Maydell case 4: 457a9d85353SPeter Maydell *data = gic_dist_readb(opaque, offset, attrs); 458a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8; 459a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 2, attrs) << 16; 460a9d85353SPeter Maydell *data |= gic_dist_readb(opaque, offset + 3, attrs) << 24; 461a9d85353SPeter Maydell return MEMTX_OK; 462a9d85353SPeter Maydell default: 463a9d85353SPeter Maydell return MEMTX_ERROR; 464e69954b9Spbrook } 465e69954b9Spbrook } 466e69954b9Spbrook 467a8170e5eSAvi Kivity static void gic_dist_writeb(void *opaque, hwaddr offset, 468a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 469e69954b9Spbrook { 470fae15286SPeter Maydell GICState *s = (GICState *)opaque; 471e69954b9Spbrook int irq; 472e69954b9Spbrook int i; 4739ee6e8bbSpbrook int cpu; 474e69954b9Spbrook 475926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 476e69954b9Spbrook if (offset < 0x100) { 477e69954b9Spbrook if (offset == 0) { 478e69954b9Spbrook s->enabled = (value & 1); 479e69954b9Spbrook DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis"); 480e69954b9Spbrook } else if (offset < 4) { 481e69954b9Spbrook /* ignored. */ 482b79f2265SRob Herring } else if (offset >= 0x80) { 483*c27a5ba9SFabian Aggeler /* Interrupt Group Registers: RAZ/WI for NS access to secure 484*c27a5ba9SFabian Aggeler * GIC, or for GICs without groups. 485*c27a5ba9SFabian Aggeler */ 486*c27a5ba9SFabian Aggeler if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { 487*c27a5ba9SFabian Aggeler /* Every byte offset holds 8 group status bits */ 488*c27a5ba9SFabian Aggeler irq = (offset - 0x80) * 8 + GIC_BASE_IRQ; 489*c27a5ba9SFabian Aggeler if (irq >= s->num_irq) { 490*c27a5ba9SFabian Aggeler goto bad_reg; 491*c27a5ba9SFabian Aggeler } 492*c27a5ba9SFabian Aggeler for (i = 0; i < 8; i++) { 493*c27a5ba9SFabian Aggeler /* Group bits are banked for private interrupts */ 494*c27a5ba9SFabian Aggeler int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 495*c27a5ba9SFabian Aggeler if (value & (1 << i)) { 496*c27a5ba9SFabian Aggeler /* Group1 (Non-secure) */ 497*c27a5ba9SFabian Aggeler GIC_SET_GROUP(irq + i, cm); 498*c27a5ba9SFabian Aggeler } else { 499*c27a5ba9SFabian Aggeler /* Group0 (Secure) */ 500*c27a5ba9SFabian Aggeler GIC_CLEAR_GROUP(irq + i, cm); 501*c27a5ba9SFabian Aggeler } 502*c27a5ba9SFabian Aggeler } 503*c27a5ba9SFabian Aggeler } 504e69954b9Spbrook } else { 505e69954b9Spbrook goto bad_reg; 506e69954b9Spbrook } 507e69954b9Spbrook } else if (offset < 0x180) { 508e69954b9Spbrook /* Interrupt Set Enable. */ 5099ee6e8bbSpbrook irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 510a32134aaSMark Langsdorf if (irq >= s->num_irq) 511e69954b9Spbrook goto bad_reg; 51241ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 5139ee6e8bbSpbrook value = 0xff; 51441ab7b55SChristoffer Dall } 51541ab7b55SChristoffer Dall 516e69954b9Spbrook for (i = 0; i < 8; i++) { 517e69954b9Spbrook if (value & (1 << i)) { 518f47b48fbSDaniel Sangorrin int mask = 519f47b48fbSDaniel Sangorrin (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i); 52069253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 52141bf234dSRabin Vincent 52241bf234dSRabin Vincent if (!GIC_TEST_ENABLED(irq + i, cm)) { 523e69954b9Spbrook DPRINTF("Enabled IRQ %d\n", irq + i); 52441bf234dSRabin Vincent } 52541bf234dSRabin Vincent GIC_SET_ENABLED(irq + i, cm); 526e69954b9Spbrook /* If a raised level triggered IRQ enabled then mark 527e69954b9Spbrook is as pending. */ 5289ee6e8bbSpbrook if (GIC_TEST_LEVEL(irq + i, mask) 52904050c5cSChristoffer Dall && !GIC_TEST_EDGE_TRIGGER(irq + i)) { 5309ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq + i, mask); 5319ee6e8bbSpbrook GIC_SET_PENDING(irq + i, mask); 5329ee6e8bbSpbrook } 533e69954b9Spbrook } 534e69954b9Spbrook } 535e69954b9Spbrook } else if (offset < 0x200) { 536e69954b9Spbrook /* Interrupt Clear Enable. */ 5379ee6e8bbSpbrook irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 538a32134aaSMark Langsdorf if (irq >= s->num_irq) 539e69954b9Spbrook goto bad_reg; 54041ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 5419ee6e8bbSpbrook value = 0; 54241ab7b55SChristoffer Dall } 54341ab7b55SChristoffer Dall 544e69954b9Spbrook for (i = 0; i < 8; i++) { 545e69954b9Spbrook if (value & (1 << i)) { 54669253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 54741bf234dSRabin Vincent 54841bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 549e69954b9Spbrook DPRINTF("Disabled IRQ %d\n", irq + i); 55041bf234dSRabin Vincent } 55141bf234dSRabin Vincent GIC_CLEAR_ENABLED(irq + i, cm); 552e69954b9Spbrook } 553e69954b9Spbrook } 554e69954b9Spbrook } else if (offset < 0x280) { 555e69954b9Spbrook /* Interrupt Set Pending. */ 5569ee6e8bbSpbrook irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 557a32134aaSMark Langsdorf if (irq >= s->num_irq) 558e69954b9Spbrook goto bad_reg; 55941ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 5605b0adce1SChristoffer Dall value = 0; 56141ab7b55SChristoffer Dall } 5629ee6e8bbSpbrook 563e69954b9Spbrook for (i = 0; i < 8; i++) { 564e69954b9Spbrook if (value & (1 << i)) { 565f47b48fbSDaniel Sangorrin GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); 566e69954b9Spbrook } 567e69954b9Spbrook } 568e69954b9Spbrook } else if (offset < 0x300) { 569e69954b9Spbrook /* Interrupt Clear Pending. */ 5709ee6e8bbSpbrook irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 571a32134aaSMark Langsdorf if (irq >= s->num_irq) 572e69954b9Spbrook goto bad_reg; 5735b0adce1SChristoffer Dall if (irq < GIC_NR_SGIS) { 5745b0adce1SChristoffer Dall value = 0; 5755b0adce1SChristoffer Dall } 5765b0adce1SChristoffer Dall 577e69954b9Spbrook for (i = 0; i < 8; i++) { 5789ee6e8bbSpbrook /* ??? This currently clears the pending bit for all CPUs, even 5799ee6e8bbSpbrook for per-CPU interrupts. It's unclear whether this is the 5809ee6e8bbSpbrook corect behavior. */ 581e69954b9Spbrook if (value & (1 << i)) { 5829ee6e8bbSpbrook GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 583e69954b9Spbrook } 584e69954b9Spbrook } 585e69954b9Spbrook } else if (offset < 0x400) { 586e69954b9Spbrook /* Interrupt Active. */ 587e69954b9Spbrook goto bad_reg; 588e69954b9Spbrook } else if (offset < 0x800) { 589e69954b9Spbrook /* Interrupt Priority. */ 5909ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 591a32134aaSMark Langsdorf if (irq >= s->num_irq) 592e69954b9Spbrook goto bad_reg; 5939df90ad0SChristoffer Dall gic_set_priority(s, cpu, irq, value); 594e69954b9Spbrook } else if (offset < 0xc00) { 5956b9680bbSPeter Maydell /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the 5966b9680bbSPeter Maydell * annoying exception of the 11MPCore's GIC. 5976b9680bbSPeter Maydell */ 5986b9680bbSPeter Maydell if (s->num_cpu != 1 || s->revision == REV_11MPCORE) { 5999ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 6006b9680bbSPeter Maydell if (irq >= s->num_irq) { 601e69954b9Spbrook goto bad_reg; 6026b9680bbSPeter Maydell } 6036b9680bbSPeter Maydell if (irq < 29) { 6049ee6e8bbSpbrook value = 0; 6056b9680bbSPeter Maydell } else if (irq < GIC_INTERNAL) { 6069ee6e8bbSpbrook value = ALL_CPU_MASK; 6076b9680bbSPeter Maydell } 6089ee6e8bbSpbrook s->irq_target[irq] = value & ALL_CPU_MASK; 6096b9680bbSPeter Maydell } 610e69954b9Spbrook } else if (offset < 0xf00) { 611e69954b9Spbrook /* Interrupt Configuration. */ 6129ee6e8bbSpbrook irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 613a32134aaSMark Langsdorf if (irq >= s->num_irq) 614e69954b9Spbrook goto bad_reg; 615de7a900fSAdam Lackorzynski if (irq < GIC_NR_SGIS) 6169ee6e8bbSpbrook value |= 0xaa; 617e69954b9Spbrook for (i = 0; i < 4; i++) { 61824b790dfSAdam Lackorzynski if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 619e69954b9Spbrook if (value & (1 << (i * 2))) { 620e69954b9Spbrook GIC_SET_MODEL(irq + i); 621e69954b9Spbrook } else { 622e69954b9Spbrook GIC_CLEAR_MODEL(irq + i); 623e69954b9Spbrook } 62424b790dfSAdam Lackorzynski } 625e69954b9Spbrook if (value & (2 << (i * 2))) { 62604050c5cSChristoffer Dall GIC_SET_EDGE_TRIGGER(irq + i); 627e69954b9Spbrook } else { 62804050c5cSChristoffer Dall GIC_CLEAR_EDGE_TRIGGER(irq + i); 629e69954b9Spbrook } 630e69954b9Spbrook } 63140d22500SChristoffer Dall } else if (offset < 0xf10) { 6329ee6e8bbSpbrook /* 0xf00 is only handled for 32-bit writes. */ 633e69954b9Spbrook goto bad_reg; 63440d22500SChristoffer Dall } else if (offset < 0xf20) { 63540d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 63640d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 63740d22500SChristoffer Dall goto bad_reg; 63840d22500SChristoffer Dall } 63940d22500SChristoffer Dall irq = (offset - 0xf10); 64040d22500SChristoffer Dall 64140d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~value; 64240d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 64340d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, 1 << cpu); 64440d22500SChristoffer Dall } 64540d22500SChristoffer Dall } else if (offset < 0xf30) { 64640d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 64740d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 64840d22500SChristoffer Dall goto bad_reg; 64940d22500SChristoffer Dall } 65040d22500SChristoffer Dall irq = (offset - 0xf20); 65140d22500SChristoffer Dall 65240d22500SChristoffer Dall GIC_SET_PENDING(irq, 1 << cpu); 65340d22500SChristoffer Dall s->sgi_pending[irq][cpu] |= value; 65440d22500SChristoffer Dall } else { 65540d22500SChristoffer Dall goto bad_reg; 656e69954b9Spbrook } 657e69954b9Spbrook gic_update(s); 658e69954b9Spbrook return; 659e69954b9Spbrook bad_reg: 6608c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 6618c8dc39fSPeter Maydell "gic_dist_writeb: Bad offset %x\n", (int)offset); 662e69954b9Spbrook } 663e69954b9Spbrook 664a8170e5eSAvi Kivity static void gic_dist_writew(void *opaque, hwaddr offset, 665a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 666e69954b9Spbrook { 667a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, value & 0xff, attrs); 668a9d85353SPeter Maydell gic_dist_writeb(opaque, offset + 1, value >> 8, attrs); 669e69954b9Spbrook } 670e69954b9Spbrook 671a8170e5eSAvi Kivity static void gic_dist_writel(void *opaque, hwaddr offset, 672a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 673e69954b9Spbrook { 674fae15286SPeter Maydell GICState *s = (GICState *)opaque; 6758da3ff18Spbrook if (offset == 0xf00) { 6769ee6e8bbSpbrook int cpu; 6779ee6e8bbSpbrook int irq; 6789ee6e8bbSpbrook int mask; 67940d22500SChristoffer Dall int target_cpu; 6809ee6e8bbSpbrook 681926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 6829ee6e8bbSpbrook irq = value & 0x3ff; 6839ee6e8bbSpbrook switch ((value >> 24) & 3) { 6849ee6e8bbSpbrook case 0: 6859ee6e8bbSpbrook mask = (value >> 16) & ALL_CPU_MASK; 6869ee6e8bbSpbrook break; 6879ee6e8bbSpbrook case 1: 688fa250144SAdam Lackorzynski mask = ALL_CPU_MASK ^ (1 << cpu); 6899ee6e8bbSpbrook break; 6909ee6e8bbSpbrook case 2: 691fa250144SAdam Lackorzynski mask = 1 << cpu; 6929ee6e8bbSpbrook break; 6939ee6e8bbSpbrook default: 6949ee6e8bbSpbrook DPRINTF("Bad Soft Int target filter\n"); 6959ee6e8bbSpbrook mask = ALL_CPU_MASK; 6969ee6e8bbSpbrook break; 6979ee6e8bbSpbrook } 6989ee6e8bbSpbrook GIC_SET_PENDING(irq, mask); 69940d22500SChristoffer Dall target_cpu = ctz32(mask); 70040d22500SChristoffer Dall while (target_cpu < GIC_NCPU) { 70140d22500SChristoffer Dall s->sgi_pending[irq][target_cpu] |= (1 << cpu); 70240d22500SChristoffer Dall mask &= ~(1 << target_cpu); 70340d22500SChristoffer Dall target_cpu = ctz32(mask); 70440d22500SChristoffer Dall } 7059ee6e8bbSpbrook gic_update(s); 7069ee6e8bbSpbrook return; 7079ee6e8bbSpbrook } 708a9d85353SPeter Maydell gic_dist_writew(opaque, offset, value & 0xffff, attrs); 709a9d85353SPeter Maydell gic_dist_writew(opaque, offset + 2, value >> 16, attrs); 710a9d85353SPeter Maydell } 711a9d85353SPeter Maydell 712a9d85353SPeter Maydell static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data, 713a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 714a9d85353SPeter Maydell { 715a9d85353SPeter Maydell switch (size) { 716a9d85353SPeter Maydell case 1: 717a9d85353SPeter Maydell gic_dist_writeb(opaque, offset, data, attrs); 718a9d85353SPeter Maydell return MEMTX_OK; 719a9d85353SPeter Maydell case 2: 720a9d85353SPeter Maydell gic_dist_writew(opaque, offset, data, attrs); 721a9d85353SPeter Maydell return MEMTX_OK; 722a9d85353SPeter Maydell case 4: 723a9d85353SPeter Maydell gic_dist_writel(opaque, offset, data, attrs); 724a9d85353SPeter Maydell return MEMTX_OK; 725a9d85353SPeter Maydell default: 726a9d85353SPeter Maydell return MEMTX_ERROR; 727a9d85353SPeter Maydell } 728e69954b9Spbrook } 729e69954b9Spbrook 730755c0802SAvi Kivity static const MemoryRegionOps gic_dist_ops = { 731a9d85353SPeter Maydell .read_with_attrs = gic_dist_read, 732a9d85353SPeter Maydell .write_with_attrs = gic_dist_write, 733755c0802SAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 734e69954b9Spbrook }; 735e69954b9Spbrook 736a9d85353SPeter Maydell static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, 737a9d85353SPeter Maydell uint64_t *data, MemTxAttrs attrs) 738e69954b9Spbrook { 739e69954b9Spbrook switch (offset) { 740e69954b9Spbrook case 0x00: /* Control */ 741a9d85353SPeter Maydell *data = s->cpu_enabled[cpu]; 742a9d85353SPeter Maydell break; 743e69954b9Spbrook case 0x04: /* Priority mask */ 744a9d85353SPeter Maydell *data = s->priority_mask[cpu]; 745a9d85353SPeter Maydell break; 746e69954b9Spbrook case 0x08: /* Binary Point */ 747a9d85353SPeter Maydell *data = s->bpr[cpu]; 748a9d85353SPeter Maydell break; 749e69954b9Spbrook case 0x0c: /* Acknowledge */ 750a9d85353SPeter Maydell *data = gic_acknowledge_irq(s, cpu); 751a9d85353SPeter Maydell break; 75266a0a2cbSDong Xu Wang case 0x14: /* Running Priority */ 753a9d85353SPeter Maydell *data = s->running_priority[cpu]; 754a9d85353SPeter Maydell break; 755e69954b9Spbrook case 0x18: /* Highest Pending Interrupt */ 756a9d85353SPeter Maydell *data = s->current_pending[cpu]; 757a9d85353SPeter Maydell break; 758aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 759a9d85353SPeter Maydell *data = s->abpr[cpu]; 760a9d85353SPeter Maydell break; 761a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 762a9d85353SPeter Maydell *data = s->apr[(offset - 0xd0) / 4][cpu]; 763a9d85353SPeter Maydell break; 764e69954b9Spbrook default: 7658c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 7668c8dc39fSPeter Maydell "gic_cpu_read: Bad offset %x\n", (int)offset); 767a9d85353SPeter Maydell return MEMTX_ERROR; 768e69954b9Spbrook } 769a9d85353SPeter Maydell return MEMTX_OK; 770e69954b9Spbrook } 771e69954b9Spbrook 772a9d85353SPeter Maydell static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, 773a9d85353SPeter Maydell uint32_t value, MemTxAttrs attrs) 774e69954b9Spbrook { 775e69954b9Spbrook switch (offset) { 776e69954b9Spbrook case 0x00: /* Control */ 7779ee6e8bbSpbrook s->cpu_enabled[cpu] = (value & 1); 7789ab1b605SEvgeny Voevodin DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis"); 779e69954b9Spbrook break; 780e69954b9Spbrook case 0x04: /* Priority mask */ 7819ee6e8bbSpbrook s->priority_mask[cpu] = (value & 0xff); 782e69954b9Spbrook break; 783e69954b9Spbrook case 0x08: /* Binary Point */ 784aa7d461aSChristoffer Dall s->bpr[cpu] = (value & 0x7); 785e69954b9Spbrook break; 786e69954b9Spbrook case 0x10: /* End Of Interrupt */ 787e7ae771fSStefan Weil gic_complete_irq(s, cpu, value & 0x3ff); 788a9d85353SPeter Maydell return MEMTX_OK; 789aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 790aa7d461aSChristoffer Dall if (s->revision >= 2) { 791aa7d461aSChristoffer Dall s->abpr[cpu] = (value & 0x7); 792aa7d461aSChristoffer Dall } 793aa7d461aSChristoffer Dall break; 794a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 795a9d477c4SChristoffer Dall qemu_log_mask(LOG_UNIMP, "Writing APR not implemented\n"); 796a9d477c4SChristoffer Dall break; 797e69954b9Spbrook default: 7988c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 7998c8dc39fSPeter Maydell "gic_cpu_write: Bad offset %x\n", (int)offset); 800a9d85353SPeter Maydell return MEMTX_ERROR; 801e69954b9Spbrook } 802e69954b9Spbrook gic_update(s); 803a9d85353SPeter Maydell return MEMTX_OK; 804e69954b9Spbrook } 805e2c56465SPeter Maydell 806e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for the current CPU */ 807a9d85353SPeter Maydell static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data, 808a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 809e2c56465SPeter Maydell { 810fae15286SPeter Maydell GICState *s = (GICState *)opaque; 811a9d85353SPeter Maydell return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs); 812e2c56465SPeter Maydell } 813e2c56465SPeter Maydell 814a9d85353SPeter Maydell static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr, 815a9d85353SPeter Maydell uint64_t value, unsigned size, 816a9d85353SPeter Maydell MemTxAttrs attrs) 817e2c56465SPeter Maydell { 818fae15286SPeter Maydell GICState *s = (GICState *)opaque; 819a9d85353SPeter Maydell return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs); 820e2c56465SPeter Maydell } 821e2c56465SPeter Maydell 822e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for a specific CPU. 823fae15286SPeter Maydell * These just decode the opaque pointer into GICState* + cpu id. 824e2c56465SPeter Maydell */ 825a9d85353SPeter Maydell static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data, 826a9d85353SPeter Maydell unsigned size, MemTxAttrs attrs) 827e2c56465SPeter Maydell { 828fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 829fae15286SPeter Maydell GICState *s = *backref; 830e2c56465SPeter Maydell int id = (backref - s->backref); 831a9d85353SPeter Maydell return gic_cpu_read(s, id, addr, data, attrs); 832e2c56465SPeter Maydell } 833e2c56465SPeter Maydell 834a9d85353SPeter Maydell static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr, 835a9d85353SPeter Maydell uint64_t value, unsigned size, 836a9d85353SPeter Maydell MemTxAttrs attrs) 837e2c56465SPeter Maydell { 838fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 839fae15286SPeter Maydell GICState *s = *backref; 840e2c56465SPeter Maydell int id = (backref - s->backref); 841a9d85353SPeter Maydell return gic_cpu_write(s, id, addr, value, attrs); 842e2c56465SPeter Maydell } 843e2c56465SPeter Maydell 844e2c56465SPeter Maydell static const MemoryRegionOps gic_thiscpu_ops = { 845a9d85353SPeter Maydell .read_with_attrs = gic_thiscpu_read, 846a9d85353SPeter Maydell .write_with_attrs = gic_thiscpu_write, 847e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 848e2c56465SPeter Maydell }; 849e2c56465SPeter Maydell 850e2c56465SPeter Maydell static const MemoryRegionOps gic_cpu_ops = { 851a9d85353SPeter Maydell .read_with_attrs = gic_do_cpu_read, 852a9d85353SPeter Maydell .write_with_attrs = gic_do_cpu_write, 853e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 854e2c56465SPeter Maydell }; 855e69954b9Spbrook 8567b95a508SKONRAD Frederic void gic_init_irqs_and_distributor(GICState *s) 857e69954b9Spbrook { 858285b4432SAndreas Färber SysBusDevice *sbd = SYS_BUS_DEVICE(s); 8599ee6e8bbSpbrook int i; 860e69954b9Spbrook 861544d1afaSPeter Maydell i = s->num_irq - GIC_INTERNAL; 862544d1afaSPeter Maydell /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU. 863544d1afaSPeter Maydell * GPIO array layout is thus: 864544d1afaSPeter Maydell * [0..N-1] SPIs 865544d1afaSPeter Maydell * [N..N+31] PPIs for CPU 0 866544d1afaSPeter Maydell * [N+32..N+63] PPIs for CPU 1 867544d1afaSPeter Maydell * ... 868544d1afaSPeter Maydell */ 86984e4fccbSPeter Maydell if (s->revision != REV_NVIC) { 870c48c6522SPeter Maydell i += (GIC_INTERNAL * s->num_cpu); 87184e4fccbSPeter Maydell } 872285b4432SAndreas Färber qdev_init_gpio_in(DEVICE(s), gic_set_irq, i); 873c988bfadSPaul Brook for (i = 0; i < NUM_CPU(s); i++) { 874285b4432SAndreas Färber sysbus_init_irq(sbd, &s->parent_irq[i]); 8759ee6e8bbSpbrook } 87644f55296SFabian Aggeler for (i = 0; i < NUM_CPU(s); i++) { 87744f55296SFabian Aggeler sysbus_init_irq(sbd, &s->parent_fiq[i]); 87844f55296SFabian Aggeler } 8791437c94bSPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s, 8801437c94bSPaolo Bonzini "gic_dist", 0x1000); 8812b518c56SPeter Maydell } 8822b518c56SPeter Maydell 88353111180SPeter Maydell static void arm_gic_realize(DeviceState *dev, Error **errp) 8842b518c56SPeter Maydell { 88553111180SPeter Maydell /* Device instance realize function for the GIC sysbus device */ 8862b518c56SPeter Maydell int i; 88753111180SPeter Maydell GICState *s = ARM_GIC(dev); 88853111180SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 8891e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_GET_CLASS(s); 8900175ba10SMarkus Armbruster Error *local_err = NULL; 8911e8cae4dSPeter Maydell 8920175ba10SMarkus Armbruster agc->parent_realize(dev, &local_err); 8930175ba10SMarkus Armbruster if (local_err) { 8940175ba10SMarkus Armbruster error_propagate(errp, local_err); 89553111180SPeter Maydell return; 89653111180SPeter Maydell } 8971e8cae4dSPeter Maydell 8987b95a508SKONRAD Frederic gic_init_irqs_and_distributor(s); 8992b518c56SPeter Maydell 900e2c56465SPeter Maydell /* Memory regions for the CPU interfaces (NVIC doesn't have these): 901e2c56465SPeter Maydell * a region for "CPU interface for this core", then a region for 902e2c56465SPeter Maydell * "CPU interface for core 0", "for core 1", ... 903e2c56465SPeter Maydell * NB that the memory region size of 0x100 applies for the 11MPCore 904e2c56465SPeter Maydell * and also cores following the GIC v1 spec (ie A9). 905e2c56465SPeter Maydell * GIC v2 defines a larger memory region (0x1000) so this will need 906e2c56465SPeter Maydell * to be extended when we implement A15. 907e2c56465SPeter Maydell */ 9081437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s, 909e2c56465SPeter Maydell "gic_cpu", 0x100); 910e2c56465SPeter Maydell for (i = 0; i < NUM_CPU(s); i++) { 911e2c56465SPeter Maydell s->backref[i] = s; 9121437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, 9131437c94bSPaolo Bonzini &s->backref[i], "gic_cpu", 0x100); 914e2c56465SPeter Maydell } 915496dbcd1SPeter Maydell /* Distributor */ 91653111180SPeter Maydell sysbus_init_mmio(sbd, &s->iomem); 917496dbcd1SPeter Maydell /* cpu interfaces (one for "current cpu" plus one per cpu) */ 918496dbcd1SPeter Maydell for (i = 0; i <= NUM_CPU(s); i++) { 91953111180SPeter Maydell sysbus_init_mmio(sbd, &s->cpuiomem[i]); 920496dbcd1SPeter Maydell } 921496dbcd1SPeter Maydell } 922496dbcd1SPeter Maydell 923496dbcd1SPeter Maydell static void arm_gic_class_init(ObjectClass *klass, void *data) 924496dbcd1SPeter Maydell { 925496dbcd1SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 9261e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_CLASS(klass); 92753111180SPeter Maydell 92853111180SPeter Maydell agc->parent_realize = dc->realize; 92953111180SPeter Maydell dc->realize = arm_gic_realize; 930496dbcd1SPeter Maydell } 931496dbcd1SPeter Maydell 9328c43a6f0SAndreas Färber static const TypeInfo arm_gic_info = { 9331e8cae4dSPeter Maydell .name = TYPE_ARM_GIC, 9341e8cae4dSPeter Maydell .parent = TYPE_ARM_GIC_COMMON, 935fae15286SPeter Maydell .instance_size = sizeof(GICState), 936496dbcd1SPeter Maydell .class_init = arm_gic_class_init, 937998a74bcSPeter Maydell .class_size = sizeof(ARMGICClass), 938496dbcd1SPeter Maydell }; 939496dbcd1SPeter Maydell 940496dbcd1SPeter Maydell static void arm_gic_register_types(void) 941496dbcd1SPeter Maydell { 942496dbcd1SPeter Maydell type_register_static(&arm_gic_info); 943496dbcd1SPeter Maydell } 944496dbcd1SPeter Maydell 945496dbcd1SPeter Maydell type_init(arm_gic_register_types) 946