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

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

A
Avi Kivity 已提交
418
static uint32_t gic_dist_readw(void *opaque, hwaddr offset)
P
pbrook 已提交
419 420 421 422 423 424 425
{
    uint32_t val;
    val = gic_dist_readb(opaque, offset);
    val |= gic_dist_readb(opaque, offset + 1) << 8;
    return val;
}

A
Avi Kivity 已提交
426
static uint32_t gic_dist_readl(void *opaque, hwaddr offset)
P
pbrook 已提交
427 428 429 430 431 432 433
{
    uint32_t val;
    val = gic_dist_readw(opaque, offset);
    val |= gic_dist_readw(opaque, offset + 2) << 16;
    return val;
}

A
Avi Kivity 已提交
434
static void gic_dist_writeb(void *opaque, hwaddr offset,
P
pbrook 已提交
435 436
                            uint32_t value)
{
437
    GICState *s = (GICState *)opaque;
P
pbrook 已提交
438 439
    int irq;
    int i;
P
pbrook 已提交
440
    int cpu;
P
pbrook 已提交
441

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

P
pbrook 已提交
463 464
        for (i = 0; i < 8; i++) {
            if (value & (1 << i)) {
465 466
                int mask =
                    (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i);
R
Rusty Russell 已提交
467
                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
468 469

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

P
pbrook 已提交
491 492
        for (i = 0; i < 8; i++) {
            if (value & (1 << i)) {
R
Rusty Russell 已提交
493
                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
494 495

                if (GIC_TEST_ENABLED(irq + i, cm)) {
P
pbrook 已提交
496
                    DPRINTF("Disabled IRQ %d\n", irq + i);
497 498
                }
                GIC_CLEAR_ENABLED(irq + i, cm);
P
pbrook 已提交
499 500 501 502
            }
        }
    } else if (offset < 0x280) {
        /* Interrupt Set Pending.  */
P
pbrook 已提交
503
        irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
504
        if (irq >= s->num_irq)
P
pbrook 已提交
505
            goto bad_reg;
506
        if (irq < GIC_NR_SGIS) {
507
            value = 0;
508
        }
P
pbrook 已提交
509

P
pbrook 已提交
510 511
        for (i = 0; i < 8; i++) {
            if (value & (1 << i)) {
512
                GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i));
P
pbrook 已提交
513 514 515 516
            }
        }
    } else if (offset < 0x300) {
        /* Interrupt Clear Pending.  */
P
pbrook 已提交
517
        irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
518
        if (irq >= s->num_irq)
P
pbrook 已提交
519
            goto bad_reg;
520 521 522 523
        if (irq < GIC_NR_SGIS) {
            value = 0;
        }

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

A
Avi Kivity 已提交
611
static void gic_dist_writew(void *opaque, hwaddr offset,
P
pbrook 已提交
612 613 614 615 616 617
                            uint32_t value)
{
    gic_dist_writeb(opaque, offset, value & 0xff);
    gic_dist_writeb(opaque, offset + 1, value >> 8);
}

A
Avi Kivity 已提交
618
static void gic_dist_writel(void *opaque, hwaddr offset,
P
pbrook 已提交
619 620
                            uint32_t value)
{
621
    GICState *s = (GICState *)opaque;
622
    if (offset == 0xf00) {
P
pbrook 已提交
623 624 625
        int cpu;
        int irq;
        int mask;
626
        int target_cpu;
P
pbrook 已提交
627

628
        cpu = gic_get_current_cpu(s);
P
pbrook 已提交
629 630 631 632 633 634
        irq = value & 0x3ff;
        switch ((value >> 24) & 3) {
        case 0:
            mask = (value >> 16) & ALL_CPU_MASK;
            break;
        case 1:
635
            mask = ALL_CPU_MASK ^ (1 << cpu);
P
pbrook 已提交
636 637
            break;
        case 2:
638
            mask = 1 << cpu;
P
pbrook 已提交
639 640 641 642 643 644 645
            break;
        default:
            DPRINTF("Bad Soft Int target filter\n");
            mask = ALL_CPU_MASK;
            break;
        }
        GIC_SET_PENDING(irq, mask);
646 647 648 649 650 651
        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 已提交
652 653 654
        gic_update(s);
        return;
    }
P
pbrook 已提交
655 656 657 658
    gic_dist_writew(opaque, offset, value & 0xffff);
    gic_dist_writew(opaque, offset + 2, value >> 16);
}

A
Avi Kivity 已提交
659 660 661 662 663 664
static const MemoryRegionOps gic_dist_ops = {
    .old_mmio = {
        .read = { gic_dist_readb, gic_dist_readw, gic_dist_readl, },
        .write = { gic_dist_writeb, gic_dist_writew, gic_dist_writel, },
    },
    .endianness = DEVICE_NATIVE_ENDIAN,
P
pbrook 已提交
665 666
};

667
static uint32_t gic_cpu_read(GICState *s, int cpu, int offset)
P
pbrook 已提交
668 669 670
{
    switch (offset) {
    case 0x00: /* Control */
P
pbrook 已提交
671
        return s->cpu_enabled[cpu];
P
pbrook 已提交
672
    case 0x04: /* Priority mask */
P
pbrook 已提交
673
        return s->priority_mask[cpu];
P
pbrook 已提交
674
    case 0x08: /* Binary Point */
675
        return s->bpr[cpu];
P
pbrook 已提交
676
    case 0x0c: /* Acknowledge */
P
pbrook 已提交
677
        return gic_acknowledge_irq(s, cpu);
D
Dong Xu Wang 已提交
678
    case 0x14: /* Running Priority */
P
pbrook 已提交
679
        return s->running_priority[cpu];
P
pbrook 已提交
680
    case 0x18: /* Highest Pending Interrupt */
P
pbrook 已提交
681
        return s->current_pending[cpu];
682 683
    case 0x1c: /* Aliased Binary Point */
        return s->abpr[cpu];
684 685
    case 0xd0: case 0xd4: case 0xd8: case 0xdc:
        return s->apr[(offset - 0xd0) / 4][cpu];
P
pbrook 已提交
686
    default:
P
Peter Maydell 已提交
687 688
        qemu_log_mask(LOG_GUEST_ERROR,
                      "gic_cpu_read: Bad offset %x\n", (int)offset);
P
pbrook 已提交
689 690 691 692
        return 0;
    }
}

693
static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value)
P
pbrook 已提交
694 695 696
{
    switch (offset) {
    case 0x00: /* Control */
P
pbrook 已提交
697
        s->cpu_enabled[cpu] = (value & 1);
698
        DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis");
P
pbrook 已提交
699 700
        break;
    case 0x04: /* Priority mask */
P
pbrook 已提交
701
        s->priority_mask[cpu] = (value & 0xff);
P
pbrook 已提交
702 703
        break;
    case 0x08: /* Binary Point */
704
        s->bpr[cpu] = (value & 0x7);
P
pbrook 已提交
705 706
        break;
    case 0x10: /* End Of Interrupt */
707 708
        gic_complete_irq(s, cpu, value & 0x3ff);
        return;
709 710 711 712 713
    case 0x1c: /* Aliased Binary Point */
        if (s->revision >= 2) {
            s->abpr[cpu] = (value & 0x7);
        }
        break;
714 715 716
    case 0xd0: case 0xd4: case 0xd8: case 0xdc:
        qemu_log_mask(LOG_UNIMP, "Writing APR not implemented\n");
        break;
P
pbrook 已提交
717
    default:
P
Peter Maydell 已提交
718 719
        qemu_log_mask(LOG_GUEST_ERROR,
                      "gic_cpu_write: Bad offset %x\n", (int)offset);
P
pbrook 已提交
720 721 722 723
        return;
    }
    gic_update(s);
}
724 725

