arm_gic.c 27.3 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;
}

P
pbrook 已提交
48 49
/* TODO: Many places that call this routine could be optimized.  */
/* Update interrupt status after enabled or pending bits have been changed.  */
50
void gic_update(GICState *s)
P
pbrook 已提交
51 52 53 54
{
    int best_irq;
    int best_prio;
    int irq;
P
pbrook 已提交
55 56 57 58
    int level;
    int cpu;
    int cm;

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

89
void gic_set_pending_private(GICState *s, int cpu, int irq)
P
pbrook 已提交
90 91 92
{
    int cm = 1 << cpu;

93
    if (gic_test_pending(s, irq, cm)) {
P
pbrook 已提交
94
        return;
95
    }
P
pbrook 已提交
96 97 98 99 100 101

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

102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
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 已提交
130
/* Process a change in an external IRQ input.  */
P
pbrook 已提交
131 132
static void gic_set_irq(void *opaque, int irq, int level)
{
133 134 135 136 137 138
    /* 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
     *  ...
     */
139
    GICState *s = (GICState *)opaque;
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
    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;
    }

155 156
    assert(irq >= GIC_NR_SGIS);

157
    if (level == GIC_TEST_LEVEL(irq, cm)) {
P
pbrook 已提交
158
        return;
159
    }
P
pbrook 已提交
160

161 162
    if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
        gic_set_irq_11mpcore(s, irq, level, cm, target);
P
pbrook 已提交
163
    } else {
164
        gic_set_irq_generic(s, irq, level, cm, target);
P
pbrook 已提交
165
    }
166

P
pbrook 已提交
167 168 169
    gic_update(s);
}

170
static void gic_set_running_irq(GICState *s, int cpu, int irq)
P
pbrook 已提交
171
{
P
pbrook 已提交
172 173 174 175 176 177
    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 已提交
178 179 180
    gic_update(s);
}

181
uint32_t gic_acknowledge_irq(GICState *s, int cpu)
P
pbrook 已提交
182
{
183
    int ret, irq, src;
P
pbrook 已提交
184
    int cm = 1 << cpu;
185 186 187
    irq = s->current_pending[cpu];
    if (irq == 1023
            || GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) {
P
pbrook 已提交
188 189 190
        DPRINTF("ACK no pending IRQ\n");
        return 1023;
    }
191 192
    s->last_active[irq][cpu] = s->running_irq[cpu];

193
    if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
        /* 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 已提交
225 226
}

227 228 229 230 231 232 233 234 235
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;
    }
}

236
void gic_complete_irq(GICState *s, int cpu, int irq)
P
pbrook 已提交
237 238
{
    int update = 0;
P
pbrook 已提交
239
    int cm = 1 << cpu;
P
pbrook 已提交
240
    DPRINTF("EOI %d\n", irq);
241
    if (irq >= s->num_irq) {
242 243 244 245 246 247 248 249 250 251
        /* 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 已提交
252
    if (s->running_irq[cpu] == 1023)
P
pbrook 已提交
253
        return; /* No active IRQ.  */
254 255 256 257 258 259 260 261 262 263

    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 已提交
264
    }
265

P
pbrook 已提交
266
    if (irq != s->running_irq[cpu]) {
P
pbrook 已提交
267
        /* Complete an IRQ that is not currently running.  */
P
pbrook 已提交
268 269 270 271
        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 已提交
272 273
                break;
            }
P
pbrook 已提交
274
            tmp = s->last_active[tmp][cpu];
P
pbrook 已提交
275 276 277 278 279 280
        }
        if (update) {
            gic_update(s);
        }
    } else {
        /* Complete the current running IRQ.  */
P
pbrook 已提交
281
        gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
P
pbrook 已提交
282 283 284
    }
}

