arm_gic.c 29.1 KB
Newer Older
1
/*
P
pbrook 已提交
2
 * ARM Generic/Distributed Interrupt Controller
P
pbrook 已提交
3
 *
P
pbrook 已提交
4
 * Copyright (c) 2006-2007 CodeSourcery.
P
pbrook 已提交
5 6
 * Written by Paul Brook
 *
M
Matthew Fernandez 已提交
7
 * This code is licensed under the GPL.
P
pbrook 已提交
8 9
 */

P
pbrook 已提交
10
/* This file contains implementation code for the RealView EB interrupt
11 12 13 14 15 16 17 18 19
 * controller, MPCore distributed interrupt controller and ARMv7-M
 * Nested Vectored Interrupt Controller.
 * It is compiled in two ways:
 *  (1) as a standalone file to produce a sysbus device which is a GIC
 *  that can be used on the realview board and as one of the builtin
 *  private peripherals for the ARM MP CPUs (11MPCore, A9, etc)
 *  (2) by being directly #included into armv7m_nvic.c to produce the
 *  armv7m_nvic device.
 */
P
pbrook 已提交
20

21
#include "hw/sysbus.h"
22
#include "gic_internal.h"
23
#include "qom/cpu.h"
24

P
pbrook 已提交
25 26 27
//#define DEBUG_GIC

#ifdef DEBUG_GIC
28
#define DPRINTF(fmt, ...) \
29
do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0)
P
pbrook 已提交
30
#else
31
#define DPRINTF(fmt, ...) do {} while(0)
P
pbrook 已提交
32 33
#endif

34 35 36 37
static const uint8_t gic_id[] = {
    0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
};

P
Paul Brook 已提交
38
#define NUM_CPU(s) ((s)->num_cpu)
P
pbrook 已提交
39

40
static inline int gic_get_current_cpu(GICState *s)
41 42
{
    if (s->num_cpu > 1) {
43
        return current_cpu->cpu_index;
44 45 46 47
    }
    return 0;
}

48 49 50 51 52 53 54 55
/* Return true if this GIC config has interrupt groups, which is
 * true if we're a GICv2, or a GICv1 with the security extensions.
 */
static inline bool gic_has_groups(GICState *s)
{
    return s->revision == 2 || s->security_extn;
}

P
pbrook 已提交
56 57
/* TODO: Many places that call this routine could be optimized.  */
/* Update interrupt status after enabled or pending bits have been changed.  */
58
void gic_update(GICState *s)
P
pbrook 已提交
59 60 61 62
{
    int best_irq;
    int best_prio;
    int irq;
P
pbrook 已提交
63 64 65 66
    int level;
    int cpu;
    int cm;

P
Paul Brook 已提交
67
    for (cpu = 0; cpu < NUM_CPU(s); cpu++) {
P
pbrook 已提交
68 69 70
        cm = 1 << cpu;
        s->current_pending[cpu] = 1023;
        if (!s->enabled || !s->cpu_enabled[cpu]) {
71
            qemu_irq_lower(s->parent_irq[cpu]);
P
pbrook 已提交
72 73 74 75
            return;
        }
        best_prio = 0x100;
        best_irq = 1023;
76
        for (irq = 0; irq < s->num_irq; irq++) {
77 78
            if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm) &&
                (irq < GIC_INTERNAL || GIC_TARGET(irq) & cm)) {
P
pbrook 已提交
79 80 81 82
                if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
                    best_prio = GIC_GET_PRIORITY(irq, cpu);
                    best_irq = irq;
                }
P
pbrook 已提交
83 84
            }
        }
P
pbrook 已提交
85
        level = 0;
86
        if (best_prio < s->priority_mask[cpu]) {
P
pbrook 已提交
87 88
            s->current_pending[cpu] = best_irq;
            if (best_prio < s->running_priority[cpu]) {
89
                DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu);
P
pbrook 已提交
90 91
                level = 1;
            }
P
pbrook 已提交
92
        }
P
pbrook 已提交
93
        qemu_set_irq(s->parent_irq[cpu], level);
P
pbrook 已提交
94 95 96
    }
}

97
void gic_set_pending_private(GICState *s, int cpu, int irq)
P
pbrook 已提交
98 99 100
{
    int cm = 1 << cpu;

101
    if (gic_test_pending(s, irq, cm)) {
P
pbrook 已提交
102
        return;
103
    }
P
pbrook 已提交
104 105 106 107 108 109

    DPRINTF("Set %d pending cpu %d\n", irq, cpu);
    GIC_SET_PENDING(irq, cm);
    gic_update(s);
}

110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
static void gic_set_irq_11mpcore(GICState *s, int irq, int level,
                                 int cm, int target)
{
    if (level) {
        GIC_SET_LEVEL(irq, cm);
        if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
            DPRINTF("Set %d pending mask %x\n", irq, target);
            GIC_SET_PENDING(irq, target);
        }
    } else {
        GIC_CLEAR_LEVEL(irq, cm);
    }
}

