Annotation of qemu/hw/i8259.c, revision 1.1.1.12

1.1       root        1: /*
                      2:  * QEMU 8259 interrupt controller emulation
1.1.1.5   root        3:  *
1.1       root        4:  * Copyright (c) 2003-2004 Fabrice Bellard
1.1.1.5   root        5:  *
1.1       root        6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
1.1.1.5   root       24: #include "hw.h"
                     25: #include "pc.h"
                     26: #include "isa.h"
1.1.1.7   root       27: #include "monitor.h"
                     28: #include "qemu-timer.h"
1.1.1.12! root       29: #include "i8259_internal.h"
1.1       root       30: 
                     31: /* debug PIC */
                     32: //#define DEBUG_PIC
                     33: 
1.1.1.9   root       34: #ifdef DEBUG_PIC
                     35: #define DPRINTF(fmt, ...)                                       \
                     36:     do { printf("pic: " fmt , ## __VA_ARGS__); } while (0)
                     37: #else
                     38: #define DPRINTF(fmt, ...)
                     39: #endif
                     40: 
1.1       root       41: //#define DEBUG_IRQ_LATENCY
                     42: //#define DEBUG_IRQ_COUNT
                     43: 
1.1.1.11  root       44: #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
1.1       root       45: static int irq_level[16];
                     46: #endif
                     47: #ifdef DEBUG_IRQ_COUNT
                     48: static uint64_t irq_count[16];
                     49: #endif
1.1.1.11  root       50: #ifdef DEBUG_IRQ_LATENCY
                     51: static int64_t irq_time[16];
                     52: #endif
1.1.1.12! root       53: DeviceState *isa_pic;
        !            54: static PICCommonState *slave_pic;
1.1       root       55: 
                     56: /* return the highest priority found in mask (highest = smallest
                     57:    number). Return 8 if no irq */
1.1.1.12! root       58: static int get_priority(PICCommonState *s, int mask)
1.1       root       59: {
                     60:     int priority;
1.1.1.11  root       61: 
                     62:     if (mask == 0) {
1.1       root       63:         return 8;
1.1.1.11  root       64:     }
1.1       root       65:     priority = 0;
1.1.1.11  root       66:     while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) {
1.1       root       67:         priority++;
1.1.1.11  root       68:     }
1.1       root       69:     return priority;
                     70: }
                     71: 
                     72: /* return the pic wanted interrupt. return -1 if none */
1.1.1.12! root       73: static int pic_get_irq(PICCommonState *s)
1.1       root       74: {
                     75:     int mask, cur_priority, priority;
                     76: 
                     77:     mask = s->irr & ~s->imr;
                     78:     priority = get_priority(s, mask);
1.1.1.11  root       79:     if (priority == 8) {
1.1       root       80:         return -1;
1.1.1.11  root       81:     }
1.1       root       82:     /* compute current priority. If special fully nested mode on the
                     83:        master, the IRQ coming from the slave is not taken into account
                     84:        for the priority computation. */
                     85:     mask = s->isr;
1.1.1.11  root       86:     if (s->special_mask) {
1.1.1.6   root       87:         mask &= ~s->imr;
1.1.1.11  root       88:     }
                     89:     if (s->special_fully_nested_mode && s->master) {
1.1       root       90:         mask &= ~(1 << 2);
1.1.1.11  root       91:     }
1.1       root       92:     cur_priority = get_priority(s, mask);
                     93:     if (priority < cur_priority) {
                     94:         /* higher priority found: an irq should be generated */
                     95:         return (priority + s->priority_add) & 7;
                     96:     } else {
                     97:         return -1;
                     98:     }
                     99: }
                    100: 
1.1.1.11  root      101: /* Update INT output. Must be called every time the output may have changed. */
1.1.1.12! root      102: static void pic_update_irq(PICCommonState *s)
1.1.1.11  root      103: {
                    104:     int irq;
1.1.1.4   root      105: 
1.1.1.11  root      106:     irq = pic_get_irq(s);
                    107:     if (irq >= 0) {
                    108:         DPRINTF("pic%d: imr=%x irr=%x padd=%d\n",
                    109:                 s->master ? 0 : 1, s->imr, s->irr, s->priority_add);
                    110:         qemu_irq_raise(s->int_out[0]);
                    111:     } else {
                    112:         qemu_irq_lower(s->int_out[0]);
1.1.1.4   root      113:     }
1.1       root      114: }
                    115: 
1.1.1.11  root      116: /* set irq level. If an edge is detected, then the IRR is set to 1 */
                    117: static void pic_set_irq(void *opaque, int irq, int level)
1.1       root      118: {
1.1.1.12! root      119:     PICCommonState *s = opaque;
1.1.1.11  root      120:     int mask = 1 << irq;
1.1       root      121: 
1.1.1.11  root      122: #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
                    123:     defined(DEBUG_IRQ_LATENCY)
                    124:     int irq_index = s->master ? irq : irq + 8;
                    125: #endif
1.1       root      126: #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
1.1.1.11  root      127:     if (level != irq_level[irq_index]) {
                    128:         DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level);
                    129:         irq_level[irq_index] = level;
1.1       root      130: #ifdef DEBUG_IRQ_COUNT
1.1.1.11  root      131:         if (level == 1) {
                    132:             irq_count[irq_index]++;
                    133:         }
1.1       root      134: #endif
                    135:     }
                    136: #endif
                    137: #ifdef DEBUG_IRQ_LATENCY
                    138:     if (level) {
1.1.1.11  root      139:         irq_time[irq_index] = qemu_get_clock_ns(vm_clock);
1.1       root      140:     }
                    141: #endif
1.1.1.11  root      142: 
                    143:     if (s->elcr & mask) {
                    144:         /* level triggered */
                    145:         if (level) {
                    146:             s->irr |= mask;
                    147:             s->last_irr |= mask;
                    148:         } else {
                    149:             s->irr &= ~mask;
                    150:             s->last_irr &= ~mask;
                    151:         }
                    152:     } else {
                    153:         /* edge triggered */
                    154:         if (level) {
                    155:             if ((s->last_irr & mask) == 0) {
                    156:                 s->irr |= mask;
                    157:             }
                    158:             s->last_irr |= mask;
                    159:         } else {
                    160:             s->last_irr &= ~mask;
                    161:         }
                    162:     }
1.1       root      163:     pic_update_irq(s);
                    164: }
                    165: 
                    166: /* acknowledge interrupt 'irq' */