285
static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs)
P
pbrook 已提交
286
{
287
    GICState *s = (GICState *)opaque;
P
pbrook 已提交
288 289 290
    uint32_t res;
    int irq;
    int i;
P
pbrook 已提交
291 292 293
    int cpu;
    int cm;
    int mask;
P
pbrook 已提交
294

295
    cpu = gic_get_current_cpu(s);
P
pbrook 已提交
296
    cm = 1 << cpu;
P
pbrook 已提交
297 298 299 300
    if (offset < 0x100) {
        if (offset == 0)
            return s->enabled;
        if (offset == 4)
301 302 303 304
            /* Interrupt Controller Type Register */
            return ((s->num_irq / 32) - 1)
                    | ((NUM_CPU(s) - 1) << 5)
                    | (s->security_extn << 10);
P
pbrook 已提交
305 306
        if (offset < 0x08)
            return 0;
307 308 309 310
        if (offset >= 0x80) {
            /* Interrupt Security , RAZ/WI */
            return 0;
        }
P
pbrook 已提交
311 312 313 314 315 316 317
        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 已提交
318
        irq += GIC_BASE_IRQ;
319
        if (irq >= s->num_irq)
P
pbrook 已提交
320 321 322
            goto bad_reg;
        res = 0;
        for (i = 0; i < 8; i++) {
323
            if (GIC_TEST_ENABLED(irq + i, cm)) {
P
pbrook 已提交
324 325 326 327 328 329 330 331 332
                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 已提交
333
        irq += GIC_BASE_IRQ;
334
        if (irq >= s->num_irq)
P
pbrook 已提交
335 336
            goto bad_reg;
        res = 0;
R
Rusty Russell 已提交
337
        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
P
pbrook 已提交
338
        for (i = 0; i < 8; i++) {
339
            if (gic_test_pending(s, irq + i, mask)) {
P
pbrook 已提交
340 341 342 343 344
                res |= (1 << i);
            }
        }
    } else if (offset < 0x400) {
        /* Interrupt Active.  */
P
pbrook 已提交
345
        irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
346
        if (irq >= s->num_irq)
P
pbrook 已提交
347 348
            goto bad_reg;
        res = 0;
R
Rusty Russell 已提交
349
        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
P
pbrook 已提交
350
        for (i = 0; i < 8; i++) {
P
pbrook 已提交
351
            if (GIC_TEST_ACTIVE(irq + i, mask)) {
P
pbrook 已提交
352 353 354 355 356
                res |= (1 << i);
            }
        }
    } else if (offset < 0x800) {
        /* Interrupt Priority.  */
P
pbrook 已提交
357
        irq = (offset - 0x400) + GIC_BASE_IRQ;
358
        if (irq >= s->num_irq)
P
pbrook 已提交
359
            goto bad_reg;
P
pbrook 已提交
360
        res = GIC_GET_PRIORITY(irq, cpu);
P
pbrook 已提交
361 362
    } else if (offset < 0xc00) {
        /* Interrupt CPU Target.  */
363 364 365
        if (s->num_cpu == 1 && s->revision != REV_11MPCORE) {
            /* For uniprocessor GICs these RAZ/WI */
            res = 0;
P
pbrook 已提交
366
        } else {
367 368 369 370 371 372 373 374 375
            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 已提交
376
        }
P
pbrook 已提交
377 378
    } else if (offset < 0xf00) {
        /* Interrupt Configuration.  */
379
        irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
380
        if (irq >= s->num_irq)
P
pbrook 已提交
381 382 383 384 385
            goto bad_reg;
        res = 0;
        for (i = 0; i < 4; i++) {
            if (GIC_TEST_MODEL(irq + i))
                res |= (1 << (i * 2));
386
            if (GIC_TEST_EDGE_TRIGGER(irq + i))
P
pbrook 已提交
387 388
                res |= (2 << (i * 2));
        }
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
    } 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 已提交
405 406 407 408 409 410 411 412 413 414 415
    } 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 已提交
416 417
    qemu_log_mask(LOG_GUEST_ERROR,
                  "gic_dist_readb: Bad offset %x\n", (int)offset);
P
pbrook 已提交
418 419 420
    return 0;
}

421 422
static MemTxResult gic_dist_read(void *opaque, hwaddr offset, uint64_t *data,
                                 unsigned size, MemTxAttrs attrs)
P
pbrook 已提交
423
{
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
    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 已提交
441 442
}

A
Avi Kivity 已提交
443
static void gic_dist_writeb(void *opaque, hwaddr offset,
444
                            uint32_t value, MemTxAttrs attrs)
P
pbrook 已提交
445
{
446
    GICState *s = (GICState *)opaque;
P
pbrook 已提交
447 448
    int irq;
    int i;
P
pbrook 已提交
449
    int cpu;
P
pbrook 已提交
450

451
    cpu = gic_get_current_cpu(s);
P
pbrook 已提交
452 453 454 455 456 457
    if (offset < 0x100) {
        if (offset == 0) {
            s->enabled = (value & 1);
            DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
        } else if (offset < 4) {
            /* ignored.  */
458 459
        } else if (offset >= 0x80) {
            /* Interrupt Security Registers, RAZ/WI */
P
pbrook 已提交
460 461 462 463 464
        } else {
            goto bad_reg;
        }
    } else if (offset < 0x180) {
        /* Interrupt Set Enable.  */
P
pbrook 已提交
465
        irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
466
        if (irq >= s->num_irq)
P
pbrook 已提交
467
            goto bad_reg;
468 469 470 471
        if (irq < GIC_NR_SGIS) {
            value = 0xff;
        }

P
pbrook 已提交
472 473
        for (i = 0; i < 8; i++) {
            if (value & (1 << i)) {
474 475
                int mask =
                    (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i);
R
Rusty Russell 已提交
476
                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
477 478

                if (!GIC_TEST_ENABLED(irq + i, cm)) {
P
pbrook 已提交
479
                    DPRINTF("Enabled IRQ %d\n", irq + i);
480 481
                }
                GIC_SET_ENABLED(irq + i, cm);
P
pbrook 已提交
482 483
                /* If a raised level triggered IRQ enabled then mark
                   is as pending.  */
P
pbrook 已提交
484
                if (GIC_TEST_LEVEL(irq + i, mask)
485
                        && !GIC_TEST_EDGE_TRIGGER(irq + i)) {
P
pbrook 已提交
486 487 488
                    DPRINTF("Set %d pending mask %x\n", irq + i, mask);
                    GIC_SET_PENDING(irq + i, mask);
                }
P
pbrook 已提交
489 490 491 492
            }
        }
    } else if (offset < 0x200) {
        /* Interrupt Clear Enable.  */
P
pbrook 已提交
493
        irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
494
        if (irq >= s->num_irq)
P
pbrook 已提交
495
            goto bad_reg;
496 497 498 499
        if (irq < GIC_NR_SGIS) {
            value = 0;
        }

P
pbrook 已提交
500 501
        for (i = 0; i < 8; i++) {
            if (value & (1 << i)) {
R
Rusty Russell 已提交
502
                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
503 504

                if (GIC_TEST_ENABLED(irq + i, cm)) {
P
pbrook 已提交
505
                    DPRINTF("Disabled IRQ %d\n", irq + i);
506 507
                }
                GIC_CLEAR_ENABLED(irq + i, cm);
P
pbrook 已提交
508 509 510 511
            }
        }
    } else if (offset < 0x280) {
        /* Interrupt Set Pending.  */
P
pbrook 已提交
512
        irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
513
        if (irq >= s->num_irq)
P
pbrook 已提交
514
            goto bad_reg;
515
        if (irq < GIC_NR_SGIS) {
516
            value = 0;
517
        }
P
pbrook 已提交
518

P
pbrook 已提交
519 520
        for (i = 0; i < 8; i++) {
            if (value & (1 << i)) {
521
                GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i));
P
pbrook 已提交
522 523 524 525
            }
        }
    } else if (offset < 0x300) {
        /* Interrupt Clear Pending.  */
P
pbrook 已提交
526
        irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
527
        if (irq >= s->num_irq)
P
pbrook 已提交
528
            goto bad_reg;
529 530 531 532
        if (irq < GIC_NR_SGIS) {
            value = 0;
        }

P
pbrook 已提交
533
        for (i = 0; i < 8; i++) {
P
pbrook 已提交
534 535 536
            /* ??? 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 已提交
537
            if (value & (1 << i)) {
P
pbrook 已提交
538
                GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
P
pbrook 已提交
539 540 541 542 543 544 545
            }
        }
    } else if (offset < 0x400) {
        /* Interrupt Active.  */
        goto bad_reg;
    } else if (offset < 0x800) {
        /* Interrupt Priority.  */
P
pbrook 已提交
546
        irq = (offset - 0x400) + GIC_BASE_IRQ;
547
        if (irq >= s->num_irq)
P
pbrook 已提交
548
            goto bad_reg;
549
        gic_set_priority(s, cpu, irq, value);
P
pbrook 已提交
550
    } else if (offset < 0xc00) {
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
        /* 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 已提交
566 567
    } else if (offset < 0xf00) {
        /* Interrupt Configuration.  */
P
pbrook 已提交
568
        irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
569
        if (irq >= s->num_irq)
P
pbrook 已提交
570
            goto bad_reg;
571
        if (irq < GIC_NR_SGIS)
P
pbrook 已提交
572
            value |= 0xaa;
P
pbrook 已提交
573
        for (i = 0; i < 4; i++) {
574 575 576 577 578 579
            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 已提交
580 581
            }
            if (value & (2 << (i * 2))) {
582
                GIC_SET_EDGE_TRIGGER(irq + i);
P
pbrook 已提交
583
            } else {
584
                GIC_CLEAR_EDGE_TRIGGER(irq + i);
P
pbrook 已提交
585 586
            }
        }
587
    } else if (offset < 0xf10) {
P
pbrook 已提交
588
        /* 0xf00 is only handled for 32-bit writes.  */
P
pbrook 已提交
589
        goto bad_reg;
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
    } 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 已提交
