Annotation of qemu/hw/arm_gic.c, revision 1.1.1.3

1.1.1.2   root        1: /*
                      2:  * ARM Generic/Distributed Interrupt Controller
1.1       root        3:  *
1.1.1.2   root        4:  * Copyright (c) 2006-2007 CodeSourcery.
1.1       root        5:  * Written by Paul Brook
                      6:  *
                      7:  * This code is licenced under the GPL.
                      8:  */
                      9: 
1.1.1.2   root       10: /* This file contains implementation code for the RealView EB interrupt
                     11:    controller, MPCore distributed interrupt controller and ARMv7-M
                     12:    Nested Vectored Interrupt Controller.  */
1.1       root       13: 
                     14: //#define DEBUG_GIC
                     15: 
                     16: #ifdef DEBUG_GIC
                     17: #define DPRINTF(fmt, args...) \
                     18: do { printf("arm_gic: " fmt , ##args); } while (0)
                     19: #else
                     20: #define DPRINTF(fmt, args...) do {} while(0)
                     21: #endif
                     22: 
1.1.1.2   root       23: #ifdef NVIC
                     24: static const uint8_t gic_id[] =
                     25: { 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 };
                     26: /* The NVIC has 16 internal vectors.  However these are not exposed
                     27:    through the normal GIC interface.  */
                     28: #define GIC_BASE_IRQ    32
                     29: #else
1.1       root       30: static const uint8_t gic_id[] =
                     31: { 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
1.1.1.2   root       32: #define GIC_BASE_IRQ    0
                     33: #endif
1.1       root       34: 
                     35: typedef struct gic_irq_state
                     36: {
1.1.1.2   root       37:     /* ??? The documentation seems to imply the enable bits are global, even
                     38:        for per-cpu interrupts.  This seems strange.  */
1.1       root       39:     unsigned enabled:1;
1.1.1.2   root       40:     unsigned pending:NCPU;
                     41:     unsigned active:NCPU;
1.1       root       42:     unsigned level:1;
1.1.1.2   root       43:     unsigned model:1; /* 0 = N:N, 1 = 1:N */
1.1       root       44:     unsigned trigger:1; /* nonzero = edge triggered.  */
                     45: } gic_irq_state;
                     46: 
1.1.1.2   root       47: #define ALL_CPU_MASK ((1 << NCPU) - 1)
                     48: 
1.1       root       49: #define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1
                     50: #define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0
                     51: #define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled
1.1.1.2   root       52: #define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
                     53: #define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
                     54: #define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)
                     55: #define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
                     56: #define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
                     57: #define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
1.1       root       58: #define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
                     59: #define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
                     60: #define GIC_TEST_MODEL(irq) s->irq_state[irq].model
1.1.1.2   root       61: #define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
                     62: #define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
1.1.1.3 ! root       63: #define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
1.1       root       64: #define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
                     65: #define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
                     66: #define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
1.1.1.2   root       67: #define GIC_GET_PRIORITY(irq, cpu) \
                     68:   (((irq) < 32) ? s->priority1[irq][cpu] : s->priority2[(irq) - 32])
                     69: #ifdef NVIC
                     70: #define GIC_TARGET(irq) 1
                     71: #else
                     72: #define GIC_TARGET(irq) s->irq_target[irq]
                     73: #endif
1.1       root       74: 
                     75: typedef struct gic_state
                     76: {
1.1.1.2   root       77:     qemu_irq parent_irq[NCPU];
1.1       root       78:     int enabled;
1.1.1.2   root       79:     int cpu_enabled[NCPU];
1.1       root       80: 
                     81:     gic_irq_state irq_state[GIC_NIRQ];
1.1.1.2   root       82: #ifndef NVIC
1.1       root       83:     int irq_target[GIC_NIRQ];
1.1.1.2   root       84: #endif
                     85:     int priority1[32][NCPU];
                     86:     int priority2[GIC_NIRQ - 32];
                     87:     int last_active[GIC_NIRQ][NCPU];
                     88: 
                     89:     int priority_mask[NCPU];
                     90:     int running_irq[NCPU];
                     91:     int running_priority[NCPU];
                     92:     int current_pending[NCPU];
                     93: 
                     94:     qemu_irq *in;
                     95: #ifdef NVIC
                     96:     void *nvic;
                     97: #endif
1.1       root       98: } gic_state;
                     99: 
                    100: /* TODO: Many places that call this routine could be optimized.  */
                    101: /* Update interrupt status after enabled or pending bits have been changed.  */
                    102: static void gic_update(gic_state *s)
                    103: {
                    104:     int best_irq;
                    105:     int best_prio;
                    106:     int irq;
1.1.1.2   root      107:     int level;
                    108:     int cpu;
                    109:     int cm;
1.1       root      110: 
1.1.1.2   root      111:     for (cpu = 0; cpu < NCPU; cpu++) {
                    112:         cm = 1 << cpu;
                    113:         s->current_pending[cpu] = 1023;
                    114:         if (!s->enabled || !s->cpu_enabled[cpu]) {
                    115:            qemu_irq_lower(s->parent_irq[cpu]);
                    116:             return;
                    117:         }
                    118:         best_prio = 0x100;
                    119:         best_irq = 1023;
                    120:         for (irq = 0; irq < GIC_NIRQ; irq++) {
                    121:             if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq, cm)) {
                    122:                 if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
                    123:                     best_prio = GIC_GET_PRIORITY(irq, cpu);
                    124:                     best_irq = irq;
                    125:                 }
1.1       root      126:             }
                    127:         }
1.1.1.2   root      128:         level = 0;
                    129:         if (best_prio <= s->priority_mask[cpu]) {
                    130:             s->current_pending[cpu] = best_irq;
                    131:             if (best_prio < s->running_priority[cpu]) {
                    132:                 DPRINTF("Raised pending IRQ %d\n", best_irq);
                    133:                 level = 1;
                    134:             }
1.1       root      135:         }
1.1.1.2   root      136:         qemu_set_irq(s->parent_irq[cpu], level);
1.1       root      137:     }
                    138: }
                    139: 