static void gic_set_irq_generic(GICState *s, int irq, int level,
                                int cm, int target)
{
    if (level) {
        GIC_SET_LEVEL(irq, cm);
        DPRINTF("Set %d pending mask %x\n", irq, target);
        if (GIC_TEST_EDGE_TRIGGER(irq)) {
            GIC_SET_PENDING(irq, target);
        }
    } else {
        GIC_CLEAR_LEVEL(irq, cm);
    }
}

P
pbrook 已提交
138
/* Process a change in an external IRQ input.  */
P
pbrook 已提交
139 140
static void gic_set_irq(void *opaque, int irq, int level)
{
141 142 143 144 145 146
    /* Meaning of the 'irq' parameter:
     *  [0..N-1] : external interrupts
     *  [N..N+31] : PPI (internal) interrupts for CPU 0
     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
     *  ...
     */
147
    GICState *s = (GICState *)opaque;
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
    int cm, target;
    if (irq < (s->num_irq - GIC_INTERNAL)) {
        /* The first external input line is internal interrupt 32.  */
        cm = ALL_CPU_MASK;
        irq += GIC_INTERNAL;
        target = GIC_TARGET(irq);
    } else {
        int cpu;
        irq -= (s->num_irq - GIC_INTERNAL);
        cpu = irq / GIC_INTERNAL;
        irq %= GIC_INTERNAL;
        cm = 1 << cpu;
        target = cm;
    }

163 164
    assert(irq >= GIC_NR_SGIS);

165
    if (level == GIC_TEST_LEVEL(irq, cm)) {
P
pbrook 已提交
166
        return;
167
    }
P
pbrook 已提交
168

169 170
    if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
        gic_set_irq_11mpcore(s, irq, level, cm, target);
P
pbrook 已提交
171
    } else {
172
        gic_set_irq_generic(s, irq, level, cm, target);
P
pbrook 已提交
173
    }
174

P
pbrook 已提交
175 176 177
    gic_update(s);
}

178
static void gic_set_running_irq(GICState *s, int cpu, int irq)
P
pbrook 已提交
179
{
P
pbrook 已提交
180 181 182 183 184 185
    s->running_irq[cpu] = irq;
    if (irq == 1023) {
        s->running_priority[cpu] = 0x100;
    } else {
        s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
    }
P
pbrook 已提交
186 187 188
    gic_update(s);
}

189
uint32_t gic_acknowledge_irq(GICState *s, int cpu)
P
pbrook 已提交
190
{
191
    int ret, irq, src;
P
pbrook 已提交
192
    int cm = 1 << cpu;
193 194 195
    irq = s->current_pending[cpu];
    if (irq == 1023
            || GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) {
P
pbrook 已提交
196 197 198
        DPRINTF("ACK no pending IRQ\n");
        return 1023;
    }
199 200
    s->last_active[irq][cpu] = s->running_irq[cpu];

201
    if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
        /* Clear pending flags for both level and edge triggered interrupts.
         * Level triggered IRQs will be reasserted once they become inactive.
         */
        GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm);
        ret = irq;
    } else {
        if (irq < GIC_NR_SGIS) {
            /* Lookup the source CPU for the SGI and clear this in the
             * sgi_pending map.  Return the src and clear the overall pending
             * state on this CPU if the SGI is not pending from any CPUs.
             */
            assert(s->sgi_pending[irq][cpu] != 0);
            src = ctz32(s->sgi_pending[irq][cpu]);
            s->sgi_pending[irq][cpu] &= ~(1 << src);
            if (s->sgi_pending[irq][cpu] == 0) {
                GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm);
            }
            ret = irq | ((src & 0x7) << 10);
        } else {
            /* Clear pending state for both level and edge triggered
             * interrupts. (level triggered interrupts with an active line
             * remain pending, see gic_test_pending)
             */
            GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm);
            ret = irq;
        }
    }

    gic_set_running_irq(s, cpu, irq);
    DPRINTF("ACK %d\n", irq);
    return ret;
P
pbrook 已提交
233 234
}

235 236 237 238 239 240 241 242 243
void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val)
{
    if (irq < GIC_INTERNAL) {
        s->priority1[irq][cpu] = val;
    } else {
        s->priority2[(irq) - GIC_INTERNAL] = val;
    }
}