612 613 614 615
    }
    gic_update(s);
    return;
bad_reg:
P
Peter Maydell 已提交
616 617
    qemu_log_mask(LOG_GUEST_ERROR,
                  "gic_dist_writeb: Bad offset %x\n", (int)offset);
P
pbrook 已提交
618 619
}

A
Avi Kivity 已提交
620
static void gic_dist_writew(void *opaque, hwaddr offset,
621
                            uint32_t value, MemTxAttrs attrs)
P
pbrook 已提交
622
{
623 624
    gic_dist_writeb(opaque, offset, value & 0xff, attrs);
    gic_dist_writeb(opaque, offset + 1, value >> 8, attrs);
P
pbrook 已提交
625 626
}

A
Avi Kivity 已提交
627
static void gic_dist_writel(void *opaque, hwaddr offset,
628
                            uint32_t value, MemTxAttrs attrs)
P
pbrook 已提交
629
{
630
    GICState *s = (GICState *)opaque;
631
    if (offset == 0xf00) {
P
pbrook 已提交
632 633 634
        int cpu;
        int irq;
        int mask;
635
        int target_cpu;
P
pbrook 已提交
636

637
        cpu = gic_get_current_cpu(s);
P
pbrook 已提交
638 639 640 641 642 643
        irq = value & 0x3ff;
        switch ((value >> 24) & 3) {
        case 0:
            mask = (value >> 16) & ALL_CPU_MASK;
            break;
        case 1:
644
            mask = ALL_CPU_MASK ^ (1 << cpu);
P
pbrook 已提交
645 646
            break;
        case 2:
647
            mask = 1 << cpu;
P
pbrook 已提交
648 649 650 651 652 653 654
            break;
        default:
            DPRINTF("Bad Soft Int target filter\n");
            mask = ALL_CPU_MASK;
            break;
        }
        GIC_SET_PENDING(irq, mask);
655 656 657 658 659 660
        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 已提交
661 662 663
        gic_update(s);
        return;
    }
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
    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 已提交
684 685
}