1.1.1.2   root      140: static void __attribute__((unused))
                    141: gic_set_pending_private(gic_state *s, int cpu, int irq)
                    142: {
                    143:     int cm = 1 << cpu;
                    144: 
                    145:     if (GIC_TEST_PENDING(irq, cm))
                    146:         return;
                    147: 
                    148:     DPRINTF("Set %d pending cpu %d\n", irq, cpu);
                    149:     GIC_SET_PENDING(irq, cm);
                    150:     gic_update(s);
                    151: }
                    152: 
                    153: /* Process a change in an external IRQ input.  */
1.1       root      154: static void gic_set_irq(void *opaque, int irq, int level)
                    155: {
                    156:     gic_state *s = (gic_state *)opaque;
                    157:     /* The first external input line is internal interrupt 32.  */
                    158:     irq += 32;
1.1.1.2   root      159:     if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK))
1.1       root      160:         return;
                    161: 
                    162:     if (level) {
1.1.1.2   root      163:         GIC_SET_LEVEL(irq, ALL_CPU_MASK);
1.1       root      164:         if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) {
1.1.1.2   root      165:             DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq));
                    166:             GIC_SET_PENDING(irq, GIC_TARGET(irq));
1.1       root      167:         }
                    168:     } else {
1.1.1.2   root      169:         GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK);
1.1       root      170:     }
                    171:     gic_update(s);
                    172: }
                    173: 
1.1.1.2   root      174: static void gic_set_running_irq(gic_state *s, int cpu, int irq)
1.1       root      175: {
1.1.1.2   root      176:     s->running_irq[cpu] = irq;
                    177:     if (irq == 1023) {
                    178:         s->running_priority[cpu] = 0x100;
                    179:     } else {
                    180:         s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
                    181:     }
1.1       root      182:     gic_update(s);
                    183: }
                    184: 
1.1.1.2   root      185: static uint32_t gic_acknowledge_irq(gic_state *s, int cpu)
1.1       root      186: {
                    187:     int new_irq;
1.1.1.2   root      188:     int cm = 1 << cpu;
                    189:     new_irq = s->current_pending[cpu];
                    190:     if (new_irq == 1023
                    191:             || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) {
1.1       root      192:         DPRINTF("ACK no pending IRQ\n");
                    193:         return 1023;
                    194:     }
1.1.1.2   root      195:     s->last_active[new_irq][cpu] = s->running_irq[cpu];
                    196:     /* Clear pending flags for both level and edge triggered interrupts.
                    197:        Level triggered IRQs will be reasserted once they become inactive.  */
                    198:     GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm);
                    199:     gic_set_running_irq(s, cpu, new_irq);