244
void gic_complete_irq(GICState *s, int cpu, int irq)
P
pbrook 已提交
245 246
{
    int update = 0;
P
pbrook 已提交
247
    int cm = 1 << cpu;
P
pbrook 已提交
248
    DPRINTF("EOI %d\n", irq);
249
    if (irq >= s->num_irq) {
250 251 252 253 254 255 256 257 258 259
        /* This handles two cases:
         * 1. If software writes the ID of a spurious interrupt [ie 1023]
         * to the GICC_EOIR, the GIC ignores that write.
         * 2. If software writes the number of a non-existent interrupt
         * this must be a subcase of "value written does not match the last
         * valid interrupt value read from the Interrupt Acknowledge
         * register" and so this is UNPREDICTABLE. We choose to ignore it.
         */
        return;
    }
P
pbrook 已提交
260
    if (s->running_irq[cpu] == 1023)
P
pbrook 已提交
261
        return; /* No active IRQ.  */
262 263 264 265 266 267 268 269 270 271

    if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
        /* Mark level triggered interrupts as pending if they are still
           raised.  */
        if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
            && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
            DPRINTF("Set %d pending mask %x\n", irq, cm);
            GIC_SET_PENDING(irq, cm);
            update = 1;
        }
P
pbrook 已提交
272
    }
273

P
pbrook 已提交
274
    if (irq != s->running_irq[cpu]) {
P
pbrook 已提交
275
        /* Complete an IRQ that is not currently running.  */
P
pbrook 已提交
276 277 278 279
        int tmp = s->running_irq[cpu];
        while (s->last_active[tmp][cpu] != 1023) {
            if (s->last_active[tmp][cpu] == irq) {
                s->last_active[tmp][cpu] = s->last_active[irq][cpu];
P
pbrook 已提交
280 281
                break;
            }
P
pbrook 已提交
282
            tmp = s->last_active[tmp][cpu];
P
pbrook 已提交
283 284 285 286 287 288
        }
        if (update) {
            gic_update(s);
        }
    } else {
        /* Complete the current running IRQ.  */
P
pbrook 已提交
289
        gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
P
pbrook 已提交
290 291 292
    }
}

293
static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs)
P
pbrook 已提交
294
{
295
    GICState *s = (GICState *)opaque;
P
pbrook 已提交
296 297 298
    uint32_t res;
    int irq;
    int i;
P
pbrook 已提交
299 300 301
    int cpu;
    int cm;
    int mask;
P
pbrook 已提交
302

303
    cpu = gic_get_current_cpu(s);
P
pbrook 已提交
304
    cm = 1 << cpu;
P
pbrook 已提交
305 306 307 308
    if (offset < 0x100) {
        if (offset == 0)
            return s->enabled;
        if (offset == 4)
309 310 311 312
            /* Interrupt Controller Type Register */
            return ((s->num_irq / 32) - 1)
                    | ((NUM_CPU(s) - 1) << 5)
                    | (s->security_extn << 10);
P
pbrook 已提交
313 314
        if (offset < 0x08)
            return 0;
315
        if (offset >= 0x80) {
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
            /* Interrupt Group Registers: these RAZ/WI if this is an NS
             * access to a GIC with the security extensions, or if the GIC
             * doesn't have groups at all.
             */
            res = 0;
            if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) {
                /* Every byte offset holds 8 group status bits */
                irq = (offset - 0x080) * 8 + GIC_BASE_IRQ;
                if (irq >= s->num_irq) {
                    goto bad_reg;
                }
                for (i = 0; i < 8; i++) {
                    if (GIC_TEST_GROUP(irq + i, cm)) {
                        res |= (1 << i);
                    }
                }
            }
            return res;
334
        }
P
pbrook 已提交
335 336 337 338 339 340 341
        goto bad_reg;
    } else if (offset < 0x200) {
        /* Interrupt Set/Clear Enable.  */
        if (offset < 0x180)
            irq = (offset - 0x100) * 8;
        else
            irq = (offset - 0x180) * 8;
P
pbrook 已提交
342
        irq += GIC_BASE_IRQ;
343
        if (irq >= s->num_irq)
P
pbrook 已提交
344 345 346
            goto bad_reg;
        res = 0;
        for (i = 0; i < 8; i++) {
347
            if (GIC_TEST_ENABLED(irq + i, cm)) {
P
pbrook 已提交
348 349 350 351 352 353 354 355 356
                res |= (1 << i);
            }
        }
    } else if (offset < 0x300) {
        /* Interrupt Set/Clear Pending.  */
        if (offset < 0x280)
            irq = (offset - 0x200) * 8;
        else
            irq = (offset - 0x280) * 8;
P
pbrook 已提交
357
        irq += GIC_BASE_IRQ;
358
        if (irq >= s->num_irq)
P
pbrook 已提交
359 360
            goto bad_reg;
        res = 0;
R
Rusty Russell 已提交
361
        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
P
pbrook 已提交
362
        for (i = 0; i < 8; i++) {
363
            if (gic_test_pending(s, irq + i, mask)) {
P
pbrook 已提交
364 365 366 367 368
                res |= (1 << i);
            }
        }
    } else if (offset < 0x400) {
        /* Interrupt Active.  */
P
pbrook 已提交
369
        irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
370
        if (irq >= s->num_irq)
P
pbrook 已提交
371 372
            goto bad_reg;
        res = 0;
R
Rusty Russell 已提交
373
        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
P
pbrook 已提交
374
        for (i = 0; i < 8; i++) {
P
pbrook 已提交
375
            if (GIC_TEST_ACTIVE(irq + i, mask)) {
P
pbrook 已提交
376 377 378 379 380
                res |= (1 << i);
            }
        }
    } else if (offset < 0x800) {
        /* Interrupt Priority.  */
P
pbrook 已提交
381
        irq = (offset - 0x400) + GIC_BASE_IRQ;
382
        if (irq >= s->num_irq)
P
pbrook 已提交
383
            goto bad_reg;
P
pbrook 已提交
384
        res = GIC_GET_PRIORITY(irq, cpu);
P
pbrook 已提交
385 386
    } else if (offset < 0xc00) {
        /* Interrupt CPU Target.  */
387 388 389
        if (s->num_cpu == 1 && s->revision != REV_11MPCORE) {
            /* For uniprocessor GICs these RAZ/WI */
            res = 0;
P
pbrook 已提交
390
        } else {
391 392 393 394 395 396 397 398 399
            irq = (offset - 0x800) + GIC_BASE_IRQ;
            if (irq >= s->num_irq) {
                goto bad_reg;
            }
            if (irq >= 29 && irq <= 31) {
                res = cm;
            } else {
                res = GIC_TARGET(irq);
            }
P
pbrook 已提交
400
        }
P
pbrook 已提交
401 402
    } else if (offset < 0xf00) {
        /* Interrupt Configuration.  */
403
        irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
404
        if (irq >= s->num_irq)
P
pbrook 已提交
405 406 407 408 409
            goto bad_reg;
        res = 0;
        for (i = 0; i < 4; i++) {
            if (GIC_TEST_MODEL(irq + i))
                res |= (1 << (i * 2));
410
            if (GIC_TEST_EDGE_TRIGGER(irq + i))
P
pbrook 已提交
411 412
                res |= (2 << (i * 2));
        }
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
    } else if (offset < 0xf10) {
        goto bad_reg;
    } else if (offset < 0xf30) {
        if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
            goto bad_reg;
        }

        if (offset < 0xf20) {
            /* GICD_CPENDSGIRn */
            irq = (offset - 0xf10);
        } else {
            irq = (offset - 0xf20);
            /* GICD_SPENDSGIRn */
        }

        res = s->sgi_pending[irq][cpu];