A
Avi Kivity 已提交
686
static const MemoryRegionOps gic_dist_ops = {
687 688
    .read_with_attrs = gic_dist_read,
    .write_with_attrs = gic_dist_write,
A
Avi Kivity 已提交
689
    .endianness = DEVICE_NATIVE_ENDIAN,
P
pbrook 已提交
690 691
};

692 693
static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
                                uint64_t *data, MemTxAttrs attrs)
P
pbrook 已提交
694 695 696
{
    switch (offset) {
    case 0x00: /* Control */
697 698
        *data = s->cpu_enabled[cpu];
        break;
P
pbrook 已提交
699
    case 0x04: /* Priority mask */
700 701
        *data = s->priority_mask[cpu];
        break;
P
pbrook 已提交
702
    case 0x08: /* Binary Point */
703 704
        *data = s->bpr[cpu];
        break;
P
pbrook 已提交
705
    case 0x0c: /* Acknowledge */
706 707
        *data = gic_acknowledge_irq(s, cpu);
        break;
D
Dong Xu Wang 已提交
708
    case 0x14: /* Running Priority */
709 710
        *data = s->running_priority[cpu];
        break;
P
pbrook 已提交
711
    case 0x18: /* Highest Pending Interrupt */
712 713
        *data = s->current_pending[cpu];
        break;
714
    case 0x1c: /* Aliased Binary Point */
715 716
        *data = s->abpr[cpu];
        break;
717
    case 0xd0: case 0xd4: case 0xd8: case 0xdc:
718 719
        *data = s->apr[(offset - 0xd0) / 4][cpu];
        break;
P
pbrook 已提交
720
    default:
P
Peter Maydell 已提交
721 722
        qemu_log_mask(LOG_GUEST_ERROR,
                      "gic_cpu_read: Bad offset %x\n", (int)offset);
723
        return MEMTX_ERROR;
P
pbrook 已提交
724
    }
725
    return MEMTX_OK;
P
pbrook 已提交
726 727
}