1.1       root      200:     DPRINTF("ACK %d\n", new_irq);
                    201:     return new_irq;
                    202: }
                    203: 
1.1.1.2   root      204: static void gic_complete_irq(gic_state * s, int cpu, int irq)
1.1       root      205: {
                    206:     int update = 0;
1.1.1.2   root      207:     int cm = 1 << cpu;
1.1       root      208:     DPRINTF("EOI %d\n", irq);
1.1.1.2   root      209:     if (s->running_irq[cpu] == 1023)
1.1       root      210:         return; /* No active IRQ.  */
                    211:     if (irq != 1023) {
                    212:         /* Mark level triggered interrupts as pending if they are still
                    213:            raised.  */
                    214:         if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq)
1.1.1.2   root      215:                 && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
                    216:             DPRINTF("Set %d pending mask %x\n", irq, cm);
                    217:             GIC_SET_PENDING(irq, cm);
1.1       root      218:             update = 1;
                    219:         }
                    220:     }
1.1.1.2   root      221:     if (irq != s->running_irq[cpu]) {
1.1       root      222:         /* Complete an IRQ that is not currently running.  */
1.1.1.2   root      223:         int tmp = s->running_irq[cpu];
                    224:         while (s->last_active[tmp][cpu] != 1023) {
                    225:             if (s->last_active[tmp][cpu] == irq) {
                    226:                 s->last_active[tmp][cpu] = s->last_active[irq][cpu];
1.1       root      227:                 break;
                    228:             }
1.1.1.2   root      229:             tmp = s->last_active[tmp][cpu];
1.1       root      230:         }
                    231:         if (update) {
                    232:             gic_update(s);
                    233:         }
                    234:     } else {
                    235:         /* Complete the current running IRQ.  */
1.1.1.2   root      236:         gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
1.1       root      237:     }
                    238: }
                    239: 
                    240: static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
                    241: {
                    242:     gic_state *s = (gic_state *)opaque;
                    243:     uint32_t res;
                    244:     int irq;
                    245:     int i;
1.1.1.2   root      246:     int cpu;
                    247:     int cm;
                    248:     int mask;
                    249: 
                    250:     cpu = gic_get_current_cpu();
                    251:     cm = 1 << cpu;
1.1       root      252:     if (offset < 0x100) {
1.1.1.2   root      253: #ifndef NVIC
1.1       root      254:         if (offset == 0)
                    255:             return s->enabled;
                    256:         if (offset == 4)
1.1.1.2   root      257:             return ((GIC_NIRQ / 32) - 1) | ((NCPU - 1) << 5);
1.1       root      258:         if (offset < 0x08)
                    259:             return 0;
1.1.1.2   root      260: #endif
1.1       root      261:         goto bad_reg;
                    262:     } else if (offset < 0x200) {
                    263:         /* Interrupt Set/Clear Enable.  */
                    264:         if (offset < 0x180)
                    265:             irq = (offset - 0x100) * 8;
                    266:         else
                    267:             irq = (offset - 0x180) * 8;
1.1.1.2   root      268:         irq += GIC_BASE_IRQ;
1.1       root      269:         if (irq >= GIC_NIRQ)
                    270:             goto bad_reg;
                    271:         res = 0;
                    272:         for (i = 0; i < 8; i++) {
                    273:             if (GIC_TEST_ENABLED(irq + i)) {
                    274:                 res |= (1 << i);
                    275:             }
                    276:         }
                    277:     } else if (offset < 0x300) {
                    278:         /* Interrupt Set/Clear Pending.  */
                    279:         if (offset < 0x280)
                    280:             irq = (offset - 0x200) * 8;
                    281:         else
                    282:             irq = (offset - 0x280) * 8;
1.1.1.2   root      283:         irq += GIC_BASE_IRQ;
1.1       root      284:         if (irq >= GIC_NIRQ)
                    285:             goto bad_reg;
                    286:         res = 0;
1.1.1.2   root      287:         mask = (irq < 32) ?  cm : ALL_CPU_MASK;
1.1       root      288:         for (i = 0; i < 8; i++) {
1.1.1.2   root      289:             if (GIC_TEST_PENDING(irq + i, mask)) {
1.1       root      290:                 res |= (1 << i);
                    291:             }
                    292:         }
                    293:     } else if (offset < 0x400) {
                    294:         /* Interrupt Active.  */
1.1.1.2   root      295:         irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
1.1       root      296:         if (irq >= GIC_NIRQ)
                    297:             goto bad_reg;
                    298:         res = 0;
1.1.1.2   root      299:         mask = (irq < 32) ?  cm : ALL_CPU_MASK;
1.1       root      300:         for (i = 0; i < 8; i++) {
1.1.1.2   root      301:             if (GIC_TEST_ACTIVE(irq + i, mask)) {
1.1       root      302:                 res |= (1 << i);
                    303:             }
                    304:         }
                    305:     } else if (offset < 0x800) {
                    306:         /* Interrupt Priority.  */
1.1.1.2   root      307:         irq = (offset - 0x400) + GIC_BASE_IRQ;
1.1       root      308:         if (irq >= GIC_NIRQ)
                    309:             goto bad_reg;
1.1.1.2   root      310:         res = GIC_GET_PRIORITY(irq, cpu);
                    311: #ifndef NVIC
1.1       root      312:     } else if (offset < 0xc00) {
                    313:         /* Interrupt CPU Target.  */
1.1.1.2   root      314:         irq = (offset - 0x800) + GIC_BASE_IRQ;
1.1       root      315:         if (irq >= GIC_NIRQ)
                    316:             goto bad_reg;
1.1.1.2   root      317:         if (irq >= 29 && irq <= 31) {
                    318:             res = cm;
                    319:         } else {
                    320:             res = GIC_TARGET(irq);
                    321:         }
1.1       root      322:     } else if (offset < 0xf00) {
                    323:         /* Interrupt Configuration.  */
1.1.1.2   root      324:         irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
1.1       root      325:         if (irq >= GIC_NIRQ)
                    326:             goto bad_reg;
                    327:         res = 0;
                    328:         for (i = 0; i < 4; i++) {
                    329:             if (GIC_TEST_MODEL(irq + i))
                    330:                 res |= (1 << (i * 2));
                    331:             if (GIC_TEST_TRIGGER(irq + i))
                    332:                 res |= (2 << (i * 2));
                    333:         }
1.1.1.2   root      334: #endif
1.1       root      335:     } else if (offset < 0xfe0) {
                    336:         goto bad_reg;
                    337:     } else /* offset >= 0xfe0 */ {
                    338:         if (offset & 3) {
                    339:             res = 0;
                    340:         } else {
                    341:             res = gic_id[(offset - 0xfe0) >> 2];
                    342:         }
                    343:     }
                    344:     return res;
                    345: bad_reg:
1.1.1.2   root      346:     cpu_abort(cpu_single_env, "gic_dist_readb: Bad offset %x\n", (int)offset);
1.1       root      347:     return 0;
                    348: }
                    349: 
                    350: static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset)
                    351: {
                    352:     uint32_t val;
                    353:     val = gic_dist_readb(opaque, offset);
                    354:     val |= gic_dist_readb(opaque, offset + 1) << 8;
                    355:     return val;
                    356: }
                    357: 
                    358: static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset)
                    359: {
                    360:     uint32_t val;
1.1.1.2   root      361: #ifdef NVIC
                    362:     gic_state *s = (gic_state *)opaque;
                    363:     uint32_t addr;
1.1.1.3 ! root      364:     addr = offset;
1.1.1.2   root      365:     if (addr < 0x100 || addr > 0xd00)
                    366:         return nvic_readl(s->nvic, addr);
                    367: #endif
1.1       root      368:     val = gic_dist_readw(opaque, offset);
                    369:     val |= gic_dist_readw(opaque, offset + 2) << 16;
                    370:     return val;
                    371: }
                    372: 
                    373: static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
                    374:                             uint32_t value)
                    375: {
                    376:     gic_state *s = (gic_state *)opaque;
                    377:     int irq;
                    378:     int i;
1.1.1.2   root      379:     int cpu;
1.1       root      380: 
1.1.1.2   root      381:     cpu = gic_get_current_cpu();
1.1       root      382:     if (offset < 0x100) {
1.1.1.2   root      383: #ifdef NVIC
                    384:         goto bad_reg;
                    385: #else
1.1       root      386:         if (offset == 0) {
                    387:             s->enabled = (value & 1);
                    388:             DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
                    389:         } else if (offset < 4) {
                    390:             /* ignored.  */
                    391:         } else {
                    392:             goto bad_reg;
                    393:         }
1.1.1.2   root      394: #endif
1.1       root      395:     } else if (offset < 0x180) {
                    396:         /* Interrupt Set Enable.  */
1.1.1.2   root      397:         irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
1.1       root      398:         if (irq >= GIC_NIRQ)
                    399:             goto bad_reg;
1.1.1.2   root      400:         if (irq < 16)
                    401:           value = 0xff;
1.1       root      402:         for (i = 0; i < 8; i++) {
                    403:             if (value & (1 << i)) {
1.1.1.2   root      404:                 int mask = (irq < 32) ? (1 << cpu) : GIC_TARGET(irq);
1.1       root      405:                 if (!GIC_TEST_ENABLED(irq + i))
                    406:                     DPRINTF("Enabled IRQ %d\n", irq + i);
                    407:                 GIC_SET_ENABLED(irq + i);
                    408:                 /* If a raised level triggered IRQ enabled then mark
                    409:                    is as pending.  */
1.1.1.2   root      410:                 if (GIC_TEST_LEVEL(irq + i, mask)
                    411:                         && !GIC_TEST_TRIGGER(irq + i)) {
                    412:                     DPRINTF("Set %d pending mask %x\n", irq + i, mask);
                    413:                     GIC_SET_PENDING(irq + i, mask);
                    414:                 }
1.1       root      415:             }
                    416:         }
                    417:     } else if (offset < 0x200) {
                    418:         /* Interrupt Clear Enable.  */
1.1.1.2   root      419:         irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
1.1       root      420:         if (irq >= GIC_NIRQ)
                    421:             goto bad_reg;
1.1.1.2   root      422:         if (irq < 16)
                    423:           value = 0;
1.1       root      424:         for (i = 0; i < 8; i++) {
                    425:             if (value & (1 << i)) {
                    426:                 if (GIC_TEST_ENABLED(irq + i))
                    427:                     DPRINTF("Disabled IRQ %d\n", irq + i);
                    428:                 GIC_CLEAR_ENABLED(irq + i);
                    429:             }
                    430:         }
                    431:     } else if (offset < 0x280) {
                    432:         /* Interrupt Set Pending.  */
1.1.1.2   root      433:         irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
1.1       root      434:         if (irq >= GIC_NIRQ)
                    435:             goto bad_reg;
1.1.1.2   root      436:         if (irq < 16)
                    437:           irq = 0;
                    438: 
1.1       root      439:         for (i = 0; i < 8; i++) {
                    440:             if (value & (1 << i)) {
1.1.1.2   root      441:                 GIC_SET_PENDING(irq + i, GIC_TARGET(irq));
1.1       root      442:             }
                    443:         }
                    444:     } else if (offset < 0x300) {
                    445:         /* Interrupt Clear Pending.  */
1.1.1.2   root      446:         irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
1.1       root      447:         if (irq >= GIC_NIRQ)
                    448:             goto bad_reg;
                    449:         for (i = 0; i < 8; i++) {
1.1.1.2   root      450:             /* ??? This currently clears the pending bit for all CPUs, even
                    451:                for per-CPU interrupts.  It's unclear whether this is the
                    452:                corect behavior.  */
1.1       root      453:             if (value & (1 << i)) {
1.1.1.2   root      454:                 GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
1.1       root      455:             }
                    456:         }
                    457:     } else if (offset < 0x400) {
                    458:         /* Interrupt Active.  */
                    459:         goto bad_reg;
                    460:     } else if (offset < 0x800) {
                    461:         /* Interrupt Priority.  */
1.1.1.2   root      462:         irq = (offset - 0x400) + GIC_BASE_IRQ;
1.1       root      463:         if (irq >= GIC_NIRQ)
                    464:             goto bad_reg;
1.1.1.2   root      465:         if (irq < 32) {
                    466:             s->priority1[irq][cpu] = value;
                    467:         } else {
                    468:             s->priority2[irq - 32] = value;
                    469:         }
                    470: #ifndef NVIC
1.1       root      471:     } else if (offset < 0xc00) {
                    472:         /* Interrupt CPU Target.  */
1.1.1.2   root      473:         irq = (offset - 0x800) + GIC_BASE_IRQ;
1.1       root      474:         if (irq >= GIC_NIRQ)
                    475:             goto bad_reg;
1.1.1.2   root      476:         if (irq < 29)
                    477:             value = 0;
                    478:         else if (irq < 32)
                    479:             value = ALL_CPU_MASK;
                    480:         s->irq_target[irq] = value & ALL_CPU_MASK;
1.1       root      481:     } else if (offset < 0xf00) {
                    482:         /* Interrupt Configuration.  */
1.1.1.2   root      483:         irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
1.1       root      484:         if (irq >= GIC_NIRQ)
                    485:             goto bad_reg;
1.1.1.2   root      486:         if (irq < 32)
                    487:             value |= 0xaa;
1.1       root      488:         for (i = 0; i < 4; i++) {
                    489:             if (value & (1 << (i * 2))) {
                    490:                 GIC_SET_MODEL(irq + i);
                    491:             } else {
                    492:                 GIC_CLEAR_MODEL(irq + i);
                    493:             }
                    494:             if (value & (2 << (i * 2))) {
                    495:                 GIC_SET_TRIGGER(irq + i);
                    496:             } else {
                    497:                 GIC_CLEAR_TRIGGER(irq + i);
                    498:             }
                    499:         }
1.1.1.2   root      500: #endif
1.1       root      501:     } else {
1.1.1.2   root      502:         /* 0xf00 is only handled for 32-bit writes.  */
1.1       root      503:         goto bad_reg;
                    504:     }
                    505:     gic_update(s);
                    506:     return;
                    507: bad_reg:
1.1.1.2   root      508:     cpu_abort(cpu_single_env, "gic_dist_writeb: Bad offset %x\n", (int)offset);
1.1       root      509: }
                    510: 
                    511: static void gic_dist_writew(void *opaque, target_phys_addr_t offset,
                    512:                             uint32_t value)
                    513: {
                    514:     gic_dist_writeb(opaque, offset, value & 0xff);
                    515:     gic_dist_writeb(opaque, offset + 1, value >> 8);
                    516: }
                    517: 
                    518: static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
                    519:                             uint32_t value)
                    520: {
1.1.1.2   root      521:     gic_state *s = (gic_state *)opaque;
                    522: #ifdef NVIC
                    523:     uint32_t addr;
1.1.1.3 ! root      524:     addr = offset;
1.1.1.2   root      525:     if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) {
                    526:         nvic_writel(s->nvic, addr, value);
                    527:         return;
                    528:     }
                    529: #endif
