arm_gic.c 25.4 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
            if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm)) {
P
pbrook 已提交
70 71 72 73
                if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
                    best_prio = GIC_GET_PRIORITY(irq, cpu);
                    best_irq = irq;
                }
P
pbrook 已提交
74 75
            }
        }
P
pbrook 已提交
76
        level = 0;
77
        if (best_prio < s->priority_mask[cpu]) {
P
pbrook 已提交
78 79
            s->current_pending[cpu] = best_irq;
            if (best_prio < s->running_priority[cpu]) {
80
                DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu);
P
pbrook 已提交
81 82
                level = 1;
            }
P
pbrook 已提交
83
        }
P
pbrook 已提交
84
        qemu_set_irq(s->parent_irq[cpu], level);
P
pbrook 已提交
85 86 87
    }
}

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

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

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

101 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
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 已提交
129
/* Process a change in an external IRQ input.  */
P
pbrook 已提交
130 131
static void gic_set_irq(void *opaque, int irq, int level)
{
132 133 134 135 136 137
    /* 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
     *  ...
     */
138
    GICState *s = (GICState *)opaque;
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
    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;
    }

154 155
    assert(irq >= GIC_NR_SGIS);

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

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

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

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

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

    if (s->revision == REV_11MPCORE) {
        /* 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 已提交
224 225
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

A
Avi Kivity 已提交
656 657 658 659 660 661
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 已提交
662 663
};

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

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

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

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

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

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

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 已提交
768

769
void gic_init_irqs_and_distributor(GICState *s, int num_irq)
P
pbrook 已提交
770
{
A
Andreas Färber 已提交
771
    SysBusDevice *sbd = SYS_BUS_DEVICE(s);
P
pbrook 已提交
772
    int i;
773

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

793
static void arm_gic_realize(DeviceState *dev, Error **errp)
794
{
795
    /* Device instance realize function for the GIC sysbus device */
796
    int i;
797 798
    GICState *s = ARM_GIC(dev);
    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
799 800
    ARMGICClass *agc = ARM_GIC_GET_CLASS(s);

801 802 803 804
    agc->parent_realize(dev, errp);
    if (error_is_set(errp)) {
        return;
    }
805

806 807
    gic_init_irqs_and_distributor(s, s->num_irq);

808 809 810 811 812 813 814 815
    /* 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.
     */
816
    memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s,
817 818 819
                          "gic_cpu", 0x100);
    for (i = 0; i < NUM_CPU(s); i++) {
        s->backref[i] = s;
820 821
        memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops,
                              &s->backref[i], "gic_cpu", 0x100);
822
    }
823
    /* Distributor */
824
    sysbus_init_mmio(sbd, &s->iomem);
825 826
    /* cpu interfaces (one for "current cpu" plus one per cpu) */
    for (i = 0; i <= NUM_CPU(s); i++) {
827
        sysbus_init_mmio(sbd, &s->cpuiomem[i]);
828 829 830 831 832 833
    }
}

static void arm_gic_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
834
    ARMGICClass *agc = ARM_GIC_CLASS(klass);
835 836 837

    agc->parent_realize = dc->realize;
    dc->realize = arm_gic_realize;
838 839
}

840
static const TypeInfo arm_gic_info = {
841 842
    .name = TYPE_ARM_GIC,
    .parent = TYPE_ARM_GIC_COMMON,
843
    .instance_size = sizeof(GICState),
844
    .class_init = arm_gic_class_init,
845
    .class_size = sizeof(ARMGICClass),
846 847 848 849 850 851 852 853
};

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

type_init(arm_gic_register_types)