728 729
static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
                                 uint32_t value, MemTxAttrs attrs)
P
pbrook 已提交
730 731 732
{
    switch (offset) {
    case 0x00: /* Control */
P
pbrook 已提交
733
        s->cpu_enabled[cpu] = (value & 1);
734
        DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis");
P
pbrook 已提交
735 736
        break;
    case 0x04: /* Priority mask */
P
pbrook 已提交
737
        s->priority_mask[cpu] = (value & 0xff);
P
pbrook 已提交
738 739
        break;
    case 0x08: /* Binary Point */
740
        s->bpr[cpu] = (value & 0x7);
P
pbrook 已提交
741 742
        break;
    case 0x10: /* End Of Interrupt */
743
        gic_complete_irq(s, cpu, value & 0x3ff);
744
        return MEMTX_OK;
745 746 747 748 749
    case 0x1c: /* Aliased Binary Point */
        if (s->revision >= 2) {
            s->abpr[cpu] = (value & 0x7);
        }
        break;
750 751 752
    case 0xd0: case 0xd4: case 0xd8: case 0xdc:
        qemu_log_mask(LOG_UNIMP, "Writing APR not implemented\n");
        break;
P
pbrook 已提交
753
    default:
P
Peter Maydell 已提交
754 755
        qemu_log_mask(LOG_GUEST_ERROR,
                      "gic_cpu_write: Bad offset %x\n", (int)offset);
756
        return MEMTX_ERROR;
P
pbrook 已提交
757 758
    }
    gic_update(s);
759
    return MEMTX_OK;
P
pbrook 已提交
760
}
761 762

/* Wrappers to read/write the GIC CPU interface for the current CPU */
763 764
static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data,
                                    unsigned size, MemTxAttrs attrs)
765
{
766
    GICState *s = (GICState *)opaque;
767
    return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs);
768 769
}

770 771 772
static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr,
                                     uint64_t value, unsigned size,
                                     MemTxAttrs attrs)
773
{
774
    GICState *s = (GICState *)opaque;
775
    return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs);
776 777 778
}

/* Wrappers to read/write the GIC CPU interface for a specific CPU.
779
 * These just decode the opaque pointer into GICState* + cpu id.
780
 */
781 782
static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data,
                                   unsigned size, MemTxAttrs attrs)