1.1.1.3 ! root      530:     if (offset == 0xf00) {
1.1.1.2   root      531:         int cpu;
                    532:         int irq;
                    533:         int mask;
                    534: 
                    535:         cpu = gic_get_current_cpu();
                    536:         irq = value & 0x3ff;
                    537:         switch ((value >> 24) & 3) {
                    538:         case 0:
                    539:             mask = (value >> 16) & ALL_CPU_MASK;
                    540:             break;
                    541:         case 1:
                    542:             mask = 1 << cpu;
                    543:             break;
                    544:         case 2:
                    545:             mask = ALL_CPU_MASK ^ (1 << cpu);
                    546:             break;
                    547:         default:
                    548:             DPRINTF("Bad Soft Int target filter\n");
                    549:             mask = ALL_CPU_MASK;
                    550:             break;
                    551:         }
                    552:         GIC_SET_PENDING(irq, mask);
                    553:         gic_update(s);
                    554:         return;
                    555:     }
1.1       root      556:     gic_dist_writew(opaque, offset, value & 0xffff);
                    557:     gic_dist_writew(opaque, offset + 2, value >> 16);
                    558: }
                    559: 
                    560: static CPUReadMemoryFunc *gic_dist_readfn[] = {
                    561:    gic_dist_readb,
                    562:    gic_dist_readw,
                    563:    gic_dist_readl
                    564: };
                    565: 
                    566: static CPUWriteMemoryFunc *gic_dist_writefn[] = {
                    567:    gic_dist_writeb,
                    568:    gic_dist_writew,
                    569:    gic_dist_writel
                    570: };
                    571: 