P
pbrook 已提交
429 430 431 432 433 434 435 436 437 438 439
    } else if (offset < 0xfe0) {
        goto bad_reg;
    } else /* offset >= 0xfe0 */ {
        if (offset & 3) {
            res = 0;
        } else {
            res = gic_id[(offset - 0xfe0) >> 2];
        }
    }
    return res;
bad_reg:
P
Peter Maydell 已提交
440 441
    qemu_log_mask(LOG_GUEST_ERROR,
                  "gic_dist_readb: Bad offset %x\n", (int)offset);
P
pbrook 已提交
442 443 444
    return 0;
}

445 446
static MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data,
                                 unsigned size, MemTxAttrs attrs)
P
pbrook 已提交
447
{
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
    switch (size) {
    case 1:
        *data = gic_dist_readb(opaque, offset, attrs);
        return MEMTX_OK;
    case 2:
        *data = gic_dist_readb(opaque, offset, attrs);
        *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8;
        return MEMTX_OK;
    case 4:
        *data = gic_dist_readb(opaque, offset, attrs);
        *data |= gic_dist_readb(opaque, offset + 1, attrs) << 8;
        *data |= gic_dist_readb(opaque, offset + 2, attrs) << 16;
        *data |= gic_dist_readb(opaque, offset + 3, attrs) << 24;
        return MEMTX_OK;
    default:
        return MEMTX_ERROR;
    }
P
pbrook 已提交
465 466
}

A
Avi Kivity 已提交
467
static void gic_dist_writeb(void *opaque, hwaddr offset,
468
                            uint32_t value, MemTxAttrs attrs)
