|
|
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"
! 27: #include "console.h"
1.1 root 28:
29: /* debug PIC */
30: //#define DEBUG_PIC
31:
32: //#define DEBUG_IRQ_LATENCY
33: //#define DEBUG_IRQ_COUNT
34:
35: typedef struct PicState {
36: uint8_t last_irr; /* edge detection */
37: uint8_t irr; /* interrupt request register */
38: uint8_t imr; /* interrupt mask register */
39: uint8_t isr; /* interrupt service register */
40: uint8_t priority_add; /* highest irq priority */
41: uint8_t irq_base;
42: uint8_t read_reg_select;
43: uint8_t poll;
44: uint8_t special_mask;
45: uint8_t init_state;
46: uint8_t auto_eoi;
47: uint8_t rotate_on_auto_eoi;
48: uint8_t special_fully_nested_mode;
49: uint8_t init4; /* true if 4 byte init */
1.1.1.5 ! root 50: uint8_t single_mode; /* true if slave pic is not initialized */
1.1 root 51: uint8_t elcr; /* PIIX edge/trigger selection*/
52: uint8_t elcr_mask;
53: PicState2 *pics_state;
54: } PicState;
55:
56: struct PicState2 {
57: /* 0 is master pic, 1 is slave pic */
58: /* XXX: better separation between the two pics */
59: PicState pics[2];
1.1.1.5 ! root 60: qemu_irq parent_irq;
1.1 root 61: void *irq_request_opaque;
62: /* IOAPIC callback support */
63: SetIRQFunc *alt_irq_func;
64: void *alt_irq_opaque;
65: };
66:
67: #if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
68: static int irq_level[16];
69: #endif
70: #ifdef DEBUG_IRQ_COUNT
71: static uint64_t irq_count[16];
72: #endif
73:
74: /* set irq level. If an edge is detected, then the IRR is set to 1 */
75: static inline void pic_set_irq1(PicState *s, int irq, int level)
76: {
77: int mask;
78: mask = 1 << irq;
79: if (s->elcr & mask) {
80: /* level triggered */
81: if (level) {
82: s->irr |= mask;
83: s->last_irr |= mask;
84: } else {
85: s->irr &= ~mask;
86: s->last_irr &= ~mask;
87: }
88: } else {
89: /* edge triggered */
90: if (level) {
91: if ((s->last_irr & mask) == 0)
92: s->irr |= mask;
93: s->last_irr |= mask;
94: } else {
95: s->last_irr &= ~mask;
96: }
97: }
98: }
99:
100: /* return the highest priority found in mask (highest = smallest
101: number). Return 8 if no irq */
102: static inline int get_priority(PicState *s, int mask)
103: {
104: int priority;
105: if (mask == 0)
106: return 8;
107: priority = 0;
108: while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
109: priority++;
110: return priority;
111: }
112:
113: /* return the pic wanted interrupt. return -1 if none */
114: static int pic_get_irq(PicState *s)
115: {
116: int mask, cur_priority, priority;
117:
118: mask = s->irr & ~s->imr;
119: priority = get_priority(s, mask);
120: if (priority == 8)
121: return -1;
122: /* compute current priority. If special fully nested mode on the
123: master, the IRQ coming from the slave is not taken into account
124: for the priority computation. */
125: mask = s->isr;
126: if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
127: mask &= ~(1 << 2);
128: cur_priority = get_priority(s, mask);
129: if (priority < cur_priority) {
130: /* higher priority found: an irq should be generated */
131: return (priority + s->priority_add) & 7;
132: } else {
133: return -1;
134: }
135: }
136:
137: /* raise irq to CPU if necessary. must be called every time the active
138: irq may change */
139: /* XXX: should not export it, but it is needed for an APIC kludge */
140: void pic_update_irq(PicState2 *s)
141: {
142: int irq2, irq;
143:
144: /* first look at slave pic */
145: irq2 = pic_get_irq(&s->pics[1]);
146: if (irq2 >= 0) {
147: /* if irq request by slave pic, signal master PIC */
148: pic_set_irq1(&s->pics[0], 2, 1);
149: pic_set_irq1(&s->pics[0], 2, 0);
150: }
151: /* look at requested irq */
152: irq = pic_get_irq(&s->pics[0]);
153: if (irq >= 0) {
154: #if defined(DEBUG_PIC)
155: {
156: int i;
157: for(i = 0; i < 2; i++) {
1.1.1.5 ! root 158: printf("pic%d: imr=%x irr=%x padd=%d\n",
! 159: i, s->pics[i].imr, s->pics[i].irr,
1.1 root 160: s->pics[i].priority_add);
1.1.1.5 ! root 161:
1.1 root 162: }
163: }
164: printf("pic: cpu_interrupt\n");
165: #endif
1.1.1.5 ! root 166: qemu_irq_raise(s->parent_irq);
1.1 root 167: }
1.1.1.4 root 168:
169: /* all targets should do this rather than acking the IRQ in the cpu */
1.1.1.5 ! root 170: #if defined(TARGET_MIPS) || defined(TARGET_PPC)
1.1.1.4 root 171: else {
1.1.1.5 ! root 172: qemu_irq_lower(s->parent_irq);
1.1.1.4 root 173: }
174: #endif
1.1 root 175: }
176:
177: #ifdef DEBUG_IRQ_LATENCY
178: int64_t irq_time[16];
179: #endif
180:
1.1.1.5 ! root 181: static void i8259_set_irq(void *opaque, int irq, int level)
1.1 root 182: {
183: PicState2 *s = opaque;
184:
185: #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
186: if (level != irq_level[irq]) {
187: #if defined(DEBUG_PIC)
1.1.1.5 ! root 188: printf("i8259_set_irq: irq=%d level=%d\n", irq, level);
1.1 root 189: #endif
190: irq_level[irq] = level;
191: #ifdef DEBUG_IRQ_COUNT
192: if (level == 1)
193: irq_count[irq]++;
194: #endif
195: }
196: #endif
197: #ifdef DEBUG_IRQ_LATENCY
198: if (level) {
199: irq_time[irq] = qemu_get_clock(vm_clock);
200: }
201: #endif
202: pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
203: /* used for IOAPIC irqs */
204: if (s->alt_irq_func)
205: s->alt_irq_func(s->alt_irq_opaque, irq, level);
206: pic_update_irq(s);
207: }
208:
209: /* acknowledge interrupt 'irq' */
210: static inline void pic_intack(PicState *s, int irq)
211: {
212: if (s->auto_eoi) {
213: if (s->rotate_on_auto_eoi)
214: s->priority_add = (irq + 1) & 7;
215: } else {
216: s->isr |= (1 << irq);
217: }
218: /* We don't clear a level sensitive interrupt here */
219: if (!(s->elcr & (1 << irq)))
220: s->irr &= ~(1 << irq);
221: }
222:
223: int pic_read_irq(PicState2 *s)
224: {
225: int irq, irq2, intno;
226:
227: irq = pic_get_irq(&s->pics[0]);
228: if (irq >= 0) {
229: pic_intack(&s->pics[0], irq);
230: if (irq == 2) {
231: irq2 = pic_get_irq(&s->pics[1]);
232: if (irq2 >= 0) {
233: pic_intack(&s->pics[1], irq2);
234: } else {
235: /* spurious IRQ on slave controller */
236: irq2 = 7;
237: }
238: intno = s->pics[1].irq_base + irq2;
239: irq = irq2 + 8;
240: } else {
241: intno = s->pics[0].irq_base + irq;
242: }
243: } else {
244: /* spurious IRQ on host controller */
245: irq = 7;
246: intno = s->pics[0].irq_base + irq;
247: }
248: pic_update_irq(s);
1.1.1.5 ! root 249:
1.1 root 250: #ifdef DEBUG_IRQ_LATENCY
1.1.1.5 ! root 251: printf("IRQ%d latency=%0.3fus\n",
! 252: irq,
1.1 root 253: (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec);
254: #endif
255: #if defined(DEBUG_PIC)
256: printf("pic_interrupt: irq=%d\n", irq);
257: #endif
258: return intno;
259: }
260:
261: static void pic_reset(void *opaque)
262: {
263: PicState *s = opaque;
264:
265: s->last_irr = 0;
266: s->irr = 0;
267: s->imr = 0;
268: s->isr = 0;
269: s->priority_add = 0;
270: s->irq_base = 0;
271: s->read_reg_select = 0;
272: s->poll = 0;
273: s->special_mask = 0;
274: s->init_state = 0;
275: s->auto_eoi = 0;
276: s->rotate_on_auto_eoi = 0;
277: s->special_fully_nested_mode = 0;
278: s->init4 = 0;
1.1.1.5 ! root 279: s->single_mode = 0;
1.1.1.2 root 280: /* Note: ELCR is not reset */
1.1 root 281: }
282:
283: static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
284: {
285: PicState *s = opaque;
286: int priority, cmd, irq;
287:
288: #ifdef DEBUG_PIC
289: printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
290: #endif
291: addr &= 1;
292: if (addr == 0) {
293: if (val & 0x10) {
294: /* init */
295: pic_reset(s);
296: /* deassert a pending interrupt */
1.1.1.5 ! root 297: qemu_irq_lower(s->pics_state->parent_irq);
1.1 root 298: s->init_state = 1;
299: s->init4 = val & 1;
1.1.1.5 ! root 300: s->single_mode = val & 2;
1.1 root 301: if (val & 0x08)
302: hw_error("level sensitive irq not supported");
303: } else if (val & 0x08) {
304: if (val & 0x04)
305: s->poll = 1;
306: if (val & 0x02)
307: s->read_reg_select = val & 1;
308: if (val & 0x40)
309: s->special_mask = (val >> 5) & 1;
310: } else {
311: cmd = val >> 5;
312: switch(cmd) {
313: case 0:
314: case 4:
315: s->rotate_on_auto_eoi = cmd >> 2;
316: break;
317: case 1: /* end of interrupt */
318: case 5:
319: priority = get_priority(s, s->isr);
320: if (priority != 8) {
321: irq = (priority + s->priority_add) & 7;
322: s->isr &= ~(1 << irq);
323: if (cmd == 5)
324: s->priority_add = (irq + 1) & 7;
325: pic_update_irq(s->pics_state);
326: }
327: break;
328: case 3:
329: irq = val & 7;
330: s->isr &= ~(1 << irq);
331: pic_update_irq(s->pics_state);
332: break;
333: case 6:
334: s->priority_add = (val + 1) & 7;
335: pic_update_irq(s->pics_state);
336: break;
337: case 7:
338: irq = val & 7;
339: s->isr &= ~(1 << irq);
340: s->priority_add = (irq + 1) & 7;
341: pic_update_irq(s->pics_state);
342: break;
343: default:
344: /* no operation */
345: break;
346: }
347: }
348: } else {
349: switch(s->init_state) {
350: case 0:
351: /* normal mode */
352: s->imr = val;
353: pic_update_irq(s->pics_state);
354: break;
355: case 1:
356: s->irq_base = val & 0xf8;
1.1.1.5 ! root 357: s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
1.1 root 358: break;
359: case 2:
360: if (s->init4) {
361: s->init_state = 3;
362: } else {
363: s->init_state = 0;
364: }
365: break;
366: case 3:
367: s->special_fully_nested_mode = (val >> 4) & 1;
368: s->auto_eoi = (val >> 1) & 1;
369: s->init_state = 0;
370: break;
371: }
372: }
373: }
374:
375: static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
376: {
377: int ret;
378:
379: ret = pic_get_irq(s);
380: if (ret >= 0) {
381: if (addr1 >> 7) {
382: s->pics_state->pics[0].isr &= ~(1 << 2);
383: s->pics_state->pics[0].irr &= ~(1 << 2);
384: }
385: s->irr &= ~(1 << ret);
386: s->isr &= ~(1 << ret);
387: if (addr1 >> 7 || ret != 2)
388: pic_update_irq(s->pics_state);
389: } else {
390: ret = 0x07;
391: pic_update_irq(s->pics_state);
392: }
393:
394: return ret;
395: }
396:
397: static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
398: {
399: PicState *s = opaque;
400: unsigned int addr;
401: int ret;
402:
403: addr = addr1;
404: addr &= 1;
405: if (s->poll) {
406: ret = pic_poll_read(s, addr1);
407: s->poll = 0;
408: } else {
409: if (addr == 0) {
410: if (s->read_reg_select)
411: ret = s->isr;
412: else
413: ret = s->irr;
414: } else {
415: ret = s->imr;
416: }
417: }
418: #ifdef DEBUG_PIC
419: printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret);
420: #endif
421: return ret;
422: }
423:
424: /* memory mapped interrupt status */
425: /* XXX: may be the same than pic_read_irq() */
426: uint32_t pic_intack_read(PicState2 *s)
427: {
428: int ret;
429:
430: ret = pic_poll_read(&s->pics[0], 0x00);
431: if (ret == 2)
432: ret = pic_poll_read(&s->pics[1], 0x80) + 8;
433: /* Prepare for ISR read */
434: s->pics[0].read_reg_select = 1;
1.1.1.5 ! root 435:
1.1 root 436: return ret;
437: }
438:
439: static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
440: {
441: PicState *s = opaque;
442: s->elcr = val & s->elcr_mask;
443: }
444:
445: static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
446: {
447: PicState *s = opaque;
448: return s->elcr;
449: }
450:
451: static void pic_save(QEMUFile *f, void *opaque)
452: {
453: PicState *s = opaque;
1.1.1.5 ! root 454:
1.1 root 455: qemu_put_8s(f, &s->last_irr);
456: qemu_put_8s(f, &s->irr);
457: qemu_put_8s(f, &s->imr);
458: qemu_put_8s(f, &s->isr);
459: qemu_put_8s(f, &s->priority_add);
460: qemu_put_8s(f, &s->irq_base);
461: qemu_put_8s(f, &s->read_reg_select);
462: qemu_put_8s(f, &s->poll);
463: qemu_put_8s(f, &s->special_mask);
464: qemu_put_8s(f, &s->init_state);
465: qemu_put_8s(f, &s->auto_eoi);
466: qemu_put_8s(f, &s->rotate_on_auto_eoi);
467: qemu_put_8s(f, &s->special_fully_nested_mode);
468: qemu_put_8s(f, &s->init4);
1.1.1.5 ! root 469: qemu_put_8s(f, &s->single_mode);
1.1 root 470: qemu_put_8s(f, &s->elcr);
471: }
472:
473: static int pic_load(QEMUFile *f, void *opaque, int version_id)
474: {
475: PicState *s = opaque;
1.1.1.5 ! root 476:
1.1 root 477: if (version_id != 1)
478: return -EINVAL;
479:
480: qemu_get_8s(f, &s->last_irr);
481: qemu_get_8s(f, &s->irr);
482: qemu_get_8s(f, &s->imr);
483: qemu_get_8s(f, &s->isr);
484: qemu_get_8s(f, &s->priority_add);
485: qemu_get_8s(f, &s->irq_base);
486: qemu_get_8s(f, &s->read_reg_select);
487: qemu_get_8s(f, &s->poll);
488: qemu_get_8s(f, &s->special_mask);
489: qemu_get_8s(f, &s->init_state);
490: qemu_get_8s(f, &s->auto_eoi);
491: qemu_get_8s(f, &s->rotate_on_auto_eoi);
492: qemu_get_8s(f, &s->special_fully_nested_mode);
493: qemu_get_8s(f, &s->init4);
1.1.1.5 ! root 494: qemu_get_8s(f, &s->single_mode);
1.1 root 495: qemu_get_8s(f, &s->elcr);
496: return 0;
497: }
498:
499: /* XXX: add generic master/slave system */
500: static void pic_init1(int io_addr, int elcr_addr, PicState *s)
501: {
502: register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
503: register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
504: if (elcr_addr >= 0) {
505: register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
506: register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
507: }
508: register_savevm("i8259", io_addr, 1, pic_save, pic_load, s);
509: qemu_register_reset(pic_reset, s);
510: }
511:
512: void pic_info(void)
513: {
514: int i;
515: PicState *s;
1.1.1.5 ! root 516:
1.1 root 517: if (!isa_pic)
518: return;
519:
520: for(i=0;i<2;i++) {
521: s = &isa_pic->pics[i];
522: term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
1.1.1.5 ! root 523: i, s->irr, s->imr, s->isr, s->priority_add,
! 524: s->irq_base, s->read_reg_select, s->elcr,
1.1 root 525: s->special_fully_nested_mode);
526: }
527: }
528:
529: void irq_info(void)
530: {
531: #ifndef DEBUG_IRQ_COUNT
532: term_printf("irq statistic code not compiled.\n");
533: #else
534: int i;
535: int64_t count;
536:
537: term_printf("IRQ statistics:\n");
538: for (i = 0; i < 16; i++) {
539: count = irq_count[i];
540: if (count > 0)
1.1.1.3 root 541: term_printf("%2d: %" PRId64 "\n", i, count);
1.1 root 542: }
543: #endif
544: }
545:
1.1.1.5 ! root 546: qemu_irq *i8259_init(qemu_irq parent_irq)
1.1 root 547: {
548: PicState2 *s;
1.1.1.5 ! root 549:
1.1 root 550: s = qemu_mallocz(sizeof(PicState2));
551: if (!s)
552: return NULL;
553: pic_init1(0x20, 0x4d0, &s->pics[0]);
554: pic_init1(0xa0, 0x4d1, &s->pics[1]);
555: s->pics[0].elcr_mask = 0xf8;
556: s->pics[1].elcr_mask = 0xde;
1.1.1.5 ! root 557: s->parent_irq = parent_irq;
1.1 root 558: s->pics[0].pics_state = s;
559: s->pics[1].pics_state = s;
1.1.1.5 ! root 560: isa_pic = s;
! 561: return qemu_allocate_irqs(i8259_set_irq, s, 16);
1.1 root 562: }
563:
564: void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
565: void *alt_irq_opaque)
566: {
567: s->alt_irq_func = alt_irq_func;
568: s->alt_irq_opaque = alt_irq_opaque;
569: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.