1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24: #include "hw.h"
25: #include "pc.h"
26: #include "isa.h"
27: #include "console.h"
28:
29:
30:
31:
32:
33:
34:
35: typedef struct PicState {
36: uint8_t last_irr;
37: uint8_t irr;
38: uint8_t imr;
39: uint8_t isr;
40: uint8_t priority_add;
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;
50: uint8_t single_mode;
51: uint8_t elcr;
52: uint8_t elcr_mask;
53: PicState2 *pics_state;
54: } PicState;
55:
56: struct PicState2 {
57:
58:
59: PicState pics[2];
60: qemu_irq parent_irq;
61: void *irq_request_opaque;
62:
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:
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:
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:
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:
101:
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:
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:
123:
124:
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:
131: return (priority + s->priority_add) & 7;
132: } else {
133: return -1;
134: }
135: }
136:
137:
138:
139:
140: void pic_update_irq(PicState2 *s)
141: {
142: int irq2, irq;
143:
144:
145: irq2 = pic_get_irq(&s->pics[1]);
146: if (irq2 >= 0) {
147:
148: pic_set_irq1(&s->pics[0], 2, 1);
149: pic_set_irq1(&s->pics[0], 2, 0);
150: }
151:
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++) {
158: printf("pic%d: imr=%x irr=%x padd=%d\n",
159: i, s->pics[i].imr, s->pics[i].irr,
160: s->pics[i].priority_add);
161:
162: }
163: }
164: printf("pic: cpu_interrupt\n");
165: #endif
166: qemu_irq_raise(s->parent_irq);
167: }
168:
169:
170: #if defined(TARGET_MIPS) || defined(TARGET_PPC)
171: else {
172: qemu_irq_lower(s->parent_irq);
173: }
174: #endif
175: }
176:
177: #ifdef DEBUG_IRQ_LATENCY
178: int64_t irq_time[16];
179: #endif
180:
181: static void i8259_set_irq(void *opaque, int irq, int level)
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)
188: printf("i8259_set_irq: irq=%d level=%d\n", irq, level);
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:
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:
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:
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:
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:
245: irq = 7;
246: intno = s->pics[0].irq_base + irq;
247: }
248: pic_update_irq(s);
249:
250: #ifdef DEBUG_IRQ_LATENCY
251: printf("IRQ%d latency=%0.3fus\n",
252: irq,
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;
279: s->single_mode = 0;
280:
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:
295: pic_reset(s);
296:
297: qemu_irq_lower(s->pics_state->parent_irq);
298: s->init_state = 1;
299: s->init4 = val & 1;
300: s->single_mode = val & 2;
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:
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:
345: break;
346: }
347: }
348: } else {
349: switch(s->init_state) {
350: case 0:
351:
352: s->imr = val;
353: pic_update_irq(s->pics_state);
354: break;
355: case 1:
356: s->irq_base = val & 0xf8;
357: s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
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:
425:
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:
434: s->pics[0].read_reg_select = 1;
435:
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;
454:
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);
469: qemu_put_8s(f, &s->single_mode);
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;
476:
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);
494: qemu_get_8s(f, &s->single_mode);
495: qemu_get_8s(f, &s->elcr);
496: return 0;
497: }
498:
499:
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;
516:
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",
523: i, s->irr, s->imr, s->isr, s->priority_add,
524: s->irq_base, s->read_reg_select, s->elcr,
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)
541: term_printf("%2d: %" PRId64 "\n", i, count);
542: }
543: #endif
544: }
545:
546: qemu_irq *i8259_init(qemu_irq parent_irq)
547: {
548: PicState2 *s;
549:
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;
557: s->parent_irq = parent_irq;
558: s->pics[0].pics_state = s;
559: s->pics[1].pics_state = s;
560: isa_pic = s;
561: return qemu_allocate_irqs(i8259_set_irq, s, 16);
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: }