P
pbrook 已提交
469
{
470
    GICState *s = (GICState *)opaque;
P
pbrook 已提交
471 472
    int irq;
    int i;
P
pbrook 已提交
473
    int cpu;
P
pbrook 已提交
474

475
    cpu = gic_get_current_cpu(s);
P
pbrook 已提交
476 477 478 479 480 481
    if (offset < 0x100) {
        if (offset == 0) {
            s->enabled = (value & 1);
            DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
        } else if (offset < 4) {
            /* ignored.  */
482
        } else if (offset >= 0x80) {
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
            /* Interrupt Group Registers: RAZ/WI for NS access to secure
             * GIC, or for GICs without groups.
             */
            if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) {
                /* Every byte offset holds 8 group status bits */
                irq = (offset - 0x80) * 8 + GIC_BASE_IRQ;
                if (irq >= s->num_irq) {
                    goto bad_reg;
                }
                for (i = 0; i < 8; i++) {
                    /* Group bits are banked for private interrupts */
                    int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
                    if (value & (1 << i)) {
                        /* Group1 (Non-secure) */
                        GIC_SET_GROUP(irq + i, cm);
                    } else {
                        /* Group0 (Secure) */
                        GIC_CLEAR_GROUP(irq + i, cm);
                    }
                }
            }
P
pbrook 已提交
504 505 506 507 508
        } else {
            goto bad_reg;
        }
    } else if (offset < 0x180) {
        /* Interrupt Set Enable.  */
P
pbrook 已提交
509
        irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
510
        if (irq >= s->num_irq)
P
pbrook 已提交
511
            goto bad_reg;
512 513 514 515
        if (irq < GIC_NR_SGIS) {
            value = 0xff;
        }

P
pbrook 已提交
516 517
        for (i = 0; i < 8; i++) {
            if (value & (1 << i)) {
518 519
                int mask =
                    (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i);
R
Rusty Russell 已提交
520
                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
521 522

                if (!GIC_TEST_ENABLED(irq + i, cm)) {
P
pbrook 已提交
523
                    DPRINTF("Enabled IRQ %d\n", irq + i);
524 525
                }
                GIC_SET_ENABLED(irq + i, cm);
P
pbrook 已提交
526 527
                /* If a raised level triggered IRQ enabled then mark
                   is as pending.  */
P
pbrook 已提交
528
                if (GIC_TEST_LEVEL(irq + i, mask)
529
                        && !GIC_TEST_EDGE_TRIGGER(irq + i)) {
P
pbrook 已提交
530 531 532
                    DPRINTF("Set %d pending mask %x\n", irq + i, mask);
                    GIC_SET_PENDING(irq + i, mask);
                }
P
pbrook 已提交
533 534 535 536
            }
        }
    } else if (offset < 0x200) {
        /* Interrupt Clear Enable.  */
P
pbrook 已提交
537
        irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
538
        if (irq >= s->num_irq)
P
pbrook 已提交
539
            goto bad_reg;
540 541 542 543
        if (irq < GIC_NR_SGIS) {
            value = 0;
        }

P
pbrook 已提交
544 545
        for (i = 0; i < 8; i++) {
            if (value & (1 << i)) {
R
Rusty Russell 已提交
546
                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
547 548

                if (GIC_TEST_ENABLED(irq + i, cm)) {
P
pbrook 已提交
549
                    DPRINTF("Disabled IRQ %d\n", irq + i);
550 551
                }
                GIC_CLEAR_ENABLED(irq + i, cm);
P
pbrook 已提交
552 553 554 555
            }
        }
    } else if (offset < 0x280) {
        /* Interrupt Set Pending.  */
P
pbrook 已提交
556
        irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
557
        if (irq >= s->num_irq)
P
pbrook 已提交
558
            goto bad_reg;
559
        if (irq < GIC_NR_SGIS) {
560
            value = 0;
561
        }
P
pbrook 已提交
562

P
pbrook 已提交
563 564
        for (i = 0; i < 8; i++) {
            if (value & (1 << i)) {
565
                GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i));
P
pbrook 已提交
566 567 568 569
            }
        }
    } else if (offset < 0x300) {
        /* Interrupt Clear Pending.  */
P
pbrook 已提交
570
        irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
571
        if (irq >= s->num_irq)
P
pbrook 已提交
572
            goto bad_reg;
573 574 575 576
        if (irq < GIC_NR_SGIS) {
            value = 0;
        }

P
pbrook 已提交
577
        for (i = 0; i < 8; i++) {
P
pbrook 已提交
578 579 580
            /* ??? This currently clears the pending bit for all CPUs, even
               for per-CPU interrupts.  It's unclear whether this is the
               corect behavior.  */
P
pbrook 已提交
581
            if (value & (1 << i)) {
P
pbrook 已提交
582
                GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
P
pbrook 已提交
583 584 585 586 587 588 589
            }
        }
    } else if (offset < 0x400) {
        /* Interrupt Active.  */
        goto bad_reg;
    } else if (offset < 0x800) {
        /* Interrupt Priority.  */
P
pbrook 已提交
590
        irq = (offset - 0x400) + GIC_BASE_IRQ;
591
        if (irq >= s->num_irq)
P
pbrook 已提交
592
            goto bad_reg;
593
        gic_set_priority(s, cpu, irq, value);
P
pbrook 已提交
594
    } else if (offset < 0xc00) {
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
        /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the
         * annoying exception of the 11MPCore's GIC.
         */
        if (s->num_cpu != 1 || s->revision == REV_11MPCORE) {
            irq = (offset - 0x800) + GIC_BASE_IRQ;
            if (irq >= s->num_irq) {
                goto bad_reg;
            }
            if (irq < 29) {
                value = 0;
            } else if (irq < GIC_INTERNAL) {
                value = ALL_CPU_MASK;
            }
            s->irq_target[irq] = value & ALL_CPU_MASK;
        }
P
pbrook 已提交
610 611
    } else if (offset < 0xf00) {
        /* Interrupt Configuration.  */
P
pbrook 已提交
612
        irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
613
        if (irq >= s->num_irq)
P
pbrook 已提交
614
            goto bad_reg;
615
        if (irq < GIC_NR_SGIS)
P
pbrook 已提交
616
            value |= 0xaa;
P
pbrook 已提交
617
        for (i = 0; i < 4; i++) {
618 619 620 621 622 623
            if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
                if (value & (1 << (i * 2))) {
                    GIC_SET_MODEL(irq + i);
                } else {
                    GIC_CLEAR_MODEL(irq + i);
                }
P
pbrook 已提交
624 625
            }
            if (value & (2 << (i * 2))) {
626
                GIC_SET_EDGE_TRIGGER(irq + i);
P
pbrook 已提交
627
            } else {
628
                GIC_CLEAR_EDGE_TRIGGER(irq + i);
P
pbrook 已提交
629 630
            }
        }