783
{
784 785
    GICState **backref = (GICState **)opaque;
    GICState *s = *backref;
786
    int id = (backref - s->backref);
787
    return gic_cpu_read(s, id, addr, data, attrs);
788 789
}

790 791 792
static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr,
                                    uint64_t value, unsigned size,
                                    MemTxAttrs attrs)
793
{
794 795
    GICState **backref = (GICState **)opaque;
    GICState *s = *backref;
796
    int id = (backref - s->backref);
797
    return gic_cpu_write(s, id, addr, value, attrs);
798 799 800
}

static const MemoryRegionOps gic_thiscpu_ops = {
801 802
    .read_with_attrs = gic_thiscpu_read,
    .write_with_attrs = gic_thiscpu_write,
803 804 805 806
    .endianness = DEVICE_NATIVE_ENDIAN,
};

static const MemoryRegionOps gic_cpu_ops = {
807 808
    .read_with_attrs = gic_do_cpu_read,
    .write_with_attrs = gic_do_cpu_write,
809 810
    .endianness = DEVICE_NATIVE_ENDIAN,
};
P
pbrook 已提交
811

812
void gic_init_irqs_and_distributor(GICState *s)
P
pbrook 已提交
813
{
A
Andreas Färber 已提交
814
    SysBusDevice *sbd = SYS_BUS_DEVICE(s);
P
pbrook 已提交
815
    int i;
816

817 818 819 820 821 822 823 824
    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
     *   ...
     */
825 826 827
    if (s->revision != REV_NVIC) {
        i += (GIC_INTERNAL * s->num_cpu);
    }
A
Andreas Färber 已提交
828
    qdev_init_gpio_in(DEVICE(s), gic_set_irq, i);
P
Paul Brook 已提交
829
    for (i = 0; i < NUM_CPU(s); i++) {
A
Andreas Färber 已提交
830
        sysbus_init_irq(sbd, &s->parent_irq[i]);
P
pbrook 已提交
831
    }
832 833 834
    for (i = 0; i < NUM_CPU(s); i++) {
        sysbus_init_irq(sbd, &s->parent_fiq[i]);
    }
835 836
    memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s,
                          "gic_dist", 0x1000);
837 838
}

839
static void arm_gic_realize(DeviceState *dev, Error **errp)
840
{
841
    /* Device instance realize function for the GIC sysbus device */
842
    int i;
843 844
    GICState *s = ARM_GIC(dev);
    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
845
    ARMGICClass *agc = ARM_GIC_GET_CLASS(s);
846
    Error *local_err = NULL;
847

848 849 850
    agc->parent_realize(dev, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
851 852
        return;
    }
853

854
    gic_init_irqs_and_distributor(s);
855

856 857 858 859 860 861 862 863
    /* 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.
     */
864
    memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s,
865 866 867
                          "gic_cpu", 0x100);
    for (i = 0; i < NUM_CPU(s); i++) {
        s->backref[i] = s;
868 869
        memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops,
                              &s->backref[i], "gic_cpu", 0x100);
870
    }
871
    /* Distributor */
872
    sysbus_init_mmio(sbd, &s->iomem);
873 874
    /* cpu interfaces (one for "current cpu" plus one per cpu) */
    for (i = 0; i <= NUM_CPU(s); i++) {
875
        sysbus_init_mmio(sbd, &s->cpuiomem[i]);
876 877 878 879 880 881
    }
}

static void arm_gic_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
882
    ARMGICClass *agc = ARM_GIC_CLASS(klass);
883 884 885

    agc->parent_realize = dc->realize;
    dc->realize = arm_gic_realize;
886 887
}

888
static const TypeInfo arm_gic_info = {
889 890
    .name = TYPE_ARM_GIC,
    .parent = TYPE_ARM_GIC_COMMON,
891
    .instance_size = sizeof(GICState),
892
    .class_init = arm_gic_class_init,
893
    .class_size = sizeof(ARMGICClass),
894 895 896 897 898 899 900 901
};

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

type_init(arm_gic_register_types)