1.1.1.2   root      572: #ifndef NVIC
                    573: static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset)
1.1       root      574: {
                    575:     switch (offset) {
                    576:     case 0x00: /* Control */
1.1.1.2   root      577:         return s->cpu_enabled[cpu];
1.1       root      578:     case 0x04: /* Priority mask */
1.1.1.2   root      579:         return s->priority_mask[cpu];
1.1       root      580:     case 0x08: /* Binary Point */
                    581:         /* ??? Not implemented.  */
                    582:         return 0;
                    583:     case 0x0c: /* Acknowledge */
1.1.1.2   root      584:         return gic_acknowledge_irq(s, cpu);
1.1       root      585:     case 0x14: /* Runing Priority */
1.1.1.2   root      586:         return s->running_priority[cpu];
1.1       root      587:     case 0x18: /* Highest Pending Interrupt */
1.1.1.2   root      588:         return s->current_pending[cpu];
1.1       root      589:     default:
1.1.1.2   root      590:         cpu_abort(cpu_single_env, "gic_cpu_read: Bad offset %x\n",
                    591:                   (int)offset);
1.1       root      592:         return 0;
                    593:     }
                    594: }
                    595: 
1.1.1.2   root      596: static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value)
1.1       root      597: {
                    598:     switch (offset) {
                    599:     case 0x00: /* Control */
1.1.1.2   root      600:         s->cpu_enabled[cpu] = (value & 1);
1.1       root      601:         DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis");
                    602:         break;
                    603:     case 0x04: /* Priority mask */
1.1.1.2   root      604:         s->priority_mask[cpu] = (value & 0xff);
1.1       root      605:         break;
                    606:     case 0x08: /* Binary Point */
                    607:         /* ??? Not implemented.  */
                    608:         break;
                    609:     case 0x10: /* End Of Interrupt */
1.1.1.2   root      610:         return gic_complete_irq(s, cpu, value & 0x3ff);
1.1       root      611:     default:
1.1.1.2   root      612:         cpu_abort(cpu_single_env, "gic_cpu_write: Bad offset %x\n",
                    613:                   (int)offset);
1.1       root      614:         return;
                    615:     }
                    616:     gic_update(s);
                    617: }
