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