1.1.1.12! root      167: static void pic_intack(PICCommonState *s, int irq)
1.1       root      168: {
                    169:     if (s->auto_eoi) {
1.1.1.11  root      170:         if (s->rotate_on_auto_eoi) {
1.1       root      171:             s->priority_add = (irq + 1) & 7;
1.1.1.11  root      172:         }
1.1       root      173:     } else {
                    174:         s->isr |= (1 << irq);
                    175:     }
                    176:     /* We don't clear a level sensitive interrupt here */
1.1.1.11  root      177:     if (!(s->elcr & (1 << irq))) {
1.1       root      178:         s->irr &= ~(1 << irq);
1.1.1.11  root      179:     }
                    180:     pic_update_irq(s);
1.1       root      181: }
                    182: 
1.1.1.12! root      183: int pic_read_irq(DeviceState *d)
1.1       root      184: {
1.1.1.12! root      185:     PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
1.1       root      186:     int irq, irq2, intno;
                    187: 
1.1.1.11  root      188:     irq = pic_get_irq(s);
1.1       root      189:     if (irq >= 0) {
                    190:         if (irq == 2) {
1.1.1.11  root      191:             irq2 = pic_get_irq(slave_pic);
1.1       root      192:             if (irq2 >= 0) {
1.1.1.11  root      193:                 pic_intack(slave_pic, irq2);
1.1       root      194:             } else {
                    195:                 /* spurious IRQ on slave controller */
                    196:                 irq2 = 7;
                    197:             }
1.1.1.11  root      198:             intno = slave_pic->irq_base + irq2;
1.1       root      199:         } else {
1.1.1.11  root      200:             intno = s->irq_base + irq;
1.1       root      201:         }
1.1.1.11  root      202:         pic_intack(s, irq);
1.1       root      203:     } else {
                    204:         /* spurious IRQ on host controller */
                    205:         irq = 7;
1.1.1.11  root      206:         intno = s->irq_base + irq;
1.1       root      207:     }
1.1.1.5   root      208: 
1.1.1.11  root      209: #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
                    210:     if (irq == 2) {
                    211:         irq = irq2 + 8;
                    212:     }
                    213: #endif
1.1       root      214: #ifdef DEBUG_IRQ_LATENCY
1.1.1.5   root      215:     printf("IRQ%d latency=%0.3fus\n",
                    216:            irq,
1.1.1.10  root      217:            (double)(qemu_get_clock_ns(vm_clock) -
1.1.1.8   root      218:                     irq_time[irq]) * 1000000.0 / get_ticks_per_sec());
1.1       root      219: #endif
1.1.1.9   root      220:     DPRINTF("pic_interrupt: irq=%d\n", irq);
1.1       root      221:     return intno;
                    222: }
                    223: 