/* Wrappers to read/write the GIC CPU interface for the current CPU */
A
Avi Kivity 已提交
726
static uint64_t gic_thiscpu_read(void *opaque, hwaddr addr,
727 728
                                 unsigned size)
{
729
    GICState *s = (GICState *)opaque;
730
    return gic_cpu_read(s, gic_get_current_cpu(s), addr);
731 732
}

A
Avi Kivity 已提交
733
static void gic_thiscpu_write(void *opaque, hwaddr addr,
734 735
                              uint64_t value, unsigned size)
{
736
    GICState *s = (GICState *)opaque;
737
    gic_cpu_write(s, gic_get_current_cpu(s), addr, value);
738 739 740
}

/* Wrappers to read/write the GIC CPU interface for a specific CPU.
741
 * These just decode the opaque pointer into GICState* + cpu id.
742
 */
A
Avi Kivity 已提交
743
static uint64_t gic_do_cpu_read(void *opaque, hwaddr addr,
744 745
                                unsigned size)
{
746 747
    GICState **backref = (GICState **)opaque;
    GICState *s = *backref;
748
    int id = (backref - s->backref);
749
    return gic_cpu_read(s, id, addr);
750 751
}

A
Avi Kivity 已提交
752
static void gic_do_cpu_write(void *opaque, hwaddr addr,
753 754
                             uint64_t value, unsigned size)
{
755 756
    GICState **backref = (GICState **)opaque;
    GICState *s = *backref;
757
    int id = (backref - s->backref);
758
    gic_cpu_write(s, id, addr, value);
759 760 761 762 763 764 765 766 767 768 769 770 771
}