631
    } else if (offset < 0xf10) {
P
pbrook 已提交
632
        /* 0xf00 is only handled for 32-bit writes.  */
P
pbrook 已提交
633
        goto bad_reg;
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
    } else if (offset < 0xf20) {
        /* GICD_CPENDSGIRn */
        if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
            goto bad_reg;
        }
        irq = (offset - 0xf10);

        s->sgi_pending[irq][cpu] &= ~value;
        if (s->sgi_pending[irq][cpu] == 0) {
            GIC_CLEAR_PENDING(irq, 1 << cpu);
        }
    } else if (offset < 0xf30) {
        /* GICD_SPENDSGIRn */
        if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
            goto bad_reg;
        }
        irq = (offset - 0xf20);

        GIC_SET_PENDING(irq, 1 << cpu);
        s->sgi_pending[irq][cpu] |= value;
    } else {
        goto bad_reg;
P
pbrook 已提交
656 657 658 659
    }
    gic_update(s);
    return;
bad_reg:
P
Peter Maydell 已提交
660 661
    qemu_log_mask(LOG_GUEST_ERROR,
                  "gic_dist_writeb: Bad offset %x\n", (int)offset);
P
pbrook 已提交
662 663
}

A
Avi Kivity 已提交
664
static void gic_dist_writew(void *opaque, hwaddr offset,
665
                            uint32_t value, MemTxAttrs attrs)
P
pbrook 已提交
666
{
667 668
    gic_dist_writeb(opaque, offset, value & 0xff, attrs);
    gic_dist_writeb(opaque, offset + 1, value >> 8, attrs);
P
pbrook 已提交
669 670
}

A
Avi Kivity 已提交
671
static void gic_dist_writel(void *opaque, hwaddr offset,
672
                            uint32_t value, MemTxAttrs attrs)
P
pbrook 已提交
673
{
674
    GICState *s = (GICState *)opaque;
675
    if (offset == 0xf00) {
P
pbrook 已提交
676 677 678
        int cpu;
        int irq;
        int mask;
679
        int target_cpu;
P
pbrook 已提交
680

681
        cpu = gic_get_current_cpu(s);
P
pbrook 已提交
682 683 684 685 686 687
        irq = value & 0x3ff;
        switch ((value >> 24) & 3) {
        case 0:
            mask = (value >> 16) & ALL_CPU_MASK;
            break;
        case 1:
688
            mask = ALL_CPU_MASK ^ (1 << cpu);
P
pbrook 已提交
689 690
            break;
        case 2:
691
            mask = 1 << cpu;
P
pbrook 已提交
692 693 694 695 696 697 698
            break;
        default:
            DPRINTF("Bad Soft Int target filter\n");
            mask = ALL_CPU_MASK;
            break;
        }
        GIC_SET_PENDING(irq, mask);
699 700 701 702 703 704
        target_cpu = ctz32(mask);
        while (target_cpu < GIC_NCPU) {
            s->sgi_pending[irq][target_cpu] |= (1 << cpu);
            mask &= ~(1 << target_cpu);
            target_cpu = ctz32(mask);
        }
P
pbrook 已提交
705 706 707
        gic_update(s);
        return;
    }
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
    gic_dist_writew(opaque, offset, value & 0xffff, attrs);
    gic_dist_writew(opaque, offset + 2, value >> 16, attrs);
}