1.1.1.12! root      224: static void pic_init_reset(PICCommonState *s)
1.1       root      225: {
1.1.1.12! root      226:     pic_reset_common(s);
1.1.1.11  root      227:     pic_update_irq(s);
                    228: }
                    229: 
                    230: static void pic_reset(DeviceState *dev)
                    231: {
1.1.1.12! root      232:     PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
1.1.1.11  root      233: 
                    234:     s->elcr = 0;
1.1.1.12! root      235:     pic_init_reset(s);
1.1       root      236: }
                    237: 
1.1.1.11  root      238: static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
                    239:                              uint64_t val64, unsigned size)
1.1       root      240: {
1.1.1.12! root      241:     PICCommonState *s = opaque;
1.1.1.11  root      242:     uint32_t addr = addr64;
                    243:     uint32_t val = val64;
1.1       root      244:     int priority, cmd, irq;
                    245: 
1.1.1.9   root      246:     DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
1.1       root      247:     if (addr == 0) {
                    248:         if (val & 0x10) {
1.1.1.11  root      249:             pic_init_reset(s);
1.1       root      250:             s->init_state = 1;
                    251:             s->init4 = val & 1;
1.1.1.5   root      252:             s->single_mode = val & 2;
1.1.1.11  root      253:             if (val & 0x08) {
1.1       root      254:                 hw_error("level sensitive irq not supported");
1.1.1.11  root      255:             }
1.1       root      256:         } else if (val & 0x08) {
1.1.1.11  root      257:             if (val & 0x04) {
1.1       root      258:                 s->poll = 1;
1.1.1.11  root      259:             }
                    260:             if (val & 0x02) {
1.1       root      261:                 s->read_reg_select = val & 1;
1.1.1.11  root      262:             }
                    263:             if (val & 0x40) {
1.1       root      264:                 s->special_mask = (val >> 5) & 1;
1.1.1.11  root      265:             }
1.1       root      266:         } else {
                    267:             cmd = val >> 5;
1.1.1.11  root      268:             switch (cmd) {
1.1       root      269:             case 0:
                    270:             case 4:
                    271:                 s->rotate_on_auto_eoi = cmd >> 2;
                    272:                 break;
                    273:             case 1: /* end of interrupt */
                    274:             case 5:
                    275:                 priority = get_priority(s, s->isr);
                    276:                 if (priority != 8) {
                    277:                     irq = (priority + s->priority_add) & 7;
                    278:                     s->isr &= ~(1 << irq);
1.1.1.11  root      279:                     if (cmd == 5) {
1.1       root      280:                         s->priority_add = (irq + 1) & 7;
1.1.1.11  root      281:                     }
                    282:                     pic_update_irq(s);
1.1       root      283:                 }
                    284:                 break;
                    285:             case 3:
                    286:                 irq = val & 7;
                    287:                 s->isr &= ~(1 << irq);
1.1.1.11  root      288:                 pic_update_irq(s);
1.1       root      289:                 break;
                    290:             case 6:
                    291:                 s->priority_add = (val + 1) & 7;
1.1.1.11  root      292:                 pic_update_irq(s);
1.1       root      293:                 break;
                    294:             case 7:
                    295:                 irq = val & 7;
                    296:                 s->isr &= ~(1 << irq);
                    297:                 s->priority_add = (irq + 1) & 7;
1.1.1.11  root      298:                 pic_update_irq(s);
1.1       root      299:                 break;
                    300:             default:
                    301:                 /* no operation */
                    302:                 break;
                    303:             }
                    304:         }
                    305:     } else {
1.1.1.11  root      306:         switch (s->init_state) {
1.1       root      307:         case 0:
                    308:             /* normal mode */
                    309:             s->imr = val;
1.1.1.11  root      310:             pic_update_irq(s);
1.1       root      311:             break;
                    312:         case 1:
                    313:             s->irq_base = val & 0xf8;
1.1.1.5   root      314:             s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
1.1       root      315:             break;
                    316:         case 2:
                    317:             if (s->init4) {
                    318:                 s->init_state = 3;
                    319:             } else {
                    320:                 s->init_state = 0;
                    321:             }
                    322:             break;
                    323:         case 3:
                    324:             s->special_fully_nested_mode = (val >> 4) & 1;
                    325:             s->auto_eoi = (val >> 1) & 1;
                    326:             s->init_state = 0;
                    327:             break;
                    328:         }
                    329:     }
                    330: }
                    331: 
