|
|
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)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.