static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data,
                                  unsigned size, MemTxAttrs attrs)
{
    switch (size) {
    case 1:
        gic_dist_writeb(opaque, offset, data, attrs);
        return MEMTX_OK;
    case 2:
        gic_dist_writew(opaque, offset, data, attrs);
        return MEMTX_OK;
    case 4:
        gic_dist_writel(opaque, offset, data, attrs);
        return MEMTX_OK;
    default:
        return MEMTX_ERROR;
    }
P
pbrook 已提交
728 729
}

A
Avi Kivity 已提交
730
static const MemoryRegionOps gic_dist_ops = {
731 732
    .read_with_attrs = gic_dist_read,
    .write_with_attrs = gic_dist_write,
A
Avi Kivity 已提交
733
    .endianness = DEVICE_NATIVE_ENDIAN,
P
pbrook 已提交
734 735
};

736 737
static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
                                uint64_t *data, MemTxAttrs attrs)
P
pbrook 已提交
738 739 740
{
    switch (offset) {
    case 0x00: /* Control */
741 742
        *data = s->cpu_enabled[cpu];
        break;
P
pbrook 已提交
743
    case 0x04: /* Priority mask */
744 745
        *data = s->priority_mask[cpu];
        break;
P
pbrook 已提交
746
    case 0x08: /* Binary Point */
747 748
        *data = s->bpr[cpu];
        break;
P
pbrook 已提交
749
    case 0x0c: /* Acknowledge */
750 751
        *data = gic_acknowledge_irq(s, cpu);
        break;
D
Dong Xu Wang 已提交
752
    case 0x14: /* Running Priority */
753 754
        *data = s->running_priority[cpu];
        break;
P
pbrook 已提交
755
    case 0x18: /* Highest Pending Interrupt */
756 757
        *data = s->current_pending[cpu];
        break;
758
    case 0x1c: /* Aliased Binary Point */
759 760
        *data = s->abpr[cpu];
        break;
761
    case 0xd0: case 0xd4: case 0xd8: case 0xdc:
762 763
        *data = s->apr[(offset - 0xd0) / 4][cpu];
        break;
P
pbrook 已提交
764
    default:
P
Peter Maydell 已提交
765 766
        qemu_log_mask(LOG_GUEST_ERROR,
                      "gic_cpu_read: Bad offset %x\n", (int)offset);
767
        return MEMTX_ERROR;
P
pbrook 已提交
768
    }
769
    return MEMTX_OK;
P
pbrook 已提交
770 771
}

772 773
static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
                                 uint32_t value, MemTxAttrs attrs)
P
pbrook 已提交
774 775 776
{
    switch (offset) {
    case 0x00: /* Control */
P
pbrook 已提交
777
        s->cpu_enabled[cpu] = (value & 1);
778
        DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis");
P
pbrook 已提交
779 780
        break;
    case 0x04: /* Priority mask */
P
pbrook 已提交
781
        s->priority_mask[cpu] = (value & 0xff);
P
pbrook 已提交
782 783
        break;
    case 0x08: /* Binary Point */
784
        s->bpr[cpu] = (value & 0x7);
P
pbrook 已提交
785 786
        break;
    case 0x10: /* End Of Interrupt */
787
        gic_complete_irq(s, cpu, value & 0x3ff);
788
        return MEMTX_OK;
789 790 791 792 793
    case 0x1c: /* Aliased Binary Point */
        if (s->revision >= 2) {
            s->abpr[cpu] = (value & 0x7);
        }
        break;
794 795 796
    case 0xd0: case 0xd4: case 0xd8: case 0xdc:
        qemu_log_mask(LOG_UNIMP, "Writing APR not implemented\n");
        break;
P
pbrook 已提交
797
    default:
P
Peter Maydell 已提交
798 799
        qemu_log_mask(LOG_GUEST_ERROR,
                      "gic_cpu_write: Bad offset %x\n", (int)offset);
800
        return MEMTX_ERROR;
P
pbrook 已提交
801 802
    }
    gic_update(s);
803
    return MEMTX_OK;
P
pbrook 已提交
804
}
805 806

/* Wrappers to read/write the GIC CPU interface for the current CPU */
807 808
static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data,
                                    unsigned size, MemTxAttrs attrs)
809
{
810
    GICState *s = (GICState *)opaque;
811
    return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs);
812 813
}

814 815 816
static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr,
                                     uint64_t value, unsigned size,
                                     MemTxAttrs attrs)
817
{
818
    GICState *s = (GICState *)opaque;
819
    return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs);
820 821 822
}

/* Wrappers to read/write the GIC CPU interface for a specific CPU.
823
 * These just decode the opaque pointer into GICState* + cpu id.
824
 */