1.1.1.11  root      332: static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
                    333:                                 unsigned size)
1.1       root      334: {
1.1.1.12! root      335:     PICCommonState *s = opaque;
1.1       root      336:     int ret;
                    337: 
                    338:     if (s->poll) {
1.1.1.11  root      339:         ret = pic_get_irq(s);
                    340:         if (ret >= 0) {
                    341:             pic_intack(s, ret);
                    342:             ret |= 0x80;
                    343:         } else {
                    344:             ret = 0;
                    345:         }
1.1       root      346:         s->poll = 0;
                    347:     } else {
                    348:         if (addr == 0) {
1.1.1.11  root      349:             if (s->read_reg_select) {
1.1       root      350:                 ret = s->isr;
1.1.1.11  root      351:             } else {
1.1       root      352:                 ret = s->irr;
1.1.1.11  root      353:             }
1.1       root      354:         } else {
                    355:             ret = s->imr;
                    356:         }
                    357:     }
1.1.1.11  root      358:     DPRINTF("read: addr=0x%02x val=0x%02x\n", addr, ret);
1.1       root      359:     return ret;
                    360: }
                    361: 
1.1.1.12! root      362: int pic_get_output(DeviceState *d)
1.1       root      363: {
1.1.1.12! root      364:     PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
        !           365: 
1.1.1.11  root      366:     return (pic_get_irq(s) >= 0);
1.1       root      367: }
                    368: 
1.1.1.11  root      369: static void elcr_ioport_write(void *opaque, target_phys_addr_t addr,
                    370:                               uint64_t val, unsigned size)
1.1       root      371: {
1.1.1.12! root      372:     PICCommonState *s = opaque;
1.1       root      373:     s->elcr = val & s->elcr_mask;
                    374: }
                    375: 
1.1.1.11  root      376: static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr,
                    377:                                  unsigned size)
1.1       root      378: {
1.1.1.12! root      379:     PICCommonState *s = opaque;
1.1       root      380:     return s->elcr;
                    381: }
                    382: 
1.1.1.11  root      383: static const MemoryRegionOps pic_base_ioport_ops = {
                    384:     .read = pic_ioport_read,
                    385:     .write = pic_ioport_write,
                    386:     .impl = {
                    387:         .min_access_size = 1,
                    388:         .max_access_size = 1,
                    389:     },
                    390: };
                    391: 
                    392: static const MemoryRegionOps pic_elcr_ioport_ops = {
                    393:     .read = elcr_ioport_read,
                    394:     .write = elcr_ioport_write,
                    395:     .impl = {
                    396:         .min_access_size = 1,
                    397:         .max_access_size = 1,
                    398:     },
                    399: };
                    400: 
1.1.1.12! root      401: static void pic_init(PICCommonState *s)
1.1       root      402: {
1.1.1.11  root      403:     memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
                    404:     memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
                    405: 
1.1.1.12! root      406:     qdev_init_gpio_out(&s->dev.qdev, s->int_out, ARRAY_SIZE(s->int_out));
        !           407:     qdev_init_gpio_in(&s->dev.qdev, pic_set_irq, 8);
1.1       root      408: }
                    409: 
