xref: /qemu/hw/intc/i8259.c (revision f260f7361ca6caf7bb672195c50db99eff26b856)
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 "qemu/osdep.h"
25 #include "hw/hw.h"
26 #include "hw/i386/pc.h"
27 #include "hw/isa/isa.h"
28 #include "monitor/monitor.h"
29 #include "qemu/timer.h"
30 #include "qemu/log.h"
31 #include "hw/isa/i8259_internal.h"
32 #include "hw/intc/intc.h"
33 #include "trace.h"
34 
35 /* debug PIC */
36 //#define DEBUG_PIC
37 
38 //#define DEBUG_IRQ_LATENCY
39 
40 #define TYPE_I8259 "isa-i8259"
41 #define PIC_CLASS(class) OBJECT_CLASS_CHECK(PICClass, (class), TYPE_I8259)
42 #define PIC_GET_CLASS(obj) OBJECT_GET_CLASS(PICClass, (obj), TYPE_I8259)
43 
44 /**
45  * PICClass:
46  * @parent_realize: The parent's realizefn.
47  */
48 typedef struct PICClass {
49     PICCommonClass parent_class;
50 
51     DeviceRealize parent_realize;
52 } PICClass;
53 
54 static int irq_level[16];
55 static uint64_t irq_count[16];
56 #ifdef DEBUG_IRQ_LATENCY
57 static int64_t irq_time[16];
58 #endif
59 DeviceState *isa_pic;
60 static PICCommonState *slave_pic;
61 
62 /* return the highest priority found in mask (highest = smallest
63    number). Return 8 if no irq */
64 static int get_priority(PICCommonState *s, int mask)
65 {
66     int priority;
67 
68     if (mask == 0) {
69         return 8;
70     }
71     priority = 0;
72     while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) {
73         priority++;
74     }
75     return priority;
76 }
77 
78 /* return the pic wanted interrupt. return -1 if none */
79 static int pic_get_irq(PICCommonState *s)
80 {
81     int mask, cur_priority, priority;
82 
83     mask = s->irr & ~s->imr;
84     priority = get_priority(s, mask);
85     if (priority == 8) {
86         return -1;
87     }
88     /* compute current priority. If special fully nested mode on the
89        master, the IRQ coming from the slave is not taken into account
90        for the priority computation. */
91     mask = s->isr;
92     if (s->special_mask) {
93         mask &= ~s->imr;
94     }
95     if (s->special_fully_nested_mode && s->master) {
96         mask &= ~(1 << 2);
97     }
98     cur_priority = get_priority(s, mask);
99     if (priority < cur_priority) {
100         /* higher priority found: an irq should be generated */
101         return (priority + s->priority_add) & 7;
102     } else {
103         return -1;
104     }
105 }
106 
107 /* Update INT output. Must be called every time the output may have changed. */
108 static void pic_update_irq(PICCommonState *s)
109 {
110     int irq;
111 
112     irq = pic_get_irq(s);
113     if (irq >= 0) {
114         trace_pic_update_irq(s->master, s->imr, s->irr, s->priority_add);
115         qemu_irq_raise(s->int_out[0]);
116     } else {
117         qemu_irq_lower(s->int_out[0]);
118     }
119 }
120 
121 /* set irq level. If an edge is detected, then the IRR is set to 1 */
122 static void pic_set_irq(void *opaque, int irq, int level)
123 {
124     PICCommonState *s = opaque;
125     int mask = 1 << irq;
126     int irq_index = s->master ? irq : irq + 8;
127 
128     trace_pic_set_irq(s->master, irq, level);
129 
130     if (level != irq_level[irq_index]) {
131         irq_level[irq_index] = level;
132         if (level == 1) {
133             irq_count[irq_index]++;
134         }
135     }
136 
137 #ifdef DEBUG_IRQ_LATENCY
138     if (level) {
139         irq_time[irq_index] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
140     }
141 #endif
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     }
163     pic_update_irq(s);
164 }
165 
166 /* acknowledge interrupt 'irq' */
167 static void pic_intack(PICCommonState *s, int irq)
168 {
169     if (s->auto_eoi) {
170         if (s->rotate_on_auto_eoi) {
171             s->priority_add = (irq + 1) & 7;
172         }
173     } else {
174         s->isr |= (1 << irq);
175     }
176     /* We don't clear a level sensitive interrupt here */
177     if (!(s->elcr & (1 << irq))) {
178         s->irr &= ~(1 << irq);
179     }
180     pic_update_irq(s);
181 }
182 
183 int pic_read_irq(DeviceState *d)
184 {
185     PICCommonState *s = PIC_COMMON(d);
186     int irq, irq2, intno;
187 
188     irq = pic_get_irq(s);
189     if (irq >= 0) {
190         if (irq == 2) {
191             irq2 = pic_get_irq(slave_pic);
192             if (irq2 >= 0) {
193                 pic_intack(slave_pic, irq2);
194             } else {
195                 /* spurious IRQ on slave controller */
196                 irq2 = 7;
197             }
198             intno = slave_pic->irq_base + irq2;
199         } else {
200             intno = s->irq_base + irq;
201         }
202         pic_intack(s, irq);
203     } else {
204         /* spurious IRQ on host controller */
205         irq = 7;
206         intno = s->irq_base + irq;
207     }
208 
209     if (irq == 2) {
210         irq = irq2 + 8;
211     }
212 
213 #ifdef DEBUG_IRQ_LATENCY
214     printf("IRQ%d latency=%0.3fus\n",
215            irq,
216            (double)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
217                     irq_time[irq]) * 1000000.0 / NANOSECONDS_PER_SECOND);
218 #endif
219 
220     trace_pic_interrupt(irq, intno);
221     return intno;
222 }
223 
224 static void pic_init_reset(PICCommonState *s)
225 {
226     pic_reset_common(s);
227     pic_update_irq(s);
228 }
229 
230 static void pic_reset(DeviceState *dev)
231 {
232     PICCommonState *s = PIC_COMMON(dev);
233 
234     s->elcr = 0;
235     pic_init_reset(s);
236 }
237 
238 static bool pic_get_statistics(InterruptStatsProvider *obj,
239                                uint64_t **irq_counts, unsigned int *nb_irqs)
240 {
241     PICCommonState *s = PIC_COMMON(obj);
242 
243     if (s->master) {
244         *irq_counts = irq_count;
245         *nb_irqs = ARRAY_SIZE(irq_count);
246     } else {
247         *irq_counts = NULL;
248         *nb_irqs = 0;
249     }
250     return true;
251 }
252 
253 static void pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
254 {
255     PICCommonState *s = PIC_COMMON(obj);
256     monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
257                    "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
258                    s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add,
259                    s->irq_base, s->read_reg_select, s->elcr,
260                    s->special_fully_nested_mode);
261 }
262 
263 static void pic_ioport_write(void *opaque, hwaddr addr64,
264                              uint64_t val64, unsigned size)
265 {
266     PICCommonState *s = opaque;
267     uint32_t addr = addr64;
268     uint32_t val = val64;
269     int priority, cmd, irq;
270 
271     trace_pic_ioport_write(s->master, addr, val);
272 
273     if (addr == 0) {
274         if (val & 0x10) {
275             pic_init_reset(s);
276             s->init_state = 1;
277             s->init4 = val & 1;
278             s->single_mode = val & 2;
279             if (val & 0x08) {
280                 qemu_log_mask(LOG_UNIMP,
281                               "i8259: level sensitive irq not supported\n");
282             }
283         } else if (val & 0x08) {
284             if (val & 0x04) {
285                 s->poll = 1;
286             }
287             if (val & 0x02) {
288                 s->read_reg_select = val & 1;
289             }
290             if (val & 0x40) {
291                 s->special_mask = (val >> 5) & 1;
292             }
293         } else {
294             cmd = val >> 5;
295             switch (cmd) {
296             case 0:
297             case 4:
298                 s->rotate_on_auto_eoi = cmd >> 2;
299                 break;
300             case 1: /* end of interrupt */
301             case 5:
302                 priority = get_priority(s, s->isr);
303                 if (priority != 8) {
304                     irq = (priority + s->priority_add) & 7;
305                     s->isr &= ~(1 << irq);
306                     if (cmd == 5) {
307                         s->priority_add = (irq + 1) & 7;
308                     }
309                     pic_update_irq(s);
310                 }
311                 break;
312             case 3:
313                 irq = val & 7;
314                 s->isr &= ~(1 << irq);
315                 pic_update_irq(s);
316                 break;
317             case 6:
318                 s->priority_add = (val + 1) & 7;
319                 pic_update_irq(s);
320                 break;
321             case 7:
322                 irq = val & 7;
323                 s->isr &= ~(1 << irq);
324                 s->priority_add = (irq + 1) & 7;
325                 pic_update_irq(s);
326                 break;
327             default:
328                 /* no operation */
329                 break;
330             }
331         }
332     } else {
333         switch (s->init_state) {
334         case 0:
335             /* normal mode */
336             s->imr = val;
337             pic_update_irq(s);
338             break;
339         case 1:
340             s->irq_base = val & 0xf8;
341             s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
342             break;
343         case 2:
344             if (s->init4) {
345                 s->init_state = 3;
346             } else {
347                 s->init_state = 0;
348             }
349             break;
350         case 3:
351             s->special_fully_nested_mode = (val >> 4) & 1;
352             s->auto_eoi = (val >> 1) & 1;
353             s->init_state = 0;
354             break;
355         }
356     }
357 }
358 
359 static uint64_t pic_ioport_read(void *opaque, hwaddr addr,
360                                 unsigned size)
361 {
362     PICCommonState *s = opaque;
363     int ret;
364 
365     if (s->poll) {
366         ret = pic_get_irq(s);
367         if (ret >= 0) {
368             pic_intack(s, ret);
369             ret |= 0x80;
370         } else {
371             ret = 0;
372         }
373         s->poll = 0;
374     } else {
375         if (addr == 0) {
376             if (s->read_reg_select) {
377                 ret = s->isr;
378             } else {
379                 ret = s->irr;
380             }
381         } else {
382             ret = s->imr;
383         }
384     }
385     trace_pic_ioport_read(s->master, addr, ret);
386     return ret;
387 }
388 
389 int pic_get_output(DeviceState *d)
390 {
391     PICCommonState *s = PIC_COMMON(d);
392 
393     return (pic_get_irq(s) >= 0);
394 }
395 
396 static void elcr_ioport_write(void *opaque, hwaddr addr,
397                               uint64_t val, unsigned size)
398 {
399     PICCommonState *s = opaque;
400     s->elcr = val & s->elcr_mask;
401 }
402 
403 static uint64_t elcr_ioport_read(void *opaque, hwaddr addr,
404                                  unsigned size)
405 {
406     PICCommonState *s = opaque;
407     return s->elcr;
408 }
409 
410 static const MemoryRegionOps pic_base_ioport_ops = {
411     .read = pic_ioport_read,
412     .write = pic_ioport_write,
413     .impl = {
414         .min_access_size = 1,
415         .max_access_size = 1,
416     },
417 };
418 
419 static const MemoryRegionOps pic_elcr_ioport_ops = {
420     .read = elcr_ioport_read,
421     .write = elcr_ioport_write,
422     .impl = {
423         .min_access_size = 1,
424         .max_access_size = 1,
425     },
426 };
427 
428 static void pic_realize(DeviceState *dev, Error **errp)
429 {
430     PICCommonState *s = PIC_COMMON(dev);
431     PICClass *pc = PIC_GET_CLASS(dev);
432 
433     memory_region_init_io(&s->base_io, OBJECT(s), &pic_base_ioport_ops, s,
434                           "pic", 2);
435     memory_region_init_io(&s->elcr_io, OBJECT(s), &pic_elcr_ioport_ops, s,
436                           "elcr", 1);
437 
438     qdev_init_gpio_out(dev, s->int_out, ARRAY_SIZE(s->int_out));
439     qdev_init_gpio_in(dev, pic_set_irq, 8);
440 
441     pc->parent_realize(dev, errp);
442 }
443 
444 qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
445 {
446     qemu_irq *irq_set;
447     DeviceState *dev;
448     ISADevice *isadev;
449     int i;
450 
451     irq_set = g_new0(qemu_irq, ISA_NUM_IRQS);
452 
453     isadev = i8259_init_chip(TYPE_I8259, bus, true);
454     dev = DEVICE(isadev);
455 
456     qdev_connect_gpio_out(dev, 0, parent_irq);
457     for (i = 0 ; i < 8; i++) {
458         irq_set[i] = qdev_get_gpio_in(dev, i);
459     }
460 
461     isa_pic = dev;
462 
463     isadev = i8259_init_chip(TYPE_I8259, bus, false);
464     dev = DEVICE(isadev);
465 
466     qdev_connect_gpio_out(dev, 0, irq_set[2]);
467     for (i = 0 ; i < 8; i++) {
468         irq_set[i + 8] = qdev_get_gpio_in(dev, i);
469     }
470 
471     slave_pic = PIC_COMMON(dev);
472 
473     return irq_set;
474 }
475 
476 static void i8259_class_init(ObjectClass *klass, void *data)
477 {
478     PICClass *k = PIC_CLASS(klass);
479     DeviceClass *dc = DEVICE_CLASS(klass);
480     InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
481 
482     k->parent_realize = dc->realize;
483     dc->realize = pic_realize;
484     dc->reset = pic_reset;
485     ic->get_statistics = pic_get_statistics;
486     ic->print_info = pic_print_info;
487 }
488 
489 static const TypeInfo i8259_info = {
490     .name       = TYPE_I8259,
491     .instance_size = sizeof(PICCommonState),
492     .parent     = TYPE_PIC_COMMON,
493     .class_init = i8259_class_init,
494     .class_size = sizeof(PICClass),
495     .interfaces = (InterfaceInfo[]) {
496         { TYPE_INTERRUPT_STATS_PROVIDER },
497         { }
498     },
499 };
500 
501 static void pic_register_types(void)
502 {
503     type_register_static(&i8259_info);
504 }
505 
506 type_init(pic_register_types)
507