825 826
static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data,
                                   unsigned size, MemTxAttrs attrs)
827
{
828 829
    GICState **backref = (GICState **)opaque;
    GICState *s = *backref;
830
    int id = (backref - s->backref);
831
    return gic_cpu_read(s, id, addr, data, attrs);
832 833
}

834 835 836
static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr,
                                    uint64_t value, unsigned size,
                                    MemTxAttrs attrs)
837
{
838 839
    GICState **backref = (GICState **)opaque;
    GICState *s = *backref;
840
    int id = (backref - s->backref);
841
    return gic_cpu_write(s, id, addr, value, attrs);
842 843 844
}

static const MemoryRegionOps gic_thiscpu_ops = {
845 846
    .read_with_attrs = gic_thiscpu_read,
    .write_with_attrs = gic_thiscpu_write,
847 848 849 850
    .endianness = DEVICE_NATIVE_ENDIAN,
};

static const MemoryRegionOps gic_cpu_ops = {
851 852
    .read_with_attrs = gic_do_cpu_read,
    .write_with_attrs = gic_do_cpu_write,
853 854
    .endianness = DEVICE_NATIVE_ENDIAN,
};
P
pbrook 已提交
855

856
void gic_init_irqs_and_distributor(GICState *s)
P
pbrook 已提交
857
{
A
Andreas Färber 已提交
858
    SysBusDevice *sbd = SYS_BUS_DEVICE(s);
P
pbrook 已提交
859
    int i;
860

861 862 863 864 865 866 867 868
    i = s->num_irq - GIC_INTERNAL;
    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
     * GPIO array layout is thus:
     *  [0..N-1] SPIs
     *  [N..N+31] PPIs for CPU 0
     *  [N+32..N+63] PPIs for CPU 1
     *   ...
     */
869 870 871
    if (s->revision != REV_NVIC) {
        i += (GIC_INTERNAL * s->num_cpu);
    }
A
Andreas Färber 已提交
872
    qdev_init_gpio_in(DEVICE(s), gic_set_irq, i);
P
Paul Brook 已提交
873
    for (i = 0; i < NUM_CPU(s); i++) {
A
Andreas Färber 已提交
874
        sysbus_init_irq(sbd, &s->parent_irq[i]);
P
pbrook 已提交
875
    }
876 877 878
    for (i = 0; i < NUM_CPU(s); i++) {
        sysbus_init_irq(sbd, &s->parent_fiq[i]);
    }
879 880
    memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s,
                          "gic_dist", 0x1000);
881 882
}

883
static void arm_gic_realize(DeviceState *dev, Error **errp)
884
{
885
    /* Device instance realize function for the GIC sysbus device */
886
    int i;
887 888
    GICState *s = ARM_GIC(dev);
    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
889
    ARMGICClass *agc = ARM_GIC_GET_CLASS(s);
890
    Error *local_err = NULL;
891

892 893 894
    agc->parent_realize(dev, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
895 896
        return;
    }
897

898
    gic_init_irqs_and_distributor(s);
899

900 901 902 903 904 905 906 907
    /* Memory regions for the CPU interfaces (NVIC doesn't have these):
     * a region for "CPU interface for this core", then a region for
     * "CPU interface for core 0", "for core 1", ...
     * NB that the memory region size of 0x100 applies for the 11MPCore
     * and also cores following the GIC v1 spec (ie A9).
     * GIC v2 defines a larger memory region (0x1000) so this will need
     * to be extended when we implement A15.
     */
908
    memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s,
909 910 911
                          "gic_cpu", 0x100);
    for (i = 0; i < NUM_CPU(s); i++) {
        s->backref[i] = s;
912 913
        memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops,
                              &s->backref[i], "gic_cpu", 0x100);
914
    }
915
    /* Distributor */
916
    sysbus_init_mmio(sbd, &s->iomem);
917 918
    /* cpu interfaces (one for "current cpu" plus one per cpu) */
    for (i = 0; i <= NUM_CPU(s); i++) {
919
        sysbus_init_mmio(sbd, &s->cpuiomem[i]);
920 921 922 923 924 925
    }
}

static void arm_gic_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
926
    ARMGICClass *agc = ARM_GIC_CLASS(klass);
927 928 929

    agc->parent_realize = dc->realize;
    dc->realize = arm_gic_realize;
930 931
}

932
static const TypeInfo arm_gic_info = {
933 934
    .name = TYPE_ARM_GIC,
    .parent = TYPE_ARM_GIC_COMMON,
935
    .instance_size = sizeof(GICState),
936
    .class_init = arm_gic_class_init,
937
    .class_size = sizeof(ARMGICClass),
938 939 940 941 942 943 944 945
};

static void arm_gic_register_types(void)
{
    type_register_static(&arm_gic_info);
}

type_init(arm_gic_register_types)