1.1.1.2   root      618: #endif
1.1       root      619: 
                    620: static void gic_reset(gic_state *s)
                    621: {
                    622:     int i;
                    623:     memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
1.1.1.2   root      624:     for (i = 0 ; i < NCPU; i++) {
                    625:         s->priority_mask[i] = 0xf0;
                    626:         s->current_pending[i] = 1023;
                    627:         s->running_irq[i] = 1023;
                    628:         s->running_priority[i] = 0x100;
                    629: #ifdef NVIC
                    630:         /* The NVIC doesn't have per-cpu interfaces, so enable by default.  */
                    631:         s->cpu_enabled[i] = 1;
                    632: #else
                    633:         s->cpu_enabled[i] = 0;
                    634: #endif
                    635:     }
                    636:     for (i = 0; i < 16; i++) {
1.1       root      637:         GIC_SET_ENABLED(i);
                    638:         GIC_SET_TRIGGER(i);
                    639:     }
1.1.1.2   root      640: #ifdef NVIC
                    641:     /* The NVIC is always enabled.  */
                    642:     s->enabled = 1;
                    643: #else
1.1       root      644:     s->enabled = 0;
1.1.1.2   root      645: #endif
1.1       root      646: }
                    647: 
1.1.1.3 ! root      648: static void gic_save(QEMUFile *f, void *opaque)
        !           649: {
        !           650:     gic_state *s = (gic_state *)opaque;
        !           651:     int i;
        !           652:     int j;
        !           653: 
        !           654:     qemu_put_be32(f, s->enabled);
        !           655:     for (i = 0; i < NCPU; i++) {
        !           656:         qemu_put_be32(f, s->cpu_enabled[i]);
        !           657: #ifndef NVIC
        !           658:         qemu_put_be32(f, s->irq_target[i]);
        !           659: #endif
        !           660:         for (j = 0; j < 32; j++)
        !           661:             qemu_put_be32(f, s->priority1[j][i]);
        !           662:         for (j = 0; j < GIC_NIRQ; j++)
        !           663:             qemu_put_be32(f, s->last_active[j][i]);
        !           664:         qemu_put_be32(f, s->priority_mask[i]);
        !           665:         qemu_put_be32(f, s->running_irq[i]);
        !           666:         qemu_put_be32(f, s->running_priority[i]);
        !           667:         qemu_put_be32(f, s->current_pending[i]);
        !           668:     }
        !           669:     for (i = 0; i < GIC_NIRQ - 32; i++) {
        !           670:         qemu_put_be32(f, s->priority2[i]);
        !           671:     }
        !           672:     for (i = 0; i < GIC_NIRQ; i++) {
        !           673:         qemu_put_byte(f, s->irq_state[i].enabled);
        !           674:         qemu_put_byte(f, s->irq_state[i].pending);
        !           675:         qemu_put_byte(f, s->irq_state[i].active);
        !           676:         qemu_put_byte(f, s->irq_state[i].level);
        !           677:         qemu_put_byte(f, s->irq_state[i].model);
        !           678:         qemu_put_byte(f, s->irq_state[i].trigger);
        !           679:     }
        !           680: }
        !           681: 
        !           682: static int gic_load(QEMUFile *f, void *opaque, int version_id)
        !           683: {
        !           684:     gic_state *s = (gic_state *)opaque;
        !           685:     int i;
        !           686:     int j;
        !           687: 
        !           688:     if (version_id != 1)
        !           689:         return -EINVAL;
        !           690: 
        !           691:     s->enabled = qemu_get_be32(f);
        !           692:     for (i = 0; i < NCPU; i++) {
        !           693:         s->cpu_enabled[i] = qemu_get_be32(f);
        !           694: #ifndef NVIC
        !           695:         s->irq_target[i] = qemu_get_be32(f);
        !           696: #endif
        !           697:         for (j = 0; j < 32; j++)
        !           698:             s->priority1[j][i] = qemu_get_be32(f);
        !           699:         for (j = 0; j < GIC_NIRQ; j++)
        !           700:             s->last_active[j][i] = qemu_get_be32(f);
        !           701:         s->priority_mask[i] = qemu_get_be32(f);
        !           702:         s->running_irq[i] = qemu_get_be32(f);
        !           703:         s->running_priority[i] = qemu_get_be32(f);
        !           704:         s->current_pending[i] = qemu_get_be32(f);
        !           705:     }
        !           706:     for (i = 0; i < GIC_NIRQ - 32; i++) {
        !           707:         s->priority2[i] = qemu_get_be32(f);
        !           708:     }
        !           709:     for (i = 0; i < GIC_NIRQ; i++) {
        !           710:         s->irq_state[i].enabled = qemu_get_byte(f);
        !           711:         s->irq_state[i].pending = qemu_get_byte(f);
        !           712:         s->irq_state[i].active = qemu_get_byte(f);
        !           713:         s->irq_state[i].level = qemu_get_byte(f);
        !           714:         s->irq_state[i].model = qemu_get_byte(f);
        !           715:         s->irq_state[i].trigger = qemu_get_byte(f);
        !           716:     }
        !           717: 
        !           718:     return 0;
        !           719: }
        !           720: 
        !           721: static gic_state *gic_init(uint32_t dist_base, qemu_irq *parent_irq)
1.1       root      722: {
                    723:     gic_state *s;
                    724:     int iomemtype;
1.1.1.2   root      725:     int i;
1.1       root      726: 
                    727:     s = (gic_state *)qemu_mallocz(sizeof(gic_state));
1.1.1.2   root      728:     s->in = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ);
                    729:     for (i = 0; i < NCPU; i++) {
                    730:         s->parent_irq[i] = parent_irq[i];
                    731:     }
                    732:     iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
                    733:                                        gic_dist_writefn, s);
1.1.1.3 ! root      734:     cpu_register_physical_memory(dist_base, 0x00001000,
1.1.1.2   root      735:                                  iomemtype);
1.1       root      736:     gic_reset(s);
1.1.1.3 ! root      737:     register_savevm("arm_gic", -1, 1, gic_save, gic_load, s);
1.1       root      738:     return s;
                    739: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.