static const MemoryRegionOps gic_thiscpu_ops = {
    .read = gic_thiscpu_read,
    .write = gic_thiscpu_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
};

static const MemoryRegionOps gic_cpu_ops = {
    .read = gic_do_cpu_read,
    .write = gic_do_cpu_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
};
P
pbrook 已提交
772

773
void gic_init_irqs_and_distributor(GICState *s)
P
pbrook 已提交
774
{
A
Andreas Färber 已提交
775
    SysBusDevice *sbd = SYS_BUS_DEVICE(s);
P
pbrook 已提交
776
    int i;
777

778 779 780 781 782 783 784 785
    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
     *   ...
     */
786 787 788
    if (s->revision != REV_NVIC) {
        i += (GIC_INTERNAL * s->num_cpu);
    }
A
Andreas Färber 已提交
789
    qdev_init_gpio_in(DEVICE(s), gic_set_irq, i);
P
Paul Brook 已提交
790
    for (i = 0; i < NUM_CPU(s); i++) {
A
Andreas Färber 已提交
791
        sysbus_init_irq(sbd, &s->parent_irq[i]);
P
pbrook 已提交
792
    }
793 794 795
    for (i = 0; i < NUM_CPU(s); i++) {
        sysbus_init_irq(sbd, &s->parent_fiq[i]);
    }
796 797
    memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s,
                          "gic_dist", 0x1000);
798 799
}

800
static void arm_gic_realize(DeviceState *dev, Error **errp)
801
{
802
    /* Device instance realize function for the GIC sysbus device */
803
    int i;
804 805
    GICState *s = ARM_GIC(dev);
    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
806
    ARMGICClass *agc = ARM_GIC_GET_CLASS(s);
807
    Error *local_err = NULL;
808

809 810 811
    agc->parent_realize(dev, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
812 813
        return;
    }
814

815
    gic_init_irqs_and_distributor(s);
816

817 818 819 820 821 822 823 824
    /* 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.
     */
825
    memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s,
826 827 828
                          "gic_cpu", 0x100);
    for (i = 0; i < NUM_CPU(s); i++) {
        s->backref[i] = s;
829 830
        memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops,
                              &s->backref[i], "gic_cpu", 0x100);
831
    }
832
    /* Distributor */
833
    sysbus_init_mmio(sbd, &s->iomem);
834 835
    /* cpu interfaces (one for "current cpu" plus one per cpu) */
    for (i = 0; i <= NUM_CPU(s); i++) {
836
        sysbus_init_mmio(sbd, &s->cpuiomem[i]);
837 838 839 840 841 842
    }
}

static void arm_gic_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
843
    ARMGICClass *agc = ARM_GIC_CLASS(klass);
844 845 846

    agc->parent_realize = dc->realize;
    dc->realize = arm_gic_realize;
847 848
}

849
static const TypeInfo arm_gic_info = {
850 851
    .name = TYPE_ARM_GIC,
    .parent = TYPE_ARM_GIC_COMMON,
852
    .instance_size = sizeof(GICState),
853
    .class_init = arm_gic_class_init,
854
    .class_size = sizeof(ARMGICClass),
855 856 857 858 859 860 861 862
};

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

type_init(arm_gic_register_types)