1.1.1.7   root      410: void pic_info(Monitor *mon)
1.1       root      411: {
                    412:     int i;
1.1.1.12! root      413:     PICCommonState *s;
1.1.1.5   root      414: 
1.1.1.11  root      415:     if (!isa_pic) {
1.1       root      416:         return;
1.1.1.11  root      417:     }
                    418:     for (i = 0; i < 2; i++) {
1.1.1.12! root      419:         s = i == 0 ? DO_UPCAST(PICCommonState, dev.qdev, isa_pic) : slave_pic;
1.1.1.7   root      420:         monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
                    421:                        "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
                    422:                        i, s->irr, s->imr, s->isr, s->priority_add,
                    423:                        s->irq_base, s->read_reg_select, s->elcr,
                    424:                        s->special_fully_nested_mode);
1.1       root      425:     }
                    426: }
                    427: 
1.1.1.7   root      428: void irq_info(Monitor *mon)
1.1       root      429: {
                    430: #ifndef DEBUG_IRQ_COUNT
1.1.1.7   root      431:     monitor_printf(mon, "irq statistic code not compiled.\n");
1.1       root      432: #else
                    433:     int i;
                    434:     int64_t count;
                    435: 
1.1.1.7   root      436:     monitor_printf(mon, "IRQ statistics:\n");
1.1       root      437:     for (i = 0; i < 16; i++) {
                    438:         count = irq_count[i];
1.1.1.11  root      439:         if (count > 0) {
1.1.1.7   root      440:             monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
1.1.1.11  root      441:         }
1.1       root      442:     }
                    443: #endif
                    444: }
                    445: 
1.1.1.12! root      446: qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
1.1       root      447: {
1.1.1.11  root      448:     qemu_irq *irq_set;
                    449:     ISADevice *dev;
                    450:     int i;
                    451: 
                    452:     irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
1.1.1.5   root      453: 
1.1.1.12! root      454:     dev = i8259_init_chip("isa-i8259", bus, true);
1.1.1.11  root      455: 
                    456:     qdev_connect_gpio_out(&dev->qdev, 0, parent_irq);
                    457:     for (i = 0 ; i < 8; i++) {
                    458:         irq_set[i] = qdev_get_gpio_in(&dev->qdev, i);
                    459:     }
                    460: 
1.1.1.12! root      461:     isa_pic = &dev->qdev;
1.1.1.11  root      462: 
1.1.1.12! root      463:     dev = i8259_init_chip("isa-i8259", bus, false);
1.1.1.11  root      464: 
                    465:     qdev_connect_gpio_out(&dev->qdev, 0, irq_set[2]);
                    466:     for (i = 0 ; i < 8; i++) {
                    467:         irq_set[i + 8] = qdev_get_gpio_in(&dev->qdev, i);
                    468:     }
                    469: 
1.1.1.12! root      470:     slave_pic = DO_UPCAST(PICCommonState, dev, dev);
1.1.1.11  root      471: 
                    472:     return irq_set;
                    473: }
                    474: 
1.1.1.12! root      475: static void i8259_class_init(ObjectClass *klass, void *data)
        !           476: {
        !           477:     PICCommonClass *k = PIC_COMMON_CLASS(klass);
        !           478:     DeviceClass *dc = DEVICE_CLASS(klass);
        !           479: 
        !           480:     k->init = pic_init;
        !           481:     dc->reset = pic_reset;
        !           482: }
        !           483: 
        !           484: static TypeInfo i8259_info = {
        !           485:     .name       = "isa-i8259",
        !           486:     .instance_size = sizeof(PICCommonState),
        !           487:     .parent     = TYPE_PIC_COMMON,
        !           488:     .class_init = i8259_class_init,
1.1.1.11  root      489: };
                    490: 
1.1.1.12! root      491: static void pic_register_types(void)
1.1.1.11  root      492: {
1.1.1.12! root      493:     type_register_static(&i8259_info);
1.1       root      494: }
1.1.1.12! root      495: 
        !           496: type_init(pic_register_types)

unix.superglobalmegacorp.com

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